From 8512de3e8e887ad13c941e60fbb9a3b48a43e9b1 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期三, 11 三月 2026 11:44:17 +0800
Subject: [PATCH] feat(projectManagement): 增加项目阶段相关功能及接口支持

---
 src/main/java/com/ruoyi/projectManagement/dto/InfoStageDto.java                           |   92 +++++++++
 src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java |  161 ++++++++++++++++
 src/main/java/com/ruoyi/projectManagement/vo/SaveInfoStageVo.java                         |   28 ++
 src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java      |    9 
 src/main/java/com/ruoyi/projectManagement/dto/PlanStageDto.java                           |    2 
 src/main/java/com/ruoyi/projectManagement/pojo/InfoStage.java                             |  141 ++++++++++++++
 src/main/java/com/ruoyi/projectManagement/vo/InfoStageVo.java                             |   24 ++
 src/main/resources/mapper/projectManagement/InfoMapper.xml                                |    9 
 src/main/java/com/ruoyi/projectManagement/mapper/InfoStageMapper.java                     |   18 +
 src/main/resources/mapper/projectManagement/InfoStageMapper.xml                           |   42 ++++
 src/main/java/com/ruoyi/projectManagement/controller/InfoController.java                  |   24 ++
 src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java                              |    4 
 12 files changed, 552 insertions(+), 2 deletions(-)

diff --git a/src/main/java/com/ruoyi/projectManagement/controller/InfoController.java b/src/main/java/com/ruoyi/projectManagement/controller/InfoController.java
index 85a7070..cb79883 100644
--- a/src/main/java/com/ruoyi/projectManagement/controller/InfoController.java
+++ b/src/main/java/com/ruoyi/projectManagement/controller/InfoController.java
@@ -1,8 +1,11 @@
 package com.ruoyi.projectManagement.controller;
 
 import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.projectManagement.dto.InfoStageDto;
 import com.ruoyi.projectManagement.dto.UpdateStateInfo;
 import com.ruoyi.projectManagement.service.InfoService;
+import com.ruoyi.projectManagement.service.impl.handle.InfoStageHandleService;
+import com.ruoyi.projectManagement.vo.SaveInfoStageVo;
 import com.ruoyi.projectManagement.vo.SaveInfoVo;
 import com.ruoyi.projectManagement.vo.SearchInfoVo;
 import io.swagger.annotations.Api;
@@ -24,6 +27,7 @@
 public class InfoController {
 
     private final InfoService infoService;
+    private final InfoStageHandleService infoStageHandleService;
 
     @PostMapping("/save")
     @ApiOperation("淇濆瓨")
@@ -59,5 +63,25 @@
         return AjaxResult.success(infoService.getInfoById(id));
     }
 
+    @PostMapping("/saveStage")
+    @ApiOperation("淇濆瓨闃舵")
+    public AjaxResult saveStage(@RequestBody @Valid SaveInfoStageVo dto) {
+        infoStageHandleService.save(dto);
+        return AjaxResult.success();
+    }
+
+    @PostMapping("/listStage/{id}")
+    @ApiOperation("鍒楄〃闃舵")
+    public AjaxResult listStage(@PathVariable Long id) {
+        return AjaxResult.success(infoStageHandleService.getListVoByInfoId(id));
+    }
+
+    @PostMapping("/deleteStage/{id}")
+    @ApiOperation("鍒犻櫎闃舵")
+    public AjaxResult deleteStage(@PathVariable Long id) {
+        infoStageHandleService.deleteById(id);
+        return AjaxResult.success();
+    }
+
 
 }
diff --git a/src/main/java/com/ruoyi/projectManagement/dto/InfoStageDto.java b/src/main/java/com/ruoyi/projectManagement/dto/InfoStageDto.java
new file mode 100644
index 0000000..baa8a21
--- /dev/null
+++ b/src/main/java/com/ruoyi/projectManagement/dto/InfoStageDto.java
@@ -0,0 +1,92 @@
+package com.ruoyi.projectManagement.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * @author buhuazhen
+ * @date 2026/3/11
+ * @email 3038525872@qq.com
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class InfoStageDto implements java.io.Serializable {
+
+    private Long id;
+
+    /**
+     * 瀵瑰簲璁″垝鑺傜偣id
+     */
+    @NotNull(message = "瀵瑰簲璁″垝鑺傜偣projectManagementPlanNodeId涓嶈兘涓虹┖")
+    private Long projectManagementPlanNodeId;
+
+    /**
+     * 瀵瑰簲椤圭洰id
+     */
+    @NotNull(message = "瀵瑰簲椤圭洰projectManagementInfoId涓嶈兘涓虹┖")
+    private Long projectManagementInfoId;
+
+    /**
+     * 鎻忚堪
+     */
+    private String description;
+
+    /**
+     * 瀹為檯璐熻矗浜篿d
+     */
+    private Long actuallyLeaderId;
+
+    /**
+     * 瀹為檯璐熻矗浜哄悕绉�
+     */
+    private String actuallyLeaderName;
+
+    /**
+     * 棰勮宸ユ湡
+     */
+    private Integer estimatedDuration;
+
+    /**
+     * 璁″垝寮�濮�
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate planStartTime;
+
+    /**
+     * 杩涘害
+     */
+    private Integer progress;
+
+    /**
+     * 瀹為檯寮�濮嬫椂闂�
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate actualStartTime;
+
+    /**
+     * 瀹為檯缁撴潫鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate actualEndTime;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    private String attachment;
+
+}
diff --git a/src/main/java/com/ruoyi/projectManagement/dto/PlanStageDto.java b/src/main/java/com/ruoyi/projectManagement/dto/PlanStageDto.java
index 45c310a..0fdde1d 100644
--- a/src/main/java/com/ruoyi/projectManagement/dto/PlanStageDto.java
+++ b/src/main/java/com/ruoyi/projectManagement/dto/PlanStageDto.java
@@ -19,4 +19,6 @@
     private Long id;
     private String name;
     private PlanStageEnum planStageEnum;
+    private Integer sort;
+    private Integer estimatedDuration; // 棰勮宸ユ湡
 }
diff --git a/src/main/java/com/ruoyi/projectManagement/mapper/InfoStageMapper.java b/src/main/java/com/ruoyi/projectManagement/mapper/InfoStageMapper.java
new file mode 100644
index 0000000..0568e1f
--- /dev/null
+++ b/src/main/java/com/ruoyi/projectManagement/mapper/InfoStageMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.projectManagement.mapper;
+
+import com.ruoyi.projectManagement.pojo.InfoStage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author buhuazhen
+* @description 閽堝琛ㄣ�恜roject_management_info_stage(椤圭洰闃舵)銆戠殑鏁版嵁搴撴搷浣淢apper
+* @createDate 2026-03-11 10:28:27
+* @Entity com.ruoyi.projectManagement.pojo.InfoStage
+*/
+public interface InfoStageMapper extends BaseMapper<InfoStage> {
+
+}
+
+
+
+
diff --git a/src/main/java/com/ruoyi/projectManagement/pojo/InfoStage.java b/src/main/java/com/ruoyi/projectManagement/pojo/InfoStage.java
new file mode 100644
index 0000000..95b439f
--- /dev/null
+++ b/src/main/java/com/ruoyi/projectManagement/pojo/InfoStage.java
@@ -0,0 +1,141 @@
+package com.ruoyi.projectManagement.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import lombok.Data;
+
+/**
+ * 椤圭洰闃舵
+ * @TableName project_management_info_stage
+ */
+@TableName(value ="project_management_info_stage")
+@Data
+public class InfoStage implements Serializable {
+    /**
+     * 
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 瀵瑰簲璁″垝鑺傜偣id
+     */
+    @TableField(value = "project_management_plan_node_id")
+    private Long projectManagementPlanNodeId;
+
+    /**
+     * 瀵瑰簲椤圭洰id
+     */
+    @TableField(value = "project_management_info_id")
+    private Long projectManagementInfoId;
+
+    /**
+     * 鎻忚堪
+     */
+    @TableField(value = "description")
+    private String description;
+
+    /**
+     * 瀹為檯璐熻矗浜篿d
+     */
+    @TableField(value = "actually_leader_id")
+    private Long actuallyLeaderId;
+
+    /**
+     * 瀹為檯璐熻矗浜哄悕绉�
+     */
+    @TableField(value = "actually_leader_name")
+    private String actuallyLeaderName;
+
+    /**
+     * 棰勮宸ユ湡
+     */
+    @TableField(value = "estimated_duration")
+    private Integer estimatedDuration;
+
+    /**
+     * 璁″垝寮�濮�
+     */
+    @TableField(value = "plan_start_time")
+    private LocalDate planStartTime;
+
+    /**
+     * 璁″垝缁撴潫
+     */
+    @TableField(value = "plan_end_time")
+    private LocalDate planEndTime;
+
+    /**
+     * 杩涘害
+     */
+    @TableField(value = "progress")
+    private Integer progress;
+
+    /**
+     * 瀹為檯寮�濮嬫椂闂�
+     */
+    @TableField(value = "actual_start_time")
+    private LocalDate actualStartTime;
+
+    /**
+     * 瀹為檯缁撴潫鏃堕棿
+     */
+    @TableField(value = "actual_end_time")
+    private LocalDate actualEndTime;
+
+    /**
+     * 闄勪欢
+     */
+    @TableField(value = "attachment")
+    private String attachment;
+
+    /**
+     * 
+     */
+    @TableField(value = "create_time")
+    private LocalDateTime createTime;
+
+    /**
+     * 
+     */
+    @TableField(value = "update_time")
+    private LocalDateTime updateTime;
+
+    /**
+     * 
+     */
+    @TableField(value = "is_delete")
+    private Integer isDelete;
+
+    /**
+     * 
+     */
+    @TableField(value = "create_user")
+    private Long createUser;
+
+    /**
+     * 
+     */
+    @TableField(value = "update_user")
+    private Long updateUser;
+
+    /**
+     * 
+     */
+    @TableField(value = "create_user_name")
+    private String createUserName;
+
+    /**
+     * 
+     */
+    @TableField(value = "update_user_name")
+    private String updateUserName;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java b/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java
index 73a18fe..84715f9 100644
--- a/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java
+++ b/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java
@@ -4,10 +4,12 @@
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.google.common.collect.Lists;
 import com.ruoyi.basic.service.CustomerFollowUpFileService;
 import com.ruoyi.common.enums.PlanStageEnum;
 import com.ruoyi.common.enums.ReviewStatusEnum;
+import com.ruoyi.projectManagement.dto.InfoStageDto;
 import com.ruoyi.projectManagement.dto.PlanStageDto;
 import com.ruoyi.projectManagement.dto.SaveInfoDto;
 import com.ruoyi.projectManagement.mapper.InfoMapper;
@@ -68,6 +70,11 @@
         return info.getId();
     }
 
+    @Transactional
+    public void updateById(@NotNull Info info){
+        infoMapper.updateById(info);
+    }
+
     public SaveInfoDto getInfoById(@NotNull Long id) {
         Info info = infoMapper.selectById(id);
         return convert(info);
@@ -99,7 +106,7 @@
 
     private List<PlanStageDto> getPlanStageList(@NotNull Long planId) {
         List<PlanNode> planNodeByPlanId = planService.getPlanNodeByPlanId(planId);
-        return planNodeByPlanId.stream().map(it -> new PlanStageDto(it.getId(), it.getName(), PlanStageEnum.TO_BEGIN)).collect(Collectors.toList());
+        return planNodeByPlanId.stream().map(it -> new PlanStageDto(it.getId(), it.getName(), PlanStageEnum.TO_BEGIN, it.getSort(), it.getEstimatedDuration())).collect(Collectors.toList());
     }
 
 
diff --git a/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java b/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java
new file mode 100644
index 0000000..dac839d
--- /dev/null
+++ b/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java
@@ -0,0 +1,161 @@
+package com.ruoyi.projectManagement.service.impl.handle;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.ruoyi.basic.service.CustomerFollowUpFileService;
+import com.ruoyi.common.enums.IsDeleteEnum;
+import com.ruoyi.common.enums.PlanStageEnum;
+import com.ruoyi.projectManagement.dto.InfoStageDto;
+import com.ruoyi.projectManagement.dto.PlanStageDto;
+import com.ruoyi.projectManagement.dto.SaveInfoDto;
+import com.ruoyi.projectManagement.mapper.InfoStageMapper;
+import com.ruoyi.projectManagement.pojo.Info;
+import com.ruoyi.projectManagement.pojo.InfoStage;
+import com.ruoyi.projectManagement.vo.InfoStageVo;
+import com.ruoyi.projectManagement.vo.SaveInfoStageVo;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.validation.constraints.NotNull;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author buhuazhen
+ * @date 2026/3/11
+ * @email 3038525872@qq.com
+ */
+@Component
+@RequiredArgsConstructor
+@Transactional(rollbackFor = Exception.class, readOnly = true)
+public class InfoStageHandleService {
+    private final InfoStageMapper infoStageMapper;
+    private final InfoHandleService infoHandleService;
+    private final CustomerFollowUpFileService customerFollowUpFileService;
+    @Autowired
+    @Lazy
+    private InfoStageHandleService infoStageHandleService;
+
+    @Transactional
+    public void save(@NotNull SaveInfoStageVo saveInfoStageVo) {
+        InfoStage infoStage = BeanUtil.copyProperties(saveInfoStageVo, InfoStage.class);
+        // 闄勪欢澶勭悊
+        String attachmentIds = StrUtil.join(",", Optional.ofNullable(saveInfoStageVo.getAttachmentIds()).orElse(Collections.emptyList()));
+        infoStage.setAttachment(attachmentIds);
+
+        if (infoStage.getId() == null) {
+            infoStageMapper.insert(infoStage);
+        } else {
+            infoStageMapper.updateById(infoStage);
+        }
+
+        infoStageHandleService.syncInfoStage(infoStage.getProjectManagementInfoId());
+    }
+
+    /**
+     * 鍚屾椤圭洰闃舵鐘舵��
+     *
+     * @param infoId
+     */
+    @Transactional
+    public void syncInfoStage(@NotNull Long infoId) {
+        SaveInfoDto infoById = infoHandleService.getInfoById(infoId);
+        List<PlanStageDto> planStage = infoById.getPlanStage();
+
+        // 鑾峰彇渚濇棫瀛樺湪鐨勯樁娈典俊鎭�
+        List<InfoStageDto> infoStageNow = getListDtoByInfoId(infoId);
+
+        Map<Long, Integer> maxProgressMap =
+                infoStageNow.stream()
+                        .filter(e -> e.getProjectManagementPlanNodeId() != null)
+                        .collect(Collectors.toMap(
+                                InfoStageDto::getProjectManagementPlanNodeId,
+                                e -> Optional.ofNullable(e.getProgress()).orElse(0),
+                                Integer::max
+                        ));
+        for (PlanStageDto stage : planStage) {
+            int progress = maxProgressMap.getOrDefault(stage.getId(), 0);
+
+            stage.setPlanStageEnum(calcStage(progress));
+        }
+
+        // 杩涜璋冩暣
+        Info info = new Info();
+        info.setId(infoId);
+        info.setPlanStage(planStage);
+        infoHandleService.updateById(info);
+    }
+
+    private PlanStageEnum calcStage(int progress) {
+        if (progress <= 0) {
+            return PlanStageEnum.TO_BEGIN;
+        } else if (progress < 100) {
+            return PlanStageEnum.ON_GOING;
+        }
+        return PlanStageEnum.ENDED;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteById(@NotNull Long id) {
+        InfoStage infoStage = infoStageMapper.selectById(id);
+        if (infoStage == null) {
+            return;
+        }
+        LambdaUpdateWrapper<InfoStage> updateWrapper = new LambdaUpdateWrapper<InfoStage>();
+        updateWrapper.eq(InfoStage::getId, id);
+        updateWrapper.set(InfoStage::getIsDelete, IsDeleteEnum.DELETED.getCode());
+        infoStageMapper.update(null, updateWrapper);
+
+        infoStageHandleService.syncInfoStage(infoStage.getProjectManagementInfoId());
+    }
+
+    public List<InfoStageDto> getListDtoByInfoId(@NotNull Long infoId) {
+        LambdaQueryWrapper<InfoStage> queryWrapper = new LambdaQueryWrapper<InfoStage>();
+        queryWrapper.eq(InfoStage::getProjectManagementInfoId, infoId);
+        queryWrapper.eq(InfoStage::getIsDelete, IsDeleteEnum.NOT_DELETED.getCode());
+        List<InfoStageDto> infoStageDtos = BeanUtil.copyToList(infoStageMapper.selectList(queryWrapper), InfoStageDto.class);
+
+        /*
+         * 杩涜鎺掑簭 鍏堟寜鐓у搴旂殑sort杩涜鎺掑簭锛屽悗鎸夌収鍒涘缓鏃堕棿鎺掑簭
+         * 鍙兘浼氬嚭鐜板悗閮ㄦ儏鍐� 姣斿
+         * 绔嬮」 100%
+         * 绔嬮」 50%   杩欑鎯呭喌锛屽綋鐒朵篃鏀寔淇敼鎿嶄綔
+         */
+        SaveInfoDto infoById = infoHandleService.getInfoById(infoId);
+        List<PlanStageDto> planStage = infoById.getPlanStage();
+
+        // 鏋勫缓 id -> sort 鏄犲皠
+        Map<Long, Integer> stageSortMap = planStage.stream()
+                .collect(Collectors.toMap(
+                        PlanStageDto::getId,
+                        PlanStageDto::getSort
+                ));
+
+        // 鎺掑簭
+        infoStageDtos.sort(
+                Comparator
+                        // 鍏堟寜闃舵鎺掑簭
+                        .comparing((InfoStageDto dto) ->
+                                stageSortMap.getOrDefault(dto.getProjectManagementPlanNodeId(), Integer.MAX_VALUE)
+                        )
+                        // 鍐嶆寜鍒涘缓鏃堕棿鎺掑簭
+                        .thenComparing(InfoStageDto::getCreateTime)
+        );
+        return infoStageDtos;
+    }
+
+    public List<InfoStageVo> getListVoByInfoId(@NotNull Long infoId) {
+        List<InfoStageDto> listByInfoId = getListDtoByInfoId(infoId);
+        List<InfoStageVo> infoStageVos = BeanUtil.copyToList(listByInfoId, InfoStageVo.class);
+        // 澶勭悊闄勪欢
+        customerFollowUpFileService.fillAttachment(infoStageVos, InfoStageVo::getAttachment, InfoStageVo::setAttachmentList);
+        return infoStageVos;
+    }
+
+
+}
diff --git a/src/main/java/com/ruoyi/projectManagement/vo/InfoStageVo.java b/src/main/java/com/ruoyi/projectManagement/vo/InfoStageVo.java
new file mode 100644
index 0000000..8be6a2d
--- /dev/null
+++ b/src/main/java/com/ruoyi/projectManagement/vo/InfoStageVo.java
@@ -0,0 +1,24 @@
+package com.ruoyi.projectManagement.vo;
+
+import com.ruoyi.common.vo.SimpleFileVo;
+import com.ruoyi.projectManagement.dto.InfoStageDto;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author buhuazhen
+ * @date 2026/3/11
+ * @email 3038525872@qq.com
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class InfoStageVo extends InfoStageDto implements java.io.Serializable {
+
+    private List<SimpleFileVo> attachmentList; // 闄勪欢鍒楄〃
+}
diff --git a/src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java b/src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java
index 864dc8e..6ad395f 100644
--- a/src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java
+++ b/src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java
@@ -1,6 +1,7 @@
 package com.ruoyi.projectManagement.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.projectManagement.dto.PlanStageDto;
 import com.ruoyi.projectManagement.dto.SaveInfoDto;
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -10,6 +11,7 @@
 
 import java.io.Serializable;
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * 椤甸潰鍒楄〃淇℃伅
@@ -39,4 +41,6 @@
 
     private String createUserName; // 鍒涘缓浜哄悕绉�
     private String updateUserName; // 鏇存柊浜哄悕绉�
+    // 鍏ㄩ儴闃舵淇℃伅
+    private List<PlanStageDto> planStage;
 }
diff --git a/src/main/java/com/ruoyi/projectManagement/vo/SaveInfoStageVo.java b/src/main/java/com/ruoyi/projectManagement/vo/SaveInfoStageVo.java
new file mode 100644
index 0000000..d19095b
--- /dev/null
+++ b/src/main/java/com/ruoyi/projectManagement/vo/SaveInfoStageVo.java
@@ -0,0 +1,28 @@
+package com.ruoyi.projectManagement.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.projectManagement.dto.InfoStageDto;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * @author buhuazhen
+ * @date 2026/3/11
+ * @email 3038525872@qq.com
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class SaveInfoStageVo extends InfoStageDto implements java.io.Serializable {
+
+    private List<String> attachmentIds;
+
+}
diff --git a/src/main/resources/mapper/projectManagement/InfoMapper.xml b/src/main/resources/mapper/projectManagement/InfoMapper.xml
index 504394e..e101797 100644
--- a/src/main/resources/mapper/projectManagement/InfoMapper.xml
+++ b/src/main/resources/mapper/projectManagement/InfoMapper.xml
@@ -48,7 +48,14 @@
         department_name,order_date,order_amount,
         remark,attachment
     </sql>
-    <select id="searchListInfo" resultType="com.ruoyi.projectManagement.vo.ListInfoVo">
+    <resultMap id="ListInfoVoMap" type="com.ruoyi.projectManagement.vo.ListInfoVo">
+
+        <result column="plan_stage"
+                property="planStage"
+                typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+
+    </resultMap>
+    <select id="searchListInfo" resultMap="ListInfoVoMap">
         select t1.*, t2.name as project_management_plan_name,t3.title as projectManagementInfoParentName
         from project_management_info as t1
         left join project_management_plan as t2 on t1.project_management_plan_id = t2.id
diff --git a/src/main/resources/mapper/projectManagement/InfoStageMapper.xml b/src/main/resources/mapper/projectManagement/InfoStageMapper.xml
new file mode 100644
index 0000000..66cc12b
--- /dev/null
+++ b/src/main/resources/mapper/projectManagement/InfoStageMapper.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.projectManagement.mapper.InfoStageMapper">
+
+    <resultMap id="BaseResultMap" type="com.ruoyi.projectManagement.pojo.InfoStage">
+            <id property="id" column="id" jdbcType="BIGINT"/>
+            <result property="projectManagementPlanNodeId" column="project_management_plan_node_id" jdbcType="BIGINT"/>
+            <result property="projectManagementInfoId" column="project_management_info_id" jdbcType="BIGINT"/>
+            <result property="description" column="description" jdbcType="VARCHAR"/>
+            <result property="actuallyLeaderId" column="actually_leader_id" jdbcType="BIGINT"/>
+            <result property="actuallyLeaderName" column="actually_leader_name" jdbcType="VARCHAR"/>
+            <result property="estimatedDuration" column="estimated_duration" jdbcType="INTEGER"/>
+            <result property="planStartTime" column="plan_start_time" jdbcType="DATE"/>
+            <result property="planEndTime" column="plan_end_time" jdbcType="DATE"/>
+            <result property="actualStartTime" column="actual_start_time" jdbcType="DATE"/>
+            <result property="actualEndTime" column="actual_end_time" jdbcType="DATE"/>
+            <result property="progress" column="progress" jdbcType="INTEGER"/>
+            <result property="actuallyStartTime" column="actually_start_time" jdbcType="DATE"/>
+            <result property="actuallyEndTime" column="actually_end_time" jdbcType="DATE"/>
+            <result property="attachment" column="attachment" jdbcType="VARCHAR"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+            <result property="isDelete" column="is_delete" jdbcType="INTEGER"/>
+            <result property="createUser" column="create_user" jdbcType="BIGINT"/>
+            <result property="updateUser" column="update_user" jdbcType="BIGINT"/>
+            <result property="createUserName" column="create_user_name" jdbcType="VARCHAR"/>
+            <result property="updateUserName" column="update_user_name" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,project_management_plan_node_id,project_management_info_id,
+        description,actually_leader_id,actually_leader_name,
+        estimated_duration,plan_start_time,plan_end_time,
+        actual_start_time,actual_end_time,progress,
+        actually_start_time,actually_end_time,attachment,
+        create_time,update_time,is_delete,
+        create_user,update_user,create_user_name,
+        update_user_name
+    </sql>
+</mapper>

--
Gitblit v1.9.3