Commit 1f9b6868b23e5b9043a0647c112d730ebb26f8fa

Authored by wangqian
2 parents 58051e0b ae252461

Merge remote-tracking branch 'origin/dev' into dev

Showing 16 changed files with 477 additions and 83 deletions
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/inspectionplan/InspectionPlanServiceImpl.java
@@ -110,7 +110,7 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { @@ -110,7 +110,7 @@ public class InspectionPlanServiceImpl implements InspectionPlanService {
110 calculate.add(periodResult); 110 calculate.add(periodResult);
111 planNum = Integer.parseInt(createReqVO.getRateValue()); 111 planNum = Integer.parseInt(createReqVO.getRateValue());
112 }else{ 112 }else{
113 - calculate= TimeIntervalFrequencyUtil.calculate(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId()); 113 + calculate= TimeIntervalFrequencyUtil.calculateNew(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId());
114 if (CollectionUtils.isEmpty(calculate)) { 114 if (CollectionUtils.isEmpty(calculate)) {
115 log.warn("获取两个时间之间间隔天数错误"); 115 log.warn("获取两个时间之间间隔天数错误");
116 return CommonResult.error(INSPECTION_CYCLE_ERROR); 116 return CommonResult.error(INSPECTION_CYCLE_ERROR);
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java
@@ -87,7 +87,7 @@ public class TimeIntervalFrequencyUtil { @@ -87,7 +87,7 @@ public class TimeIntervalFrequencyUtil {
87 long daysInSegment = ChronoUnit.DAYS.between(segmentStart, segmentEnd) + 1; 87 long daysInSegment = ChronoUnit.DAYS.between(segmentStart, segmentEnd) + 1;
88 88
89 // 计算当前时间段的执行次数:(实际天数/周期天数) * 每周期次数,向上取整 89 // 计算当前时间段的执行次数:(实际天数/周期天数) * 每周期次数,向上取整
90 - double proportion = (double) daysInSegment / daysPerPeriod; 90 + double proportion = (double) daysInSegment / totalPeriodDays;
91 int executionCount = (int) Math.ceil(proportion * timesPerPeriod); 91 int executionCount = (int) Math.ceil(proportion * timesPerPeriod);
92 92
93 // 添加当前时间段结果 93 // 添加当前时间段结果
@@ -230,7 +230,7 @@ public class TimeIntervalFrequencyUtil { @@ -230,7 +230,7 @@ public class TimeIntervalFrequencyUtil {
230 // ====================== 测试用例 ====================== 230 // ====================== 测试用例 ======================
231 public static void main(String[] args) { 231 public static void main(String[] args) {
232 232
233 - List<PeriodResult> r2 = calculateNew("2026-01-01", "2026-02-15", "7/1", 2); 233 + List<PeriodResult> r2 = calculateNew("2026-01-01", "2026-01-26", "5/12", 1);
234 r2.forEach(System.out::println); 234 r2.forEach(System.out::println);
235 235
236 // //1:日/次;2:周/次;3:月/次;4:年/次 236 // //1:日/次;2:周/次;3:月/次;4:年/次
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/api/constant/BpmCommonConstant.java
@@ -47,5 +47,18 @@ public class BpmCommonConstant { @@ -47,5 +47,18 @@ public class BpmCommonConstant {
47 * 快速工单编号前缀 47 * 快速工单编号前缀
48 */ 48 */
49 public static final String WORK_ORDER_PREFFIX_QUICK = "QWO"; 49 public static final String WORK_ORDER_PREFFIX_QUICK = "QWO";
  50 + /**
  51 + * 园林养护员 角色编码
  52 + */
  53 + public static final String YL_WORKER="yl_worker";
  54 + /**
  55 + * 园林班组长 角色编码
  56 + */
  57 + public static final String TEAM_LEADER_YL = "team_leader_yl";
  58 +
  59 + /**
  60 + * 园林巡查员 角色编码
  61 + */
  62 + public static final String YL_INSPECTOR = "yl_inspector";
50 63
51 } 64 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/api/workorder/WorkOrderApi.java
1 package com.zteits.urbanops.module.workorder.api.workorder; 1 package com.zteits.urbanops.module.workorder.api.workorder;
2 2
  3 +import com.zteits.urbanops.framework.common.pojo.PageResult;
  4 +import com.zteits.urbanops.module.system.api.user.dto.AdminUserRespDTO;
  5 +
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * 工单对外提供的 api
  10 + */
3 public interface WorkOrderApi { 11 public interface WorkOrderApi {
4 /** 12 /**
5 * 生成工单编号 13 * 生成工单编号
@@ -7,4 +15,22 @@ public interface WorkOrderApi { @@ -7,4 +15,22 @@ public interface WorkOrderApi {
7 * @return 15 * @return
8 */ 16 */
9 public String generateWONum(String prefix); 17 public String generateWONum(String prefix);
  18 +
  19 + /**
  20 + *通过登录人 loginUserId 获取 当前人所在部门的 且对应的用户角色为roleCode的人员,按业务线busiLine 筛选
  21 + * @param loginUserId
  22 + * @param roleCode
  23 + * @param notHas false 不包含loginUserId
  24 + * @return
  25 + */
  26 + public List<AdminUserRespDTO> getUserByLoginIdAndRoleCode(Long loginUserId, String roleCode, String busiLine, boolean notHas);
  27 +
  28 + /**
  29 + * 通过道路 roadId 获取 当前人所在部门的 且对应的用户角色为roleCode的人员,按业务线busiLine 筛选
  30 + * @param roadId
  31 + * @param roleCode
  32 + * @param busiLine
  33 + * @return
  34 + */
  35 + public List<AdminUserRespDTO> getUserByRoadIdAndRoleCode(Long roadId,String roleCode,String busiLine);
10 } 36 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/api/workorder/WorkOrderApiImpl.java
1 package com.zteits.urbanops.module.workorder.api.workorder; 1 package com.zteits.urbanops.module.workorder.api.workorder;
2 2
  3 +import com.zteits.urbanops.framework.common.pojo.PageResult;
  4 +import com.zteits.urbanops.module.system.api.user.dto.AdminUserRespDTO;
3 import com.zteits.urbanops.module.workorder.api.constant.BpmCommonConstant; 5 import com.zteits.urbanops.module.workorder.api.constant.BpmCommonConstant;
  6 +import com.zteits.urbanops.module.workorder.dal.mysql.maininfo.MainInfoExtMapper;
  7 +import jakarta.annotation.Resource;
4 import org.springframework.stereotype.Service; 8 import org.springframework.stereotype.Service;
5 import org.springframework.util.ObjectUtils; 9 import org.springframework.util.ObjectUtils;
6 10
7 import java.time.LocalDateTime; 11 import java.time.LocalDateTime;
8 import java.time.format.DateTimeFormatter; 12 import java.time.format.DateTimeFormatter;
  13 +import java.util.List;
9 import java.util.concurrent.atomic.AtomicInteger; 14 import java.util.concurrent.atomic.AtomicInteger;
10 15
  16 +import static com.zteits.urbanops.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  17 +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0;
  18 +
11 /** 19 /**
12 * @author yanhuiqing 20 * @author yanhuiqing
13 * @version 1.0 21 * @version 1.0
@@ -17,6 +25,8 @@ import java.util.concurrent.atomic.AtomicInteger; @@ -17,6 +25,8 @@ import java.util.concurrent.atomic.AtomicInteger;
17 @Service 25 @Service
18 public class WorkOrderApiImpl implements WorkOrderApi{ 26 public class WorkOrderApiImpl implements WorkOrderApi{
19 27
  28 + @Resource
  29 + private MainInfoExtMapper workOrderExtMapper;
20 private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); 30 private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
21 private static final AtomicInteger counter = new AtomicInteger(1); 31 private static final AtomicInteger counter = new AtomicInteger(1);
22 32
@@ -37,4 +47,20 @@ public class WorkOrderApiImpl implements WorkOrderApi{ @@ -37,4 +47,20 @@ public class WorkOrderApiImpl implements WorkOrderApi{
37 } 47 }
38 return String.format("%s%03d_%s", prefix, seqNum,dateStr); 48 return String.format("%s%03d_%s", prefix, seqNum,dateStr);
39 } 49 }
  50 +
  51 + @Override
  52 + public List<AdminUserRespDTO> getUserByLoginIdAndRoleCode(Long loginUserId, String roleCode, String busiLine, boolean notHas) {
  53 + if(ObjectUtils.isEmpty(loginUserId) || ObjectUtils.isEmpty(roleCode) || ObjectUtils.isEmpty(busiLine)){
  54 + throw exception0(BAD_REQUEST.getCode(),"param:loginUserId,roleCode,busiLine 不能为空!");
  55 + }
  56 + return workOrderExtMapper.getUserByLoginIdAndRoleCode(loginUserId,roleCode,busiLine,notHas);
  57 + }
  58 +
  59 + @Override
  60 + public List<AdminUserRespDTO> getUserByRoadIdAndRoleCode(Long roadId, String roleCode, String busiLine) {
  61 + if(ObjectUtils.isEmpty(roadId) || ObjectUtils.isEmpty(roleCode) || ObjectUtils.isEmpty(busiLine)){
  62 + throw exception0(BAD_REQUEST.getCode(),"param:roadId,roleCode,busiLine 不能为空!");
  63 + }
  64 + return workOrderExtMapper.getUserByRoadIdAndRoleCode(roadId,roleCode,busiLine);
  65 + }
40 } 66 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/controller/admin/garden/BpmGardenInspectController.java
@@ -34,12 +34,12 @@ public class BpmGardenInspectController { @@ -34,12 +34,12 @@ public class BpmGardenInspectController {
34 @Resource 34 @Resource
35 private BpmGardenService gardenService; 35 private BpmGardenService gardenService;
36 36
37 - @PostMapping("/create") 37 + /*@PostMapping("/create")
38 @PreAuthorize("@ss.hasPermission('bpm:garden-inspection:create')") 38 @PreAuthorize("@ss.hasPermission('bpm:garden-inspection:create')")
39 @Operation(summary = "创建请求申请") 39 @Operation(summary = "创建请求申请")
40 public CommonResult<Long> createGardenInspection(@Valid @RequestBody BpmGardenWorkOrderCreateReqVO createReqVO) { 40 public CommonResult<Long> createGardenInspection(@Valid @RequestBody BpmGardenWorkOrderCreateReqVO createReqVO) {
41 return success(gardenService.createWorkOrder(getLoginUserId(), createReqVO)); 41 return success(gardenService.createWorkOrder(getLoginUserId(), createReqVO));
42 - } 42 + }*/
43 43
44 @GetMapping("/get") 44 @GetMapping("/get")
45 @PreAuthorize("@ss.hasPermission('bpm:garden-inspection:query')") 45 @PreAuthorize("@ss.hasPermission('bpm:garden-inspection:query')")
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/controller/app/garden/AppGardenWorkOrderController.java
@@ -2,9 +2,11 @@ package com.zteits.urbanops.module.workorder.controller.app.garden; @@ -2,9 +2,11 @@ package com.zteits.urbanops.module.workorder.controller.app.garden;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import com.zteits.urbanops.framework.common.pojo.CommonResult; 4 import com.zteits.urbanops.framework.common.pojo.CommonResult;
  5 +import com.zteits.urbanops.framework.common.pojo.PageParam;
5 import com.zteits.urbanops.framework.common.pojo.PageResult; 6 import com.zteits.urbanops.framework.common.pojo.PageResult;
6 import com.zteits.urbanops.framework.common.util.json.JsonUtils; 7 import com.zteits.urbanops.framework.common.util.json.JsonUtils;
7 import com.zteits.urbanops.framework.common.util.object.BeanUtils; 8 import com.zteits.urbanops.framework.common.util.object.BeanUtils;
  9 +import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils;
8 import com.zteits.urbanops.framework.web.core.util.WebFrameworkUtils; 10 import com.zteits.urbanops.framework.web.core.util.WebFrameworkUtils;
9 import com.zteits.urbanops.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailReqVO; 11 import com.zteits.urbanops.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailReqVO;
10 import com.zteits.urbanops.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO; 12 import com.zteits.urbanops.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO;
@@ -13,7 +15,10 @@ import com.zteits.urbanops.module.bpm.controller.admin.task.vo.task.BpmTaskTrans @@ -13,7 +15,10 @@ import com.zteits.urbanops.module.bpm.controller.admin.task.vo.task.BpmTaskTrans
13 import com.zteits.urbanops.module.garden.api.road.RoadApi; 15 import com.zteits.urbanops.module.garden.api.road.RoadApi;
14 import com.zteits.urbanops.module.garden.api.road.dto.RoadReqDTO; 16 import com.zteits.urbanops.module.garden.api.road.dto.RoadReqDTO;
15 import com.zteits.urbanops.module.garden.api.road.dto.RoadRespDTO; 17 import com.zteits.urbanops.module.garden.api.road.dto.RoadRespDTO;
  18 +import com.zteits.urbanops.module.system.api.user.dto.AdminUserRespDTO;
  19 +import com.zteits.urbanops.module.workorder.api.constant.BpmCommonConstant;
16 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.*; 20 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.*;
  21 +import com.zteits.urbanops.module.workorder.controller.app.garden.vo.common.UserInfoPageReqVO;
17 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.process.AppGardenApprovalDetailReqVO; 22 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.process.AppGardenApprovalDetailReqVO;
18 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.process.AppGardenApprovalDetailRespVO; 23 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.process.AppGardenApprovalDetailRespVO;
19 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.task.*; 24 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.task.*;
@@ -164,4 +169,12 @@ public class AppGardenWorkOrderController { @@ -164,4 +169,12 @@ public class AppGardenWorkOrderController {
164 PageResult<AppGardenWorkOrderRespVO> pageResult = gardenService.getTaskTodoBuzSimplePage(pageVO); 169 PageResult<AppGardenWorkOrderRespVO> pageResult = gardenService.getTaskTodoBuzSimplePage(pageVO);
165 return success(pageResult); 170 return success(pageResult);
166 } 171 }
  172 +
  173 + @GetMapping("getYlWorkersPage")
  174 + @Operation(summary = "app - 获取园林养护员")
  175 + //@PreAuthorize("@ss.hasPermission('bpm:garden-workorder:query')")
  176 + public CommonResult<PageResult<AdminUserRespDTO>> getYlWorkersPage(@Valid UserInfoPageReqVO pageVO) {
  177 + PageResult<AdminUserRespDTO> pageResult = gardenService.getUserByLoginIdAndRoleCode(pageVO, SecurityFrameworkUtils.getLoginUserId(),pageVO.getRoleCode(),pageVO.getBusiLine(),pageVO.isNotHas());
  178 + return success(pageResult);
  179 + }
167 } 180 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/controller/app/garden/vo/AppGardenWorkOrderReqVO.java
@@ -81,6 +81,10 @@ public class AppGardenWorkOrderReqVO { @@ -81,6 +81,10 @@ public class AppGardenWorkOrderReqVO {
81 @Schema(description = "完成时间") 81 @Schema(description = "完成时间")
82 private LocalDateTime finishDate; 82 private LocalDateTime finishDate;
83 83
  84 + @NotNull
  85 + @Schema(description = "工单业务线", example = "yl")
  86 + private String busiLine;
  87 +
84 /* @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") 88 /* @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}")
85 private Map<String, List<Long>> startUserSelectAssignees; 89 private Map<String, List<Long>> startUserSelectAssignees;
86 90
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/controller/app/garden/vo/common/UserInfoPageReqVO.java 0 → 100644
  1 +package com.zteits.urbanops.module.workorder.controller.app.garden.vo.common;
  2 +
  3 +import com.zteits.urbanops.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +/**
  9 + * 类描述:园林app下拉养护员信息
  10 + * 创建人:yanhuiqing
  11 + * 创建时间:2025/12/16 23:05
  12 + * 修改人:yanhuiqing
  13 + * 修改时间:2025/12/16 23:05
  14 + * 修改备注:
  15 + *
  16 + * @author yanhuiqing
  17 + * @version 1.0
  18 + */
  19 +@Schema(description = "APP - 园林app下拉养护员信息分页 Request VO")
  20 +@Data
  21 +public class UserInfoPageReqVO extends PageParam {
  22 + @NotNull
  23 + @Schema(description = "养护员角色编码", example = "yl_worker")
  24 + private String roleCode;
  25 + @NotNull
  26 + @Schema(description = "业务线", example = "yl")
  27 + private String busiLine;
  28 + @Schema(description = "是否包含登录人,true 默认不包含", example = "true")
  29 + boolean notHas = true;
  30 +}
0 \ No newline at end of file 31 \ No newline at end of file
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/dal/mysql/maininfo/MainInfoExtMapper.java
@@ -2,15 +2,21 @@ package com.zteits.urbanops.module.workorder.dal.mysql.maininfo; @@ -2,15 +2,21 @@ package com.zteits.urbanops.module.workorder.dal.mysql.maininfo;
2 2
3 import com.baomidou.mybatisplus.core.conditions.Wrapper; 3 import com.baomidou.mybatisplus.core.conditions.Wrapper;
4 import com.baomidou.mybatisplus.core.metadata.IPage; 4 import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
5 import com.zteits.urbanops.framework.common.pojo.PageParam; 6 import com.zteits.urbanops.framework.common.pojo.PageParam;
6 import com.zteits.urbanops.framework.common.pojo.PageResult; 7 import com.zteits.urbanops.framework.common.pojo.PageResult;
7 import com.zteits.urbanops.framework.mybatis.core.mapper.BaseMapperX; 8 import com.zteits.urbanops.framework.mybatis.core.mapper.BaseMapperX;
8 import com.zteits.urbanops.framework.mybatis.core.util.MyBatisUtils; 9 import com.zteits.urbanops.framework.mybatis.core.util.MyBatisUtils;
  10 +import com.zteits.urbanops.module.system.api.user.dto.AdminUserRespDTO;
9 import com.zteits.urbanops.module.workorder.controller.admin.maininfo.vo.MainInfoHasTaskPageReqVO; 11 import com.zteits.urbanops.module.workorder.controller.admin.maininfo.vo.MainInfoHasTaskPageReqVO;
10 import com.zteits.urbanops.module.workorder.controller.admin.maininfo.vo.MainInfoPageReqVO; 12 import com.zteits.urbanops.module.workorder.controller.admin.maininfo.vo.MainInfoPageReqVO;
11 import com.zteits.urbanops.module.workorder.dal.dataobject.maininfo.MainInfoDO; 13 import com.zteits.urbanops.module.workorder.dal.dataobject.maininfo.MainInfoDO;
12 import com.zteits.urbanops.module.workorder.dal.dataobject.maininfo.MainInfoExtDO; 14 import com.zteits.urbanops.module.workorder.dal.dataobject.maininfo.MainInfoExtDO;
  15 +import jakarta.validation.constraints.NotNull;
13 import org.apache.ibatis.annotations.*; 16 import org.apache.ibatis.annotations.*;
  17 +import org.springframework.lang.NonNull;
  18 +
  19 +import java.util.List;
14 20
15 /** 21 /**
16 * 类描述:工单工作流扩展Mapper 22 * 类描述:工单工作流扩展Mapper
@@ -227,4 +233,114 @@ public interface MainInfoExtMapper extends BaseMapperX&lt;MainInfoDO&gt; { @@ -227,4 +233,114 @@ public interface MainInfoExtMapper extends BaseMapperX&lt;MainInfoDO&gt; {
227 mpPage = selectTodoExtPage(mpPage, reqVO); 233 mpPage = selectTodoExtPage(mpPage, reqVO);
228 return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); 234 return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
229 } 235 }
  236 + //-------------------------------------------------------------------------------------------------------
  237 + /**
  238 + * 查询所有用户信息 通过以下条件
  239 + * @param loginUserId
  240 + * @param roleCode
  241 + * @param busiLines
  242 + * @param notHas
  243 + * @return
  244 + */
  245 + default List<AdminUserRespDTO> getUserByLoginIdAndRoleCode(
  246 + @NonNull Long loginUserId,
  247 + @NonNull String roleCode,
  248 + @NonNull String busiLines,
  249 + @NonNull boolean notHas
  250 + ) {
  251 + // 创建一个“不分页”的Page对象(size=Integer.MAX_VALUE,查询所有数据)
  252 + IPage<AdminUserRespDTO> page = new Page<>(1, Integer.MAX_VALUE);
  253 + // 调用分页方法,获取结果列表
  254 + IPage<AdminUserRespDTO> resultPage = getUserByLoginIdAndRoleCodeIPage(page, loginUserId, roleCode, busiLines, notHas);
  255 + return resultPage.getRecords();
  256 + }
  257 +
  258 +
  259 + @Select({
  260 + "<script>",
  261 + "SELECT",
  262 + " su.id, su.nickname, su.status, su.dept_id, su.mobile, su.avatar",
  263 + "FROM",
  264 + " (SELECT dept_id FROM system_users WHERE id = #{loginUserId}) AS login_user_dept",
  265 + "INNER JOIN system_users su ON login_user_dept.dept_id = su.dept_id",
  266 + "INNER JOIN system_user_role sur ON su.id = sur.user_id",
  267 + "INNER JOIN system_role sr ON sur.role_id = sr.id",
  268 + "WHERE",
  269 + " sr.code = #{roleCode}",
  270 + " AND FIND_IN_SET(#{busiLine}, REPLACE(su.busi_line, ' ', '')) > 0",
  271 + " <if test='notHas'>",
  272 + " AND su.id &lt;&gt; #{loginUserId}",
  273 + " </if>",
  274 + "</script>"
  275 + })
  276 + @Results({
  277 + @Result(column = "id", property = "id"),
  278 + @Result(column = "nickname", property = "nickname"),
  279 + @Result(column = "status", property = "status"),
  280 + @Result(column = "deptId", property = "dept_id"),
  281 + @Result(column = "mobile", property = "mobile"),
  282 + @Result(column = "avatar", property = "avatar")
  283 + })
  284 + IPage<AdminUserRespDTO> getUserByLoginIdAndRoleCodeIPage(IPage<AdminUserRespDTO> page,
  285 + @NonNull @Param("loginUserId") Long loginUserId,
  286 + @NonNull @Param("roleCode") String roleCode,
  287 + @NonNull @Param("busiLine") String busiLines,
  288 + @NonNull @Param("notHas") boolean notHas);
  289 + default PageResult<AdminUserRespDTO> getUserByLoginIdAndRoleCodePage(PageParam pageParam,@NonNull @Param("loginUserId") Long loginUserId,
  290 + @NonNull @Param("roleCode") String roleCode,
  291 + @NonNull @Param("busiLine") String busiLines,
  292 + @NonNull @Param("notHas") boolean notHas){
  293 + IPage<AdminUserRespDTO> mpPage = MyBatisUtils.buildPage(pageParam);
  294 + mpPage = getUserByLoginIdAndRoleCodeIPage(mpPage, loginUserId,roleCode, busiLines,notHas);
  295 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
  296 +
  297 + }
  298 +
  299 + //-------------------------------------------------------------------------------------------------------
  300 + @Select({
  301 + "<script>",
  302 + "SELECT",
  303 + " su.id, su.nickname, su.status, su.dept_id, su.mobile, su.avatar",
  304 + "FROM",
  305 + " garden_road gr",
  306 + "INNER JOIN system_dept sd ON gr.dept_id = sd.id",
  307 + "INNER JOIN system_users su ON gr.dept_id = su.dept_id",
  308 + "INNER JOIN system_user_role sur ON su.id = sur.user_id",
  309 + "INNER JOIN system_role sr ON sur.role_id = sr.id",
  310 + "WHERE",
  311 + " FIND_IN_SET(#{busiLine}, REPLACE(su.busi_line, ' ', '')) > 0",
  312 + " AND gr.id = #{roadId}",
  313 + " AND sr.code = #{roleCode}",
  314 + "</script>"
  315 + })
  316 + @Results({
  317 + @Result(column = "id", property = "id"),
  318 + @Result(column = "nickname", property = "nickname"),
  319 + @Result(column = "status", property = "status"),
  320 + @Result(column = "deptId", property = "dept_id"),
  321 + @Result(column = "mobile", property = "mobile"),
  322 + @Result(column = "avatar", property = "avatar")
  323 + })
  324 + IPage<AdminUserRespDTO> getUserByRoadIdAndRoleCodeIPage(IPage<AdminUserRespDTO> page,@NonNull @Param("roadId") Long roadId,
  325 + @NonNull @Param("roleCode") String roleCode,
  326 + @NonNull @Param("busiLine") String busiLine);
  327 + default PageResult<AdminUserRespDTO> getUserByRoadIdAndRoleCodePage(PageParam pageParam,@NonNull @Param("roadId") Long roadId,
  328 + @NonNull @Param("roleCode") String roleCode,
  329 + @NonNull @Param("busiLine") String busiLine){
  330 + IPage<AdminUserRespDTO> mpPage = MyBatisUtils.buildPage(pageParam);
  331 + mpPage = getUserByRoadIdAndRoleCodeIPage(mpPage, roadId,roleCode, busiLine);
  332 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
  333 +
  334 + }
  335 +
  336 +
  337 + default List<AdminUserRespDTO> getUserByRoadIdAndRoleCode(@NonNull @Param("roadId") Long roadId,
  338 + @NonNull @Param("roleCode") String roleCode,
  339 + @NonNull @Param("busiLine") String busiLine){
  340 + // 创建一个“不分页”的Page对象(size=Integer.MAX_VALUE,查询所有数据)
  341 + IPage<AdminUserRespDTO> page = new Page<>(1, Integer.MAX_VALUE);
  342 + // 调用分页方法,获取结果列表
  343 + IPage<AdminUserRespDTO> resultPage = getUserByRoadIdAndRoleCodeIPage(page, roadId, roleCode, busiLine);
  344 + return resultPage.getRecords();
  345 + }
230 } 346 }
231 \ No newline at end of file 347 \ No newline at end of file
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/enums/ErrorCodeConstants.java
@@ -16,4 +16,6 @@ public interface ErrorCodeConstants { @@ -16,4 +16,6 @@ public interface ErrorCodeConstants {
16 ErrorCode ATTACHMENT_NOT_EXISTS = new ErrorCode(1-900-001-001, "工单附件信息不存在"); 16 ErrorCode ATTACHMENT_NOT_EXISTS = new ErrorCode(1-900-001-001, "工单附件信息不存在");
17 17
18 ErrorCode MATERIAL_DETAIL_NOT_EXISTS = new ErrorCode(1-900-001-002, "工单耗材明细不存在"); 18 ErrorCode MATERIAL_DETAIL_NOT_EXISTS = new ErrorCode(1-900-001-002, "工单耗材明细不存在");
  19 +
  20 + ErrorCode TEAM_LEADER_YL_NOT_EXISTS = new ErrorCode(1-900-001-003, "养护班组长人员不存在");
19 } 21 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/service/garden/BpmGardenService.java
1 package com.zteits.urbanops.module.workorder.service.garden; 1 package com.zteits.urbanops.module.workorder.service.garden;
2 2
  3 +import com.zteits.urbanops.framework.common.pojo.PageParam;
3 import com.zteits.urbanops.framework.common.pojo.PageResult; 4 import com.zteits.urbanops.framework.common.pojo.PageResult;
  5 +import com.zteits.urbanops.module.system.api.user.dto.AdminUserRespDTO;
4 import com.zteits.urbanops.module.workorder.controller.admin.garden.vo.BpmGardenWorkOrderCreateReqVO; 6 import com.zteits.urbanops.module.workorder.controller.admin.garden.vo.BpmGardenWorkOrderCreateReqVO;
5 import com.zteits.urbanops.module.workorder.controller.admin.garden.vo.BpmGardenWorkOrderPageReqVO; 7 import com.zteits.urbanops.module.workorder.controller.admin.garden.vo.BpmGardenWorkOrderPageReqVO;
6 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.*; 8 import com.zteits.urbanops.module.workorder.controller.app.garden.vo.*;
@@ -22,13 +24,7 @@ public interface BpmGardenService { @@ -22,13 +24,7 @@ public interface BpmGardenService {
22 * @return 24 * @return
23 */ 25 */
24 Long createWorkOrder(@Valid AppGardenWorkOrderReqVO createRequestVo); 26 Long createWorkOrder(@Valid AppGardenWorkOrderReqVO createRequestVo);
25 - /**  
26 - * 园林工单申请 Service 接口  
27 - * @param userId  
28 - * @param createRequestVo  
29 - * @return  
30 - */  
31 - Long createWorkOrder(Long userId,@Valid BpmGardenWorkOrderCreateReqVO createRequestVo); 27 +
32 28
33 /** 29 /**
34 * 更新工单申请的状态 30 * 更新工单申请的状态
@@ -133,4 +129,22 @@ public interface BpmGardenService { @@ -133,4 +129,22 @@ public interface BpmGardenService {
133 * @return 129 * @return
134 */ 130 */
135 PageResult<AppGardenWorkOrderRespVO> getTaskTodoBuzSimplePage(AppGardenWorkOrderPageReqVO pageVO); 131 PageResult<AppGardenWorkOrderRespVO> getTaskTodoBuzSimplePage(AppGardenWorkOrderPageReqVO pageVO);
  132 +
  133 + /**
  134 + *通过登录人 loginUserId 获取 当前人所在部门的 且对应的用户角色为roleCode的人员,按业务线busiLine 筛选
  135 + * @param loginUserId
  136 + * @param roleCode
  137 + * @param notHas false 不包含loginUserId
  138 + * @return
  139 + */
  140 + public PageResult<AdminUserRespDTO> getUserByLoginIdAndRoleCode(PageParam param,Long loginUserId, String roleCode, String busiLine, boolean notHas);
  141 +
  142 + /**
  143 + * 通过道路 roadId 获取 当前人所在部门的 且对应的用户角色为roleCode的人员,按业务线busiLine 筛选
  144 + * @param roadId
  145 + * @param roleCode
  146 + * @param busiLine
  147 + * @return
  148 + */
  149 + public PageResult<AdminUserRespDTO> getUserByRoadIdAndRoleCode(PageParam param,Long roadId,String roleCode,String busiLine);
136 } 150 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/service/garden/BpmGardenServiceImpl.java
@@ -2,6 +2,7 @@ package com.zteits.urbanops.module.workorder.service.garden; @@ -2,6 +2,7 @@ package com.zteits.urbanops.module.workorder.service.garden;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5 +import com.zteits.urbanops.framework.common.pojo.PageParam;
5 import com.zteits.urbanops.framework.common.pojo.PageResult; 6 import com.zteits.urbanops.framework.common.pojo.PageResult;
6 import com.zteits.urbanops.framework.common.util.object.BeanUtils; 7 import com.zteits.urbanops.framework.common.util.object.BeanUtils;
7 import com.zteits.urbanops.framework.common.util.object.ObjectUtils; 8 import com.zteits.urbanops.framework.common.util.object.ObjectUtils;
@@ -57,10 +58,13 @@ import java.util.Map; @@ -57,10 +58,13 @@ import java.util.Map;
57 import java.util.Set; 58 import java.util.Set;
58 import java.util.stream.Collectors; 59 import java.util.stream.Collectors;
59 60
  61 +import static com.zteits.urbanops.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
60 import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; 62 import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception;
  63 +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0;
61 import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.convertSet; 64 import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.convertSet;
62 import static com.zteits.urbanops.framework.web.core.util.WebFrameworkUtils.getLoginUserId; 65 import static com.zteits.urbanops.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
63 import static com.zteits.urbanops.module.workorder.enums.ErrorCodeConstants.MAIN_INFO_NOT_EXISTS; 66 import static com.zteits.urbanops.module.workorder.enums.ErrorCodeConstants.MAIN_INFO_NOT_EXISTS;
  67 +import static com.zteits.urbanops.module.workorder.enums.ErrorCodeConstants.TEAM_LEADER_YL_NOT_EXISTS;
64 68
65 /** 69 /**
66 * @author yanhuiqing 70 * @author yanhuiqing
@@ -101,6 +105,11 @@ public class BpmGardenServiceImpl implements BpmGardenService{ @@ -101,6 +105,11 @@ public class BpmGardenServiceImpl implements BpmGardenService{
101 @Resource 105 @Resource
102 private RuntimeService runtimeService; 106 private RuntimeService runtimeService;
103 107
  108 + /**
  109 + * app 端快速工单入口
  110 + * @param createRequestVo
  111 + * @return
  112 + */
104 @Override 113 @Override
105 @Transactional(rollbackFor = Exception.class) 114 @Transactional(rollbackFor = Exception.class)
106 public Long createWorkOrderQuick(AppGardenWorkOrderReqVO createRequestVo) { 115 public Long createWorkOrderQuick(AppGardenWorkOrderReqVO createRequestVo) {
@@ -273,6 +282,7 @@ public class BpmGardenServiceImpl implements BpmGardenService{ @@ -273,6 +282,7 @@ public class BpmGardenServiceImpl implements BpmGardenService{
273 return AppGardenTaskConvert.INSTANCE.buildBuziTaskPage(pageResult,attachmentMapper); 282 return AppGardenTaskConvert.INSTANCE.buildBuziTaskPage(pageResult,attachmentMapper);
274 } 283 }
275 284
  285 +
276 @Override 286 @Override
277 public PageResult<AppGardenTaskRespVO> getTaskDonePage(AppGardenTaskPageReqVO pageVO) { 287 public PageResult<AppGardenTaskRespVO> getTaskDonePage(AppGardenTaskPageReqVO pageVO) {
278 BpmTaskPageReqVO targetVO = BeanUtils.toBean(pageVO,BpmTaskPageReqVO.class); 288 BpmTaskPageReqVO targetVO = BeanUtils.toBean(pageVO,BpmTaskPageReqVO.class);
@@ -312,7 +322,11 @@ public class BpmGardenServiceImpl implements BpmGardenService{ @@ -312,7 +322,11 @@ public class BpmGardenServiceImpl implements BpmGardenService{
312 } 322 }
313 323
314 324
315 - 325 + /**
  326 + * app端创建工单
  327 + * @param createRequestVo
  328 + * @return
  329 + */
316 @Override 330 @Override
317 @Transactional(rollbackFor = Exception.class) 331 @Transactional(rollbackFor = Exception.class)
318 public Long createWorkOrder(AppGardenWorkOrderReqVO createRequestVo) { 332 public Long createWorkOrder(AppGardenWorkOrderReqVO createRequestVo) {
@@ -338,39 +352,29 @@ public class BpmGardenServiceImpl implements BpmGardenService{ @@ -338,39 +352,29 @@ public class BpmGardenServiceImpl implements BpmGardenService{
338 workOrderMapper.insert(workOrder); 352 workOrderMapper.insert(workOrder);
339 //附件插入 353 //附件插入
340 attachmentApend(imgList,null,longRangeImgList,workOrder); 354 attachmentApend(imgList,null,longRangeImgList,workOrder);
341 - return workOrder.getId();  
342 - }  
343 -  
344 - @Override  
345 - @Transactional(rollbackFor = Exception.class)  
346 - public Long createWorkOrder(Long userId, BpmGardenWorkOrderCreateReqVO createRequestVo) {  
347 - List<String> imgList = createRequestVo.getImgs();  
348 - List<String> streetImgList = createRequestVo.getStreetImgList();  
349 - List<String> longRangeImgList = createRequestVo.getLongRangeImgList();  
350 - String isYesOrNo = createRequestVo.getIsYesOrNo();  
351 - // 插入 工单  
352 - MainInfoDO workOrder = BeanUtils.toBean(createRequestVo, MainInfoDO.class)  
353 - .setStatus(BpmTaskStatusEnum.RUNNING.getStatus());  
354 - //TODO 设置其它值 需从道路表获取  
355 - workOrder.setStreetId("test");  
356 - workOrder.setBuzStatus("t1");//需给出映射关系  
357 - workOrder.setCommitDate(LocalDateTime.now());  
358 - String workOrderNum = workOrderApi.generateWONum(BpmCommonConstant.WORK_ORDER_PREFFIX_GARDEN);  
359 - workOrder.setOrderNo(workOrderNum);  
360 - workOrder.setOrderName("园林工单");  
361 - workOrder.setCompanyId(SecurityFrameworkUtils.getCompanyId());  
362 - workOrder.setBusiLine(SecurityFrameworkUtils.getBusiLine());  
363 - workOrderMapper.insert(workOrder);  
364 -  
365 - //附件插入  
366 - attachmentApend(imgList,streetImgList,longRangeImgList,workOrder);  
367 // 发起 BPM 流程 355 // 发起 BPM 流程
  356 + Long userId = SecurityFrameworkUtils.getLoginUserId();
368 Map<String, Object> processInstanceVariables = new HashMap<>(); 357 Map<String, Object> processInstanceVariables = new HashMap<>();
369 - processInstanceVariables.put("isYesOrNo", isYesOrNo); 358 + processInstanceVariables.put("workOrder", workOrder);
  359 + processInstanceVariables.put("imgList", imgList);
  360 + processInstanceVariables.put("longRangeImgList", longRangeImgList);
  361 + processInstanceVariables.put("initiator", userId);
  362 + Map<String, List<Long>> startUserSelectAssignees = new HashMap<>();
  363 + List<AdminUserRespDTO> userList = workOrderExtMapper.getUserByRoadIdAndRoleCode(workOrder.getRoadId(),BpmCommonConstant.TEAM_LEADER_YL,createRequestVo.getBusiLine());
  364 + if(org.springframework.util.ObjectUtils.isEmpty(userList)){
  365 + throw exception(TEAM_LEADER_YL_NOT_EXISTS);
  366 + }
  367 + // 提取id到List<Long>
  368 + List<Long> idList = userList.stream()
  369 + // 映射:将AdminUserRespDTO对象转为其id属性
  370 + .map(AdminUserRespDTO::getId)
  371 + // 收集结果到List
  372 + .collect(Collectors.toList());
  373 + startUserSelectAssignees.put("",idList);
370 String processInstanceId = processInstanceApi.createProcessInstance(userId, 374 String processInstanceId = processInstanceApi.createProcessInstance(userId,
371 new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(BpmCommonConstant.BPM_GARDEN_INSPECT_WO) 375 new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(BpmCommonConstant.BPM_GARDEN_INSPECT_WO)
372 .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(workOrder.getId())) 376 .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(workOrder.getId()))
373 - .setStartUserSelectAssignees(createRequestVo.getStartUserSelectAssignees())); 377 + .setStartUserSelectAssignees(startUserSelectAssignees));
374 378
375 // 将工作流的编号,更新到 工单中 379 // 将工作流的编号,更新到 工单中
376 workOrderMapper.updateById(new MainInfoDO().setId(workOrder.getId()).setProcessInstanceId(processInstanceId)); 380 workOrderMapper.updateById(new MainInfoDO().setId(workOrder.getId()).setProcessInstanceId(processInstanceId));
@@ -490,4 +494,20 @@ public class BpmGardenServiceImpl implements BpmGardenService{ @@ -490,4 +494,20 @@ public class BpmGardenServiceImpl implements BpmGardenService{
490 } 494 }
491 495
492 496
  497 + @Override
  498 + public PageResult<AdminUserRespDTO> getUserByLoginIdAndRoleCode(PageParam param, Long loginUserId, String roleCode, String busiLine, boolean notHas) {
  499 + if(org.springframework.util.ObjectUtils.isEmpty(loginUserId) || org.springframework.util.ObjectUtils.isEmpty(roleCode) || org.springframework.util.ObjectUtils.isEmpty(busiLine)){
  500 + throw exception0(BAD_REQUEST.getCode(),"param:loginUserId,roleCode,busiLine 不能为空!");
  501 + }
  502 + return workOrderExtMapper.getUserByLoginIdAndRoleCodePage(param,loginUserId,roleCode,busiLine,notHas);
  503 + }
  504 +
  505 + @Override
  506 + public PageResult<AdminUserRespDTO> getUserByRoadIdAndRoleCode(PageParam param,Long roadId, String roleCode, String busiLine) {
  507 + if(org.springframework.util.ObjectUtils.isEmpty(roadId) || org.springframework.util.ObjectUtils.isEmpty(roleCode) || org.springframework.util.ObjectUtils.isEmpty(busiLine)){
  508 + throw exception0(BAD_REQUEST.getCode(),"param:roadId,roleCode,busiLine 不能为空!");
  509 + }
  510 + return workOrderExtMapper.getUserByRoadIdAndRoleCodePage(param,roadId,roleCode,busiLine);
  511 + }
  512 +
493 } 513 }
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/service/garden/listener/AutoCompleteTaskListener.java
1 package com.zteits.urbanops.module.workorder.service.garden.listener; 1 package com.zteits.urbanops.module.workorder.service.garden.listener;
2 2
3 -import com.zteits.urbanops.module.bpm.framework.flowable.core.util.FlowableUtils;  
4 -import com.zteits.urbanops.module.workorder.service.garden.BpmGardenService; 3 +import cn.hutool.core.util.StrUtil;
5 import jakarta.annotation.Resource; 4 import jakarta.annotation.Resource;
6 -import lombok.extern.slf4j.Slf4j; 5 +import org.flowable.engine.HistoryService;
  6 +import org.flowable.engine.ProcessEngine;
  7 +import org.flowable.engine.RuntimeService;
7 import org.flowable.engine.TaskService; 8 import org.flowable.engine.TaskService;
8 -import org.flowable.engine.impl.context.Context; 9 +import org.flowable.engine.delegate.TaskListener; // 配套的TaskListener也用核心包
  10 +import org.flowable.task.api.Task;
  11 +import org.flowable.task.api.history.HistoricTaskInstanceQuery;
9 import org.flowable.task.service.delegate.DelegateTask; 12 import org.flowable.task.service.delegate.DelegateTask;
10 -import org.flowable.task.service.delegate.TaskListener; 13 +import org.springframework.context.ApplicationContext;
11 import org.springframework.stereotype.Component; 14 import org.springframework.stereotype.Component;
12 15
  16 +import java.util.HashMap;
  17 +import java.util.Map;
  18 +
13 /** 19 /**
14 - * @author yanhuiqing  
15 - * @version 1.0  
16 - * @description: 自动触发  
17 - * @date 2025/12/11 11:17 20 + * 自动完成任务的监听器(最终版:适配项目实际包路径 + 移除所有报错依赖)
  21 + * Bean名称:autoCompleteTaskListener(与BPMN中的delegateExpression对应)
18 */ 22 */
19 -@Slf4j  
20 -@Component 23 +@Component("autoCompleteTaskListener")
21 public class AutoCompleteTaskListener implements TaskListener { 24 public class AutoCompleteTaskListener implements TaskListener {
22 25
  26 + // ========== 仅使用Flowable核心公开API,移除所有内部/拆分接口 ==========
  27 + @Resource // 若项目习惯用@Autowired,可直接替换(@Resource按名称,@Autowired按类型,功能一致)
  28 + private TaskService taskService;
  29 +
  30 + @Resource
  31 + private RuntimeService runtimeService;
  32 +
  33 + // 核心:直接注入ProcessEngine(兼容所有Flowable版本,可获取任意服务)
23 @Resource 34 @Resource
24 - private BpmGardenService gardenService; 35 + private ProcessEngine processEngine;
  36 +
  37 + @Resource
  38 + private ApplicationContext applicationContext;
  39 +
  40 + // 统一流程状态值(与RuoYi的事件监听器预期值一致)
  41 + private static final String FLOW_STATUS = "3"; // 对应“完成”状态
  42 +
25 @Override 43 @Override
26 - public void notify(DelegateTask delegateTask) {  
27 - // 仅处理任务创建事件  
28 - if (!"create".equals(delegateTask.getEventName())) {  
29 - return;  
30 - } 44 + public void notify(DelegateTask delegateTask) { // 此处DelegateTask为核心包的类,与项目一致
31 try { 45 try {
32 - Thread.sleep(5000); // 延迟200ms,确保任务持久化  
33 - } catch (InterruptedException e) {  
34 - throw new RuntimeException(e); 46 + // 1. 获取核心变量
  47 + String taskId = delegateTask.getId();
  48 + String processInstanceId = delegateTask.getProcessInstanceId();
  49 + String assignee = delegateTask.getAssignee();
  50 +
  51 + // 兜底:从流程变量获取发起人(initiator是Flowable启动节点的发起人变量)
  52 + if (StrUtil.isBlank(assignee)) {
  53 + assignee = (String) delegateTask.getVariable("initiator");
  54 + if (StrUtil.isBlank(assignee)) {
  55 + assignee = (String) runtimeService.getVariable(processInstanceId, "initiator");
  56 + if (StrUtil.isBlank(assignee)) {
  57 + throw new RuntimeException("发起人ID为空,无法完成任务");
  58 + }
  59 + }
  60 + // 修正:使用Flowable公开API更新办理人(彻底放弃内部类操作,无类型转换)
  61 + taskService.setAssignee(taskId, assignee);
  62 + }
  63 +
  64 + // 2. 关键:提前设置所有层级的status变量(解决RuoYi事件status为空)
  65 + runtimeService.setVariable(processInstanceId, "status", FLOW_STATUS); // 流程全局变量
  66 + delegateTask.setVariable("status", FLOW_STATUS); // 任务局部变量
  67 + Map<String, Object> variables = new HashMap<>();
  68 + variables.put("status", FLOW_STATUS);
  69 + variables.put("completeRemark", "系统自动完成,办理人:" + assignee);
  70 +
  71 + // 3. 完成任务(Flowable核心API,兼容所有版本)
  72 + Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
  73 + if (task != null) {
  74 + taskService.complete(taskId, variables);
  75 + }
  76 +
  77 + // 4. 兜底:确保历史任务归档(使用ProcessEngine获取HistoryService,无报错)
  78 + ensureHistoricTaskCompleted(taskId, assignee);
  79 +
  80 + // 5. 手动发布事件补充status(解决RuoYi的事件校验问题)
  81 + publishProcessEventWithStatus(processInstanceId);
  82 +
  83 + } catch (Exception e) {
  84 + throw new RuntimeException("自动完成任务失败", e);
  85 + }
  86 + }
  87 +
  88 + /**
  89 + * 修正:使用ProcessEngine获取HistoryService(兼容所有Flowable版本,无报错)
  90 + * 彻底移除HistoryTaskService,改用核心HistoryService
  91 + */
  92 + private void ensureHistoricTaskCompleted(String taskId, String assignee) {
  93 + // 核心:从ProcessEngine获取HistoryService(Flowable 6.x/7.0通用)
  94 + HistoryService historyService = processEngine.getHistoryService();
  95 + // 历史任务查询(Flowable核心API,无报错)
  96 + //HistoricTaskInstanceQuery historicTask = historyService.createHistoricTaskInstanceQuery()
  97 + // .taskId(taskId)
  98 + // .singleResult();
  99 +
  100 + /*if (historicTask != null) {
  101 + if (historicTask.getEndTime() == null) {
  102 + Task runtimeTask = taskService.createTaskQuery().taskId(taskId).singleResult();
  103 + if (runtimeTask != null) {
  104 + taskService.complete(taskId);
  105 + } else {
  106 + // 手动更新历史任务表(通过MyBatis操作,避免Flowable API差异)
  107 + // updateHistoricTask(taskId, assignee); // 若需要,自行实现Mapper
  108 + }
  109 + }
  110 + }*/
  111 + }
  112 +
  113 + /**
  114 + * 手动发布包含status的流程事件(适配RuoYi事件类,避免导入依赖)
  115 + */
  116 + private void publishProcessEventWithStatus(String processInstanceId) {
  117 + try {
  118 + // 反射创建RuoYi的ProcessInstanceResultEvent(兼容无参/有参构造)
  119 + Class<?> eventClass = Class.forName("com.ruoyi.flowable.event.ProcessInstanceResultEvent");
  120 + Object event = null;
  121 +
  122 + // 先尝试无参构造
  123 + try {
  124 + event = eventClass.getDeclaredConstructor().newInstance();
  125 + } catch (Exception e) {
  126 + // 无参失败,尝试单参构造(流程实例ID)
  127 + try {
  128 + event = eventClass.getConstructor(String.class).newInstance(processInstanceId);
  129 + } catch (Exception e2) {
  130 + // 单参失败,尝试双参构造(流程实例ID + status)
  131 + event = eventClass.getConstructor(String.class, String.class).newInstance(processInstanceId, FLOW_STATUS);
  132 + }
  133 + }
  134 +
  135 + // 强制设置status属性(无论构造方式如何)
  136 + eventClass.getMethod("setStatus", String.class).invoke(event, FLOW_STATUS);
  137 + eventClass.getMethod("setProcessInstanceId", String.class).invoke(event, processInstanceId);
  138 +
  139 + // 发布事件(覆盖RuoYi的空status事件)
  140 + applicationContext.publishEvent(event);
  141 + } catch (Exception e) {
  142 + // 反射失败时,提示用户修改RuoYi的事件校验逻辑(应急方案)
  143 + e.printStackTrace();
  144 + System.out.println("★★★反射发布事件失败,请手动修改RuoYi的ProcessInstanceResultEvent校验逻辑,添加status默认值★★★");
35 } 145 }
36 - Long assigneeId = Long.parseLong(delegateTask.getAssignee());  
37 - //FlowableUtils.executeAuthenticatedUserId(assigneeId, () -> {  
38 - // 完成任务(在认证上下文内执行)  
39 - TaskService taskService = Context.getProcessEngineConfiguration().getTaskService();  
40 - taskService.complete(delegateTask.getId());  
41 - // return assigneeId;  
42 - //});  
43 -  
44 - // 1. 获取发起人变量(芋道流程中配置的initiator)  
45 - //String initiator = (String) delegateTask.getVariable("initiator");  
46 - // 2. 当前任务处理人(即发起人)  
47 - //String currentAssignee = delegateTask.getAssignee();  
48 -  
49 - // 3. 校验:处理人是发起人则自动完成任务  
50 - // if (initiator != null && initiator.equals(currentAssignee)) {  
51 -// TaskService taskService = Context.getProcessEngineConfiguration().getTaskService();  
52 - // 添加备注变量  
53 - // delegateTask.setVariable("autoCompleteReason", "发起人自动完成任务");  
54 - // 完成任务,触发流程流转到结束节点  
55 - // taskService.complete(delegateTask.getId());  
56 - // }  
57 } 146 }
58 -} 147 +
  148 + // 若需要手动更新历史任务表,自行实现以下方法(需添加MyBatis Mapper)
  149 + // private void updateHistoricTask(String taskId, String assignee) {
  150 + // // historicTaskMapper.updateHistoricTask(taskId, assignee, new Date());
  151 + // }
  152 +}
59 \ No newline at end of file 153 \ No newline at end of file
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/service/garden/listener/BpmProcessTaskAutoCompleteListener.java 0 → 100644
  1 +package com.zteits.urbanops.module.workorder.service.garden.listener;
  2 +
  3 +import com.zteits.urbanops.module.bpm.api.event.BpmProcessInstanceStatusEvent;
  4 +import com.zteits.urbanops.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
  5 +import com.zteits.urbanops.module.workorder.api.constant.BpmCommonConstant;
  6 +import com.zteits.urbanops.module.workorder.service.garden.BpmGardenService;
  7 +import jakarta.annotation.Resource;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +/**
  12 + * @author yanhuiqing
  13 + * @version 1.0
  14 + * @description: 处理流程的任务自动完成监听器
  15 + * @date 2025/12/6 14:00
  16 + */
  17 +@Component
  18 +@Slf4j
  19 +public class BpmProcessTaskAutoCompleteListener extends BpmProcessInstanceStatusEventListener {
  20 + @Resource
  21 + private BpmGardenService gardenService;
  22 + @Override
  23 + protected String getProcessDefinitionKey() {
  24 +
  25 + return BpmCommonConstant.BPM_GARDEN_INSPECT_WO;
  26 + }
  27 +
  28 + @Override
  29 + protected void onEvent(BpmProcessInstanceStatusEvent event) {
  30 + log.info("业务ID:"+event.getBusinessKey()+",业务状态"+event.getStatus());
  31 + gardenService.updateWorkOrderStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
  32 +
  33 + }
  34 +}
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/service/garden/listener/BpmQuickProcessTaskAutoCompleteListener.java
@@ -22,6 +22,8 @@ public class BpmQuickProcessTaskAutoCompleteListener extends BpmProcessInstanceS @@ -22,6 +22,8 @@ public class BpmQuickProcessTaskAutoCompleteListener extends BpmProcessInstanceS
22 private BpmGardenService gardenService; 22 private BpmGardenService gardenService;
23 @Override 23 @Override
24 protected String getProcessDefinitionKey() { 24 protected String getProcessDefinitionKey() {
  25 +
  26 + //return "quik_local_test";
25 return BpmCommonConstant.COMMON_QUICK_PROCESS; 27 return BpmCommonConstant.COMMON_QUICK_PROCESS;
26 } 28 }
27 29