feat(bpm): 新增工单模块设计和数据库结构
- 添加工单模块前端设计文档,详细描述了页面架构、权限设计和API调用流程 - 新增工单模块数据库表结构,包括工单主表、分配规则表和跟踪记录表 - 创建工单类型、状态和优先级的字典数据 - 添加示例分配规则数据
This commit is contained in:
parent
1144d4692a
commit
197605f4d2
@ -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;
|
||||
|
||||
}
|
@ -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<Long> 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<PageResult<BpmOAWorkOrderRespVO>> 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<PageResult<BpmOAWorkOrderRespVO>> 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<PageResult<BpmOAWorkOrderRespVO>> 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<BpmOAWorkOrderRespVO> getWorkOrder(@PathVariable("id") Long id) {
|
||||
return success(workOrderService.getWorkOrderDetail(id));
|
||||
}
|
||||
|
||||
@PostMapping("/track")
|
||||
@Operation(summary = "添加工单跟踪记录")
|
||||
@PreAuthorize("@ss.hasPermission('bpm:oa-work-order:update')")
|
||||
public CommonResult<Boolean> 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<Boolean> updateWorkOrder(@Valid @RequestBody BpmOAWorkOrderUpdateReqVO updateReqVO) {
|
||||
workOrderService.updateWorkOrder(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/my-assigned-count")
|
||||
@Operation(summary = "获得我的待处理工单数量")
|
||||
@PermitAll
|
||||
public CommonResult<Long> getMyAssignedWorkOrderCount() {
|
||||
return success(workOrderService.getMyAssignedWorkOrderCount(getLoginUserId()));
|
||||
}
|
||||
|
||||
}
|
@ -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<UploadUserFile> fileItems;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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<String> fileItems;
|
||||
|
||||
@Schema(description = "工单跟踪记录")
|
||||
private List<BpmOAWorkOrderTrackInfo> 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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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<UploadUserFile> fileItems;
|
||||
|
||||
/**
|
||||
* 工单跟踪记录信息
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<BpmOAWorkOrderTrackInfo> trackInfo;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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<BpmOAWorkOrderAssignRuleDO> {
|
||||
|
||||
/**
|
||||
* 根据工单类型查询启用的分配规则
|
||||
*/
|
||||
default List<BpmOAWorkOrderAssignRuleDO> selectRulesByType(String workOrderType) {
|
||||
return selectList(new LambdaQueryWrapperX<BpmOAWorkOrderAssignRuleDO>()
|
||||
.eq(BpmOAWorkOrderAssignRuleDO::getWorkOrderType, workOrderType)
|
||||
.eq(BpmOAWorkOrderAssignRuleDO::getStatus, 1)
|
||||
.orderByAsc(BpmOAWorkOrderAssignRuleDO::getPriority));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID查询分配规则
|
||||
*/
|
||||
default List<BpmOAWorkOrderAssignRuleDO> selectRulesByDept(Long deptId) {
|
||||
return selectList(new LambdaQueryWrapperX<BpmOAWorkOrderAssignRuleDO>()
|
||||
.eq(BpmOAWorkOrderAssignRuleDO::getDeptId, deptId)
|
||||
.eq(BpmOAWorkOrderAssignRuleDO::getStatus, 1)
|
||||
.orderByAsc(BpmOAWorkOrderAssignRuleDO::getPriority));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据责任人ID查询分配规则
|
||||
*/
|
||||
default List<BpmOAWorkOrderAssignRuleDO> selectRulesByAssignee(Long assigneeUserId) {
|
||||
return selectList(new LambdaQueryWrapperX<BpmOAWorkOrderAssignRuleDO>()
|
||||
.eq(BpmOAWorkOrderAssignRuleDO::getAssigneeUserId, assigneeUserId)
|
||||
.eq(BpmOAWorkOrderAssignRuleDO::getStatus, 1)
|
||||
.orderByAsc(BpmOAWorkOrderAssignRuleDO::getPriority));
|
||||
}
|
||||
|
||||
}
|
@ -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<BpmOAWorkOrderDO> {
|
||||
|
||||
/**
|
||||
* 工单分页查询
|
||||
*/
|
||||
default PageResult<BpmOAWorkOrderDO> selectPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
|
||||
return selectPage(pageVO, new LambdaQueryWrapperX<BpmOAWorkOrderDO>()
|
||||
.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<BpmOAWorkOrderDO> selectMyPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
|
||||
return selectPage(pageVO, new LambdaQueryWrapperX<BpmOAWorkOrderDO>()
|
||||
.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<BpmOAWorkOrderDO> selectAssignedPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
|
||||
return selectPage(pageVO, new LambdaQueryWrapperX<BpmOAWorkOrderDO>()
|
||||
.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<BpmOAWorkOrderDO>()
|
||||
.eq(BpmOAWorkOrderDO::getAssigneeUserId, userId)
|
||||
.in(BpmOAWorkOrderDO::getStatus, 1, 2)); // 待分配和处理中
|
||||
}
|
||||
|
||||
}
|
@ -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<BpmOAWorkOrderTrackDO> {
|
||||
|
||||
/**
|
||||
* 根据工单ID查询跟踪记录列表
|
||||
*/
|
||||
default List<BpmOAWorkOrderTrackDO> selectByWorkOrderId(Long workOrderId) {
|
||||
return selectList(new LambdaQueryWrapperX<BpmOAWorkOrderTrackDO>()
|
||||
.eq(BpmOAWorkOrderTrackDO::getWorkOrderId, workOrderId)
|
||||
.orderByAsc(BpmOAWorkOrderTrackDO::getCreateTime));
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<BpmOAWorkOrderRespVO> getWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO);
|
||||
|
||||
/**
|
||||
* 获取我发起的工单分页
|
||||
*
|
||||
* @param loginUserId 登录用户ID
|
||||
* @param pageVO 分页请求
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageResult<BpmOAWorkOrderRespVO> getMyWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO);
|
||||
|
||||
/**
|
||||
* 获取分配给我的工单分页
|
||||
*
|
||||
* @param loginUserId 登录用户ID
|
||||
* @param pageVO 分页请求
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageResult<BpmOAWorkOrderRespVO> getAssignedWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO);
|
||||
|
||||
/**
|
||||
* 获取我负责工单的数量
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 工单数量
|
||||
*/
|
||||
Long getMyAssignedWorkOrderCount(Long userId);
|
||||
|
||||
}
|
@ -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<String, Object> 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<UploadUserFile> 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<BpmOAWorkOrderTrackDO> trackList = trackMapper.selectByWorkOrderId(id);
|
||||
List<BpmOAWorkOrderTrackInfo> 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<BpmOAWorkOrderRespVO> getWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
|
||||
PageResult<BpmOAWorkOrderDO> pageResult = workOrderMapper.selectPage(loginUserId, pageVO);
|
||||
return convertToPageResult(pageResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BpmOAWorkOrderRespVO> getMyWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
|
||||
PageResult<BpmOAWorkOrderDO> pageResult = workOrderMapper.selectMyPage(loginUserId, pageVO);
|
||||
return convertToPageResult(pageResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BpmOAWorkOrderRespVO> getAssignedWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
|
||||
PageResult<BpmOAWorkOrderDO> 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<BpmOAWorkOrderAssignRuleDO> 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<UploadUserFile> 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<BpmOAWorkOrderRespVO> convertToPageResult(PageResult<BpmOAWorkOrderDO> pageResult) {
|
||||
if (pageResult == null || pageResult.getList() == null) {
|
||||
return new PageResult<>();
|
||||
}
|
||||
|
||||
List<BpmOAWorkOrderRespVO> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user