feat: 页面功能完善

3.1 供货商管理页面

  - 移除了右侧面板的"供货清单"Tab
  - 报价历史板块新增搜索功能(物料名称/报价单号/状态/日期范围)
  - 后端 Mapper 改造支持动态 SQL 过滤

  3.2 报价请求与供应商报价关联

  - 新增"供应商报价汇总"弹窗,展示 RFQ 下所有供应商的报价对比
  - 报价单号改为可点击链接,跳转到供应商报价列表并按单号搜索

  3.3 智慧比价详情页

  - 修复了比价详情页路由(在 router/index.js 中补充)
  - 移除了评分维度展示(价格/交期/质量/服务评分条、综合分标签)
  - 精简为纯粹的供应商价格对比视图

  3.4 其他修复

  - 首页快捷操作路径修正(/bid/xxx → /xxx)
  - 停用 bid 目录后受影响的 router.push 路径全部修复
  - biz_tenant 表缺失修复(创建建表 SQL 并执行)
  - 比价详情页路由注册补充
  - goCompare 跳转路径修正
This commit is contained in:
2026-06-06 15:20:46 +08:00
parent 5a1d7111cc
commit c97fdf4c6f
50 changed files with 1174 additions and 301 deletions

View File

@@ -19,6 +19,8 @@ public class BizRfq extends BaseEntity {
private String status;
private List<BizRfqItem> items;
private List<Long> supplierIds;
/** 供应商数据过滤非持久化仅用于查询时传入当前供应商ID */
private Long supplierId;
public Long getRfqId() { return rfqId; }
public void setRfqId(Long rfqId) { this.rfqId = rfqId; }
@@ -44,4 +46,6 @@ public class BizRfq extends BaseEntity {
public void setItems(List<BizRfqItem> items) { this.items = items; }
public List<Long> getSupplierIds() { return supplierIds; }
public void setSupplierIds(List<Long> supplierIds) { this.supplierIds = supplierIds; }
public Long getSupplierId() { return supplierId; }
public void setSupplierId(Long supplierId) { this.supplierId = supplierId; }
}

View File

@@ -25,6 +25,12 @@ public interface BizClientQuoteMapper {
// ========== 按物料ID关联查询 ==========
List<Map<String, Object>> selectClientQuotesByMaterialId(@Param("materialId") Long materialId);
// ========== 按客户+物料查询历史报价(编辑参考) ==========
List<Map<String, Object>> selectClientQuoteHistory(@Param("clientName") String clientName, @Param("materialId") Long materialId);
// ========== 客户名称自动补全 ==========
List<String> selectDistinctClientNames(@Param("keyword") String keyword);
// ========== 快速复制 ==========
List<BizClientQuoteItem> selectItemsByQuoteIdForCopy(@Param("quoteId") Long quoteId);
}

View File

@@ -16,6 +16,9 @@ public interface BizMaterialMapper {
// 物料详情页
List<Map<String, Object>> selectSupplierQuotesByMaterialId(Long materialId);
// 供应商报价参考(编辑参考用,按价格升序,每供应商取最新一条)
List<Map<String, Object>> selectSupplierQuoteReference(Long materialId);
// 批量物料对比
List<BizMaterial> selectBizMaterialByIds(List<Long> materialIds);
List<Map<String, Object>> selectSupplierPriceSummaryByMaterialIds(List<Long> materialIds);

View File

@@ -7,7 +7,7 @@ import java.util.Map;
public interface BizQuotationItemMapper {
List<BizQuotationItem> selectItemsByQuotationId(Long quotationId);
List<Map<String, Object>> selectItemsBySupplierId(@Param("supplierId") Long supplierId);
List<Map<String, Object>> selectItemsBySupplierId(Map<String, Object> params);
int insertBizQuotationItem(BizQuotationItem item);
int deleteByQuotationId(Long quotationId);
}

View File

@@ -1,11 +1,13 @@
package com.ruoyi.system.mapper.bid;
import com.ruoyi.system.domain.bid.BizSupplier;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BizSupplierMapper {
List<BizSupplier> selectBizSupplierList(BizSupplier query);
BizSupplier selectBizSupplierById(Long id);
BizSupplier selectBizSupplierByUserId(@Param("userId") Long userId);
int insertBizSupplier(BizSupplier record);
int updateBizSupplier(BizSupplier record);
int deleteBizSupplierById(Long id);

View File

@@ -18,6 +18,12 @@ public interface IBizClientQuoteService {
// 按物料ID查询报价历史
List<Map<String, Object>> selectClientQuotesByMaterialId(Long materialId);
// 按客户+物料查询历史报价(编辑参考用)
List<Map<String, Object>> selectClientQuoteHistory(String clientName, Long materialId);
// 客户名称自动补全
List<String> selectDistinctClientNames(String keyword);
// 基于历史报价快速新建
BizClientQuote copyFromExisting(Long quoteId);
}

View File

@@ -14,6 +14,7 @@ public interface IBizMaterialService {
List<Map<String, Object>> selectSupplierQuotesByMaterialId(Long materialId);
List<Map<String, Object>> selectClientQuotesByMaterialId(Long materialId);
List<Map<String, Object>> selectSupplierQuoteReference(Long materialId);
List<String> selectManufacturerList();
// 批量物料对比

View File

@@ -6,6 +6,7 @@ import java.util.List;
public interface IBizSupplierService {
List<BizSupplier> selectBizSupplierList(BizSupplier query);
BizSupplier selectBizSupplierById(Long id);
BizSupplier selectBizSupplierByUserId(Long userId);
int insertBizSupplier(BizSupplier record);
int updateBizSupplier(BizSupplier record);
int deleteBizSupplierById(Long id);

View File

@@ -106,6 +106,20 @@ public class BizClientQuoteServiceImpl implements IBizClientQuoteService {
return mapper.selectClientQuotesByMaterialId(materialId);
}
// ========== 按客户+物料查询历史报价(编辑参考) ==========
@Override
public List<Map<String, Object>> selectClientQuoteHistory(String clientName, Long materialId) {
return mapper.selectClientQuoteHistory(clientName, materialId);
}
// ========== 客户名称自动补全 ==========
@Override
public List<String> selectDistinctClientNames(String keyword) {
return mapper.selectDistinctClientNames(keyword);
}
// ========== 基于历史报价快速新建 ==========
@Override

View File

@@ -53,6 +53,11 @@ public class BizMaterialServiceImpl implements IBizMaterialService {
return mapper.selectClientQuotesByMaterialId(materialId);
}
@Override
public List<Map<String, Object>> selectSupplierQuoteReference(Long materialId) {
return mapper.selectSupplierQuoteReference(materialId);
}
@Override
public List<String> selectManufacturerList() {
return mapper.selectManufacturerList();

View File

@@ -22,6 +22,11 @@ public class BizSupplierServiceImpl implements IBizSupplierService {
return mapper.selectBizSupplierById(id);
}
@Override
public BizSupplier selectBizSupplierByUserId(Long userId) {
return mapper.selectBizSupplierByUserId(userId);
}
@Override
public int insertBizSupplier(BizSupplier record) {
return mapper.insertBizSupplier(record);

View File

@@ -99,6 +99,16 @@
</where>
</select>
<!-- ========== 获取去重的客户名称列表(用于自动补全) ========== -->
<select id="selectDistinctClientNames" resultType="java.lang.String">
SELECT DISTINCT client_name FROM biz_client_quote
WHERE client_name IS NOT NULL AND client_name != ''
<if test="keyword != null and keyword != ''">AND client_name LIKE CONCAT('%',#{keyword},'%')</if>
ORDER BY client_name
LIMIT 20
</select>
<!-- ========== 按物料ID查询甲方报价历史使用material_id精确关联 ========== -->
<select id="selectClientQuotesByMaterialId" resultType="java.util.Map">
@@ -114,6 +124,23 @@
ORDER BY cq.create_time DESC
</select>
<!-- ========== 按客户+物料ID查询历史报价甲方编辑时参考 ========== -->
<!-- materialId为可选为空时返回该客户所有历史物料 -->
<select id="selectClientQuoteHistory" resultType="java.util.Map">
SELECT cqi.item_id AS itemId, cqi.spec, cqi.unit, cqi.quantity,
cqi.cost_price AS costPrice, cqi.unit_price AS unitPrice, cqi.total_price AS totalPrice,
cqi.delivery_days AS deliveryDays, cqi.material_id AS materialId,
cqi.material_name AS materialName,
cq.quote_id AS quoteId, cq.quote_no AS quoteNo, cq.create_time AS createTime
FROM biz_client_quote_item cqi
JOIN biz_client_quote cq ON cqi.quote_id = cq.quote_id
WHERE cq.client_name LIKE CONCAT('%', #{clientName}, '%')
<if test="materialId != null">AND cqi.material_id = #{materialId}</if>
ORDER BY cq.create_time DESC
LIMIT 20
</select>
<!-- ========== 快速创建 - 复制历史报价单的明细按报价单ID ========== -->
<select id="selectItemsByQuoteIdForCopy" resultType="com.ruoyi.system.domain.bid.BizClientQuoteItem">

View File

@@ -92,6 +92,27 @@
ORDER BY q.submit_time DESC
</select>
<!-- 供应商报价参考按物料ID按价格升序每个供应商取最新一条 -->
<select id="selectSupplierQuoteReference" resultType="java.util.Map">
SELECT t.supplier_id AS supplierId, t.supplier_name AS supplierName,
t.unit_price AS unitPrice, t.delivery_days AS deliveryDays,
t.quote_no AS quoteNo, t.submit_time AS submitTime, t.quote_status
FROM (
SELECT s.supplier_id, s.supplier_name,
qi.unit_price, qi.delivery_days,
q.quote_no, q.submit_time, q.status AS quote_status,
ROW_NUMBER() OVER (PARTITION BY s.supplier_id ORDER BY q.submit_time DESC) AS rn
FROM biz_quotation_item qi
JOIN biz_quotation q ON qi.quotation_id = q.quotation_id
JOIN biz_supplier s ON q.supplier_id = s.supplier_id
JOIN biz_rfq_item ri ON qi.rfq_item_id = ri.item_id
WHERE ri.material_id = #{materialId}
AND qi.unit_price IS NOT NULL
) t
WHERE t.rn = 1
ORDER BY t.unit_price ASC
</select>
<!-- 甲方报价历史通过material_id精确关联 -->
<select id="selectClientQuotesByMaterialId" resultType="java.util.Map">
SELECT cqi.item_id, cqi.spec, cqi.model_no, cqi.unit, cqi.quantity,

View File

@@ -19,8 +19,8 @@
SELECT * FROM biz_quotation_item WHERE quotation_id=#{quotationId}
</select>
<!-- 按供应商ID查询报价明细展开为每行一条物料 -->
<select id="selectItemsBySupplierId" resultType="java.util.Map">
<!-- 按供应商ID查询报价明细展开为每行一条物料,支持搜索过滤 -->
<select id="selectItemsBySupplierId" parameterType="java.util.Map" resultType="java.util.Map">
SELECT qi.item_id AS itemId, qi.quotation_id AS quotationId,
qi.material_name AS materialName, qi.spec, qi.unit,
qi.quantity, qi.unit_price AS unitPrice, qi.total_price AS totalPrice,
@@ -33,6 +33,21 @@
JOIN biz_quotation q ON qi.quotation_id = q.quotation_id
LEFT JOIN biz_rfq_item ri ON qi.rfq_item_id = ri.item_id
WHERE q.supplier_id = #{supplierId}
<if test="materialName != null and materialName != ''">
AND qi.material_name LIKE CONCAT('%', #{materialName}, '%')
</if>
<if test="quoteNo != null and quoteNo != ''">
AND q.quote_no LIKE CONCAT('%', #{quoteNo}, '%')
</if>
<if test="quoteStatus != null and quoteStatus != ''">
AND q.status = #{quoteStatus}
</if>
<if test="beginTime != null and beginTime != ''">
AND q.submit_time &gt;= #{beginTime}
</if>
<if test="endTime != null and endTime != ''">
AND q.submit_time &lt;= #{endTime}
</if>
ORDER BY q.submit_time DESC, qi.item_id
</select>

View File

@@ -32,7 +32,14 @@
<if test="tenantId != null"> AND q.tenant_id=#{tenantId}</if>
<if test="rfqId != null"> AND q.rfq_id=#{rfqId}</if>
<if test="supplierId != null"> AND q.supplier_id=#{supplierId}</if>
<!-- 供应商过滤:仅显示未过交期的报价(仅供应商用户时生效) -->
<if test="supplierId != null">
AND (q.submit_time IS NULL OR DATE_ADD(q.submit_time, INTERVAL q.delivery_days DAY) >= NOW())
</if>
<if test="status != null and status != ''"> AND q.status=#{status}</if>
<if test="quoteNo != null and quoteNo != ''"> AND q.quote_no LIKE CONCAT('%', #{quoteNo}, '%')</if>
<if test="rfqNo != null and rfqNo != ''"> AND r.rfq_no LIKE CONCAT('%', #{rfqNo}, '%')</if>
<if test="supplierName != null and supplierName != ''"> AND s.supplier_name LIKE CONCAT('%', #{supplierName}, '%')</if>
</where>
ORDER BY q.quotation_id DESC
</select>

View File

@@ -36,6 +36,9 @@
<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>
<if test="supplierId != null">
AND r.rfq_id IN (SELECT rfq_id FROM biz_rfq_supplier WHERE supplier_id = #{supplierId})
</if>
</where>
ORDER BY r.rfq_id DESC
</select>

View File

@@ -30,6 +30,10 @@
<select id="selectBizSupplierById" resultMap="BaseRM">SELECT * FROM biz_supplier WHERE supplier_id=#{id}</select>
<select id="selectBizSupplierByUserId" resultMap="BaseRM">
SELECT * FROM biz_supplier WHERE user_id = #{userId}
</select>
<insert id="insertBizSupplier" useGeneratedKeys="true" keyProperty="supplierId">
INSERT INTO biz_supplier(tenant_id,supplier_name,contact,phone,email,address,user_id,status,create_by,create_time)
VALUES(#{tenantId},#{supplierName},#{contact},#{phone},#{email},#{address},#{userId},#{status},#{createBy},NOW())