feat(bid): 完成甲方报价模块全量功能开发

1.  新增甲方报价业务实体,继承基础实体类
2.  新增供应商报价明细查询接口,支持按供应商ID展开物料明细
3.  重构甲方报价关联逻辑,通过material_id精确关联物料表
4.  新增甲方报价历史统计、月度趋势、快速新建等服务功能
5.  完善菜单配置,修正甲方报价菜单结构,添加完整权限控制
6.  新增物料搜索自动补全功能,优化报价单详情页面
7.  在供应商详情页新增报价历史Tab页签,展示该供应商的所有报价物料明细
8.  在物料详情页新增甲方报价记录Tab页签,展示该物料的所有甲方报价历史
9.  新增数据库优化脚本,添加索引并修复历史数据关联
This commit is contained in:
2026-06-01 19:05:04 +08:00
parent 18a71526dc
commit a75589018f
23 changed files with 1758 additions and 144 deletions

View File

@@ -1,10 +1,11 @@
package com.ruoyi.system.domain.bid;
import com.ruoyi.common.core.domain.BaseEntity;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
public class BizClientQuote {
public class BizClientQuote extends BaseEntity {
private Long quoteId;
private Long tenantId;
private String quoteNo;

View File

@@ -5,6 +5,7 @@ import java.math.BigDecimal;
public class BizClientQuoteItem {
private Long itemId;
private Long quoteId;
private Long materialId;
private String materialName;
private String spec;
private String modelNo;
@@ -20,6 +21,8 @@ public class BizClientQuoteItem {
public void setItemId(Long v){itemId=v;}
public Long getQuoteId(){return quoteId;}
public void setQuoteId(Long v){quoteId=v;}
public Long getMaterialId(){return materialId;}
public void setMaterialId(Long v){materialId=v;}
public String getMaterialName(){return materialName;}
public void setMaterialName(String v){materialName=v;}
public String getSpec(){return spec;}

View File

@@ -4,8 +4,10 @@ import com.ruoyi.system.domain.bid.BizClientQuote;
import com.ruoyi.system.domain.bid.BizClientQuoteItem;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface BizClientQuoteMapper {
// ========== CRUD ==========
List<BizClientQuote> selectClientQuoteList(@Param("q") BizClientQuote query);
BizClientQuote selectClientQuoteById(@Param("quoteId") Long quoteId);
List<BizClientQuoteItem> selectItemsByQuoteId(@Param("quoteId") Long quoteId);
@@ -15,4 +17,14 @@ public interface BizClientQuoteMapper {
int deleteClientQuoteById(@Param("quoteId") Long quoteId);
int deleteItemsByQuoteId(@Param("quoteId") Long quoteId);
String selectNextQuoteNo();
// ========== 甲方报价历史 - 统计 ==========
Map<String, Object> selectClientQuoteStatistics(@Param("q") BizClientQuote query);
List<Map<String, Object>> selectMonthlyTrend();
// ========== 按物料ID关联查询 ==========
List<Map<String, Object>> selectClientQuotesByMaterialId(@Param("materialId") Long materialId);
// ========== 快速复制 ==========
List<BizClientQuoteItem> selectItemsByQuoteIdForCopy(@Param("quoteId") Long quoteId);
}

View File

@@ -1,10 +1,13 @@
package com.ruoyi.system.mapper.bid;
import com.ruoyi.system.domain.bid.BizQuotationItem;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface BizQuotationItemMapper {
List<BizQuotationItem> selectItemsByQuotationId(Long quotationId);
List<Map<String, Object>> selectItemsBySupplierId(@Param("supplierId") Long supplierId);
int insertBizQuotationItem(BizQuotationItem item);
int deleteByQuotationId(Long quotationId);
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.system.service.bid;
import com.ruoyi.system.domain.bid.BizClientQuote;
import java.util.List;
import java.util.Map;
public interface IBizClientQuoteService {
List<BizClientQuote> selectClientQuoteList(BizClientQuote query);
@@ -9,4 +10,14 @@ public interface IBizClientQuoteService {
int insertClientQuote(BizClientQuote quote);
int updateClientQuote(BizClientQuote quote);
int deleteClientQuoteById(Long quoteId);
// 甲方报价历史 - 统计
Map<String, Object> selectClientQuoteStatistics(BizClientQuote query);
List<Map<String, Object>> selectMonthlyTrend();
// 按物料ID查询报价历史
List<Map<String, Object>> selectClientQuotesByMaterialId(Long materialId);
// 基于历史报价快速新建
BizClientQuote copyFromExisting(Long quoteId);
}

View File

@@ -10,6 +10,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
@Service
public class BizClientQuoteServiceImpl implements IBizClientQuoteService {
@@ -85,4 +86,70 @@ public class BizClientQuoteServiceImpl implements IBizClientQuoteService {
mapper.deleteItemsByQuoteId(quoteId);
return mapper.deleteClientQuoteById(quoteId);
}
// ========== 甲方报价历史 - 统计 ==========
@Override
public Map<String, Object> selectClientQuoteStatistics(BizClientQuote query) {
return mapper.selectClientQuoteStatistics(query);
}
@Override
public List<Map<String, Object>> selectMonthlyTrend() {
return mapper.selectMonthlyTrend();
}
// ========== 按物料ID查询 ==========
@Override
public List<Map<String, Object>> selectClientQuotesByMaterialId(Long materialId) {
return mapper.selectClientQuotesByMaterialId(materialId);
}
// ========== 基于历史报价快速新建 ==========
@Override
@Transactional
public BizClientQuote copyFromExisting(Long quoteId) {
BizClientQuote existing = mapper.selectClientQuoteById(quoteId);
if (existing == null) {
throw new RuntimeException("报价单不存在: " + quoteId);
}
// 创建新的报价单(复制主表信息,重置状态和金额)
BizClientQuote newQuote = new BizClientQuote();
newQuote.setQuoteNo(mapper.selectNextQuoteNo());
newQuote.setClientName(existing.getClientName());
newQuote.setRfqId(existing.getRfqId());
newQuote.setRfqNo(existing.getRfqNo());
newQuote.setRfqTitle(existing.getRfqTitle());
newQuote.setStatus("draft");
newQuote.setValidityDate(existing.getValidityDate());
newQuote.setCurrency(existing.getCurrency());
newQuote.setRemark(existing.getRemark());
newQuote.setTotalAmount(BigDecimal.ZERO);
int rows = mapper.insertClientQuote(newQuote);
// 复制明细
List<BizClientQuoteItem> items = mapper.selectItemsByQuoteId(quoteId);
if (items != null && !items.isEmpty()) {
BigDecimal total = BigDecimal.ZERO;
for (BizClientQuoteItem item : items) {
// 重置为新行
item.setItemId(null);
item.setQuoteId(newQuote.getQuoteId());
// 保留原物料信息和价格,方便用户修改
if (item.getUnitPrice() != null && item.getQuantity() != null) {
BigDecimal line = item.getUnitPrice().multiply(item.getQuantity()).setScale(2, RoundingMode.HALF_UP);
item.setTotalPrice(line);
total = total.add(line);
}
mapper.insertClientQuoteItem(item);
}
newQuote.setTotalAmount(total);
mapper.updateClientQuote(newQuote);
}
newQuote.setItems(items);
return newQuote;
}
}