package com.zhgd.xmgl.call; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.dahuatech.icc.brm.model.v202010.department.*; import com.dahuatech.icc.brm.model.v202010.person.BrmPersonDelResponse; 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.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.PersonAddRequest; import com.dahuatech.icc.model.brm.person.PersonAddResponse; import com.dahuatech.icc.model.brm.person.PersonPageRequest; import com.dahuatech.icc.model.brm.person.PersonPageResponse; import com.dahuatech.icc.oauth.http.IccTokenResponse; import com.dahuatech.icc.oauth.model.v202010.GeneralResponse; import com.dahuatech.icc.oauth.utils.HttpUtils; import com.gexin.fastjson.JSON; import com.gexin.fastjson.TypeReference; import com.zhgd.xmgl.call.api.WorkerManufacturer; import com.zhgd.xmgl.call.util.IccHttpUtil; import com.zhgd.xmgl.constant.Cts; import com.zhgd.xmgl.modules.basicdata.service.impl.NoticeServiceImpl; import com.zhgd.xmgl.modules.car.service.impl.CarInfoServiceImpl; import com.zhgd.xmgl.modules.project.entity.Project; 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.project.service.IProjectUfaceConfigService; import com.zhgd.xmgl.modules.worker.entity.*; import com.zhgd.xmgl.modules.worker.mapper.DepartmentInfoMapper; 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.entity.XzHikvisionSync; import com.zhgd.xmgl.modules.xz.service.IXzHikvisionCompareDataService; import com.zhgd.xmgl.modules.xz.service.impl.XzHikvisionSyncServiceImpl; import com.zhgd.xmgl.util.Base64Util; import com.zhgd.xmgl.util.MapBuilder; 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.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.io.File; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @Slf4j @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class IccWorkerCall implements WorkerManufacturer { /** * 发送通知用 */ private static final ThreadLocal noticeSubject = new ThreadLocal<>(); @Autowired @Lazy public WorkerInfoServiceImpl workerInfoService; @Autowired @Lazy public IProjectUfaceConfigService projectUfaceConfigService; @Lazy @Autowired public CarInfoServiceImpl carInfoService; @Lazy @Autowired XzHikvisionSyncServiceImpl xzHikvisionSyncService; @Lazy @Autowired private IProjectService projectService; private Long noticeUser; @Lazy @Autowired private EnterpriseInfoServiceImpl enterpriseInfoService; private ProjectUfaceConfig config; @Lazy @Autowired private IProjectEnterpriseService projectEnterpriseService; @Lazy @Autowired private IDepartmentInfoService departmentInfoService; @Lazy @Autowired private ITeamInfoService teamInfoService; @Lazy @Autowired private NoticeServiceImpl noticeService; @Autowired @Lazy private IWorkerAttendanceService workerAttendanceService; @Autowired @Lazy private WorkerAttendanceServiceImpl workerAttendanceServiceImpl; @Lazy @Resource private IUfaceDevService ufaceDevService; @Lazy @Autowired private IXzHikvisionCompareDataService xzHikvisionCompareDataService; @Lazy @Autowired private DepartmentInfoMapper departmentInfoMapper; public static void main(String[] args) throws ClientException { IccTokenResponse.IccToken accessToken = HttpUtils.getToken(OauthConfigUtil.getOauthConfig()); System.out.println(accessToken.getToken_type() + " " + accessToken.getAccess_token()); } @Override public ProjectUfaceConfig getConfig() { return config; } @Override public void setConfig(ProjectUfaceConfig config) { this.config = config; } @Override public void setNoticeUser(Long noticeUser) { this.noticeUser = noticeUser; } @Override public void saveEnterpriseInfo(EnterpriseInfo enterpriseInfo) { String subject = getAndSetSubjectIfNotExist("保存单位"); try { Project project = projectService.getOne(new LambdaQueryWrapper() .eq(Project::getProjectSn, enterpriseInfo.getProjectSn())); if (project.getIccId() == null) { //保存项目的部门 saveProject(project); } if (enterpriseInfo.getIccId() == null) { EnterpriseInfo enterprise = enterpriseInfoService.getEnterpriseByProjectSnAndEnterpriseId(config.getProjectSn(), enterpriseInfo.getId()); enterpriseInfo.setIccId(enterprise.getIccId()); } saveIccDepartment(iccId1 -> { enterpriseInfo.setIccId(iccId1); projectEnterpriseService.update(null, new LambdaUpdateWrapper() .set(ProjectEnterprise::getIccId, iccId1) .eq(ProjectEnterprise::getProjectSn, config.getProjectSn()) .eq(ProjectEnterprise::getEnterpriseId, enterpriseInfo.getId()) ); }, project.getIccId(), enterpriseInfo.getIccId(), enterpriseInfo.getEnterpriseName()); noticeSuccess(subject, enterpriseInfo.getEnterpriseName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, enterpriseInfo.getEnterpriseName(), e.getMessage(), false); } } /** * 获取并设置(不存在)subject * * @param subject * @return */ private String getAndSetSubjectIfNotExist(String subject) { if (noticeSubject.get() == null) { noticeSubject.set(subject); } return subject; } /** * 发成功通知 * * @param subject * @param name * @param alwaysShow */ private void noticeSuccess(String subject, String name, boolean alwaysShow) { if (alwaysShow || subject.equals(noticeSubject.get())) { noticeService.addUserNotice(noticeUser, subject + "到ICC通知", subject + "<<" + name + ">>到ICC成功", "1"); } } /** * 发失败通知 * * @param subject * @param name * @param failedMsg * @param alwaysShow */ private void noticeFailed(String subject, String name, String failedMsg, boolean alwaysShow) { if (alwaysShow || subject.equals(noticeSubject.get())) { noticeService.addUserNotice(noticeUser, subject + "到ICC通知", subject + "<<" + name + ">>到ICC失败,失败原因:" + failedMsg, "1"); } } @Override public void deleteEnterpriseInfo(EnterpriseInfo enterpriseInfo) { String subject = getAndSetSubjectIfNotExist("删除单位"); try { deleteIccDepartmentByIccId(enterpriseInfo.getIccId()); noticeSuccess(subject, enterpriseInfo.getEnterpriseName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, enterpriseInfo.getEnterpriseName(), e.getMessage(), false); } } @Override public void saveDepartmentInfo(DepartmentInfo departmentInfo) { String subject = getAndSetSubjectIfNotExist("保存部门"); try { EnterpriseInfo enterpriseInfo = enterpriseInfoService.getEnterpriseByProjectSnAndEnterpriseId(config.getProjectSn(), departmentInfo.getEnterpriseId()); saveEnterpriseInfo(enterpriseInfo); saveIccDepartment(iccId1 -> { departmentInfo.setIccId(iccId1); departmentInfoService.updateById(departmentInfo); }, enterpriseInfo.getIccId(), departmentInfo.getIccId(), departmentInfo.getDepartmentName() + "(部门)"); noticeSuccess(subject, departmentInfo.getDepartmentName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, departmentInfo.getDepartmentName(), e.getMessage(), false); } } /** * 保存icc部门 * * @param updateConsumer * @param pid * @param iccId * @param name */ private void saveIccDepartment(Consumer updateConsumer, Long pid, Long iccId, String name) { BrmDeptQueryResponse.DeptPageData data = IccHttpUtil.getDepartmentById(iccId, config); if (data == null) { BrmDeptAddResponse response = IccHttpUtil.addDepartment(pid, name, config); if (response.isSuccess()) { updateConsumer.accept(response.getData().getId()); } else if (response.getCode().equals("28170001")) { //名称已存在,mysql保存里面的iccId BrmDeptPageRequest request = new BrmDeptPageRequest(); request.setParentId(pid); request.setPageNum(1); request.setPageSize(1000); request.setSearchKey(name); BrmDeptPageResponse pageResp = IccHttpUtil.getDepartmentPage(request, config); if (pageResp.isSuccess()) { Long qid = pageResp.getData().getPageData().stream().filter(dp -> dp.getName().equals(name)).findFirst().map(BrmDeptPageResponse.DeptPageList::getId).orElse(null); updateConsumer.accept(qid); } else { IccHttpUtil.throwErrIf(pageResp); } } else { IccHttpUtil.throwErrIf(response); } } else { if (!Objects.equals(data.getName(), name)) { BrmDeptUpdateResponse response = IccHttpUtil.updateDepartment(pid, iccId, name, config); IccHttpUtil.throwErrIf(response); } } } @Override public void deleteDepartmentInfo(DepartmentInfo departmentInfo) { String subject = getAndSetSubjectIfNotExist("删除部门"); try { deleteIccDepartmentByIccId(departmentInfo.getIccId()); noticeSuccess(subject, departmentInfo.getDepartmentName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, departmentInfo.getDepartmentName(), e.getMessage(), false); } } /** * 删除icc部门通过iccId * * @param iccId */ private void deleteIccDepartmentByIccId(Long iccId) { if (iccId == null) { return; } DepartmentUpdateResponse response = IccHttpUtil.deleteDepartment(iccId, config); if (response.isSuccess() || response.getCode().equals("28170002")) { //28170002:部门不存在 } else { IccHttpUtil.throwErrIf(response); } } @Override public void saveTeamInfo(TeamInfo teamInfo) { String subject = getAndSetSubjectIfNotExist("保存班组"); try { EnterpriseInfo enterpriseInfo = enterpriseInfoService.getEnterpriseByProjectSnAndEnterpriseId(config.getProjectSn(), teamInfo.getEnterpriseId()); saveEnterpriseInfo(enterpriseInfo); saveIccDepartment(iccId -> { teamInfo.setIccId(iccId); teamInfoService.updateById(teamInfo); }, enterpriseInfo.getIccId(), teamInfo.getIccId(), teamInfo.getTeamName() + "(班组)"); noticeSuccess(subject, teamInfo.getTeamName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, teamInfo.getTeamName(), e.getMessage(), false); } } @Override public void deleteTeamInfo(TeamInfo teamInfo) { String subject = getAndSetSubjectIfNotExist("删除班组"); try { deleteIccDepartmentByIccId(teamInfo.getIccId()); noticeSuccess(subject, teamInfo.getTeamName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, teamInfo.getTeamName(), e.getMessage(), false); } } @Override public void saveProject(Project newProject) { String subject = getAndSetSubjectIfNotExist("保存项目"); try { saveIccDepartment(iccId -> { Project project = new Project(); project.setProjectId(newProject.getProjectId()); project.setIccId(iccId); newProject.setIccId(iccId); projectService.updateById(project); }, 1L, newProject.getIccId(), newProject.getProjectName()); noticeSuccess(subject, newProject.getProjectName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, newProject.getProjectName(), e.getMessage(), false); throw e; } } @Override public void saveWorkerAndFace(WorkerInfo workerInfo) { saveWorker(workerInfo); saveWorkerFace(workerInfo); } @Override public void saveWorker(WorkerInfo workerInfo) { String subject = getAndSetSubjectIfNotExist("保存劳务人员"); try { BrmPersonQueryByIdCardResponse idCardResponse = IccHttpUtil.getByPaperNumber(workerInfo.getIdCard(), config); WorkerInfoExt workerInfoExt = new WorkerInfoExt(); BeanUtil.copyProperties(workerInfo, workerInfoExt); workerInfoExt.setIccDepartmentId(getIccDepartmentId(workerInfo)); if (idCardResponse.getData() == null || idCardResponse.getData().getId() == null) { PersonAddResponse response = IccHttpUtil.addWorker(workerInfoExt, config); if (response.isSuccess()) { workerInfo.setIccId(response.getData().getId()); workerInfoService.updateById(workerInfo); } else { IccHttpUtil.throwErrIf(response); } } else { if (!Objects.equals(idCardResponse.getData().getId(), workerInfo.getIccId())) { workerInfo.setIccId(idCardResponse.getData().getId()); workerInfoService.updateById(workerInfo); } PersonAddResponse response = IccHttpUtil.updateWorker(workerInfoExt, config); IccHttpUtil.throwErrIf(response); } updateProcessStatus(workerInfo.getId(), 1, 1); noticeSuccess(subject, workerInfo.getWorkerName(), true); } catch (Exception e) { log.error("err", e); updateProcessStatus(workerInfo.getId(), 1, 0); noticeFailed(subject, workerInfo.getWorkerName(), e.getMessage(), true); } } @Override public void saveWorkerFace(WorkerInfo workerInfo) { String subjectFace = getAndSetSubjectIfNotExist("保存劳务人员人脸"); try { //保存人脸 if (StrUtil.isNotBlank(workerInfo.getFieldAcquisitionUrl())) { try { GeneralResponse workerFaceResponse = IccHttpUtil.saveWorkerFace(workerInfo.getIccId(), workerInfo.getFieldAcquisitionUrl(), config); IccHttpUtil.throwErrIf(workerFaceResponse); updateProcessStatus(workerInfo.getId(), 2, 1); noticeSuccess(subjectFace, workerInfo.getWorkerName(), true); } catch (Exception e) { log.error("err", e); noticeFailed(subjectFace, workerInfo.getWorkerName(), e.getMessage(), true); } } } catch (Exception e) { log.error("err", e); if (StrUtil.isNotBlank(workerInfo.getFieldAcquisitionUrl())) { updateProcessStatus(workerInfo.getId(), 2, 0); noticeFailed(subjectFace, workerInfo.getWorkerName(), e.getMessage(), true); } } } /** * 根据下发进度状态 * * @param whoId * @param type * @param isSuccess */ @Transactional(rollbackFor = Exception.class) public void updateProcessStatus(Long whoId, int type, int isSuccess) { xzHikvisionSyncService.updateStatusByWhoId(1, whoId, type, isSuccess); updateTotalStatus(whoId); } @Override @Transactional(rollbackFor = Exception.class) public void saveWorkerProcessStatus(WorkerInfo workerInfo) { xzHikvisionSyncService.remove(new LambdaQueryWrapper() .eq(XzHikvisionSync::getBigType, 1) .eq(XzHikvisionSync::getWhoId, workerInfo.getId()) ); List adds = new ArrayList<>(); adds.add(new XzHikvisionSync(workerInfo.getProjectSn(), workerInfo.getId(), 1, 1, 1, Convert.toStr(noticeUser))); if (StrUtil.isNotBlank(workerInfo.getFieldAcquisitionUrl())) { adds.add(new XzHikvisionSync(workerInfo.getProjectSn(), workerInfo.getId(), 2, 1, 1, Convert.toStr(noticeUser))); Pair sendAndDeleteDevSns = projectUfaceConfigService.getSendAndDeleteDevSns(workerInfo); if (StrUtil.isNotBlank(sendAndDeleteDevSns.getLeft())) { for (String devSn : StrUtil.split(sendAndDeleteDevSns.getLeft(), ",")) { adds.add(new XzHikvisionSync(workerInfo.getProjectSn(), workerInfo.getId(), 3, 1, 1, Convert.toStr(noticeUser), devSn)); } } if (StrUtil.isNotBlank(sendAndDeleteDevSns.getRight())) { for (String devSn : StrUtil.split(sendAndDeleteDevSns.getRight(), ",")) { adds.add(new XzHikvisionSync(workerInfo.getProjectSn(), workerInfo.getId(), 3, 3, 1, Convert.toStr(noticeUser), devSn)); } } } xzHikvisionSyncService.saveBatch(adds); workerInfoService.update(null, new LambdaUpdateWrapper() .set(WorkerInfo::getSendSuccessStatus, 4) .eq(WorkerInfo::getId, workerInfo.getId()) ); } @Override @Transactional(rollbackFor = Exception.class) public void saveWorkerAuthProcessStatus(WorkerInfo workerInfo) { xzHikvisionSyncService.remove(new LambdaQueryWrapper() .eq(XzHikvisionSync::getBigType, 1) .eq(XzHikvisionSync::getWhoId, workerInfo.getId()) ); List adds = new ArrayList<>(); if (StrUtil.isNotBlank(workerInfo.getFieldAcquisitionUrl())) { Pair sendAndDeleteDevSns = projectUfaceConfigService.getSendAndDeleteDevSns(workerInfo); if (StrUtil.isNotBlank(sendAndDeleteDevSns.getLeft())) { for (String devSn : StrUtil.split(sendAndDeleteDevSns.getLeft(), ",")) { adds.add(new XzHikvisionSync(workerInfo.getProjectSn(), workerInfo.getId(), 3, 1, 1, Convert.toStr(noticeUser), devSn)); } } if (StrUtil.isNotBlank(sendAndDeleteDevSns.getRight())) { for (String devSn : StrUtil.split(sendAndDeleteDevSns.getRight(), ",")) { adds.add(new XzHikvisionSync(workerInfo.getProjectSn(), workerInfo.getId(), 3, 3, 1, Convert.toStr(noticeUser), devSn)); } } } xzHikvisionSyncService.saveBatch(adds); workerInfoService.update(null, new LambdaUpdateWrapper() .set(WorkerInfo::getSendSuccessStatus, 4) .eq(WorkerInfo::getId, workerInfo.getId()) ); } /** * 获取icc部门id * * @param workerInfo * @return */ private Long getIccDepartmentId(WorkerInfo workerInfo) { Long iccId; if (Objects.equals(workerInfo.getPersonType(), 1)) { TeamInfo teamInfo = teamInfoService.getById(workerInfo.getTeamId()); if (teamInfo.getIccId() == null) { saveTeamInfo(teamInfo); } iccId = teamInfo.getIccId(); } else { DepartmentInfo departmentInfo = departmentInfoService.getById(workerInfo.getDepartmentId()); if (departmentInfo.getIccId() == null) { saveDepartmentInfo(departmentInfo); } iccId = departmentInfo.getIccId(); } return iccId; } @Override public void saveWorkerUFaceAuth(WorkerInfo workerInfo) { try { Pair sendAddDeleteDevSns = projectUfaceConfigService.getSendAndDeleteDevSns(workerInfo); saveWorkerUFaceAuthToOneDev(workerInfo, sendAddDeleteDevSns); } catch (Exception e) { log.error("err", e); } } @Override public void saveWorkerUFaceAuthToOneDev(WorkerInfo workerInfo, Pair sendAddDeleteDevSns) { List addDevSns = StrUtil.split(sendAddDeleteDevSns.getLeft(), ","); List deleteDevSns = StrUtil.split(sendAddDeleteDevSns.getRight(), ","); List personCodes = Collections.singletonList(workerInfo.getPersonSn()); if (CollUtil.isEmpty(addDevSns) && CollUtil.isNotEmpty(deleteDevSns)) { IccHttpUtil.deleteWorkerAllAuth(personCodes, config); } else { if (CollUtil.isNotEmpty(addDevSns)) { GeneralResponse response = IccHttpUtil.addWorkerAuth(personCodes, addDevSns, config); IccHttpUtil.throwErrIf(response); } if (CollUtil.isNotEmpty(deleteDevSns)) { GeneralResponse response = IccHttpUtil.deleteWorkerAuth(workerInfo.getPersonSn(), deleteDevSns, config); IccHttpUtil.throwErrIf(response); } } } @Override public void deleteWorker(WorkerInfo workerInfo) { String subject = getAndSetSubjectIfNotExist("删除劳务人员"); try { List iccIds = new ArrayList<>(); iccIds.add(workerInfo.getIccId()); BrmPersonDelResponse response = IccHttpUtil.deleteWorker(iccIds, config); if (response.isSuccess()) { } else { IccHttpUtil.throwErrIf(response); } noticeSuccess(subject, workerInfo.getWorkerName(), false); } catch (Exception e) { log.error("err", e); noticeFailed(subject, workerInfo.getWorkerName(), e.getMessage(), false); } } @Override public IccWorkerCall.CheckFaceResp checkFace(File file) { return IccHttpUtil.checkFace(Base64Util.convertFileToBase64WithPrefix(file.getAbsolutePath()), config); } @Override public void saveWorkerAttendances(Date beginTime, Date endTime) { 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.getWorkerAttendances(queryRecordRequest, config); IccHttpUtil.throwErrIf(response); QueryRecordResponse.Data data = response.getData(); if (CollUtil.isNotEmpty(data.getPageData())) { for (QueryRecordResponse.Data.PageData pageData : data.getPageData()) { saveWorkerAttendance(pageData.getPaperNumber(), pageData.getPersonName(), pageData.getChannelName(), pageData.getCreateTime(), pageData.getRecordImageUrl()); } } } } /** * 保存icc门禁记录 * * @param idCard * @param personName * @param devSn * @param passTime * @param faceUrl */ public void saveWorkerAttendance(String idCard, String personName, String devSn, String passTime, String faceUrl) { try { WorkerInfo workerInfo = workerInfoService.getOne(new LambdaQueryWrapper() .eq(WorkerInfo::getIdCard, idCard) .eq(WorkerInfo::getProjectSn, config.getProjectSn()) ); if (workerInfo == null) { log.error("未找到该人员信息,personName:{}", personName); return; } UfaceDev ufaceDev = ufaceDevService.getOne(new LambdaQueryWrapper() .eq(UfaceDev::getDevSn, devSn)); if (ufaceDev == null) { log.error("未找到该设备信息,channelName:{}", devSn); return; } HashMap map = new HashMap<>(16); map.put("passTime", passTime); map.put("idCard", idCard); map.put("attendanceNumber", workerInfo.getAttendanceNumber()); map.put("direction", workerAttendanceServiceImpl.getPassType(ufaceDev, passTime)); map.put("passType", 2); map.put("projectCode", workerInfo.getProjectSn()); map.put("devCode", devSn); map.put("faceUrl", IccHttpUtil.downloadOssFile(faceUrl, config).getName()); workerAttendanceService.saveExternalPassRecord(map); } catch (Exception e) { log.error("保存icc考勤失败:", e); } } @Override public void updateWorkerUfaceProcess() { Map> workerIdMap = xzHikvisionSyncService.list(new LambdaQueryWrapper() .eq(XzHikvisionSync::getProjectSn, config.getProjectSn()) .eq(XzHikvisionSync::getType, 3) .isNull(XzHikvisionSync::getIsSuccess) ).stream().collect(Collectors.groupingBy(XzHikvisionSync::getWhoId)); //过去一天还没有下发成功,默认就失败 DateTime yesterday = DateUtil.offsetDay(new Date(), -1); Map workerInfoMap = workerInfoService.list(new LambdaQueryWrapper() .eq(WorkerInfo::getProjectSn, config.getProjectSn())).stream().collect(Collectors.toMap(WorkerInfo::getId, Function.identity(), (o1, o2) -> o1)); Map devMap = ufaceDevService.list(new LambdaQueryWrapper() .eq(UfaceDev::getProjectSn, config.getProjectSn())).stream().collect(Collectors.toMap(UfaceDev::getDevSn, Function.identity(), (o1, o2) -> o1)); for (Map.Entry> entry : workerIdMap.entrySet()) { WorkerInfo worker = workerInfoMap.get(entry.getKey()); if (worker == null) { xzHikvisionSyncService.remove(new LambdaQueryWrapper() .eq(XzHikvisionSync::getWhoId, entry.getKey()) .eq(XzHikvisionSync::getBigType, 1) ); continue; } updateOneWorkerUfaceProcess(worker, devMap, entry.getValue(), yesterday); } } @Override public void saveCompareData() { //对比企业 Project project = projectService.getOne(new LambdaQueryWrapper() .eq(Project::getProjectSn, config.getProjectSn())); List httpEnterprises = getChildrenDepts(project.getIccId()); List enterpriseInfos = BeanUtil.copyToList(enterpriseInfoService.getEnterpriseInfoList(new MapBuilder().put(Cts.PROJECT_SN, config.getProjectSn()).build()), EnterpriseInfo.class); log.info("数据校验我们平台的企业列表:{}", JSON.toJSONString(enterpriseInfos)); if (CollUtil.isEmpty(httpEnterprises)) { for (EnterpriseInfo enterpriseInfo : enterpriseInfos) { xzHikvisionCompareDataService.addCompareDataForEnterprise(project, enterpriseInfo.getEnterpriseName(), 0, 1, String.valueOf(enterpriseInfo.getId())); compareHikvisionForDepartmentAndTeamEtc(project, enterpriseInfo.getIccId(), enterpriseInfo.getId()); } } else { //isc存在,平台也存在 HashSet nameSet = new HashSet<>(); enterpriseInfos.forEach(enterpriseInfo -> nameSet.add(enterpriseInfo.getEnterpriseName())); httpEnterprises.forEach(o -> nameSet.add(o.getName())); Map iccMap = httpEnterprises.stream().collect(Collectors.toMap(BrmDeptPageResponse.DeptPageList::getName, Function.identity(), (o, o2) -> o2)); Map myMap = enterpriseInfos.stream().collect(Collectors.toMap(EnterpriseInfo::getEnterpriseName, Function.identity(), (o, o2) -> o2)); for (String name : nameSet) { Long orgIndex = null; Long enterpriseId = null; if (myMap.containsKey(name) && !iccMap.containsKey(name)) { orgIndex = myMap.get(name).getIccId(); enterpriseId = myMap.get(name).getId(); xzHikvisionCompareDataService.addCompareDataForEnterprise(project, name, 0, 1, enterpriseId + ""); } else if (!myMap.containsKey(name) && iccMap.containsKey(name)) { orgIndex = iccMap.get(name).getId(); enterpriseId = orgIndex; xzHikvisionCompareDataService.addCompareDataForEnterprise(project, name, 1, 0, enterpriseId + ""); } else { enterpriseId = myMap.get(name).getIccId(); orgIndex = iccMap.get(name).getId(); } compareHikvisionForDepartmentAndTeamEtc(project, orgIndex, enterpriseId); } } xzHikvisionCompareDataService.addSuccessShow(project.getProjectSn(), "1"); } /** * 获取儿子的部门列表 * * @param pIccId * @return */ private List getChildrenDepts(Long pIccId) { BrmDeptPageRequest request = new BrmDeptPageRequest(); request.setParentId(pIccId); int pageNum = 1; int pageSize = 1000; BrmDeptPageResponse departmentPage; List httpEnterprises = new ArrayList<>(); do { request.setPageNum(pageNum); request.setPageSize(pageSize); departmentPage = IccHttpUtil.getDepartmentPage(request, config); List data = departmentPage.getData().getPageData(); httpEnterprises.addAll(data); } while (pageNum++ * pageSize < departmentPage.getTotalRows()); return httpEnterprises; } /** * 对比班组和部门 * * @param project * @param orgIndex * @param enterpriseId * @throws Exception */ private void compareHikvisionForDepartmentAndTeamEtc(Project project, Long orgIndex, Long enterpriseId) { List teamDepartMentDepts = getChildrenDepts(orgIndex); List teamList = teamInfoService.getProjectTeamList(new MapBuilder() .put(Cts.PROJECT_SN, project.getProjectSn()).put(Cts.ENTERPRISE_ID, enterpriseId).build()); log.info("数据校验我们平台的班组列表:{}", JSON.toJSONString(teamList)); List departmentInfoList = departmentInfoMapper.getDepartmentInfoList(new MapBuilder() .put(Cts.PROJECT_SN, project.getProjectSn()).put(Cts.ENTERPRISE_ID, enterpriseId).build()); log.info("数据校验我们平台的部门列表:{}", JSON.toJSONString(departmentInfoList)); if (CollUtil.isEmpty(teamDepartMentDepts)) { for (TeamInfo teamInfo : teamList) { xzHikvisionCompareDataService.addCompareDataForTeam(project, teamInfo.getTeamName(), 0, 1, String.valueOf(teamInfo.getId())); compareHikvisionForWorker(project, teamInfo.getIccId(), 1); } for (DepartmentInfo departmentInfo : departmentInfoList) { xzHikvisionCompareDataService.addCompareDataForDepartment(project, departmentInfo.getDepartmentName(), 0, 1, String.valueOf(departmentInfo.getId())); compareHikvisionForWorker(project, departmentInfo.getId(), 2); } } else { //isc存在,平台也存在 HashSet nameSet = new HashSet<>(); teamList.forEach(teamInfo -> nameSet.add(teamInfo.getTeamName())); departmentInfoList.forEach(departmentInfo -> nameSet.add(departmentInfo.getDepartmentName())); teamDepartMentDepts.forEach(o -> nameSet.add(o.getName())); Map iscMap = teamDepartMentDepts.stream().collect(Collectors.toMap(BrmDeptPageResponse.DeptPageList::getName, Function.identity(), (o, o2) -> o2)); Map myTeamMap = teamList.stream().collect(Collectors.toMap(TeamInfo::getTeamName, Function.identity(), (o, o2) -> o2)); Map myDepartmentMap = departmentInfoList.stream().collect(Collectors.toMap(DepartmentInfo::getDepartmentName, Function.identity(), (o, o2) -> o2)); for (String name : nameSet) { Long iccId; Integer type = null; if (myTeamMap.containsKey(name) && !iscMap.containsKey(name)) { iccId = myTeamMap.get(name).getId(); xzHikvisionCompareDataService.addCompareDataForTeam(project, name, 0, 1, iccId + ""); type = 1; } else if (myDepartmentMap.containsKey(name) && !iscMap.containsKey(name)) { iccId = myDepartmentMap.get(name).getId(); xzHikvisionCompareDataService.addCompareDataForDepartment(project, name, 0, 1, iccId + ""); type = 2; } else if ((!myTeamMap.containsKey(name) && !myDepartmentMap.containsKey(name)) && iscMap.containsKey(name)) { iccId = iscMap.get(name).getId(); xzHikvisionCompareDataService.addCompareDataForTeam(project, name, 1, 0, iccId + ""); type = 1; } else if (myTeamMap.containsKey(name) && iscMap.containsKey(name)) { //班组存在和isc存在 iccId = myTeamMap.get(name).getId(); type = 1; } else { //部门存在和isc存在 iccId = myDepartmentMap.get(name).getId(); type = 2; } compareHikvisionForWorker(project, iccId, type); } } xzHikvisionCompareDataService.addSuccessShow(project.getProjectSn(), "1"); } /** * 对比人员 * * @param project * @param orgIndex * @param type 1班组 2部门 * @throws Exception */ private void compareHikvisionForWorker(Project project, Long orgIndex, Integer type) { List httpWorkers = getWorkersByDepartmentId(orgIndex); IPage workerPage = workerInfoService.selectWorkerInfoList(new MapBuilder() .put(Cts.PROJECT_SN, project.getProjectSn()) .put(type == 1, Cts.TEAM_ID, orgIndex) .put(type == 2, Cts.DEPARTMENT_ID, orgIndex) .build()); List workerInfoList = workerPage.getRecords(); log.info("数据校验我们平台的人员列表:{}", JSON.toJSONString(workerInfoList)); if (CollUtil.isEmpty(httpWorkers)) { for (WorkerInfo workerInfo : workerInfoList) { xzHikvisionCompareDataService.addCompareDataForWorker(project, workerInfo.getWorkerName(), 0, 1, String.valueOf(workerInfo.getId()), workerInfo.getIdCard()); xzHikvisionCompareDataService.addCompareDataForFace(project, workerInfo.getWorkerName(), 0, 1, String.valueOf(workerInfo.getId()), workerInfo.getIdCard()); } } else { //isc存在,平台也存在 HashSet idCardSet = new HashSet<>(); workerInfoList.forEach(workerInfo -> idCardSet.add(workerInfo.getIdCard())); httpWorkers.forEach(o -> idCardSet.add(o.getPaperNumber())); Map iscMap = httpWorkers.stream().collect(Collectors.toMap(o -> o.getPaperNumber(), Function.identity(), (o, o2) -> o2)); Map myMap = workerInfoList.stream().collect(Collectors.toMap(WorkerInfo::getIdCard, Function.identity(), (o, o2) -> o2)); for (String idCard : idCardSet) { if (myMap.containsKey(idCard) && !iscMap.containsKey(idCard)) { xzHikvisionCompareDataService.addCompareDataForWorker(project, myMap.get(idCard).getWorkerName(), 0, 1, String.valueOf(myMap.get(idCard).getId()), idCard); WorkerInfo wi = myMap.get(idCard); if (StrUtil.isNotBlank(wi.getFieldAcquisitionUrl())) { xzHikvisionCompareDataService.addCompareDataForFace(project, myMap.get(idCard).getWorkerName(), 0, 1, String.valueOf(myMap.get(idCard).getId()), idCard); } } else if (!myMap.containsKey(idCard) && iscMap.containsKey(idCard)) { xzHikvisionCompareDataService.addCompareDataForWorker(project, iscMap.get(idCard).getName(), 1, 0, iscMap.get(idCard).getId() + "", idCard); List ppJa = iscMap.get(idCard).getPersonBiosignatures().stream().filter(s -> s.getType() == 3).collect(Collectors.toList()); if (CollUtil.isNotEmpty(ppJa)) { xzHikvisionCompareDataService.addCompareDataForFace(project, iscMap.get(idCard).getName(), 1, 0, iscMap.get(idCard).getId() + "", idCard); } } else { //isc存在,平台也存在该人员 boolean myHave = StrUtil.isNotBlank(myMap.get(idCard).getFieldAcquisitionUrl()); boolean iscHave = CollUtil.isNotEmpty(iscMap.get(idCard).getPersonBiosignatures().stream().filter(s -> s.getType() == 3).collect(Collectors.toList())); if (myHave && !iscHave) { xzHikvisionCompareDataService.addCompareDataForFace(project, iscMap.get(idCard).getName(), 0, 1, String.valueOf(myMap.get(idCard).getId()), idCard); } else if (!myHave && iscHave) { xzHikvisionCompareDataService.addCompareDataForFace(project, iscMap.get(idCard).getName(), 1, 0, String.valueOf(myMap.get(idCard).getId()), idCard); } } } } xzHikvisionCompareDataService.addSuccessShow(project.getProjectSn(), "2"); xzHikvisionCompareDataService.addSuccessShow(project.getProjectSn(), "3"); } /** * 查询部门、班组下的人员列表 * * @param orgIndex * @return */ private List getWorkersByDepartmentId(Long orgIndex) { PersonPageRequest personPageRequest = new PersonPageRequest(); int pageNum = 1; int pageSize = 1000; List httpWorkers = new ArrayList<>(); PersonPageResponse workerPage; do { personPageRequest.setPageNum(pageNum); personPageRequest.setPageSize(pageSize); personPageRequest.setDepartmentId(Math.toIntExact(orgIndex)); workerPage = IccHttpUtil.getWorkerPage(personPageRequest, config); List pageData = workerPage.getData().getPageData(); httpWorkers.addAll(pageData); } while (pageNum++ * pageSize < workerPage.getData().getTotalRows()); return httpWorkers; } /** * 定时更新授权一个人员到门禁进度 * * @param worker * @param devMap * @param syncList * @param yesterday */ @Transactional(rollbackFor = Exception.class) public void updateOneWorkerUfaceProcess(WorkerInfo worker, Map devMap, List syncList, DateTime yesterday) { ArrayList devSns = new ArrayList<>(); //待查询进度的设备devSn的map Map deviceSnMap = new HashMap<>(); List syncBos = new ArrayList<>(); for (XzHikvisionSync sync : syncList) { Date date = sync.getUpdateDate(); if (DateUtil.compare(date, yesterday) < 0) { sync.setIsSuccess(0); XzHikvisionSyncBo bo = new XzHikvisionSyncBo(); BeanUtil.copyProperties(sync, bo); bo.setErrMsg("下发超时"); syncBos.add(bo); } else { devSns.add(sync.getDeviceSn()); deviceSnMap.put(sync.getDeviceSn(), sync); } } if (CollUtil.isNotEmpty(devSns)) { GeneralResponse response = IccHttpUtil.getAuthProcess(Collections.singletonList(worker.getPersonSn()), devSns, config); IccHttpUtil.throwErrIf(response); String result = response.getResult(); List authProcessResps = JSON.parseObject(result).getObject("data", new TypeReference>() { }); Map> devSnRespMap = authProcessResps.stream().collect(Collectors.groupingBy(AuthProcessResp::getChannelCode)); String sucCode = "1"; String failCode = "3"; List saveAuthType = Arrays.asList(1, 3); List saveAuthTypeDb = Arrays.asList(1, 2); for (Map.Entry> deviceCodeEntry : devSnRespMap.entrySet()) { Boolean workerSuc = null; Boolean workerFaceSuc = null; XzHikvisionSync sync = deviceSnMap.get(deviceCodeEntry.getKey()); if (sync != null) { for (AuthProcessResp processResp : deviceCodeEntry.getValue()) { //两者同保存或删除 if ((saveAuthTypeDb.contains(sync.getOperate()) && saveAuthType.contains(processResp.getOperateType())) || (sync.getOperate() == 3 && processResp.getOperateType() == 2)) { if (Objects.equals(processResp.getSyncFlag(), sucCode)) { if (processResp.getEventType() == 1) { workerSuc = true; } else if (processResp.getEventType() == 3) { workerFaceSuc = true; } } else if (Objects.equals(processResp.getSyncFlag(), failCode)) { if (processResp.getEventType() == 1) { workerSuc = false; } else if (processResp.getEventType() == 3) { workerFaceSuc = false; } } } } if (Objects.equals(workerSuc, true) && Objects.equals(workerFaceSuc, true)) { sync.setIsSuccess(1); XzHikvisionSyncBo bo = new XzHikvisionSyncBo(); BeanUtil.copyProperties(sync, bo); syncBos.add(bo); } else if (Objects.equals(workerSuc, false) && Objects.equals(workerFaceSuc, false)) { sync.setIsSuccess(0); XzHikvisionSyncBo bo = new XzHikvisionSyncBo(); BeanUtil.copyProperties(sync, bo); bo.setErrMsg("下发异常,请联系管理员," + response.getErrMsg()); syncBos.add(bo); } } } } xzHikvisionSyncService.updateBatchById(syncList); updateTotalStatus(worker.getId()); noticeWorkerUface(worker, devMap, syncBos); } /** * 发送人员下发门禁通知 * * @param worker * @param devMap * @param syncBos */ public void noticeWorkerUface(WorkerInfo worker, Map devMap, List syncBos) { if (CollUtil.isNotEmpty(syncBos)) { String subject = "下发人员到门禁"; for (XzHikvisionSyncBo syncNoticeBo : syncBos) { String name = worker.getWorkerName() + "(" + Optional.of(devMap.get(syncNoticeBo.getDeviceSn())).map(UfaceDev::getDevName).orElse(syncNoticeBo.getDeviceSn()) + ")"; if (Objects.equals(syncNoticeBo.getIsSuccess(), 1)) { if (StrUtil.isNotBlank(syncNoticeBo.getNoticeUserIds())) { for (String id : StrUtil.split(syncNoticeBo.getNoticeUserIds(), ",")) { noticeService.addUserNotice(Long.valueOf(id), subject + "通知", subject + "<<" + name + ">>成功", "1"); } } } else { if (StrUtil.isNotBlank(syncNoticeBo.getNoticeUserIds())) { for (String id : StrUtil.split(syncNoticeBo.getNoticeUserIds(), ",")) { noticeService.addUserNotice(Long.valueOf(id), subject + "通知", subject + "<<" + name + ">>失败", "1"); } } } } } } /** * 更新人员总状态 * * @param whoId */ public void updateTotalStatus(Long whoId) { List xzHikvisionSyncs = xzHikvisionSyncService.list(new LambdaQueryWrapper() .eq(XzHikvisionSync::getWhoId, whoId) .eq(XzHikvisionSync::getBigType, 1) ); Integer sendSuccessStatus = 4; if (CollUtil.isEmpty(xzHikvisionSyncs) || xzHikvisionSyncs.stream().allMatch(xzHikvisionSync1 -> xzHikvisionSync1.getIsSuccess() == null)) { sendSuccessStatus = 4; } else if (xzHikvisionSyncs.stream().allMatch(xzHikvisionSync1 -> Objects.equals(xzHikvisionSync1.getIsSuccess(), 1))) { sendSuccessStatus = 1; } else if (xzHikvisionSyncs.stream().allMatch(xzHikvisionSync1 -> xzHikvisionSync1.getIsSuccess() == null || Objects.equals(xzHikvisionSync1.getIsSuccess(), 0))) { sendSuccessStatus = 2; } else { sendSuccessStatus = 3; } workerInfoService.update(null, new LambdaUpdateWrapper() .eq(WorkerInfo::getId, whoId) .set(WorkerInfo::getSendSuccessStatus, sendSuccessStatus) ); } @Data public static class AccessRecordEvent { /** * 部门名称 */ private String deptName; /** * 部门ID列表 (JSON示例中未出现,但参数中明确为List) */ private List deptIdList; // Assuming list of Longs for department IDs /** * 通道编号 */ private String acsChannelCode; /** * 口罩状态: 3-戴口罩,2-未戴口罩,1-未识别,0-未知 */ private Integer maskState; // JSON example shows "0" as String, but logic suggests int /** * 进出门类型: 详见读卡器业务类型字典 */ private String enterOrExit; /** * 开门类型字符串 */ private String openTypeStr; /** * 刷卡时间,格式:yyyy-MM:dd HH:mm:ss */ private String swingTime; // Using String to exactly match the input format /** * 设备名称 */ private String deviceName; /** * 人员编号 */ private String personCode; /** * 开门类型, 详见开门类型字典 */ private String openType; /** * 组织编码 */ private String orgCode; /** * 证件类型 */ private String paperType; /** * 证件号 */ private String paperNumber; /** * 错误详情 */ private String errorDetail; /** * 开门错误码,0代表成功,96代表需远程验证,其他参考门禁开门错误码 */ private String openFailedCode; // JSON example shows "0" as String /** * 固定值:evo-accesscontrol */ private String from; /** * id标识 (数据库记录ID) */ private Long id; /** * 开始时间, 13位时间戳 (毫秒) */ private Long beginTime; /** * 通道名称 */ private String acsChannelName; /** * 预留字段,暂未使用,默认值为0 */ private Integer cardStatus; // JSON example shows "0" as String, but type suggests number/int /** * 组织名称 */ private String orgName; /** * 性别 1 男,2 女,0 未知 */ private Integer sex; // JSON example shows "0" as String, but logic suggests int /** * 人员部门ID */ private Long deptId; // JSON example doesn't show directly, but parameters suggest Long /** * 卡类型 */ private Integer cardType; // JSON example shows "0" as String, but logic suggests int /** * 设备编号 (与上面deviceCode重复,但参数列表和JSON都包含,保持一致) */ private String deviceCode; /** * 人员姓名 */ private String personName; /** * 刷卡人在平台上的图片,相对路径,拼接方式可查看:FAQ-常见问题-图片服务-OSS方式 */ private String personImg; /** * 开门结果 0 失败 1 成功 */ private Integer openResult; // JSON example shows "1" as String, but logic suggests int /** * 人员ID */ private Long personId; /** * 抓拍图,相对路径,拼接方式可查看:FAQ-常见问题-图片服务-OSS方式 */ private String recordImage1; /** * 卡介质 0 IC 1 有源RFID 2 CPU */ private Integer category; // JSON example doesn't show, but parameters specify int /** * 卡号 */ private String cardNumber; /** * rfid子类型,0:普通门禁,1:电动车,2:特殊人群关怀, 3:宠物 */ private Integer rfidType; // JSON example shows "0" as String, but logic suggests int /** * 年龄 */ private Integer age; // JSON example shows "0" as String, but logic suggests int /** * 0-非访客,1-访客 */ private Integer vRecordFlag; // JSON example doesn't show, but parameters specify int } /** * 事件报警消息体 */ @Data public static class AlarmRecordEventExt { /** * 节点编码 */ private String nodeCode; /** * 设备编号 */ private String deviceCode; /** * 报警编号 */ private String alarmCode; /** * 报警图片相对路径,与recordImage一样,路径拼接方式可参考:对接FAQ-图片服务-OSS方式 */ private String alarmPicture; /** * 节点类型 */ private String nodeType; // JSON example shows "2" as String /** * 报警时间,10位时间戳(秒) */ private Long alarmDate; /** * 报警等级 1:严重,2:一般,3:轻微 */ private Integer alarmGrade; // JSON example shows "1" as String, but logic suggests int /** * 单元类型 */ private Integer unitType; // JSON example shows "7" as String, but type suggests int /** * 报警类型 */ private String alarmType; // JSON example shows "61" as String, but type suggests int /** * 通道序号 */ private Integer channelSeq; // JSON example shows "0" as String, but type suggests int /** * 通道名称 */ private String channelName; /** * 报警状态 1:报警产生,2:报警消失 */ private Integer alarmStat; // JSON example shows "1" as String, but type suggests int private AccessRecordEvent extend; } @Data public static class XzHikvisionSyncBo extends XzHikvisionSync { private String errMsg; } /** * 授权进度查询响应实体 */ @Data public static class AuthProcessResp { /** * 下发结果: *
    *
  • 1-成功
  • *
  • 2-下发中
  • *
  • 3-下发失败
  • *
  • 4-设备离线(仅卡任务有)
  • *
  • 5-等待下发
  • *
*/ private String syncFlag; /** * 通道编号。 * 当事件类型为卡片时(即 eventType=2)生效。 */ private String channelCode; /** * 设备编号。 * 当事件类型为人员、人脸、指纹时(即 eventType=1、3、4)生效。 */ private String deviceCode; /** * 卡号。 * 仅卡任务有此字段。 */ private String cardNumber; /** * 事件类型: *
    *
  • 1-人员
  • *
  • 2-卡片
  • *
  • 3-人脸
  • *
  • 4-指纹
  • *
*/ private int eventType; // Changed to int based on description /** * 操作类型: *
    *
  • 1-增加
  • *
  • 2-删除
  • *
  • 3-修改
  • *
*/ private int operateType; // Changed to int based on description /** * 下发失败原因。 * 仅当 syncFlag 为“下发失败”时提供具体错误信息。 */ private String errMsg; /** * 设备类型: *
    *
  • 1-一代设备
  • *
  • 2-二代设备
  • *
*/ private String deviceType; // Kept as String based on description (though int might be more appropriate for 1/2) /** * 人员编号。 */ private String personCode; } /** * 检测人脸响应response */ @lombok.Data public static class CheckFaceResp { private Boolean success; private Data data; private String code; private String errMsg; @lombok.Data public static class Data { private String fileUrl; private String result; } } /** * 人员扩展 */ @Data public static class WorkerInfoExt extends WorkerInfo { /** * icc部门id */ private Long iccDepartmentId; } }