icc的劳务人员和考勤提交

This commit is contained in:
guoshengxiong 2025-07-16 18:10:59 +08:00
parent a8b76fd788
commit 67855c9ce2
4 changed files with 279 additions and 13 deletions

View File

@ -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<String, String> sendAndDeleteDevSns = projectUfaceConfigService.getSendAndDeleteDevSns(workerInfo);
List<String> addDevSns = StrUtil.split(sendAndDeleteDevSns.getLeft(), ",");
List<String> deleteDevSns = StrUtil.split(sendAndDeleteDevSns.getRight(), ",");
List<String> 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<WorkerAttendance> workerAttendancelist = Lists.newArrayList();
QueryRecordRequest queryRecordRequest = new QueryRecordRequest();
queryRecordRequest.setStartSwingTime(DateUtil.formatDateTime(beginTime));
queryRecordRequest.setEndSwingTime(DateUtil.formatDateTime(endTime));
Project project = projectService.getOne(new LambdaQueryWrapper<Project>()
.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<WorkerInfo>()
.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<UfaceDev>()
.eq(UfaceDev::getDevSn, pageData.getChannelName()));
if (ufaceDev == null) {
log.error("未找到该设备信息,channelName:{}", pageData.getChannelName());
continue;
}
HashMap<String, Object> 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<String> 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<String> 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<String> personCodes, List<String> devSns, ProjectUfaceConfig config) {
PersonAuthRequest personAuthRequest = new PersonAuthRequest();
personAuthRequest.setPersonCodes(personCodes);
personAuthRequest.setTimeQuantumId(1l);
List<PersonAuthRequest.PrivilegeDetail> 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);
}
}
/**

View File

@ -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);
}

View File

@ -550,7 +550,7 @@ public class WorkerInfoServiceImpl extends ServiceImpl<WorkerInfoMapper, WorkerI
if (workerManufacturer != null) {
CompletableFuture.runAsync(() -> {
workerManufacturer.saveWorkerInfo(workerInfo);
}, threadPoolTaskExecutor).thenRun(() -> {
}, threadPoolTaskExecutor).thenRunAsync(() -> {
workerManufacturer.saveWorkerUFaceAuth(workerInfo);
});
}

View File

@ -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<Project> projects = projectMapper.selectList(null);
for (Project project : projects) {
WorkerManufacturer workerManufacturer = workerManufacturerFactory.getWorkerManufacturer(project.getProjectSn());
if (workerManufacturer != null) {
workerManufacturer.saveWorkerAttendances(startTime, endTime);
}
}
}
}