|
|
@@ -0,0 +1,799 @@
|
|
|
+package org.dromara.server.hik.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.dromara.backstage.api.RemotePtXfTermService;
|
|
|
+import org.dromara.backstage.api.RemoteUserAccountService;
|
|
|
+import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
|
|
|
+import org.dromara.backstage.api.domain.vo.RemoteXfTermVo;
|
|
|
+import org.dromara.common.core.config.DefaultConfig;
|
|
|
+import org.dromara.common.core.constant.DefaultConstants;
|
|
|
+import org.dromara.common.core.domain.R;
|
|
|
+import org.dromara.common.core.enums.DeviceBrandEnum;
|
|
|
+import org.dromara.common.core.exception.ServiceException;
|
|
|
+import org.dromara.common.core.utils.StringUtils;
|
|
|
+import org.dromara.common.core.utils.ValidatorUtils;
|
|
|
+import org.dromara.server.hik.constant.ErrCodeConstants;
|
|
|
+import org.dromara.server.hik.constant.HikApiConstants;
|
|
|
+import org.dromara.server.hik.constant.HikDefaultConstants;
|
|
|
+import org.dromara.server.hik.domain.dto.DeviceDto;
|
|
|
+import org.dromara.server.hik.domain.dto.QueryDto;
|
|
|
+import org.dromara.server.hik.domain.dto.UploadEmpDto;
|
|
|
+import org.dromara.server.hik.domain.dto.UserInfoDto;
|
|
|
+import org.dromara.server.hik.domain.dto.base.*;
|
|
|
+import org.dromara.server.hik.domain.dto.query.QueryEmpResultDto;
|
|
|
+import org.dromara.server.hik.domain.vo.XfTermVo;
|
|
|
+import org.dromara.server.hik.enums.ContentTypeEnum;
|
|
|
+import org.dromara.server.hik.enums.StatusCodeEnum;
|
|
|
+import org.dromara.server.hik.service.ISendDeviceService;
|
|
|
+import org.dromara.server.hik.service.IXfTermService;
|
|
|
+import org.dromara.server.hik.utils.DigestHttpUtil;
|
|
|
+import org.dromara.server.hik.utils.JsonConfig;
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.validation.annotation.Validated;
|
|
|
+
|
|
|
+import java.text.MessageFormat;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 向消费机发送信息服务接口实现
|
|
|
+ * <p>
|
|
|
+ * 向消费机发磅的服务接口的功能实现
|
|
|
+ *
|
|
|
+ * @author luoyibo
|
|
|
+ * @version 2.2.0
|
|
|
+ * @date 2025-05-21
|
|
|
+ * @since JDK17
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class SendDeviceServiceImpl implements ISendDeviceService {
|
|
|
+ private final DigestHttpUtil digestHttpUtil;
|
|
|
+ private final DefaultConfig defaultConfig;
|
|
|
+ private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
|
|
+
|
|
|
+ private final IXfTermService xfTermService;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private final RemotePtXfTermService remotePtXfTermService;
|
|
|
+ @DubboReference
|
|
|
+ private final RemoteUserAccountService remoteUserAccountService;
|
|
|
+
|
|
|
+ // region 私有方法
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据提供的 RemoteUserAccountVo 对象和删除标志,构造并返回一个 EmpInfoDto 对象。
|
|
|
+ *
|
|
|
+ * @param accountVo 包含用户账户信息的 RemoteUserAccountVo 对象
|
|
|
+ * @param deleteUser 布尔标志,指示是否应将用户标记为删除
|
|
|
+ * @param deleteAllFace 布尔标志,指示是否应删除与用户相关的所有人脸数据
|
|
|
+ * @param deleteFace 布尔标志,指示是否应删除特定的人脸数据
|
|
|
+ * @param deleteAllCard 布尔标志,指示是否应删除与用户相关的所有卡片数据
|
|
|
+ * @param deleteCard 布尔标志,指示是否应删除特定的卡片数据
|
|
|
+ * @param uploadPhoto 布尔标志,指示是否应上传用户照片
|
|
|
+ * @return 一个填充了用户信息、有效性详情、卡片信息和人脸数据的 EmpInfoDto 对象
|
|
|
+ */
|
|
|
+ @NotNull
|
|
|
+ private static EmpInfoDto getEmpInfoDto(@NotNull RemoteUserAccountVo accountVo, Boolean deleteUser, Boolean deleteAllFace, Boolean deleteFace,
|
|
|
+ Boolean deleteAllCard, Boolean deleteCard, Boolean uploadPhoto) {
|
|
|
+ EmpInfoDto empDto = createEmpInfoDto(accountVo, deleteUser);
|
|
|
+
|
|
|
+ // 设置用户卡片信息,有物理卡号并且物理卡号>0时设置
|
|
|
+ Long factoryId = accountVo.getFactoryId();
|
|
|
+ setCardToEmpInfoDto(empDto, factoryId, deleteAllCard, deleteCard);
|
|
|
+
|
|
|
+ if(uploadPhoto){
|
|
|
+ // TODO 2025-05-24 因为人员照片原因,暂时不将人脸照片上传到消费机
|
|
|
+ // 设置用户人脸图片信息
|
|
|
+ String photo = accountVo.getFacePicUrl();
|
|
|
+ setPhotoToEmpInfoDto(empDto, photo, deleteAllFace, deleteFace);
|
|
|
+ }
|
|
|
+
|
|
|
+ return empDto;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static EmpInfoDto createEmpInfoDto(@NotNull RemoteUserAccountVo accountVo,Boolean deleteUser) {
|
|
|
+ EmpInfoDto empDto = new EmpInfoDto();
|
|
|
+ // 设置用户基本信息
|
|
|
+ empDto.setEmployeeNo(accountVo.getUserNo().toString()).setName(accountVo.getRealName());
|
|
|
+ empDto.setDeleteUser(deleteUser);
|
|
|
+ // 设置有效期,海康设备支持有效期最大2037-12-31 23:59:59,所以要和系统的有效期比较取较小值
|
|
|
+ Date endTime = accountVo.getLifespan();
|
|
|
+ if (ObjectUtil.isNotEmpty(endTime)) {
|
|
|
+ Date hikEndTime = DateUtil.parse(HikDefaultConstants.EMP_END_TIME);
|
|
|
+ if (endTime.compareTo(hikEndTime) > 0) {
|
|
|
+ endTime = hikEndTime;
|
|
|
+ }
|
|
|
+ ValidDto validDto = new ValidDto().setBeginTime(getBeginTime()).setEndTime(DateUtil.date(endTime));
|
|
|
+ empDto.setValid(validDto);
|
|
|
+ }
|
|
|
+ return empDto;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新人脸
|
|
|
+ private static void setPhotoToEmpInfoDto(EmpInfoDto empDto,String photo,Boolean deleteAllFace, Boolean deleteFace) {
|
|
|
+ if (ObjectUtil.isNotEmpty(photo)) {
|
|
|
+ FaceDto faceDto = new FaceDto().setFDID("1").setFaceID(1L).setFacePicURL(photo);
|
|
|
+ faceDto.setDeleteFace(deleteFace);
|
|
|
+
|
|
|
+ List<FaceDto> faceList = new ArrayList<>();
|
|
|
+ faceList.add(faceDto);
|
|
|
+ FaceListDto faceListDto = new FaceListDto().setList(faceList);
|
|
|
+ faceListDto.setDeleteAllFace(deleteAllFace);
|
|
|
+
|
|
|
+ empDto.setFaceInfo(faceListDto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新卡片
|
|
|
+ private static void setCardToEmpInfoDto(EmpInfoDto empDto,Long factoryId,Boolean deleteAllCard, Boolean deleteCard) {
|
|
|
+ if (ObjectUtil.isNotEmpty(factoryId) && factoryId > 0L) {
|
|
|
+ CardDto cardDto = new CardDto().setCardNo(factoryId.toString());
|
|
|
+ cardDto.setDeleteCard(deleteCard);
|
|
|
+
|
|
|
+ List<CardDto> cardList = new ArrayList<>();
|
|
|
+ cardList.add(cardDto);
|
|
|
+
|
|
|
+ CardListDto cardListDto = new CardListDto();
|
|
|
+ cardListDto.setList(cardList);
|
|
|
+ cardListDto.setDeleteAllCard(deleteAllCard);
|
|
|
+
|
|
|
+ empDto.setCardInfo(cardListDto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 RemoteXfTermVo 对象转换为 DeviceDto 对象。
|
|
|
+ * 它提取了终端号、管理员名称、管理员密码、设备 IP、设备端口、服务器 IP 和服务器端口等信息,并将其设置到 DeviceDto 实例中。
|
|
|
+ *
|
|
|
+ * @param termVo 包含终端信息的 RemoteXfTermVo 对象
|
|
|
+ * @return 转换后的 DeviceDto 对象
|
|
|
+ */
|
|
|
+ @NotNull
|
|
|
+ private static DeviceDto getDeviceDto(@NotNull RemoteXfTermVo termVo) {
|
|
|
+ return getDeviceDto(termVo.getTermNo(), termVo.getAdminName(), termVo.getAdminPwd(), termVo.getTermIp(),
|
|
|
+ termVo.getCommPort(), termVo.getServerIp(), termVo.getServerPort());
|
|
|
+ }
|
|
|
+
|
|
|
+ @NotNull
|
|
|
+ private static DeviceDto getDeviceDto(@NotNull XfTermVo termVo) {
|
|
|
+ return getDeviceDto(termVo.getTermNo(), termVo.getAdminName(), termVo.getAdminPwd(), termVo.getTermIp(),
|
|
|
+ termVo.getCommPort(), termVo.getServerIp(), termVo.getServerPort());
|
|
|
+ }
|
|
|
+
|
|
|
+ @NotNull
|
|
|
+ private static DeviceDto getDeviceDto(Long termNo, String adminName, String adminPwd, String termIp, Long commPort, String serverIp, Long serverPort) {
|
|
|
+ DeviceDto dto = new DeviceDto();
|
|
|
+ dto.setTermNo(termNo.intValue());
|
|
|
+ dto.setAdminName(adminName);
|
|
|
+ dto.setAdminPwd(adminPwd);
|
|
|
+ dto.setDeviceIp(termIp);
|
|
|
+ dto.setDevicePort(commPort.intValue());
|
|
|
+ dto.setServerIp(serverIp);
|
|
|
+ dto.setServerPort(serverPort.intValue());
|
|
|
+
|
|
|
+ return dto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 返回当前日期的开始时间,格式化为当天 00:00:00,
|
|
|
+ *
|
|
|
+ * @return 当前日期的开始时间
|
|
|
+ */
|
|
|
+ private static Date getBeginTime() {
|
|
|
+ String temp = DateUtil.format(DateUtil.date(), DefaultConstants.DATE_FORMAT);
|
|
|
+ temp = temp + " 00:00:00";
|
|
|
+ return DateUtil.parse(temp);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 动态构建下发监听服务地址的请求报文
|
|
|
+ *
|
|
|
+ * @param dto 设备信息
|
|
|
+ * @return 下发的请求报文
|
|
|
+ */
|
|
|
+ private String createHostXml(@NotNull DeviceDto dto) {
|
|
|
+ String xmlTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
|
|
+ "<HttpHostNotification version=\"2.0\"\n" +
|
|
|
+ " xmlns=\"http://www.isapi.org/ver20/XMLSchema\">\n" +
|
|
|
+ " <id>1</id>\n" +
|
|
|
+ " <url>{}</url>\n" +
|
|
|
+ " <protocolType>HTTP</protocolType>\n" +
|
|
|
+ " <parameterFormatType>XML</parameterFormatType>\n" +
|
|
|
+ " <addressingFormatType>ipaddress</addressingFormatType>\n" +
|
|
|
+ " <ipAddress>{}</ipAddress>\n" +
|
|
|
+ " <portNo>{}</portNo>\n" +
|
|
|
+ " <httpAuthenticationMethod>none</httpAuthenticationMethod>\n" +
|
|
|
+ " <SubscribeEvent>\n" +
|
|
|
+ " <heartbeat>30</heartbeat>\n" +
|
|
|
+ " <eventMode>list</eventMode>\n" +
|
|
|
+ " <EventList>\n" +
|
|
|
+ " <Event>\n" +
|
|
|
+ " <type>ConsumptionAndTransactionRecordEvent</type>\n" +
|
|
|
+ " </Event>\n" +
|
|
|
+ " </EventList>\n" +
|
|
|
+ " </SubscribeEvent>\n" +
|
|
|
+ "</HttpHostNotification>\n";
|
|
|
+
|
|
|
+ return StringUtils.format(xmlTemplate,dto.getServerUrl(), dto.getServerIp(), dto.getServerPort());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理设置监听服务地址返回数据
|
|
|
+ * <p>
|
|
|
+ * 对返回的json对象进行处理,根据内容的不同返回不同的处理结果,已有的情况
|
|
|
+ * 1.有 ResponseStatus 对象,获取对象中的 statusCode,根据 statusCode 返回成功或错误消息
|
|
|
+ * 2.有 userCheck 对象,获取对象的 statusValue ,根据 statusValue 返回成功或错误消息
|
|
|
+ * 3.有 code 对象,获取 code 的值 ,根据 code 返回成功或错误消息
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param obj 返回数据
|
|
|
+ * @return 处理结果
|
|
|
+ */
|
|
|
+ private R<Void> doSetHostReturnData(JSONObject obj) {
|
|
|
+ if (obj == null) {
|
|
|
+ return R.fail("请求失败,设备无返回");
|
|
|
+ }
|
|
|
+ Integer statusCode;
|
|
|
+ if (ObjectUtil.isNotEmpty(obj.getObj("ResponseStatus"))) {
|
|
|
+ JSONObject responseStatus = obj.getJSONObject("ResponseStatus");
|
|
|
+ statusCode = responseStatus.getInt("statusCode");
|
|
|
+ if (ObjectUtil.notEqual(statusCode, ErrCodeConstants.OK) && ObjectUtil.notEqual(statusCode, ErrCodeConstants.YES)) {
|
|
|
+ return R.fail(StatusCodeEnum.getMessage(statusCode.toString()));
|
|
|
+ }
|
|
|
+ } else if (ObjectUtil.isNotEmpty(obj.getObj("userCheck"))) {
|
|
|
+ JSONObject responseStatus = obj.getJSONObject("userCheck");
|
|
|
+ statusCode = responseStatus.getInt("statusValue");
|
|
|
+ if (ObjectUtil.notEqual(statusCode, ErrCodeConstants.OK) && ObjectUtil.notEqual(statusCode, ErrCodeConstants.YES)) {
|
|
|
+ return R.fail(StatusCodeEnum.getMessage("userCheck_" + statusCode.toString()));
|
|
|
+ }
|
|
|
+ } else if (ObjectUtil.isNotEmpty(obj.getObj("code"))) {
|
|
|
+ statusCode = obj.getInt("code");
|
|
|
+ if (ObjectUtil.notEqual(statusCode, ErrCodeConstants.OK) && ObjectUtil.notEqual(statusCode, ErrCodeConstants.YES)) {
|
|
|
+ return R.fail(obj.getStr("msg"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理设备返回的人员查询结果
|
|
|
+ * <p>
|
|
|
+ * 该方法目前只处理了设备授权造成的查询错误和获取本次查询的记录数和总记录数
|
|
|
+ * 对数据的其它处理,如将人员信息解析出来供其它业务使用则根据具体情况处理
|
|
|
+ *
|
|
|
+ * @param obj 待处理 JSONObject对象
|
|
|
+ * @return 处理结果
|
|
|
+ */
|
|
|
+ private R<Void> doQueryEmpReturnData(@NotNull JSONObject obj) {
|
|
|
+ Integer statusCode;
|
|
|
+ if (ObjectUtil.isNotEmpty(obj.getObj("userCheck"))) {
|
|
|
+ JSONObject responseStatus = obj.getJSONObject("userCheck");
|
|
|
+ statusCode = responseStatus.getInt("statusValue");
|
|
|
+ if (ObjectUtil.notEqual(statusCode, ErrCodeConstants.OK) && ObjectUtil.notEqual(statusCode, ErrCodeConstants.YES)) {
|
|
|
+ return R.fail(StatusCodeEnum.getMessage("userCheck_" + statusCode.toString()));
|
|
|
+ } else {
|
|
|
+ return R.fail("未知异常");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ QueryEmpResultDto result = JSONUtil.toBean(obj, QueryEmpResultDto.class);
|
|
|
+ String msg = StringUtils.format("共[{}]条,本次[{}]条", result.getTotalMatches(), result.getNumOfMatches());
|
|
|
+
|
|
|
+ return R.ok(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据提供的 JSON 对象验证用户检查异常。
|
|
|
+ * 该方法检查给定 JSON 对象中的 "userCheck" 字段,以确定状态值是否表示错误条件。
|
|
|
+ * 如果检测到错误,则返回带有适当消息的失败响应。
|
|
|
+ *
|
|
|
+ * @param obj 一个非空的 JSON 对象,包含要验证的 "userCheck" 字段
|
|
|
+ * @return 如果未发现错误则返回成功响应;如果状态值表示错误或发生未知异常,则返回带错误消息的失败响应
|
|
|
+ */
|
|
|
+ private R<Void> validUserCheckException(@NotNull JSONObject obj) {
|
|
|
+ if (ObjectUtil.isNotEmpty(obj.getObj("userCheck"))) {
|
|
|
+ JSONObject responseStatus = obj.getJSONObject("userCheck");
|
|
|
+ Integer statusCode = responseStatus.getInt("statusValue");
|
|
|
+ if (ObjectUtil.notEqual(statusCode, ErrCodeConstants.OK) && ObjectUtil.notEqual(statusCode, ErrCodeConstants.YES)) {
|
|
|
+ return R.fail(StatusCodeEnum.getMessage("userCheck_" + statusCode.toString()));
|
|
|
+ } else {
|
|
|
+ return R.fail("未知异常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据提供的 JSON 对象验证状态码异常。
|
|
|
+ * 如果 JSON 对象中的 "errorMsg" 字段不为空,则返回带有错误消息的失败响应。
|
|
|
+ * 否则,返回成功响应。
|
|
|
+ *
|
|
|
+ * @param obj 包含要验证的错误消息的 JSON 对象;不能为空
|
|
|
+ * @return 一个响应对象,根据验证结果指示成功或失败
|
|
|
+ */
|
|
|
+ private R<Void> validStatusCodeException(@NotNull JSONObject obj) {
|
|
|
+ String errorMsg = obj.getStr("errorMsg");
|
|
|
+ if (ObjectUtil.isNotEmpty(errorMsg)) {
|
|
|
+ return R.fail(errorMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证提供的 JSON 对象中包含的详细信息。
|
|
|
+ * 检查 "DetailInfo" 对象是否存在,并评估其错误码。
|
|
|
+ * 如果错误码与可接受的值(ErrCodeConstants.OK 或 ErrCodeConstants.YES)不匹配,
|
|
|
+ * 则返回失败响应以及相关的用户错误消息。
|
|
|
+ * 否则,返回成功响应。
|
|
|
+ *
|
|
|
+ * @param obj 包含要验证的 "DetailInfo" 的 JSON 对象;不能为空
|
|
|
+ * @return 如果验证通过则返回成功响应,如果验证失败则返回包含错误消息的失败响应
|
|
|
+ */
|
|
|
+ private R<Void> validDetailInfo(@NotNull JSONObject obj) {
|
|
|
+ if (ObjectUtil.isNotEmpty(obj.getObj("DetailInfo"))) {
|
|
|
+ JSONObject responseStatus = obj.getJSONObject("DetailInfo");
|
|
|
+ Integer statusCode = responseStatus.getInt("errorCode");
|
|
|
+ if (ObjectUtil.notEqual(statusCode, ErrCodeConstants.OK) && ObjectUtil.notEqual(statusCode, ErrCodeConstants.YES)) {
|
|
|
+ return R.fail(responseStatus.getStr("userErrorMsg"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建并发送需要操作的员工信息到指定设备
|
|
|
+ *
|
|
|
+ * @param device 员工信息将被发送到的设备
|
|
|
+ * @param empInfo 要创建并传输的员工信息
|
|
|
+ * @return 一个表示操作结果的 R 实例,封装了任何可能的异常或验证结果
|
|
|
+ */
|
|
|
+ private R<Void> createOperatorEmpInfo(DeviceDto device, EmpInfoDto empInfo) {
|
|
|
+ UserInfoDto sendDto = new UserInfoDto();
|
|
|
+ sendDto.setUserInfoAndRight(empInfo);
|
|
|
+ String setData = JSONUtil.toJsonStr(sendDto, JsonConfig.getConfig());
|
|
|
+
|
|
|
+ JSONObject sendResult = digestHttpUtil.sendPost(device, setData, HikApiConstants.SEND_EMP_INFO, ContentTypeEnum.JSON.getCode());
|
|
|
+ R<Void> check = this.validUserCheckException(sendResult);
|
|
|
+ if (R.isError(check)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[上传人员信息失败]-[设备IP:{0}, 人员信息:{1}, 错误信息:{2}", device.getDeviceIp(), empInfo,
|
|
|
+ check.getMsg()));
|
|
|
+ }
|
|
|
+ check = this.validStatusCodeException(sendResult);
|
|
|
+ if (R.isError(check)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[上传人员信息失败]-[设备IP:{0}, 人员信息:{1}, 错误信息:{2}", device.getDeviceIp(), empInfo,
|
|
|
+ check.getMsg()));
|
|
|
+ }
|
|
|
+ check = this.validDetailInfo(sendResult);
|
|
|
+ if (R.isError(check)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[上传人员信息失败]-[设备IP:{0}, 人员信息:{1}, 错误信息:{2}", device.getDeviceIp(), empInfo,
|
|
|
+ check.getMsg()));
|
|
|
+ }
|
|
|
+ return R.ok(MessageFormat.format("[上传人员信息成功]-[设备IP:{0}, 人员信息:{1}]", device.getDeviceIp(), empInfo));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据提供的终端编号获取一个 DeviceDto 对象。
|
|
|
+ *
|
|
|
+ * @param termNo 用于查询和检索设备信息的终端编号
|
|
|
+ * @return 与查询的终端编号对应的 DeviceDto 对象
|
|
|
+ * @throws ServiceException 如果设备不存在,或者设备不是海康威视(Hikvision)品牌的设备
|
|
|
+ */
|
|
|
+ @NotNull
|
|
|
+ private DeviceDto getDeviceDto(Long termNo) {
|
|
|
+ RemoteXfTermVo termVo = remotePtXfTermService.queryByNo(termNo, defaultConfig.getTenantId());
|
|
|
+ if (ObjectUtil.isEmpty(termVo)) {
|
|
|
+ throw new ServiceException(MessageFormat.format("设备不存在,设备编号:{0}", termNo));
|
|
|
+ }
|
|
|
+ if (ObjectUtil.notEqual(DeviceBrandEnum.HK.getCode(), termVo.getBrand())) {
|
|
|
+ throw new ServiceException(MessageFormat.format("无法处理非海康设备,设备编号:{0}", termNo));
|
|
|
+ }
|
|
|
+ return getDeviceDto(termVo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送指定员工信息到所有设备
|
|
|
+ *
|
|
|
+ * @param empDto 待发送员工信息
|
|
|
+ */
|
|
|
+ private void sendEmpToAllDevice(EmpInfoDto empDto) {
|
|
|
+ List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
|
|
|
+ if (CollectionUtil.isEmpty(termList)) {
|
|
|
+ throw new ServiceException("没有要处理的设备");
|
|
|
+ }
|
|
|
+ termList.forEach(p -> {
|
|
|
+ threadPoolTaskExecutor.submit(() -> {
|
|
|
+ DeviceDto deviceDto = getDeviceDto(p);
|
|
|
+ R<Void> result = this.createOperatorEmpInfo(deviceDto, empDto);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // endregion
|
|
|
+
|
|
|
+ // region 设置监听相关
|
|
|
+ @Override
|
|
|
+ public R<Void> setHttpHostByDto(@Validated DeviceDto dto) {
|
|
|
+ ValidatorUtils.validate(dto);
|
|
|
+
|
|
|
+ if (ObjectUtil.isEmpty(dto.getServerIp())) {
|
|
|
+ return R.fail("监听IP不能为空");
|
|
|
+ }
|
|
|
+ if (ObjectUtil.isEmpty(dto.getServerPort())) {
|
|
|
+ return R.fail("监听端口不能为空");
|
|
|
+ }
|
|
|
+ String setData = this.createHostXml(dto);
|
|
|
+
|
|
|
+ JSONObject sendResult = digestHttpUtil.sendPost(dto, setData, HikApiConstants.SET_HTTP_HOSTS, ContentTypeEnum.XML.getCode());
|
|
|
+ R<Void> doResult = this.doSetHostReturnData(sendResult);
|
|
|
+ if (R.isError(doResult)) {
|
|
|
+ return R.fail(MessageFormat.format("[IP:{0}的设备设置失败,原因:{1}]", dto.getDeviceIp(), doResult.getMsg()));
|
|
|
+ }
|
|
|
+ return R.ok(MessageFormat.format("[IP:{0}的设备设置成功]", dto.getDeviceIp()));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> setHttpHostByTermNo(Long termNo) {
|
|
|
+ DeviceDto dto = getDeviceDto(termNo);
|
|
|
+
|
|
|
+ return this.setHttpHostByDto(dto);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> setHttpHostAll() {
|
|
|
+ List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
|
|
|
+ if (CollectionUtil.isEmpty(termList)) {
|
|
|
+ return R.warn("没有要配置的设备");
|
|
|
+ }
|
|
|
+
|
|
|
+ termList.forEach(p -> {
|
|
|
+ threadPoolTaskExecutor.submit(() -> {
|
|
|
+ DeviceDto dto = getDeviceDto(p);
|
|
|
+ R<Void> result = setHttpHostByDto(dto);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return R.ok("处理完成,详情见处理日志");
|
|
|
+ }
|
|
|
+ // endregion
|
|
|
+
|
|
|
+ // region 从消费机删除人员相关
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteEmpByUserNo(DeviceDto device, String userNo) {
|
|
|
+ EmpInfoDto delEmpDto = new EmpInfoDto();
|
|
|
+ delEmpDto.setDeleteUser(Boolean.TRUE);
|
|
|
+ delEmpDto.setEmployeeNo(userNo);
|
|
|
+
|
|
|
+ R<Void> delResult = this.createOperatorEmpInfo(device, delEmpDto);
|
|
|
+ if (R.isError(delResult)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[处理人员失败]-[设备IP:{0}, 人员编号:{1}, 错误信息:{2}", device.getDeviceIp(), userNo, delResult.getMsg()));
|
|
|
+ }
|
|
|
+ return R.ok(MessageFormat.format("[处理人员成功]-[设备IP:{0}, 人员编号:{1}]", device.getDeviceIp(), userNo));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteEmpFromDevice(Long termNo, Long userId) {
|
|
|
+ DeviceDto device = getDeviceDto(termNo);
|
|
|
+ RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoBy(userId);
|
|
|
+ if (ObjectUtil.isEmpty(accountVo)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[处理人员失败]-[设备IP:{0}, 人员Id:{1}, 错误信息:无此Id对应的人员信息", device.getDeviceIp(), userId));
|
|
|
+ }
|
|
|
+ EmpInfoDto empInfo = getEmpInfoDto(accountVo, true, false, false, false, false, true);
|
|
|
+ R<Void> result = createOperatorEmpInfo(device, empInfo);
|
|
|
+
|
|
|
+ log.info(result.getMsg());
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteEmpFromDevice(Long termNo) {
|
|
|
+ DeviceDto deviceDto = getDeviceDto(termNo);
|
|
|
+ List<RemoteUserAccountVo> accountVoList = remoteUserAccountService.getUserAccountVoList();
|
|
|
+ accountVoList.forEach(p -> {
|
|
|
+ threadPoolTaskExecutor.submit(() -> {
|
|
|
+ EmpInfoDto empDto = getEmpInfoDto(p, true, false, false, false, false, true);
|
|
|
+ R<Void> result = createOperatorEmpInfo(deviceDto, empDto);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ public R<Void> deleteOneEmpFromDevice(Long userId) {
|
|
|
+ RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoBy(userId);
|
|
|
+ if (ObjectUtil.isEmpty(accountVo)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[处理人员失败]-[人员Id:{0}, 错误信息:无此Id对应的人员信息", userId));
|
|
|
+ }
|
|
|
+ EmpInfoDto empInfo = getEmpInfoDto(accountVo, true, false, false, false, false, true);
|
|
|
+
|
|
|
+ List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
|
|
|
+ if (CollectionUtil.isEmpty(termList)) {
|
|
|
+ return R.warn("没有要处理人员的设备");
|
|
|
+ }
|
|
|
+
|
|
|
+ termList.forEach(p -> {
|
|
|
+ threadPoolTaskExecutor.submit(() -> {
|
|
|
+ DeviceDto device = getDeviceDto(p);
|
|
|
+ R<Void> result = createOperatorEmpInfo(device, empInfo);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteEmpFromDevice() {
|
|
|
+ // 获取所有设备
|
|
|
+ List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
|
|
|
+ if (CollectionUtil.isEmpty(termList)) {
|
|
|
+ return R.warn("没有要处理人员的设备");
|
|
|
+ }
|
|
|
+ // 获取所有人员
|
|
|
+ List<RemoteUserAccountVo> accountVoList = remoteUserAccountService.getUserAccountVoList();
|
|
|
+ if (CollectionUtil.isEmpty(accountVoList)) {
|
|
|
+ return R.warn("没有要处理的人员");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 并行处理
|
|
|
+ termList.forEach(p -> {
|
|
|
+ threadPoolTaskExecutor.submit(() -> {
|
|
|
+ DeviceDto device = getDeviceDto(p);
|
|
|
+ accountVoList.parallelStream().forEach(t -> {
|
|
|
+ EmpInfoDto empInfo = getEmpInfoDto(t, true, false, false, false, false, true);
|
|
|
+ R<Void> result = createOperatorEmpInfo(device, empInfo);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+ // endregion
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteAllCardByUserNo(DeviceDto device, String userNo) {
|
|
|
+ CardListDto cardList = new CardListDto();
|
|
|
+ cardList.setDeleteAllCard(Boolean.TRUE);
|
|
|
+
|
|
|
+ EmpInfoDto delEmpDto = new EmpInfoDto();
|
|
|
+ delEmpDto.setEmployeeNo(userNo);
|
|
|
+ delEmpDto.setName("胡哲");
|
|
|
+ delEmpDto.setCardInfo(cardList);
|
|
|
+
|
|
|
+ R<Void> check = this.createOperatorEmpInfo(device, delEmpDto);
|
|
|
+ if (R.isError(check)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[处理人员所有卡片失败]-[设备IP:{0}, 人员编号:{1}, 错误信息:{2}", device.getDeviceIp(), userNo, check.getMsg()));
|
|
|
+ }
|
|
|
+ return R.ok(MessageFormat.format("[处理人员所有卡片成功]-[设备IP:{0}, 人员编号:{1}]", device.getDeviceIp(), userNo));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteCardByUserNo(DeviceDto device, String userNo, String factoryId) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteAllFaceByUserNo(DeviceDto device, String userNo) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> deleteFaceByUserNo(DeviceDto device, String userNo, String faceId) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // region 向消费机上传人员相关
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToDevice(UploadEmpDto uploadEmpDto) {
|
|
|
+ DeviceDto device = uploadEmpDto.getDevice();
|
|
|
+ EmpInfoDto empDto = uploadEmpDto.getEmployee();
|
|
|
+ ValidDto validDto = uploadEmpDto.getValid();
|
|
|
+ CardDto cardDto = uploadEmpDto.getCard();
|
|
|
+ FaceDto faceDto = uploadEmpDto.getFace();
|
|
|
+ if (ObjectUtil.isNotEmpty(cardDto)) {
|
|
|
+ List<CardDto> cardList = new ArrayList<>();
|
|
|
+ cardList.add(cardDto);
|
|
|
+
|
|
|
+ CardListDto cardListDto = new CardListDto();
|
|
|
+ cardListDto.setList(cardList);
|
|
|
+ empDto.setCardInfo(cardListDto);
|
|
|
+ }
|
|
|
+ if (ObjectUtil.isNotEmpty(faceDto)) {
|
|
|
+ List<FaceDto> faceList = new ArrayList<>();
|
|
|
+ faceList.add(faceDto);
|
|
|
+ FaceListDto faceListDto = new FaceListDto();
|
|
|
+ faceListDto.setList(faceList);
|
|
|
+ empDto.setFaceInfo(faceListDto);
|
|
|
+ }
|
|
|
+ if (ObjectUtil.isNotEmpty(validDto)) {
|
|
|
+ empDto.setValid(validDto);
|
|
|
+ }
|
|
|
+ String strEmpInfo = JSONUtil.toJsonStr(empDto, JsonConfig.getConfig());
|
|
|
+ R<Void> check = this.createOperatorEmpInfo(device, empDto);
|
|
|
+ if (R.isError(check)) {
|
|
|
+ return R.fail(
|
|
|
+ MessageFormat.format("[上传人员信息失败]-[设备IP:{0}, 人员信息:{1}, 错误信息:{2}", device.getDeviceIp(), strEmpInfo, check.getMsg()));
|
|
|
+ }
|
|
|
+ return R.ok(MessageFormat.format("[上传人员信息成功]-[设备IP:{0}, 人员信息:{1}]", device.getDeviceIp(), strEmpInfo));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToDevice(Long termNo) {
|
|
|
+ DeviceDto deviceDto = getDeviceDto(termNo);
|
|
|
+ List<RemoteUserAccountVo> accountVoList = remoteUserAccountService.getUserAccountVoList();
|
|
|
+ if (CollectionUtil.isEmpty(accountVoList)) {
|
|
|
+ return R.warn("没有要处理的人员");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理人员列表
|
|
|
+ accountVoList.forEach(p -> {
|
|
|
+ threadPoolTaskExecutor.submit(() -> {
|
|
|
+ try {
|
|
|
+ EmpInfoDto empDto = getEmpInfoDto(p, false, false, false, false, false,true);
|
|
|
+ R<Void> result = createOperatorEmpInfo(deviceDto, empDto);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理人员{}异常: {}", p.getUserId(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToDevice(Long termNo, Long userId) {
|
|
|
+ DeviceDto deviceDto = getDeviceDto(termNo);
|
|
|
+
|
|
|
+ RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoBy(userId);
|
|
|
+
|
|
|
+ EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, false, false,true);
|
|
|
+
|
|
|
+ return this.createOperatorEmpInfo(deviceDto, empDto);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToDevice(Boolean uploadPhoto) {
|
|
|
+ // 获取所有设备
|
|
|
+ List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
|
|
|
+ if (CollectionUtil.isEmpty(termList)) {
|
|
|
+ return R.warn("没有要处理人员的设备");
|
|
|
+ }
|
|
|
+ // 获取所有人员
|
|
|
+ List<RemoteUserAccountVo> accountVoList = remoteUserAccountService.getUserAccountVoList();
|
|
|
+ if (CollectionUtil.isEmpty(accountVoList)) {
|
|
|
+ return R.warn("没有要处理的人员");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 循环处理
|
|
|
+ termList.forEach(p -> {
|
|
|
+ DeviceDto device = getDeviceDto(p);
|
|
|
+ accountVoList.forEach(t -> {
|
|
|
+ threadPoolTaskExecutor.submit(()->{
|
|
|
+ EmpInfoDto empInfo = getEmpInfoDto(t, false, false, false, false, false,uploadPhoto);
|
|
|
+ R<Void> result = createOperatorEmpInfo(device, empInfo);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传days内的数据至指定mac设备
|
|
|
+ *
|
|
|
+ * @param startDate 天数
|
|
|
+ * @param uploadPhoto 是否上传照片
|
|
|
+ * @return 无
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToDevice(String macAddress,Date startDate, Boolean uploadPhoto) {
|
|
|
+ List<RemoteUserAccountVo> vos = remoteUserAccountService.getUpdateUserAccountVo(startDate);
|
|
|
+ if (CollectionUtil.isEmpty(vos)) {
|
|
|
+ return R.warn("没有要处理人员数据");
|
|
|
+ }
|
|
|
+ log.info("day处理人员数据条数" + vos.size());
|
|
|
+ XfTermVo termVo = xfTermService.getByMac(macAddress);
|
|
|
+ if (ObjectUtil.isEmpty(termVo)) {
|
|
|
+ return R.warn(MessageFormat.format("设备未找到,mac:{0}", macAddress));
|
|
|
+ }
|
|
|
+ DeviceDto device = getDeviceDto(termVo);
|
|
|
+ vos.forEach(t -> {
|
|
|
+ threadPoolTaskExecutor.submit(()->{
|
|
|
+ try{
|
|
|
+ EmpInfoDto empInfo = getEmpInfoDto(t, false, false, false, false, false,uploadPhoto);
|
|
|
+ R<Void> result = createOperatorEmpInfo(device, empInfo);
|
|
|
+ log.info(result.getMsg());
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error("heartBeat处理人员{}异常: {}", t.getUserId(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToAllDevice(Long userId) {
|
|
|
+ RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoBy(userId);
|
|
|
+ if (ObjectUtil.isEmpty(accountVo)) {
|
|
|
+ return R.warn(MessageFormat.format("没有要处理的人员信息,userId:{0}", userId));
|
|
|
+ }
|
|
|
+ EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, false, false,true);
|
|
|
+
|
|
|
+ sendEmpToAllDevice(empDto);
|
|
|
+
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpToAllDeviceByUserNo(Long userNo, Date lifeSpan, Boolean deleteUser) {
|
|
|
+ RemoteUserAccountVo accountVo = new RemoteUserAccountVo();
|
|
|
+ accountVo.setUserNo(userNo);
|
|
|
+ accountVo.setLifespan(lifeSpan);
|
|
|
+
|
|
|
+ // 实时下发数据不下发人脸,避免引起卡机
|
|
|
+ EmpInfoDto empDto = getEmpInfoDto(accountVo, deleteUser, false, false, false, false, false);
|
|
|
+
|
|
|
+ sendEmpToAllDevice(empDto);
|
|
|
+
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ // endregion
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> upLoadEmpCardToAllDevice(Long userId, Long factorId, Boolean deleteAllCard, Boolean deleteCard) {
|
|
|
+ RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoBy(userId);
|
|
|
+ if (ObjectUtil.isEmpty(accountVo)) {
|
|
|
+ return R.warn(MessageFormat.format("没有要处理的人员信息,userId:{0}", userId));
|
|
|
+ }
|
|
|
+ accountVo.setFactoryId(factorId);
|
|
|
+ // 实时下发数据不下发人脸,避免引起卡机
|
|
|
+ EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, deleteAllCard, deleteCard, false);
|
|
|
+
|
|
|
+ sendEmpToAllDevice(empDto);
|
|
|
+
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Void> queryBatchEmpFormDevice(@NotNull QueryDto dto) {
|
|
|
+ DeviceDto device = dto.getDevice();
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("searchID", dto.getSearchID());
|
|
|
+ params.put("searchResultPosition", (dto.getPageNo() - 1) * dto.getPageSize());
|
|
|
+ params.put("maxResults", dto.getPageSize());
|
|
|
+
|
|
|
+ String setData = JSONUtil.toJsonStr(params);
|
|
|
+ JSONObject sendResult = digestHttpUtil.sendPost(dto.getDevice(), setData, HikApiConstants.QUERY_EMP_ALL, ContentTypeEnum.JSON.getCode());
|
|
|
+
|
|
|
+ R<Void> doResult = this.doQueryEmpReturnData(sendResult);
|
|
|
+ if (R.isError(doResult)) {
|
|
|
+ return R.fail(StringUtils.format("[IP:{}的设备查询失败,原因:{}]", device.getDeviceIp(), doResult.getMsg()));
|
|
|
+ }
|
|
|
+ return R.ok(StringUtils.format("[IP:{}的设备查询成功],结果:{}", device.getDeviceIp(), doResult.getMsg()));
|
|
|
+ }
|
|
|
+}
|