feat(bid): 新增基于甲方报价快速创建RFQ功能
本次提交完成以下核心变更: 1. 新增RFQ编号自动生成逻辑,添加selectNextRfqNo方法获取月度递增的RFQ编号 2. 在biz_rfq表新增client_quote_id关联字段,添加索引并完善实体类映射 3. 实现基于甲方报价复制物料快速创建RFQ的业务逻辑,包括事务处理和明细复制 4. 新增RFQ列表页关联甲方报价展示,支持点击跳转查看甲方报价详情 5. 在RFQ编辑页新增甲方报价选择器,选中后自动填充对应物料和标题 6. 优化甲方报价单页面,新增生成RFQ按钮和已生成RFQ列表展示 7. 调整RFQ详情页,新增编辑模式支持草稿状态修改 8. 修复路由跳转路径,统一RFQ相关页面路由到/bid/rfq路径组
This commit is contained in:
@@ -13,6 +13,9 @@ public class BizRfq extends BaseEntity {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date deadline;
|
||||
private String deliveryAddr;
|
||||
private Long clientQuoteId;
|
||||
private String clientQuoteNo;
|
||||
private String clientName;
|
||||
private String status;
|
||||
private List<BizRfqItem> items;
|
||||
private List<Long> supplierIds;
|
||||
@@ -29,6 +32,12 @@ public class BizRfq extends BaseEntity {
|
||||
public void setDeadline(Date deadline) { this.deadline = deadline; }
|
||||
public String getDeliveryAddr() { return deliveryAddr; }
|
||||
public void setDeliveryAddr(String deliveryAddr) { this.deliveryAddr = deliveryAddr; }
|
||||
public Long getClientQuoteId() { return clientQuoteId; }
|
||||
public void setClientQuoteId(Long clientQuoteId) { this.clientQuoteId = clientQuoteId; }
|
||||
public String getClientQuoteNo() { return clientQuoteNo; }
|
||||
public void setClientQuoteNo(String clientQuoteNo) { this.clientQuoteNo = clientQuoteNo; }
|
||||
public String getClientName() { return clientName; }
|
||||
public void setClientName(String clientName) { this.clientName = clientName; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public List<BizRfqItem> getItems() { return items; }
|
||||
|
||||
@@ -9,5 +9,6 @@ public interface BizRfqMapper {
|
||||
int insertBizRfq(BizRfq record);
|
||||
int updateBizRfq(BizRfq record);
|
||||
int deleteBizRfqById(Long id);
|
||||
String selectNextRfqNo();
|
||||
int deleteBizRfqByIds(Long[] ids);
|
||||
}
|
||||
|
||||
@@ -13,4 +13,6 @@ public interface IBizRfqService {
|
||||
int deleteBizRfqByIds(Long[] ids);
|
||||
int publishRfq(Long rfqId, Long[] supplierIds);
|
||||
List<BizRfqItem> selectItemsByRfqId(Long rfqId);
|
||||
/** 基于甲方报价快速创建 RFQ(复制物料明细) */
|
||||
BizRfq createRfqFromClientQuote(Long clientQuoteId, Long tenantId);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
package com.ruoyi.system.service.bid.impl;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizClientQuote;
|
||||
import com.ruoyi.system.domain.bid.BizClientQuoteItem;
|
||||
import com.ruoyi.system.domain.bid.BizRfq;
|
||||
import com.ruoyi.system.domain.bid.BizRfqItem;
|
||||
import com.ruoyi.system.mapper.bid.BizClientQuoteMapper;
|
||||
import com.ruoyi.system.mapper.bid.BizRfqItemMapper;
|
||||
import com.ruoyi.system.mapper.bid.BizRfqMapper;
|
||||
import com.ruoyi.system.service.bid.IBizRfqService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class BizRfqServiceImpl implements IBizRfqService {
|
||||
@Autowired private BizRfqMapper rfqMapper;
|
||||
@Autowired private BizRfqItemMapper itemMapper;
|
||||
@Autowired private BizClientQuoteMapper clientQuoteMapper;
|
||||
|
||||
@Override
|
||||
public List<BizRfq> selectBizRfqList(BizRfq query) { return rfqMapper.selectBizRfqList(query); }
|
||||
@@ -29,6 +33,9 @@ public class BizRfqServiceImpl implements IBizRfqService {
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertBizRfq(BizRfq rfq) {
|
||||
if (rfq.getRfqNo() == null || rfq.getRfqNo().isBlank()) {
|
||||
rfq.setRfqNo(rfqMapper.selectNextRfqNo());
|
||||
}
|
||||
rfq.setStatus("draft");
|
||||
int rows = rfqMapper.insertBizRfq(rfq);
|
||||
if (rfq.getItems() != null) {
|
||||
@@ -71,4 +78,50 @@ public class BizRfqServiceImpl implements IBizRfqService {
|
||||
public List<BizRfqItem> selectItemsByRfqId(Long rfqId) {
|
||||
return itemMapper.selectItemsByRfqId(rfqId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public BizRfq createRfqFromClientQuote(Long clientQuoteId, Long tenantId) {
|
||||
// 加载甲方报价
|
||||
BizClientQuote quote = clientQuoteMapper.selectClientQuoteById(clientQuoteId);
|
||||
if (quote == null) {
|
||||
throw new RuntimeException("甲方报价单不存在: " + clientQuoteId);
|
||||
}
|
||||
|
||||
// 创建 RFQ
|
||||
BizRfq rfq = new BizRfq();
|
||||
rfq.setRfqNo(rfqMapper.selectNextRfqNo());
|
||||
rfq.setTenantId(tenantId);
|
||||
rfq.setRfqTitle("采购需求: " + quote.getClientName() + " - " + quote.getQuoteNo());
|
||||
rfq.setClientQuoteId(quote.getQuoteId());
|
||||
rfq.setDeliveryAddr("");
|
||||
rfq.setStatus("draft");
|
||||
rfq.setRemark("源自甲方报价单: " + quote.getQuoteNo());
|
||||
|
||||
// 复制物料明细
|
||||
List<BizClientQuoteItem> sourceItems = clientQuoteMapper.selectItemsByQuoteId(clientQuoteId);
|
||||
if (sourceItems != null && !sourceItems.isEmpty()) {
|
||||
rfq.setItems(sourceItems.stream().map(src -> {
|
||||
BizRfqItem item = new BizRfqItem();
|
||||
item.setMaterialId(src.getMaterialId());
|
||||
item.setMaterialName(src.getMaterialName());
|
||||
item.setSpec(src.getSpec());
|
||||
item.setUnit(src.getUnit());
|
||||
item.setQuantity(src.getQuantity());
|
||||
item.setExpectedPrice(src.getUnitPrice());
|
||||
item.setRemark(src.getRemark());
|
||||
return item;
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
rfqMapper.insertBizRfq(rfq);
|
||||
if (rfq.getItems() != null) {
|
||||
for (BizRfqItem item : rfq.getItems()) {
|
||||
item.setRfqId(rfq.getRfqId());
|
||||
itemMapper.insertBizRfqItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
return rfqMapper.selectBizRfqById(rfq.getRfqId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
<result property="rfqTitle" column="rfq_title"/>
|
||||
<result property="deadline" column="deadline"/>
|
||||
<result property="deliveryAddr" column="delivery_addr"/>
|
||||
<result property="clientQuoteId" column="client_quote_id"/>
|
||||
<result property="clientQuoteNo" column="clientQuoteNo"/>
|
||||
<result property="clientName" column="clientName"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
@@ -17,22 +20,40 @@
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectRfqSql">
|
||||
SELECT r.*,
|
||||
cq.quote_no AS clientQuoteNo,
|
||||
cq.client_name AS clientName
|
||||
FROM biz_rfq r
|
||||
LEFT JOIN biz_client_quote cq ON r.client_quote_id = cq.quote_id
|
||||
</sql>
|
||||
|
||||
<select id="selectBizRfqList" resultMap="BaseRM">
|
||||
SELECT * FROM biz_rfq
|
||||
<include refid="selectRfqSql"/>
|
||||
<where>
|
||||
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
|
||||
<if test="rfqNo != null and rfqNo != ''"> AND rfq_no LIKE CONCAT('%',#{rfqNo},'%')</if>
|
||||
<if test="rfqTitle != null and rfqTitle != ''"> AND rfq_title LIKE CONCAT('%',#{rfqTitle},'%')</if>
|
||||
<if test="status != null and status != ''"> AND status=#{status}</if>
|
||||
<if test="tenantId != null"> AND r.tenant_id=#{tenantId}</if>
|
||||
<if test="rfqNo != null and rfqNo != ''"> AND r.rfq_no LIKE CONCAT('%',#{rfqNo},'%')</if>
|
||||
<if test="rfqTitle != null and rfqTitle != ''"> AND r.rfq_title LIKE CONCAT('%',#{rfqTitle},'%')</if>
|
||||
<if test="status != null and status != ''"> AND r.status=#{status}</if>
|
||||
<if test="clientQuoteId != null"> AND r.client_quote_id=#{clientQuoteId}</if>
|
||||
</where>
|
||||
ORDER BY rfq_id DESC
|
||||
ORDER BY r.rfq_id DESC
|
||||
</select>
|
||||
|
||||
<select id="selectBizRfqById" resultMap="BaseRM">SELECT * FROM biz_rfq WHERE rfq_id=#{id}</select>
|
||||
<select id="selectBizRfqById" resultMap="BaseRM">
|
||||
<include refid="selectRfqSql"/>
|
||||
WHERE r.rfq_id=#{id}
|
||||
</select>
|
||||
|
||||
<select id="selectNextRfqNo" resultType="String">
|
||||
SELECT CONCAT('RFQ-', DATE_FORMAT(NOW(),'%Y%m'), '-',
|
||||
LPAD(IFNULL(MAX(CAST(SUBSTRING_INDEX(rfq_no,'-',-1) AS UNSIGNED)),0)+1,3,'0'))
|
||||
FROM biz_rfq WHERE rfq_no LIKE CONCAT('RFQ-', DATE_FORMAT(NOW(),'%Y%m'), '%')
|
||||
</select>
|
||||
|
||||
<insert id="insertBizRfq" useGeneratedKeys="true" keyProperty="rfqId">
|
||||
INSERT INTO biz_rfq(tenant_id,rfq_no,rfq_title,deadline,delivery_addr,status,remark,create_by,create_time)
|
||||
VALUES(#{tenantId},#{rfqNo},#{rfqTitle},#{deadline},#{deliveryAddr},#{status},#{remark},#{createBy},NOW())
|
||||
INSERT INTO biz_rfq(tenant_id,rfq_no,rfq_title,deadline,delivery_addr,client_quote_id,status,remark,create_by,create_time)
|
||||
VALUES(#{tenantId},#{rfqNo},#{rfqTitle},#{deadline},#{deliveryAddr},#{clientQuoteId},#{status},#{remark},#{createBy},NOW())
|
||||
</insert>
|
||||
|
||||
<update id="updateBizRfq">
|
||||
@@ -41,6 +62,7 @@
|
||||
<if test="rfqTitle != null">rfq_title=#{rfqTitle},</if>
|
||||
<if test="deadline != null">deadline=#{deadline},</if>
|
||||
<if test="deliveryAddr != null">delivery_addr=#{deliveryAddr},</if>
|
||||
<if test="clientQuoteId != null">client_quote_id=#{clientQuoteId},</if>
|
||||
<if test="status != null">status=#{status},</if>
|
||||
<if test="remark != null">remark=#{remark},</if>
|
||||
update_by=#{updateBy}, update_time=NOW()
|
||||
|
||||
Reference in New Issue
Block a user