zhangwencui
2 天以前 b30f4c40c77a940a2a749a676e901787f55040b0
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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.enums.IsDeleteEnum;
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.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
 
import jakarta.validation.constraints.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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;
 
    private final NamedParameterJdbcTemplate jdbc;
 
    @Transactional(rollbackFor = Exception.class)
    public Long save(@NotNull SaveInfoDto saveInfoDto) {
        Info info = BeanUtil.copyProperties(saveInfoDto, Info.class);
 
        if (info.getPlanStartTime() != null && info.getPlanEndTime() != null
                && info.getPlanEndTime().isBefore(info.getPlanStartTime())) {
            throw new ServiceException("预计结束时间不能早于预计开始时间");
        }
        bindProjectCategory(info);
 
        // 附件特殊处理
        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 || Integer.valueOf(IsDeleteEnum.DELETED.getCode()).equals(existing.getIsDelete())) {
                throw new ServiceException("项目不存在或已删除");
            }
            if (!StrUtil.isBlank(existing.getCurrentPhase()) && !"未开始".equals(existing.getCurrentPhase())) {
                throw new ServiceException("项目开始后,项目基本信息、负责人和项目经理均不可修改");
            }
            infoMapper.updateById(info);
        }
        return info.getId();
    }
 
    private void bindProjectCategory(Info info) {
        if (info.getProjectCategoryId() != null) {
            List<String> names = jdbc.queryForList("""
                    select category_name from project_management_category
                    where id=:id and is_deleted=0
                    """, Map.of("id", info.getProjectCategoryId()), String.class);
            if (names.isEmpty()) throw new ServiceException("项目分类不存在或已删除");
            info.setProjectClassification(names.getFirst());
            return;
        }
        if (!StrUtil.isBlank(info.getProjectClassification())) {
            List<Long> ids = jdbc.queryForList("""
                    select id from project_management_category
                    where category_name=:name and is_deleted=0 order by id
                    """, Map.of("name", info.getProjectClassification().trim()), Long.class);
            if (ids.size() == 1) info.setProjectCategoryId(ids.getFirst());
        }
    }
 
    @Transactional
    public void updateById(@NotNull Info info){
        infoMapper.updateById(info);
    }
 
    public SaveInfoDto getInfoById(@NotNull Long id) {
        Info info = infoMapper.selectById(id);
        if (info == null || Integer.valueOf(IsDeleteEnum.DELETED.getCode()).equals(info.getIsDelete())) {
            throw new ServiceException("项目不存在或已删除");
        }
        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.eq(Info::getIsDelete, IsDeleteEnum.NOT_DELETED.getCode());
        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;
    }
 
}