feat(sip): 增加项目管理功能

- 在 ProjectInfo 模型中添加 partnerName 字段
- 在 ProjectInfoMapper 中添加 selectUserById 方法
- 在 ProjectInfoMapper.xml 中添加 selectUserById SQL 语句
- 在 ProjectInfoServiceImpl 中实现项目信息保存和其他信息变更记录功能
-优化项目信息更新逻辑,增加操作日志记录
- 重构操作日志记录方法,提高可读性和可维护性
master
chenhao 2025-05-30 11:56:17 +08:00
parent 3ef4149d83
commit d5fedeb3f5
4 changed files with 170 additions and 46 deletions

View File

@ -66,8 +66,10 @@ public class ProjectInfo extends BaseEntity
private String operateInstitution;
/** 代理商code */
@Excel(name = "代理商code")
private String partnerCode;
@Excel(name = "代理商")
private String partnerName;
/** 联系方式 */
@Excel(name = "联系方式")

View File

@ -1,6 +1,8 @@
package com.ruoyi.sip.mapper;
import java.util.List;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.sip.domain.ProjectInfo;
/**
@ -60,4 +62,6 @@ public interface ProjectInfoMapper
public int deleteProjectInfoByIds(String[] ids);
String selectMaxProjectCode(ProjectInfo projectInfo);
List<SysUser> selectUserById(List<String> list);
}

View File

@ -1,12 +1,14 @@
package com.ruoyi.sip.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.service.IProjectOperateLogService;
@ -35,9 +37,15 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
private IProjectWorkProgressService workProgressService;
@Autowired
private IProjectOperateLogService operateLogService;
private static final String PROJECT_CODE_PREFIX = "V";
private static final Integer PROJECT_CODE_LENGTH = 5;
public static final String INDUSTRY_TYPE_DICT_TYPE = "industry_type";
public static final String PROJECT_STAGE_DICT_TYPE = "project_stage";
public static final String OPERATE_INSTITUTION_DICT_TYPE = "operate_institution";
/**
*
*
@ -91,29 +99,40 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
projectInfo.setCreateTime(DateUtils.getNowDate());
projectInfo.setCreateBy(ShiroUtils.getUserId().toString());
int i = projectInfoMapper.insertProjectInfo(projectInfo);
saveOtherInfo(projectInfo);
return i;
}
private void saveOtherInfo(ProjectInfo projectInfo1) {
//插入产品信息
List<ProjectProductInfo> hardwareProjectProductInfoList = projectInfo.getHardwareProjectProductInfoList();
List<ProjectProductInfo> softwareProjectProductInfoList = projectInfo.getSoftwareProjectProductInfoList();
List<ProjectProductInfo> addList=new ArrayList<>();
addList.addAll(hardwareProjectProductInfoList);
addList.addAll(softwareProjectProductInfoList);
if (CollUtil.isNotEmpty(addList)){
List<ProjectProductInfo> hardwareProjectProductInfoList = projectInfo1.getHardwareProjectProductInfoList();
List<ProjectProductInfo> softwareProjectProductInfoList = projectInfo1.getSoftwareProjectProductInfoList();
List<ProjectProductInfo> addList = new ArrayList<>();
if (CollUtil.isNotEmpty(hardwareProjectProductInfoList)) {
addList.addAll(hardwareProjectProductInfoList);
}
if (CollUtil.isNotEmpty(softwareProjectProductInfoList)) {
addList.addAll(softwareProjectProductInfoList);
}
if (CollUtil.isNotEmpty(addList)) {
for (ProjectProductInfo projectProductInfo : addList) {
projectProductInfo.setProjectId(projectInfo.getId());
projectProductInfo.setProjectId(projectInfo1.getId());
}
productInfoService.saveBatch(addList);
}
//插入变更记录信息
List<ProjectWorkProgress> projectWorkProgressList = projectInfo.getProjectWorkProgressList();
List<ProjectWorkProgress> projectWorkProgressList = projectInfo1.getProjectWorkProgressList();
if (CollUtil.isNotEmpty(projectWorkProgressList)) {
for (ProjectWorkProgress workProgress : projectWorkProgressList) {
workProgress.setProjectId(projectInfo.getId());
workProgress.setProjectId(projectInfo1.getId());
workProgress.setWorkUser(ShiroUtils.getUserId().toString());
workProgress.setWorkTime(DateUtils.getNowDate());
}
workProgressService.insertIgnoreBatch(projectWorkProgressList);
}
return i;
}
/**
*
*
@ -124,35 +143,60 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
public int updateProjectInfo(ProjectInfo projectInfo) {
// 获取更新前的项目信息
ProjectInfo oldProjectInfo = projectInfoMapper.selectProjectInfoById(projectInfo.getId());
// 更新项目信息
projectInfo.setUpdateTime(DateUtils.getNowDate());
int result = projectInfoMapper.updateProjectInfo(projectInfo);
//变更其它信息
saveOtherInfo(projectInfo);
// 记录操作日志
recordOperationLogs(projectInfo, oldProjectInfo);
return result;
}
private void recordOperationLogs(ProjectInfo projectInfo, ProjectInfo oldProjectInfo) {
StringBuilder logContent = new StringBuilder();
int logIndex = 1;
// 比较项目信息字段差异
logIndex = compareField(logContent, logIndex, "项目名称", oldProjectInfo.getProjectName(), projectInfo.getProjectName());
logIndex = compareField(logContent, logIndex, "客户名称", oldProjectInfo.getCustomerName(), projectInfo.getCustomerName());
logIndex = compareField(logContent, logIndex, "行业", DictUtils.getDictLabel(INDUSTRY_TYPE_DICT_TYPE, oldProjectInfo.getIndustryType())
, DictUtils.getDictLabel(INDUSTRY_TYPE_DICT_TYPE, projectInfo.getIndustryType()));
logIndex = compareField(logContent, logIndex, "属地", oldProjectInfo.getProvince(), projectInfo.getProvince());
logIndex = compareField(logContent, logIndex, "项目阶段", DictUtils.getDictLabel(PROJECT_STAGE_DICT_TYPE, oldProjectInfo.getProjectStage())
, DictUtils.getDictLabel(PROJECT_STAGE_DICT_TYPE, projectInfo.getProjectStage()));
logIndex = compareField(logContent, logIndex, "项目把握度", oldProjectInfo.getProjectGraspDegree(), projectInfo.getProjectGraspDegree());
if (oldProjectInfo.getHzSupportUser() != null || projectInfo.getHzSupportUser() != null) {
List<SysUser> sysUsers = projectInfoMapper.selectUserById(Stream.of(oldProjectInfo.getHzSupportUser(), projectInfo.getHzSupportUser()).filter(Objects::nonNull).collect(Collectors.toList()));
Map<String, String> userMap = sysUsers.stream().collect(Collectors.toMap(item -> item.getUserId().toString(), SysUser::getUserName));
logIndex = compareField(logContent, logIndex, "汇智支撑人员", userMap.get(oldProjectInfo.getHzSupportUser()), userMap.get(projectInfo.getHzSupportUser()));
}
logIndex = compareField(logContent, logIndex, "运作机构", DictUtils.getDictLabel(OPERATE_INSTITUTION_DICT_TYPE, oldProjectInfo.getOperateInstitution()),
DictUtils.getDictLabel(OPERATE_INSTITUTION_DICT_TYPE, projectInfo.getOperateInstitution()));
//替换代理商名称
logIndex = compareField(logContent, logIndex, "代理商", oldProjectInfo.getPartnerName(), projectInfo.getPartnerName());
logIndex = compareField(logContent, logIndex, "联系方式", oldProjectInfo.getContactWay(), projectInfo.getContactWay());
logIndex = compareBigDecimalField(logContent, logIndex, "预计金额", oldProjectInfo.getEstimatedAmount(), projectInfo.getEstimatedAmount());
logIndex = compareField(logContent, logIndex, "预计下单时间", oldProjectInfo.getEstimatedOrderTime(), projectInfo.getEstimatedOrderTime());
logIndex = compareField(logContent, logIndex, "预计发货时间", oldProjectInfo.getEstimatedDeliverTime(), projectInfo.getEstimatedDeliverTime());
logIndex = compareField(logContent, logIndex, "竞争对手", oldProjectInfo.getCompetitor(), projectInfo.getCompetitor());
logIndex = compareField(logContent, logIndex, "关键技术问题", oldProjectInfo.getKeyProblem(), projectInfo.getKeyProblem());
logIndex = compareField(logContent, logIndex, "项目简述", oldProjectInfo.getProjectDesc(), projectInfo.getProjectDesc());
// 配置信息变更
List<ProjectProductInfo> oldHardwareList = oldProjectInfo.getHardwareProjectProductInfoList();
List<ProjectProductInfo> oldSoftwareList = oldProjectInfo.getSoftwareProjectProductInfoList();
List<ProjectProductInfo> newHardwareList = projectInfo.getHardwareProjectProductInfoList();
List<ProjectProductInfo> newSoftwareList = projectInfo.getSoftwareProjectProductInfoList();
// 比较硬件产品信息
logIndex = compareProductInfoList(logContent, logIndex, "硬件产品", oldHardwareList, newHardwareList);
// 比较软件产品信息
logIndex = compareProductInfoList(logContent, logIndex, "软件产品", oldSoftwareList, newSoftwareList);
// 比较字段差异
compareField(logContent, logIndex++, "项目名称", oldProjectInfo.getProjectName(), projectInfo.getProjectName());
compareField(logContent, logIndex++, "客户名称", oldProjectInfo.getCustomerName(), projectInfo.getCustomerName());
compareField(logContent, logIndex++, "行业", oldProjectInfo.getIndustryType(), projectInfo.getIndustryType());
compareField(logContent, logIndex++, "属地", oldProjectInfo.getProvince(), projectInfo.getProvince());
compareField(logContent, logIndex++, "项目阶段", oldProjectInfo.getProjectStage(), projectInfo.getProjectStage());
compareField(logContent, logIndex++, "项目把握度", oldProjectInfo.getProjectGraspDegree(), projectInfo.getProjectGraspDegree());
compareField(logContent, logIndex++, "汇智支撑人员", oldProjectInfo.getHzSupportUser(), projectInfo.getHzSupportUser());
compareField(logContent, logIndex++, "运作机构", oldProjectInfo.getOperateInstitution(), projectInfo.getOperateInstitution());
compareField(logContent, logIndex++, "代理商", oldProjectInfo.getOperateInstitution(), projectInfo.getOperateInstitution());
compareField(logContent, logIndex++, "竞争对手", oldProjectInfo.getCompetitor(), projectInfo.getCompetitor());
// compareField(logContent, logIndex++, "项目类型", oldProjectInfo.getProjectType(), projectInfo.getProjectType());
// compareField(logContent, logIndex++, "项目状态", oldProjectInfo.getProjectStatus(), projectInfo.getProjectStatus());
// compareField(logContent, logIndex++, "项目经理", oldProjectInfo.getProjectManager(), projectInfo.getProjectManager());
// compareField(logContent, logIndex++, "预期收益", oldProjectInfo.getExpectedRevenue(), projectInfo.getExpectedRevenue());
// compareField(logContent, logIndex++, "实际收益", oldProjectInfo.getActualRevenue(), projectInfo.getActualRevenue());
// compareField(logContent, logIndex++, "开始日期", oldProjectInfo.getStartDate(), projectInfo.getStartDate());
// compareField(logContent, logIndex++, "结束日期", oldProjectInfo.getEndDate(), projectInfo.getEndDate());
// compareField(logContent, logIndex++, "风险等级", oldProjectInfo.getRiskLevel(), projectInfo.getRiskLevel());
// compareField(logContent, logIndex++, "备注", oldProjectInfo.getRemarks(), projectInfo.getRemarks());
// 插入操作日志
if (logContent.length() > 0) {
@ -163,21 +207,81 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
operateLog.setOperateUser(ShiroUtils.getUserId().toString());
operateLogService.insertProjectOperateLog(operateLog);
}
return result;
}
/**
*
*
*
* @param logContent
* @param index
* @param fieldName
* @param oldValue
* @param newValue
* @param type
* @param oldList
* @param newList
*/
private void compareField(StringBuilder logContent, int index, String fieldName, Object oldValue, Object newValue) {
if (!oldValue.equals(newValue)) {
private int compareProductInfoList(StringBuilder logContent, int index, String type, List<ProjectProductInfo> oldList, List<ProjectProductInfo> newList) {
// 将旧列表和新列表转换为以 id 为键的 Map便于快速查找
Map<Long, ProjectProductInfo> oldMap = CollUtil.isEmpty(oldList) ? new HashMap<>() : oldList.stream()
.collect(Collectors.toMap(ProjectProductInfo::getId, product -> product));
Map<Long, ProjectProductInfo> newMap = CollUtil.isEmpty(newList) ? new HashMap<>() : newList.stream()
.collect(Collectors.toMap(ProjectProductInfo::getId, product -> product));
// 获取所有 id 的并集
Set<Long> allIds = new HashSet<>(oldMap.keySet());
allIds.addAll(newMap.keySet());
for (Long id : allIds) {
ProjectProductInfo oldProduct = oldMap.get(id);
ProjectProductInfo newProduct = newMap.get(id);
if (oldProduct == null && newProduct != null) {
// 新增产品
logContent.append(index).append(".").append(type).append("新增:").append(newProduct.getProductCode()).append("\n");
index++;
} else if (oldProduct != null && newProduct == null) {
// 删除产品
logContent.append(index).append(".").append(type).append("删除:").append(oldProduct.getProductCode()).append("\n");
index++;
} else if (oldProduct != null) {
// 变更产品
if (!oldProduct.getProductCode().equals(newProduct.getProductCode())) {
logContent.append(index).append(".").append(type).append("变更:").append(oldProduct.getProductCode()).append(" -> ").append(newProduct.getProductCode()).append("\n");
index++;
}
if (!Objects.equals(oldProduct.getModel(), newProduct.getModel())) {
logContent.append(index).append(".").append("型号").append("由‘").append(oldProduct.getModel()).append("’变更为‘").append(newProduct.getModel()).append("\n");
index++;
}
if (!Objects.equals(oldProduct.getQuantity(), newProduct.getQuantity())) {
logContent.append(index).append(".").append("数量").append("由‘").append(oldProduct.getQuantity()).append("’变更为‘").append(newProduct.getQuantity()).append("\n");
index++;
}
if (!Objects.equals(oldProduct.getRemark(), newProduct.getRemark())) {
logContent.append(index).append(".").append("备注").append("由‘").append(oldProduct.getRemark()).append("’变更为‘").append(newProduct.getRemark()).append("\n");
index++;
}
}
}
return index;
}
private int compareField(StringBuilder logContent, int index, String fieldName, Object oldValue, Object newValue) {
if (!Objects.equals(oldValue, newValue)) {
logContent.append(index).append(".")
.append(fieldName)
.append("由‘")
.append(oldValue == null ? "" : oldValue)
.append("’变更为‘")
.append(newValue == null ? "" : oldValue)
.append("\n");
index++;
}
return index;
}
private int compareBigDecimalField(StringBuilder logContent, int index, String fieldName, BigDecimal oldValue, BigDecimal newValue) {
if (oldValue != null && newValue != null && oldValue.compareTo(newValue) != 0) {
logContent.append(index).append(".")
.append(fieldName)
.append("由‘")
@ -185,7 +289,9 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
.append("’变更为‘")
.append(newValue)
.append("\n");
index++;
}
return index;
}
/**

View File

@ -34,7 +34,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectProjectInfoVo">
select id, project_code, project_name, customer_code, customer_name, industry_type, province, project_stage, project_grasp_degree, hz_support_user, operate_institution, partner_code, contact_way, estimated_amount, currency_type, estimated_order_time, estimated_deliver_time, competitor, country_product, server_configuration, key_problem, project_desc, create_by, create_time, update_by, update_time from project_info
select id, project_code, project_name, customer_code, customer_name, industry_type, province, project_stage, project_grasp_degree, hz_support_user, operate_institution
, partner_code, partner_name, contact_way, estimated_amount, currency_type, estimated_order_time, estimated_deliver_time, competitor, country_product, server_configuration
, key_problem, project_desc, create_by, create_time, update_by, update_time from project_info
</sql>
<select id="selectProjectInfoList" parameterType="ProjectInfo" resultMap="ProjectInfoResult">
@ -51,6 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="hzSupportUser != null and hzSupportUser != ''"> and hz_support_user = #{hzSupportUser}</if>
<if test="operateInstitution != null and operateInstitution != ''"> and operate_institution = #{operateInstitution}</if>
<if test="partnerCode != null and partnerCode != ''"> and partner_code = #{partnerCode}</if>
<if test="partnerName != null and partnerName != ''"> and partner_name = #{partnerName}</if>
<if test="contactWay != null and contactWay != ''"> and contact_way = #{contactWay}</if>
<if test="estimatedAmount != null "> and estimated_amount = #{estimatedAmount}</if>
<if test="currencyType != null and currencyType != ''"> and currency_type = #{currencyType}</if>
@ -73,6 +76,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where province=#{province}
order by project_code desc limit 1
</select>
<select id="selectUserById" resultType="com.ruoyi.common.core.domain.entity.SysUser">
select * from sys_user
where id in <foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<insert id="insertProjectInfo" parameterType="ProjectInfo" useGeneratedKeys="true" keyProperty="id">
insert into project_info
@ -88,6 +97,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="hzSupportUser != null">hz_support_user,</if>
<if test="operateInstitution != null">operate_institution,</if>
<if test="partnerCode != null">partner_code,</if>
<if test="partnerName != null">partner_name,</if>
<if test="contactWay != null">contact_way,</if>
<if test="estimatedAmount != null">estimated_amount,</if>
<if test="currencyType != null">currency_type,</if>
@ -115,6 +125,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="hzSupportUser != null">#{hzSupportUser},</if>
<if test="operateInstitution != null">#{operateInstitution},</if>
<if test="partnerCode != null">#{partnerCode},</if>
<if test="partnerName != null">#{partnerName},</if>
<if test="contactWay != null">#{contactWay},</if>
<if test="estimatedAmount != null">#{estimatedAmount},</if>
<if test="currencyType != null">#{currencyType},</if>
@ -145,7 +156,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="projectGraspDegree != null">project_grasp_degree = #{projectGraspDegree},</if>
<if test="hzSupportUser != null">hz_support_user = #{hzSupportUser},</if>
<if test="operateInstitution != null">operate_institution = #{operateInstitution},</if>
<if test="partnerCode != null">partner_code = #{partnerCode},</if>
partner_code = #{partnerCode},
<if test="partnerName != null">partner_name = #{partnerName},</if>
<if test="contactWay != null">contact_way = #{contactWay},</if>
<if test="estimatedAmount != null">estimated_amount = #{estimatedAmount},</if>
<if test="currencyType != null">currency_type = #{currencyType},</if>