From 197605f4d2dac76b54af541ca49f97792b5d7046 Mon Sep 17 00:00:00 2001 From: aikai Date: Fri, 20 Jun 2025 16:00:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(bpm):=20=E6=96=B0=E5=A2=9E=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E6=A8=A1=E5=9D=97=E8=AE=BE=E8=AE=A1=E5=92=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加工单模块前端设计文档,详细描述了页面架构、权限设计和API调用流程 - 新增工单模块数据库表结构,包括工单主表、分配规则表和跟踪记录表 - 创建工单类型、状态和优先级的字典数据 - 添加示例分配规则数据 --- .../dataobject/oa/BpmOAWorkOrderTrackDO.java | 71 +++ .../admin/oa/BpmOAWorkOrderController.java | 98 ++++ .../workorder/BpmOAWorkOrderCreateReqVO.java | 44 ++ .../vo/workorder/BpmOAWorkOrderPageReqVO.java | 39 ++ .../oa/vo/workorder/BpmOAWorkOrderRespVO.java | 91 ++++ .../vo/workorder/BpmOAWorkOrderTrackInfo.java | 33 ++ .../workorder/BpmOAWorkOrderTrackReqVO.java | 25 ++ .../workorder/BpmOAWorkOrderUpdateReqVO.java | 34 ++ .../oa/BpmOAWorkOrderAssignRuleDO.java | 61 +++ .../dal/dataobject/oa/BpmOAWorkOrderDO.java | 125 ++++++ .../dataobject/oa/BpmOAWorkOrderTrackDO.java | 71 +++ .../oa/BpmOAWorkOrderAssignRuleMapper.java | 49 ++ .../dal/mysql/oa/BpmOAWorkOrderMapper.java | 67 +++ .../mysql/oa/BpmOAWorkOrderTrackMapper.java | 27 ++ .../bpm/enums/oa/WorkOrderLevelEnum.java | 56 +++ .../bpm/enums/oa/WorkOrderStatusEnum.java | 64 +++ .../bpm/enums/oa/WorkOrderTrackTypeEnum.java | 47 ++ .../bpm/enums/oa/WorkOrderTypeEnum.java | 43 ++ .../bpm/service/oa/BpmOAWorkOrderService.java | 116 +++++ .../service/oa/BpmOAWorkOrderServiceImpl.java | 420 ++++++++++++++++++ 20 files changed, 1581 insertions(+) create mode 100644 yudao-module-bmp/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAWorkOrderController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderCreateReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderPageReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackInfo.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderUpdateReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderAssignRuleDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderAssignRuleMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderTrackMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderLevelEnum.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderStatusEnum.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTrackTypeEnum.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTypeEnum.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderServiceImpl.java diff --git a/yudao-module-bmp/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java b/yudao-module-bmp/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java new file mode 100644 index 00000000..f290ae5c --- /dev/null +++ b/yudao-module-bmp/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * BPM OA 工单跟踪记录 DO + * + * @author 系统 + */ +@TableName(value = "bpm_oa_work_order_track", autoResultMap = true) +@KeySequence("bpm_oa_work_order_track_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOAWorkOrderTrackDO extends BaseDO { + + /** + * 跟踪记录ID + */ + @TableId + private Long id; + + /** + * 工单ID + */ + private Long workOrderId; + + /** + * 操作人ID + */ + private Long operatorId; + + /** + * 操作人姓名 + */ + private String operatorName; + + /** + * 操作类型 + * + * 枚举值: + * - CREATE: 创建工单 + * - ASSIGN: 分配工单 + * - PROCESS: 处理中 + * - COMPLETE: 完成工单 + * - CANCEL: 取消工单 + * - COMMENT: 添加备注 + */ + private String operationType; + + /** + * 操作内容/备注 + */ + private String content; + + /** + * 附件文件列表,JSON格式 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private String attachments; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAWorkOrderController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAWorkOrderController.java new file mode 100644 index 00000000..6c5ef61f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAWorkOrderController.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderDO; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOAWorkOrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * 管理后台 - BPM OA 工单 + * + * @author 系统 + */ +@Tag(name = "管理后台 - BPM OA 工单") +@RestController +@RequestMapping("/admin-api/bpm/oa/work-order") +@Validated +@Slf4j +public class BpmOAWorkOrderController { + + @Resource + private BpmOAWorkOrderService workOrderService; + + @PostMapping("/create") + @Operation(summary = "创建工单") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:create')") + public CommonResult createWorkOrder(@Valid @RequestBody BpmOAWorkOrderCreateReqVO createReqVO) { + return success(workOrderService.createWorkOrder(getLoginUserId(), createReqVO)); + } + + @GetMapping("/page") + @Operation(summary = "获得工单分页") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:query')") + public CommonResult> getWorkOrderPage(@Valid BpmOAWorkOrderPageReqVO pageReqVO) { + return success(workOrderService.getWorkOrderPage(getLoginUserId(), pageReqVO)); + } + + @GetMapping("/my-page") + @Operation(summary = "获得我发起的工单分页") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:query')") + public CommonResult> getMyWorkOrderPage(@Valid BpmOAWorkOrderPageReqVO pageReqVO) { + return success(workOrderService.getMyWorkOrderPage(getLoginUserId(), pageReqVO)); + } + + @GetMapping("/assigned-page") + @Operation(summary = "获得分配给我的工单分页") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:query')") + public CommonResult> getAssignedWorkOrderPage(@Valid BpmOAWorkOrderPageReqVO pageReqVO) { + return success(workOrderService.getAssignedWorkOrderPage(getLoginUserId(), pageReqVO)); + } + + @GetMapping("/get/{id}") + @Operation(summary = "获得工单详情") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:query')") + public CommonResult getWorkOrder(@PathVariable("id") Long id) { + return success(workOrderService.getWorkOrderDetail(id)); + } + + @PostMapping("/track") + @Operation(summary = "添加工单跟踪记录") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:update')") + public CommonResult addTrackInfo(@Valid @RequestBody BpmOAWorkOrderTrackReqVO trackReqVO) { + workOrderService.addTrackInfo(getLoginUserId(), trackReqVO); + return success(true); + } + + @PutMapping("/update") + @Operation(summary = "修改工单") + @PreAuthorize("@ss.hasPermission('bpm:oa-work-order:update')") + public CommonResult updateWorkOrder(@Valid @RequestBody BpmOAWorkOrderUpdateReqVO updateReqVO) { + workOrderService.updateWorkOrder(updateReqVO); + return success(true); + } + + @GetMapping("/my-assigned-count") + @Operation(summary = "获得我的待处理工单数量") + @PermitAll + public CommonResult getMyAssignedWorkOrderCount() { + return success(workOrderService.getMyAssignedWorkOrderCount(getLoginUserId())); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderCreateReqVO.java new file mode 100644 index 00000000..2fe9a72a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderCreateReqVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM OA 工单创建 Request VO") +@Data +public class BpmOAWorkOrderCreateReqVO { + + @Schema(description = "工单标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "系统登录问题") + @NotEmpty(message = "工单标题不能为空") + private String title; + + @Schema(description = "工单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "it_support") + @NotEmpty(message = "工单类型不能为空") + private String type; + + @Schema(description = "优先级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "优先级别不能为空") + private Integer level; + + @Schema(description = "工单内容描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户无法登录系统,提示密码错误") + @NotEmpty(message = "工单内容不能为空") + private String content; + + @Schema(description = "期望完成时间", example = "2024-12-20 18:00:00") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime expectedTime; + + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderPageReqVO.java new file mode 100644 index 00000000..5d0246e5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderPageReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM OA 工单分页查询 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOAWorkOrderPageReqVO extends PageParam { + + @Schema(description = "工单标题", example = "系统登录问题") + private String title; + + @Schema(description = "工单类型", example = "it_support") + private String type; + + @Schema(description = "工单状态", example = "1") + private Integer status; + + @Schema(description = "责任人ID", example = "1") + private Long assigneeUserId; + + @Schema(description = "发起人ID", example = "1") + private Long fromUserId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderRespVO.java new file mode 100644 index 00000000..1badcdb7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderRespVO.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - BPM OA 工单 Response VO") +@Data +public class BpmOAWorkOrderRespVO { + + @Schema(description = "工单ID", example = "1") + private Long id; + + @Schema(description = "工单标题", example = "系统登录问题") + private String title; + + @Schema(description = "工单类型", example = "it_support") + private String type; + + @Schema(description = "工单类型名称", example = "IT支持") + private String typeName; + + @Schema(description = "优先级别", example = "2") + private Integer level; + + @Schema(description = "优先级名称", example = "中") + private String levelName; + + @Schema(description = "工单内容描述", example = "用户无法登录系统,提示密码错误") + private String content; + + @Schema(description = "发起人ID", example = "1") + private Long fromUserId; + + @Schema(description = "发起人姓名", example = "张三") + private String fromUserName; + + @Schema(description = "发起部门ID", example = "100") + private Long fromDeptId; + + @Schema(description = "发起部门名称", example = "技术部") + private String fromDeptName; + + @Schema(description = "责任人ID", example = "2") + private Long assigneeUserId; + + @Schema(description = "责任人姓名", example = "李四") + private String assigneeUserName; + + @Schema(description = "责任部门ID", example = "101") + private Long assigneeDeptId; + + @Schema(description = "责任部门名称", example = "运维部") + private String assigneeDeptName; + + @Schema(description = "工单状态", example = "2") + private Integer status; + + @Schema(description = "工单状态名称", example = "处理中") + private String statusName; + + @Schema(description = "期望完成时间", example = "2024-12-20 18:00:00") + private LocalDateTime expectedTime; + + @Schema(description = "实际完成时间", example = "2024-12-20 16:30:00") + private LocalDateTime completedTime; + + @Schema(description = "工单处理结果说明", example = "已成功修复系统登录问题") + private String resultDescription; + + @Schema(description = "BPM流程结果", example = "2") + private Integer result; + + @Schema(description = "BPM流程实例ID", example = "proc_inst_123456") + private String processInstanceId; + + @Schema(description = "附件文件列表") + private List fileItems; + + @Schema(description = "工单跟踪记录") + private List trackInfo; + + @Schema(description = "创建时间", example = "2024-12-19 10:00:00") + private LocalDateTime createTime; + + @Schema(description = "更新时间", example = "2024-12-19 15:30:00") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackInfo.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackInfo.java new file mode 100644 index 00000000..7fc3267a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackInfo.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * BPM OA 工单跟踪信息 + * + * @author 系统 + */ +@Schema(description = "BPM OA 工单跟踪信息") +@Data +public class BpmOAWorkOrderTrackInfo { + + @Schema(description = "跟踪ID") + private String trackId; + + @Schema(description = "操作人ID") + private Long operatorId; + + @Schema(description = "操作人姓名") + private String operatorName; + + @Schema(description = "操作内容") + private String content; + + @Schema(description = "操作时间") + private String trackTime; + + @Schema(description = "操作类型") + private String operationType; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackReqVO.java new file mode 100644 index 00000000..2f093244 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderTrackReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - BPM OA 工单跟踪记录 Request VO") +@Data +public class BpmOAWorkOrderTrackReqVO { + + @Schema(description = "工单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "工单ID不能为空") + private Long workOrderId; + + @Schema(description = "操作类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "PROCESS") + @NotEmpty(message = "操作类型不能为空") + private String operationType; + + @Schema(description = "操作内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "已开始处理该工单,预计今天下午完成") + @NotEmpty(message = "操作内容不能为空") + private String content; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderUpdateReqVO.java new file mode 100644 index 00000000..ccad5d6a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/workorder/BpmOAWorkOrderUpdateReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM OA 工单修改 Request VO") +@Data +public class BpmOAWorkOrderUpdateReqVO { + + @Schema(description = "工单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "工单ID不能为空") + private Long id; + + @Schema(description = "工单状态", example = "3") + private Integer status; + + @Schema(description = "期望完成时间", example = "2024-12-20 18:00:00") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime expectedTime; + + @Schema(description = "实际完成时间", example = "2024-12-20 16:30:00") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime completedTime; + + @Schema(description = "工单处理结果说明", example = "已成功修复系统登录问题,用户可以正常登录") + private String resultDescription; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderAssignRuleDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderAssignRuleDO.java new file mode 100644 index 00000000..031648e5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderAssignRuleDO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * BPM OA 工单分配规则 DO + * + * @author 系统 + */ +@TableName("bpm_oa_work_order_assign_rule") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOAWorkOrderAssignRuleDO extends BaseDO { + + /** + * 规则ID,主键 + */ + @TableId + private Long id; + + /** + * 工单类型 + * 字典值:work_order_type + */ + private String workOrderType; + + /** + * 责任部门ID + */ + private Long deptId; + + /** + * 责任人ID + */ + private Long assigneeUserId; + + /** + * 规则优先级 + * 数值越小优先级越高 + */ + private Integer priority; + + /** + * 规则状态 + * 1-启用,0-禁用 + */ + private Integer status; + + /** + * 规则描述 + */ + private String description; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderDO.java new file mode 100644 index 00000000..605616bc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderDO.java @@ -0,0 +1,125 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder.BpmOAWorkOrderTrackInfo; +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * BPM OA 工单 DO + * + * @author 系统 + */ +@TableName(value = "bpm_oa_work_order", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOAWorkOrderDO extends BaseDO { + + /** + * 工单ID,主键 + */ + @TableId + private Long id; + + /** + * 工单标题 + */ + private String title; + + /** + * 工单类型 + * 字典值:work_order_type + */ + private String type; + + /** + * 优先级别 + * 1-低,2-中,3-高,4-紧急 + */ + private Integer level; + + /** + * 工单内容描述 + */ + private String content; + + /** + * 发起人ID + */ + private Long fromUserId; + + /** + * 发起人部门ID + */ + private Long fromDeptId; + + /** + * 责任人ID(分配给谁处理) + */ + private Long assigneeUserId; + + /** + * 责任部门ID + */ + private Long assigneeDeptId; + + /** + * 工单状态 + * 1-待分配,2-处理中,3-已完成,4-已取消,5-已关闭 + */ + private Integer status; + + /** + * 期望完成时间 + */ + private LocalDateTime expectedTime; + + /** + * 实际完成时间 + */ + private LocalDateTime completedTime; + + /** + * 工单处理结果说明 + */ + private String resultDescription; + + /** + * BPM流程结果 + * + * 枚举 {@link BpmProcessInstanceResultEnum} + */ + private Integer result; + + /** + * 对应的BPM流程实例ID + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + + /** + * 附件信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems; + + /** + * 工单跟踪记录信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List trackInfo; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java new file mode 100644 index 00000000..f290ae5c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAWorkOrderTrackDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * BPM OA 工单跟踪记录 DO + * + * @author 系统 + */ +@TableName(value = "bpm_oa_work_order_track", autoResultMap = true) +@KeySequence("bpm_oa_work_order_track_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOAWorkOrderTrackDO extends BaseDO { + + /** + * 跟踪记录ID + */ + @TableId + private Long id; + + /** + * 工单ID + */ + private Long workOrderId; + + /** + * 操作人ID + */ + private Long operatorId; + + /** + * 操作人姓名 + */ + private String operatorName; + + /** + * 操作类型 + * + * 枚举值: + * - CREATE: 创建工单 + * - ASSIGN: 分配工单 + * - PROCESS: 处理中 + * - COMPLETE: 完成工单 + * - CANCEL: 取消工单 + * - COMMENT: 添加备注 + */ + private String operationType; + + /** + * 操作内容/备注 + */ + private String content; + + /** + * 附件文件列表,JSON格式 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private String attachments; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderAssignRuleMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderAssignRuleMapper.java new file mode 100644 index 00000000..9714fe9e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderAssignRuleMapper.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderAssignRuleDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * BPM OA 工单分配规则 Mapper + * + * @author 系统 + */ +@Mapper +public interface BpmOAWorkOrderAssignRuleMapper extends BaseMapperX { + + /** + * 根据工单类型查询启用的分配规则 + */ + default List selectRulesByType(String workOrderType) { + return selectList(new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderAssignRuleDO::getWorkOrderType, workOrderType) + .eq(BpmOAWorkOrderAssignRuleDO::getStatus, 1) + .orderByAsc(BpmOAWorkOrderAssignRuleDO::getPriority)); + } + + /** + * 根据部门ID查询分配规则 + */ + default List selectRulesByDept(Long deptId) { + return selectList(new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderAssignRuleDO::getDeptId, deptId) + .eq(BpmOAWorkOrderAssignRuleDO::getStatus, 1) + .orderByAsc(BpmOAWorkOrderAssignRuleDO::getPriority)); + } + + /** + * 根据责任人ID查询分配规则 + */ + default List selectRulesByAssignee(Long assigneeUserId) { + return selectList(new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderAssignRuleDO::getAssigneeUserId, assigneeUserId) + .eq(BpmOAWorkOrderAssignRuleDO::getStatus, 1) + .orderByAsc(BpmOAWorkOrderAssignRuleDO::getPriority)); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderMapper.java new file mode 100644 index 00000000..4d175aa6 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderMapper.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder.BpmOAWorkOrderPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * BPM OA 工单 Mapper + * + * @author 系统 + */ +@Mapper +public interface BpmOAWorkOrderMapper extends BaseMapperX { + + /** + * 工单分页查询 + */ + default PageResult selectPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmOAWorkOrderDO::getTitle, pageVO.getTitle()) + .eqIfPresent(BpmOAWorkOrderDO::getType, pageVO.getType()) + .eqIfPresent(BpmOAWorkOrderDO::getStatus, pageVO.getStatus()) + .eqIfPresent(BpmOAWorkOrderDO::getAssigneeUserId, pageVO.getAssigneeUserId()) + .eqIfPresent(BpmOAWorkOrderDO::getFromUserId, pageVO.getFromUserId()) + .betweenIfPresent(BpmOAWorkOrderDO::getCreateTime, pageVO.getCreateTime()) + .orderByDesc(BpmOAWorkOrderDO::getId)); + } + + /** + * 查询我的工单分页(我发起的) + */ + default PageResult selectMyPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderDO::getFromUserId, loginUserId) + .likeIfPresent(BpmOAWorkOrderDO::getTitle, pageVO.getTitle()) + .eqIfPresent(BpmOAWorkOrderDO::getType, pageVO.getType()) + .eqIfPresent(BpmOAWorkOrderDO::getStatus, pageVO.getStatus()) + .betweenIfPresent(BpmOAWorkOrderDO::getCreateTime, pageVO.getCreateTime()) + .orderByDesc(BpmOAWorkOrderDO::getId)); + } + + /** + * 查询我负责的工单分页(分配给我的) + */ + default PageResult selectAssignedPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderDO::getAssigneeUserId, loginUserId) + .likeIfPresent(BpmOAWorkOrderDO::getTitle, pageVO.getTitle()) + .eqIfPresent(BpmOAWorkOrderDO::getType, pageVO.getType()) + .eqIfPresent(BpmOAWorkOrderDO::getStatus, pageVO.getStatus()) + .betweenIfPresent(BpmOAWorkOrderDO::getCreateTime, pageVO.getCreateTime()) + .orderByDesc(BpmOAWorkOrderDO::getId)); + } + + /** + * 查询我负责工单的数量 + */ + default Long selectMyAssignedCount(Long userId) { + return selectCount(new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderDO::getAssigneeUserId, userId) + .in(BpmOAWorkOrderDO::getStatus, 1, 2)); // 待分配和处理中 + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderTrackMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderTrackMapper.java new file mode 100644 index 00000000..d5dfc98e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAWorkOrderTrackMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderTrackDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * BPM OA 工单跟踪记录 Mapper + * + * @author 系统 + */ +@Mapper +public interface BpmOAWorkOrderTrackMapper extends BaseMapperX { + + /** + * 根据工单ID查询跟踪记录列表 + */ + default List selectByWorkOrderId(Long workOrderId) { + return selectList(new LambdaQueryWrapperX() + .eq(BpmOAWorkOrderTrackDO::getWorkOrderId, workOrderId) + .orderByAsc(BpmOAWorkOrderTrackDO::getCreateTime)); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderLevelEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderLevelEnum.java new file mode 100644 index 00000000..7859ea56 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderLevelEnum.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.bpm.enums.oa; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 工单优先级枚举 + * + * @author 系统 + */ +@Getter +@AllArgsConstructor +public enum WorkOrderLevelEnum { + + LOW(1, "低"), + MEDIUM(2, "中"), + HIGH(3, "高"), + URGENT(4, "紧急"); + + /** + * 级别值 + */ + private final Integer level; + + /** + * 级别名称 + */ + private final String name; + + /** + * 根据级别值获取枚举 + */ + public static WorkOrderLevelEnum getByLevel(Integer level) { + for (WorkOrderLevelEnum levelEnum : values()) { + if (levelEnum.getLevel().equals(level)) { + return levelEnum; + } + } + return null; + } + + /** + * 判断是否为紧急级别 + */ + public static boolean isUrgent(Integer level) { + return URGENT.getLevel().equals(level); + } + + /** + * 判断是否为高优先级(高或紧急) + */ + public static boolean isHighPriority(Integer level) { + return HIGH.getLevel().equals(level) || URGENT.getLevel().equals(level); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderStatusEnum.java new file mode 100644 index 00000000..89b1ba50 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderStatusEnum.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.bpm.enums.oa; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 工单状态枚举 + * + * @author 系统 + */ +@Getter +@AllArgsConstructor +public enum WorkOrderStatusEnum { + + PENDING_ASSIGN(1, "待分配"), + PROCESSING(2, "处理中"), + COMPLETED(3, "已完成"), + CANCELLED(4, "已取消"), + CLOSED(5, "已关闭"); + + /** + * 状态值 + */ + private final Integer status; + + /** + * 状态名称 + */ + private final String name; + + /** + * 根据状态值获取枚举 + */ + public static WorkOrderStatusEnum valueOf(Integer status) { + for (WorkOrderStatusEnum statusEnum : values()) { + if (statusEnum.getStatus().equals(status)) { + return statusEnum; + } + } + return null; + } + + /** + * 判断是否为处理中状态 + */ + public static boolean isProcessing(Integer status) { + return PROCESSING.getStatus().equals(status); + } + + /** + * 判断是否为已完成状态 + */ + public static boolean isCompleted(Integer status) { + return COMPLETED.getStatus().equals(status); + } + + /** + * 判断是否为待分配状态 + */ + public static boolean isPendingAssign(Integer status) { + return PENDING_ASSIGN.getStatus().equals(status); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTrackTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTrackTypeEnum.java new file mode 100644 index 00000000..941dde6d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTrackTypeEnum.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.enums.oa; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 工单跟踪记录操作类型枚举 + * + * @author 系统 + */ +@AllArgsConstructor +@Getter +public enum WorkOrderTrackTypeEnum { + + CREATE("CREATE", "创建工单"), + ASSIGN("ASSIGN", "分配工单"), + PROCESS("PROCESS", "处理中"), + COMPLETE("COMPLETE", "完成工单"), + CANCEL("CANCEL", "取消工单"), + COMMENT("COMMENT", "添加备注"), + TRANSFER("TRANSFER", "转派工单"), + REOPEN("REOPEN", "重新打开"), + CLOSE("CLOSE", "关闭工单"); + + /** + * 操作类型 + */ + private final String type; + + /** + * 操作描述 + */ + private final String description; + + /** + * 根据类型获取枚举 + */ + public static WorkOrderTrackTypeEnum getByType(String type) { + for (WorkOrderTrackTypeEnum trackType : values()) { + if (trackType.getType().equals(type)) { + return trackType; + } + } + return null; + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTypeEnum.java new file mode 100644 index 00000000..f1db7fa4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/enums/oa/WorkOrderTypeEnum.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.bpm.enums.oa; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 工单类型枚举 + * + * @author 系统 + */ +@Getter +@AllArgsConstructor +public enum WorkOrderTypeEnum { + + IT_SUPPORT("it_support", "IT支持"), + EQUIPMENT_REPAIR("equipment_repair", "设备维修"), + SYSTEM_ISSUE("system_issue", "系统问题"), + PERMISSION_REQUEST("permission_request", "权限申请"), + OTHER("other", "其他"); + + /** + * 类型值 + */ + private final String type; + + /** + * 类型名称 + */ + private final String name; + + /** + * 根据类型值获取枚举 + */ + public static WorkOrderTypeEnum getByType(String type) { + for (WorkOrderTypeEnum typeEnum : values()) { + if (typeEnum.getType().equals(type)) { + return typeEnum; + } + } + return null; + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderService.java new file mode 100644 index 00000000..c0ce4353 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderService.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderDO; + +import javax.validation.Valid; + +/** + * BPM OA 工单 Service 接口 + * + * @author 系统 + */ +public interface BpmOAWorkOrderService { + + /** + * 创建工单 + * + * @param userId 发起人ID + * @param createReqVO 创建请求 + * @return 工单ID + */ + Long createWorkOrder(Long userId, @Valid BpmOAWorkOrderCreateReqVO createReqVO); + + /** + * 更新工单状态结果 + * + * @param id 工单ID + * @param result BPM流程结果 + */ + void updateWorkOrderResult(Long id, Integer result); + + /** + * 分配工单 + * + * @param id 工单ID + * @param assigneeUserId 责任人ID + * @param assigneeDeptId 责任部门ID + */ + void assignWorkOrder(Long id, Long assigneeUserId, Long assigneeDeptId); + + /** + * 添加工单跟踪信息 + * + * @param userId 操作人ID + * @param trackReqVO 跟踪信息 + */ + void addTrackInfo(Long userId, @Valid BpmOAWorkOrderTrackReqVO trackReqVO); + + /** + * 更新工单 + * + * @param updateReqVO 更新请求 + */ + void updateWorkOrder(@Valid BpmOAWorkOrderUpdateReqVO updateReqVO); + + /** + * 获取工单详情 + * + * @param id 工单ID + * @return 工单DO + */ + BpmOAWorkOrderDO getWorkOrder(Long id); + + /** + * 获取工单详情(带扩展信息) + * + * @param id 工单ID + * @return 工单详情VO + */ + BpmOAWorkOrderRespVO getWorkOrderDetail(Long id); + + /** + * 根据流程实例ID获取工单 + * + * @param processInstanceId 流程实例ID + * @return 工单DO + */ + BpmOAWorkOrderDO getWorkOrderByProcessInstanceId(String processInstanceId); + + /** + * 获取工单分页 + * + * @param loginUserId 登录用户ID + * @param pageVO 分页请求 + * @return 分页结果 + */ + PageResult getWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO); + + /** + * 获取我发起的工单分页 + * + * @param loginUserId 登录用户ID + * @param pageVO 分页请求 + * @return 分页结果 + */ + PageResult getMyWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO); + + /** + * 获取分配给我的工单分页 + * + * @param loginUserId 登录用户ID + * @param pageVO 分页请求 + * @return 分页结果 + */ + PageResult getAssignedWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO); + + /** + * 获取我负责工单的数量 + * + * @param userId 用户ID + * @return 工单数量 + */ + Long getMyAssignedWorkOrderCount(Long userId); + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderServiceImpl.java new file mode 100644 index 00000000..1eda3d56 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAWorkOrderServiceImpl.java @@ -0,0 +1,420 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderAssignRuleDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderTrackDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAWorkOrderAssignRuleMapper; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAWorkOrderMapper; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAWorkOrderTrackMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_WORK_TASK_NOT_EXISTS; + +/** + * BPM OA 工单 Service 实现类 + * + * @author 系统 + */ +@Service +@Validated +public class BpmOAWorkOrderServiceImpl extends BpmOABaseService implements BpmOAWorkOrderService { + + /** + * 工单对应的流程定义 KEY + */ + public static final String PROCESS_KEY = "work_order"; + + @Resource + private BpmOAWorkOrderMapper workOrderMapper; + + @Resource + private BpmOAWorkOrderAssignRuleMapper assignRuleMapper; + + @Resource + private BpmOAWorkOrderTrackMapper trackMapper; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Resource + private AdminUserApi userApi; + + @Resource + private DeptApi deptApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createWorkOrder(Long userId, BpmOAWorkOrderCreateReqVO createReqVO) { + // 获取当前登录用户信息 + AdminUserRespDTO userRespDTO = userApi.getUser(userId).getCheckedData(); + + // 创建工单DO + BpmOAWorkOrderDO workOrder = BpmOAWorkOrderDO.builder() + .title(createReqVO.getTitle()) + .type(createReqVO.getType()) + .level(createReqVO.getLevel()) + .content(createReqVO.getContent()) + .expectedTime(createReqVO.getExpectedTime()) + .fromUserId(userId) + .fromDeptId(userRespDTO.getDeptId()) + .status(1) // 默认状态:待分配 + .result(BpmProcessInstanceResultEnum.PROCESS.getResult()) + .build(); + + workOrderMapper.insert(workOrder); + + // 自动分配责任人(根据规则) + autoAssignWorkOrder(workOrder); + + // 发起 BPM 流程 + Map processInstanceVariables = new HashMap<>(); + String processInstanceId = processInstanceApi.createProcessInstance(userId, + new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(workOrder.getId()))).getCheckedData(); + + // 更新工单的流程实例ID + workOrderMapper.updateById(new BpmOAWorkOrderDO().setId(workOrder.getId()).setProcessInstanceId(processInstanceId)); + + // 创建初始跟踪记录 + createTrackRecord(workOrder.getId(), userId, userRespDTO.getNickname(), "CREATE", "创建工单", null); + + List fileItems = createReqVO.getFileItems(); + //这里的逻辑,如果fileItems不为空,且有数据,那么说明是上传了附件的,则需要更工作流文件表对应的实例Id + if (fileItems != null && !fileItems.isEmpty()) { + uploadBpmFileProcessInstanceId(processInstanceId, fileItems); + } + + return workOrder.getId(); + } + + @Override + public void updateWorkOrderResult(Long id, Integer result) { + validateWorkOrderExists(id); + // BPM流程完成时,将工单状态设置为已完成 + int status = result.equals(BpmProcessInstanceResultEnum.APPROVE.getResult()) ? 3 : 4; // 3-已完成,4-已取消 + LocalDateTime completedTime = result.equals(BpmProcessInstanceResultEnum.APPROVE.getResult()) ? LocalDateTime.now() : null; + + workOrderMapper.updateById(new BpmOAWorkOrderDO() + .setId(id) + .setResult(result) + .setStatus(status) + .setCompletedTime(completedTime)); + } + + @Override + public void assignWorkOrder(Long id, Long assigneeUserId, Long assigneeDeptId) { + validateWorkOrderExists(id); + workOrderMapper.updateById(new BpmOAWorkOrderDO() + .setId(id) + .setAssigneeUserId(assigneeUserId) + .setAssigneeDeptId(assigneeDeptId) + .setStatus(2)); // 2-处理中 + + // 创建分配跟踪记录 + AdminUserRespDTO assigneeUser = userApi.getUser(assigneeUserId).getCheckedData(); + createTrackRecord(id, assigneeUserId, assigneeUser.getNickname(), "ASSIGN", "工单已分配给:" + assigneeUser.getNickname(), null); + } + + @Override + public void addTrackInfo(Long userId, BpmOAWorkOrderTrackReqVO trackReqVO) { + AdminUserRespDTO userRespDTO = userApi.getUser(userId).getCheckedData(); + createTrackRecord(trackReqVO.getWorkOrderId(), userId, userRespDTO.getNickname(), + trackReqVO.getOperationType(), trackReqVO.getContent(), null); + } + + @Override + public void updateWorkOrder(BpmOAWorkOrderUpdateReqVO updateReqVO) { + validateWorkOrderExists(updateReqVO.getId()); + BpmOAWorkOrderDO updateData = BpmOAWorkOrderDO.builder() + .id(updateReqVO.getId()) + .status(updateReqVO.getStatus()) + .expectedTime(updateReqVO.getExpectedTime()) + .completedTime(updateReqVO.getCompletedTime()) + .resultDescription(updateReqVO.getResultDescription()) + .build(); + workOrderMapper.updateById(updateData); + } + + @Override + public BpmOAWorkOrderDO getWorkOrder(Long id) { + return workOrderMapper.selectById(id); + } + + @Override + public BpmOAWorkOrderRespVO getWorkOrderDetail(Long id) { + BpmOAWorkOrderDO workOrder = validateWorkOrderExists(id); + + // 转换为VO + BpmOAWorkOrderRespVO respVO = convertToRespVO(workOrder); + + // 获取跟踪记录 + List trackList = trackMapper.selectByWorkOrderId(id); + List trackInfoList = trackList.stream() + .map(this::convertToTrackInfo) + .collect(Collectors.toList()); + respVO.setTrackInfo(trackInfoList); + + return respVO; + } + + @Override + public BpmOAWorkOrderDO getWorkOrderByProcessInstanceId(String processInstanceId) { + return workOrderMapper.selectOne(BpmOAWorkOrderDO::getProcessInstanceId, processInstanceId); + } + + @Override + public PageResult getWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) { + PageResult pageResult = workOrderMapper.selectPage(loginUserId, pageVO); + return convertToPageResult(pageResult); + } + + @Override + public PageResult getMyWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) { + PageResult pageResult = workOrderMapper.selectMyPage(loginUserId, pageVO); + return convertToPageResult(pageResult); + } + + @Override + public PageResult getAssignedWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) { + PageResult pageResult = workOrderMapper.selectAssignedPage(loginUserId, pageVO); + return convertToPageResult(pageResult); + } + + @Override + public Long getMyAssignedWorkOrderCount(Long userId) { + return workOrderMapper.selectMyAssignedCount(userId); + } + + /** + * 创建跟踪记录 + */ + private void createTrackRecord(Long workOrderId, Long operatorId, String operatorName, String operationType, String content, String attachments) { + BpmOAWorkOrderTrackDO track = BpmOAWorkOrderTrackDO.builder() + .workOrderId(workOrderId) + .operatorId(operatorId) + .operatorName(operatorName) + .operationType(operationType) + .content(content) + .attachments(attachments) + .build(); + trackMapper.insert(track); + } + + /** + * 自动分配工单责任人 + */ + private void autoAssignWorkOrder(BpmOAWorkOrderDO workOrder) { + // 根据工单类型查询分配规则 + List rules = assignRuleMapper.selectRulesByType(workOrder.getType()); + + if (!rules.isEmpty()) { + // 选择第一个匹配的规则(按优先级排序) + BpmOAWorkOrderAssignRuleDO rule = rules.get(0); + workOrder.setAssigneeUserId(rule.getAssigneeUserId()); + workOrder.setAssigneeDeptId(rule.getDeptId()); + workOrder.setStatus(2); // 2-处理中 + } + // 如果没有匹配的规则,保持待分配状态 + } + + /** + * 校验工单是否存在 + */ + private BpmOAWorkOrderDO validateWorkOrderExists(Long id) { + BpmOAWorkOrderDO workOrder = workOrderMapper.selectById(id); + if (workOrder == null) { + throw exception(OA_WORK_TASK_NOT_EXISTS); // 暂时复用现有错误码 + } + return workOrder; + } + + /** + * 上传BPM文件流程实例ID + * 重写父类方法,使用父类的实现 + */ + @Override + public void uploadBpmFileProcessInstanceId(String processInstanceId, List fileItems) { + super.uploadBpmFileProcessInstanceId(processInstanceId, fileItems); + } + + /** + * 转换DO为RespVO + */ + private BpmOAWorkOrderRespVO convertToRespVO(BpmOAWorkOrderDO workOrder) { + if (workOrder == null) { + return null; + } + + BpmOAWorkOrderRespVO respVO = new BpmOAWorkOrderRespVO(); + respVO.setId(workOrder.getId()); + respVO.setTitle(workOrder.getTitle()); + respVO.setType(workOrder.getType()); + respVO.setLevel(workOrder.getLevel()); + respVO.setContent(workOrder.getContent()); + respVO.setFromUserId(workOrder.getFromUserId()); + respVO.setFromDeptId(workOrder.getFromDeptId()); + respVO.setAssigneeUserId(workOrder.getAssigneeUserId()); + respVO.setAssigneeDeptId(workOrder.getAssigneeDeptId()); + respVO.setStatus(workOrder.getStatus()); + respVO.setExpectedTime(workOrder.getExpectedTime()); + respVO.setCompletedTime(workOrder.getCompletedTime()); + respVO.setResultDescription(workOrder.getResultDescription()); + respVO.setResult(workOrder.getResult()); + respVO.setProcessInstanceId(workOrder.getProcessInstanceId()); + respVO.setCreateTime(workOrder.getCreateTime()); + respVO.setUpdateTime(workOrder.getUpdateTime()); + + // 设置类型名称 + respVO.setTypeName(getWorkOrderTypeName(workOrder.getType())); + + // 设置优先级名称 + respVO.setLevelName(getWorkOrderLevelName(workOrder.getLevel())); + + // 设置状态名称 + respVO.setStatusName(getWorkOrderStatusName(workOrder.getStatus())); + + // 获取用户和部门名称 + if (workOrder.getFromUserId() != null) { + AdminUserRespDTO fromUser = userApi.getUser(workOrder.getFromUserId()).getCheckedData(); + respVO.setFromUserName(fromUser.getNickname()); + } + + if (workOrder.getAssigneeUserId() != null) { + AdminUserRespDTO assigneeUser = userApi.getUser(workOrder.getAssigneeUserId()).getCheckedData(); + respVO.setAssigneeUserName(assigneeUser.getNickname()); + } + + if (workOrder.getFromDeptId() != null) { + DeptRespDTO fromDept = deptApi.getDept(workOrder.getFromDeptId()).getCheckedData(); + respVO.setFromDeptName(fromDept.getName()); + } + + if (workOrder.getAssigneeDeptId() != null) { + DeptRespDTO assigneeDept = deptApi.getDept(workOrder.getAssigneeDeptId()).getCheckedData(); + respVO.setAssigneeDeptName(assigneeDept.getName()); + } + + return respVO; + } + + /** + * 转换跟踪记录DO为TrackInfo + */ + private BpmOAWorkOrderTrackInfo convertToTrackInfo(BpmOAWorkOrderTrackDO trackDO) { + if (trackDO == null) { + return null; + } + + BpmOAWorkOrderTrackInfo trackInfo = new BpmOAWorkOrderTrackInfo(); + trackInfo.setTrackId(String.valueOf(trackDO.getId())); + trackInfo.setOperatorId(trackDO.getOperatorId()); + trackInfo.setOperatorName(trackDO.getOperatorName()); + trackInfo.setContent(trackDO.getContent()); + trackInfo.setOperationType(trackDO.getOperationType()); + trackInfo.setTrackTime(trackDO.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + + return trackInfo; + } + + /** + * 转换分页结果 + */ + private PageResult convertToPageResult(PageResult pageResult) { + if (pageResult == null || pageResult.getList() == null) { + return new PageResult<>(); + } + + List respList = pageResult.getList().stream() + .map(this::convertToRespVO) + .collect(Collectors.toList()); + + return new PageResult<>(respList, pageResult.getTotal()); + } + + /** + * 获取工单类型名称 + */ + private String getWorkOrderTypeName(String type) { + switch (type) { + case "it_support": + return "IT支持"; + case "equipment_repair": + return "设备维修"; + case "system_issue": + return "系统问题"; + case "permission_request": + return "权限申请"; + case "other": + return "其他"; + default: + return type; + } + } + + /** + * 获取工单优先级名称 + */ + private String getWorkOrderLevelName(Integer level) { + if (level == null) { + return ""; + } + switch (level) { + case 1: + return "低"; + case 2: + return "中"; + case 3: + return "高"; + case 4: + return "紧急"; + default: + return String.valueOf(level); + } + } + + /** + * 获取工单状态名称 + */ + private String getWorkOrderStatusName(Integer status) { + if (status == null) { + return ""; + } + switch (status) { + case 1: + return "待分配"; + case 2: + return "处理中"; + case 3: + return "已完成"; + case 4: + return "已取消"; + case 5: + return "已关闭"; + default: + return String.valueOf(status); + } + } + +}