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

@@ -62,6 +62,20 @@ public class BizClientQuoteController extends BaseController {
return success(service.selectClientQuotesByMaterialId(materialId));
}
// ========== 按客户+物料查询历史报价(编辑参考用) ==========
@GetMapping("/history")
public AjaxResult history(@RequestParam String clientName, @RequestParam(required = false) Long materialId) {
return success(service.selectClientQuoteHistory(clientName, materialId));
}
// ========== 客户名称自动补全 ==========
@GetMapping("/client-names")
public AjaxResult clientNames(@RequestParam(required = false) String keyword) {
return success(service.selectDistinctClientNames(keyword));
}
// ========== 基于历史报价快速新建 ==========
@PostMapping("/quick-create/{quoteId}")

View File

@@ -75,6 +75,12 @@ public class BizMaterialController extends BaseController {
return success(service.selectClientQuotesByMaterialId(id));
}
@PreAuthorize("@ss.hasPermi('bid:material:detail')")
@GetMapping("/{id}/supplier-reference")
public AjaxResult supplierReference(@PathVariable Long id) {
return success(service.selectSupplierQuoteReference(id));
}
@GetMapping("/manufacturer/list")
public AjaxResult manufacturerList() {
return success(service.selectManufacturerList());

View File

@@ -1,5 +1,6 @@
package com.ruoyi.web.controller.bid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
@@ -10,45 +11,63 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.bid.BizQuotation;
import com.ruoyi.system.domain.bid.BizSupplier;
import com.ruoyi.system.service.bid.IBizQuotationService;
import com.ruoyi.system.service.bid.IBizSupplierService;
import com.ruoyi.system.mapper.bid.BizQuotationItemMapper;
@RestController
@RequestMapping("/bid/quotation")
public class BizQuotationController extends BaseController {
@Autowired private IBizQuotationService service;
@Autowired private IBizSupplierService supplierService;
@Autowired private BizQuotationItemMapper quotationItemMapper;
@PreAuthorize("@ss.hasPermi('bid:quotation:list')")
@PreAuthorize("@ss.hasPermi('bid:quotation:list') || @ss.hasRole('supplier')")
@GetMapping("/list")
public TableDataInfo list(BizQuotation q) {
// 供应商:自动按 supplier_id 过滤,只显示自己的报价
if (SecurityUtils.hasRole("supplier")) {
BizSupplier supplier = supplierService.selectBizSupplierByUserId(SecurityUtils.getUserId());
if (supplier != null) {
q.setSupplierId(supplier.getSupplierId());
}
}
startPage();
return getDataTable(service.selectBizQuotationList(q));
}
@PreAuthorize("@ss.hasPermi('bid:quotation:query')")
@PreAuthorize("@ss.hasPermi('bid:quotation:query') || @ss.hasRole('supplier')")
@GetMapping("/{quotationId}")
public AjaxResult getInfo(@PathVariable Long quotationId) {
return success(service.selectBizQuotationById(quotationId));
}
@PreAuthorize("@ss.hasPermi('bid:quotation:add')")
@PreAuthorize("@ss.hasPermi('bid:quotation:add') || @ss.hasRole('supplier')")
@Log(title = "报价单", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody BizQuotation q) {
q.setCreateBy(getUsername());
// 供应商新建报价时自动设置 supplier_id
if (SecurityUtils.hasRole("supplier")) {
BizSupplier supplier = supplierService.selectBizSupplierByUserId(SecurityUtils.getUserId());
if (supplier != null) {
q.setSupplierId(supplier.getSupplierId());
}
}
return toAjax(service.insertBizQuotation(q));
}
@PreAuthorize("@ss.hasPermi('bid:quotation:edit')")
@PreAuthorize("@ss.hasPermi('bid:quotation:edit') || @ss.hasRole('supplier')")
@Log(title = "报价单", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody BizQuotation q) {
return toAjax(service.updateBizQuotation(q));
}
@PreAuthorize("@ss.hasPermi('bid:quotation:edit')")
@PreAuthorize("@ss.hasPermi('bid:quotation:edit') || @ss.hasRole('supplier')")
@Log(title = "提交报价", businessType = BusinessType.UPDATE)
@PutMapping("/submit/{quotationId}")
public AjaxResult submit(@PathVariable Long quotationId) {
@@ -67,7 +86,7 @@ public class BizQuotationController extends BaseController {
return toAjax(service.rejectQuotation(quotationId));
}
@PreAuthorize("@ss.hasPermi('bid:quotation:remove')")
@PreAuthorize("@ss.hasPermi('bid:quotation:remove') || @ss.hasRole('supplier')")
@Log(title = "报价单", businessType = BusinessType.DELETE)
@DeleteMapping("/{quotationIds}")
public AjaxResult remove(@PathVariable Long[] quotationIds) {
@@ -75,13 +94,38 @@ public class BizQuotationController extends BaseController {
}
/**
* 按供应商ID查询报价明细展开为每行一条物料
* 按供应商ID查询报价明细展开为每行一条物料,支持搜索过滤
* 用于供应商管理页面的"报价历史"Tab
*/
@PreAuthorize("@ss.hasPermi('bid:quotation:list')")
@GetMapping("/supplier-items/{supplierId}")
public AjaxResult supplierItems(@PathVariable Long supplierId) {
List<Map<String, Object>> list = quotationItemMapper.selectItemsBySupplierId(supplierId);
public AjaxResult supplierItems(@PathVariable Long supplierId,
@RequestParam(required = false) String materialName,
@RequestParam(required = false) String quoteNo,
@RequestParam(required = false) String quoteStatus,
@RequestParam(required = false) String beginTime,
@RequestParam(required = false) String endTime) {
Map<String, Object> params = new HashMap<>();
params.put("supplierId", supplierId);
params.put("materialName", materialName);
params.put("quoteNo", quoteNo);
params.put("quoteStatus", quoteStatus);
params.put("beginTime", beginTime);
params.put("endTime", endTime);
List<Map<String, Object>> list = quotationItemMapper.selectItemsBySupplierId(params);
return success(list);
}
/**
* 根据RFQ ID查询所有供应商报价
* 用于RFQ列表页的"供应商报价汇总"弹窗
*/
@PreAuthorize("@ss.hasPermi('bid:quotation:list')")
@GetMapping("/by-rfq/{rfqId}")
public AjaxResult listByRfq(@PathVariable Long rfqId) {
BizQuotation query = new BizQuotation();
query.setRfqId(rfqId);
List<BizQuotation> list = service.selectBizQuotationList(query);
return success(list);
}
}

View File

@@ -13,28 +13,39 @@ import com.ruoyi.system.domain.bid.BizClientQuote;
import com.ruoyi.system.domain.bid.BizRfq;
import com.ruoyi.system.domain.bid.BizRfqItem;
import com.ruoyi.system.mapper.bid.BizClientQuoteMapper;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.bid.BizSupplier;
import com.ruoyi.system.service.bid.IBizRfqService;
import com.ruoyi.system.service.bid.IBizSupplierService;
@RestController
@RequestMapping("/bid/rfq")
public class BizRfqController extends BaseController {
@Autowired private IBizRfqService service;
@Autowired private IBizSupplierService supplierService;
@Autowired private BizClientQuoteMapper clientQuoteMapper;
@PreAuthorize("@ss.hasPermi('bid:rfq:list')")
@PreAuthorize("@ss.hasPermi('bid:rfq:list') || @ss.hasRole('supplier')")
@GetMapping("/list")
public TableDataInfo list(BizRfq query) {
// 供应商用户自动过滤只可见自己被邀请的RFQ
if (SecurityUtils.hasRole("supplier")) {
BizSupplier supplier = supplierService.selectBizSupplierByUserId(SecurityUtils.getUserId());
if (supplier != null) {
query.setSupplierId(supplier.getSupplierId());
}
}
startPage();
return getDataTable(service.selectBizRfqList(query));
}
@PreAuthorize("@ss.hasPermi('bid:rfq:query')")
@PreAuthorize("@ss.hasPermi('bid:rfq:query') || @ss.hasRole('supplier')")
@GetMapping("/{rfqId}")
public AjaxResult getInfo(@PathVariable Long rfqId) {
return success(service.selectBizRfqById(rfqId));
}
@PreAuthorize("@ss.hasPermi('bid:rfq:query')")
@PreAuthorize("@ss.hasPermi('bid:rfq:query') || @ss.hasRole('supplier')")
@GetMapping("/{rfqId}/items")
public AjaxResult getItems(@PathVariable Long rfqId) {
return success(service.selectItemsByRfqId(rfqId));