feat(quotation): 实现报价单绑定项目功能

- 在报价单表格中添加状态显示,使用字典标签展示报价状态
- 增加quotation_status字典类型用于状态管理
- 扩展ProjectInfo实体类,添加quotationId和quotationIdList字段
- 更新数据库映射文件,增加报价单ID相关字段和查询条件
- 在项目创建和更新流程中实现报价单绑定逻辑
- 添加bind和unBind方法到报价单服务接口和实现类
- 实现报价单状态枚举类,定义未绑定和已绑定状态
- 清理报价单表中废弃的项目代码和项目ID字段
- 优化报价单导出Excel模板中的项目信息展示
- 添加延迟注入项目信息服务以解决循环依赖问题
dev_1.0.2
chenhao 2026-02-03 10:32:34 +08:00
parent 701d90779a
commit 50ee54d6ef
9 changed files with 115 additions and 37 deletions

View File

@ -85,7 +85,11 @@
<el-table-column label="项目编号" align="center" prop="projectCode" />
<!-- <el-table-column label="报价金额" align="center" prop="quotationAmount" />-->
<el-table-column label="报价金额(¥)" align="center" prop="discountAmount" />
<el-table-column label="状态" align="center" prop="quotationStatus" />
<el-table-column label="状态" align="center" prop="quotationStatus" >
<template slot-scope="scope">
<dict-tag :options="dict.type.quotation_status" :value="scope.row.quotationStatus"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
@ -249,7 +253,7 @@ export default {
ProductConfig,
QuotationDetail
},
dicts: ['currency_type'],
dicts: ['currency_type','quotation_status'],
data() {
return {
//

View File

@ -872,6 +872,7 @@ export default {
this.$set(this.form.productConfig, 'softwareProjectProductInfoList', softwareList);
this.$set(this.form.productConfig, 'hardwareProjectProductInfoList', hardwareList);
this.$set(this.form.productConfig, 'maintenanceProjectProductInfoList', maintenanceList);
this.$set(this.form, 'quotationId', quotation.id);
this.$modal.msgSuccess("导入成功");
});

View File

@ -230,6 +230,8 @@ public class ProjectInfo extends BaseEntity
private List<OmsFileLog> projectFileList;
private String fileId;
private Integer quotationId;
private List<Integer> quotationIdList;
private Boolean availableForOrder;

View File

@ -7,6 +7,7 @@ import java.util.List;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.Getter;
/**
*
@ -77,6 +78,24 @@ public class Quotation extends BaseEntity {
private List<QuotationProductInfo> hardwareProjectProductInfoList;
// @Excel(name = "服务")
private List<QuotationProductInfo> maintenanceProjectProductInfoList;
@Getter
public enum QuotationStatusEnum {
NOT_BIND("0", "未绑定"),
BIND("1", "已绑定"),
;
private final String value;
private final String code;
QuotationStatusEnum(String code, String value) {
this.code = code;
this.value = value;
}
}
}

View File

@ -44,6 +44,10 @@ public interface IQuotationService {
int batchRemove(Integer[] ids);
String exportSingle(Integer id);
void bind(Integer quotationId);
void unBind(Integer quotationId);
}

View File

@ -27,6 +27,7 @@ import com.ruoyi.sip.dto.StatisticsDetailDto;
import com.ruoyi.sip.dto.StatisticsDto;
import com.ruoyi.sip.mapper.ProjectInfoMapper;
import com.ruoyi.sip.service.*;
import liquibase.hub.model.Project;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
@ -87,6 +88,8 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
private static final String PROJECT_CODE_PREFIX = "V";
private static final Integer PROJECT_CODE_LENGTH = 6;
@Autowired
private IQuotationService quotationService;
public static final String INDUSTRY_TYPE_YYS_DICT_TYPE = "bg_yys";
public static final String INDUSTRY_TYPE_DICT_TYPE = "bg_hysy";
@ -210,6 +213,7 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
}
int i = projectInfoMapper.insertProjectInfo(projectInfo);
saveOtherInfo(projectInfo);
quotationService.bind(projectInfo.getQuotationId());
return i;
}
@ -296,6 +300,13 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
update.setProjectId(projectOrderInfo.getProjectId());
orderInfoService.updateProjectOrderInfo(update);
}
quotationService.bind(projectInfo.getQuotationId());
ProjectInfo queryQuotationProject = new ProjectInfo();
queryQuotationProject.setQuotationId(oldProjectInfo.getQuotationId());
List<ProjectInfo> projectInfos = projectInfoMapper.selectProjectInfoList(queryQuotationProject);
if(CollUtil.isEmpty(projectInfos)){
quotationService.unBind(oldProjectInfo.getQuotationId());
}
return result;
}

View File

@ -12,16 +12,20 @@ import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.mapper.QuotationMapper;
import com.ruoyi.sip.service.ICodeGenTableService;
import com.ruoyi.sip.service.IProjectInfoService;
import com.ruoyi.sip.service.IQuotationProductInfoService;
import com.ruoyi.sip.service.IQuotationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -53,6 +57,10 @@ public class QuotationServiceImpl implements IQuotationService {
@Autowired
private IQuotationProductInfoService quotationProductInfoService;
@Autowired
@Lazy
private IProjectInfoService projectInfoService;
/**
*
@ -63,6 +71,15 @@ public class QuotationServiceImpl implements IQuotationService {
@Override
public List<Quotation> queryAll(Quotation quotation) {
List<Quotation> dataList = quotationMapper.queryAll(quotation);
PageUtils.clearPage();
if (CollUtil.isNotEmpty(dataList)) {
ProjectInfo projectInfo = new ProjectInfo();
List<Integer> collect = dataList.stream().map(Quotation::getId).collect(Collectors.toList());
projectInfo.setQuotationIdList(collect);
List<ProjectInfo> projectInfos = projectInfoService.selectProjectInfoList(projectInfo);
Map<Integer, String> projectCodeMap = projectInfos.stream().collect(Collectors.groupingBy(ProjectInfo::getQuotationId, Collectors.mapping(ProjectInfo::getProjectCode, Collectors.joining(","))));
dataList.forEach(item -> item.setProjectCode(projectCodeMap.get(item.getId())));
}
return dataList;
}
@ -87,6 +104,8 @@ public class QuotationServiceImpl implements IQuotationService {
public int insert(Quotation quotation) {
String s = codeGenTableService.generateCode(CodeGenTable.TableNameEnum.OMS_QUOTATION.getName());
quotation.setQuotationCode(s);
quotation.setQuotationStatus(Quotation.QuotationStatusEnum.NOT_BIND.getCode());
quotation.setCreateBy(ShiroUtils.getUserId().toString());
int insert = quotationMapper.insert(quotation);
List<QuotationProductInfo> productList = new ArrayList<>();
if (CollUtil.isNotEmpty(quotation.getSoftwareProjectProductInfoList())) {
@ -101,6 +120,7 @@ public class QuotationServiceImpl implements IQuotationService {
for (QuotationProductInfo quotationProductInfo : productList) {
quotationProductInfo.setQuotationId(quotation.getId());
}
quotationProductInfoService.saveBatch(productList);
return insert;
}
@ -175,7 +195,10 @@ public class QuotationServiceImpl implements IQuotationService {
List<Object> row2 = new ArrayList<>();
row2.add("项目名称:");
row2.add(quotation.getQuotationName());
row2.add(""); row2.add(""); row2.add(""); row2.add(""); // Padding
row2.add("");
row2.add("");
row2.add("");
row2.add(""); // Padding
row2.add("*本报价单有效期至:");
row2.add(validDate);
rows.add(row2);
@ -183,14 +206,20 @@ public class QuotationServiceImpl implements IQuotationService {
List<Object> row3 = new ArrayList<>();
row3.add("*项目ID:");
row3.add(quotation.getProjectCode());
row3.add(""); row3.add(""); row3.add(""); row3.add("");
row3.add("");
row3.add("");
row3.add("");
row3.add("");
row3.add("*云桌面完整报价单必须包含部署服务、现场维保、省代集成服务,此三项由省代进行补充报价,不能缺项");
rows.add(row3);
List<Object> row4 = new ArrayList<>();
row4.add("国家/地区 :");
row4.add("中国大陆");
row4.add(""); row4.add(""); row4.add(""); row4.add("");
row4.add("");
row4.add("");
row4.add("");
row4.add("");
row4.add("*因上游CPU、内存、存储波动较大封标前3天与汇智区域接口人邮件确定商务折扣和供货周期否则报价单无效");
rows.add(row4);
@ -198,7 +227,7 @@ public class QuotationServiceImpl implements IQuotationService {
row5.add("备注:");
row5.add(quotation.getRemark());
rows.add(row5);
rows.add(Collections.emptyList());
// 2. 第二部分:列标题
@ -305,6 +334,22 @@ public class QuotationServiceImpl implements IQuotationService {
}
}
@Override
public void bind(Integer quotationId) {
Quotation quotation = new Quotation();
quotation.setId(quotationId);
quotation.setQuotationStatus(Quotation.QuotationStatusEnum.BIND.getCode());
quotationMapper.update(quotation);
}
@Override
public void unBind(Integer quotationId) {
Quotation quotation = new Quotation();
quotation.setId(quotationId);
quotation.setQuotationStatus(Quotation.QuotationStatusEnum.NOT_BIND.getCode());
quotationMapper.update(quotation);
}
private void addSection(List<List<Object>> rows, String title, List<QuotationProductInfo> list, Set<Integer> coloredRowIndices, Set<Integer> aquaRowIndices, AtomicInteger sectionCounter) {
if (CollUtil.isEmpty(list)) {
return;
@ -388,7 +433,7 @@ public class QuotationServiceImpl implements IQuotationService {
// 自定义列宽策略:自适应但有最大宽度
public static class CustomColumnWidthStrategy extends AbstractColumnWidthStyleStrategy {
private static final int MAX_COLUMN_WIDTH = 50;
private static final int MAX_COLUMN_WIDTH = 50;
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

View File

@ -6,7 +6,6 @@
<result property="id" column="id"/>
<result property="quotationCode" column="quotation_code"/>
<result property="quotationName" column="quotation_name"/>
<result property="projectCode" column="project_code"/>
<result property="quotationAmount" column="quotation_amount"/>
<result property="discountAmount" column="discount_amount"/>
<result property="quotationStatus" column="quotation_status"/>
@ -15,7 +14,6 @@
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
<result property="projectId" column="project_id"/>
<result property="agentCode" column="agent_code"/>
<result property="amountType" column="amount_type"/>
<result property="customerName" column="customer_name"/>
@ -24,7 +22,7 @@
<!-- 基本字段 -->
<sql id="Base_Column_List">
id
, quotation_code, quotation_name, project_code, quotation_amount, discount_amount, quotation_status, create_time, create_by, update_by, update_time, remark, project_id, agent_code, amount_type, customer_name
, quotation_code, quotation_name, quotation_amount, discount_amount, quotation_status, create_time, create_by, update_by, update_time, remark, agent_code, amount_type, customer_name
</sql>
<!--通过实体作为筛选条件查询-->
@ -42,9 +40,7 @@
<if test="quotationName != null and quotationName != ''">
and quotation_name = #{quotationName}
</if>
<if test="projectCode != null and projectCode != ''">
and project_code = #{projectCode}
</if>
<if test="quotationAmount != null">
and quotation_amount = #{quotationAmount}
</if>
@ -69,9 +65,7 @@
<if test="remark != null and remark != ''">
and remark = #{remark}
</if>
<if test="projectId != null and projectId != ''">
and project_id = #{projectId}
</if>
<if test="agentCode != null and agentCode != ''">
and agent_code = #{agentCode}
</if>
@ -107,7 +101,7 @@
SELECT id,
quotation_code,
quotation_name,
project_code,
quotation_amount,
discount_amount,
quotation_status,
@ -116,7 +110,7 @@
update_by,
update_time,
remark,
project_id,
agent_code,
amount_type,
customer_name
@ -135,9 +129,7 @@
<if test="quotationName != null and quotationName != ''">
quotation_name,
</if>
<if test="projectCode != null and projectCode != ''">
project_code,
</if>
<if test="quotationAmount != null">
quotation_amount,
</if>
@ -162,9 +154,7 @@
<if test="remark != null and remark != ''">
remark,
</if>
<if test="projectId != null and projectId != ''">
project_id,
</if>
<if test="agentCode != null and agentCode != ''">
agent_code,
</if>
@ -182,9 +172,7 @@
<if test="quotationName != null and quotationName != ''">
#{quotationName},
</if>
<if test="projectCode != null and projectCode != ''">
#{projectCode},
</if>
<if test="quotationAmount != null">
#{quotationAmount},
</if>
@ -209,9 +197,7 @@
<if test="remark != null and remark != ''">
#{remark},
</if>
<if test="projectId != null and projectId != ''">
#{projectId},
</if>
<if test="agentCode != null and agentCode != ''">
#{agentCode},
</if>
@ -234,9 +220,7 @@
<if test="quotationName != null and quotationName != ''">
quotation_name = #{quotationName},
</if>
<if test="projectCode != null and projectCode != ''">
project_code = #{projectCode},
</if>
<if test="quotationAmount != null">
quotation_amount = #{quotationAmount},
</if>
@ -261,9 +245,7 @@
<if test="remark != null and remark != ''">
remark = #{remark},
</if>
<if test="projectId != null and projectId != ''">
project_id = #{projectId},
</if>
<if test="agentCode != null and agentCode != ''">
agent_code = #{agentCode},
</if>

View File

@ -45,7 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectProjectInfoVo">
select id, project_code, project_name,bg_property, customer_code, customer_name, industry_type, agent_code, 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,file_id
, key_problem, project_desc, create_by, create_time, update_by, update_time,customer_user_name,customer_phone,partner_email,partner_user_name,h3c_person,h3c_phone,poc,joint_trial,software_info,hardware_info,terminal_peripheral,management_version,desktop_vm_os_version,vm_spec_quantity,joint_trial_result from project_info t1
, key_problem, project_desc, create_by, create_time, update_by, update_time,customer_user_name,customer_phone,partner_email,partner_user_name,h3c_person,h3c_phone,poc,joint_trial,software_info,hardware_info,terminal_peripheral,management_version,desktop_vm_os_version,vm_spec_quantity,joint_trial_result,quotation_id from project_info t1
</sql>
<sql id="selectRelationProjectInfoVo">
select t1.id,
@ -85,6 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
t1.vm_spec_quantity,
t1.joint_trial_result,
t1.file_id,
t1.quotation_id,
t1.customer_user_name,t1.customer_phone,t1.partner_user_name,t1.h3c_person,t1.poc,t1.h3c_phone,
t2.agent_name,t2.contact_email,t2.contact_phone,t2.contact_person,
t3.user_name as hz_support_user_name,
@ -113,6 +114,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="agentName != null and agentName != ''"> and t2.agent_name like concat('%', #{agentName}, '%')</if>
<if test="customerName != null and customerName != ''"> and t1.customer_name like concat('%', #{customerName}, '%')</if>
<if test="industryType != null and industryType != ''"> and t1.industry_type = #{industryType}</if>
<if test="quotationId != null and quotationId != ''"> and t1.quotation_id = #{quotationId}</if>
<if test="quotationIdList != null and quotationIdList.size>0">
and t1.quotation_id in
<foreach collection="quotationIdList" item="item" separator="," open="(" close=")">
#{item}
</foreach></if>
<if test="industryTypeList != null and industryTypeList.size>0"> and t1.industry_type in
<foreach collection="industryTypeList" item="item" separator="," open="(" close=")">
#{item}
@ -286,6 +293,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="desktopVmOsVersion != null">desktop_vm_os_version,</if>
<if test="vmSpecQuantity != null">vm_spec_quantity,</if>
<if test="jointTrialResult != null">joint_trial_result,</if>
<if test="quotationId != null">quotation_id,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="projectCode != null">#{projectCode},</if>
@ -330,6 +338,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="desktopVmOsVersion != null">#{desktopVmOsVersion},</if>
<if test="vmSpecQuantity != null">#{vmSpecQuantity},</if>
<if test="jointTrialResult != null">#{jointTrialResult},</if>
<if test="quotationId != null">#{quotationId},</if>
</trim>
</insert>
<update id="updateCustomerCodeByCode">
@ -380,6 +389,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="desktopVmOsVersion != null">desktop_vm_os_version = #{desktopVmOsVersion},</if>
<if test="vmSpecQuantity != null">vm_spec_quantity = #{vmSpecQuantity},</if>
<if test="jointTrialResult != null">joint_trial_result = #{jointTrialResult},</if>
<if test="quotationId != null">quotation_id=#{quotationId},</if>
partner_code = #{partnerCode},
file_id = #{fileId},
update_by = now()