Ver Fonte

Merge remote-tracking branch 'origin/master'

autumnal_wind há 11 meses atrás
pai
commit
08716a062c
18 ficheiros alterados com 340 adições e 73 exclusões
  1. 8 0
      ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/RemoteUserAccountService.java
  2. 2 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
  3. 3 3
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java
  4. 7 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/IPtCardService.java
  5. 13 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/impl/PtCardServiceImpl.java
  6. 27 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/dubbo/RemoteUserAccountServiceImpl.java
  7. 5 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/IPtUserAccountService.java
  8. 35 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/impl/PtUserAccountServiceImpl.java
  9. 1 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/XfTermServiceImpl.java
  10. 2 1
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/controller/TestController.java
  11. 9 0
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/domain/XfTerm.java
  12. 9 0
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/domain/vo/XfTermVo.java
  13. 54 2
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/event/handler/HeatBeatHandler.java
  14. 3 2
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/mq/event/impl/HikBackStageEventImpl.java
  15. 9 1
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/service/ISendDeviceService.java
  16. 111 39
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/service/impl/SendDeviceServiceImpl.java
  17. 21 22
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/service/impl/XfTermServiceImpl.java
  18. 21 3
      ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/task/ScheduledTasks.java

+ 8 - 0
ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/RemoteUserAccountService.java

@@ -4,6 +4,7 @@ import org.dromara.backstage.api.domain.bo.RemoteUserAccountBo;
 import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
 import org.dromara.common.core.domain.R;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -88,4 +89,11 @@ public interface RemoteUserAccountService {
     RemoteUserAccountVo getUserAccountVoBy(Long userId);
 
     List<Long> getUserAccountIdList();
+
+    /**
+     * 获取指定天数内有更新账户信息的和有卡片更新的账户信息
+     * @param days
+     * @return
+     */
+    List<RemoteUserAccountVo> getUpdateUserAccountVo(Date startDate);
 }

+ 2 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java

@@ -202,4 +202,6 @@ public interface CacheNames {
 
     String XF_ORIGINAL_ID = "xf_original_id";
     String XF_DETAIL_ID = "xf_detail_id";
+
+    String XF_TERM_IP = "term_ip:";
 }

+ 3 - 3
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java

@@ -174,11 +174,11 @@ public class FileUtils extends FileUtil {
 
     // 本地压缩图片
     public static void main(String[] args) throws IOException {
-        String fileName = "C:\\Users\\LENOVO\\Desktop\\1978.jpg";
+        String fileName = "C:\\file\\upload\\image\\avatar\\TeaBaseinfo\\20241022\\1729560631186.jpg";
         File file = new File(fileName);
         // 获取bytes
-        FileOutputStream fileOutputStream = new FileOutputStream("C:\\file\\upload\\image\\avatar\\1978.jpg");
-        Img.from(file).setQuality(0.5f).write(fileOutputStream);
+        FileOutputStream fileOutputStream = new FileOutputStream("C:\\file\\upload\\image\\avatar\\TeaBaseinfo\\20241022\\1729560631186-3.jpg");
+        Img.from(file).setQuality(0.8f).write(fileOutputStream);
         fileOutputStream.close();
 
     }

+ 7 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/IPtCardService.java

@@ -52,6 +52,13 @@ public interface IPtCardService {
      */
     List<PtCardVo> getList(PtCardBo bo);
 
+    /**
+     * 获取时间到当前有更新的卡片列表
+     * @param startDate 开始时间
+     * @return 卡片列表
+     */
+    List<PtCardVo> getList(Date startDate,Date endDate);
+
     /**
      * 新增账户卡片
      *

+ 13 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/impl/PtCardServiceImpl.java

@@ -118,6 +118,19 @@ public class PtCardServiceImpl implements IPtCardService {
         return baseMapper.selectVoList(lqw);
     }
 
+    /**
+     * 获取时间到当前有更新的卡片列表
+     *
+     * @param startDate 开始时间
+     * @return 卡片列表
+     */
+    @Override
+    public List<PtCardVo> getList(Date startDate, Date endDate) {
+        LambdaQueryWrapper<PtCard> between = Wrappers.lambdaQuery(PtCard.class).eq(PtCard::getStatus, CardStatusEnum.NORMAL.code().toString())
+            .and(wrapper -> wrapper.between(PtCard::getChangeTime, startDate, endDate).or().between(PtCard::getCreateTime, startDate, endDate));
+        return baseMapper.selectVoList(between);
+    }
+
 
     private LambdaQueryWrapper<PtCard> buildQueryWrapper(PtCardBo bo) {
         Map<String, Object> params = bo.getParams();

+ 27 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/dubbo/RemoteUserAccountServiceImpl.java

@@ -8,6 +8,7 @@ import org.dromara.backstage.api.RemoteUserAccountService;
 import org.dromara.backstage.api.domain.bo.RemoteUserAccountBo;
 import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
 import org.dromara.backstage.business.accouunt.UserAccountBusiness;
+import org.dromara.backstage.domain.vo.card.PtCardVo;
 import org.dromara.backstage.payment.domain.bo.PtUserAccountBo;
 import org.dromara.backstage.payment.domain.vo.PtUserAccountVo;
 import org.dromara.backstage.payment.service.IPtUserAccountService;
@@ -17,6 +18,7 @@ import org.dromara.common.core.utils.MapstructUtils;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -184,4 +186,29 @@ public class RemoteUserAccountServiceImpl implements RemoteUserAccountService {
 
         return voList.stream().map(PtUserAccountVo::getUserId).toList();
     }
+
+    /**
+     * 获取指定天数内有更新账户信息的和有卡片更新的账户信息
+     *
+     * @param startDate 天数
+     * @return List<RemoteUserAccountVo>
+     */
+    @Override
+    public List<RemoteUserAccountVo> getUpdateUserAccountVo(Date startDate) {
+        List<RemoteUserAccountVo> rs = new ArrayList<>();
+        List<PtUserAccountVo> userAccountVoByDay = userAccountService.getUserAccountVoByDay(startDate);
+        for (PtUserAccountVo userAccountAndCard : userAccountVoByDay) {
+            RemoteUserAccountVo vo = MapstructUtils.convert(userAccountAndCard, RemoteUserAccountVo.class);
+            if(vo !=null){
+                PtCardVo card = userAccountAndCard.getCard();
+                if(card != null){
+                    vo.setFactoryId(card.getFactoryId());
+                }
+                rs.add(vo);
+            }
+        }
+        return rs;
+    }
+
+
 }

+ 5 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/IPtUserAccountService.java

@@ -208,4 +208,9 @@ public interface IPtUserAccountService {
      * @return 账户信息及账户卡信息
      */
     List<PtUserAccountVo> getUserAccountsAndCard(Long userId);
+
+    /**
+     * 获取指定天数内有更新账户信息的和有卡片更新的账户信息
+     */
+    List<PtUserAccountVo> getUserAccountVoByDay(Date startDate);
 }

+ 35 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/impl/PtUserAccountServiceImpl.java

@@ -3,6 +3,8 @@ package org.dromara.backstage.payment.service.impl;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.lang.UUID;
 import cn.hutool.core.util.ObjUtil;
@@ -668,5 +670,38 @@ public class PtUserAccountServiceImpl implements IPtUserAccountService {
         return res;
     }
 
+    /**
+     * 获取指定天数内有更新账户信息的和有卡片更新的账户信息
+     *
+     * @param startDate
+     */
+    @Override
+    public List<PtUserAccountVo> getUserAccountVoByDay(Date startDate) {
+        // 获取指定天数内有更新账户信息的
+        // 人脸的
+        Date date = new Date();
+        LambdaQueryWrapper<PtUserAccount> between = Wrappers.lambdaQuery(PtUserAccount.class).between(PtUserAccount::getUpdateTime, startDate, date);
+        List<PtUserAccountVo> userAccountVos = baseMapper.selectVoList(between);
+        List<PtUserAccountVo> updatePhotos = userAccountVos.stream().filter(e -> StringUtils.isNotBlank(e.getPhoto())).toList();
+        updatePhotos.forEach(e -> e.setFacePicUrl(photoPrefix+e.getPhoto()));
+
+        List<PtUserAccountVo> rs = new ArrayList<>(updatePhotos);
+
+        // 卡片的
+        List<PtCardVo> cardVos = ptCardService.getList(startDate, date);
+        List<Long> userIds = cardVos.stream().map(PtCardVo::getUserId).toList();
+        Map<Long, PtCardVo> collect = cardVos.stream().collect(Collectors.toMap(PtCardVo::getUserId, e -> e));
+        if(CollectionUtil.isNotEmpty(userIds)){
+            LambdaQueryWrapper<PtUserAccount> in = Wrappers.lambdaQuery(PtUserAccount.class).in(PtUserAccount::getUserId, userIds);
+            List<PtUserAccountVo> userAccountVos1 = baseMapper.selectVoList(in);
+            userAccountVos1.forEach(e -> e.setCard(collect.get(e.getUserId())));
+            //不更新人脸
+            //userAccount.setFacePicUrl(photoPrefix+userAccount.getPhoto());
+            rs.addAll(userAccountVos1);
+        }
+
+        return rs;
+    }
+
 
 }

+ 1 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/XfTermServiceImpl.java

@@ -128,6 +128,7 @@ public class XfTermServiceImpl implements IXfTermService {
     @Override
     @Cacheable(cacheNames = CacheNames.PT_TERM_MAC_MAP, key = "#mac", unless = "#result == null")
     public XfTermVo queryVoOneByMac(String mac) {
+        if (StringUtils.isBlank(mac)) return null;
         XfTermBo bo = new XfTermBo();
         bo.setTermMac(mac);
         return queryVoOneByBo(bo);

+ 2 - 1
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/controller/TestController.java

@@ -224,6 +224,7 @@ public class TestController {
     }
 
     /**
+     *  通常不要调用此接口,不能同时给所有设备上传员工信息,只能给指定设备上传员工信息
      * 上传所有员工信息到所有设备。
      * <p>
      * 该方法通过HTTP GET请求触发,将系统中的所有员工信息上传至所有关联的设备。
@@ -233,7 +234,7 @@ public class TestController {
      */
     @GetMapping("/emp/upload/all")
     public R<Void> upLoadAllEmpToAllDevice(){
-        return sendDeviceService.upLoadEmpToDevice();
+        return sendDeviceService.upLoadEmpToDevice(true);
     }
     //endregion
 

+ 9 - 0
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/domain/XfTerm.java

@@ -354,5 +354,14 @@ public class XfTerm extends TenantEntity {
     @TableField(exist = false)
     private Long accountName;
 
+    /*消费机管理账号*/
+    private String adminName;
+
+    /*消费机管理密码*/
+    private String adminPwd;
+
+    /*消费机品牌*/
+    private String brand;
+
 
 }

+ 9 - 0
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/domain/vo/XfTermVo.java

@@ -326,4 +326,13 @@ public class XfTermVo implements Serializable {
      */
     private Date blackDownTime;
     //endregion
+
+    /*消费机管理账号*/
+    private String adminName;
+
+    /*消费机管理密码*/
+    private String adminPwd;
+
+    /*消费机品牌*/
+    private String brand;
 }

+ 54 - 2
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/event/handler/HeatBeatHandler.java

@@ -3,12 +3,22 @@ package org.dromara.server.hik.event.handler;
 import com.alibaba.fastjson.JSONObject;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.backstage.api.RemoteUserAccountService;
+import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.server.hik.event.HikEventHandler;
 import org.dromara.server.hik.event.domain.FileContent;
 import org.dromara.server.hik.event.domain.HeatBeatData;
+import org.dromara.server.hik.service.ISendDeviceService;
 import org.dromara.server.hik.service.IXfTermService;
 import org.springframework.stereotype.Component;
 
+import java.time.*;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import java.util.List;
 import java.util.Map;
 
 @Slf4j
@@ -18,6 +28,8 @@ public class HeatBeatHandler implements HikEventHandler {
 
     public final IXfTermService xfTermService;
 
+    public final ISendDeviceService sendDeviceService;
+
     @Override
     public Map<String, Object> handleEvent(JSONObject jsonObject, FileContent fileContent) {
         // 1.JSONObject 转换成心跳 HeadBeatData对象
@@ -26,9 +38,49 @@ public class HeatBeatHandler implements HikEventHandler {
 
         //更新设备的IP地址
         // mac -> ip 和 心跳的IP 是否相等,不相等则更新
-        xfTermService.updateByMac(heatBeatData.getMacAddress(), heatBeatData.getIpAddress());
+        String ipAddress = heatBeatData.getIpAddress();
+        String macAddress = heatBeatData.getMacAddress();
+        boolean b = xfTermService.updateByMac(macAddress, ipAddress);
+
+        if(b){
+            //增量下发 人脸数据和卡数据
+            Long cacheObject = RedisUtils.getCacheObject(CacheNames.XF_TERM_IP + ipAddress);
+            if(cacheObject == null){
+                // 第一次上线 默认只下发最近1天的 新增或修改的数据
+                //记录每天第一次上来的心跳数据时 下发最近3天的 新增或修改的数据
+                //        t_pt_useraccount表 update_time  更新人脸
+                //        t_pt_card表   change_time、create_time  更新卡片
+                //下发数据
+                // 获取当前时间的前一天的时间
+                LocalDateTime localDate = LocalDateTime.now();
+                LocalDateTime minus = localDate.minus(1, ChronoUnit.DAYS);
+                // LocalDateTime 转 date
+                Date date = Date.from(minus.atZone(ZoneId.systemDefault()).toInstant());
+                System.err.println("minus: " + minus);
+                System.err.println("date: " + date);
+                sendDeviceService.upLoadEmpToDevice(macAddress,date,true);
+
+                RedisUtils.setCacheObject(CacheNames.XF_TERM_IP + ipAddress, date.getTime());
+            }else{
+                // 当前时间-上次下发时间 >= 1天 就下发
+                Date now = new Date();
+                Date last = new Date(cacheObject);
+                // 舍弃时分秒,只保留日期部分
+                LocalDate nowDate = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+                LocalDate lastDate = last.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+                System.err.println("nowDate: " + nowDate);
+                System.err.println("lastDate: " + lastDate);
+                // 计算两个日期之间的天数差
+                long daysBetween = ChronoUnit.DAYS.between(lastDate, nowDate);
 
-        //记录第一次上来的心跳数据时 是否下发全量数据到当前设备
+                // 判断是否相差 1 天或以上
+                if (daysBetween >= 1) {
+                    // 相差一天以上,执行下发逻辑
+                    sendDeviceService.upLoadEmpToDevice(macAddress, last, true);
+                    RedisUtils.setCacheObject(CacheNames.XF_TERM_IP + ipAddress, now.getTime());
+                }
+            }
+        }
 
         return null;
     }

+ 3 - 2
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/mq/event/impl/HikBackStageEventImpl.java

@@ -31,6 +31,7 @@ import java.util.Date;
 public class HikBackStageEventImpl implements IHIKEventStrategy {
     private final ISendDeviceService sendDeviceService;
 
+    // 实时下发数据不下发人脸,避免引起卡机
     @Override
     public void doMsgHandle(String eventType, Object msg) {
         switch (eventType) {
@@ -39,7 +40,7 @@ public class HikBackStageEventImpl implements IHIKEventStrategy {
                 log.info("[海康服务处理云端->本地一卡通账户同步请求]-[账户信息:{}]", JSONUtil.toJsonStr(remoteVo));
 
                 Long userNo = remoteVo.getUserNo();
-                Boolean deleteUser = !remoteVo.getDelFlag().equals("0");
+                Boolean deleteUser = !"0".equals(remoteVo.getDelFlag());
                 Date lifespan = remoteVo.getLifespan();
                 R<Void> result = sendDeviceService.upLoadEmpToAllDeviceByUserNo(userNo, lifespan, deleteUser);
                 log.info(result.getMsg());
@@ -49,7 +50,7 @@ public class HikBackStageEventImpl implements IHIKEventStrategy {
                 Long userId = remoteCard.getUserId();
                 Long factorId = remoteCard.getFactoryId();
                 String status = remoteCard.getStatus();
-                Boolean deleteCard = !status.equals(CardStatusEnum.NORMAL.code().toString());
+                Boolean deleteCard = !CardStatusEnum.NORMAL.code().toString().equals(status);
 
                 log.info("[海康服务处理云端->本地卡片同步请求]-[卡片信息:{}]", JSONUtil.toJsonStr(remoteCard));
 

+ 9 - 1
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/service/ISendDeviceService.java

@@ -177,7 +177,15 @@ public interface ISendDeviceService {
      *
      * @return 响应信息主体,表示上传操作的结果状态及可能的附加信息
      */
-    R<Void> upLoadEmpToDevice();
+    R<Void> upLoadEmpToDevice(Boolean uploadPhoto);
+
+    /**
+     * 上传days内的数据至到指定设备
+     * @param startDate 天数
+     * @param uploadPhoto 是否上传照片
+     * @return 无
+     */
+    R<Void> upLoadEmpToDevice(String macAddress,Date startDate, Boolean uploadPhoto);
 
     /**
      * 上传指定员工信息到所有设备。

+ 111 - 39
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/service/impl/SendDeviceServiceImpl.java

@@ -28,9 +28,11 @@ 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;
@@ -59,6 +61,8 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
     private final DefaultConfig defaultConfig;
     private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
 
+    private final IXfTermService xfTermService;
+
     @DubboReference
     private final RemotePtXfTermService remotePtXfTermService;
     @DubboReference
@@ -75,11 +79,30 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
      * @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 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());
@@ -94,8 +117,26 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
             ValidDto validDto = new ValidDto().setBeginTime(getBeginTime()).setEndTime(DateUtil.date(endTime));
             empDto.setValid(validDto);
         }
-        // 设置用户卡片信息,有物理卡号并且物理卡号>0时设置
-        Long factoryId = accountVo.getFactoryId();
+        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);
@@ -109,24 +150,6 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
 
             empDto.setCardInfo(cardListDto);
         }
-
-        // TODO 2025-05-24 因为人员照片原因,暂时不将人脸照片上传到消费机
-        // 设置用户人脸图片信息
-         String photo = accountVo.getFacePicUrl();
-         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);
-         }
-
-        return empDto;
-
     }
 
     /**
@@ -138,14 +161,26 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
      */
     @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(termVo.getTermNo().intValue());
-        dto.setAdminName(termVo.getAdminName());
-        dto.setAdminPwd(termVo.getAdminPwd());
-        dto.setDeviceIp(termVo.getTermIp());
-        dto.setDevicePort(termVo.getCommPort().intValue());
-        dto.setServerIp(termVo.getServerIp());
-        dto.setServerPort(termVo.getServerPort().intValue());
+        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;
     }
@@ -460,7 +495,7 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
             return R.fail(
                 MessageFormat.format("[处理人员失败]-[设备IP:{0}, 人员Id:{1}, 错误信息:无此Id对应的人员信息", device.getDeviceIp(), userId));
         }
-        EmpInfoDto empInfo = getEmpInfoDto(accountVo, true, false, false, false, false);
+        EmpInfoDto empInfo = getEmpInfoDto(accountVo, true, false, false, false, false, true);
         R<Void> result = createOperatorEmpInfo(device, empInfo);
 
         log.info(result.getMsg());
@@ -474,7 +509,7 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
         List<RemoteUserAccountVo> accountVoList = remoteUserAccountService.getUserAccountVoList();
         accountVoList.forEach(p -> {
             threadPoolTaskExecutor.submit(() -> {
-                EmpInfoDto empDto = getEmpInfoDto(p, true, false, false, false, false);
+                EmpInfoDto empDto = getEmpInfoDto(p, true, false, false, false, false, true);
                 R<Void> result = createOperatorEmpInfo(deviceDto, empDto);
                 log.info(result.getMsg());
             });
@@ -489,7 +524,7 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
             return R.fail(
                 MessageFormat.format("[处理人员失败]-[人员Id:{0}, 错误信息:无此Id对应的人员信息", userId));
         }
-        EmpInfoDto empInfo = getEmpInfoDto(accountVo, true, false, false, false, false);
+        EmpInfoDto empInfo = getEmpInfoDto(accountVo, true, false, false, false, false, true);
 
         List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
         if (CollectionUtil.isEmpty(termList)) {
@@ -524,7 +559,7 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
             threadPoolTaskExecutor.submit(() -> {
                 DeviceDto device = getDeviceDto(p);
                 accountVoList.parallelStream().forEach(t -> {
-                    EmpInfoDto empInfo = getEmpInfoDto(t, true, false, false, false, false);
+                    EmpInfoDto empInfo = getEmpInfoDto(t, true, false, false, false, false, true);
                     R<Void> result = createOperatorEmpInfo(device, empInfo);
                     log.info(result.getMsg());
                 });
@@ -616,7 +651,7 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
         accountVoList.forEach(p -> {
             threadPoolTaskExecutor.submit(() -> {
                 try {
-                    EmpInfoDto empDto = getEmpInfoDto(p, false, false, false, false, false);
+                    EmpInfoDto empDto = getEmpInfoDto(p, false, false, false, false, false,true);
                     R<Void> result = createOperatorEmpInfo(deviceDto, empDto);
                     log.info(result.getMsg());
                 } catch (Exception e) {
@@ -633,13 +668,13 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
 
         RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoBy(userId);
 
-        EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, false, false);
+        EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, false, false,true);
 
         return this.createOperatorEmpInfo(deviceDto, empDto);
     }
 
     @Override
-    public R<Void> upLoadEmpToDevice() {
+    public R<Void> upLoadEmpToDevice(Boolean uploadPhoto) {
         // 获取所有设备
         List<RemoteXfTermVo> termList = remotePtXfTermService.queryListByBrand("hk");
         if (CollectionUtil.isEmpty(termList)) {
@@ -656,7 +691,7 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
             DeviceDto device = getDeviceDto(p);
             accountVoList.forEach(t -> {
                 threadPoolTaskExecutor.submit(()->{
-                    EmpInfoDto empInfo = getEmpInfoDto(t, false, false, false, false, false);
+                    EmpInfoDto empInfo = getEmpInfoDto(t, false, false, false, false, false,uploadPhoto);
                     R<Void> result = createOperatorEmpInfo(device, empInfo);
                     log.info(result.getMsg());
                 });
@@ -665,13 +700,48 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
         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.queryByMac(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);
+        EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, false, false,true);
 
         sendEmpToAllDevice(empDto);
 
@@ -684,7 +754,8 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
         accountVo.setUserNo(userNo);
         accountVo.setLifespan(lifeSpan);
 
-        EmpInfoDto empDto = getEmpInfoDto(accountVo, deleteUser, false, false, false, false);
+        // 实时下发数据不下发人脸,避免引起卡机
+        EmpInfoDto empDto = getEmpInfoDto(accountVo, deleteUser, false, false, false, false, false);
 
         sendEmpToAllDevice(empDto);
 
@@ -700,7 +771,8 @@ public class SendDeviceServiceImpl implements ISendDeviceService {
             return R.warn(MessageFormat.format("没有要处理的人员信息,userId:{0}", userId));
         }
         accountVo.setFactoryId(factorId);
-        EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, deleteAllCard, deleteCard);
+        // 实时下发数据不下发人脸,避免引起卡机
+        EmpInfoDto empDto = getEmpInfoDto(accountVo, false, false, false, deleteAllCard, deleteCard, false);
 
         sendEmpToAllDevice(empDto);
 

+ 21 - 22
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/service/impl/XfTermServiceImpl.java

@@ -41,10 +41,12 @@ public class XfTermServiceImpl implements IXfTermService {
     private final XfTermMapper baseMapper;
     private final DefaultConfig defaultConfig;
 
+    private String cache = CacheNames.PT_TERM_MAC_MAP + "_hik";
+
 
     @Override
     public XfTermVo queryByMac(String termMac) {
-        boolean existsObject = RedisUtils.isExistsObject(CacheNames.PT_TERM_MAC_MAP);
+        boolean existsObject = RedisUtils.isExistsObject(cache);
         if(!existsObject){
             // 缓存设备mac地址
             XfTermVo byMac = getByMac(termMac);
@@ -53,29 +55,27 @@ public class XfTermServiceImpl implements IXfTermService {
             }
             Map<String, XfTermVo> map = new HashMap<>();
             map.put(termMac, byMac);
-            RedisUtils.setCacheMap(CacheNames.PT_TERM_MAC_MAP, map);
-            RedisUtils.expire(CacheNames.PT_TERM_MAC_MAP, Duration.ofHours(1));
+            RedisUtils.setCacheMap(cache, map);
+            RedisUtils.expire(cache, Duration.ofHours(1));
             return byMac;
         }
-        Object value = RedisUtils.getCacheMapValue(CacheNames.PT_TERM_MAC_MAP, termMac);
+        XfTermVo value = RedisUtils.getCacheMapValue(cache, termMac);
         if(ObjUtil.isNull(value)){
             // 缓存设备mac地址
             XfTermVo byMac = getByMac(termMac);
             if(ObjUtil.isNull(byMac)){
                 return null;
             }
-            RedisUtils.setCacheMapValue(CacheNames.PT_TERM_MAC_MAP, termMac, byMac);
+            RedisUtils.setCacheMapValue(cache, termMac, byMac);
             return byMac;
         }
-        return (XfTermVo) value;
+        return value;
 
     }
 
     @Override
     public XfTermVo getByMac(String termMac){
-        List<XfTermVo> termVos = TenantHelper.ignore(() -> {
-            return baseMapper.selectVoList(new LambdaQueryWrapper<XfTerm>().eq(XfTerm::getTermMac, termMac));
-        });
+        List<XfTermVo> termVos = baseMapper.selectVoList(new LambdaQueryWrapper<XfTerm>().eq(XfTerm::getTermMac, termMac));
         if(CollectionUtil.isEmpty(termVos)){
             return null;
         }else if(termVos.size()>1){
@@ -93,20 +93,19 @@ public class XfTermServiceImpl implements IXfTermService {
      */
     @Override
     public boolean updateByMac(String termMac, String newIP) {
-        List<XfTermVo> termVos = TenantHelper.ignore(() -> {
-            LambdaQueryWrapper<XfTerm> select = new LambdaQueryWrapper<XfTerm>().eq(XfTerm::getTermMac, termMac)
-                .select(XfTerm::getTermId, XfTerm::getTermIp, XfTerm::getTermMac);
-            return baseMapper.selectVoList(select);
-        });
-        if(CollectionUtil.isNotEmpty(termVos) && termVos.size()==1){
-            XfTermVo xfTermVo = termVos.get(0);
+        XfTermVo xfTermVo = queryByMac(termMac);
+        if(xfTermVo!=null){
             if(StringUtils.isBlank(xfTermVo.getTermIp()) || !xfTermVo.getTermIp().equals(newIP)){
-                return TenantHelper.ignore(() -> {
-                    XfTerm xfTerm = new XfTerm();
-                    xfTerm.setTermId(xfTermVo.getTermId());
-                    xfTerm.setTermIp(newIP);
-                    return baseMapper.updateById(xfTerm) > 0;
-                });
+                XfTerm xfTerm = new XfTerm();
+                xfTerm.setTermId(xfTermVo.getTermId());
+                xfTerm.setTermIp(newIP);
+                xfTermVo.setTermIp(newIP);
+                boolean b = baseMapper.updateById(xfTerm) > 0;
+                boolean existsObject = RedisUtils.isExistsObject(cache);
+                if(existsObject){
+                    RedisUtils.setCacheMapValue(cache, termMac, xfTermVo);
+                }
+                return b;
             }
             return true;
         }

+ 21 - 3
ruoyi-server/ruoyi-server-hik/src/main/java/org/dromara/server/hik/task/ScheduledTasks.java

@@ -28,16 +28,34 @@ public class ScheduledTasks {
 
     /**
      * 定时任务方法,用于每天凌晨1点30分将员工信息上传至设备。
-     * 该方法通过调用 {@link ISendDeviceService#upLoadEmpToDevice()} 实现具体的上传逻辑。
+     * 该方法通过调用 {@link ISendDeviceService#upLoadEmpToDevice(Boolean uploadPhoto)} 实现具体的上传逻辑。
      * 此任务由 Spring 的定时任务机制驱动,按照指定的 cron 表达式执行。
      * <p>
      * 注意:此方法依赖于外部服务接口的具体实现,确保目标设备和员工信息管理后台接口可用。
      */
-    @Scheduled(cron = "0 30 1 * * *")
+    // 每天11:10和17:10、7:00执行
+//    @Scheduled(cron = "0 20 11,17 * * *")
     public void upLoadEmpToDevice() {
         scheduledExecutorService.submit(() -> {
             log.info("向所有海康消费机下发人员定时任务开始执行");
-            sendDeviceService.upLoadEmpToDevice();
+            // 下发人脸会是设备卡机,所以这里设置为false
+            sendDeviceService.upLoadEmpToDevice(false);
+        });
+    }
+
+    /**
+     * 定时任务方法,用于每天早上7点执行。
+     * 该方法通过调用 {@link ISendDeviceService#upLoadEmpToDevice(Boolean uploadPhoto)} 实现具体的上传逻辑。
+     * 此任务由 Spring 的定时任务机制驱动,按照指定的 cron 表达式执行。
+     * <p>
+     * 注意:此方法依赖于外部服务接口的具体实现,确保目标设备和员工信息管理后台接口可用。
+     */
+//    @Scheduled(cron = "0 0 7 * * *")
+    public void upLoadEmpToDevice2() {
+        scheduledExecutorService.submit(() -> {
+            log.info("向所有海康消费机下发人员定时任务开始执行");
+            // 下发人脸会是设备卡机,所以这里设置为false
+            sendDeviceService.upLoadEmpToDevice(false);
         });
     }
 }