feat(项目需求): 开发项目需求的富文本和附件功能。

This commit is contained in:
dk
2026-05-13 22:55:31 +08:00
parent e1db030c37
commit 3946c0a0aa
12 changed files with 170 additions and 58 deletions

View File

@@ -1,5 +1,6 @@
package com.njcn.rdms.module.project.controller.admin.product.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -37,13 +38,13 @@ public class ProductRequirementRespVO {
@Schema(description = "需求分类名称", example = "功能需求")
private String categoryName;
@Schema(description = "需求来源类型manual 表示手工新增work_order 表示工单流转", requiredMode = Schema.RequiredMode.REQUIRED, example = "manual")
@Schema(description = "需求来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "manual")
private String sourceType;
@Schema(description = "来源业务ID", example = "1024")
private Long sourceBizId;
@Schema(description = "优先级0低、1中、2高、3紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "优先级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer priority;
@Schema(description = "优先级名称", example = "")
@@ -88,10 +89,13 @@ public class ProductRequirementRespVO {
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime updateTime;
@Schema(description = "附件列表")
private List<AttachmentItem> attachments;
@Schema(description = "子需求列表,树形结构")
private List<ProductRequirementRespVO> children;
@Schema(description = "是否为终态,已拒绝、已取消、已关闭都算终态", example = "false")
@Schema(description = "是否为终态", example = "false")
private Boolean terminal;
}

View File

@@ -1,11 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.product.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 管理后台 - 产品需求保存 Request VO
*/
@@ -29,7 +33,7 @@ public class ProductRequirementSaveReqVO {
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@NotBlank(message = "需求标题不能为空")
@Size(max = 200, message = "需求标题长度不能超过 200 个字符")
@Size(max = 200, message = "需求标题长度不能超过200个字符")
private String title;
@Schema(description = "需求描述,支持富文本", example = "<p>详细描述需求内容</p>")
@@ -37,7 +41,7 @@ public class ProductRequirementSaveReqVO {
@Schema(description = "需求分类字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "function")
@NotBlank(message = "需求分类不能为空")
@Size(max = 64, message = "需求分类长度不能超过 64 个字符")
@Size(max = 64, message = "需求分类长度不能超过64个字符")
private String category;
@Schema(description = "优先级0低、1中、2高、3紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -67,4 +71,8 @@ public class ProductRequirementSaveReqVO {
@Schema(description = "排序值,越小越靠前", example = "0")
private Integer sort;
@Schema(description = "附件列表")
@Valid
private List<AttachmentItem> attachments;
}

View File

@@ -1,11 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.product.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 管理后台 - 产品需求拆分 Request VO
*/
@@ -30,7 +34,7 @@ public class ProductRequirementSplitReqVO {
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@NotBlank(message = "需求标题不能为空")
@Size(max = 200, message = "需求标题长度不能超过 200 个字符")
@Size(max = 200, message = "需求标题长度不能超过200个字符")
private String title;
@Schema(description = "需求描述,支持富文本", example = "<p>详细描述需求内容</p>")
@@ -38,7 +42,7 @@ public class ProductRequirementSplitReqVO {
@Schema(description = "需求分类字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "function")
@NotBlank(message = "需求分类不能为空")
@Size(max = 64, message = "需求分类长度不能超过 64 个字符")
@Size(max = 64, message = "需求分类长度不能超过64个字符")
private String category;
@Schema(description = "优先级0低、1中、2高、3紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -68,4 +72,8 @@ public class ProductRequirementSplitReqVO {
@Schema(description = "排序值,越小越靠前", example = "0")
private Integer sort;
@Schema(description = "附件列表")
@Valid
private List<AttachmentItem> attachments;
}

View File

@@ -1,11 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.product.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 管理后台 - 产品需求编辑 Request VO
*/
@@ -30,7 +34,7 @@ public class ProductRequirementUpdateReqVO {
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@NotBlank(message = "需求标题不能为空")
@Size(max = 200, message = "需求标题长度不能超过 200 个字符")
@Size(max = 200, message = "需求标题长度不能超过200个字符")
private String title;
@Schema(description = "需求描述,支持富文本", example = "<p>详细描述需求内容</p>")
@@ -38,7 +42,7 @@ public class ProductRequirementUpdateReqVO {
@Schema(description = "需求分类字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "function")
@NotBlank(message = "需求分类不能为空")
@Size(max = 64, message = "需求分类长度不能超过 64 个字符")
@Size(max = 64, message = "需求分类长度不能超过64个字符")
private String category;
@Schema(description = "优先级0低、1中、2高、3紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -68,4 +72,8 @@ public class ProductRequirementUpdateReqVO {
@Schema(description = "排序值,越小越靠前", example = "0")
private Integer sort;
@Schema(description = "附件列表")
@Valid
private List<AttachmentItem> attachments;
}

View File

@@ -1,5 +1,6 @@
package com.njcn.rdms.module.project.controller.admin.project.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -13,19 +14,19 @@ import java.util.List;
@Data
public class ProjectRequirementRespVO {
@Schema(description = "需求 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "需求ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "父需求 ID0 表示顶级需求", example = "0")
@Schema(description = "父需求ID0 表示顶级需求", example = "0")
private Long parentId;
@Schema(description = "所属项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "所属项目ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long projectId;
@Schema(description = "所属模块 ID", example = "1024")
@Schema(description = "所属模块ID", example = "1024")
private Long moduleId;
@Schema(description = "是否需要评审0 不需要1 需要", example = "0")
@Schema(description = "是否需要评审0不需要1需要", example = "0")
private Integer reviewRequired;
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@@ -43,7 +44,7 @@ public class ProjectRequirementRespVO {
@Schema(description = "需求来源类型", example = "manual")
private String sourceType;
@Schema(description = "来源业务 ID", example = "1024")
@Schema(description = "来源业务ID", example = "1024")
private Long sourceBizId;
@Schema(description = "优先级", example = "1")
@@ -61,19 +62,19 @@ public class ProjectRequirementRespVO {
@Schema(description = "最近一次状态动作原因", example = "评审通过")
private String lastStatusReason;
@Schema(description = "提出人用户 ID", example = "1024")
@Schema(description = "提出人用户ID", example = "1024")
private Long proposerId;
@Schema(description = "提出人昵称", example = "张三")
@Schema(description = "提出人姓名", example = "张三")
private String proposerNickname;
@Schema(description = "所需工时", example = "8")
private Double workHours;
@Schema(description = "当前处理人用户 ID", example = "1024")
@Schema(description = "当前处理人用户ID", example = "1024")
private Long currentHandlerUserId;
@Schema(description = "当前处理人昵称", example = "李四")
@Schema(description = "当前处理人姓名", example = "李四")
private String currentHandlerUserNickname;
@Schema(description = "排序值", example = "0")
@@ -85,6 +86,9 @@ public class ProjectRequirementRespVO {
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime updateTime;
@Schema(description = "附件列表")
private List<AttachmentItem> attachments;
@Schema(description = "子需求列表,树形结构")
private List<ProjectRequirementRespVO> children;

View File

@@ -1,11 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.project.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 管理后台 - 项目需求保存 Request VO
*/
@@ -13,23 +17,23 @@ import lombok.Data;
@Data
public class ProjectRequirementSaveReqVO {
@Schema(description = "需求 ID", example = "1024")
@Schema(description = "需求ID", example = "1024")
private Long id;
@Schema(description = "所属项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "项目 ID 不能为空")
@Schema(description = "所属项目ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "项目ID不能为空")
private Long projectId;
@Schema(description = "所属模块 ID为空时归入全部需求模块", example = "1024")
@Schema(description = "所属模块ID为空时归入全部需求模块", example = "1024")
private Long moduleId;
@Schema(description = "是否需要评审0 不需要1 需要", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@Schema(description = "是否需要评审0不需要1需要", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "是否需要评审不能为空")
private Integer reviewRequired;
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@NotBlank(message = "需求标题不能为空")
@Size(max = 200, message = "需求标题长度不能超过 200 个字符")
@Size(max = 200, message = "需求标题长度不能超过200个字符")
private String title;
@Schema(description = "需求描述,支持富文本", example = "<p>详细描述需求内容</p>")
@@ -37,31 +41,35 @@ public class ProjectRequirementSaveReqVO {
@Schema(description = "需求分类字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "function")
@NotBlank(message = "需求分类不能为空")
@Size(max = 64, message = "需求分类长度不能超过 64 个字符")
@Size(max = 64, message = "需求分类长度不能超过64个字符")
private String category;
@Schema(description = "优先级0 低、1 中、2 高、3 紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "优先级0低、1中、2高、3紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "优先级不能为空")
private Integer priority;
@Schema(description = "提出人用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "提出人用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "提出人不能为空")
private Long proposerId;
@Schema(description = "提出人昵称", example = "张三")
@Schema(description = "提出人姓名", example = "张三")
private String proposerNickname;
@Schema(description = "所需工时", example = "8")
@NotNull(message = "所需工时不能为空")
private Double workHours;
@Schema(description = "当前处理人用户 ID", example = "1024")
@Schema(description = "当前处理人用户ID", example = "1024")
private Long currentHandlerUserId;
@Schema(description = "当前处理人昵称", example = "李四")
@Schema(description = "当前处理人姓名", example = "李四")
private String currentHandlerUserNickname;
@Schema(description = "排序值,越小越靠前", example = "0")
private Integer sort;
@Schema(description = "附件列表")
@Valid
private List<AttachmentItem> attachments;
}

View File

@@ -1,11 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.project.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 管理后台 - 项目需求拆分 Request VO
*/
@@ -13,24 +17,24 @@ import lombok.Data;
@Data
public class ProjectRequirementSplitReqVO {
@Schema(description = "父需求 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "父需求 ID 不能为空")
@Schema(description = "父需求ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "父需求ID不能为空")
private Long parentId;
@Schema(description = "所属项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "项目 ID 不能为空")
@Schema(description = "所属项目ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "项目ID不能为空")
private Long projectId;
@Schema(description = "所属模块 ID为空时继承父需求模块", example = "1024")
@Schema(description = "所属模块ID为空时继承父需求模块", example = "1024")
private Long moduleId;
@Schema(description = "是否需要评审0 不需要1 需要", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@Schema(description = "是否需要评审0不需要1需要", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "是否需要评审不能为空")
private Integer reviewRequired;
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@NotBlank(message = "需求标题不能为空")
@Size(max = 200, message = "需求标题长度不能超过 200 个字符")
@Size(max = 200, message = "需求标题长度不能超过200个字符")
private String title;
@Schema(description = "需求描述,支持富文本", example = "<p>详细描述需求内容</p>")
@@ -38,31 +42,35 @@ public class ProjectRequirementSplitReqVO {
@Schema(description = "需求分类字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "function")
@NotBlank(message = "需求分类不能为空")
@Size(max = 64, message = "需求分类长度不能超过 64 个字符")
@Size(max = 64, message = "需求分类长度不能超过64个字符")
private String category;
@Schema(description = "优先级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "优先级不能为空")
private Integer priority;
@Schema(description = "提出人用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "提出人用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "提出人不能为空")
private Long proposerId;
@Schema(description = "提出人昵称", example = "张三")
@Schema(description = "提出人姓名", example = "张三")
private String proposerNickname;
@Schema(description = "所需工时", example = "8")
@NotNull(message = "所需工时不能为空")
private Double workHours;
@Schema(description = "当前处理人用户 ID", example = "1024")
@Schema(description = "当前处理人用户ID", example = "1024")
private Long currentHandlerUserId;
@Schema(description = "当前处理人昵称", example = "李四")
@Schema(description = "当前处理人姓名", example = "李四")
private String currentHandlerUserNickname;
@Schema(description = "排序值,越小越靠前", example = "0")
private Integer sort;
@Schema(description = "附件列表")
@Valid
private List<AttachmentItem> attachments;
}

View File

@@ -1,11 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.project.vo.requirement;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 管理后台 - 项目需求编辑 Request VO
*/
@@ -13,24 +17,24 @@ import lombok.Data;
@Data
public class ProjectRequirementUpdateReqVO {
@Schema(description = "需求 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "需求 ID 不能为空")
@Schema(description = "需求ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "需求ID不能为空")
private Long id;
@Schema(description = "所属项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "项目 ID 不能为空")
@Schema(description = "所属项目ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "项目ID不能为空")
private Long projectId;
@Schema(description = "所属模块 ID为空时归入全部需求模块", example = "1024")
@Schema(description = "所属模块ID为空时归入全部需求模块", example = "1024")
private Long moduleId;
@Schema(description = "是否需要评审0 不需要1 需要", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@Schema(description = "是否需要评审0不需要1需要", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "是否需要评审不能为空")
private Integer reviewRequired;
@Schema(description = "需求标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "支持需求模块化管理")
@NotBlank(message = "需求标题不能为空")
@Size(max = 200, message = "需求标题长度不能超过 200 个字符")
@Size(max = 200, message = "需求标题长度不能超过200个字符")
private String title;
@Schema(description = "需求描述,支持富文本", example = "<p>详细描述需求内容</p>")
@@ -38,31 +42,35 @@ public class ProjectRequirementUpdateReqVO {
@Schema(description = "需求分类字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "function")
@NotBlank(message = "需求分类不能为空")
@Size(max = 64, message = "需求分类长度不能超过 64 个字符")
@Size(max = 64, message = "需求分类长度不能超过64个字符")
private String category;
@Schema(description = "优先级0 低、1 中、2 高、3 紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "优先级0低、1中、2高、3紧急", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "优先级不能为空")
private Integer priority;
@Schema(description = "提出人用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Schema(description = "提出人用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "提出人不能为空")
private Long proposerId;
@Schema(description = "提出人昵称", example = "张三")
@Schema(description = "提出人姓名", example = "张三")
private String proposerNickname;
@Schema(description = "所需工时", example = "8")
@NotNull(message = "所需工时不能为空")
private Double workHours;
@Schema(description = "当前处理人用户 ID", example = "1024")
@Schema(description = "当前处理人用户ID", example = "1024")
private Long currentHandlerUserId;
@Schema(description = "当前处理人昵称", example = "李四")
@Schema(description = "当前处理人姓名", example = "李四")
private String currentHandlerUserNickname;
@Schema(description = "排序值,越小越靠前", example = "0")
private Integer sort;
@Schema(description = "附件列表")
@Valid
private List<AttachmentItem> attachments;
}

View File

@@ -1,15 +1,20 @@
package com.njcn.rdms.module.project.dal.dataobject.product;
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 com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 产品需求主表
*/
@TableName("rdms_product_requirement")
@TableName(value = "rdms_product_requirement", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class ProductRequirementDO extends BaseDO {
@@ -95,5 +100,10 @@ public class ProductRequirementDO extends BaseDO {
* 排序值,越小越靠前
*/
private Integer sort;
/**
* 闄勪欢鍒楄〃锛圝SON锛夈€傚厓绱?{@link AttachmentItem}锛歩d / url / name / size / contentType銆?
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<AttachmentItem> attachments;
}

View File

@@ -1,15 +1,20 @@
package com.njcn.rdms.module.project.dal.dataobject.project;
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 com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 项目需求主表
*/
@TableName("rdms_project_requirement")
@TableName(value = "rdms_project_requirement", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectRequirementDO extends BaseDO {
@@ -95,5 +100,10 @@ public class ProjectRequirementDO extends BaseDO {
* 排序值
*/
private Integer sort;
/**
* 闄勪欢鍒楄〃锛圝SON锛夈€傚厓绱?{@link AttachmentItem}锛歩d / url / name / size / contentType銆?
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<AttachmentItem> attachments;
}

View File

@@ -26,6 +26,8 @@ import com.njcn.rdms.module.project.dal.mysql.project.ProjectRequirementModuleMa
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
import com.njcn.rdms.module.project.framework.attachment.AttachmentFileIdResolver;
import com.njcn.rdms.module.project.framework.attachment.AttachmentValidator;
import com.njcn.rdms.module.project.framework.security.annotation.CheckObjectPermission;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -108,6 +110,8 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
private ProjectRequirementModuleMapper projectRequirementModuleMapper;
@Resource
private UserObjectRoleMapper userObjectRoleMapper;
@Resource
private AttachmentFileIdResolver attachmentFileIdResolver;
// ========== 需求增删改查 ==========
@@ -120,6 +124,8 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
Long moduleId = resolveModuleId(createReqVO.getModuleId(), createReqVO.getProductId());
// 校验模块是否属于当前产品
validateModuleBelongsToProduct(moduleId, createReqVO.getProductId());
AttachmentValidator.validate(createReqVO.getAttachments());
attachmentFileIdResolver.resolve(createReqVO.getAttachments());
ProductRequirementDO requirement = new ProductRequirementDO();
requirement.setProductId(createReqVO.getProductId());
@@ -142,6 +148,7 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
requirement.setCurrentHandlerUserNickname(normalizeNullableText(createReqVO.getCurrentHandlerUserNickname()));
requirement.setImplementProjectId(createReqVO.getImplementProjectId());
requirement.setSort(createReqVO.getSort() != null ? createReqVO.getSort() : 0);
requirement.setAttachments(createReqVO.getAttachments());
requirementMapper.insert(requirement);
// 写入业务审计日志
@@ -162,6 +169,8 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
Long moduleId = resolveModuleId(updateReqVO.getModuleId(), updateReqVO.getProductId());
// 校验模块是否属于当前产品
validateModuleBelongsToProduct(moduleId, updateReqVO.getProductId());
AttachmentValidator.validate(updateReqVO.getAttachments());
attachmentFileIdResolver.resolve(updateReqVO.getAttachments());
ProductRequirementDO before = cloneRequirement(requirement);
String fromStatus = requirement.getStatusCode();
@@ -178,6 +187,7 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
requirement.setCurrentHandlerUserNickname(normalizeNullableText(updateReqVO.getCurrentHandlerUserNickname()));
requirement.setImplementProjectId(updateReqVO.getImplementProjectId());
requirement.setSort(updateReqVO.getSort() != null ? updateReqVO.getSort() : 0);
requirement.setAttachments(updateReqVO.getAttachments());
requirementMapper.updateById(requirement);
writeBizAuditLog(requirement, ACTION_UPDATE, fromStatus, requirement.getStatusCode(),
@@ -582,6 +592,8 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
validateRequirementNotDispatched(parentRequirement);
// 校验父需求状态是否允许拆分(只能是待分流或实施中)
validateParentAllowSplit(parentRequirement);
AttachmentValidator.validate(reqVO.getAttachments());
attachmentFileIdResolver.resolve(reqVO.getAttachments());
// 创建子需求
ProductRequirementDO childRequirement = new ProductRequirementDO();
@@ -606,6 +618,7 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
childRequirement.setCurrentHandlerUserNickname(normalizeNullableText(reqVO.getCurrentHandlerUserNickname()));
childRequirement.setImplementProjectId(reqVO.getImplementProjectId());
childRequirement.setSort(reqVO.getSort() != null ? reqVO.getSort() : 0);
childRequirement.setAttachments(reqVO.getAttachments());
requirementMapper.insert(childRequirement);
// 父需求状态从待分流变为实施中
@@ -1257,6 +1270,7 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
target.setCurrentHandlerUserNickname(source.getCurrentHandlerUserNickname());
target.setImplementProjectId(source.getImplementProjectId());
target.setSort(source.getSort());
target.setAttachments(source.getAttachments());
return target;
}
@@ -1304,6 +1318,8 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
valueOf(after, ProductRequirementDO::getImplementProjectId));
appendFieldChange(fieldChanges, "sort", valueOf(before, ProductRequirementDO::getSort),
valueOf(after, ProductRequirementDO::getSort));
appendFieldChange(fieldChanges, "attachments", valueOf(before, ProductRequirementDO::getAttachments),
valueOf(after, ProductRequirementDO::getAttachments));
return fieldChanges.isEmpty() ? null : JsonUtils.toJsonString(fieldChanges);
}
@@ -1384,6 +1400,7 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
newRequirement.setCurrentHandlerUserId(productRequirement.getCurrentHandlerUserId());
newRequirement.setCurrentHandlerUserNickname(productRequirement.getCurrentHandlerUserNickname());
newRequirement.setWorkHours(productRequirement.getWorkHours());
newRequirement.setAttachments(productRequirement.getAttachments());
newRequirement.setCreator(productRequirement.getCreator());
newRequirement.setCreateTime(productRequirement.getCreateTime());

View File

@@ -36,6 +36,8 @@ import com.njcn.rdms.module.project.dal.mysql.project.ProjectRequirementStatusLo
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
import com.njcn.rdms.module.project.framework.attachment.AttachmentFileIdResolver;
import com.njcn.rdms.module.project.framework.attachment.AttachmentValidator;
import com.njcn.rdms.module.project.framework.security.annotation.CheckObjectPermission;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -122,6 +124,8 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
private ObjectStatusTransitionMapper statusTransitionMapper;
@Resource
private ObjectStatusModelMapper statusModelMapper;
@Resource
private AttachmentFileIdResolver attachmentFileIdResolver;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -130,6 +134,8 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
public Long createRequirement(ProjectRequirementSaveReqVO createReqVO) {
Long moduleId = resolveModuleId(createReqVO.getModuleId(), createReqVO.getProjectId());
validateModuleBelongsToProject(moduleId, createReqVO.getProjectId());
AttachmentValidator.validate(createReqVO.getAttachments());
attachmentFileIdResolver.resolve(createReqVO.getAttachments());
ProjectRequirementDO requirement = new ProjectRequirementDO();
requirement.setProjectId(createReqVO.getProjectId());
@@ -150,6 +156,7 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
requirement.setCurrentHandlerUserId(createReqVO.getCurrentHandlerUserId());
requirement.setCurrentHandlerUserNickname(normalizeNullableText(createReqVO.getCurrentHandlerUserNickname()));
requirement.setSort(createReqVO.getSort() != null ? createReqVO.getSort() : 0);
requirement.setAttachments(createReqVO.getAttachments());
requirementMapper.insert(requirement);
writeBizAuditLog(requirement, ACTION_CREATE, null, initialStatus,
@@ -168,6 +175,8 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
Long moduleId = resolveModuleId(updateReqVO.getModuleId(), updateReqVO.getProjectId());
validateModuleBelongsToProject(moduleId, updateReqVO.getProjectId());
AttachmentValidator.validate(updateReqVO.getAttachments());
attachmentFileIdResolver.resolve(updateReqVO.getAttachments());
ProjectRequirementDO before = cloneRequirement(requirement);
String fromStatus = requirement.getStatusCode();
@@ -183,6 +192,7 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
requirement.setCurrentHandlerUserId(updateReqVO.getCurrentHandlerUserId());
requirement.setCurrentHandlerUserNickname(normalizeNullableText(updateReqVO.getCurrentHandlerUserNickname()));
requirement.setSort(updateReqVO.getSort() != null ? updateReqVO.getSort() : 0);
requirement.setAttachments(updateReqVO.getAttachments());
requirementMapper.updateById(requirement);
writeBizAuditLog(requirement, ACTION_UPDATE, fromStatus, requirement.getStatusCode(),
@@ -346,6 +356,8 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
ProjectRequirementDO parentRequirement = validateRequirementExists(reqVO.getParentId());
validateRequirementBelongsToProject(parentRequirement, reqVO.getProjectId());
validateParentAllowSplit(parentRequirement);
AttachmentValidator.validate(reqVO.getAttachments());
attachmentFileIdResolver.resolve(reqVO.getAttachments());
Long moduleId = reqVO.getModuleId() != null ? reqVO.getModuleId() : parentRequirement.getModuleId();
validateModuleBelongsToProject(moduleId, reqVO.getProjectId());
@@ -371,6 +383,7 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
childRequirement.setCurrentHandlerUserId(reqVO.getCurrentHandlerUserId());
childRequirement.setCurrentHandlerUserNickname(normalizeNullableText(reqVO.getCurrentHandlerUserNickname()));
childRequirement.setSort(reqVO.getSort() != null ? reqVO.getSort() : 0);
childRequirement.setAttachments(reqVO.getAttachments());
requirementMapper.insert(childRequirement);
writeBizAuditLog(childRequirement, ACTION_CREATE, null, initialStatus,
@@ -1110,6 +1123,7 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
target.setCurrentHandlerUserId(source.getCurrentHandlerUserId());
target.setCurrentHandlerUserNickname(source.getCurrentHandlerUserNickname());
target.setSort(source.getSort());
target.setAttachments(source.getAttachments());
return target;
}
@@ -1158,6 +1172,8 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
valueOf(after, ProjectRequirementDO::getCurrentHandlerUserNickname));
appendFieldChange(fieldChanges, "sort", valueOf(before, ProjectRequirementDO::getSort),
valueOf(after, ProjectRequirementDO::getSort));
appendFieldChange(fieldChanges, "attachments", valueOf(before, ProjectRequirementDO::getAttachments),
valueOf(after, ProjectRequirementDO::getAttachments));
return fieldChanges.isEmpty() ? null : JsonUtils.toJsonString(fieldChanges);
}
@@ -1218,6 +1234,7 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
target.setCurrentHandlerUserNickname(source.getCurrentHandlerUserNickname());
target.setImplementProjectId(source.getImplementProjectId());
target.setSort(source.getSort());
target.setAttachments(source.getAttachments());
return target;
}
@@ -1262,6 +1279,8 @@ public class ProjectRequirementServiceImpl implements ProjectRequirementService
valueOf(after, ProductRequirementDO::getImplementProjectId));
appendFieldChange(fieldChanges, "sort", valueOf(before, ProductRequirementDO::getSort),
valueOf(after, ProductRequirementDO::getSort));
appendFieldChange(fieldChanges, "attachments", valueOf(before, ProductRequirementDO::getAttachments),
valueOf(after, ProductRequirementDO::getAttachments));
return fieldChanges.isEmpty() ? null : JsonUtils.toJsonString(fieldChanges);
}