1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package com.ruoyi.projectManagement.service.impl.handle;
 
import cn.hutool.core.bean.BeanUtil;
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.common.exception.ServiceException;
import com.ruoyi.projectManagement.dto.InfoStageDto;
import com.ruoyi.projectManagement.dto.PlanStageDto;
import com.ruoyi.projectManagement.dto.SaveInfoDto;
import com.ruoyi.projectManagement.mapper.InfoMapper;
import com.ruoyi.projectManagement.pojo.Info;
import com.ruoyi.projectManagement.pojo.PlanNode;
import com.ruoyi.projectManagement.service.PlanService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
 
import jakarta.validation.constraints.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
 
/**
 * @author buhuazhen
 * @date 2026/3/9
 * @email 3038525872@qq.com
 */
@Component
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class, readOnly = true)
public class InfoHandleService {
 
    private static final String GENERATE_SERIAL_NUMBER_PREFIX = "XM";
 
    private final InfoMapper infoMapper;
 
    private final PlanService planService;
 
    private final CustomerFollowUpFileService customerFollowUpFileService;
 
    @Transactional(rollbackFor = Exception.class)
    public Long save(@NotNull SaveInfoDto saveInfoDto) {
        Info info = BeanUtil.copyProperties(saveInfoDto, Info.class);
 
        // 附件特殊处理
        String attachmentIds = StrUtil.join(",", Optional.ofNullable(saveInfoDto.getAttachmentIds()).orElse(Collections.emptyList()));
        info.setAttachment(attachmentIds);
 
        // 生成序号 (如果需要自动生成的话)
        if (StrUtil.isBlank(info.getNo())) {
            info.setNo(generateSerialNumber());
        }
        info.setTeam(saveInfoDto.getTeamList());
        if (info.getId() == null) {
            // 新项目阶段由 project_management_phase 独立维护,不再生成旧计划模板阶段。
            info.setPlanStage(Collections.emptyList());
            if (StrUtil.isBlank(info.getCurrentPhase())) {
                info.setCurrentPhase("未开始");
            }
            // 插入默认状态
            info.setStatus(PlanStageEnum.TO_BEGIN.getCode());
            info.setReviewStatus(ReviewStatusEnum.PENDING_REVIEW.getCode());
            infoMapper.insert(info);
        } else {
            Info existing = infoMapper.selectById(info.getId());
            if (existing == null) throw new ServiceException("项目不存在");
            if (!StrUtil.isBlank(existing.getCurrentPhase()) && !"未开始".equals(existing.getCurrentPhase())) {
                throw new ServiceException("项目开始后,项目基本信息、负责人和项目经理均不可修改");
            }
            infoMapper.updateById(info);
        }
        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);
    }
 
    private SaveInfoDto convert(Info info) {
        SaveInfoDto saveInfoDto = BeanUtil.copyProperties(info, SaveInfoDto.class);
        // 附件处理
        saveInfoDto.setTeamList(info.getTeam());
        customerFollowUpFileService.fillAttachment(Lists.newArrayList(saveInfoDto), SaveInfoDto::getAttachment, SaveInfoDto::setAttachmentList);
        return saveInfoDto;
 
    }
 
    /**
     * 获取改id下子项目信息
     *
     * @param id
     * @return
     */
    public List<SaveInfoDto> getSubordinateInfo(@NotNull Long id) {
        LambdaQueryWrapper<Info> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Info::getProjectManagementInfoParentId, id);
        queryWrapper.orderByAsc(Info::getCreateTime);
        List<Info> infoList = infoMapper.selectList(queryWrapper);
        return infoList.stream().map(this::convert).collect(Collectors.toList());
    }
 
 
    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, it.getSort(), it.getEstimatedDuration())).collect(Collectors.toList());
    }
 
 
    /**
     * 生成项目编号
     *
     * @return
     */
    private String generateSerialNumber() {
        // 获取当前日期
        String date = DateUtil.format(DateUtil.date(), "yyyyMMdd");
 
        // 查询今天已经生成的数量
        LambdaQueryWrapper<Info> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(Info::getNo, GENERATE_SERIAL_NUMBER_PREFIX + date);
 
        Long count = infoMapper.selectCount(queryWrapper);
 
        // 序号 +1
        Long serial = count + 1;
 
        // 3位补0
        String serialStr = String.format("%03d", serial);
 
        return GENERATE_SERIAL_NUMBER_PREFIX + date + serialStr;
    }
 
}