Przeglądaj źródła

feat:冷链设备新增字段的适配
feat:预警人员新增新增接口
feat:新增同步公网系统人员及预警人员功能
fix:修改私有化用户无法公众号跳转小程序

黄渊昊 4 dni temu
rodzic
commit
2075f241fb
12 zmienionych plików z 338 dodań i 10 usunięć
  1. 213 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/AlarmUserScheduled.java
  2. 5 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/entity/AlarmUser.java
  3. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/param/AlarmUserAddParam.java
  4. 3 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/param/AlarmUserEditParam.java
  5. 28 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/service/impl/AlarmUserServiceImpl.java
  6. 18 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/entity/MonitorDevice.java
  7. 19 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/param/MonitorDeviceAddParam.java
  8. 19 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/param/MonitorDeviceEditParam.java
  9. 2 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/service/impl/MonitorDeviceServiceImpl.java
  10. 10 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/utils/PushUtil.java
  11. 1 1
      snowy-web-app/src/main/resources/application-master.properties
  12. 5 1
      snowy-web-app/src/main/resources/application.properties

+ 213 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/AlarmUserScheduled.java

@@ -0,0 +1,213 @@
+package vip.xiaonuo.coldchain.modular.alarmuser;
+
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.coldchain.modular.alarmuser.entity.AlarmUser;
+import vip.xiaonuo.coldchain.modular.alarmuser.service.AlarmUserService;
+import vip.xiaonuo.sys.modular.user.entity.SysUser;
+import vip.xiaonuo.sys.modular.user.service.SysUserService;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component
+@ConditionalOnProperty(name = "private.flag", havingValue = "true")
+@Slf4j
+public class AlarmUserScheduled {
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+    @Resource
+    private SysUserService sysUserService;
+    @Resource
+    private AlarmUserService alarmUserService;
+
+    @Scheduled(cron = "${private.cron}")
+    @Transactional
+    public void alarmUser() {
+        log.info("开始执行数据同步任务");
+        long startTime = System.currentTimeMillis();
+
+        try {
+            // 同步sys_user数据
+            syncSysUserData();
+
+            // 同步alarm_user数据
+            syncAlarmUserData();
+
+            long costTime = System.currentTimeMillis() - startTime;
+            log.info("数据同步任务完成,耗时: {}ms", costTime);
+
+        } catch (Exception e) {
+            log.error("数据同步任务执行失败", e);
+        }
+    }
+
+    /**
+     * 同步sys_user数据
+     */
+    private void syncSysUserData() {
+        try {
+            // 获取公网的sysUser
+            List<SysUser> publicSysUserList = getPublicSysUserList();
+            // 获取本地的sysUser
+            List<SysUser> privateSysUserList = sysUserService.list();
+
+            log.info("SysUser同步 - 公网: {}条, 本地: {}条",
+                    publicSysUserList.size(), privateSysUserList.size());
+
+            // 差异对比,对本地sysUser进行更新,只增不减
+            List<SysUser> newSysUsers = extractNewSysUsers(publicSysUserList, privateSysUserList);
+
+            if (!newSysUsers.isEmpty()) {
+                sysUserService.saveBatch(newSysUsers);
+                log.info("SysUser同步 - 成功新增 {} 条数据", newSysUsers.size());
+            } else {
+                log.info("SysUser同步 - 没有新数据需要同步");
+            }
+
+        } catch (Exception e) {
+            log.error("SysUser数据同步失败", e);
+        }
+    }
+
+    /**
+     * 同步alarm_user数据
+     */
+    private void syncAlarmUserData() {
+        try {
+            // 获取公网的alarmUser
+            List<AlarmUser> publicAlarmUserList = getPublicAlarmUserList();
+            // 获取本地的alarmUser
+            List<AlarmUser> privateAlarmUserList = alarmUserService.list();
+
+            log.info("AlarmUser同步 - 公网: {}条, 本地: {}条",
+                    publicAlarmUserList.size(), privateAlarmUserList.size());
+
+            // 差异对比,对本地alarmUser进行更新,只增不减
+            List<AlarmUser> newAlarmUsers = extractNewAlarmUsers(publicAlarmUserList, privateAlarmUserList);
+
+            if (!newAlarmUsers.isEmpty()) {
+                alarmUserService.saveBatch(newAlarmUsers);
+                log.info("AlarmUser同步 - 成功新增 {} 条数据", newAlarmUsers.size());
+            } else {
+                log.info("AlarmUser同步 - 没有新数据需要同步");
+            }
+
+        } catch (Exception e) {
+            log.error("AlarmUser数据同步失败", e);
+        }
+    }
+
+    /**
+     * 使用JdbcTemplate获取公网sys_user数据
+     */
+    public List<SysUser> getPublicSysUserList() {
+        String sql = "SELECT * FROM sys_user_public WHERE DELETE_FLAG = 'NOT_DELETE'";
+        try {
+            // 方式1:使用BeanPropertyRowMapper(字段名匹配时)
+            return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(SysUser.class));
+        } catch (Exception e) {
+            log.warn("BeanPropertyRowMapper映射失败,尝试手动映射: {}", e.getMessage());
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 使用JdbcTemplate获取公网alarm_user数据
+     */
+    public List<AlarmUser> getPublicAlarmUserList() {
+        String sql = "SELECT * FROM alarm_user_public WHERE DELETE_FLAG = 'NOT_DELETE'";
+        try {
+            return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(AlarmUser.class));
+        } catch (Exception e) {
+            log.warn("BeanPropertyRowMapper映射失败,尝试手动映射: {}", e.getMessage());
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 提取新的SysUser(公网有但本地没有的)
+     */
+    private List<SysUser> extractNewSysUsers(List<SysUser> publicUsers, List<SysUser> privateUsers) {
+        if (publicUsers == null || publicUsers.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // 提取本地用户的ID集合
+        Set<String> privateUserIds = privateUsers.stream()
+                .map(SysUser::getId)
+                .filter(id -> id != null && !id.trim().isEmpty())
+                .collect(Collectors.toSet());
+
+        // 过滤出公网用户中ID不在本地用户ID集合中的用户
+        return publicUsers.stream()
+                .filter(user -> user.getId() != null && !user.getId().trim().isEmpty())
+                .filter(user -> !privateUserIds.contains(user.getId()))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 提取新的AlarmUser(公网有但本地没有的)
+     */
+    private List<AlarmUser> extractNewAlarmUsers(List<AlarmUser> publicUsers, List<AlarmUser> privateUsers) {
+        if (publicUsers == null || publicUsers.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // 提取本地用户的ID集合
+        Set<String> privateUserIds = privateUsers.stream()
+                .map(AlarmUser::getId)
+                .filter(id -> id != null && !id.trim().isEmpty())
+                .collect(Collectors.toSet());
+
+        // 过滤出公网用户中ID不在本地用户ID集合中的用户
+        return publicUsers.stream()
+                .filter(user -> user.getId() != null && !user.getId().trim().isEmpty())
+                .filter(user -> !privateUserIds.contains(user.getId()))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 增强版的数据获取方法(带分页,适合大数据量)
+     */
+    public List<SysUser> getPublicSysUserListWithPagination(int pageSize, int pageNum) {
+        int offset = (pageNum - 1) * pageSize;
+        String sql = "SELECT * FROM sys_user_public LIMIT ? OFFSET ?";
+
+        try {
+            return jdbcTemplate.query(sql, new Object[]{pageSize, offset}, new BeanPropertyRowMapper<>(SysUser.class));
+        } catch (Exception e) {
+            log.error("分页查询公网sys_user数据失败", e);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 获取数据总数(用于分页)
+     */
+    public int getPublicSysUserCount() {
+        String sql = "SELECT COUNT(*) FROM sys_user_public";
+
+        try {
+            return jdbcTemplate.queryForObject(sql, Integer.class);
+        } catch (Exception e) {
+            log.error("获取公网sys_user数据总数失败", e);
+            return 0;
+        }
+    }
+}

+ 5 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/entity/AlarmUser.java

@@ -46,6 +46,11 @@ public class AlarmUser extends OrgEntity {
     @Column(name = "open_id")
     private String openId;
 
+    /** 电话 */
+    @Schema(description = "电话")
+    @Column(name = "phone")
+    private String phone;
+
     /** AccessToken */
     @Schema(description = "AccessToken")
     @Column(name = "access_token")

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/param/AlarmUserAddParam.java

@@ -35,4 +35,19 @@ public class AlarmUserAddParam {
     @Schema(description = "系统用户id")
     private String userId;
 
+    @Schema(description = "机构id")
+    private String createOrg;
+
+    @Schema(description = "用户姓名")
+    private String name;
+
+    @Schema(description = "用户昵称")
+    private String nickName;
+
+    @Schema(description = "手机号")
+    private String phone;
+
+    @Schema(description = "微信openId")
+    private String openId;
+
 }

+ 3 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/param/AlarmUserEditParam.java

@@ -45,4 +45,7 @@ public class AlarmUserEditParam {
     @Schema(description = "手机号")
     private String phone;
 
+    @Schema(description = "微信openId")
+    private String openId;
+
 }

+ 28 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/alarmuser/service/impl/AlarmUserServiceImpl.java

@@ -56,13 +56,11 @@ import vip.xiaonuo.dev.api.DevConfigApi;
 import vip.xiaonuo.sys.core.enums.SysDataTypeEnum;
 import vip.xiaonuo.sys.modular.user.entity.SysUser;
 import vip.xiaonuo.sys.modular.user.enums.SysUserStatusEnum;
+import vip.xiaonuo.sys.modular.user.mapper.SysUserMapper;
 import vip.xiaonuo.sys.modular.user.service.SysUserService;
 import vip.xiaonuo.sys.modular.user.service.impl.SysUserServiceImpl;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -82,6 +80,8 @@ public class AlarmUserServiceImpl extends ServiceImpl<AlarmUserMapper, AlarmUser
     private DevConfigApi devConfigApi;
     @Resource
     private MonitorTargetMapper monitorTargetMapper;
+    @Resource
+    private SysUserMapper sysUserMapper;
 
     @Override
     public Page<ExtendUserDTO> page(AlarmUserPageParam alarmUserPageParam) {
@@ -145,6 +145,11 @@ public class AlarmUserServiceImpl extends ServiceImpl<AlarmUserMapper, AlarmUser
     @Override
     public void add(AlarmUserAddParam alarmUserAddParam) {
         AlarmUser alarmUser = BeanUtil.toBean(alarmUserAddParam, AlarmUser.class);
+        List<AlarmUser> alarmByOpenId = getAlarmByOpenId(alarmUser.getOpenId());
+        SysUser sysUser = createSysUser(alarmUser, alarmUserAddParam.getCreateOrg(), alarmUserAddParam.getName());
+        Assert.isTrue(alarmByOpenId.isEmpty(), "微信已绑定其他报警接收人,请勿重复绑定");
+        sysUserMapper.insert(sysUser);
+        alarmUser.setUserId(sysUser.getId());
         this.save(alarmUser);
     }
 
@@ -153,7 +158,18 @@ public class AlarmUserServiceImpl extends ServiceImpl<AlarmUserMapper, AlarmUser
     public void edit(AlarmUserEditParam alarmUserEditParam) {
         AlarmUser alarmUser = this.queryEntity(alarmUserEditParam.getId());
         BeanUtil.copyProperties(alarmUserEditParam, alarmUser);
+        if (!Objects.equals(alarmUser.getOpenId(), alarmUserEditParam.getOpenId())) {
+            List<AlarmUser> alarmByOpenId = getAlarmByOpenId(alarmUser.getOpenId());
+
+            // 先检查集合是否为空
+            if (!alarmByOpenId.isEmpty()) {
+                // 排除当前用户自身,检查是否与其他用户重复
+                boolean isDuplicate = alarmByOpenId.stream()
+                        .anyMatch(user -> !user.getId().equals(alarmUser.getId()));
 
+                Assert.isTrue(!isDuplicate, "微信已绑定其他报警接收人,请勿重复绑定");
+            }
+        }
         // 判断是否有系统用户关联
         if (StrUtil.isBlank(alarmUser.getUserId())) {
             // 如果没有关联,则创建用户
@@ -336,4 +352,12 @@ public class AlarmUserServiceImpl extends ServiceImpl<AlarmUserMapper, AlarmUser
 
         return sysUser;
     }
+
+    private List<AlarmUser> getAlarmByOpenId(String openId) {
+        LambdaQueryWrapper<AlarmUser> queryWrapper = new LambdaQueryWrapper<>(AlarmUser.class)
+                .eq(AlarmUser::getOpenId, openId)
+                .eq(AlarmUser::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
+                .orderByDesc(AlarmUser::getCreateTime);
+        return list(queryWrapper);
+    }
 }

+ 18 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/entity/MonitorDevice.java

@@ -89,6 +89,24 @@ public class MonitorDevice  extends OrgEntity {
     @Schema(description = "最后心跳时间")
     private Date lastHeartbeatTime;
 
+    /**
+     * 通知方式
+     */
+    @Schema(description = "通知方式")
+    private String notificationChannel;
+
+    /**
+     * 延时提醒
+     */
+    @Schema(description = "延时提醒")
+    private Integer hours;
+
+    /**
+     * 是否开启预警
+     */
+    @Schema(description = "是否开启预警(0开启-1禁用)")
+    private String enabled;
+
     /**
      * 设备状态(1:正常,2:闲置)
      */

+ 19 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/param/MonitorDeviceAddParam.java

@@ -18,6 +18,7 @@ import lombok.Setter;
 
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
+import java.util.List;
 
 /**
  * 采集器管理添加参数
@@ -86,6 +87,24 @@ public class MonitorDeviceAddParam {
     @Schema(description = "ip")
     private String ip;
 
+    /**
+     * 通知方式
+     */
+    @Schema(description = "通知方式")
+    private List<String> notificationChannel;
+
+    /**
+     * 延时提醒
+     */
+    @Schema(description = "延时提醒")
+    private Integer hours;
+
+    /**
+     * 是否开启预警
+     */
+    @Schema(description = "是否开启预警(0开启-1禁用)")
+    private String enabled;
+
     /**
      * 报警上限
      */

+ 19 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/param/MonitorDeviceEditParam.java

@@ -19,6 +19,7 @@ import lombok.Setter;
 
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
+import java.util.List;
 
 /**
  * 采集器管理编辑参数
@@ -50,6 +51,24 @@ public class MonitorDeviceEditParam {
     @NotNull(message = "设备编码不能为空")
     private String deviceCode;
 
+    /**
+     * 通知方式
+     */
+    @Schema(description = "通知方式")
+    private List<String> notificationChannel;
+
+    /**
+     * 延时提醒
+     */
+    @Schema(description = "延时提醒")
+    private Integer hours;
+
+    /**
+     * 是否开启预警
+     */
+    @Schema(description = "是否开启预警(0开启-1禁用)")
+    private String enabled;
+
     /**
      * 设备型号
      */

+ 2 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/service/impl/MonitorDeviceServiceImpl.java

@@ -172,6 +172,7 @@ public class MonitorDeviceServiceImpl extends ServiceImpl<MonitorDeviceMapper, M
     public void add(MonitorDeviceAddParam monitorDeviceAddParam) {
         // 转换参数
         MonitorDevice monitorDevice = BeanUtil.toBean(monitorDeviceAddParam, MonitorDevice.class);
+        monitorDevice.setNotificationChannel(monitorDeviceAddParam.getNotificationChannel().toString());
         // 检查设备编码是否已注册
         if (this.getByDeviceCode(monitorDevice.getDeviceCode())) {
             throw new CommonException("设备编码已注册使用:{}", monitorDevice.getDeviceCode());
@@ -229,6 +230,7 @@ public class MonitorDeviceServiceImpl extends ServiceImpl<MonitorDeviceMapper, M
     @Override
     public void edit(MonitorDeviceEditParam monitorDeviceEditParam) {
         MonitorDevice monitorDevice = this.queryEntity(monitorDeviceEditParam.getId());
+        monitorDevice.setNotificationChannel(monitorDeviceEditParam.getNotificationChannel().toString());
         BeanUtil.copyProperties(monitorDeviceEditParam, monitorDevice);
         List<MonitorDevice> deviceByDeviceName = this.getDeviceByDeviceName(monitorDevice.getDeviceName());
         for (MonitorDevice device : deviceByDeviceName) {

+ 10 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/utils/PushUtil.java

@@ -13,6 +13,8 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
 import vip.xiaonuo.coldchain.modular.push.config.PushConfigure;
 import vip.xiaonuo.coldchain.modular.push.entity.WeChatUser;
 import vip.xiaonuo.coldchain.modular.push.param.AlarmPushParam;
@@ -27,6 +29,7 @@ import java.util.*;
  * 推送类
  */
 @Slf4j
+@Component
 public class PushUtil {
     private final static String ACCESS_TOKEN = "access_token";
     private final static String OPEN_ID = "openid";
@@ -39,6 +42,9 @@ public class PushUtil {
     private final static String PRIVILEGE = "privilege";
     private final static String UNION_ID = "unionid";
 
+    @Value("private.flag")
+    private static Boolean privateFlag;
+
     private static WxMpConfigStorage wxMpConfigStorage() {
         WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
         config.setAppId(PushConfigure.getAppId());
@@ -67,7 +73,7 @@ public class PushUtil {
             WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                     .toUser(userId)
                     .templateId(PushConfigure.getAlarmsTemplateId())
-                    .miniProgram(miniProgram)
+                    .miniProgram(privateFlag ? null : miniProgram)
                     .build();
             // 配置你的信息
             //设备名称
@@ -127,7 +133,7 @@ public class PushUtil {
             WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                     .toUser(userId)
                     .templateId(PushConfigure.getAlarmsRecoverTemplateId())
-                    .miniProgram(miniProgram)
+                    .miniProgram(privateFlag ? null : miniProgram)
                     .build();
             // 配置你的信息
             //设备名
@@ -188,7 +194,7 @@ public class PushUtil {
             WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                     .toUser(userId)
                     .templateId(PushConfigure.getOnlineTemplateId())
-                    .miniProgram(miniProgram)
+                    .miniProgram(privateFlag ? null : miniProgram)
                     .build();
             // 配置你的信息
             //设备名
@@ -249,7 +255,7 @@ public class PushUtil {
             WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                     .toUser(userId)
                     .templateId(PushConfigure.getOfflineTemplateId())
-                    .miniProgram(miniProgram)
+                    .miniProgram(privateFlag ? null : miniProgram)
                     .build();
             // 配置你的信息
             //设备名

+ 1 - 1
snowy-web-app/src/main/resources/application-master.properties

@@ -1,2 +1,2 @@
 server.port=58888
-coldchain.port=40404
+coldchain.port=0

+ 5 - 1
snowy-web-app/src/main/resources/application.properties

@@ -269,4 +269,8 @@ qp.appSecret=a098d282b91211efbca452540055385a
 
 airnow.save.enable=true
 #airnow.save.crno=0/10 * * * * ?
-airnow.save.crno=0 0/1 * * * ?
+airnow.save.crno=0 0/1 * * * ?
+
+private.flag=false
+private.cron=0 0/5 * * * ?
+#private.cron=0/5 * * * * ?