From 67855c9ce2b151517f05a2e8e63ace6f9a06602a Mon Sep 17 00:00:00 2001 From: guoshengxiong <1923636941@qq.com> Date: Wed, 16 Jul 2025 18:10:59 +0800 Subject: [PATCH] =?UTF-8?q?icc=E7=9A=84=E5=8A=B3=E5=8A=A1=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E5=92=8C=E8=80=83=E5=8B=A4=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zhgd/xmgl/call/IccWorkerCall.java | 248 +++++++++++++++++- .../xmgl/call/api/WorkerManufacturer.java | 18 +- .../service/impl/WorkerInfoServiceImpl.java | 2 +- .../java/com/zhgd/xmgl/task/ProjectTask.java | 24 ++ 4 files changed, 279 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/zhgd/xmgl/call/IccWorkerCall.java b/src/main/java/com/zhgd/xmgl/call/IccWorkerCall.java index 08dea5ad0..73e82409f 100644 --- a/src/main/java/com/zhgd/xmgl/call/IccWorkerCall.java +++ b/src/main/java/com/zhgd/xmgl/call/IccWorkerCall.java @@ -1,6 +1,8 @@ package com.zhgd.xmgl.call; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; @@ -18,13 +20,19 @@ import com.dahuatech.icc.brm.model.v202010.person.BrmPersonQueryByIdCardRequest; import com.dahuatech.icc.brm.model.v202010.person.BrmPersonQueryByIdCardResponse; import com.dahuatech.icc.config.OauthConfigUtil; import com.dahuatech.icc.exception.ClientException; +import com.dahuatech.icc.model.accesscontrol.auth.PersonAuthRequest; +import com.dahuatech.icc.model.accesscontrol.record.QueryRecordCountResponse; +import com.dahuatech.icc.model.accesscontrol.record.QueryRecordRequest; +import com.dahuatech.icc.model.accesscontrol.record.QueryRecordResponse; import com.dahuatech.icc.model.brm.department.DepartmentUpdateResponse; import com.dahuatech.icc.model.brm.person.*; import com.dahuatech.icc.oauth.http.IccResponse; import com.dahuatech.icc.oauth.http.IccTokenResponse; +import com.dahuatech.icc.oauth.model.v202010.GeneralResponse; import com.dahuatech.icc.oauth.model.v202010.OauthConfigUserPwdInfo; import com.dahuatech.icc.oauth.utils.HttpUtils; import com.gexin.fastjson.JSON; +import com.google.common.collect.Lists; import com.zhgd.jeecg.common.execption.OpenAlertException; import com.zhgd.xmgl.call.api.WorkerManufacturer; import com.zhgd.xmgl.modules.basicdata.service.impl.NoticeServiceImpl; @@ -33,19 +41,21 @@ import com.zhgd.xmgl.modules.project.entity.ProjectEnterprise; import com.zhgd.xmgl.modules.project.entity.ProjectUfaceConfig; import com.zhgd.xmgl.modules.project.service.IProjectEnterpriseService; import com.zhgd.xmgl.modules.project.service.IProjectService; -import com.zhgd.xmgl.modules.worker.entity.DepartmentInfo; -import com.zhgd.xmgl.modules.worker.entity.EnterpriseInfo; -import com.zhgd.xmgl.modules.worker.entity.TeamInfo; -import com.zhgd.xmgl.modules.worker.entity.WorkerInfo; +import com.zhgd.xmgl.modules.project.service.IProjectUfaceConfigService; +import com.zhgd.xmgl.modules.worker.entity.*; import com.zhgd.xmgl.modules.worker.service.IDepartmentInfoService; import com.zhgd.xmgl.modules.worker.service.ITeamInfoService; +import com.zhgd.xmgl.modules.worker.service.IUfaceDevService; +import com.zhgd.xmgl.modules.worker.service.IWorkerAttendanceService; import com.zhgd.xmgl.modules.worker.service.impl.EnterpriseInfoServiceImpl; +import com.zhgd.xmgl.modules.worker.service.impl.WorkerAttendanceServiceImpl; import com.zhgd.xmgl.modules.worker.service.impl.WorkerInfoServiceImpl; import com.zhgd.xmgl.modules.xz.service.impl.XzHikvisionSyncServiceImpl; import com.zhgd.xmgl.util.Base64Util; import com.zhgd.xmgl.util.PathUtil; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -53,9 +63,11 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import javax.annotation.Resource; import java.io.File; import java.util.*; import java.util.function.Consumer; +import java.util.stream.Collectors; @Slf4j @Component @@ -68,6 +80,9 @@ public class IccWorkerCall implements WorkerManufacturer { @Autowired @Lazy public WorkerInfoServiceImpl workerInfoService; + @Autowired + @Lazy + public IProjectUfaceConfigService projectUfaceConfigService; @Lazy @Autowired XzHikvisionSyncServiceImpl xzHikvisionSyncService; @@ -93,6 +108,15 @@ public class IccWorkerCall implements WorkerManufacturer { private NoticeServiceImpl noticeService; @Value("${basePath}") private String basePath; + @Autowired + @Lazy + private IWorkerAttendanceService workerAttendanceService; + @Autowired + @Lazy + private WorkerAttendanceServiceImpl workerAttendanceServiceImpl; + @Lazy + @Resource + private IUfaceDevService ufaceDevService; public static void main(String[] args) throws ClientException { IccTokenResponse.IccToken accessToken = HttpUtils.getToken(OauthConfigUtil.getOauthConfig()); @@ -381,9 +405,24 @@ public class IccWorkerCall implements WorkerManufacturer { @Override public void saveWorkerUFaceAuth(WorkerInfo workerInfo) { - String subject = getAndSetSubjectIfNotExist("保存劳务人员门禁权限"); + String subject = getAndSetSubjectIfNotExist("同步劳务人员门禁权限"); try { - + Pair sendAndDeleteDevSns = projectUfaceConfigService.getSendAndDeleteDevSns(workerInfo); + List addDevSns = StrUtil.split(sendAndDeleteDevSns.getLeft(), ","); + List deleteDevSns = StrUtil.split(sendAndDeleteDevSns.getRight(), ","); + List personCodes = Collections.singletonList(workerInfo.getPersonSn()); + if (CollUtil.isEmpty(addDevSns) && CollUtil.isNotEmpty(deleteDevSns)) { + IccHttpUtil.deletePersonAllAuth(personCodes, config); + } else { + if (CollUtil.isNotEmpty(addDevSns)) { + GeneralResponse response = IccHttpUtil.addPersonAuth(personCodes, addDevSns, config); + IccHttpUtil.throwErrIf(response); + } + if (CollUtil.isNotEmpty(deleteDevSns)) { + GeneralResponse response = IccHttpUtil.deletePersonAuth(workerInfo.getPersonSn(), deleteDevSns, config); + IccHttpUtil.throwErrIf(response); + } + } noticeSuccess(subject, workerInfo.getWorkerName()); } catch (Exception e) { log.error("err", e); @@ -415,6 +454,63 @@ public class IccWorkerCall implements WorkerManufacturer { return IccHttpUtil.checkFace(Base64Util.convertFileToBase64WithPrefix(file.getAbsolutePath()), config); } + @Override + public void saveWorkerAttendances(Date beginTime, Date endTime) { + List workerAttendancelist = Lists.newArrayList(); + QueryRecordRequest queryRecordRequest = new QueryRecordRequest(); + queryRecordRequest.setStartSwingTime(DateUtil.formatDateTime(beginTime)); + queryRecordRequest.setEndSwingTime(DateUtil.formatDateTime(endTime)); + Project project = projectService.getOne(new LambdaQueryWrapper() + .eq(Project::getProjectSn, config.getProjectSn())); + queryRecordRequest.setDeptIds(String.valueOf(project.getIccId())); + queryRecordRequest.setPageNum(1); + queryRecordRequest.setPageSize(20); + QueryRecordResponse response = null; + //获取门禁记录数量 + Integer totalRows = IccHttpUtil.getRecordCount(queryRecordRequest, config); + //获取总页数 + Integer totalPage = (totalRows - 1) / queryRecordRequest.getPageSize() + 1; + for (int i = 1; i <= totalPage; i++) { + //获取每一页门禁记录 + queryRecordRequest.setPageNum(i); + response = IccHttpUtil.queryWorkerAttendances(queryRecordRequest, config); + IccHttpUtil.throwErrIf(response); + QueryRecordResponse.Data data = response.getData(); + if (CollUtil.isNotEmpty(data.getPageData())) { + for (QueryRecordResponse.Data.PageData pageData : data.getPageData()) { + try { + WorkerInfo workerInfo = workerInfoService.getOne(new LambdaQueryWrapper() + .eq(WorkerInfo::getIdCard, pageData.getPaperNumber()) + .eq(WorkerInfo::getProjectSn, config.getProjectSn()) + ); + if (workerInfo == null) { + log.error("未找到该人员信息,personName:{}", pageData.getPersonName()); + continue; + } + UfaceDev ufaceDev = ufaceDevService.getOne(new LambdaQueryWrapper() + .eq(UfaceDev::getDevSn, pageData.getChannelName())); + if (ufaceDev == null) { + log.error("未找到该设备信息,channelName:{}", pageData.getChannelName()); + continue; + } + HashMap map = new HashMap<>(16); + map.put("passTime", pageData.getCreateTime()); + map.put("idCard", pageData.getPaperNumber()); + map.put("attendanceNumber", workerInfo.getAttendanceNumber()); + map.put("direction", workerAttendanceServiceImpl.getPassType(ufaceDev, pageData.getCreateTime())); + map.put("passType", 2); + map.put("projectCode", workerInfo.getProjectSn()); + map.put("devCode", pageData.getChannelCode()); + map.put("faceUrl", IccHttpUtil.downFile(pageData.getRecordImageUrl(), config)); + workerAttendanceService.saveExternalPassRecord(map); + } catch (Exception e) { + log.error("保存icc考勤失败:", e); + } + } + } + } + } + /** * 检测人脸响应response */ @@ -501,6 +597,85 @@ public class IccWorkerCall implements WorkerManufacturer { NATION_MAP.put("基诺族", 56); } + /** + * 删除单个人员权限 + * + * @param personCode + * @param config + * @return + */ + public static GeneralResponse deletePersonAuth(String personCode, List devSns, ProjectUfaceConfig config) { + try { + JSONObject body = new JSONObject(); + body.put("personCode", personCode); + body.put("deleteDetails", devSns.stream().map(devSn -> { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("privilegeType", 1); + jsonObject.put("resourceCode", devSn); + return jsonObject; + }).collect(Collectors.toList())); + printReq(body, "删除单个人员权限"); + GeneralResponse response = HttpUtils.executeJson("/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/personAuthority/deleteSinglePrivilege", body, null, Method.POST, getOauthConfig(config), GeneralResponse.class); + printResp(response, "删除单个人员权限"); + return response; + } catch (Exception e) { + throw new OpenAlertException("删除单个人员权限请求异常,请联系管理员", e); + } + } + + /** + * 批量删除人员所有权限 + * + * @param personCodes + * @param config + * @return + */ + public static GeneralResponse deletePersonAllAuth(List personCodes, ProjectUfaceConfig config) { + try { + JSONObject body = new JSONObject(); + body.put("personCodes", personCodes); + printReq(body, "批量删除人员权限"); + GeneralResponse response = HttpUtils.executeJson("/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/personAuthority/deleteBatch", body, null, Method.POST, getOauthConfig(config), GeneralResponse.class); + printResp(response, "批量删除人员权限"); + return response; + } catch (OpenAlertException e) { + throw e; + } catch (Exception e) { + throw new OpenAlertException("请求异常,请联系管理员", e); + } + } + + /** + * 批量按人新增授权 + * + * @param personCodes + * @param config + * @return + */ + public static GeneralResponse addPersonAuth(List personCodes, List devSns, ProjectUfaceConfig config) { + PersonAuthRequest personAuthRequest = new PersonAuthRequest(); + personAuthRequest.setPersonCodes(personCodes); + personAuthRequest.setTimeQuantumId(1l); + List privilegeDetails = new ArrayList<>(); + for (String devSn : devSns) { + //按通道授权 + PersonAuthRequest.PrivilegeDetail privilegeDetail1 = new PersonAuthRequest.PrivilegeDetail(); + privilegeDetail1.setPrivilegeType(1); + privilegeDetail1.setResourceCode(devSn); + privilegeDetails.add(privilegeDetail1); + } + personAuthRequest.setPrivilegeDetails(privilegeDetails); + GeneralResponse response = null; + try { + printReq(personAuthRequest, "批量按人新增授权"); + response = HttpUtils.executeJson("/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/personAuthority/batchAuthority", personAuthRequest, null, Method.POST, getOauthConfig(config), GeneralResponse.class); + printResp(response, "批量按人新增授权"); + } catch (ClientException e) { + throw new OpenAlertException(e.getMessage(), e); + } + return response; + } + /** * 人员详情信息获取(根据人员证件号获取) * @@ -581,13 +756,25 @@ public class IccWorkerCall implements WorkerManufacturer { * @throws ClientException */ public static String getAuthorizationValue(ProjectUfaceConfig config) { + IccTokenResponse.IccToken accessToken = getToken(config); + return accessToken.getToken_type() + " " + accessToken.getAccess_token(); + } + + /** + * 获取token + * + * @param config + * @return + * @throws ClientException + */ + public static IccTokenResponse.IccToken getToken(ProjectUfaceConfig config) { IccTokenResponse.IccToken accessToken = null; try { accessToken = HttpUtils.getToken(getOauthConfig(config)); } catch (ClientException e) { throw new OpenAlertException("获取icc的token失败,请联系管理员", e); } - return accessToken.getToken_type() + " " + accessToken.getAccess_token(); + return accessToken; } /** @@ -910,6 +1097,53 @@ public class IccWorkerCall implements WorkerManufacturer { printResp(response, "人员新增"); return response; } + + /** + * 查询门禁记录数量 + */ + public static Integer getRecordCount(QueryRecordRequest queryRecordRequest, ProjectUfaceConfig config) { + QueryRecordCountResponse response = null; + try { + printReq(queryRecordRequest, "查询门禁记录数量"); + response = HttpUtils.executeJson("/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/swingCardRecord/bycondition/combinedCount", queryRecordRequest, null, Method.POST, getOauthConfig(config), QueryRecordCountResponse.class); + printResp(response, "查询门禁记录数量"); + } catch (ClientException e) { + throw new OpenAlertException(e.getErrMsg(), e); + } + return response.getData(); + } + + /** + * 查询门禁记录 + * + * @param config + * @return + */ + public static QueryRecordResponse queryWorkerAttendances(QueryRecordRequest queryRecordRequest, ProjectUfaceConfig config) { + QueryRecordResponse response = null; + try { + printReq(queryRecordRequest, "查询门禁记录"); + response = HttpUtils.executeJson("/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/swingCardRecord/bycondition/combined", queryRecordRequest, null, Method.POST, getOauthConfig(config), QueryRecordResponse.class); + printReq(response, "查询门禁记录"); + } catch (ClientException e) { + throw new OpenAlertException(e.getErrMsg(), e); + } + return response; + } + + /** + * 下载文件 + * + * @param uri + * @param config + * @return + */ + public static File downFile(String uri, ProjectUfaceConfig config) { + //https://<平台IP>:<平台端口>/evo-apigw/evo-oss/URI?token=access_token + String url = StrUtil.format("https://{}:{}/evo-apigw/evo-oss/{}?token={}", config.getIccIp(), config.getIccPort(), uri, getToken(config).getAccess_token()); + log.info("url:{}", url); + return com.zhgd.jeecg.common.util.pass.HttpUtils.downloadFile(url, PathUtil.getBasePath(), null); + } } /** diff --git a/src/main/java/com/zhgd/xmgl/call/api/WorkerManufacturer.java b/src/main/java/com/zhgd/xmgl/call/api/WorkerManufacturer.java index 452dac757..4f6f3e943 100644 --- a/src/main/java/com/zhgd/xmgl/call/api/WorkerManufacturer.java +++ b/src/main/java/com/zhgd/xmgl/call/api/WorkerManufacturer.java @@ -3,12 +3,11 @@ package com.zhgd.xmgl.call.api; import com.zhgd.xmgl.call.IccWorkerCall; import com.zhgd.xmgl.modules.project.entity.Project; import com.zhgd.xmgl.modules.project.entity.ProjectUfaceConfig; -import com.zhgd.xmgl.modules.worker.entity.DepartmentInfo; -import com.zhgd.xmgl.modules.worker.entity.EnterpriseInfo; -import com.zhgd.xmgl.modules.worker.entity.TeamInfo; -import com.zhgd.xmgl.modules.worker.entity.WorkerInfo; +import com.zhgd.xmgl.modules.worker.entity.*; import java.io.File; +import java.util.Date; +import java.util.List; /** * 同步第三方劳务接口 @@ -88,7 +87,7 @@ public interface WorkerManufacturer { void saveWorkerInfoStatus(WorkerInfo workerInfo); /** - * 保存劳务人员门禁权限 + * 同步劳务人员门禁权限 * * @param workerInfo */ @@ -108,4 +107,13 @@ public interface WorkerManufacturer { * @return */ IccWorkerCall.CheckFaceResp checkFace(File file); + + /** + * 保存外部的门禁记录 + * + * @param beginTime + * @param endTime + */ + void saveWorkerAttendances(Date beginTime, Date endTime); + } diff --git a/src/main/java/com/zhgd/xmgl/modules/worker/service/impl/WorkerInfoServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/worker/service/impl/WorkerInfoServiceImpl.java index d3cf175b1..30e89f32a 100644 --- a/src/main/java/com/zhgd/xmgl/modules/worker/service/impl/WorkerInfoServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/worker/service/impl/WorkerInfoServiceImpl.java @@ -550,7 +550,7 @@ public class WorkerInfoServiceImpl extends ServiceImpl { workerManufacturer.saveWorkerInfo(workerInfo); - }, threadPoolTaskExecutor).thenRun(() -> { + }, threadPoolTaskExecutor).thenRunAsync(() -> { workerManufacturer.saveWorkerUFaceAuth(workerInfo); }); } diff --git a/src/main/java/com/zhgd/xmgl/task/ProjectTask.java b/src/main/java/com/zhgd/xmgl/task/ProjectTask.java index 7d2c11de7..9742500fe 100644 --- a/src/main/java/com/zhgd/xmgl/task/ProjectTask.java +++ b/src/main/java/com/zhgd/xmgl/task/ProjectTask.java @@ -1,10 +1,13 @@ package com.zhgd.xmgl.task; +import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zhgd.jeecg.common.mybatis.EntityMap; import com.zhgd.xmgl.async.AsyncAttendance; import com.zhgd.xmgl.async.AsyncCommon; +import com.zhgd.xmgl.call.api.WorkerManufacturer; +import com.zhgd.xmgl.call.factory.WorkerManufacturerFactory; import com.zhgd.xmgl.modules.basicdata.mapper.VerificationCodeMapper; import com.zhgd.xmgl.modules.basicdata.service.ISystemUserService; import com.zhgd.xmgl.modules.environment.entity.AirQualityAnalysis; @@ -19,6 +22,7 @@ import com.zhgd.xmgl.modules.project.service.impl.ProjectServiceImpl; import com.zhgd.xmgl.modules.standard.entity.StandardSampleNotice; import com.zhgd.xmgl.modules.standard.mapper.StandardSampleNoticeMapper; import com.zhgd.xmgl.modules.standard.mapper.StandardSampleRecordMapper; +import com.zhgd.xmgl.modules.worker.entity.WorkerAttendance; import com.zhgd.xmgl.modules.worker.mapper.WorkerAttendancePresenceMapper; import com.zhgd.xmgl.modules.worker.service.IWorkerAttendanceRuleV2Service; import com.zhgd.xmgl.modules.worker.service.IWorkerAttendanceService; @@ -90,6 +94,9 @@ public class ProjectTask { @Lazy @Autowired private AsyncAttendance asyncAttendance; + @Lazy + @Autowired + private WorkerManufacturerFactory workerManufacturerFactory; /** * 定时清除无效的校验码 @@ -317,5 +324,22 @@ public class ProjectTask { workerAttendancePresenceMapper.deleteAttendancePresence(); } + /** + * 定时保存外部获取的考勤数据 + */ + @SchedulerLock(name = "saveWorkerAttendances", lockAtMostFor = 1000 * 30, lockAtLeastFor = 1000 * 30) + @Scheduled(cron = "0 */1 * * * ?") + @RequestMapping("saveWorkerAttendances") + public void saveWorkerAttendances() { + DateTime startTime = DateUtil.offsetMinute(new Date(), -2); + Date endTime = new Date(); + List projects = projectMapper.selectList(null); + for (Project project : projects) { + WorkerManufacturer workerManufacturer = workerManufacturerFactory.getWorkerManufacturer(project.getProjectSn()); + if (workerManufacturer != null) { + workerManufacturer.saveWorkerAttendances(startTime, endTime); + } + } + } }