Explorar el Código

fix(service): 解决设备导入和微信绑定功能问题

- 修复Excel导入时大屏显示和子设备标识被错误覆盖的问题
- 添加getChildForUpdate和getShowForUpdate方法处理导入时空值情况
- 修复快捷登录认证异常信息被掩盖的问题
- 添加listByNo方法用于检测设备编号重复
- 解决导入时Excel内部重复编号和系统中重复编号的校验问题
- 实现导入时自动创建缺失的设备位置功能
- 修复导入时使用人不存在时的处理逻辑
- 解决移动端扫码启停用报500错误的问题
- 修复微信重新绑定时旧绑定未清理的问题
- 完善用户角色和菜单的客户端过滤逻辑
dazhaxie hace 3 semanas
padre
commit
dbebb29d2a
Se han modificado 29 ficheros con 493 adiciones y 41 borrados
  1. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/check/CheckJobDTO.java
  2. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/check/CheckStandardDTO.java
  3. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/repair/RepairApplicationFormDTO.java
  4. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/repair/RepairEntrustDTO.java
  5. 25 0
      platform-dao/src/main/java/com/platform/dao/dto/sb/SbInfoDTO.java
  6. 20 0
      platform-dao/src/main/java/com/platform/dao/dto/sqarepartmanage/SparePartInfoDTO.java
  7. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/store/InStoreFormDTO.java
  8. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/store/OutStoreFormDTO.java
  9. 5 0
      platform-dao/src/main/java/com/platform/dao/dto/store/SpareStoreDTO.java
  10. 6 0
      platform-dao/src/main/java/com/platform/dao/dto/store/StoreDTO.java
  11. 5 0
      platform-dao/src/main/java/com/platform/dao/vo/index/GatherTaskVO.java
  12. 12 0
      platform-dao/src/main/resources/mapper/check/CheckJobMapper.xml
  13. 12 0
      platform-dao/src/main/resources/mapper/check/CheckStandardMapper.xml
  14. 6 0
      platform-dao/src/main/resources/mapper/repair/RepairApplicationFormMapper.xml
  15. 6 0
      platform-dao/src/main/resources/mapper/repair/RepairEntrustMapper.xml
  16. 42 0
      platform-dao/src/main/resources/mapper/sb/SbInfoMapper.xml
  17. 54 0
      platform-dao/src/main/resources/mapper/sqarepartmanage/SparePartInfoMapper.xml
  18. 7 0
      platform-dao/src/main/resources/mapper/store/InStoreFormMapper.xml
  19. 7 0
      platform-dao/src/main/resources/mapper/store/OutStoreFormMapper.xml
  20. 18 0
      platform-dao/src/main/resources/mapper/store/SpareStoreMapper.xml
  21. 6 0
      platform-dao/src/main/resources/mapper/store/StoreMapper.xml
  22. 5 1
      platform-rest/src/main/java/com/platform/rest/controller/index/IndexController.java
  23. 8 0
      platform-service/src/main/java/com/platform/service/repair/RepairApplicationFormService.java
  24. 76 1
      platform-service/src/main/java/com/platform/service/repair/impl/RepairApplicationFormServiceImpl.java
  25. 55 19
      platform-service/src/main/java/com/platform/service/sb/impl/SbInfoServiceImpl.java
  26. 7 19
      platform-service/src/main/java/com/platform/service/upms/impl/SysUserServiceImpl.java
  27. 1 1
      platform-service/src/main/java/com/platform/service/wechat/model/request/WechatTemplateRequestBuilder.java
  28. 79 0
      platform-service/src/main/java/com/platform/service/wechat/util/WeChatMessageUtil.java
  29. 1 0
      pom.xml

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/check/CheckJobDTO.java

@@ -300,4 +300,9 @@ public class CheckJobDTO extends BaseDTO implements Serializable {
      */
     private List<String> jobIdList;
 
+    /**
+     * 设备类别列表(多选)
+     */
+    private List<String> typeIdList;
+
 }

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/check/CheckStandardDTO.java

@@ -233,4 +233,9 @@ public class CheckStandardDTO extends BaseDTO implements Serializable {
      * 更换备件
      */
     private List<CheckStandardSpareDTO> detailList;
+
+    /**
+     * 设备类别列表(多选)
+     */
+    private List<String> typeIdList;
 }

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/repair/RepairApplicationFormDTO.java

@@ -355,6 +355,11 @@ public class RepairApplicationFormDTO extends BaseDTO implements Serializable {
     private String deptId;
 
     /**
+     * 报修部门ID列表(多选)
+     */
+    private List<String> deptIdList;
+
+    /**
      * 通知班长用户id,多个用逗号分隔(非必填,提交报修时给选中班长发邮件+站内通知)
      */
     private String notifyTeamLeaders;

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/repair/RepairEntrustDTO.java

@@ -91,4 +91,9 @@ public class RepairEntrustDTO extends BaseDTO implements Serializable {
      */
     @Transient
     private String currentUserId;
+
+    /**
+     * 状态列表(多选)
+     */
+    private List<Integer> statusList;
 }

+ 25 - 0
platform-dao/src/main/java/com/platform/dao/dto/sb/SbInfoDTO.java

@@ -543,4 +543,29 @@ public class SbInfoDTO extends BaseDTO implements Serializable {
     private String scrapUserName;
 
     private String mapName; // 底图名称
+
+    /**
+     * 设备等级列表(多选)
+     */
+    private List<Integer> levelList;
+
+    /**
+     * 自定义类型列表(多选)
+     */
+    private List<Integer> useTypeList;
+
+    /**
+     * 所属车间列表(多选)
+     */
+    private List<String> positionIdList;
+
+    /**
+     * 主子设备列表(多选)
+     */
+    private List<Integer> isChildList;
+
+    /**
+     * 设备类别列表(多选)
+     */
+    private List<String> typeIdList;
 }

+ 20 - 0
platform-dao/src/main/java/com/platform/dao/dto/sqarepartmanage/SparePartInfoDTO.java

@@ -314,4 +314,24 @@ public class SparePartInfoDTO extends BaseDTO implements Serializable {
      * 保养计划消耗
      */
     private BigDecimal planCheckNum;
+
+    /**
+     * 等级列表(多选)
+     */
+    private List<Integer> levelList;
+
+    /**
+     * 用途列表(多选)
+     */
+    private List<Integer> ytList;
+
+    /**
+     * 是否专用列表(多选)
+     */
+    private List<Integer> isSpecialList;
+
+    /**
+     * 备件类别列表(多选)
+     */
+    private List<String> typeIdList;
 }

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/store/InStoreFormDTO.java

@@ -181,4 +181,9 @@ public class InStoreFormDTO extends BaseDTO implements Serializable {
 
     private String bomId;
 
+    /**
+     * 备件类别列表(多选)
+     */
+    private List<String> typeIdList;
+
 }

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/store/OutStoreFormDTO.java

@@ -163,4 +163,9 @@ public class OutStoreFormDTO extends BaseDTO implements Serializable {
 
     private String bomId;
 
+    /**
+     * 备件类别列表(多选)
+     */
+    private List<String> typeIdList;
+
 }

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/dto/store/SpareStoreDTO.java

@@ -186,4 +186,9 @@ public class SpareStoreDTO extends BaseDTO implements Serializable {
 
     private Integer level;
 
+    /**
+     * 备件类别列表(多选)
+     */
+    private List<String> typeIdList;
+
 }

+ 6 - 0
platform-dao/src/main/java/com/platform/dao/dto/store/StoreDTO.java

@@ -11,6 +11,7 @@ import javax.validation.constraints.*;
 import java.io.Serializable;
 import java.time.LocalDateTime;
 import java.time.LocalDate;
+import java.util.List;
 
 /**
  * @Description 仓库信息DTO
@@ -116,4 +117,9 @@ public class StoreDTO extends BaseDTO implements Serializable {
      */
     private String keyword;
 
+    /**
+     * 仓库等级列表(多选)
+     */
+    private List<Integer> levelList;
+
 }

+ 5 - 0
platform-dao/src/main/java/com/platform/dao/vo/index/GatherTaskVO.java

@@ -58,4 +58,9 @@ public class GatherTaskVO extends BaseVO implements Serializable {
      */
     private Integer repairCheckTask;
 
+    /**
+     * 转派审批任务(处于转派审批中的工单数)
+     */
+    private Integer transferApproveTask;
+
 }

+ 12 - 0
platform-dao/src/main/resources/mapper/check/CheckJobMapper.xml

@@ -232,6 +232,12 @@
         <if test="typeId != null and typeId != ''">
             and sbinfo.type_id = #{typeId}
         </if>
+        <if test="typeIdList != null and typeIdList.size > 0">
+            AND sbinfo.type_id in
+            <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="periodType != null and periodType != ''">
             and standard.period_type = #{periodType}
         </if>
@@ -448,6 +454,12 @@
         <if test="typeId != null and typeId != ''">
             and sbinfo_inner.type_id = #{typeId}
         </if>
+        <if test="typeIdList != null and typeIdList.size > 0">
+            AND sbinfo_inner.type_id in
+            <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="periodType != null and periodType != ''">
             and standard_inner.period_type = #{periodType}
         </if>

+ 12 - 0
platform-dao/src/main/resources/mapper/check/CheckStandardMapper.xml

@@ -257,6 +257,12 @@ checkstandard.last_date,
             <if test="typeId != null and typeId != ''">
                 and sbInfo.type_id  = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND sbInfo.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="sbLevel != null and sbLevel != ''">
                 and sbInfo.level = #{sbLevel}
             </if>
@@ -316,6 +322,12 @@ checkstandard.last_date,
             <if test="typeId != null and typeId != ''">
                 and sbInfo.type_id  = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND sbInfo.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="sbLevel != null and sbLevel != ''">
                 and sbInfo.level = #{sbLevel}
             </if>

+ 6 - 0
platform-dao/src/main/resources/mapper/repair/RepairApplicationFormMapper.xml

@@ -130,6 +130,12 @@
             <if test="deptId != null and deptId != ''">
                 and application.dept_id = #{deptId}
             </if>
+            <if test="deptIdList != null and deptIdList.size > 0">
+                AND application.dept_id in
+                <foreach item="item" index="index" collection="deptIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
         </where>
     </select>
     <select id="selectById" parameterType="java.lang.Object"

+ 6 - 0
platform-dao/src/main/resources/mapper/repair/RepairEntrustMapper.xml

@@ -43,6 +43,12 @@
             <if test="status != null">
                 and e.status = #{status}
             </if>
+            <if test="statusList != null and statusList.size > 0">
+                AND e.status in
+                <foreach item="item" index="index" collection="statusList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="repairId != null and repairId != ''">
                 and e.repair_id = #{repairId}
             </if>

+ 42 - 0
platform-dao/src/main/resources/mapper/sb/SbInfoMapper.xml

@@ -261,6 +261,12 @@ user.real_name as saveUserName
         <if test="typeId != null">
             and sb.type_id = #{typeId}
         </if>
+        <if test="typeIdList != null and typeIdList.size > 0">
+            AND sb.type_id in
+            <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="parentId != null">
             and sb.parent_id = #{parentId}
         </if>
@@ -331,6 +337,30 @@ user.real_name as saveUserName
         <if test="level!=null">
             and sb.level = #{level}
         </if>
+        <if test="levelList != null and levelList.size > 0">
+            AND sb.level in
+            <foreach item="item" index="index" collection="levelList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
+        <if test="useTypeList != null and useTypeList.size > 0">
+            AND sb.use_type in
+            <foreach item="item" index="index" collection="useTypeList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
+        <if test="positionIdList != null and positionIdList.size > 0">
+            AND sb.position_id in
+            <foreach item="item" index="index" collection="positionIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
+        <if test="isChildList != null and isChildList.size > 0">
+            AND sb.is_child in
+            <foreach item="item" index="index" collection="isChildList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
     </select>
 
     <select id="selectVOListStandard" parameterType="com.platform.dao.dto.sb.SbInfoDTO"
@@ -391,6 +421,12 @@ user.real_name as saveUserName
         <if test="typeId != null">
             and sb.type_id = #{typeId}
         </if>
+        <if test="typeIdList != null and typeIdList.size > 0">
+            AND sb.type_id in
+            <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="parentId != null">
             and sb.parent_id = #{parentId}
         </if>
@@ -498,6 +534,12 @@ user.real_name as saveUserName
         <if test="typeId != null">
             and sb.type_id = #{typeId}
         </if>
+        <if test="typeIdList != null and typeIdList.size > 0">
+            AND sb.type_id in
+            <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="model != null">
             and sb.model like concat('%',#{model},'%')
         </if>

+ 54 - 0
platform-dao/src/main/resources/mapper/sqarepartmanage/SparePartInfoMapper.xml

@@ -120,6 +120,12 @@ warn_status,forecast_status,
             <if test="typeId != null and typeId != ''">
                 and info.type_id = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND info.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="isSpecial == 0 and isSpecial == 1">
                 and info.is_special = #{isSpecial}
             </if>
@@ -151,12 +157,24 @@ warn_status,forecast_status,
             <if test="yt != null">
                 AND info.yt=#{yt}
             </if>
+            <if test="ytList != null and ytList.size > 0">
+                AND info.yt in
+                <foreach item="item" index="index" collection="ytList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="storeId != null and storeId != ''">
                 AND spare.store_id=#{storeId}
             </if>
             <if test="level != null and level != ''">
                 AND info.level=#{level}
             </if>
+            <if test="levelList != null and levelList.size > 0">
+                AND info.level in
+                <foreach item="item" index="index" collection="levelList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="typeIds != null and typeIds.size > 0">
                 AND info.type_id in
                 <foreach item="item" index="index" collection="typeIds" open="(" close=")" separator=",">
@@ -391,9 +409,21 @@ warn_status,forecast_status,
             <if test="typeId != null and typeId != ''">
                 and info.type_id = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND info.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="isSpecial != null and isSpecial != ''">
                 and info.is_special = #{isSpecial}
             </if>
+            <if test="isSpecialList != null and isSpecialList.size > 0">
+                AND info.is_special in
+                <foreach item="item" index="index" collection="isSpecialList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="producerName != null and producerName != ''">
                 AND producer.name like concat('%',#{producerName},'%')
             </if>
@@ -422,12 +452,24 @@ warn_status,forecast_status,
             <if test="yt != null">
                 AND info.yt=#{yt}
             </if>
+            <if test="ytList != null and ytList.size > 0">
+                AND info.yt in
+                <foreach item="item" index="index" collection="ytList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="storeId != null and storeId != ''">
                 AND spare.store_id=#{storeId}
             </if>
             <if test="level != null and level != ''">
                 AND info.level=#{level}
             </if>
+            <if test="levelList != null and levelList.size > 0">
+                AND info.level in
+                <foreach item="item" index="index" collection="levelList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="typeIds != null and typeIds.size > 0">
                 AND info.type_id in
                 <foreach item="item" index="index" collection="typeIds" open="(" close=")" separator=",">
@@ -499,12 +541,24 @@ warn_status,forecast_status,
             <if test="typeId != null and typeId != ''">
                 and info.type_id = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND info.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="ggxh != null and ggxh != ''">
                 AND info.ggxh like concat('%',#{ggxh},'%')
             </if>
             <if test="level != null and level != ''">
                 AND info.level=#{level}
             </if>
+            <if test="levelList != null and levelList.size > 0">
+                AND info.level in
+                <foreach item="item" index="index" collection="levelList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="searchMinStockWarn">
                 AND info.min_stock is not null
             </if>

+ 7 - 0
platform-dao/src/main/resources/mapper/store/InStoreFormMapper.xml

@@ -451,6 +451,7 @@
             resultType="com.platform.dao.vo.query.store.InStoreFormVO">
         select instoreform.*,store.name as storeName
         from t_in_store_form as instoreform left join t_store store on store.id = instoreform.store_id
+        left join t_spare_part_info info on instoreform.spare_id = info.id
         <where>
             <if test="keyword != null and keyword != ''">
                 and (
@@ -468,6 +469,12 @@
             <if test="createdTimeEnd!=null">
                 and instoreform.created_time <![CDATA[<=]]>#{createdTimeEnd}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND info.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
         </where>
     </select>
 </mapper>

+ 7 - 0
platform-dao/src/main/resources/mapper/store/OutStoreFormMapper.xml

@@ -412,6 +412,7 @@
         select outstoreform.*, store.name as storeName
         from t_out_store_form as outstoreform
         left join t_store store on store.id = outstoreform.store_id
+        left join t_spare_part_info info on outstoreform.spare_id = info.id
         <where>
             <if test="keyword != null and keyword != ''">
                 and (
@@ -429,6 +430,12 @@
             <if test="createdTimeEnd!=null">
                 and outstoreform.created_time <![CDATA[<=]]>#{createdTimeEnd}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND info.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
         </where>
     </select>
 </mapper>

+ 18 - 0
platform-dao/src/main/resources/mapper/store/SpareStoreMapper.xml

@@ -140,6 +140,12 @@
         <if test="typeId != null and typeId != ''">
             and info.type_id = #{typeId}
         </if>
+        <if test="typeIdList != null and typeIdList.size > 0">
+            AND info.type_id in
+            <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="keyword != null and keyword != ''">
             AND ( info.name like concat('%',#{keyword},'%') or
             info.ggxh like concat('%',#{keyword},'%'))
@@ -179,6 +185,12 @@
             <if test="typeId != null and typeId != ''">
                 and spareinfo.type_id = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND spareinfo.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="parentTypeId != null and parentTypeId != ''">
                 and spareinfo.parent_type_id = #{parentTypeId}
             </if>
@@ -283,6 +295,12 @@
             <if test="typeId != null and typeId != ''">
                 and info.type_id = #{typeId}
             </if>
+            <if test="typeIdList != null and typeIdList.size > 0">
+                AND info.type_id in
+                <foreach item="item" index="index" collection="typeIdList" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
             <if test="storeId != null and storeId != ''">
                 and bom.store_id = #{storeId}
             </if>

+ 6 - 0
platform-dao/src/main/resources/mapper/store/StoreMapper.xml

@@ -41,6 +41,12 @@
         <if test="level != null and level != ''">
             and store.level = #{level}
         </if>
+        <if test="levelList != null and levelList.size > 0">
+            AND store.level in
+            <foreach item="item" index="index" collection="levelList" open="(" close=")" separator=",">
+                #{item}
+            </foreach>
+        </if>
         <if test="no != null and no != ''">
             and store.no = #{no}
         </if>

+ 5 - 1
platform-rest/src/main/java/com/platform/rest/controller/index/IndexController.java

@@ -71,11 +71,15 @@ public class IndexController {
 
         // 维修验收任务
         int repairCheckTask = repairApplicationFormService.countTask(null, userInfo.getUserId(), 3);
+
+        // 转派审批任务:处于转派审批中的工单数
+        int transferApproveTask = repairApplicationFormService.countTransferApprovalTask();
         return R.success(new GatherTaskVO()
                 .setLubricationTask(lubricationTask)
                 .setLubricationTaskWeek(lubricationTaskWeek)
                 .setLubricationTaskMonth(lubricationTaskMonth)
-                .setRepairTask(repairTask).setRepairCheckTask(repairCheckTask));
+                .setRepairTask(repairTask).setRepairCheckTask(repairCheckTask)
+                .setTransferApproveTask(transferApproveTask));
     }
 
     /**

+ 8 - 0
platform-service/src/main/java/com/platform/service/repair/RepairApplicationFormService.java

@@ -102,6 +102,14 @@ public interface RepairApplicationFormService extends IBaseService<RepairApplica
     int countTask(String sbId, String userId, Integer searchType);
 
     /**
+     * 统计处于“转派审批中”状态的工单数(手机端转派审批入口待办角标)
+     * 转派审批不绑定具体审批人,拥有维修审核角色的账号均可处理,故按状态全局统计
+     *
+     * @return 待审批的转派工单数
+     */
+    int countTransferApprovalTask();
+
+    /**
      * 自动分配任务
      */
     void autoAssignTaskForTimer();

+ 76 - 1
platform-service/src/main/java/com/platform/service/repair/impl/RepairApplicationFormServiceImpl.java

@@ -78,6 +78,15 @@ public class RepairApplicationFormServiceImpl
         extends BaseServiceImpl<RepairApplicationFormMapper, RepairApplicationForm, RepairApplicationFormDTO>
         implements RepairApplicationFormService {
 
+    /**
+     * 工单状态自定义排序 CASE 表达式:
+     * 待接收(1) → 维修中(2) → 转派审批中(8) → 委外维修中(9) → 待审核(3) → 审核中(4) → 已驳回(5) → 已完成(6) → 拒单(7)
+     * 将「进行中」类状态排在「已完成/已拒单」之前,避免转派审批中(8)排在已完成(6)之后
+     */
+    private static final String STATUS_SORT_CASE = "CASE application.status "
+            + "WHEN 1 THEN 1 WHEN 2 THEN 2 WHEN 8 THEN 3 WHEN 9 THEN 4 "
+            + "WHEN 3 THEN 5 WHEN 4 THEN 6 WHEN 5 THEN 7 WHEN 6 THEN 8 WHEN 7 THEN 9 ELSE 10 END";
+
     private RepairReasonMapper repairReasonMapper;
     private final SysUserService sysUserService;
     private final SbInfoService sbInfoService;
@@ -280,6 +289,13 @@ public class RepairApplicationFormServiceImpl
                 record.setStatusList(statusList);
                 record.setStatus(null);
             }
+            // 转派审批查询:仅显示转派审批中的工单(手机端“转派审批”入口列表)
+            if (record.getSearchType() == 4) {
+                List<Integer> statusList = new ArrayList<>();
+                statusList.add(RepairApplicationFormStatusEnum.TRANSFER_APPROVAL.getValue());
+                record.setStatusList(statusList);
+                record.setStatus(null);
+            }
         }
 
         // 审批查询:仅显示审核中和已驳回状态的工单
@@ -301,7 +317,11 @@ public class RepairApplicationFormServiceImpl
                 if (name.isEmpty()) {
                     continue;
                 }
-                if (!name.contains(".")) {
+                // 当排序字段为 status 时,使用 CASE 表达式实现自定义状态排序,
+                // 使「转派审批中(8)」等进行中状态排在「已完成(6)」之前
+                if ("status".equals(name)) {
+                    name = STATUS_SORT_CASE;
+                } else if (!name.contains(".")) {
                     name = "application." + name;
                 }
                 if (aliasedSortName.length() > 0) {
@@ -628,6 +648,7 @@ public class RepairApplicationFormServiceImpl
         }
         List<String> leaderUserIds = new ArrayList<>();
         List<String> leaderMails = new ArrayList<>();
+        List<String> leaderOpenIds = new ArrayList<>();
         for (String leaderId : leaderIds) {
             SysUser leader = userMapper.selectByPrimaryKey(leaderId);
             if (leader == null) {
@@ -640,6 +661,9 @@ public class RepairApplicationFormServiceImpl
             } else {
                 log.warn("班长 {} 未配置邮箱,报修通知跳过邮件发送", leader.getRealName());
             }
+            if (StringUtils.isNotBlank(leader.getWxOpenId())) {
+                leaderOpenIds.add(leader.getWxOpenId());
+            }
         }
         if (CollectionUtil.isEmpty(leaderUserIds)) {
             return;
@@ -665,6 +689,20 @@ public class RepairApplicationFormServiceImpl
         SpringContextHolder.publishEvent(new WorkplaceBacklogEvent(WorkplaceBacklogTypeEnum.REPAIR.getValue(),
                 WorkplaceBacklogDetailTypeEnum.REPAIR_APPLICATION.getValue(),
                 model.getId(), content.toString(), model.getId(), leaderUserIds, leaderMails));
+
+        // 发送微信通知给班长
+        if (CollectionUtil.isNotEmpty(leaderOpenIds) && BeanUtils.isProd()) {
+            String mobileDomain = ConfigCache.getLabelByValueAllowNull(SysConfigEnum.SYSTEM_DOMAIN_MOBILE.name());
+            if (StringUtils.isNotBlank(mobileDomain)) {
+                if (!mobileDomain.endsWith("/")) {
+                    mobileDomain = mobileDomain + "/";
+                }
+                String mobileRepairUrl = mobileDomain + "pages/repair-detail/repair-detail?detailId=" + model.getId();
+                for (String openId : leaderOpenIds) {
+                    WeChatMessageUtil.teamLeaderDispatchMessage(openId, mobileRepairUrl, model, sb);
+                }
+            }
+        }
     }
 
     @Override
@@ -895,6 +933,24 @@ public class RepairApplicationFormServiceImpl
                     applicationForm.getId(), ListUtils.newArrayList(model.getRepairUserId()),
                     ListUtils.newArrayList(repairUser.getEmail())));
         }
+
+        // 发送微信通知给被派工人
+        if (repairUser != null && StringUtils.isNotBlank(repairUser.getWxOpenId()) && BeanUtils.isProd()) {
+            try {
+                String mobileDomain = ConfigCache.getLabelByValueAllowNull(SysConfigEnum.SYSTEM_DOMAIN_MOBILE.name());
+                if (StringUtils.isNotBlank(mobileDomain)) {
+                    if (!mobileDomain.endsWith("/")) {
+                        mobileDomain = mobileDomain + "/";
+                    }
+                    String mobileRepairUrl = mobileDomain + "pages/repair-detail/repair-detail?detailId=" + applicationForm.getId();
+                    RepairApplicationFormDTO dispatchDTO = BeanConverterUtil.copyObjectProperties(applicationForm, RepairApplicationFormDTO.class);
+                    String dispatcherName = operatorName;
+                    WeChatMessageUtil.repairDispatchMessage(repairUser.getWxOpenId(), mobileRepairUrl, dispatchDTO, sbInfoVO, dispatcherName);
+                }
+            } catch (Exception e) {
+                log.error("派工微信通知发送失败, 报修id: " + applicationForm.getId(), e);
+            }
+        }
     }
 
     /**
@@ -912,6 +968,13 @@ public class RepairApplicationFormServiceImpl
 
         // 1. 将维修单的状态修改已完成
         RepairApplicationForm applicationForm = mapper.selectById(dto.getId());
+
+        // 校验:只有被派工的维修人才能点击完成
+        UserInfo currentUser = SecurityUtils.getUserInfo();
+        if (currentUser == null || !currentUser.getUserId().equals(applicationForm.getRepairUserId())) {
+            throw new BusinessException("只有被派工的维修人才能完成工单");
+        }
+
         applicationForm.setStatus(RepairApplicationFormStatusEnum.WAIT_SUBMIT.getValue());
         applicationForm.setRepairContent(dto.getRepairContent());
 
@@ -1580,6 +1643,9 @@ public class RepairApplicationFormServiceImpl
         applicationForm.setCheckEndTime(LocalDateTime.now());
         applicationForm.setStatus(RepairApplicationFormStatusEnum.FINISHED.getValue());
         applicationForm.setUpdateTime(applicationForm.getCheckEndTime());
+        // 更新审核人为当前登录用户(实际审核人)
+        UserInfo userInfo = SecurityUtils.getUserInfo();
+        applicationForm.setCheckUserId(userInfo.getUserId());
         super.modModelByPrimaryKey(applicationForm);
         // 给设备使用人员发送消息通知
         if (StringUtils.isNotBlank(info.getSaveUser())) {
@@ -1755,6 +1821,15 @@ public class RepairApplicationFormServiceImpl
     }
 
     @Override
+    public int countTransferApprovalTask() {
+        Weekend<RepairApplicationForm> weekend = new Weekend<>(RepairApplicationForm.class);
+        WeekendCriteria<RepairApplicationForm, Object> weekendCriteria = weekend.weekendCriteria();
+        weekendCriteria.andEqualTo(RepairApplicationForm::getStatus,
+                RepairApplicationFormStatusEnum.TRANSFER_APPROVAL.getValue());
+        return mapper.selectCountByExample(weekend);
+    }
+
+    @Override
     public void autoAssignTaskForTimer() {
         LocalDateTime minutesAgo = DateUtils.minus(LocalDateTime.now(), 10, ChronoUnit.MINUTES);
         Weekend<RepairApplicationForm> weekend = new Weekend<>(RepairApplicationForm.class);

+ 55 - 19
platform-service/src/main/java/com/platform/service/sb/impl/SbInfoServiceImpl.java

@@ -375,7 +375,7 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
         String filePath = rootPath + path;
         String codePath = path + model.getId() + ".png";
         model.setQrCode(codePath);
-        CodeFileUtils.uploadFileECode(model.getId(), rootPath, filePath, model.getId() + ".png");
+        CodeFileUtils.uploadFileECode(buildSbQrCodeUrl(model.getId()), rootPath, filePath, model.getId() + ".png");
         // 保存文件
         this.saveImageFile(model);
         this.saveUseFile(model);
@@ -427,7 +427,7 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
         String filePath = rootPath + path;
         String codePath = path + model.getId() + ".png";
         model.setQrCode(codePath);
-        CodeFileUtils.uploadFileECode(model.getId(), rootPath, filePath, model.getId() + ".png");
+        CodeFileUtils.uploadFileECode(buildSbQrCodeUrl(model.getId()), rootPath, filePath, model.getId() + ".png");
 
         // 2:复制部位
         PartInfoDTO partInfoDTO = new PartInfoDTO();
@@ -1565,7 +1565,7 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
                 String rootPath = environment.getProperty("upload.root-dir");
                 String filePath = rootPath + path;
                 String codePath = path + vo.getId() + ".png";
-                CodeFileUtils.uploadFileECode(vo.getId(), rootPath, filePath, vo.getId() + ".png");
+                CodeFileUtils.uploadFileECode(buildSbQrCodeUrl(vo.getId()), rootPath, filePath, vo.getId() + ".png");
                 // 修改二维码
                 SbInfoDTO sbInfoDTO = new SbInfoDTO();
                 sbInfoDTO.setId(vo.getId());
@@ -1611,29 +1611,15 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
     public void generateSbCodeAll() {
         List<SbInfo> list = mapper.selectAll();
 
-        String domain = ConfigCache.getLabelByValueAllowNull(SysConfigEnum.SYSTEM_DOMAIN_MOBILE.name());
-        String sbUrl = ConfigCache.getLabelByValueAllowNull(SysConfigEnum.SYSTEM_SB_URL.name());
-        if (StringUtils.isBlank(domain)) {
-            throw new BusinessException("请先设置系统域名地址,系统管理-》系统参数配置-》SYSTEM_DOMAIN");
-        }
-        if (!domain.endsWith("/")) {
-            domain = domain + "/";
-        }
-        if (StringUtils.isBlank(sbUrl)) {
-            throw new BusinessException("请先设置设备跳转前缀地址,系统管理-》系统参数配置-》SYSTEM_DOMAIN_MOBILE");
-        }
-        if (!sbUrl.endsWith("/") && !sbUrl.endsWith("=")) {
-            sbUrl = sbUrl + "/";
-        }
         if (CollectionUtil.isNotEmpty(list)) {
+            String rootPath = environment.getProperty("upload.root-dir");
             // 保存二维码
             for (SbInfo sbInfo : list) {
                 String path = CommonConstants.RESOURCE_PREFIX + "/png/" + DateUtil.formatDate(new Date()) + "/"
                         + IdGeneratorUtils.getObjectId() + "/";
-                String rootPath = environment.getProperty("upload.root-dir");
                 String filePath = rootPath + path;
                 String codePath = path + sbInfo.getId() + ".png";
-                CodeFileUtils.uploadFileECode(domain + sbUrl + sbInfo.getId(), rootPath, filePath,
+                CodeFileUtils.uploadFileECode(buildSbQrCodeUrl(sbInfo.getId()), rootPath, filePath,
                         sbInfo.getId() + ".png");
                 // 修改
                 sbInfo.setQrCode(codePath);
@@ -1642,6 +1628,30 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
         }
     }
 
+    /**
+     * 构建设备二维码URL:domain + sbUrl + id
+     *
+     * @param id 设备ID
+     * @return 完整的移动端跳转URL
+     */
+    private String buildSbQrCodeUrl(String id) {
+        String domain = ConfigCache.getLabelByValueAllowNull(SysConfigEnum.SYSTEM_DOMAIN_MOBILE.name());
+        String sbUrl = ConfigCache.getLabelByValueAllowNull(SysConfigEnum.SYSTEM_SB_URL.name());
+        if (StringUtils.isBlank(domain)) {
+            throw new BusinessException("请先设置系统域名地址,系统管理-》系统参数配置-》SYSTEM_DOMAIN_MOBILE");
+        }
+        if (StringUtils.isBlank(sbUrl)) {
+            throw new BusinessException("请先设置设备跳转前缀地址,系统管理-》系统参数配置-》SYSTEM_SB_URL");
+        }
+        if (!domain.endsWith("/")) {
+            domain = domain + "/";
+        }
+        if (!sbUrl.endsWith("/") && !sbUrl.endsWith("=")) {
+            sbUrl = sbUrl + "/";
+        }
+        return domain + sbUrl + id;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public String importListByAdd(MultipartFile file) {
@@ -1792,6 +1802,20 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
                 if (!CollectionUtils.isEmpty(addItems)) {
                     List<SbInfo> itemsAdd = BeanConverterUtil.copyListProperties(addItems, SbInfo.class);
                     mapper.insertListforComplex(itemsAdd);
+                    
+                    // 为每个新导入的设备生成二维码
+                    String rootPath = environment.getProperty("upload.root-dir");
+                    for (SbInfo sbInfo : itemsAdd) {
+                        // 保存二维码
+                        String path = CommonConstants.RESOURCE_PREFIX + "/png/" + DateUtil.formatDate(new Date()) + "/"
+                                + IdGeneratorUtils.getObjectId() + "/";
+                        String filePath = rootPath + path;
+                        String codePath = path + sbInfo.getId() + ".png";
+                        sbInfo.setQrCode(codePath);
+                        CodeFileUtils.uploadFileECode(buildSbQrCodeUrl(sbInfo.getId()), rootPath, filePath, sbInfo.getId() + ".png");
+                        // 更新二维码路径到数据库
+                        mapper.updateByPrimaryKeySelective(sbInfo);
+                    }
                 }
             }
             return "总计新增导入:" + (items.size());
@@ -2031,6 +2055,18 @@ public class SbInfoServiceImpl extends BaseServiceImpl<SbInfoMapper, SbInfo, SbI
                         singleList.add(toSave.get(idx));
                         mapper.insertListforComplex(singleList);
                         newCount++;
+                        
+                        // 为新增的设备生成二维码
+                        SbInfo sbInfo = toSave.get(idx);
+                        String rootPath = environment.getProperty("upload.root-dir");
+                        String path = CommonConstants.RESOURCE_PREFIX + "/png/" + DateUtil.formatDate(new Date()) + "/"
+                                + IdGeneratorUtils.getObjectId() + "/";
+                        String filePath = rootPath + path;
+                        String codePath = path + sbInfo.getId() + ".png";
+                        sbInfo.setQrCode(codePath);
+                        CodeFileUtils.uploadFileECode(buildSbQrCodeUrl(sbInfo.getId()), rootPath, filePath, sbInfo.getId() + ".png");
+                        // 更新二维码路径到数据库
+                        mapper.updateByPrimaryKeySelective(sbInfo);
                     } else {
                         mapper.updateByPrimaryKeySelective(toSave.get(idx));
                     }

+ 7 - 19
platform-service/src/main/java/com/platform/service/upms/impl/SysUserServiceImpl.java

@@ -158,8 +158,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser,
 
         sysUserDeptService.deleteByUserId(userId);
         sysUserDeptService.saveUserDepts(entity.getUserId(), model.getDeptIds());
-        // 校验区域是否存在
-        entity.setPassword(PasswordUtil.encrypt(InitialPasswordEnum.INITIAL_PASSWORD_123456.getValue()));
+        // 编辑用户时不修改密码,保留原密码
+        entity.setPassword(null);
         mapper.updateByPrimaryKeySelective(entity);
     }
 
@@ -402,27 +402,15 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser,
             // 新密码不能与旧密码相同
             throw new BusinessException(ResultCode.USER_PASSWORD_NOT_CONFIRM);
         } else {
+            // 1. 更新数据库密码
             SysUser updateUser = new SysUser();
             updateUser.setPassword(passwordEncypt);
             updateUser.setPwdChanged(1);
             updateUser.setUserId(user.getUserId());
-            updateUser(updateUser);
-            // 重新缓存用户信息
-            Cache cache = cacheManager.getCache("user_details");
-            if (cache != null) {
-                Cache.ValueWrapper valueWrapper = cache.get(username);
-                if (valueWrapper != null) {
-                    OauthUser details = (OauthUser) valueWrapper.get();
-                    UserInfo userInfo = details.getUserInfo();
-                    userInfo.setPassword(updateUser.getPassword());
-                    cache.evict(username);
-                    // 重新设置密码
-                    details = new OauthUser(details.getId(), details.getUsername(), SecurityConstants.BCRYPT + userInfo.getPassword(),
-                            CommonConstants.USER_STATUS_NORMAL.equals(userInfo.getStatus()), true,
-                            true, true, details.getAuthorities(), userInfo);
-                    cache.put(username, details);
-                }
-            }
+            updateUser.setUsername(username);
+            mapper.updateByPrimaryKeySelective(updateUser);
+            // 2. 清理缓存(用户缓存 + OAuth token),强制用户重新登录
+            cleanUserInfoCache(username);
         }
     }
 

+ 1 - 1
platform-service/src/main/java/com/platform/service/wechat/model/request/WechatTemplateRequestBuilder.java

@@ -28,7 +28,7 @@ public class WechatTemplateRequestBuilder {
     /**
      * 维修提醒模板keys 模板ID:njA6sdMf0EPi1k8iruwe2aw0miH6q-0AvB_GCEyzJpE  维修提醒
      */
-    public static String[] TEMPLATE_KEYS_REPAIR = new String[]{"first", "keyword1", "keyword2","keyword3", "keyword4", "remark"};
+    public static String[] TEMPLATE_KEYS_REPAIR = new String[]{"first", "keyword1", "keyword2","keyword3", "keyword4", "keyword5", "remark"};
 
     /**
 	 * 修改提醒模板keys 模板6VegnWIea-Gj1F1GeLPFlekkznoPaqS-vs1H-liFp10  修改提醒

+ 79 - 0
platform-service/src/main/java/com/platform/service/wechat/util/WeChatMessageUtil.java

@@ -109,6 +109,85 @@ public class WeChatMessageUtil {
         }
     }
 
+    /**
+     * 派工微信通知
+     * 您有一条新的派工任务
+     * 报修单号:BX20260001
+     * 派工人:张三
+     * 派工时间:2026-10-10 10:00
+     * 设备位置:1号车间
+     * 故障描述:电机异常
+     * 设备名称:粗纱001
+     *
+     * @param openId         被派工人微信openId
+     * @param url            移动端维修单详情链接
+     * @param model          报修单DTO
+     * @param vo             设备信息
+     * @param dispatchUserName 派工人姓名
+     */
+    public static void repairDispatchMessage(String openId, String url, RepairApplicationFormDTO model, SbInfoVO vo, String dispatchUserName) {
+        try {
+            if (StringUtils.isBlank(url)) {
+                url = repair_url;
+            }
+            if (isSend() && StringUtils.isNotBlank(openId)) {
+                WechatTemplateRequest request = WechatTemplateRequestBuilder.
+                        getRepairRequest(url,
+                                template_id_repair,
+                                openId,
+                                new String[]{
+                                        "您有新的派工任务,请及时处理",
+                                        model.getNo(),
+                                        StringUtils.isBlank(dispatchUserName) ? "未知" : dispatchUserName,
+                                        DateUtils.dateToString(LocalDateTime.now()),
+                                        model.getSbCph(),
+                                        vo != null ? vo.getName() : "未知",
+                                        model.getContent()
+                                }, new String[]{"#000000",
+                                        "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"});
+                SpringContextHolder.publishEvent(new WechatEvent(request));
+            }
+        } catch (Exception e) {
+            log.error("发送派工微信消息失败", e);
+        }
+    }
+
+    /**
+     * 报修通知班长微信通知
+     * 有人提交了报修单,请知晓
+     *
+     * @param openId   班长微信openId
+     * @param url      移动端维修单详情链接
+     * @param model    报修单DTO
+     * @param vo       设备信息
+     */
+    public static void teamLeaderDispatchMessage(String openId, String url, RepairApplicationFormDTO model, SbInfo vo) {
+        try {
+            if (StringUtils.isBlank(url)) {
+                url = repair_url;
+            }
+            if (isSend() && StringUtils.isNotBlank(openId)) {
+                WechatTemplateRequest request = WechatTemplateRequestBuilder.
+                        getRepairRequest(url,
+                                template_id_repair,
+                                openId,
+                                new String[]{
+                                        "有人提交了报修单,请知晓",
+                                        model.getNo(),
+                                        model.getActualUser(),
+                                        DateUtils.dateToString(model.getApplyTime()),
+                                        model.getSbCph(),
+                                        vo != null ? vo.getName() : "未知",
+                                        model.getContent()
+                                }, new String[]{"#000000",
+                                        "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"});
+                SpringContextHolder.publishEvent(new WechatEvent(request));
+            }
+        } catch (Exception e) {
+            log.error("发送班长通知微信消息失败", e);
+        }
+    }
+
     public static void sendRepairMessage(String openId, WechatTemplateRequest request) {
         try {
             if (isSend() && StringUtils.isNotBlank(openId)) {

+ 1 - 0
pom.xml

@@ -140,6 +140,7 @@
                     <target>${maven.compiler.target}</target>
                     <source>${maven.compiler.source}</source>
                     <encoding>${project.build.sourceEncoding}</encoding>
+                    <parameters>true</parameters>
                 </configuration>
             </plugin>
             <plugin>