diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/project/service/impl/ProjectServiceImpl.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/project/service/impl/ProjectServiceImpl.java index 790ce9e..2ef3b90 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/project/service/impl/ProjectServiceImpl.java +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/project/service/impl/ProjectServiceImpl.java @@ -161,7 +161,7 @@ public class ProjectServiceImpl extends ServiceImpl impl ProjectRequestVo.RequestDescription req = new ProjectRequestVo.RequestDescription(); BeanUtil.copyProperties(detail, req); req.setDays(CommonTimeFormatUtil.calculateDaysBetween(req.getStartTime(), req.getEndTime())); - if (ObjectUtil.isEmpty(req.getParentDetailId())) { + if ("0".equals(req.getParentDetailId())) { requestDescriptions.add(req); } for (StageDetail stageDetail : details) { diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/controller/StageDetailController.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/controller/StageDetailController.java index 3c1e9f9..69c058f 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/controller/StageDetailController.java +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/controller/StageDetailController.java @@ -16,24 +16,22 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; +import org.nl.pmm.modular.stagedetail.entity.vo.TreeStageDetailVo; +import org.nl.pmm.modular.stagedetail.param.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.nl.common.annotation.CommonLog; import org.nl.common.pojo.CommonResult; import org.nl.pmm.modular.stagedetail.entity.StageDetail; -import org.nl.pmm.modular.stagedetail.param.StageDetailAddParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailEditParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailIdParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailPageParam; import org.nl.pmm.modular.stagedetail.service.StageDetailService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import java.util.List; +import java.util.Map; /** * 项目阶段明细控制器 @@ -120,4 +118,24 @@ public class StageDetailController { public CommonResult detail(@Valid StageDetailIdParam stageDetailIdParam) { return CommonResult.data(stageDetailService.detail(stageDetailIdParam)); } + + /** + * 查询基础类型 + * @param detailTreeParam + * @return + */ + @GetMapping("/pmm/stagedetail/loadClass") + public CommonResult> loadClass(StageDetailTreeParam detailTreeParam) { + return CommonResult.data(stageDetailService.loadClass(detailTreeParam)); + } + + /** + * 获取当前层级以及所有父类层级 + * @param detailTreeParam + * @return + */ + @GetMapping("/pmm/stagedetail/superior") + public CommonResult> superior(StageDetailTreeParam detailTreeParam) { + return CommonResult.data(stageDetailService.getSuperior(detailTreeParam)); + } } diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/entity/vo/TreeStageDetailVo.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/entity/vo/TreeStageDetailVo.java new file mode 100644 index 0000000..e3c27e0 --- /dev/null +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/entity/vo/TreeStageDetailVo.java @@ -0,0 +1,43 @@ +package org.nl.pmm.modular.stagedetail.entity.vo; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * + * @author: lyd + * @date: 2026/1/20 + */ +@Data +public class TreeStageDetailVo { + /** 明细id */ + private String detailId; + + /** 阶段id */ + private String stageId; + + /** 父明细id */ + private String parentDetailId; + + /** 序号 */ + private String seq; + + /** 功能模块 */ + private String modelName; + + /** 功能明细 */ + private String modelDetail; + + /** 是否为叶子节点 */ + private Boolean isLeaf; + + /** 子节点 */ + private List children; + +} diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/StageDetailMapper.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/StageDetailMapper.java index aa3e41f..2e6e517 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/StageDetailMapper.java +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/StageDetailMapper.java @@ -14,6 +14,10 @@ package org.nl.pmm.modular.stagedetail.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.nl.pmm.modular.stagedetail.entity.StageDetail; +import org.nl.pmm.modular.stagedetail.entity.vo.TreeStageDetailVo; +import org.nl.pmm.modular.stagedetail.param.StageDetailTreeParam; + +import java.util.List; /** * 项目阶段明细Mapper接口 @@ -22,4 +26,8 @@ import org.nl.pmm.modular.stagedetail.entity.StageDetail; * @date 2025/11/17 20:34 **/ public interface StageDetailMapper extends BaseMapper { + /** + * 树形加载 + */ + List loadClass(StageDetailTreeParam detailTreeParam); } diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/mapping/StageDetailMapper.xml b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/mapping/StageDetailMapper.xml index 914be47..01457c4 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/mapping/StageDetailMapper.xml +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/mapper/mapping/StageDetailMapper.xml @@ -2,4 +2,27 @@ + + \ No newline at end of file diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailAddParam.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailAddParam.java index c744f02..2b5447f 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailAddParam.java +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailAddParam.java @@ -12,13 +12,14 @@ */ package org.nl.pmm.modular.stagedetail.param; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import java.math.BigDecimal; import java.util.Date; /** @@ -71,4 +72,36 @@ public class StageDetailAddParam { @Schema(description = "结束时间") private Date endTime; + /** 创建时间 */ + @Schema(description = "创建时间") + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** 创建人 */ + @Schema(description = "创建人") + @TableField(fill = FieldFill.INSERT) + @Trans(type = TransType.RPC, targetClassName = "org.nl.sys.modular.user.entity.SysUser", fields = "name", alias = "createUser", ref = "createUserName") + private String createUser; + + /** 创建人名称 */ + @Schema(description = "创建人名称") + @TableField(exist = false) + private String createUserName; + + /** 更新时间 */ + @Schema(description = "更新时间") + @TableField(fill = FieldFill.UPDATE) + private Date updateTime; + + /** 更新人 */ + @Schema(description = "更新人") + @TableField(fill = FieldFill.UPDATE) + @Trans(type = TransType.RPC, targetClassName = "org.nl.sys.modular.user.entity.SysUser", fields = "name", alias = "updateUser", ref = "updateUserName") + private String updateUser; + + /** 更新人名称 */ + @Schema(description = "更新人名称") + @TableField(exist = false) + private String updateUserName; + } diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailTreeParam.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailTreeParam.java new file mode 100644 index 0000000..6686679 --- /dev/null +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/param/StageDetailTreeParam.java @@ -0,0 +1,21 @@ +package org.nl.pmm.modular.stagedetail.param; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * + * @author: lyd + * @date: 2026/1/20 + */ +@Data +public class StageDetailTreeParam { + /** 阶段id */ + @Schema(description = "阶段id") + private String stageId; + + /** 父明细id */ + @Schema(description = "父明细id") + private String parentDetailId; + +} diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/StageDetailService.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/StageDetailService.java index 9c4e52a..b1df928 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/StageDetailService.java +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/StageDetailService.java @@ -15,10 +15,8 @@ package org.nl.pmm.modular.stagedetail.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import org.nl.pmm.modular.stagedetail.entity.StageDetail; -import org.nl.pmm.modular.stagedetail.param.StageDetailAddParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailEditParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailIdParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailPageParam; +import org.nl.pmm.modular.stagedetail.entity.vo.TreeStageDetailVo; +import org.nl.pmm.modular.stagedetail.param.*; import java.util.List; @@ -79,4 +77,13 @@ public interface StageDetailService extends IService { StageDetail queryEntity(String id); List getByStageId(String stageId); + + /** + * 获取当前父类的所有下一子集数据 + * @param detailTreeParam + * @return + */ + List loadClass(StageDetailTreeParam detailTreeParam); + + List getSuperior(StageDetailTreeParam detailTreeParam); } diff --git a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/impl/StageDetailServiceImpl.java b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/impl/StageDetailServiceImpl.java index 45f6f00..19a88b5 100644 --- a/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/impl/StageDetailServiceImpl.java +++ b/nl-plugin/nl-plugin-pmm/src/main/java/org/nl/pmm/modular/stagedetail/service/impl/StageDetailServiceImpl.java @@ -20,6 +20,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.nl.pmm.modular.stagedetail.entity.vo.TreeStageDetailVo; +import org.nl.pmm.modular.stagedetail.param.*; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.nl.common.enums.CommonSortOrderEnum; @@ -27,10 +29,6 @@ import org.nl.common.exception.CommonException; import org.nl.common.page.CommonPageRequest; import org.nl.pmm.modular.stagedetail.entity.StageDetail; import org.nl.pmm.modular.stagedetail.mapper.StageDetailMapper; -import org.nl.pmm.modular.stagedetail.param.StageDetailAddParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailEditParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailIdParam; -import org.nl.pmm.modular.stagedetail.param.StageDetailPageParam; import org.nl.pmm.modular.stagedetail.service.StageDetailService; import java.util.List; @@ -100,4 +98,21 @@ public class StageDetailServiceImpl extends ServiceImpl loadClass(StageDetailTreeParam detailTreeParam) { + return this.baseMapper.loadClass(detailTreeParam); + } + + /** + * 获取当前对应父节点的所有子节点,以及所有的父节点数据 + *

例:当前是顶层,则返回所有当前stageId的顶层(parentDetailId), + * 如果当前是第三层,则获取当前节点的所有同父节点的数据以及所有第二层和所有第一层,并且保持上下级关系,子节点放到children字段中。 + * @param detailTreeParam + * @return + */ + @Override + public List getSuperior(StageDetailTreeParam detailTreeParam) { + return List.of(); + } } diff --git a/nl-vue/src/views/pmm/project/request/addRequestDialog.vue b/nl-vue/src/views/pmm/project/request/addRequestDialog.vue new file mode 100644 index 0000000..44b6418 --- /dev/null +++ b/nl-vue/src/views/pmm/project/request/addRequestDialog.vue @@ -0,0 +1,312 @@ + + + + + diff --git a/nl-vue/src/views/pmm/project/request/description.vue b/nl-vue/src/views/pmm/project/request/description.vue index 1f251ca..62cbae7 100644 --- a/nl-vue/src/views/pmm/project/request/description.vue +++ b/nl-vue/src/views/pmm/project/request/description.vue @@ -75,7 +75,7 @@ @@ -183,6 +183,7 @@ + @@ -191,8 +192,10 @@ import { useRoute } from 'vue-router' import projectApi from '@/api/pmm/projectApi' import projectFileApi from '@/api/pmm/projectFileApi' + import stageDetailApi from '@/api/pmm/stageDetailApi' import { Modal, message } from 'ant-design-vue' import StageAddDialog from "@/views/pmm/project/request/stageAddDialog.vue"; + import AddRequestDialog from "@/views/pmm/project/request/addRequestDialog.vue"; import Preview from '@/views/dev/file/preview.vue' import FjUploadForm from "@/views/pmm/project/request/fjUploadForm.vue"; import BatchStageAddDialog from "@/views/pmm/project/request/batchStageAddDialog.vue"; @@ -213,6 +216,7 @@ const plannedHours = ref(0) const formRef = ref() const form2Ref = ref() + const requestFormRef = ref() const previewRef = ref() const uploadFormRef = ref() const previewVisible = ref(false) @@ -360,8 +364,15 @@ const attachmentList = ref([]) .requestDetail({ projectId: projectId.value }) .then((data) => { if (Array.isArray(data)) { - stageList.value = data - plannedHours.value = calculatePlannedHours(data) + const normalized = data.map((stage: any) => { + const descriptions = Array.isArray(stage?.descriptions) ? stage.descriptions : [] + return { + ...stage, + descriptions: descriptions.map((d: any) => ({ ...d, stageId: stage.stageId })) + } + }) + stageList.value = normalized + plannedHours.value = calculatePlannedHours(normalized) } else { stageList.value = [] message.warning('数据格式错误') @@ -549,6 +560,69 @@ watch(projectId, () => { } }) } + + // 创建需求(不携带 parentDetailId) + const openCreateRequest = (stage: any) => { + if (!projectId.value) return + requestFormRef.value?.onOpen?.({ + projectId: projectId.value, + stageId: stage?.stageId, + isTop: true + }) + } + + // 新增同级:带过去 parentDetailId(等同 record.parentDetailId) + const openAddSibling = (record: any) => { + if (!projectId.value) return + const parentDetailId = record?.parentDetailId || '' + requestFormRef.value?.onOpen?.({ + projectId: projectId.value, + stageId: record?.stageId, + isTop: !parentDetailId, + parentDetailId + }) + } + + // 新增子级:把自己的 detailId 作为 parentDetailId + const openAddChild = (record: any) => { + if (!projectId.value) return + requestFormRef.value?.onOpen?.({ + projectId: projectId.value, + stageId: record?.stageId, + isTop: false, + parentDetailId: record?.detailId + }) + } + + // 编辑 + const openEditRequest = (record: any) => { + if (!projectId.value) return + const parentDetailId = record?.parentDetailId || '' + requestFormRef.value?.onOpen?.({ + ...record, + projectId: projectId.value, + isTop: !parentDetailId, + parentDetailId + }) + } + + // 删除 + const deleteRequest = (record: any) => { + if (!record?.detailId) return + Modal.confirm({ + title: '确认删除该需求?', + content: `需求:${record?.modelDetail || record?.modelName || record?.detailId}`, + okText: '确认', + cancelText: '取消', + onOk: () => { + const params = [{ detailId: record.detailId }] + return stageDetailApi.stageDetailDelete(params).then(() => { + message.success('删除成功') + fetchDetail() + }) + } + }) + }