瀏覽代碼

Merge remote-tracking branch 'origin/master'

luo.yibo@datuai.com 1 年之前
父節點
當前提交
295f769eb2
共有 21 個文件被更改,包括 253 次插入113 次删除
  1. 8 0
      ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/RemotePtXfTermService.java
  2. 6 0
      ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/RemoteUserAccountService.java
  3. 10 0
      ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/domain/vo/RemoteUserAccountVo.java
  4. 9 0
      ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/domain/vo/RemoteXfTermVo.java
  5. 2 2
      ruoyi-modules/ruoyi-backstage/pom.xml
  6. 8 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/IPtCardService.java
  7. 13 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/cardCenter/service/impl/PtCardServiceImpl.java
  8. 9 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/XfTerm.java
  9. 9 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/bo/XfTermBo.java
  10. 8 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/vo/XfTermVo.java
  11. 21 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/dubbo/RemoteXfTermServiceImpl.java
  12. 7 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/IXfTermService.java
  13. 14 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/impl/XfTermServiceImpl.java
  14. 10 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/domain/vo/PtUserAccountVo.java
  15. 31 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/dubbo/RemoteUserAccountServiceImpl.java
  16. 7 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/IPtUserAccountService.java
  17. 53 110
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/service/impl/PtUserAccountServiceImpl.java
  18. 9 0
      sql/2025-5-21/kingbase/ddl.sql
  19. 8 0
      sql/2025-5-21/kingbase/dml.sql
  20. 3 0
      sql/2025-5-21/mysql/ddl.sql
  21. 8 0
      sql/2025-5-21/mysql/dml.sql

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

@@ -5,6 +5,7 @@ import org.dromara.backstage.api.domain.bo.RemoteXfTermParamBo;
 import org.dromara.backstage.api.domain.vo.RemoteXfTermVo;
 
 import java.util.Collection;
+import java.util.List;
 
 /**
  * 消费设备服务
@@ -41,4 +42,11 @@ public interface RemotePtXfTermService {
      */
     RemoteXfTermVo queryByNo(Long termNo,String tenantId);
 
+    /**
+     * 根据品牌查询设备列表
+     * @param brand 设备品牌
+     * @return 设备信息列表
+     */
+    List<RemoteXfTermVo> queryListByBrand(String brand);
+
 }

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

@@ -82,4 +82,10 @@ public interface RemoteUserAccountService {
      */
     List<RemoteUserAccountVo> getAllUserAccountVo();
 
+
+    List<RemoteUserAccountVo> getUserAccountVoList();
+
+    RemoteUserAccountVo getUserAccountVoBy(Long userId);
+
+
 }

+ 10 - 0
ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/domain/vo/RemoteUserAccountVo.java

@@ -173,4 +173,14 @@ public class RemoteUserAccountVo implements Serializable {
      * 租户编号
      */
     private String tenantId;
+
+    /**
+     * 物理卡号
+     */
+    private Long factoryId;
+
+    /**
+     * 完整的人脸照片地址
+     */
+    private String facePicUrl;
 }

+ 9 - 0
ruoyi-api/ruoyi-api-backstage/src/main/java/org/dromara/backstage/api/domain/vo/RemoteXfTermVo.java

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

+ 2 - 2
ruoyi-modules/ruoyi-backstage/pom.xml

@@ -162,11 +162,11 @@
         </dependency>
 
         <!-- 人脸识别 -->
-        <dependency>
+        <!--<dependency>
             <groupId>com.arcsoft.face</groupId>
             <artifactId>arcsoft-sdk-face</artifactId>
             <version>1.1.1.0</version>
-        </dependency>
+        </dependency>-->
         <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-api-consume</artifactId>

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

@@ -44,6 +44,14 @@ public interface IPtCardService {
      */
     List<PtCardVo> queryList(PtCardBo bo);
 
+    /**
+     * 查询账户卡片列表
+     *
+     * @param bo 账户卡片
+     * @return 账户卡片
+     */
+    List<PtCardVo> getList(PtCardBo bo);
+
     /**
      * 新增账户卡片
      *

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

@@ -106,6 +106,19 @@ public class PtCardServiceImpl implements IPtCardService {
         return list;
     }
 
+    /**
+     * 查询账户卡片列表
+     *
+     * @param bo 账户卡片
+     * @return 账户卡片
+     */
+    @Override
+    public List<PtCardVo> getList(PtCardBo bo) {
+        LambdaQueryWrapper<PtCard> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+
     private LambdaQueryWrapper<PtCard> buildQueryWrapper(PtCardBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<PtCard> lqw = Wrappers.lambdaQuery();

+ 9 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/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-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/bo/XfTermBo.java

@@ -356,5 +356,14 @@ public class XfTermBo extends TenantEntity {
      */
     private String remark;
 
+    /*消费机管理账号*/
+    private String adminName;
+
+    /*消费机管理密码*/
+    private String adminPwd;
+
+    /*消费机品牌*/
+    private String brand;
+
 
 }

+ 8 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/vo/XfTermVo.java

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

+ 21 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/dubbo/RemoteXfTermServiceImpl.java

@@ -2,6 +2,7 @@ package org.dromara.backstage.consumption.dubbo;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.util.StringUtils;
 import lombok.RequiredArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.dromara.backstage.api.RemotePtXfTermService;
@@ -12,10 +13,12 @@ import org.dromara.backstage.consumption.domain.bo.XfTermBo;
 import org.dromara.backstage.consumption.domain.bo.XfTermParamBo;
 import org.dromara.backstage.consumption.domain.vo.XfTermVo;
 import org.dromara.backstage.consumption.service.IXfTermService;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.springframework.stereotype.Service;
 
 import java.util.Collection;
+import java.util.List;
 
 /**
  * @author Hz
@@ -61,4 +64,22 @@ public class RemoteXfTermServiceImpl implements RemotePtXfTermService {
         }
         return null;
     }
+
+    /**
+     * 根据品牌查询设备列表
+     *
+     * @param brand 设备品牌
+     * @return 设备信息列表
+     */
+    @Override
+    public List<RemoteXfTermVo> queryListByBrand(String brand) {
+        if(StringUtils.isBlank(brand)){
+            throw new ServiceException("品牌不能为空");
+        }
+        List<XfTermVo> xfTermVos = xfTermService.queryListByBrand(brand);
+        if (ObjectUtil.isNotEmpty(xfTermVos)) {
+            return MapstructUtils.convert(xfTermVos, RemoteXfTermVo.class);
+        }
+        return null;
+    }
 }

+ 7 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/IXfTermService.java

@@ -48,6 +48,13 @@ public interface IXfTermService {
     List<XfTermVo> queryListByNoOrName(XfTermBo bo);
     List<XfTermVo> queryListByIds(List<Long> ids);
 
+    /**
+     * 根据品牌查询设备列表
+     * @param brand
+     * @return
+     */
+    List<XfTermVo> queryListByBrand(String brand);
+
     public Map<Long,XfTermVo> queryMapByIds(List<Long> ids);
 
     /**

+ 14 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/impl/XfTermServiceImpl.java

@@ -136,6 +136,19 @@ public class XfTermServiceImpl implements IXfTermService {
         return baseMapper.selectVoList(lqw.in(XfTerm::getTermId, ids));
     }
 
+    /**
+     * 根据品牌查询设备列表
+     *
+     * @param brand
+     * @return
+     */
+    @Override
+    public List<XfTermVo> queryListByBrand(String brand) {
+        LambdaQueryWrapper<XfTerm> lqw = Wrappers.lambdaQuery();
+        lqw.eq(XfTerm::getBrand, brand);
+        return baseMapper.selectVoList(lqw);
+    }
+
     public Map<Long, XfTermVo> queryMapByIds(List<Long> ids) {
         List<XfTermVo> xfTermVos = queryListByIds(ids);
         if (CollectionUtil.isNotEmpty(xfTermVos)) {
@@ -151,6 +164,7 @@ public class XfTermServiceImpl implements IXfTermService {
         lqw.eq(bo.getTermNo() != null, XfTerm::getTermNo, bo.getTermNo());
         lqw.like(StringUtils.isNotBlank(bo.getTermName()), XfTerm::getTermName, bo.getTermName());
         lqw.eq(StringUtils.isNotBlank(bo.getTermIp()), XfTerm::getTermIp, bo.getTermIp());
+        lqw.eq(StringUtils.isNotBlank(bo.getBrand()), XfTerm::getBrand, bo.getBrand());
 
         lqw.orderByAsc(XfTerm::getTermNo);
         return lqw;

+ 10 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/payment/domain/vo/PtUserAccountVo.java

@@ -4,6 +4,7 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
+import org.dromara.backstage.domain.vo.card.PtCardVo;
 import org.dromara.backstage.payment.domain.PtUserAccount;
 import org.dromara.common.excel.annotation.ExcelDictFormat;
 import org.dromara.common.excel.convert.ExcelDictConvert;
@@ -13,7 +14,7 @@ import org.dromara.common.translation.constant.TransConstant;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.Date;
-
+import java.util.List;
 
 
 /**
@@ -276,4 +277,12 @@ public class PtUserAccountVo implements Serializable {
     private String customerName;
     //商户编号
     private String customerNo;
+
+    // 一个账户 只会 有一个 状态为正常的卡片
+    private PtCardVo card;
+
+    /**
+     * 完整的人脸照片地址
+     */
+    private String facePicUrl;
 }

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

@@ -1,6 +1,7 @@
 package org.dromara.backstage.payment.dubbo;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import lombok.RequiredArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.dromara.backstage.api.RemoteUserAccountService;
@@ -14,6 +15,7 @@ import org.dromara.common.core.domain.R;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -142,4 +144,33 @@ public class RemoteUserAccountServiceImpl implements RemoteUserAccountService {
         List<PtUserAccountVo> voList = userAccountService.queryList(bo);
         return MapstructUtils.convert(voList,RemoteUserAccountVo.class);
     }
+
+    @Override
+    public List<RemoteUserAccountVo> getUserAccountVoList() {
+        List<PtUserAccountVo> userAccountsAndCard = userAccountService.getUserAccountsAndCard(null);
+        List<RemoteUserAccountVo> rs = new ArrayList<>();
+        for (PtUserAccountVo userAccountAndCard : userAccountsAndCard) {
+            RemoteUserAccountVo vo = MapstructUtils.convert(userAccountAndCard, RemoteUserAccountVo.class);
+            if(vo !=null){
+                vo.setFactoryId(userAccountAndCard.getCard().getFactoryId());
+                rs.add(vo);
+            }
+        }
+        return rs;
+    }
+
+    @Override
+    public RemoteUserAccountVo getUserAccountVoBy(Long userId) {
+        List<PtUserAccountVo> userAccountsAndCard = userAccountService.getUserAccountsAndCard(userId);
+        if(CollectionUtil.isEmpty(userAccountsAndCard)){
+            return null;
+        }
+        RemoteUserAccountVo convert = MapstructUtils.convert(userAccountsAndCard.get(0), RemoteUserAccountVo.class);
+        if(convert != null){
+            convert.setFactoryId(userAccountsAndCard.get(0).getCard().getFactoryId());
+        }
+        return convert;
+    }
+
+
 }

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

@@ -201,4 +201,11 @@ public interface IPtUserAccountService {
     int delByUserAndDeptId(Long userId,Long deptId, Long operatorId);
 
     PtUserAccount4SelectVo getCardInfoByFactoryId(String factoryId);
+
+    /**
+     * 根据用户查询账户信息及账户卡信息
+     * @param userId userId 为null 则查询所有账户信息
+     * @return 账户信息及账户卡信息
+     */
+    List<PtUserAccountVo> getUserAccountsAndCard(Long userId);
 }

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

@@ -1,6 +1,7 @@
 package org.dromara.backstage.payment.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.lang.UUID;
 import cn.hutool.core.util.ObjUtil;
@@ -19,6 +20,7 @@ import org.dromara.backstage.basics.domain.vo.PtCardtypeVo;
 import org.dromara.backstage.basics.service.IPtCardtypeService;
 import org.dromara.backstage.cardCenter.domain.bo.PtCardBo;
 import org.dromara.backstage.cardCenter.service.IPtCardService;
+import org.dromara.backstage.domain.vo.card.PtCardVo;
 import org.dromara.backstage.domain.vo.yc.YcTraineeVo;
 import org.dromara.backstage.mq.PushKafkaData;
 import org.dromara.backstage.payment.domain.PtUserAccount;
@@ -31,6 +33,7 @@ import org.dromara.backstage.payment.service.IPtUserAccountService;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.constant.DefaultConstants;
 import org.dromara.common.core.domain.R;
+import org.dromara.common.core.enums.CardStatusEnum;
 import org.dromara.common.core.service.DictService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.SpringUtils;
@@ -47,6 +50,7 @@ import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.tenant.helper.TenantHelper;
 import org.dromara.system.api.RemoteDeptService;
 import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -80,6 +84,9 @@ public class PtUserAccountServiceImpl implements IPtUserAccountService {
     @DubboReference
     private final RemoteDeptService remoteDeptService;
 
+    @Value("${photo-prefix:}")
+    private String photoPrefix;
+
     /**
      * 查询一卡通账户
      *
@@ -602,116 +609,6 @@ public class PtUserAccountServiceImpl implements IPtUserAccountService {
         return 0;
     }
 
-    public static void downloadPicture(String urlList, String name, String userNumb) {
-        URL url = null;
-        int imageNumber = 0;
-
-        try {
-            url = new URL("http://172.16.137.86:8080/upload/" + urlList);
-            DataInputStream dataInputStream = new DataInputStream(url.openStream());
-
-            String imageName = "C:\\Users\\LENOVO\\Desktop\\img\\" + name + "_" + userNumb + urlList.substring(urlList.lastIndexOf("."));
-
-            FileOutputStream fileOutputStream = new FileOutputStream(new File(imageName));
-            ByteArrayOutputStream output = new ByteArrayOutputStream();
-
-            byte[] buffer = new byte[1024];
-            int length;
-
-            while ((length = dataInputStream.read(buffer)) > 0) {
-                output.write(buffer, 0, length);
-            }
-            byte[] context = output.toByteArray();
-            fileOutputStream.write(output.toByteArray());
-            dataInputStream.close();
-            fileOutputStream.close();
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    public static class ImageData {
-        private String url;
-        private String name;
-
-        private String userNumb;
-
-        public ImageData(String url, String name, String userNumb) {
-            this.url = url;
-            this.name = name;
-            this.userNumb = userNumb;
-        }
-    }
-
-    public static List<ImageData> parseTxt(String filePath) {
-        return FileUtils.readLines(filePath, Charset.defaultCharset()).stream().map(line -> {
-            String[] split = line.split("\\|");
-            if (split.length != 3) {
-                throw new RuntimeException("txt文件格式错误");
-            }
-            String userNumb = split[0].replaceAll(" ", "");
-            String url = split[1].replaceAll(" ", "");
-            String name = split[2].replaceAll(" ", "");
-            return new ImageData(url, name, userNumb);
-        }).collect(Collectors.toList());
-    }
-
-    //使用 http form-data方式上传图片,使用hutool工具包
-    public static String uploadImage(String userNumb, String name) throws IOException {
-        //使用 http form-data方式上传图片,使用hutool工具包
-        String imagePath = "C:\\Users\\LENOVO\\Desktop\\img\\" + name + "_" + userNumb + ".jpg";
-        File file = new File(imagePath);
-        Long length = file.length();
-        if (!file.exists() || length <= 0) {
-            System.err.println(userNumb + " " + name + " " + "照片不存在 " + imagePath);
-            return "error: " + userNumb + " " + name + " " + "照片不存在";
-        }
-        Map<String, String> headers = new HashMap<>();
-        headers.put("Content-Type", "multipart/form-data");
-        headers.put("cookie", "Data=jsv2g08wiSwgsuDrAwQvLCDfueDealwvg330G2yywIAVWXnLV1M/jR6EKPdJqhxGkWwYfHnmjF6+WJk2b8t4gPWQ8T35rBBxD1GiOIQF9jM%3D; Words=MTY6OTQyNjgyNDIyOjg1ODkyODk0NTo5NDMwNzU2MzI6ODQyMDE5NjM3");
-        String json = "{\"method\":\"faceInfoUpdate.addFace\",\"params\":{\"GroupID\":1,\"PersonInfo\":{\"CertificateType\":\"IC\",\"ID\":\"" + userNumb + "\"},\"ImageInfo\":{\"Lengths\":[" + length + "],\"Amount\":1}},\"session\":\"1d6e61e33641e339c68a3930c4b3e949\",\"id\":120}";
-//        System.err.println(" json "+json);
-        HttpRequest form = HttpRequest.post("http://172.19.50.101/CmdCall")
-            .addHeaders(headers)
-            .form("json", json)
-            .form("data", file);
-        HttpResponse execute = form.execute();
-        String body = execute.body();
-
-        if (body.contains("error")) {
-            System.err.println("error: " + userNumb + " " + name + " " + "照片上传失败,请手动上传" + "  " + body);
-        } else {
-            System.out.println("state : " + userNumb + " " + name + " " + execute.isOk() + "  " + body);
-        }
-//        System.err.println("body : " + body);
-        return "ok";
-    }
-
-    public static void main(String[] args) throws IOException {
-        /*List<ImageData> list = new ArrayList<>();
-        list = parseTxt("C:\\Users\\LENOVO\\Desktop\\T_PT_User_202410221658_txt.txt");
-
-        System.err.println(list);
-
-        list.forEach(item->{
-            downloadPicture(item.url,item.name, item.userNumb);
-        });*/
-        /*File file = new File("C:\\Users\\LENOVO\\Desktop\\img\\冯晓辉_2022118036.jpg");
-        System.err.println(file.length());*/
-
-        List<ImageData> list = new ArrayList<>();
-        list = parseTxt("C:\\Users\\LENOVO\\Desktop\\userdata.txt");
-
-        for (ImageData imageData : list) {
-            uploadImage(imageData.userNumb, imageData.name);
-        }
-
-
-        System.err.println("11111");
-    }
-
     @Override
     public PtUserAccount4SelectVo getCardInfoByFactoryId(String factoryId) {
         if (StringUtils.isBlank(factoryId)){
@@ -729,4 +626,50 @@ public class PtUserAccountServiceImpl implements IPtUserAccountService {
         return res;
 
     }
+
+    /**
+     * 根据用户查询账户信息及账户卡信息
+     *
+     * @param userId userId 为null 则查询所有账户信息
+     * @return 账户信息及账户卡信息
+     */
+    @Override
+    public List<PtUserAccountVo> getUserAccountsAndCard(Long userId) {
+        List<PtUserAccountVo> res = new ArrayList<>();
+        //账户信息
+        LambdaQueryWrapper<PtUserAccount> lqw = Wrappers.lambdaQuery();
+        lqw.eq(userId != null, PtUserAccount::getUserId, userId);
+        List<PtUserAccountVo> userAccounts = baseMapper.selectVoList(lqw);
+        if(CollectionUtil.isEmpty(userAccounts)){
+            return res;
+        }
+        // 正常卡信息
+        PtCardBo ptCardBo = new PtCardBo();
+        ptCardBo.setStatus(CardStatusEnum.NORMAL.code().toString());
+        if(userId != null){
+            ptCardBo.setUserId(userId);
+        }
+        List<PtCardVo> cards = ptCardService.getList(ptCardBo);
+        if(CollectionUtil.isEmpty(cards)){
+            return userAccounts;
+        }
+
+        // 拼接信息
+        for (PtUserAccountVo userAccount : userAccounts) {
+            Long id = userAccount.getUserId();
+            // 按时间排序
+            PtCardVo ptCardVo = new PtCardVo();
+            Optional<PtCardVo> first = cards.stream()
+                .filter(p -> Objects.equals(p.getUserId(), id))
+                .sorted(Comparator.comparing(PtCardVo::getChangeTime).reversed()).findFirst();
+            if(first.isPresent()){
+                ptCardVo = first.get();
+            }
+            userAccount.setCard(ptCardVo);
+            userAccount.setFacePicUrl(photoPrefix+userAccount.getPhoto());
+        }
+        return res;
+    }
+
+
 }

+ 9 - 0
sql/2025-5-21/kingbase/ddl.sql

@@ -0,0 +1,9 @@
+ALTER TABLE "dbo"."t_xf_term" ADD COLUMN admin_name CHARACTER VARYING(
+    32 char
+    ) NOT NULL DEFAULT 'admin'::varchar COMMENT '消费机管理账号';
+ALTER TABLE "dbo"."t_xf_term" ADD COLUMN admin_pwd CHARACTER VARYING(
+    32 char
+    ) NOT NULL DEFAULT 'Dt20250512'::varchar COMMENT '消费机管理密码';
+ALTER TABLE "dbo"."t_xf_term" ADD COLUMN brand CHARACTER VARYING(
+    4 char
+    ) NOT NULL DEFAULT 'dt'::varchar COMMENT '消费机品牌';

+ 8 - 0
sql/2025-5-21/kingbase/dml.sql

@@ -0,0 +1,8 @@
+INSERT INTO t_sys_dictType ("dict_id","tenant_id","dict_name","dict_type","create_dept","create_by","create_time","update_by","update_time","remark","del_flag") VALUES
+    (1925092337927163906,'25','消费机品牌','xf_brand',100,100,'''2025-05-21 15:32:35''',100,'''2025-05-21 15:32:35''','消费机品牌','0');
+
+
+INSERT INTO t_sys_dictData ("dict_code","tenant_id","dict_sort","dict_label","dict_value","dict_type","css_class","list_class","is_default","create_dept","create_by","create_time","update_by","update_time","remark","del_flag")
+VALUES
+    (1925092890581241857,'25',1,'海康','hk','xf_brand','','success','N',100,100,'''2025-05-21 15:34:46''',100,'''2025-05-21 15:34:46''','','0'),
+    (1925092664504061954,'25',0,'大图','dt','xf_brand','','primary','N',100,100,'''2025-05-21 15:33:52''',100,'''2025-05-21 15:33:52''','','0');

+ 3 - 0
sql/2025-5-21/mysql/ddl.sql

@@ -0,0 +1,3 @@
+ALTER TABLE t_xf_term ADD admin_name varchar(32) not NULL  DEFAULT 'admin' comment '消费机管理账号';
+ALTER TABLE t_xf_term ADD admin_pwd varchar(32) not NULL  DEFAULT 'Dt20250512' comment '消费机管理密码';
+ALTER TABLE t_xf_term ADD brand varchar(4) not NULL  DEFAULT 'dt' comment '消费机品牌';

+ 8 - 0
sql/2025-5-21/mysql/dml.sql

@@ -0,0 +1,8 @@
+INSERT INTO t_sys_dictType (dict_id,tenant_id,dict_name,dict_type,create_dept,create_by,create_time,update_by,update_time,remark,del_flag) VALUES
+    (1925092337927163906,'25','消费机品牌','xf_brand',100,100,'2025-05-21 15:32:35',100,'2025-05-21 15:32:35','消费机品牌','0');
+
+
+INSERT INTO t_sys_dictData (dict_code,tenant_id,dict_sort,dict_label,dict_value,dict_type,css_class,list_class,is_default,create_dept,create_by,create_time,update_by,update_time,remark,del_flag)
+VALUES
+    (1925092890581241857,'25',1,'海康','hk','xf_brand','','success','N',100,100,'2025-05-21 15:34:46',100,'2025-05-21 15:34:46','','0'),
+    (1925092664504061954,'25',0,'大图','dt','xf_brand','','primary','N',100,100,'2025-05-21 15:33:52',100,'2025-05-21 15:33:52','','0');