Ver código fonte

Merge remote-tracking branch 'origin/master'

xiari 1 ano atrás
pai
commit
3c8150da0e
46 arquivos alterados com 1427 adições e 98 exclusões
  1. 59 0
      ruoyi-api/ruoyi-api-hotel/src/main/java/org/dromara/hotel/api/domain/bo/RemoteDoorOpenBo.java
  2. 23 0
      ruoyi-api/ruoyi-api-hotel/src/main/java/org/dromara/hotel/api/service/RemoteOpenDoorService.java
  3. 0 6
      ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/YcEncryptUtil.java
  4. 1 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/mapper/PtRoomMapper.java
  5. 6 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/IPtRoomService.java
  6. 9 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/impl/PtRoomServiceImpl.java
  7. 131 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/lock/LockBusiness.java
  8. 1 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/ThirdPayBusiness.java
  9. 46 4
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/controller/lock/LockController.java
  10. 11 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/task/ScheduledTasks.java
  11. 9 0
      ruoyi-modules/ruoyi-backstage/src/main/resources/mapper/basics/room/PtRoomMapper.xml
  12. 34 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/dubbo/RemoteOpenDoorServiceImpl.java
  13. 12 5
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfDoorOpenHisService.java
  14. 41 22
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfDoorOpenHisServiceImpl.java
  15. 43 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/ArcFaceBusiness.java
  16. 46 29
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/BaseBusiness.java
  17. 17 4
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/ConsumeBusiness.java
  18. 1 1
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/TermBusiness.java
  19. 9 19
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/controller/v1/ConsumeController.java
  20. 49 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/controller/v1/FaceCollectController.java
  21. 50 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/PtArcFaceFeature.java
  22. 52 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/PtArcFaceKey.java
  23. 45 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/PtTermFaceVersion.java
  24. 51 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/bo/PtArcFaceFeatureBo.java
  25. 50 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/bo/PtArcFaceKeyBo.java
  26. 45 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/bo/PtTermFaceVersionBo.java
  27. 18 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/convert/YcFaceFeatureVoConvert.java
  28. 67 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/PtArcFaceFeatureVo.java
  29. 54 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/PtArcFaceKeyVo.java
  30. 48 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/PtTermFaceVersionVo.java
  31. 51 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/YcFaceFeatureVo.java
  32. 23 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/mapper/PtArcFaceFeatureMapper.java
  33. 18 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/mapper/PtArcFaceKeyMapper.java
  34. 19 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/mapper/PtTermFaceVersionMapper.java
  35. 25 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IFaceEngineService.java
  36. 27 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtArcFaceFeatureService.java
  37. 14 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtArcFaceKeyService.java
  38. 21 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtTermFaceVersionService.java
  39. 44 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/FaceEngineServiceImpl.java
  40. 32 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtArcFaceFeatureServiceImpl.java
  41. 20 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtArcFaceKeyServiceImpl.java
  42. 43 0
      ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtTermFaceVersionServiceImpl.java
  43. 25 0
      ruoyi-server/ruoyi-server-consume/src/main/resources/mapper/consume/PtArcFaceFeatureMapper.xml
  44. 19 0
      ruoyi-server/ruoyi-server-consume/src/main/resources/mapper/consume/PtArcFaceKeyMapper.xml
  45. 18 0
      ruoyi-server/ruoyi-server-consume/src/main/resources/mapper/consume/PtTermFaceVersionMapper.xml
  46. 0 5
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/cloud/ConsumeEventStrategyImpl.java

+ 59 - 0
ruoyi-api/ruoyi-api-hotel/src/main/java/org/dromara/hotel/api/domain/bo/RemoteDoorOpenBo.java

@@ -0,0 +1,59 @@
+package org.dromara.hotel.api.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 开门记录业务对象 t_kf_door_open_his
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+@Data
+public class RemoteDoorOpenBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -5379473789330294396L;
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 房间编号
+     */
+    private String roomCode;
+
+    /**
+     * 房间名称
+     */
+    private String roomName;
+
+    /**
+     * 开门方式
+     */
+    private String openDoorMode;
+
+    /**
+     * 开门时间
+     */
+    private Date openTime;
+
+    /**
+     * 开门结果
+     */
+    private String openResult;
+
+    /**
+     * 物理卡号
+     */
+    private String factoryId;
+
+    /**
+     * 开门用户
+     */
+    private Long openDoorUser;
+}

+ 23 - 0
ruoyi-api/ruoyi-api-hotel/src/main/java/org/dromara/hotel/api/service/RemoteOpenDoorService.java

@@ -0,0 +1,23 @@
+package org.dromara.hotel.api.service;
+
+import org.dromara.hotel.api.domain.bo.RemoteDoorOpenBo;
+
+/**
+ * @ClassName RemoteOpenDoorService
+ * @Description 酒店系统开门记录远程服务接口
+ * @Author luoyibo
+ * @Date 2024-11-12 12:40
+ * @Version 1.0
+ * @since jdk17
+ */
+public interface RemoteOpenDoorService {
+
+    /**
+     * 增加开门记录信息
+     *
+     * @param remoteBo 开门纪录业务对象
+     * @return 操作结果
+     */
+    Integer insertOpenDoorByBo(RemoteDoorOpenBo remoteBo);
+}
+

+ 0 - 6
ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/YcEncryptUtil.java

@@ -7,7 +7,6 @@ import cn.hutool.crypto.asymmetric.KeyType;
 import cn.hutool.crypto.asymmetric.RSA;
 import cn.hutool.crypto.digest.MD5;
 import lombok.extern.slf4j.Slf4j;
-import lombok.extern.slf4j.XSlf4j;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.utils.DigitUtils;
@@ -16,8 +15,6 @@ import org.dromara.common.redis.utils.RedisUtils;
 import javax.crypto.Cipher;
 import javax.crypto.spec.SecretKeySpec;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * name: YcEncryptUtil
@@ -127,14 +124,11 @@ public class YcEncryptUtil extends EncryptUtils {
     public static String getBalanceSecretKey(String publicKey, String data) {
         String secretKey;
         String cacheKey = CacheNames.USER_SECRET_KEY + ":" + data;
-        log.info("[卡余加密缓存KEY]-[{}]",cacheKey);
         if (ObjectUtil.isNotNull(RedisUtils.getCacheObject(cacheKey))) {
             secretKey = RedisUtils.getCacheObject(cacheKey).toString();
-            log.info("[缓存获取到的密钥]-[{}]",secretKey);
         } else {
             String md5DigestData = getMd5DigestData(publicKey);
             secretKey = encryptByMd5WidthAes(data, md5DigestData, false);
-            log.info("[生成的密钥]-[{}]",secretKey);
             RedisUtils.setCacheObject(cacheKey, secretKey);
         }
 

+ 1 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/mapper/PtRoomMapper.java

@@ -24,4 +24,5 @@ public interface PtRoomMapper extends BaseMapperPlus<PtRoom, PtRoomVo> {
     List<PtRoomVo> selectRoomLockList(@Param(Constants.WRAPPER) Wrapper<PtRoom> ew);
     List<PtRoomVo> selectHotelRoomList(@Param("areaIds") List<Long> areaIds);
     List<PtRoomVo> selectHotelRoomList();
+    PtRoomVo selectHotelRoom(@Param("roomCode") String roomCode);
 }

+ 6 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/IPtRoomService.java

@@ -121,5 +121,10 @@ public interface IPtRoomService {
      * @return 客房集合
      */
     List<PtRoomVo>queryHotelRoomList();
-
+    /**
+     * 根据房间号查询客房信息
+     * @param roomCode 房间号
+     * @return 房间信息
+     */
+    PtRoomVo selectHotelRoom(String roomCode);
 }

+ 9 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/impl/PtRoomServiceImpl.java

@@ -422,4 +422,13 @@ public class PtRoomServiceImpl implements IPtRoomService {
         return baseMapper.selectHotelRoomList();
     }
 
+    /**
+     * 根据房间号查询客房信息
+     * @param roomCode 房间号
+     * @return 房间信息
+     */
+    @Override
+    public PtRoomVo selectHotelRoom(String roomCode) {
+        return baseMapper.selectHotelRoom(roomCode);
+    }
 }

+ 131 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/lock/LockBusiness.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
+import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import lombok.RequiredArgsConstructor;
@@ -16,13 +17,16 @@ import org.dromara.backstage.util.LockUtils;
 import org.dromara.common.core.constant.DefaultConstants;
 import org.dromara.common.core.constant.LockConstants;
 import org.dromara.common.core.domain.R;
+import org.dromara.hotel.api.domain.bo.RemoteDoorOpenBo;
 import org.dromara.hotel.api.domain.bo.RemoteLockPowerBo;
 import org.dromara.hotel.api.service.RemoteLockPowerService;
+import org.dromara.hotel.api.service.RemoteOpenDoorService;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * @ClassName LockBusiness
@@ -42,6 +46,9 @@ public class LockBusiness {
     @DubboReference
     private final RemoteLockPowerService remoteLockPowerService;
 
+    @DubboReference
+    private final RemoteOpenDoorService remoteOpenDoorService;
+
     /**
      * 获取门锁发卡数据
      *
@@ -49,7 +56,7 @@ public class LockBusiness {
      * @return 发卡数据
      */
     public R<String> getWriteCardData(RoomCardBo bo) {
-        log.debug("发卡入参:{}, {}", JSONUtil.toJsonStr(bo),bo.getCardType());
+        log.debug("发卡入参:{}, {}", JSONUtil.toJsonStr(bo), bo.getCardType());
         Integer cardType = bo.getCardType();
         String cardData = "";
         Map<String, Object> formMap;
@@ -80,6 +87,7 @@ public class LockBusiness {
 
     /**
      * 远程开门
+     *
      * @param lockId 门锁Id
      * @return 开门结果
      */
@@ -117,6 +125,7 @@ public class LockBusiness {
 
     /**
      * 查询门锁电量并保持至数据库
+     *
      * @param areaId 指定区域
      * @return 查询结果
      */
@@ -128,6 +137,7 @@ public class LockBusiness {
 
     /**
      * 查询门锁电量并保持至数据库
+     *
      * @return 查询结果
      */
     public Boolean syncLockPower() {
@@ -136,8 +146,128 @@ public class LockBusiness {
         return true;
     }
 
+    /**
+     * 同步所有房间的开门记录
+     *
+     * @return 同步记录数
+     */
+    public Integer queryOpenDoorRecord() {
+        AtomicReference<Integer> openDoorRecord = new AtomicReference<>(0);
+        List<PtRoomVo> roomVos = roomService.queryHotelRoomList();
+        if (CollectionUtil.isNotEmpty(roomVos)) {
+            roomVos.parallelStream().forEach(p -> {
+                String lockId = p.getLockId();
+                openDoorRecord.updateAndGet(v -> v + this.queryOpenDoorRecord(lockId, p.getRoomCode(), p.getRoomName()));
+            });
+        }
+        return openDoorRecord.get();
+    }
+
+    public Integer queryOpenDoorRecord(Integer pageNo) {
+        AtomicReference<Integer> openDoorRecord = new AtomicReference<>(0);
+        List<PtRoomVo> roomVos = roomService.queryHotelRoomList();
+        if (CollectionUtil.isNotEmpty(roomVos)) {
+            roomVos.parallelStream().forEach(p -> {
+                String lockId = p.getLockId();
+                openDoorRecord.updateAndGet(v -> v + this.queryOpenDoorRecord(lockId, p.getRoomCode(), p.getRoomName(),pageNo));
+            });
+        }
+        return openDoorRecord.get();
+    }
+
+    public Integer queryOpenDoorRecordByRoomCode(String RoomCode) {
+        PtRoomVo vo = roomService.selectHotelRoom(RoomCode);
+        if (ObjectUtil.isNotEmpty(vo)) {
+            return queryOpenDoorRecord(vo.getLockId(), vo.getRoomCode(), vo.getRoomName());
+        } else {
+            return 0;
+        }
+    }
+    public Integer queryOpenDoorRecordByRoomCode(String RoomCode,int pageNo) {
+        PtRoomVo vo = roomService.selectHotelRoom(RoomCode);
+        if (ObjectUtil.isNotEmpty(vo)) {
+            return queryOpenDoorRecord(vo.getLockId(), vo.getRoomCode(), vo.getRoomName(),pageNo);
+        } else {
+            return 0;
+        }
+    }
+    /**
+     * 同步处理开门记录(指定门锁)
+     *
+     * @param lockId   门锁Id
+     * @param roomCode
+     * @param roomName
+     */
+    private Integer queryOpenDoorRecord(String lockId, String roomCode, String roomName) {
+        Map<String, Object> formMap = new HashMap<>();
+        formMap.put("KEYLOCKID", lockId);
+        formMap.put("CARDPSWBIT", "1");
+        formMap.put("OPERATETYPE", "2");
+        formMap.put("PAGENO", "1");
+
+        String result = lockUtils.sendPost(formMap, "operateLockRecord");
+        String flag = JSONUtil.parseObj(result).getStr("result");
+        Integer syncCount = 0;
+        if (ObjectUtil.equals(flag, "0")) {
+            int totalPage = JSONUtil.parseObj(result).getInt("totalPage");
+            for (int i = 0; i < totalPage; i++) {
+                syncCount += queryOpenDoorRecord(lockId, roomCode, roomName, i + 1);
+            }
+        }
+        return syncCount;
+    }
+
+    /**
+     * 同步处理开门记录(指定门锁与页码)
+     *
+     * @param lockId   门锁Id
+     * @param roomCode
+     * @param roomName
+     * @param pageNo   页码
+     * @return 记录条数
+     */
+    private Integer queryOpenDoorRecord(String lockId, String roomCode, String roomName, int pageNo) {
+        Map<String, Object> formMap = new HashMap<>();
+        formMap.put("KEYLOCKID", lockId);
+        formMap.put("CARDPSWBIT", "1");
+        formMap.put("OPERATETYPE", "2");
+        formMap.put("PAGENO", pageNo);
+
+        AtomicReference<Integer> syncCount = new AtomicReference<>(0);
+        String result = lockUtils.sendPost(formMap, "operateLockRecord");
+        String flag = JSONUtil.parseObj(result).getStr("result");
+        if (ObjectUtil.equals(flag, "0")) {
+            JSONArray pageData = JSONUtil.parseObj(result).getJSONArray("pageData");
+            pageData.parallelStream().forEach(p -> {
+                JSONObject record = JSONUtil.parseObj(p);
+                RemoteDoorOpenBo remoteBo = new RemoteDoorOpenBo();
+                remoteBo.setRoomCode(roomCode);
+                remoteBo.setRoomName(roomName);
+                remoteBo.setOpenDoorMode(record.getStr("openWay"));
+                remoteBo.setOpenTime(DateUtil.parse(record.getStr("operateTime"), DefaultConstants.DATE_TIME_FORMAT));
+                remoteBo.setOpenResult(record.getStr("openResult"));
+                if (ObjectUtil.isNotEmpty(record.get("cardId"))) {
+                    remoteBo.setFactoryId(record.getStr("cardId"));
+                } else {
+                    remoteBo.setFactoryId("");
+                }
+                remoteBo.setOpenDoorUser(0L);
+                try {
+                    int iCount = remoteOpenDoorService.insertOpenDoorByBo(remoteBo);
+                    if (iCount > 0) {
+                        syncCount.getAndSet(syncCount.get() + 1);
+                    }
+                } catch (Exception e) {
+                    log.error("[同步开门记录异常]-[{}]", record, e);
+                }
+            });
+        }
+        return syncCount.get();
+    }
+
     /**
      * 门锁电量入库
+     *
      * @param roomVos 门锁列表
      */
     private void insertLockPower(List<PtRoomVo> roomVos) {

+ 1 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/payments/ThirdPayBusiness.java

@@ -126,7 +126,7 @@ public class ThirdPayBusiness {
         if (ObjectUtil.isEmpty(userAccountVo)) {
             return R.fail(String.format("[无此充值账户信息]-[userId:%s]", userId));
         }
-        String callBackUrl = thirdPayConfig.getRechargeBackUrl() + "result/";
+        String callBackUrl = thirdPayConfig.getRechargeBackUrl();
         PayOrderBo payOrderBo = new PayOrderBo();
         payOrderBo.setStationId(stationId.longValue());
         payOrderBo.setCreditTime(DateUtil.date());

+ 46 - 4
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/controller/lock/LockController.java

@@ -10,6 +10,8 @@ import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.ResultCodeEnum;
 import org.springframework.web.bind.annotation.*;
 
+import java.text.MessageFormat;
+
 /**
  * name: lockController
  * package: org.dromara.backstage.controller.lock
@@ -36,21 +38,23 @@ public class LockController {
     @GetMapping(value = "/device/battery")
     ReturnResult queryDeviceBattery() {
         Boolean result = lockBusiness.syncLockPower();
-        if(result) {
+        if (result) {
             return ReturnResult.success();
         } else {
             return ReturnResult.failure(ResultCodeEnum.INTERFACE_OUTER_INVOKE_ERROR);
         }
     }
+
     @GetMapping(value = "/device/battery/{areaId}")
-    ReturnResult queryDeviceBattery(@PathVariable Long areaId){
+    ReturnResult queryDeviceBattery(@PathVariable Long areaId) {
         Boolean result = lockBusiness.syncLockPower(areaId);
-        if(result) {
+        if (result) {
             return ReturnResult.success();
         } else {
             return ReturnResult.failure(ResultCodeEnum.INTERFACE_OUTER_INVOKE_ERROR);
         }
     }
+
     /**
      * 请求发卡数据
      *
@@ -58,7 +62,7 @@ public class LockController {
      * @return 发卡数据
      */
     @GetMapping(value = "/card/data")
-    ReturnResult getRoomCardData( RoomCardBo bo) {
+    ReturnResult getRoomCardData(RoomCardBo bo) {
         return ReturnResult.success(lockBusiness.getWriteCardData(bo));
     }
 
@@ -77,4 +81,42 @@ public class LockController {
             return ReturnResult.failure(ResultCodeEnum.INTERFACE_OUTER_INVOKE_ERROR, result.getMsg());
         }
     }
+
+    /**
+     * 同步指定房间的开门记录(全部记录)
+     * @param roomCode 房间编号
+     */
+    @GetMapping(value = "/open/record/{roomCode}")
+    public ReturnResult queryOpenDoorRecord(@PathVariable String roomCode) {
+        Integer syncCount = lockBusiness.queryOpenDoorRecordByRoomCode(roomCode);
+        String message = MessageFormat.format("开门记录同步完成,本次同步了 {0} 条记录", syncCount);
+        log.info(message);
+        return ReturnResult.success(message);
+    }
+
+    /**
+     * 同步指定门锁的开门记录(指定页码)
+     * @param roomCode 门锁Id
+     * @param pageNo 页码
+     */
+    @GetMapping(value = "/open/record/{roomCode}/{pageNo}")
+    public ReturnResult queryOpenDoorRecord(@PathVariable String roomCode, @PathVariable int pageNo) {
+        Integer syncCount = lockBusiness.queryOpenDoorRecordByRoomCode(roomCode,  pageNo);
+        String message = MessageFormat.format("开门记录同步完成,本次同步了 {0} 条记录", syncCount);
+        log.info(message);
+        return ReturnResult.success(message);
+    }
+
+    /**
+     * 同步所有房间的开门记录
+     *
+     * @return 同步结果
+     */
+    @GetMapping(value = "/open/record")
+    public ReturnResult queryOpenDoorRecord() {
+        Integer syncCount = lockBusiness.queryOpenDoorRecord();
+        String message = MessageFormat.format("开门记录同步完成,本次同步了 {0} 条记录", syncCount);
+        log.info(message);
+        return ReturnResult.success(message);
+    }
 }

+ 11 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/task/ScheduledTasks.java

@@ -1,11 +1,14 @@
 package org.dromara.backstage.task;
 
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.dromara.backstage.business.lock.LockBusiness;
 import org.dromara.backstage.business.self.SelfBusiness;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
+import java.text.MessageFormat;
+
 /**
  * name: ScheduledTasks
  * package: org.dromara.backstage.task
@@ -16,6 +19,7 @@ import org.springframework.stereotype.Component;
  * @version 0.1
  * @since JDK 1.8
  */
+@Slf4j
 @Component
 @RequiredArgsConstructor
 public class ScheduledTasks {
@@ -36,4 +40,11 @@ public class ScheduledTasks {
     public void syncLockBattery(){
         lockBusiness.syncLockPower();
     }
+
+    @Scheduled(cron = "0 0 10,14,23 * * *")
+    public void syncDoorOpenRecord(){
+        int iCount = lockBusiness.queryOpenDoorRecord(1);
+        String message = MessageFormat.format("开门记录同步完成,本次同步了 {0} 条记录", iCount);
+        log.info(message);
+    }
 }

+ 9 - 0
ruoyi-modules/ruoyi-backstage/src/main/resources/mapper/basics/room/PtRoomMapper.xml

@@ -53,4 +53,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </foreach>
         </if>
     </select>
+
+    <select id="selectHotelRoom" resultType="org.dromara.backstage.basics.domain.vo.PtRoomVo">
+        SELECT tpr.*,tkrlr.lock_id,tkrlr.lock_password FROM t_pt_room tpr
+        INNER JOIN t_kf_room_lock_r tkrlr on tkrlr.room_id=tpr.room_id
+        where tpr.del_flag='0'
+        <if test="roomCode != null and roomCode!=''" >
+            and tpr.room_code = #{roomCode}
+        </if>
+    </select>
 </mapper>

+ 34 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/dubbo/RemoteOpenDoorServiceImpl.java

@@ -0,0 +1,34 @@
+package org.dromara.hotel.dubbo;
+
+import cn.hutool.core.bean.BeanUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.hotel.api.domain.bo.RemoteDoorOpenBo;
+import org.dromara.hotel.api.service.RemoteOpenDoorService;
+import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
+import org.dromara.hotel.service.IKfDoorOpenHisService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @ClassName RemoteLockPowerServiceImpl
+ * @Description 酒店门锁电量远程服务实现
+ * @Author luoyibo
+ * @Date 2024-11-14 20:31
+ * @Version 1.0
+ * @since jdk17
+ */
+
+@Slf4j
+@Service
+@DubboService
+@RequiredArgsConstructor
+public class RemoteOpenDoorServiceImpl implements RemoteOpenDoorService {
+    private final IKfDoorOpenHisService doorOpenHisService;
+
+    @Override
+    public Integer insertOpenDoorByBo(RemoteDoorOpenBo remoteBo) {
+        KfDoorOpenHisBo bo = BeanUtil.copyProperties(remoteBo, KfDoorOpenHisBo.class);
+        return doorOpenHisService.insertOrUpdateByBo(bo);
+    }
+}

+ 12 - 5
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfDoorOpenHisService.java

@@ -1,10 +1,9 @@
 package org.dromara.hotel.service;
 
-import org.dromara.hotel.domain.KfDoorOpenHis;
-import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
-import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
+import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -48,7 +47,7 @@ public interface IKfDoorOpenHisService {
      * @param bo 开门记录
      * @return 是否新增成功
      */
-    Boolean insertByBo(KfDoorOpenHisBo bo);
+    Integer insertByBo(KfDoorOpenHisBo bo);
 
     /**
      * 修改开门记录
@@ -66,4 +65,12 @@ public interface IKfDoorOpenHisService {
      * @return 是否删除成功
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 增加或修改开门记录
+     *
+     * @param bo 开门记录业务对象
+     * @return 受影响记录数
+     */
+    Integer insertOrUpdateByBo(KfDoorOpenHisBo bo);
 }

+ 41 - 22
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfDoorOpenHisServiceImpl.java

@@ -1,24 +1,25 @@
 package org.dromara.hotel.service.impl;
 
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import cn.hutool.core.collection.CollectionUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.hotel.domain.KfDoorOpenHis;
 import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
 import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
-import org.dromara.hotel.domain.KfDoorOpenHis;
 import org.dromara.hotel.mapper.KfDoorOpenHisMapper;
 import org.dromara.hotel.service.IKfDoorOpenHisService;
+import org.springframework.stereotype.Service;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Collection;
 
 /**
  * 开门记录Service业务层处理
@@ -39,7 +40,7 @@ public class KfDoorOpenHisServiceImpl implements IKfDoorOpenHisService {
      * @return 开门记录
      */
     @Override
-    public KfDoorOpenHisVo queryById(Long id){
+    public KfDoorOpenHisVo queryById(Long id) {
         return baseMapper.selectVoById(id);
     }
 
@@ -75,24 +76,24 @@ public class KfDoorOpenHisServiceImpl implements IKfDoorOpenHisService {
         lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), KfDoorOpenHis::getRoomCode, bo.getRoomCode());
         lqw.eq(StringUtils.isNotBlank(bo.getOpenDoorMode()), KfDoorOpenHis::getOpenDoorMode, bo.getOpenDoorMode());
         lqw.between(params.get("beginOpenTime") != null && params.get("endOpenTime") != null,
-            KfDoorOpenHis::getOpenTime ,params.get("beginOpenTime"), params.get("endOpenTime"));
+            KfDoorOpenHis::getOpenTime, params.get("beginOpenTime"), params.get("endOpenTime"));
         lqw.eq(StringUtils.isNotBlank(bo.getOpenResult()), KfDoorOpenHis::getOpenResult, bo.getOpenResult());
         lqw.orderByDesc(KfDoorOpenHis::getOpenTime);
         return lqw;
     }
 
-    private QueryWrapper<KfDoorOpenHis> buildQueryWrapper(KfDoorOpenHisBo bo,String tableAlias) {
+    private QueryWrapper<KfDoorOpenHis> buildQueryWrapper(KfDoorOpenHisBo bo, String tableAlias) {
         QueryWrapper<KfDoorOpenHis> lqw = new QueryWrapper<>();
         Map<String, Object> params = bo.getParams();
         String columnPrefix = "";
-        if(StringUtils.isNotBlank(tableAlias)){
+        if (StringUtils.isNotBlank(tableAlias)) {
             columnPrefix = tableAlias + ".";
         }
-        lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), columnPrefix+"room_code", bo.getRoomCode());
-        lqw.eq(StringUtils.isNotBlank(bo.getOpenDoorMode()), columnPrefix+"open_door_mode", bo.getOpenDoorMode());
+        lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), columnPrefix + "room_code", bo.getRoomCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getOpenDoorMode()), columnPrefix + "open_door_mode", bo.getOpenDoorMode());
         lqw.between(params.get("beginOpenTime") != null && params.get("endOpenTime") != null,
-        columnPrefix+"open_time" ,params.get("beginOpenTime"), params.get("endOpenTime"));
-        lqw.eq(StringUtils.isNotBlank(bo.getOpenResult()), columnPrefix+"open_result", bo.getOpenResult());
+            columnPrefix + "open_time", params.get("beginOpenTime"), params.get("endOpenTime"));
+        lqw.eq(StringUtils.isNotBlank(bo.getOpenResult()), columnPrefix + "open_result", bo.getOpenResult());
         return lqw;
     }
 
@@ -103,11 +104,11 @@ public class KfDoorOpenHisServiceImpl implements IKfDoorOpenHisService {
      * @return 是否新增成功
      */
     @Override
-    public Boolean insertByBo(KfDoorOpenHisBo bo) {
+    public Integer insertByBo(KfDoorOpenHisBo bo) {
         KfDoorOpenHis add = MapstructUtils.convert(bo, KfDoorOpenHis.class);
         validEntityBeforeSave(add);
-        boolean flag = baseMapper.insert(add) > 0;
-        if (flag) {
+        int flag = baseMapper.insert(add);
+        if (flag > 0) {
             bo.setId(add.getId());
         }
         return flag;
@@ -129,7 +130,7 @@ public class KfDoorOpenHisServiceImpl implements IKfDoorOpenHisService {
     /**
      * 保存前的数据校验
      */
-    private void validEntityBeforeSave(KfDoorOpenHis entity){
+    private void validEntityBeforeSave(KfDoorOpenHis entity) {
         //TODO 做一些数据校验,如唯一约束
     }
 
@@ -142,9 +143,27 @@ public class KfDoorOpenHisServiceImpl implements IKfDoorOpenHisService {
      */
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if(isValid){
+        if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
         return baseMapper.deleteByIds(ids) > 0;
     }
+
+    /**
+     * 增加或修改开门记录
+     *
+     * @param bo 开门记录业务对象
+     * @return 受影响记录数
+     */
+    @Override
+    public Integer insertOrUpdateByBo(KfDoorOpenHisBo bo) {
+        KfDoorOpenHis add = MapstructUtils.convert(bo, KfDoorOpenHis.class);
+        List<KfDoorOpenHisVo> vos = baseMapper.selectVoList(new LambdaQueryWrapper<KfDoorOpenHis>().eq(KfDoorOpenHis::getFactoryId, bo.getFactoryId())
+            .eq(KfDoorOpenHis::getRoomCode, bo.getRoomCode()).eq(KfDoorOpenHis::getOpenTime, bo.getOpenTime())
+            .eq(KfDoorOpenHis::getOpenDoorMode, bo.getOpenDoorMode()).eq(KfDoorOpenHis::getOpenResult, bo.getOpenResult()));
+        if (CollectionUtil.isEmpty(vos)) {
+            return baseMapper.insert(add);
+        }
+        return 0;
+    }
 }

+ 43 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/ArcFaceBusiness.java

@@ -0,0 +1,43 @@
+package org.dromara.server.consume.business;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.server.consume.domain.vo.YcFaceFeatureVo;
+import org.dromara.server.consume.domain.vo.PtArcFaceFeatureVo;
+import org.dromara.server.consume.service.IPtArcFaceFeatureService;
+import org.dromara.server.consume.service.IPtTermFaceVersionService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: ArcFaceBusiness
+ * package: org.dromara.server.consume.business
+ * description: 人脸业务处理
+ * date: 2025-02-26 16:12:29 16:12
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+public class ArcFaceBusiness {
+    private final IPtTermFaceVersionService termFaceVersionService;
+    private final IPtArcFaceFeatureService arcFaceFeatureService;
+
+    public List<YcFaceFeatureVo> getIncrementFeatureDataUser(Integer termNo) {
+        Long versionTime = termFaceVersionService.getFaceVersionByTerm(termNo);
+        if(ObjectUtil.isEmpty(versionTime) || versionTime==0L){
+            // 如果没有该值或为0,那么认为是初次调用,因此返回全量数据
+            return List.of();
+        }
+
+        Date lastDown = DateUtil.date(versionTime);
+        List<PtArcFaceFeatureVo> faceFeatureVoList = arcFaceFeatureService.getIncrFeatureDataUser(lastDown);
+        return MapstructUtils.convert(faceFeatureVoList, YcFaceFeatureVo.class);
+    }
+}

+ 46 - 29
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/BaseBusiness.java

@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
@@ -37,6 +38,7 @@ import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -138,7 +140,7 @@ public class BaseBusiness {
         List<XfConsumeDetailVo> detailVos = new ArrayList<>();
 
         for (PtBagVo bagVo : bagVos) {
-            log.info("钱包代码:{},钱包余额:{},消费金额:{}", bagVo.getBagCode(), bagVo.getBalance(), bo.getConsumeMoney());
+            log.info("扣费钱包代码:{},钱包余额:{},消费金额:{}", bagVo.getBagCode(), bagVo.getBalance(), bo.getConsumeMoney());
             XfConsumeDetailVo vo = createConsumeRecord(bo, userAccountVo, cardVo, bagVo, termVo, mealTypeVo, remark);
             // 多钱包扣费时,只要有一个钱包入消费明细表失败,则都失败
             if (ObjUtil.isEmpty(vo)) {
@@ -153,21 +155,24 @@ public class BaseBusiness {
             return R.fail(errorInfo);
         }
         // 2.更新人员日统计表
+        log.info("[上传交易]-[更新人员日统计表]-[{}]", JSONUtil.toJsonStr(bo));
         if (!createOrUpdateUserTotal(bo, userAccountVo, cardVo)) {
             return R.fail(new ErrorInfo(400, ApiErrorTypeConstants.EXCEPTION, "更新个人日统计表失败", ""));
         }
         // 3.更新设备日统计表
+        log.info("[上传交易]-[更新设备日统计表]-[{}]", JSONUtil.toJsonStr(bo));
         if (!createOrUpdateTermTotal(bo, termVo, mealTypeVo)) {
             return R.fail(new ErrorInfo(400, ApiErrorTypeConstants.EXCEPTION, "更新设备日统计表失败", ""));
         }
         // 4.更新钱包余额
+        log.info("[上传交易]-[更新钱包余额]-[{}]", JSONUtil.toJsonStr(bo));
         if (!updateBagBalance(bagVos)) {
             return R.fail(new ErrorInfo(400, ApiErrorTypeConstants.EXCEPTION, "更新钱包余额表失败", ""));
         }
 
         // 5.发送一条消费记录到kafka(教务就餐打卡)
         if (ObjectUtil.equals(defaultConfig.getLocationFlag(), DefaultConstants.LOCAL_FLAG)) {
-            this.sendConsumeToKafka(detailVos,userAccountVo);
+            this.sendConsumeToKafka(detailVos, userAccountVo);
         }
         return R.ok();
     }
@@ -212,7 +217,7 @@ public class BaseBusiness {
         CreditTypeEnum creditType = CreditTypeEnum.fromCode(bo.getCreditType());
         if (creditType != null) {
             switch (creditType) {
-                case TERM_CONSUME,HAND_CONSUME:
+                case TERM_CONSUME, HAND_CONSUME:
                     termTotalBo.setMealCount(1L);
                     termTotalBo.setMealAmount(bo.getConsumeMoney());
                     break;
@@ -235,30 +240,36 @@ public class BaseBusiness {
     public boolean updateBagBalance(List<PtBagVo> bagVos) {
         AtomicReference<Boolean> result = new AtomicReference<>();
         bagVos.parallelStream().forEach(bagVo -> {
-            PtBagBo bagBo = new PtBagBo();
-            bagBo.setUserId(bagVo.getUserId());
-            bagBo.setBagId(bagVo.getBagId());
-            bagBo.setBagCode(bagVo.getBagCode());
-            bagBo.setReceiptMoney(bagVo.getReceiptMoney());
-            bagBo.setOperationMode(BalanceUpdateEnum.CONSUME);
-            PtBagVo vo = bagService.updateBalanceByBo(bagBo);
-            // 多钱包更新余额时,只要有一个钱包更新余额失败,则都失败
-            if (ObjUtil.isEmpty(vo)) {
-                result.set(false);
+            if (bagVo.getReceiptMoney().compareTo(BigDecimal.ZERO) == 0) {
+                // 如果操作金额为0,不操作钱包余额
+                result.set(true);
+            } else {
+                PtBagBo bagBo = new PtBagBo();
+                bagBo.setUserId(bagVo.getUserId());
+                bagBo.setBagId(bagVo.getBagId());
+                bagBo.setBagCode(bagVo.getBagCode());
+                bagBo.setReceiptMoney(bagVo.getReceiptMoney());
+                bagBo.setOperationMode(BalanceUpdateEnum.CONSUME);
+                PtBagVo vo = bagService.updateBalanceByBo(bagBo);
+                // 多钱包更新余额时,只要有一个钱包更新余额失败,则都失败
+                if (ObjUtil.isEmpty(vo)) {
+                    result.set(false);
+                }
+                result.set(true);
             }
-            result.set(true);
         });
         return result.get();
     }
 
     /**
      * 请求云端消费业务的kafka消息推送
+     *
      * @param bo 请求消费数据
      */
     @Async
-    public void sendCloudConsume(ConsumptionBo bo){
+    public void sendCloudConsume(ConsumptionBo bo) {
         kafkaNormalProducer.sendKafkaMessage(KafkaTopicConstants.TO_CLOUD_TOPIC, EventTypeConstants.CONSUME, EventSenderEnum.CONSUME.code(), bo);
-        //kafkaNormalProducer.sendKafkaMessage("test", EventTypeConstants.CONSUME, EventSenderEnum.CONSUME.code(), bo);
+        // kafkaNormalProducer.sendKafkaMessage("test", EventTypeConstants.CONSUME, EventSenderEnum.CONSUME.code(), bo);
     }
 
     /**
@@ -290,7 +301,7 @@ public class BaseBusiness {
             consumeDetailBo.setConsumeDate(bo.getConsumeDate());
             consumeDetailBo.setConsumeMoney(bo.getConsumeMoney());
             consumeDetailBo.setConsumeBalance(bo.getBalance());
-            //consumeDetailBo.setCardValue(bagVo.getBalance());
+            // consumeDetailBo.setCardValue(bagVo.getBalance());
             // 设置卡片信息
             consumeDetailBo.setCardNo(cardVo.getCardNo());
             consumeDetailBo.setFactoryId(cardVo.getFactoryId());
@@ -317,51 +328,56 @@ public class BaseBusiness {
             consumeDetailBo.setTenantId(bo.getTenantId());
 
             return consumeDetailService.createConsumeDetailRecord(consumeDetailBo);
-        } catch (Exception ex){
-            log.error("消费明细入库错误",ex);
+        } catch (Exception ex) {
+            log.error("消费明细入库错误", ex);
             return null;
         }
     }
 
     /**
      * 查询指定日期的消费对账记录
+     *
      * @param consumeDate 消费日期
      * @return 消费记录
      */
-    public List<ConsumptionBo> selectOriginalReconciliation(Date consumeDate){
+    public List<ConsumptionBo> selectOriginalReconciliation(Date consumeDate) {
         return TenantHelper.ignore(() -> originalService.selectReconciliationData(consumeDate));
     }
 
     /**
      * 查询注册信息,用来检查客户的公钥和么钥
      */
-    public void getRegisterInfo(){
-        if (ObjectUtil.isEmpty(RedisUtils.getCacheObject(CacheNames.CUSTOM_PUB_KEY)) || ObjectUtil.isEmpty(RedisUtils.getCacheObject(CacheNames.CUSTOM_PRI_KEY))) {
+    public void getRegisterInfo() {
+        if (ObjectUtil.isEmpty(RedisUtils.getCacheObject(CacheNames.CUSTOM_PUB_KEY)) || ObjectUtil.isEmpty(
+            RedisUtils.getCacheObject(CacheNames.CUSTOM_PRI_KEY))) {
             remoteRegisterInfoService.queryRegisterInfo();
         }
     }
 
     /**
      * 根据消费记录的状态标志获取
+     *
      * @param statusFlag 状态标志
-     *         1,4--消费机消费=25000
-     *         3-消费补扣=25020
-     *         0-错扣补款=25010
+     *                   1,4--消费机消费=25000
+     *                   3-消费补扣=25020
+     *                   0-错扣补款=25010
      * @return 根据状态转换的消费类型
      */
-    public Integer getCreditType(Integer statusFlag){
+    public Integer getCreditType(Integer statusFlag) {
         return switch (statusFlag) {
             case 0 -> CreditTypeEnum.ERROR_FILL.code();
             case 3 -> CreditTypeEnum.HAND_CONSUME.code();
             default -> CreditTypeEnum.TERM_CONSUME.code();
         };
     }
+
     /**
      * 将消费信息发送到kafka,教务消费此消息实现就餐打卡
+     *
      * @param consumeList 消费记录列表
-     * @param accountVo 消费人员信息
+     * @param accountVo   消费人员信息
      */
-    private void sendConsumeToKafka(List<XfConsumeDetailVo> consumeList,RemoteUserAccountVo accountVo){
+    private void sendConsumeToKafka(List<XfConsumeDetailVo> consumeList, RemoteUserAccountVo accountVo) {
         for (XfConsumeDetailVo vo : consumeList) {
             YcPushConsumeInfoVo ycSendConsumeInfo = new YcPushConsumeInfoVo();
             ycSendConsumeInfo.setRecordId(vo.getRecordId().toString());
@@ -387,7 +403,8 @@ public class BaseBusiness {
             ycSendConsumeInfo.setTermRecordID(vo.getTermRecordId());
             ycSendConsumeInfo.setPosRecordState(vo.getRecordStatus().intValue());
 
-            kafkaNormalProducer.sendKafkaMessage(KafkaTopicConstants.OLD_SYNC_TOPIC, EventTypeConstants.CONSUME_RECORD, EventSenderEnum.OLD.code(), ycSendConsumeInfo);
+            kafkaNormalProducer.sendKafkaMessage(KafkaTopicConstants.OLD_SYNC_TOPIC, EventTypeConstants.CONSUME_RECORD, EventSenderEnum.OLD.code(),
+                                                 ycSendConsumeInfo);
         }
     }
 }

+ 17 - 4
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/ConsumeBusiness.java

@@ -2,6 +2,7 @@ package org.dromara.server.consume.business;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -13,6 +14,8 @@ import org.dromara.common.core.config.AsyncConfig;
 import org.dromara.common.core.constant.ApiErrorTypeConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.ErrorInfo;
+import org.dromara.common.core.enums.ConsumeRecordTypeEnum;
+import org.dromara.common.core.enums.CreditTypeEnum;
 import org.dromara.common.core.enums.ResultCodeEnum;
 import org.dromara.common.core.enums.SystemUseTypeEnum;
 import org.dromara.common.json.utils.JsonUtils;
@@ -54,7 +57,7 @@ public class ConsumeBusiness {
      * @param xfPwd 消费密码
      * @return 请求结果
      */
-    public R<ErrorInfo> createOrder(ConsumptionBo bo, java.lang.String mac, java.lang.String xfPwd) {
+    public R<ErrorInfo> createOrder(ConsumptionBo bo, String mac, String xfPwd) {
         //检查下客户的公钥与么钥
         baseBusiness.getRegisterInfo();
 
@@ -117,7 +120,7 @@ public class ConsumeBusiness {
      * @param xfPwd 消费密码
      * @return 上传结果
      */
-    public R<ErrorInfo> postOrder(ConsumptionBo bo, java.lang.String mac, java.lang.String xfPwd) {
+    public R<ErrorInfo> postOrder(ConsumptionBo bo, String mac, String xfPwd) {
         log.info("[上传交易]-[开始参数验证]-[{}]", JSONUtil.toJsonStr(bo));
         R<ErrorInfo> result = checkBusiness.checkParam(bo);
         if (R.isError(result)) {
@@ -158,7 +161,17 @@ public class ConsumeBusiness {
      * @param xfPwd 消费密码
      * @return 处理结果
      */
-    public R<ErrorInfo> fullOrder(ConsumptionBo bo, java.lang.String mac, java.lang.String xfPwd) {
+    public R<ErrorInfo> fullOrder(ConsumptionBo bo, String mac, String xfPwd) {
+        if (ObjectUtil.isEmpty(bo.getCreditType())) {
+            bo.setCreditType(CreditTypeEnum.TERM_CONSUME.code());
+        }
+        if (ObjectUtil.isEmpty(bo.getUseType())) {
+            bo.setUseType(SystemUseTypeEnum.CONSUME.code());
+        }
+        if (ObjectUtil.isEmpty(bo.getStatusFlag())) {
+            bo.setStatusFlag(Integer.valueOf(ConsumeRecordTypeEnum.XFJXF_4.code()));
+        }
+
         R<ErrorInfo> result = this.createOrder(bo, mac, xfPwd);
         if(!R.isSuccess(result)) {
             log.error("[请求交易]-[请求交易处理失败]-[{}]", JSONUtil.toJsonStr(result.getData()));
@@ -182,7 +195,7 @@ public class ConsumeBusiness {
         if (CollectionUtil.isEmpty(list)) {
             return R.ok(new ErrorInfo(ResultCodeEnum.DATA_NOT_FOUND.code(), ApiErrorTypeConstants.NOT_FOUND, "没有待入账的原始消费记录"));
         }
-        List<java.lang.String> doMessage = new ArrayList<>();
+        List<String> doMessage = new ArrayList<>();
         //循环写入原始消费记录
         int total = list.size();
         AtomicInteger success = new AtomicInteger();

+ 1 - 1
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/TermBusiness.java

@@ -132,7 +132,7 @@ public class TermBusiness {
             lastCheckModify.put(termNo, currentTime + 1000 * 60);
         }
         resultMap.put("time", DateUtil.format(nowDate, DefaultConstants.DATE_TIME_FORMAT));
-        resultMap.put("type", "");
+        resultMap.put("type", "te_term");
         resultMap.put("data", termVo == null ? "" : termVo.getTermName());
 
         return R.ok(resultMap);

+ 9 - 19
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/controller/v1/ConsumeController.java

@@ -1,6 +1,5 @@
 package org.dromara.server.consume.controller.v1;
 
-import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -26,10 +25,8 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.Date;
 import java.util.Objects;
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 /**
  * name: ConsumeController
@@ -77,14 +74,8 @@ public class ConsumeController {
         }
         RedisUtils.setCacheMapValue(CacheNames.SCHOOL_CODE, Long.toString(userNo), qrcode);
 
-        //return doRecordData(record, "requestConsume", mac, xfPwd);
+        return doRecordData(record, "requestConsume", mac, xfPwd);
 
-        Object object = doRecordData(record, "requestConsume", mac, xfPwd);
-        JSONObject jsonObject = JSONUtil.parseObj(object);
-
-        sendConsumeToCloud(jsonObject, record);
-
-        return object;
     }
 
     /**
@@ -99,12 +90,7 @@ public class ConsumeController {
     public Object consumeOriginal(@RequestBody Object record, @RequestParam(name = "mac", required = false) java.lang.String mac,
                                   @RequestParam(name = "xfPwd", required = false) java.lang.String xfPwd) {
 
-        Object object = doRecordData(record, "requestConsume", mac, xfPwd);
-        JSONObject jsonObject = JSONUtil.parseObj(object);
-
-        sendConsumeToCloud(jsonObject, record);
-
-        return object;
+        return doRecordData(record, "requestConsume", mac, xfPwd);
     }
 
     /**
@@ -116,7 +102,13 @@ public class ConsumeController {
      */
     @PostMapping("/Consume")
     public Object uploadRecord(@RequestBody Object record, @RequestParam(name = "mac", required = false) java.lang.String mac) {
-        return doRecordData(record, "uploadRecord", mac, "");
+        //return doRecordData(record, "uploadRecord", mac, "");
+        Object object = doRecordData(record, "uploadRecord", mac, "");
+        JSONObject jsonObject = JSONUtil.parseObj(object);
+
+        sendConsumeToCloud(jsonObject, record);
+
+        return object;
     }
 
     /**
@@ -174,9 +166,7 @@ public class ConsumeController {
         if (Objects.equals(type, "requestConsume")) {
             if (ObjectUtil.equals(bo.getCreditType(), CreditTypeEnum.TERM_CONSUME.code())) {
                 // 如果是消费机请求消费,将消费时间设置为当前时间,以防消费时时钟不对造成实际消费时间不正确
-                String requestTime = DateUtil.format(bo.getConsumeDate(), DefaultConstants.DATE_TIME_FORMAT);
                 bo.setConsumeDate(DateUtil.date());
-                log.info("[请求消费时间:{},调整后消费时间:{}",requestTime, DateUtil.format(bo.getConsumeDate(), DefaultConstants.DATE_TIME_FORMAT));
             }
             errorInfo = consumeBusiness.createOrder(bo, mac, xfPwd);
         } else if (Objects.equals(type, "uploadRecord")) {

+ 49 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/controller/v1/FaceCollectController.java

@@ -0,0 +1,49 @@
+package org.dromara.server.consume.controller.v1;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.api.ReturnResult;
+import org.dromara.server.consume.business.ArcFaceBusiness;
+import org.dromara.server.consume.domain.vo.YcFaceFeatureVo;
+import org.dromara.server.consume.service.IFaceEngineService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: FaceCollectController
+ * package: org.dromara.server.consume.controller.v1
+ * description: 人脸集合控制器
+ * date: 2025-02-26 08:58:33 08:58
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/faceFeature")
+public class FaceCollectController {
+    private final ArcFaceBusiness faceBusiness;
+    /**
+     * 增量下载人脸特征数据
+     * 建议设备每10分钟,从后台获取一次增量数据
+     * 后台会根据设备当前的人脸权限版本号,来取出有更新的人脸数据(若人脸版本号不存在,则返回全量人脸数据)
+     *
+     * @param termNo 设备机号
+     *
+     * @return
+     */
+    @GetMapping(value = "/incrFeature/{termNo}")
+    public ReturnResult getIncrementFeatureData(@PathVariable("termNo") Integer termNo) {
+        List<YcFaceFeatureVo> featureData = faceBusiness.getIncrementFeatureDataUser(termNo);
+        if (featureData == null) {
+            featureData = new ArrayList<>();
+        }
+
+        return new ReturnResult(true,1, "获取增量数据成功!", featureData);
+    }
+}

+ 50 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/PtArcFaceFeature.java

@@ -0,0 +1,50 @@
+package org.dromara.server.consume.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * name: PtArcFaceFeature
+ * package: org.dromara.server.consume.domain
+ * description: 人脸特征对象实体
+ * date: 2025-02-26 16:01:34 16:01
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("t_pt_arcFaceFeature")
+public class PtArcFaceFeature extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 特征Id,主键
+     */
+    @TableId(value = "feature_id")
+    private Long featureId;
+
+    /**
+     * 人员Id
+     */
+    private Long userId;
+
+    /**
+     * 人员照片地址
+     */
+    private String photo;
+
+    /**
+     * 人脸特征数据
+     */
+    private String featureData;
+}
+

+ 52 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/PtArcFaceKey.java

@@ -0,0 +1,52 @@
+package org.dromara.server.consume.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * name: PtArcFaceKey
+ * package: org.dromara.server.consume.domain
+ * description: 消费机激活表
+ * date: 2025-02-26 14:44:35 14:44
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("t_pt_arcFaceKey")
+public class PtArcFaceKey extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 激活Id,主键
+     */
+    @TableId(value = "active_id")
+    private Long activeId;
+
+    /**
+     * 激活码
+     */
+    private String activeKey;
+
+    /**
+     * 注册时间
+     */
+    private Date registerTime;
+
+    /**
+     * 设备序列号
+     */
+    private String termSn;
+
+
+}

+ 45 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/PtTermFaceVersion.java

@@ -0,0 +1,45 @@
+package org.dromara.server.consume.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * name: PtTermFaceVersion
+ * package: org.dromara.server.consume.domain
+ * description:
+ * date: 2025-02-26 15:16:14 15:16
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("t_pt_termFaceVersion")
+public class PtTermFaceVersion extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 版本Id,主键
+     */
+    @TableId(value = "version_id")
+    private Long versionId;
+
+    /**
+     * 设备机号
+     */
+    private Long termNo;
+
+    /**
+     * 版本时间
+     */
+    private Long versionTime;
+}
+

+ 51 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/bo/PtArcFaceFeatureBo.java

@@ -0,0 +1,51 @@
+package org.dromara.server.consume.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.server.consume.domain.PtArcFaceFeature;
+import jakarta.validation.constraints.*;
+/**
+ * name: PtArcFaceFeatureBo
+ * package: org.dromara.server.consume.domain.bo
+ * description: 人脸特征业务对象
+ * date: 2025-02-26 16:03:22 16:03
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = PtArcFaceFeature.class, reverseConvertGenerate = false)
+public class PtArcFaceFeatureBo extends BaseEntity {
+
+    /**
+     * 特征Id,主键
+     */
+    @NotNull(message = "特征Id,主键不能为空", groups = { EditGroup.class })
+    private Long featureId;
+
+    /**
+     * 人员Id
+     */
+    @NotNull(message = "人员Id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long userId;
+
+    /**
+     * 人员照片地址
+     */
+    @NotBlank(message = "人员照片地址不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String photo;
+
+    /**
+     * 人脸特征数据
+     */
+    @NotBlank(message = "人脸特征数据不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String featureData;
+
+
+}

+ 50 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/bo/PtArcFaceKeyBo.java

@@ -0,0 +1,50 @@
+package org.dromara.server.consume.domain.bo;
+
+import org.dromara.server.consume.domain.PtArcFaceKey;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+
+/**
+ * name: PtArcFaceKeyBo
+ * package: org.dromara.server.consume.domain.bo
+ * description:
+ * date: 2025-02-26 14:50:51 14:50
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = PtArcFaceKey.class, reverseConvertGenerate = false)
+public class PtArcFaceKeyBo extends BaseEntity {
+    /**
+     * 激活Id,主键
+     */
+    @NotNull(message = "激活Id,主键不能为空", groups = { EditGroup.class })
+    private Long activeId;
+
+    /**
+     * 激活码
+     */
+    @NotBlank(message = "激活码不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String activeKey;
+
+    /**
+     * 注册时间
+     */
+    @NotNull(message = "注册时间不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Date registerTime;
+
+    /**
+     * 设备序列号
+     */
+    @NotBlank(message = "设备序列号不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String termSn;
+}

+ 45 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/bo/PtTermFaceVersionBo.java

@@ -0,0 +1,45 @@
+package org.dromara.server.consume.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.server.consume.domain.PtTermFaceVersion;
+import jakarta.validation.constraints.*;
+/**
+ * name: PtTermFaceVersionBo
+ * package: org.dromara.server.consume.domain.bo
+ * description:
+ * date: 2025-02-26 15:19:01 15:19
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = PtTermFaceVersion.class, reverseConvertGenerate = false)
+public class PtTermFaceVersionBo extends BaseEntity {
+
+    /**
+     * 版本Id,主键
+     */
+    @NotNull(message = "版本Id,主键不能为空", groups = { EditGroup.class })
+    private Long versionId;
+
+    /**
+     * 设备机号
+     */
+    @NotNull(message = "设备机号不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long termNo;
+
+    /**
+     * 版本时间
+     */
+    @NotNull(message = "版本时间不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long versionTime;
+
+
+}

+ 18 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/convert/YcFaceFeatureVoConvert.java

@@ -0,0 +1,18 @@
+package org.dromara.server.consume.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.server.consume.domain.vo.PtArcFaceFeatureVo;
+import org.dromara.server.consume.domain.vo.YcFaceFeatureVo;
+import org.mapstruct.*;
+
+/**
+ * 卡片视图对象转换器
+ * @author bing
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface YcFaceFeatureVoConvert extends BaseMapper<PtArcFaceFeatureVo, YcFaceFeatureVo> {
+    @Mappings({
+        @Mapping(source = "realName", target = "name")
+    })
+    YcFaceFeatureVo convert(PtArcFaceFeatureVo ptArcFaceFeatureVo);
+}

+ 67 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/PtArcFaceFeatureVo.java

@@ -0,0 +1,67 @@
+package org.dromara.server.consume.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.server.consume.domain.PtArcFaceFeature;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * name: PtArcFaceFeatureVo
+ * package: org.dromara.server.consume.domain.vo
+ * description: 人脸特征视图对象
+ * date: 2025-02-26 16:04:53 16:04
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = PtArcFaceFeature.class)
+public class PtArcFaceFeatureVo  implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 特征Id,主键
+     */
+    @ExcelProperty(value = "特征Id,主键")
+    private Long featureId;
+
+    /**
+     * 人员Id
+     */
+    @ExcelProperty(value = "人员Id")
+    private Long userId;
+
+    /**
+     * 人员照片地址
+     */
+    @ExcelProperty(value = "人员照片地址")
+    private String photoUrl;
+
+    /**
+     * 人脸特征数据
+     */
+    @ExcelProperty(value = "人脸特征数据")
+    private String featureData;
+
+     /**
+     * 用户流水号
+     */
+    String userNo;
+    /**
+     * 用户学工号
+     */
+    String userNumb;
+    /**
+     * 用户姓名
+     */
+    String realName;
+
+}

+ 54 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/PtArcFaceKeyVo.java

@@ -0,0 +1,54 @@
+package org.dromara.server.consume.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.server.consume.domain.PtArcFaceKey;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * name: PtArcFaceKeyVo
+ * package: org.dromara.server.consume.domain.vo
+ * description:
+ * date: 2025-02-26 14:48:05 14:48
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = PtArcFaceKey.class)
+public class PtArcFaceKeyVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 激活Id,主键
+     */
+    @ExcelProperty(value = "激活Id,主键")
+    private Long activeId;
+
+    /**
+     * 激活码
+     */
+    @ExcelProperty(value = "激活码")
+    private String activeKey;
+
+    /**
+     * 注册时间
+     */
+    @ExcelProperty(value = "注册时间")
+    private Date registerTime;
+
+    /**
+     * 设备序列号
+     */
+    @ExcelProperty(value = "设备序列号")
+    private String termSn;
+}

+ 48 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/PtTermFaceVersionVo.java

@@ -0,0 +1,48 @@
+package org.dromara.server.consume.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.server.consume.domain.PtTermFaceVersion;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * name: PtTermFaceVersionVo
+ * package: org.dromara.server.consume.domain.vo
+ * description:
+ * date: 2025-02-26 15:17:37 15:17
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = PtTermFaceVersion.class)
+public class PtTermFaceVersionVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 版本Id,主键
+     */
+    @ExcelProperty(value = "版本Id,主键")
+    private Long versionId;
+
+    /**
+     * 设备机号
+     */
+    @ExcelProperty(value = "设备机号")
+    private Long termNo;
+
+    /**
+     * 版本时间
+     */
+    @ExcelProperty(value = "版本时间")
+    private Long versionTime;
+
+}

+ 51 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/domain/vo/YcFaceFeatureVo.java

@@ -0,0 +1,51 @@
+package org.dromara.server.consume.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * name: FaceFeatureBo
+ * package: org.dromara.server.consume.domain.bo
+ * description: 人脸特征业务对象
+ * date: 2025-02-26 09:03:55 09:03
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class YcFaceFeatureVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -7788991545488485759L;
+    /**
+     * 用户id
+     */
+    String userId;
+    /**
+     * 用户流水号
+     */
+    String userNo;
+    /**
+     * 用户学工号
+     */
+    String userNumb;
+    /**
+     * 用户姓名
+     */
+    String name;
+    /**
+     * 用户照片
+     */
+    String photoUrl;
+    /**
+     * 用户的特征码
+     */
+    String featureData;
+    /**
+     * 主键id
+     */
+    String featureId;
+}

+ 23 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/mapper/PtArcFaceFeatureMapper.java

@@ -0,0 +1,23 @@
+package org.dromara.server.consume.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.server.consume.domain.PtArcFaceFeature;
+import org.dromara.server.consume.domain.vo.PtArcFaceFeatureVo;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: PtArcFaceFeatureMapper
+ * package: org.dromara.server.consume.mapper
+ * description:
+ * date: 2025-02-26 16:08:16 16:08
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface PtArcFaceFeatureMapper extends BaseMapperPlus<PtArcFaceFeature, PtArcFaceFeatureVo> {
+    List<PtArcFaceFeatureVo> getIncrementFeatureDataUser(@Param("lastTime") Date lastTime);
+}

+ 18 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/mapper/PtArcFaceKeyMapper.java

@@ -0,0 +1,18 @@
+package org.dromara.server.consume.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.server.consume.domain.PtArcFaceKey;
+import org.dromara.server.consume.domain.vo.PtArcFaceKeyVo;
+
+/**
+ * name: PtArcFaceKeyMapper
+ * package: org.dromara.server.consume.mapper
+ * description:
+ * date: 2025-02-26 14:55:10 14:55
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface PtArcFaceKeyMapper extends BaseMapperPlus<PtArcFaceKey, PtArcFaceKeyVo> {
+}

+ 19 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/mapper/PtTermFaceVersionMapper.java

@@ -0,0 +1,19 @@
+package org.dromara.server.consume.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.server.consume.domain.PtTermFaceVersion;
+import org.dromara.server.consume.domain.vo.PtTermFaceVersionVo;
+
+/**
+ * name: PtTermFaceVersionMapper
+ * package: org.dromara.server.consume.mapper
+ * description:
+ * date: 2025-02-26 15:21:03 15:21
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface PtTermFaceVersionMapper extends BaseMapperPlus<PtTermFaceVersion, PtTermFaceVersionVo> {
+
+}

+ 25 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IFaceEngineService.java

@@ -0,0 +1,25 @@
+package org.dromara.server.consume.service;
+
+import org.dromara.server.consume.domain.vo.YcFaceFeatureVo;
+
+import java.util.List;
+
+/**
+ * name: IFaceEngineService
+ * package: org.dromara.server.consume.service
+ * description: 人脸消费相关服务
+ * date: 2025-02-26 14:03:43 14:03
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface IFaceEngineService {
+
+    /**
+     * 增量获取人脸特征数据
+     * @param termNo 消费机编号
+     * @return 人脸特征数据
+     */
+    List<YcFaceFeatureVo> getIncrementFeatureDataUser(Integer termNo);
+}

+ 27 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtArcFaceFeatureService.java

@@ -0,0 +1,27 @@
+package org.dromara.server.consume.service;
+
+import org.dromara.server.consume.domain.bo.PtArcFaceFeatureBo;
+import org.dromara.server.consume.domain.vo.PtArcFaceFeatureVo;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: PtArcFaceFeatureService
+ * package: org.dromara.server.consume.service
+ * description:
+ * date: 2025-02-26 16:10:01 16:10
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface IPtArcFaceFeatureService {
+
+    /**
+     * 获取上次下载后更新的人脸特征数据
+     * @param lastTime 上次更新时间
+     * @return 人脸特征数据
+     */
+    List<PtArcFaceFeatureVo> getIncrFeatureDataUser(Date lastTime);
+}

+ 14 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtArcFaceKeyService.java

@@ -0,0 +1,14 @@
+package org.dromara.server.consume.service;
+
+/**
+ * name: IPtArcFaceKeyService
+ * package: org.dromara.server.consume.service
+ * description:
+ * date: 2025-02-26 14:57:00 14:57
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface IPtArcFaceKeyService {
+}

+ 21 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtTermFaceVersionService.java

@@ -0,0 +1,21 @@
+package org.dromara.server.consume.service;
+
+/**
+ * name: IPtTermFaceVersionService
+ * package: org.dromara.server.consume.service
+ * description:
+ * date: 2025-02-26 15:23:21 15:23
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface IPtTermFaceVersionService {
+
+    /**
+     * 查询设备最后下载人脸特征的版本时间
+     * @param termNo 设备机号
+     * @return 版本时间
+     */
+    Long getFaceVersionByTerm(Integer termNo);
+}

+ 44 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/FaceEngineServiceImpl.java

@@ -0,0 +1,44 @@
+package org.dromara.server.consume.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.server.consume.domain.vo.YcFaceFeatureVo;
+import org.dromara.server.consume.service.IFaceEngineService;
+import org.dromara.server.consume.service.IPtTermFaceVersionService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: FaceEngineServiceImpl
+ * package: org.dromara.server.consume.service.impl
+ * description: 人脸消费相关服务实现
+ * date: 2025-02-26 14:08:27 14:08
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+public class FaceEngineServiceImpl implements IFaceEngineService {
+    private final IPtTermFaceVersionService termFaceVersionService;
+    /**
+     * 增量获取人脸特征数据
+     * @param termNo 消费机编号
+     * @return 人脸特征数据
+     */
+    @Override
+    public List<YcFaceFeatureVo> getIncrementFeatureDataUser(Integer termNo) {
+        Long versionTime = termFaceVersionService.getFaceVersionByTerm(termNo);
+        if(ObjectUtil.isEmpty(versionTime) || versionTime==0L){
+            // 如果没有该值或为0,那么认为是初次调用,因此返回全量数据
+            return List.of();
+        }
+
+        Date lastDown = DateUtil.date(versionTime);
+        return List.of();
+    }
+}

+ 32 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtArcFaceFeatureServiceImpl.java

@@ -0,0 +1,32 @@
+package org.dromara.server.consume.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.server.consume.domain.bo.PtArcFaceFeatureBo;
+import org.dromara.server.consume.domain.vo.PtArcFaceFeatureVo;
+import org.dromara.server.consume.mapper.PtArcFaceFeatureMapper;
+import org.dromara.server.consume.service.IPtArcFaceFeatureService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: PtArcFaceFeatureServiceImpl
+ * package: org.dromara.server.consume.service.impl
+ * description:
+ * date: 2025-02-26 16:10:47 16:10
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+public class PtArcFaceFeatureServiceImpl implements IPtArcFaceFeatureService {
+    private final PtArcFaceFeatureMapper baseMapper;
+
+    @Override
+    public List<PtArcFaceFeatureVo> getIncrFeatureDataUser(Date lastTime) {
+        return baseMapper.getIncrementFeatureDataUser(lastTime);
+    }
+}

+ 20 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtArcFaceKeyServiceImpl.java

@@ -0,0 +1,20 @@
+package org.dromara.server.consume.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.server.consume.service.IPtArcFaceKeyService;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: PtArcFaceKeyServiceImpl
+ * package: org.dromara.server.consume.service.impl
+ * description:
+ * date: 2025-02-26 15:01:15 15:01
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+public class PtArcFaceKeyServiceImpl implements IPtArcFaceKeyService {
+}

+ 43 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtTermFaceVersionServiceImpl.java

@@ -0,0 +1,43 @@
+package org.dromara.server.consume.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.server.consume.domain.PtTermFaceVersion;
+import org.dromara.server.consume.domain.bo.PtTermFaceVersionBo;
+import org.dromara.server.consume.domain.vo.PtTermFaceVersionVo;
+import org.dromara.server.consume.mapper.PtTermFaceVersionMapper;
+import org.dromara.server.consume.mapper.XfCardLimitedMapper;
+import org.dromara.server.consume.service.IPtTermFaceVersionService;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: PtTermFaceVersionServiceImpl
+ * package: org.dromara.server.consume.service.impl
+ * description:
+ * date: 2025-02-26 15:22:58 15:22
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Service
+public class PtTermFaceVersionServiceImpl implements IPtTermFaceVersionService {
+    private final PtTermFaceVersionMapper baseMapper;
+
+    /**
+     * 查询设备最后下载人脸特征的版本时间
+     * @param termNo 设备机号
+     * @return 版本时间
+     */
+    @Override
+    public Long getFaceVersionByTerm(Integer termNo) {
+        PtTermFaceVersionVo vo = baseMapper.selectVoOne(new LambdaQueryWrapper<PtTermFaceVersion>()
+            .eq(PtTermFaceVersion::getTermNo,termNo));
+        if (ObjectUtil.isNotEmpty(vo)) {
+            return vo.getVersionTime();
+        }
+        return 0L;
+    }
+}

+ 25 - 0
ruoyi-server/ruoyi-server-consume/src/main/resources/mapper/consume/PtArcFaceFeatureMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.server.consume.mapper.PtArcFaceFeatureMapper">
+
+    <resultMap type="org.dromara.server.consume.domain.PtArcFaceFeature" id="PtArcFaceFeatureResult">
+        <result property="featureId"    column="feature_id"    />
+        <result property="tenantId"    column="tenant_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="photo"    column="photo"    />
+        <result property="featureData"    column="feature_data"    />
+        <result property="createDept"    column="create_dept"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <select id="getIncrementFeatureDataUser" resultType="org.dromara.server.consume.domain.vo.PtArcFaceFeatureVo">
+        SELECT tpua.user_id,tpua.user_no,tpua.user_numb,tpua.real_name,tpaff.photo_url,tpaff.feature_data,tpaff.feature_id FROM t_pt_arcFaceFeature tpaff
+        INNER JOIN t_pt_userAccount tpua ON tpua.user_id=tpaff.user_id
+        WHERE tpaff.update_time>#{lastTime}
+    </select>
+</mapper>

+ 19 - 0
ruoyi-server/ruoyi-server-consume/src/main/resources/mapper/consume/PtArcFaceKeyMapper.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.server.consume.mapper.PtArcFaceKeyMapper">
+
+    <resultMap type="org.dromara.server.consume.domain.PtArcFaceKey" id="PtArcFaceKeyResult">
+        <result property="activeId"    column="active_id"    />
+        <result property="tenantId"    column="tenant_id"    />
+        <result property="activeKey"    column="active_key"    />
+        <result property="registerTime"    column="register_time"    />
+        <result property="termSn"    column="term_sn"    />
+        <result property="createDept"    column="create_dept"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+</mapper>

+ 18 - 0
ruoyi-server/ruoyi-server-consume/src/main/resources/mapper/consume/PtTermFaceVersionMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.server.consume.mapper.PtTermFaceVersionMapper">
+
+    <resultMap type="org.dromara.server.consume.domain.PtTermFaceVersion" id="PtTermFaceVersionResult">
+        <result property="versionId"    column="version_id"    />
+        <result property="tenantId"    column="tenant_id"    />
+        <result property="termNo"    column="term_no"    />
+        <result property="versionTime"    column="version_time"    />
+        <result property="createDept"    column="create_dept"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+</mapper>

+ 0 - 5
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/cloud/ConsumeEventStrategyImpl.java

@@ -33,12 +33,7 @@ public class ConsumeEventStrategyImpl implements IYktEventStrategy {
         if (ObjectUtil.equals(eventType, EventTypeConstants.CONSUME)) {
             // 解决枚举类转换异常的问题
             JSONObject entries = JSONUtil.parseObj(msg);
-            //entries.set("creditType", null);
-            //entries.set("useType", null);
             RemoteConsumeBo recordBo = JSONUtil.toBean(entries, RemoteConsumeBo.class);
-            //recordBo.setStatusFlag(4);
-            //recordBo.setUseType(String.CONSUME);
-            //recordBo.setCreditType(CreditTypeEnum.TERM_CONSUME);
             log.info("[处理本地->云端消费请求]-[消费信息:{}]", JSONUtil.toJsonStr(recordBo));
             remoteConsumeService.dealKafkaConsumeData(recordBo);
         }