From 3946c0a0aad1a17f8f5d96f5fa0f162abd62c190 Mon Sep 17 00:00:00 2001 From: dk <1260500659@qq.com> Date: Wed, 13 May 2026 22:55:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E9=A1=B9=E7=9B=AE=E9=9C=80=E6=B1=82):=20?= =?UTF-8?q?=E5=BC=80=E5=8F=91=E9=A1=B9=E7=9B=AE=E9=9C=80=E6=B1=82=E7=9A=84?= =?UTF-8?q?=E5=AF=8C=E6=96=87=E6=9C=AC=E5=92=8C=E9=99=84=E4=BB=B6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../requirement/ProductRequirementRespVO.java | 10 ++++-- .../ProductRequirementSaveReqVO.java | 12 +++++-- .../ProductRequirementSplitReqVO.java | 12 +++++-- .../ProductRequirementUpdateReqVO.java | 12 +++++-- .../requirement/ProjectRequirementRespVO.java | 24 +++++++------ .../ProjectRequirementSaveReqVO.java | 32 ++++++++++------- .../ProjectRequirementSplitReqVO.java | 32 ++++++++++------- .../ProjectRequirementUpdateReqVO.java | 34 ++++++++++++------- .../product/ProductRequirementDO.java | 12 ++++++- .../project/ProjectRequirementDO.java | 12 ++++++- .../ProductRequirementServiceImpl.java | 17 ++++++++++ .../ProjectRequirementServiceImpl.java | 19 +++++++++++ 12 files changed, 170 insertions(+), 58 deletions(-) diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementRespVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementRespVO.java index 80854e6..e8433ff 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementRespVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementRespVO.java @@ -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 attachments; + @Schema(description = "子需求列表,树形结构") private List children; - @Schema(description = "是否为终态,已拒绝、已取消、已关闭都算终态", example = "false") + @Schema(description = "是否为终态", example = "false") private Boolean terminal; } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSaveReqVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSaveReqVO.java index e626b22..523e42f 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSaveReqVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSaveReqVO.java @@ -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 = "

详细描述需求内容

") @@ -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 attachments; + } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSplitReqVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSplitReqVO.java index cb88c9b..154c9d1 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSplitReqVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementSplitReqVO.java @@ -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 = "

详细描述需求内容

") @@ -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 attachments; + } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementUpdateReqVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementUpdateReqVO.java index 1b7d7b8..a988110 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementUpdateReqVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/product/vo/requirement/ProductRequirementUpdateReqVO.java @@ -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 = "

详细描述需求内容

") @@ -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 attachments; + } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementRespVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementRespVO.java index 586b061..449f6de 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementRespVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementRespVO.java @@ -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 = "父需求 ID,0 表示顶级需求", example = "0") + @Schema(description = "父需求ID,0 表示顶级需求", 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 attachments; + @Schema(description = "子需求列表,树形结构") private List children; diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSaveReqVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSaveReqVO.java index 5651cde..fe2a271 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSaveReqVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSaveReqVO.java @@ -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 = "

详细描述需求内容

") @@ -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 attachments; + } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSplitReqVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSplitReqVO.java index 422f6a1..352348d 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSplitReqVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementSplitReqVO.java @@ -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 = "

详细描述需求内容

") @@ -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 attachments; + } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementUpdateReqVO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementUpdateReqVO.java index 2616212..878c765 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementUpdateReqVO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/controller/admin/project/vo/requirement/ProjectRequirementUpdateReqVO.java @@ -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 = "

详细描述需求内容

") @@ -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 attachments; + } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/product/ProductRequirementDO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/product/ProductRequirementDO.java index 05bf62f..fcf20ae 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/product/ProductRequirementDO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/product/ProductRequirementDO.java @@ -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 attachments; } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/project/ProjectRequirementDO.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/project/ProjectRequirementDO.java index 38d21b0..f29727b 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/project/ProjectRequirementDO.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/dataobject/project/ProjectRequirementDO.java @@ -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 attachments; } diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/product/ProductRequirementServiceImpl.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/product/ProductRequirementServiceImpl.java index 41c7d06..46cc80e 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/product/ProductRequirementServiceImpl.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/product/ProductRequirementServiceImpl.java @@ -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()); diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/project/ProjectRequirementServiceImpl.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/project/ProjectRequirementServiceImpl.java index e6310fb..846a43d 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/project/ProjectRequirementServiceImpl.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/project/ProjectRequirementServiceImpl.java @@ -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); }