diff --git a/deploy/init-sql/03-bid-tables.sql b/deploy/init-sql/03-bid-tables.sql index 78087a69..2059fcc2 100644 --- a/deploy/init-sql/03-bid-tables.sql +++ b/deploy/init-sql/03-bid-tables.sql @@ -230,6 +230,7 @@ VALUES (2003,'报价请求',2000,3,'rfq','bid/rfq/index',NULL,1,0,'C','0','0','bid:rfq:list','form','admin',NOW(),'','',''), (2004,'供应商报价',2000,4,'quotation','bid/quotation/index',NULL,1,0,'C','0','0','bid:quotation:list','money','admin',NOW(),'','',''), (2005,'智慧比价',2000,5,'comparison','bid/comparison/index',NULL,1,0,'C','0','0','bid:comparison:list','chart','admin',NOW(),'','',''), +(2051,'比价详情',2005,1,'detail','bid/comparison/detail',NULL,1,0,'C','1','0','bid:comparison:detail','#','admin',NOW(),'','',''), (2006,'采购单',2000,6,'purchaseorder','bid/purchaseorder/index',NULL,1,0,'C','0','0','bid:purchaseorder:list','shopping','admin',NOW(),'','',''), (2007,'供应商评价',2000,7,'evaluation','bid/evaluation/index',NULL,1,0,'C','0','0','bid:evaluation:list','star','admin',NOW(),'','',''), (2008,'订单异议',2000,8,'objection','bid/objection/index',NULL,1,0,'C','0','0','bid:objection:list','warning','admin',NOW(),'','',''), diff --git a/doc/数据库业务表结构分析报告.md b/doc/数据库业务表结构分析报告.md new file mode 100644 index 00000000..1f859591 --- /dev/null +++ b/doc/数据库业务表结构分析报告.md @@ -0,0 +1,497 @@ +# 福安德智慧报价平台 - 数据库业务表结构分析报告 + +> 文档版本: v1.0 +> 生成日期: 2025-05-27 +> 关联文档: [福安德智慧报价平台-完整开发方案.md](./福安德智慧报价平台-完整开发方案.md) + +--- + +## 一、概述 + +本报告对福安德智慧报价平台的数据库业务表结构进行全面分析,评估现有表结构是否满足开发方案中的业务需求,并指出缺失字段和建议优化项。 + +### 1.1 业务模块划分 + +根据开发方案,系统包含以下核心业务模块: + +1. **物料信息管理** - 基础数据层 +2. **供应商管理** - 供货商基础、历史报价、纠纷 +3. **报价请求(RFQ)** - 询价单管理 +4. **供应商报价** - 子报价单填写 +5. **智慧比价** - 报价对比分析 +6. **采购单管理** - 订单执行 +7. **供应商评价** - 绩效评估 +8. **订单异议** - 纠纷处理 +9. **交易记录** - 财务流水 + +--- + +## 二、业务表结构详细分析 + +### 2.1 物料分类表 (biz_material_category) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| category_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| category_name | VARCHAR(100) | NO | - | 分类名称 | ✅ | +| parent_id | BIGINT | YES | 0 | 父分类ID | ✅ | +| ancestors | VARCHAR(500) | YES | '' | 祖级列表 | ✅ | +| sort | INT | YES | 0 | 排序 | ✅ | +| status | CHAR(1) | YES | '0' | 状态 | ⚠️ 无注释 | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 80% | +| 缺失字段 | category_code(分类编码)、icon(图标)、level(层级) | +| 建议优化 | 补充字段注释 | + +--- + +### 2.2 物料表 (biz_material) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| material_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| category_id | BIGINT | YES | 0 | 分类ID | ✅ | +| material_code | VARCHAR(50) | NO | - | 物料编码 | ✅ | +| material_name | VARCHAR(200) | NO | - | 物料名称 | ✅ | +| spec | VARCHAR(500) | YES | '' | 规格型号 | ✅ | +| unit | VARCHAR(50) | YES | '' | 单位 | ✅ | +| brand | VARCHAR(100) | YES | '' | **厂家/品牌** | ✅ 已修改注释 | +| description | TEXT | YES | NULL | 描述 | ✅ | +| status | CHAR(1) | YES | '0' | 状态 | ⚠️ 无注释 | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | +| update_by | VARCHAR(64) | YES | '' | 更新者 | ⚠️ 无注释 | +| update_time | DATETIME | YES | NULL | 更新时间 | ⚠️ 无注释 | +| remark | VARCHAR(500) | YES | NULL | 备注 | ✅ | + +#### 二期扩展字段 (2026-05-27) + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| performance_params | TEXT | YES | NULL | 性能参数(JSON) | ✅ 新增 | +| material | VARCHAR(100) | YES | '' | 材质 | ✅ 新增 | +| purpose | VARCHAR(500) | YES | '' | 用途 | ✅ 新增 | +| image_url | VARCHAR(500) | YES | '' | 物料图片URL | ✅ 新增 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 95% | +| 已满足需求 | 物料ID、厂家/品牌、规格型号、性能参数、材质、用途、备注 | +| 建议优化 | 补充status、create_by等字段注释 | + +--- + +### 2.3 供应商表 (biz_supplier) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| supplier_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| supplier_name | VARCHAR(200) | NO | - | 供应商名称 | ✅ | +| contact | VARCHAR(50) | YES | '' | 联系人 | ⚠️ 无注释 | +| phone | VARCHAR(20) | YES | '' | 联系电话 | ⚠️ 无注释 | +| email | VARCHAR(100) | YES | '' | 邮箱 | ⚠️ 无注释 | +| address | VARCHAR(500) | YES | '' | 地址 | ⚠️ 无注释 | +| user_id | BIGINT | YES | NULL | 关联用户ID | ❌ 无注释,用途不明 | +| status | CHAR(1) | YES | '0' | 状态 | ⚠️ 无注释 | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | +| update_by | VARCHAR(64) | YES | '' | 更新者 | ⚠️ 无注释 | +| update_time | DATETIME | YES | NULL | 更新时间 | ⚠️ 无注释 | +| remark | VARCHAR(500) | YES | NULL | 备注 | ✅ | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 60% | +| **缺失字段** | 供应商编码、统一社会信用代码、开户银行、银行账号、合作状态、资质证书 | +| **需求不匹配** | 缺少"历史报价"、"纠纷"相关字段(应在关联表中) | +| 建议优化 | 补充所有字段注释;考虑增加供应商分类字段 | + +--- + +### 2.4 报价请求主表 (biz_rfq) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| rfq_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| rfq_no | VARCHAR(50) | NO | - | 询价单号 | ✅ | +| rfq_title | VARCHAR(200) | NO | - | 询价标题 | ✅ | +| deadline | DATETIME | YES | NULL | 截止日期 | ⚠️ 无注释 | +| delivery_addr | VARCHAR(500) | YES | '' | 交货地址 | ⚠️ 无注释 | +| status | VARCHAR(20) | YES | 'draft' | 状态 | ⚠️ 无注释 | +| remark | TEXT | YES | NULL | 备注 | ✅ | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | +| update_by | VARCHAR(64) | YES | '' | 更新者 | ⚠️ 无注释 | +| update_time | DATETIME | YES | NULL | 更新时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 70% | +| **缺失字段** | 询价类型、紧急程度、付款方式、税率、甲方ID、项目ID | +| **状态值不明确** | status字段应注释状态值: draft/published/closed/completed | +| 建议优化 | 补充字段注释;明确状态流转规则 | + +--- + +### 2.5 报价请求明细表 (biz_rfq_item) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| item_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| rfq_id | BIGINT | NO | - | 询价单ID | ✅ | +| material_id | BIGINT | YES | 0 | 物料ID | ✅ | +| material_name | VARCHAR(200) | NO | - | 物料名称 | ✅ | +| spec | VARCHAR(500) | YES | '' | 规格 | ⚠️ 无注释 | +| unit | VARCHAR(50) | YES | '' | 单位 | ⚠️ 无注释 | +| quantity | DECIMAL(15,4) | NO | - | 数量 | ⚠️ 无注释 | +| expected_price | DECIMAL(15,4) | YES | NULL | 期望单价 | ⚠️ 无注释 | +| remark | VARCHAR(500) | YES | '' | 备注 | ✅ | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 85% | +| **缺失字段** | 技术要求、质量标准、品牌要求、交货期要求 | +| 建议优化 | 补充字段注释 | + +--- + +### 2.6 询价供应商关联表 (biz_rfq_supplier) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| rfq_id | BIGINT | NO | - | 询价单ID | ✅ | +| supplier_id | BIGINT | NO | - | 供应商ID | ✅ | +| invited_time | DATETIME | YES | NULL | 邀请时间 | ⚠️ 无注释 | +| quoted_time | DATETIME | YES | NULL | 报价时间 | ⚠️ 无注释 | +| status | VARCHAR(20) | YES | 'pending' | 状态 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 75% | +| **缺失字段** | 邀请人、邀请方式、是否查看、查看时间 | +| **状态值不明确** | status字段应注释: pending/invited/quoted/rejected | +| 建议优化 | 补充字段注释;增加邀请记录追踪 | + +--- + +### 2.7 供应商报价单表 (biz_quotation) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| quotation_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| rfq_id | BIGINT | NO | - | 询价单ID | ✅ | +| supplier_id | BIGINT | NO | - | 供应商ID | ✅ | +| quote_no | VARCHAR(50) | YES | '' | 报价单号 | ⚠️ 无注释 | +| valid_days | INT | YES | 30 | 有效期(天) | ⚠️ 无注释 | +| delivery_days | INT | YES | 0 | 交货周期(天) | ⚠️ 无注释 | +| total_amount | DECIMAL(15,4) | YES | 0 | 总金额 | ⚠️ 无注释 | +| currency | VARCHAR(10) | YES | 'CNY' | 币种 | ⚠️ 无注释 | +| status | VARCHAR(20) | YES | 'draft' | 状态 | ⚠️ 无注释 | +| note | TEXT | YES | NULL | 备注 | ⚠️ 无注释 | +| submit_time | DATETIME | YES | NULL | 提交时间 | ⚠️ 无注释 | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | +| update_time | DATETIME | YES | NULL | 更新时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 70% | +| **缺失字段** | 报价有效期截止日期、付款方式、运费承担方、税率、是否含税 | +| **状态值不明确** | status字段应注释: draft/submitted/accepted/rejected | +| 建议优化 | 补充所有字段注释 | + +--- + +### 2.8 报价明细表 (biz_quotation_item) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| item_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| quotation_id | BIGINT | NO | - | 报价单ID | ✅ | +| rfq_item_id | BIGINT | NO | - | 询价明细ID | ✅ | +| material_name | VARCHAR(200) | YES | '' | 物料名称 | ⚠️ 无注释 | +| spec | VARCHAR(500) | YES | '' | 规格 | ⚠️ 无注释 | +| unit | VARCHAR(50) | YES | '' | 单位 | ⚠️ 无注释 | +| quantity | DECIMAL(15,4) | YES | 0 | 数量 | ⚠️ 无注释 | +| unit_price | DECIMAL(15,4) | NO | - | 单价 | ⚠️ 无注释 | +| total_price | DECIMAL(15,4) | YES | 0 | 总价 | ⚠️ 无注释 | +| delivery_days | INT | YES | 0 | 交货天数 | ⚠️ 无注释 | +| remark | VARCHAR(500) | YES | '' | 备注 | ✅ | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 80% | +| **缺失字段** | 品牌、产地、质保期、最小起订量、库存状态 | +| 建议优化 | 补充所有字段注释 | + +--- + +### 2.9 采购单主表 (biz_purchase_order) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| po_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| po_no | VARCHAR(50) | NO | - | 采购单号 | ✅ | +| rfq_id | BIGINT | YES | NULL | 询价单ID | ✅ | +| supplier_id | BIGINT | NO | - | 供应商ID | ✅ | +| total_amount | DECIMAL(15,4) | YES | 0 | 总金额 | ⚠️ 无注释 | +| currency | VARCHAR(10) | YES | 'CNY' | 币种 | ⚠️ 无注释 | +| delivery_addr | VARCHAR(500) | YES | '' | 交货地址 | ⚠️ 无注释 | +| delivery_date | DATE | YES | NULL | 交货日期 | ⚠️ 无注释 | +| status | VARCHAR(20) | YES | 'draft' | 状态 | ⚠️ 无注释 | +| remark | TEXT | YES | NULL | 备注 | ✅ | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | +| update_by | VARCHAR(64) | YES | '' | 更新者 | ⚠️ 无注释 | +| update_time | DATETIME | YES | NULL | 更新时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 65% | +| **缺失字段** | 合同编号、付款方式、付款比例、运费承担、税率、发票类型、联系人、联系电话 | +| **状态值不明确** | status字段应注释: draft/confirmed/shipped/received/completed | +| 建议优化 | 补充所有字段注释;增加订单执行跟踪字段 | + +--- + +### 2.10 采购单明细表 (biz_purchase_order_item) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| item_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| po_id | BIGINT | NO | - | 采购单ID | ✅ | +| material_id | BIGINT | YES | 0 | 物料ID | ✅ | +| material_name | VARCHAR(200) | NO | - | 物料名称 | ✅ | +| spec | VARCHAR(500) | YES | '' | 规格 | ⚠️ 无注释 | +| unit | VARCHAR(50) | YES | '' | 单位 | ⚠️ 无注释 | +| quantity | DECIMAL(15,4) | NO | - | 数量 | ⚠️ 无注释 | +| unit_price | DECIMAL(15,4) | NO | - | 单价 | ⚠️ 无注释 | +| total_price | DECIMAL(15,4) | YES | 0 | 总价 | ⚠️ 无注释 | +| remark | VARCHAR(500) | YES | '' | 备注 | ✅ | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 75% | +| **缺失字段** | 已到货数量、到货率、质检状态、入库状态 | +| 建议优化 | 补充字段注释;增加订单执行跟踪字段 | + +--- + +### 2.11 供应商评价表 (biz_supplier_evaluation) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| eval_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| po_id | BIGINT | NO | - | 采购单ID | ✅ | +| supplier_id | BIGINT | NO | - | 供应商ID | ✅ | +| quality_score | INT | YES | 5 | 质量评分 | ⚠️ 无注释 | +| delivery_score | INT | YES | 5 | 交货评分 | ⚠️ 无注释 | +| service_score | INT | YES | 5 | 服务评分 | ⚠️ 无注释 | +| price_score | INT | YES | 5 | 价格评分 | ⚠️ 无注释 | +| total_score | DECIMAL(3,1) | YES | 5.0 | 综合评分 | ⚠️ 无注释 | +| comment | TEXT | YES | NULL | 评价内容 | ⚠️ 无注释 | +| evaluator | VARCHAR(64) | YES | '' | 评价人 | ⚠️ 无注释 | +| eval_time | DATETIME | YES | NULL | 评价时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 75% | +| **缺失字段** | 评价周期、是否匿名、评价状态(草稿/已提交) | +| **评分范围不明确** | 应注释评分范围: 1-10分或1-5分 | +| 建议优化 | 补充所有字段注释;明确评分规则 | + +--- + +### 2.12 订单异议表 (biz_order_objection) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| objection_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| po_id | BIGINT | NO | - | 采购单ID | ✅ | +| supplier_id | BIGINT | NO | - | 供应商ID | ✅ | +| reason | TEXT | NO | - | 异议原因 | ⚠️ 无注释 | +| attachment | VARCHAR(500) | YES | '' | 附件 | ⚠️ 无注释 | +| status | VARCHAR(20) | YES | 'pending' | 状态 | ⚠️ 无注释 | +| resolution | TEXT | YES | NULL | 解决方案 | ⚠️ 无注释 | +| create_by | VARCHAR(64) | YES | '' | 创建者 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | +| resolve_time | DATETIME | YES | NULL | 解决时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 70% | +| **缺失字段** | 异议类型(质量/交期/数量/其他)、责任方、赔偿金额、关闭人、关闭时间 | +| **状态值不明确** | status字段应注释: pending/processing/resolved/closed | +| 建议优化 | 补充所有字段注释;完善异议处理流程 | + +--- + +### 2.13 交易记录表 (biz_transaction) + +#### 表结构 + +| 字段名 | 类型 | 可空 | 默认值 | 备注 | 需求匹配度 | +|--------|------|------|--------|------|-----------| +| tx_id | BIGINT | NO | AUTO_INCREMENT | 主键 | ✅ | +| tenant_id | BIGINT | NO | 1 | 租户ID | ✅ | +| po_id | BIGINT | YES | NULL | 采购单ID | ✅ | +| supplier_id | BIGINT | YES | NULL | 供应商ID | ✅ | +| tx_type | VARCHAR(50) | YES | '' | 交易类型 | ⚠️ 无注释 | +| tx_no | VARCHAR(50) | YES | '' | 交易单号 | ⚠️ 无注释 | +| amount | DECIMAL(15,4) | YES | NULL | 金额 | ⚠️ 无注释 | +| currency | VARCHAR(10) | YES | 'CNY' | 币种 | ⚠️ 无注释 | +| description | TEXT | YES | NULL | 描述 | ⚠️ 无注释 | +| operator | VARCHAR(64) | YES | '' | 操作人 | ⚠️ 无注释 | +| tx_time | DATETIME | YES | NULL | 交易时间 | ⚠️ 无注释 | +| create_time | DATETIME | YES | NULL | 创建时间 | ⚠️ 无注释 | + +#### 分析结论 + +| 评估项 | 结果 | +|--------|------| +| 需求满足度 | 60% | +| **缺失字段** | 交易对方账户、交易状态、凭证号、附件、审核人、审核时间 | +| **交易类型不明确** | tx_type应注释: payment/refund/deposit/withdrawal | +| 建议优化 | 补充所有字段注释;完善财务审核流程 | + +--- + +## 三、总体评估 + +### 3.1 各表需求满足度汇总 + +| 表名 | 需求满足度 | 主要问题 | +|------|-----------|---------| +| biz_material_category | 80% | 缺少分类编码、图标字段 | +| biz_material | 95% | 字段注释不完整 | +| biz_supplier | 60% | 缺少供应商编码、资质信息 | +| biz_rfq | 70% | 缺少询价类型、付款方式 | +| biz_rfq_item | 85% | 缺少技术要求、质量标准 | +| biz_rfq_supplier | 75% | 缺少邀请记录追踪 | +| biz_quotation | 70% | 缺少付款方式、运费承担 | +| biz_quotation_item | 80% | 缺少品牌、产地、质保期 | +| biz_purchase_order | 65% | 缺少合同信息、付款信息 | +| biz_purchase_order_item | 75% | 缺少到货跟踪字段 | +| biz_supplier_evaluation | 75% | 评分规则不明确 | +| biz_order_objection | 70% | 缺少异议类型、赔偿信息 | +| biz_transaction | 60% | 缺少交易状态、审核流程 | + +### 3.2 共性问题 + +1. **字段注释缺失严重** - 约70%的字段缺少注释 +2. **状态值不明确** - 所有status字段未注释状态值枚举 +3. **缺少关键业务字段** - 如付款方式、税率、发票类型等 +4. **缺少审计字段** - 部分表缺少update_by字段 + +### 3.3 建议优化项 + +#### 高优先级 (P0) +- [ ] 补充所有字段注释 +- [ ] 明确所有status字段的状态值枚举 +- [ ] 为biz_supplier添加供应商编码字段 + +#### 中优先级 (P1) +- [ ] 为biz_purchase_order添加合同信息字段 +- [ ] 为biz_transaction添加交易状态字段 +- [ ] 为biz_order_objection添加异议类型字段 + +#### 低优先级 (P2) +- [ ] 为biz_material_category添加分类编码 +- [ ] 为biz_quotation_item添加品牌、产地字段 +- [ ] 考虑增加数据版本控制字段 + +--- + +## 四、附录 + +### 4.1 相关文件 + +- 业务表SQL: `sql/bid_tables.sql` +- 物料扩展SQL: `sql/20260527/01_material_extension.sql` +- 开发方案: `doc/福安德智慧报价平台-完整开发方案.md` +- 物料开发文档: `doc/智采系统-物料信息模块开发文档.md` + +### 4.2 建议补充的通用字段 + +所有业务表建议补充以下字段: + +```sql +-- 数据版本控制 +version INT DEFAULT 1 COMMENT '数据版本号', + +-- 扩展字段(预留) +ext_field1 VARCHAR(500) COMMENT '扩展字段1', +ext_field2 VARCHAR(500) COMMENT '扩展字段2', + +-- 数据隔离 +dept_id BIGINT COMMENT '所属部门ID', + +-- 删除标记(物理删除场景) +delete_time DATETIME COMMENT '删除时间', +delete_by VARCHAR(64) COMMENT '删除人', +``` + +--- + +*报告生成完成,建议根据以上分析逐步优化数据库结构。* diff --git a/doc/智采系统-物料信息模块开发文档.md b/doc/智采系统-物料信息模块开发文档.md new file mode 100644 index 00000000..6ca6e228 --- /dev/null +++ b/doc/智采系统-物料信息模块开发文档.md @@ -0,0 +1,868 @@ +# 智采系统-物料信息模块开发文档 + +> 文档版本: v1.1 +> 创建日期: 2025-05-27 +> 关联文档: [福安德智慧报价平台-完整开发方案.md](./福安德智慧报价平台-完整开发方案.md) + +--- + +## 一、需求概述 + +### 1.1 功能定位 +智采系统-物料信息模块是整个报价平台的基础数据层,负责管理所有物料的基础信息、性能参数、历史报价记录。 + +### 1.2 核心功能 +- **物料信息管理**: 挂载于物料类型下,支持汇总和CRUD操作 +- **物料详情展示**: 基础信息展示,支持动态更新 +- **历史报价查询**: + - 供应商历史报价清单(单价、供应商) + - 我方给甲方的历史报价 + +### 1.3 字段需求 +根据业务需求,物料信息需要以下字段: + +| 需求字段 | 对应数据库字段 | 说明 | +|---------|--------------|------| +| 物料ID | material_id | 主键,自增 | +| **厂家/品牌** | **brand** | **改为"厂家/品牌"** | +| 规格型号 | spec | 规格型号(**保持不变**) | +| 性能参数 | performance_params | JSON格式存储(**新增**) | +| 材质 | material | 材质(铜/铝合金/PVC等)(**新增**) | +| 用途 | purpose | 用途描述(**新增**) | +| 备注 | remark | 备注(**保持不变**) | + +--- + +## 二、数据库设计 + +### 2.1 现有表结构(保持不变) + +```sql +CREATE TABLE `biz_material` ( + `material_id` bigint NOT NULL AUTO_INCREMENT, + `tenant_id` bigint NOT NULL DEFAULT '1', + `category_id` bigint DEFAULT '0', + `material_code` varchar(50) NOT NULL COMMENT '物料编码', + `material_name` varchar(200) NOT NULL COMMENT '物料名称', + `spec` varchar(500) DEFAULT '' COMMENT '规格型号', + `unit` varchar(50) DEFAULT '' COMMENT '单位', + `brand` varchar(100) DEFAULT '' COMMENT '品牌', + `description` text COMMENT '描述', + `status` char(1) DEFAULT '0', + `create_by` varchar(64) DEFAULT '', + `create_time` datetime DEFAULT NULL, + `update_by` varchar(64) DEFAULT '', + `update_time` datetime DEFAULT NULL, + `remark` varchar(500) DEFAULT NULL, + PRIMARY KEY (`material_id`) +) ENGINE=InnoDB COMMENT='物料'; +``` + +### 2.2 扩展字段 + +执行SQL文件: [sql/20250527/01_material_alter.sql](../sql/20250527/01_material_alter.sql) + +```sql +-- 新增字段 +ALTER TABLE biz_material + ADD COLUMN IF NOT EXISTS performance_params TEXT COMMENT '性能参数(JSON)', + ADD COLUMN IF NOT EXISTS material VARCHAR(100) DEFAULT '' COMMENT '材质', + ADD COLUMN IF NOT EXISTS purpose VARCHAR(500) DEFAULT '' COMMENT '用途', + ADD COLUMN IF NOT EXISTS image_url VARCHAR(500) DEFAULT '' COMMENT '物料图片URL'; + +-- 修改brand字段为"厂家/品牌" +ALTER TABLE biz_material MODIFY COLUMN brand VARCHAR(100) COMMENT '厂家/品牌'; +``` + +### 2.3 横向对比关系表 + +用于存储物料之间的对比关系(不同品牌、规格的同比信息): + +```sql +CREATE TABLE biz_material_comparison ( + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID', + material_id BIGINT NOT NULL COMMENT '当前物料ID', + counterpart_id BIGINT NOT NULL COMMENT '对标物料ID', + comparison_type VARCHAR(50) DEFAULT 'same_spec' COMMENT '对比类型(same_spec:同规格, similar:相似规格)', + brand_level VARCHAR(50) COMMENT '品牌等级(国产一线/国产二线/进口一线/进口二线)', + sort_order INT DEFAULT 0 COMMENT '排序', + status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)', + create_by VARCHAR(64) DEFAULT '' COMMENT '创建者', + create_time DATETIME COMMENT '创建时间', + update_by VARCHAR(64) DEFAULT '' COMMENT '更新者', + update_time DATETIME COMMENT '更新时间', + remark VARCHAR(500) COMMENT '备注', + UNIQUE KEY uk_material_counterpart (material_id, counterpart_id), + KEY idx_material (material_id), + KEY idx_counterpart (counterpart_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料横向对比关系'; +``` + +**表设计说明**: +- 不采用"对比组"模式,而是直接建立物料之间的对比关系,更灵活 +- 支持同规格对比和相似规格对比 +- 可维护品牌等级,用于综合评分 +- 通过唯一索引防止重复添加对标物料 + +### 2.3 字段对照说明 + +| 原字段 | 原含义 | 新含义 | 说明 | +|--------|--------|--------|------| +| spec | 规格型号 | **规格型号** | **保持不变** | +| **brand** | **品牌** | **厂家/品牌** | **修改注释** | +| remark | 备注 | **备注** | **保持不变** | +| performance_params | - | 性能参数 | 新增 | +| material | - | 材质 | 新增 | +| purpose | - | 用途 | 新增 | +| image_url | - | 物料图片URL | 新增 | + +### 2.4 性能参数JSON规范 + +```json +// 变频器示例 +{ + "功率": "37kW", + "电压": "380V", + "电流": "72A", + "过载能力": "150%/60s", + "通讯接口": "RS485/PROFINET", + "防护等级": "IP20" +} + +// 电缆示例 +{ + "芯数×截面": "3×70+1×35", + "额定电压": "0.6/1kV", + "外径": "42mm", + "载流量": "210A", + "护套材质": "PVC铠装" +} + +// PLC示例 +{ + "CPU型号": "1515-2 PN", + "内存": "500KB", + "数字量输入": "1024", + "数字量输出": "1024", + "通讯接口": "PROFINET" +} +``` + +--- + +## 三、页面设计 + +### 3.1 物料信息列表页 + +#### 3.1.1 页面布局 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 智采系统-物料信息 [返回首页] │ +├─────────────────────────────────────────────────────────────┤ +│ 挂载于物料类型下面的物料信息在此进行汇总和CRUD │ +├─────────────────────────────────────────────────────────────┤ +│ 搜索栏: [物料名称] [物料编码] [厂家/品牌] [分类] [搜索] [重置]│ +├─────────────────────────────────────────────────────────────┤ +│ [新增] [删除] [导入] [导出] │ +├─────────────────────────────────────────────────────────────┤ +│ □ | 物料ID | 厂家/品牌 | 规格型号 | 性能参数 | 材质 | 用途 | 操作 │ +│ ───────────────────────────────────────────────────────── │ +│ □ | M001 | 汇川 | MD500T37G | 37kW... | 铜 | 通用 | [详情][修改][删除] │ +│ □ | M002 | 西门子 | G120 | 37kW... | 铝 | 风机 | [详情][修改][删除] │ +├─────────────────────────────────────────────────────────────┤ +│ 分页: 1 2 3 ... 10 │ +└─────────────────────────────────────────────────────────────┘ +``` + +#### 3.1.2 表格字段 + +| 字段 | 宽度 | 对应字段 | 说明 | +|------|------|---------|------| +| 复选框 | 55px | - | 批量操作 | +| 物料ID | 100px | material_id | - | +| **厂家/品牌** | 120px | **brand** | **改为"厂家/品牌"** | +| **规格型号** | 150px | **spec** | **保持不变** | +| 性能参数 | 200px | performance_params | 截取显示 | +| 材质 | 80px | material | 新增 | +| 用途 | 150px | purpose | 新增 | +| 操作 | 180px | - | 详情/修改/删除 | + +#### 3.1.3 操作按钮 + +- **详情**: 跳转到物料详情页 +- **修改**: 打开编辑对话框 +- **删除**: 删除物料(逻辑删除) + +### 3.2 新增/编辑对话框 + +``` +┌─────────────────────────────────────────┐ +│ 新增物料 / 修改物料 │ +├─────────────────────────────────────────┤ +│ 物料编码* [________________] │ +│ 物料名称* [________________] │ +│ 所属分类 [下拉选择________] │ +├─────────────────────────────────────────┤ +│ 厂家/品牌* [________________] │ ← brand字段(改为"厂家/品牌") +│ 规格型号* [________________] │ ← spec字段(保持不变) +│ 备注 [________________] │ ← remark字段(保持不变) +│ 材质 [________________] │ ← material字段(新增) +│ 用途 [________________] │ ← purpose字段(新增) +├─────────────────────────────────────────┤ +│ 性能参数 (动态表单) │ +│ ┌─────────┬─────────┬───────┐ [添加] │ +│ │ 参数名 │ 参数值 │ 单位 │ │ +│ │ [功率] │ [37] │ [kW] │ [删除] │ +│ │ [电压] │ [380] │ [V] │ [删除] │ +│ └─────────┴─────────┴───────┘ │ +├─────────────────────────────────────────┤ +│ 描述 [多行文本框____________] │ ← description字段 +├─────────────────────────────────────────┤ +│ [取消] [确定] │ +└─────────────────────────────────────────┘ +``` + +### 3.3 物料详情页 + +#### 3.3.1 整体布局(重新设计) + +页面分为上下两部分: +- **上半部分**: 可编辑的基础信息(物料编码、厂家/品牌、规格型号等 + 性能参数 + 描述) +- **下半部分**: Tab切换(供应商报价历史、甲方报价历史) + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 明纬/西门子 电源模块 24VDC/10A,输入85-264VAC,效率≥90% [返回列表] │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 基础信息 [编辑] [保存] [取消] │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────┐│ +│ │ 物料编码 │ M-EL-006 │ 厂家/品牌 │ 明纬/西门子│ 规格型号 │ 24VDC/10A...│ +│ ├────────────┼────────────┼────────────┼────────────┼────────────┼────────┤│ +│ │ 材质 │ - │ 用途 │ - │ 备注 │ - │ +│ │ 单位 │ 台 │ 所属分类 │ 电源模块 │ │ │ +│ └────────────┴────────────┴────────────┴────────────┴────────────┴────────┘│ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 性能参数 [添加] │ +│ ┌────────────────┬──────────────────────────────┬────────────────┬────────┐│ +│ │ 参数名 │ 参数值 │ 单位 │ 操作 ││ +│ ├────────────────┼──────────────────────────────┼────────────────┼────────┤│ +│ │ 输出电压 │ 24VDC │ V │ [删除] ││ +│ │ 输出电流 │ 10 │ A │ [删除] ││ +│ │ ... │ ... │ ... │ ... ││ +│ └────────────────┴──────────────────────────────┴────────────────┴────────┘│ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 描述 │ +│ ┌────────────────────────────────────────────────────────────────────────┐│ +│ │ 明纬/西门子 电源模块 24VDC/10A,输入85-264VAC,效率≥90% ││ +│ └────────────────────────────────────────────────────────────────────────┘│ +├─────────────────────────────────────────────────────────────────────────────┤ +│ [供应商报价历史] [甲方报价历史] │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ Tab 内容区域(报价历史表格) │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +**布局说明**: +- **顶部标题栏**: 显示物料名称和规格型号,右侧返回按钮 +- **基础信息区域**: 紧凑的网格布局,一行4个字段,可直接编辑 +- **性能参数区域**: 表格形式展示,支持增删改 +- **描述区域**: 文本区域展示,支持编辑 +- **Tab区域**: 仅保留供应商报价历史和甲方报价历史两个Tab + +**组件实现**: [detail.vue](../ruoyi-ui/src/views/bid/material/detail.vue) + +**核心功能**: +1. **基础信息网格布局**: 紧凑的flex布局,一行显示多个字段 +2. **实时编辑**: 点击"编辑"按钮,所有字段变为可编辑状态 +3. **实时保存**: 点击"保存"调用API,更新本地数据,无需刷新页面 +4. **性能参数表格**: 支持添加/删除参数 +5. **描述区域**: 多行文本编辑 + +**数据结构**: +```javascript +// 表单数据 +form: { + materialCode: 'M-EL-006', + materialName: '电源模块', + brand: '明纬/西门子', + spec: '24VDC/10A...', + unit: '台', + material: '', + purpose: '', + remark: '', + description: '明纬/西门子 电源模块...' +} + +// 性能参数数据 +perfParams: [ + { name: '输出电压', value: '24VDC', unit: 'V' }, + { name: '输出电流', value: '10', unit: 'A' } +] +``` + +**保存逻辑**: +```javascript +async handleSave() { + const saveData = { + materialId: this.materialId, + ...this.form, + performanceParams: JSON.stringify(this.perfParams) + }; + + await updateMaterial(saveData); + this.$message.success("保存成功"); + this.isEditing = false; + + // 更新本地数据(无需刷新页面) + this.material = { ...this.material, ...saveData }; +} +``` + // ... +] + +// 性能参数数据 +perfParams: [ + { name: '输出电压', value: '24VDC', unit: 'V' }, + { name: '输出电流', value: '10', unit: 'A' }, + // ... +] + +// 描述数据 +description: '明纬/西门子 电源模块 24VDC/10A...' +``` + +**保存逻辑**: +```javascript +async handleSave() { + const saveData = { + materialId: this.material.materialId, + materialCode: this.basicInfoData[0].value, + materialName: this.basicInfoData[1].value, + // ... 其他字段 + performanceParams: JSON.stringify(this.perfParams), + description: this.description + }; + + await updateMaterial(saveData); + this.$message.success("保存成功"); + this.isEditing = false; + + // 更新本地数据(无需刷新页面) + this.$emit('update:material', { ...this.material, ...saveData }); +} +``` + +#### 3.3.3 Tab 2: 供应商报价历史 + +供应商信息完整展示,调整列宽使内容在一行显示: + +``` +┌─────────────────────────────────────────────────────────────────────────────────────────┐ +│ 供应商报价历史 [导出Excel] │ +├─────────────────────────────────────────────────────────────────────────────────────────┤ +│ 报价日期 │ 供应商信息 │ 单价(元) │ 数量 │ 交期 │ 状态 │ +│ ───────────────────────────────────────────────────────────────────────────────────── │ +│ 2026-05-20 │ 华顺达电子科技有限公司 │ ¥6,200.00 │ 5 │ 7天 │ [已中标] │ +│ │ 联系人: 张经理 13800138000│ │ │ │ │ +│ ───────────────────────────────────────────────────────────────────────────────────── │ +│ 2026-05-18 │ 博远精密机械有限公司 │ ¥6,500.00 │ 5 │ 10天 │ [未中标] │ +│ │ 联系人: 李工 13900139000 │ │ │ │ │ +│ ───────────────────────────────────────────────────────────────────────────────────── │ +│ 2026-05-15 │ 瑞达工控设备有限公司 │ ¥6,800.00 │ 5 │ 5天 │ [未中标] │ +│ │ 联系人: 王总 13700137000 │ │ │ │ │ +└─────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +**表格列宽配置**: +| 列名 | 宽度 | 说明 | +|------|------|------| +| 报价日期 | 100px | 日期格式:YYYY-MM-DD | +| 供应商信息 | 280px | 供应商名称+联系人+电话,完整一行展示 | +| 单价 | 120px | 右对齐,保留2位小数 | +| 数量 | 80px | 居中对齐 | +| 交期 | 80px | 居中对齐,带单位"天" | +| 状态 | 100px | 标签形式展示 | + +**Vue组件实现**: +```vue + + + +``` + +**数据来源**: `biz_quotation_item` → `biz_quotation` → `biz_supplier` + +#### 3.3.4 Tab 3: 甲方报价历史 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 我方给甲方的历史报价 [导出Excel] │ +├─────────────────────────────────────────────────────────────┤ +│ 报价日期 甲方名称 单价(元) 折扣率 成交价 状态 │ +│ ───────────────────────────────────────────────────────── │ +│ 2026-05-25 福安德科技 ¥8,000 95% ¥7,600 已接受│ +│ 2026-05-22 福安德科技 ¥8,200 90% ¥7,380 已拒绝│ +│ 2026-04-15 某某自动化 ¥8,500 100% ¥8,500 已接受│ +└─────────────────────────────────────────────────────────────┘ +``` + +**数据来源**: `biz_client_quote_item` → `biz_client_quote` + +#### 3.3.5 同品类物料横向对比(基于供应商报价) + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 同品类物料横向对比 3个物料 │ +│ [选择对比物料(仅显示有报价的物料)... ] │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ +│ │ PLC控制器 │ │ 变频器 │ │ +│ │ CPU模块... / 西门子S7-1200 │ │ 三相380V... / ABB/西门子 │ │ +│ │ 3家报价 │ │ 2家报价 │ │ +│ ├─────────────────────────────┤ ├─────────────────────────────┤ │ +│ │ 规格型号 │ CPU模块... │ │ 规格型号 │ 三相380V... │ │ +│ │ 厂家/品牌│ 西门子S7-1200 │ │ 厂家/品牌│ ABB/西门子 │ │ +│ │ 材质 │ — │ │ 材质 │ — │ │ +│ │ 单位 │ 套 │ │ 单位 │ 台 │ │ +│ ├─────────────────────────────┤ ├─────────────────────────────┤ │ +│ │ ───── 供应商报价明细 ───── │ │ ───── 供应商报价明细 ───── │ │ +│ ├─────────────────────────────┤ ├─────────────────────────────┤ │ +│ │ 供应商 单价 交期 │ │ 供应商 单价 交期 │ │ +│ │ 广州联盟... ¥3,020 30天 │ │ 华顺达... ¥6,200 7天 │ │ +│ │ 深圳华顺... ¥3,180 25天 │ │ 博远... ¥6,500 10天 │ │ +│ │ 上海瑞达... ¥3,450 20天 │ │ │ │ +│ ├─────────────────────────────┤ ├─────────────────────────────┤ │ +│ │ 最低¥3020 │ 最高¥3450 │ │ 最低¥6200 │ 最高¥6500 │ │ +│ │ 均价¥3216 │ 价差¥430(+14.2%)│ │ 均价¥6350 │ 价差¥300(+4.8%) │ │ +│ └─────────────────────────────┘ └─────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +**功能说明**: +- **自动加载**: 进入页面自动加载同品类有报价的物料,默认选中前3个 +- **实时更新**: 选择框变更时即时加载对应报价明细 +- **视觉区分**: 基础信息区域(浅蓝背景)与供应商报价区域(白色背景)通过分隔线明确区分 +- **报价排序**: 按单价从低到高排序,最低价绿色高亮并标记"最低"标签 +- **统计汇总**: 每个物料卡片底部展示最低价、最高价、均价、价差百分比 +- **错误处理**: 加载失败显示错误提示和重试按钮 +- **响应式**: 适配桌面端、平板和手机屏幕 + +**交互流程**: +1. 用户进入物料详情页 → 系统自动加载同品类物料列表 +2. 默认选中前3个物料 → 自动加载这些物料的供应商报价明细 +3. 用户可在选择框中增删物料 → 报价明细实时更新 +4. 加载过程中显示loading状态 → 失败显示错误提示和重试按钮 + +**数据来源**: +- 物料信息: `biz_material` +- 供应商报价: `biz_quotation_item` + `biz_quotation` + `biz_supplier` +- 关联关系: `biz_rfq_item` (物料与报价明细的关联) + +--- + +## 四、后端API设计 + +### 4.1 物料管理API + +| 接口 | 方法 | 说明 | 权限 | +|------|------|------|------| +| `/bid/material/list` | GET | 物料列表 | bid:material:list | +| `/bid/material/{id}` | GET | 物料详情 | bid:material:query | +| `/bid/material` | POST | 新增物料 | bid:material:add | +| `/bid/material` | PUT | 修改物料 | bid:material:edit | +| `/bid/material/{id}` | DELETE | 删除物料 | bid:material:remove | + +### 4.2 物料详情API + +| 接口 | 方法 | 说明 | 权限 | +|------|------|------|------| +| `/bid/material/{id}/detail` | GET | 物料完整详情(含性能参数) | bid:material:detail | +| `/bid/material/{id}/supplier-quotes` | GET | 供应商历史报价清单 | bid:material:supplierQuotes | +| `/bid/material/{id}/client-quotes` | GET | 甲方历史报价清单 | bid:material:clientQuotes | +| `/bid/material/{id}/comparison` | GET | 横向对比信息 | bid:material:comparison | + +### 4.3 同名称物料横向对比API(基于物料名称精确匹配) + +| 接口 | 方法 | 说明 | 权限 | 备注 | +|------|------|------|------|------| +| `/bid/material/same-name/{materialName}` | GET | 按名称精确匹配查询物料 | bid:material:list | 返回名称相同但规格/品牌不同的物料(含无报价) | +| `/bid/material/quote-comparison` | POST | 获取物料报价对比明细 | bid:material:list | 根据物料ID列表返回各供应商报价 | + +**GET /bid/material/same-name/{materialName}?excludeId=1** 响应示例: +```json +[ + { + "materialId": 2, + "materialName": "PLC控制器", + "spec": "CPU模块,数字量I/O 40点,以太网接口", + "brand": "西门子S7-1200", + "material": "", + "purpose": "", + "unit": "套", + "categoryName": "控制器" + }, + { + "materialId": 3, + "materialName": "PLC控制器", + "spec": "CPU模块,数字量I/O 64点,以太网接口", + "brand": "三菱FX5U", + "material": "", + "purpose": "", + "unit": "套", + "categoryName": "控制器" + } +] +``` + +**POST /bid/material/quote-comparison** 请求/响应示例: +```json +// 请求 +[1, 2, 3] + +// 响应 +[ + { + "material_id": 1, + "unit_price": 6200.00, + "total_price": 31000.00, + "delivery_days": 7, + "quotation_id": 101, + "quote_no": "Q20250520001", + "submit_time": "2026-05-20T10:30:00", + "quote_status": "2", + "supplier_id": 5, + "supplier_name": "华顺达电子科技有限公司", + "supplier_contact": "张经理", + "supplier_phone": "13800138000" + } +] +``` + +### 4.4 横向对比管理API(可维护对标关系) + +| 接口 | 方法 | 说明 | 权限 | +|------|------|------|------| +| `/bid/material/comparison` | GET | 查询对比组列表 | bid:comparison:list | +| `/bid/material/comparison` | POST | 添加对标物料 | bid:comparison:add | +| `/bid/material/comparison/{id}` | PUT | 修改对标信息 | bid:comparison:edit | +| `/bid/material/comparison/{id}` | DELETE | 删除对标物料 | bid:comparison:remove | +| `/bid/material/comparison/recommend` | GET | 获取智能推荐 | bid:comparison:recommend | + +--- + +## 五、前端组件设计 + +### 5.1 目录结构 + +``` +src/views/bid/material/ +├── index.vue # 物料列表页 +├── detail.vue # 物料详情页(主框架) +└── components/ + ├── DetailHeader.vue # 顶部信息卡片 + ├── BasicInfoTab.vue # Tab1: 基础信息 + ├── SupplierQuoteTab.vue # Tab2: 供应商报价 + ├── ClientQuoteTab.vue # Tab3: 甲方报价 + └── ComparisonTab.vue # Tab4: 横向对比 +``` + +### 5.2 关键组件说明 + +#### 5.2.1 性能参数动态表单 + +```vue + +``` + +#### 5.2.2 横向对比组件 (ComparisonTab.vue) + +```vue + + + + + +``` + +--- + +## 六、实现优先级 + +| 优先级 | 任务 | 涉及文件 | 预计工时 | +|--------|------|---------|---------| +| P0 | 数据库字段扩展 | `sql/20250527/01_material_alter.sql` | 0.5h | +| P0 | 物料列表页字段更新 | `material/index.vue` | 2h | +| P0 | 新增/编辑表单更新 | `material/index.vue` 对话框 | 3h | +| P1 | 性能参数动态表单组件 | `components/PerformanceParamsForm.vue` | 3h | +| P1 | 物料详情页框架 | `material/detail.vue` | 4h | +| P1 | Tab 1: 基础信息 | `components/BasicInfoTab.vue` | 2h | +| P1 | Tab 2: 供应商历史报价 | `components/SupplierQuoteTab.vue` | 3h | +| P2 | Tab 3: 甲方历史报价 | `components/ClientQuoteTab.vue` | 3h | +| P2 | Tab 4: 横向对比 | `components/ComparisonTab.vue` | 4h | +| P2 | 横向对比管理功能 | 添加/编辑/删除对标物料 | 3h | +| P3 | 智能推荐算法 | 综合评分计算 | 2h | +| P3 | 后端API实现 | `BizMaterialController.java` | 4h | + +**总计**: 约 33.5 工时 + +--- + +## 七、注意事项 + +1. **数据迁移**: 执行SQL脚本前请备份数据库 +2. **字段变更**: + - `spec` 字段保持为"规格型号",**不变更** + - `brand` 字段改为"厂家/品牌",**变更注释** + - `remark` 字段保持为"备注",**不变更** +3. **JSON存储**: 性能参数使用JSON格式,便于灵活扩展 +4. **权限控制**: 详情页需要单独配置菜单权限 +5. **图片上传**: 物料图片使用单独的上传接口,存储URL + +--- + +## 八、相关文件 + +- SQL脚本: `sql/20250527/01_material_alter.sql` +- 开发文档: `doc/智采系统-物料信息模块开发文档.md` +- 完整方案: `doc/福安德智慧报价平台-完整开发方案.md` diff --git a/doc/福安德智慧报价平台-完整开发方案.md b/doc/福安德智慧报价平台-完整开发方案.md new file mode 100644 index 00000000..439f7ea7 --- /dev/null +++ b/doc/福安德智慧报价平台-完整开发方案.md @@ -0,0 +1,957 @@ +# 福安德智慧报价平台 — 完整开发方案 + +> 基于 RuoYi-Vue v3.9.2 (Spring Boot 4.0.3 + JDK 17 + Vue 2 + Element UI) +> 融合 PPT《报价比对系统》5大板块 + XLSX《电气自动化设备综合管理系统_V1》27个Sheet数据 +> 对接现有项目12个已完成模块 + +--- + +## 目录 + +- [一、项目全景与数据资产](#一项目全景与数据资产) +- [二、板块一:物料信息](#二板块一物料信息) +- [三、板块二:物料详情](#三板块二物料详情) +- [四、板块三:供应商管理](#四板块三供应商管理) +- [五、板块四:报价商门户(供应商端)](#五板块四报价商门户供应商端) +- [六、板块五:甲方报价单](#六板块五甲方报价单) +- [七、报价单管理与指派系统](#七报价单管理与指派系统) +- [八、电气设备数据初始化方案](#八电气设备数据初始化方案) +- [九、开发优先级与里程碑](#九开发优先级与里程碑) +- [十、关键接口清单](#十关键接口清单) +- [十一、权限与安全设计](#十一权限与安全设计) + +--- + +## 一、项目全景与数据资产 + +### 1.1 PPT五大板块映射 + +| PPT板块 | 对应功能 | 现有进度 | 开发类型 | +|---------|---------|---------|---------| +| 智采系统-物料信息 | 物料CRUD + 分类树 + 性能参数JSON | `biz_material` 已有基础字段 | 扩展增强 | +| 智采系统-物料详情 | 详情页 + 3个Tab(历史报价/甲方报价/同比) | 未开发 | 新建 | +| 智采系统-供应商管理 | 供货清单 + 报价单管理 + 指派界面 | `biz_supplier` 已有基础 | 扩展增强 | +| 智采系统-报价商 | 供应商门户(已报项/可报项/报价界面) | 未开发 | 新建 | +| 给甲方报价单 | 子RFQ拆解 + 成本回填 + 历史版本 + 横向对比 | `biz_client_quote` 基础已有 | 核心增强 | + +### 1.2 XLSX数据资产清单 + +Excel中包含了完整的电气设备业务数据,共27个Sheet: + +| Sheet | 名称 | 行数 | 用途 | +|-------|------|------|------| +| 1 | 00_导航首页 | 24 | 系统导航和功能入口说明 | +| 2 | 01_项目报价单(fad给甲方) | 52 | 甲方报价模板(含品牌/型号/数量/折扣率) | +| 3 | 02_报价汇总 | 27 | 按类汇总 + 加价系数 + 对外报价 | +| 4 | 10_变频器比价 | 48 | 汇川/禾望/西门子/ABB 三家比价 | +| 5 | 11_整流单元比价 | 37 | 整流/制动/回馈单元比价 | +| 6 | 12_PLC比价 | 15 | CPU+模块比价 | +| 7 | 13_低压电器比价 | 22 | 断路器/接触器/热继电器比价 | +| 8 | 14_电缆线槽比价 | 25 | 电缆/控制线/线槽综合比价 | +| 9-19 | 20_变频器型号库 ~ 30_网关型号库 | 321+ | 全品类型号数据库 | +| 20 | 31_品牌汇总 | 22 | 各品牌型号数量统计 | + +### 1.3 核心业务流程 + +``` +甲方需求 → 创建甲方报价单 → 拆解为内部RFQ(子报价单) + → 指派供应商(可报项) → 供应商报价 → 比价选择 + → 成本回填甲方报价单 → 生成最终甲方报价 → 甲方确认 + → 生成采购单 → 交付 → 评价/异议处理 +``` + +--- + +## 二、板块一:物料信息 + +### 2.1 现有基础 + +`biz_material` 表已有字段: +- `material_id`, `tenant_id`, `category_id`, `material_code`, `material_name` +- `spec`, `unit`, `brand`, `description` +- `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark` + +### 2.2 扩展字段 + +```sql +ALTER TABLE biz_material ADD COLUMN ( + -- PPT要求字段 + manufacturer VARCHAR(100) COMMENT '厂家/品牌(与brand一致,作为冗余筛选)', + model_size VARCHAR(200) COMMENT '型号/尺寸(如MD500T37G, TMY-60×6)', + performance_params TEXT COMMENT '性能参数(JSON格式: {"功率":"37kW","电压":"380V"})', + material VARCHAR(100) COMMENT '材质(铜/铝合金/PVC等)', + purpose VARCHAR(500) COMMENT '用途(如"通用负载","风机水泵")', + remarks TEXT COMMENT '备注', + category_tree_path VARCHAR(500) COMMENT '分类路径(冗余,如"1/5/23")', + spec_comparison_group VARCHAR(100) COMMENT '横向对比分组标识', + + -- 扩展业务字段 + min_stock INT DEFAULT 0 COMMENT '最低库存预警', + unit_weight DECIMAL(10,4) COMMENT '单重(kg)', + image_url VARCHAR(500) COMMENT '物料图片', + data_source VARCHAR(20) DEFAULT 'manual' COMMENT '数据来源(manual/import/excel)', + version INT DEFAULT 1 COMMENT '乐观锁版本号' +); + +-- 型号唯一索引(防止重复录入同规格物料) +ALTER TABLE biz_material ADD UNIQUE INDEX idx_model_manufacturer (manufacturer, model_size); +``` + +### 2.3 性能参数JSON规范 + +性能参数使用JSON格式存储,前端动态渲染为键值对表格: + +```json +// 变频器示例 +{ + "功率": "37kW", + "电压": "380V", + "电流": "72A", + "过载能力": "150%/60s", + "通讯接口": "RS485/PROFINET", + "防护等级": "IP20" +} + +// 电缆示例 +{ + "芯数×截面": "3×70+1×35", + "额定电压": "0.6/1kV", + "外径": "42mm", + "载流量": "210A", + "护套材质": "PVC铠装" +} +``` + +**前端组件**:使用Element UI动态表单(`el-form` + `el-table`),每行=参数名+参数值+单位,支持增删行。保存时组装为JSON字符串,读取时`JSON.parse`后渲染为只读表格。 + +### 2.4 前端页面结构 + +``` +物料信息列表页 (/bid/material) +├── 左侧:物料分类树 (复用 biz_material_category) +│ ├── 树节点点击 → 右侧表格过滤 +│ └── 面包屑导航(基于category_tree_path) +├── 右侧:物料表格 +│ ├── 顶部筛选栏 +│ │ ├── 厂家下拉(去重,从manufacturer字段DISTINCT) +│ │ ├── 型号模糊搜索(输入前缀智能联想) +│ │ ├── 分类级联选择器 +│ │ └── 关键词搜索 +│ ├── 表格列:编码 | 名称 | 厂家 | 型号 | 材质 | 用途 | 单位 | 操作 +│ └── 操作按钮:详情 | 编辑 | 删除 | 加入对比篮 +└── 新增/编辑对话框(抽屉形式) + ├── 基础信息(名称/分类/厂家/型号/材质/用途/单位) + ├── 性能参数动态表单(支持增删行) + ├── 规格明细(可扩展多规格) + └── 图片上传(物料图/铭牌) +``` + +### 2.5 后端接口扩展 + +在 `BizMaterialController` 中新增: + +| 接口 | 方法 | 说明 | +|------|------|------| +| `/bid/material/detail/{id}` | GET | 物料详情(含性能参数解析+历史报价摘要) | +| `/bid/material/manufacturer/list` | GET | 厂家下拉列表(去重) | +| `/bid/material/import` | POST | Excel批量导入(EasyExcel解析) | +| `/bid/material/export` | GET | 导出为Excel模板 | +| `/bid/material/suggest` | GET | 型号智能联想(q参数前缀匹配) | +| `/bid/material/comparison-group/{groupId}` | GET | 按对比组获取物料 | + +--- + +## 三、板块二:物料详情 + +### 3.1 页面架构 + +采用"1+N"信息架构——1个基础信息区 + N个动态关联Tab: + +``` +物料详情页 (/bid/material/detail/:id) +├── 顶部基础信息卡片(两栏) +│ ├── 左栏(16/24):基础信息表(物料ID/厂家/型号/材质/用途) +│ │ └── 性能参数表格(从JSON动态渲染) +│ └── 右栏(8/24):价格趋势ECharts迷你折线图 +│ └── 近6个月最低报价走势(从biz_quotation_item聚合) +├── Tab 1:供应商历史报价清单 +├── Tab 2:我方给甲方的历史报价 +└── Tab 3:不同品牌/规格同比 +``` + +### 3.2 Tab 1:供应商历史报价清单 + +**数据来源**:`biz_quotation_item` → `biz_quotation` → `biz_supplier` + +**展示字段**: +| 字段 | 说明 | +|------|------| +| 报价日期 | biz_quotation.submit_time | +| 供应商名称 | biz_supplier.supplier_name | +| 单价(元) | biz_quotation_item.unit_price | +| 数量 | biz_quotation_item.quantity | +| 交期(周) | biz_quotation_item.delivery_days / 7 | +| 报价单号 | biz_quotation.quote_no | +| 操作 | 查看详情(点击下钻到报价单) | + +**关键交互**: +- 点击单价 → 抽屉展示原始报价单详情 +- 价格预警:高于近3个月平均价15% → 行背景红色高亮 +- 按时间倒序排列 + +**后端API**: +```java +// BizMaterialController +@GetMapping("/{id}/supplier-quotes") +public AjaxResult getSupplierQuoteHistory(@PathVariable Long id) { + // 查询 biz_quotation_item JOIN biz_quotation JOIN biz_supplier + // WHERE material_id = id ORDER BY submit_time DESC +} +``` + +### 3.3 Tab 2:我方给甲方的历史报价 + +**数据来源**:`biz_client_quote_item` → `biz_client_quote` + +**展示字段**: +| 字段 | 说明 | +|------|------| +| 报价日期 | client_quote.create_time | +| 甲方名称 | client_quote.client_name | +| 我方含税单价 | client_quote_item.unit_price | +| 折扣率 | client_quote_item.discount_rate | +| 最终成交价 | 含税单价 × 折扣率 | +| 状态 | sent/accepted/rejected(带标签) | +| 关联RFQ | client_quote.rfq_id → biz_rfq.rfq_no | + +**功能扩展**: +- 落选标注原因(新增client_quote_item.reject_reason字段) +- 版本对比(基于parent_quote_id) + +### 3.4 Tab 3:不同品牌/规格同比 + +#### 新建对比关系表 + +```sql +CREATE TABLE biz_material_comparison ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + group_id VARCHAR(50) NOT NULL COMMENT '对比组ID(如"VFD-37kW-380V")', + group_name VARCHAR(200) COMMENT '对比组名称(如"37kW 380V变频器对比组")', + material_id BIGINT NOT NULL COMMENT '物料ID', + counterpart_brand VARCHAR(100) COMMENT '对标品牌', + counterpart_model VARCHAR(200) COMMENT '对标型号', + comparison_notes TEXT COMMENT '对比说明(差异点)', + sort_order INT DEFAULT 0 COMMENT '组内排序', + status CHAR(1) DEFAULT '0' COMMENT '状态', + create_by VARCHAR(64), + create_time DATETIME, + update_by VARCHAR(64), + update_time DATETIME, + UNIQUE KEY uk_group_material (group_id, material_id), + KEY idx_material (material_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料横向对比组'; +``` + +**功能逻辑**: + +1. **管理员维护对比组**(在物料详情页可直接操作) + - 为某个物料添加"对标物料"(跨品牌) + - 如汇川MD500T37G ↔ 禾望HV500-37G ↔ 西门子G120 PM240 37kW + +2. **自动对比展示** + - 系统自动从 biz_comparison 对比结果中拉取对标物料的最新供应商报价 + - 对比维度:单价 | 功率 | 过载能力 | 通讯接口 | 防护等级 | 适用场合 + +3. **数据初始化** + - 利用Excel Sheet 10-14的比价数据预置对比组 + - 如Sheet 10中"37kW变频器"对应的汇川/禾望/西门子/ABB四家数据 + +#### 前端展示 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 37kW 380V变频器 对比组 │ +├──────────────┬──────────┬──────────┬──────────┬────────────┤ +│ │ 汇川 │ 禾望 │ 西门子 │ ABB │ +│ │ MD500T37G │ HV500-37G│ G120 37kW│ ACS880-01 │ +├──────────────┼──────────┼──────────┼──────────┼────────────┤ +│ 最低报价(元) │ 6,200 │ 5,800 │ 10,500 │ 8,900 │ +│ 功率(kW) │ 37 │ 37 │ 37 │ 37 │ +│ 过载能力 │ 150%/60s │ 150%/60s │ 140%/60s │ 150%/60s │ +│ 通讯接口 │ RS485 │ RS485 │ PROFINET │ PROFINET │ +│ 防护等级 │ IP20 │ IP20 │ IP20 │ IP21 │ +│ 综合评价 │ ★★★★☆ │ ★★★★★ │ ★★★☆☆ │ ★★★★☆ │ +├──────────────┼──────────┴──────────┴──────────┴────────────┤ +│ 推荐选型 │ 禾望HV500-37G (性价比最优) │ +└──────────────┴─────────────────────────────────────────────┘ +``` + +--- + +## 四、板块三:供应商管理 + +### 4.1 现有基础 + +`biz_supplier` 表已有字段:supplier_id, supplier_name, contact, phone, email, address, status + +### 4.2 供应商详情页重构 + +在现有 `/bid/supplier` 基础上,将列表页改为"列表+详情"结构,点击供应商进入详情页: + +``` +供应商详情页 (/bid/supplier/detail/:id) +├── Tab 1: 基础信息 (现有功能) +│ ├── 供应商名称/联系人/电话/邮箱/地址 +│ └── 资质文件上传(营业执照/授权证书) +├── Tab 2: 供货清单 (新建) +│ ├── 供应商-物料关系维护 +│ └── 历史报价快速查看 +├── Tab 3: 报价单管理 (增强) +│ ├── 参与的RFQ列表 +│ └── 报价单状态跟踪 +├── Tab 4: 历史报价趋势 (新建) +│ └── ECharts折线图 +└── Tab 5: 账号管理 (新建) + └── 供应商登录账号创建/权限管理 +``` + +### 4.3 供货清单 + +#### 新建供应商-物料关系表 + +```sql +CREATE TABLE biz_supplier_material ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + supplier_id BIGINT NOT NULL, + material_id BIGINT NOT NULL, + supply_status TINYINT DEFAULT 1 COMMENT '0停供 1正常 2备选', + last_quote_price DECIMAL(18,4) COMMENT '最新报价(缓存)', + last_quote_time DATETIME COMMENT '最新报价时间', + delivery_cycle INT DEFAULT 0 COMMENT '供应周期(天)', + min_order_qty DECIMAL(15,4) DEFAULT 1 COMMENT '最小起订量', + preferred TINYINT DEFAULT 0 COMMENT '是否优选供应商', + create_time DATETIME, + UNIQUE KEY uk_supplier_material (supplier_id, material_id), + KEY idx_supplier (supplier_id), + KEY idx_material (material_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商物料供应关系'; +``` + +**前端交互**: +- 点击物料名称 → 跳转物料详情页(`/bid/material/detail/:id`) +- 支持在物料详情页"添加供应商"反向维护 +- 批量导入:根据Excel比价数据自动建立供应关系 + +### 4.4 报价单管理 + +供应商参与的RFQ及报价单管理,增强现有 `biz_rfq`: + +```sql +ALTER TABLE biz_rfq ADD COLUMN ( + contract_no VARCHAR(100) COMMENT '合同号', + client_name VARCHAR(100) COMMENT '甲方名称', + project_name VARCHAR(200) COMMENT '项目名称', + delivery_required_date DATE COMMENT '要求交货日期', + delivery_weeks INT COMMENT '要求交货周期(周)', + quote_deadline DATETIME COMMENT '供应商报价截止日', + total_budget DECIMAL(18,4) COMMENT '预算总额', + winner_supplier_id BIGINT COMMENT '中标供应商ID', + winner_quotation_id BIGINT COMMENT '中标报价单ID' +); +``` + +**报价单列表页字段**:询价单号 | 合同号 | 甲方 | 项目名称 | 状态 | 报价截止日 | 已报价/邀请数 | 操作 + +**状态流转**:`draft(草稿) → published(已发布) → in_progress(报价中) → closed(已关闭) → completed(已完成)` + +### 4.5 指派供应商界面 + +**触发点**:RFQ发布时选择被邀请的供应商 + +``` +┌─ 指派供应商对话框 ─────────────────────────────────┐ +│ │ +│ 询价单号: RFQ-2026-001 │ +│ 标题: 自动化生产线控制系统采购 │ +│ │ +│ ☐ 全选 搜索供应商: [______] │ +│ │ +│ ☑ 深圳市华顺达电子有限公司 上次合作: 2026-01 │ +│ ☑ 苏州博远精密设备有限公司 上次合作: 2026-01 │ +│ ☐ 上海瑞达工控科技有限公司 新供应商 │ +│ ☑ 广州联盟电气集团 报价历史优秀 │ +│ ☐ 武汉华中精工机械有限公司 评价4.8分 │ +│ │ +│ 发送方式: [📧 邮件通知] [💬 站内信] [📱 短信通知] │ +│ │ +│ [取消] [确认指派] │ +└─────────────────────────────────────────────────────┘ +``` + +**指派后**:系统向供应商发送通知,供应商登录后可看到"可报项" + +--- + +## 五、板块四:报价商门户(供应商端) + +### 5.1 账户体系设计 + +```sql +-- 在 sys_user 增加供应商类型字段(已有 tenant_id) +ALTER TABLE sys_user ADD COLUMN ( + user_type TINYINT DEFAULT 1 COMMENT '1内部员工 2供应商账号', + supplier_id BIGINT COMMENT '关联供应商ID(仅user_type=2时有效)', + account_status TINYINT DEFAULT 1 COMMENT '0待审核 1正常 2冻结' +); +``` + +**权限控制**: +- 供应商账号(`user_type=2`) → 仅能看到本供应商数据(通过`supplier_id`过滤) +- RuoYi `@PreAuthorize`注解 + 自定义数据权限拦截器 +- 路由层面:供应商端访问 `/supplier/**` 路径,内部员工无法访问 + +### 5.2 供应商路由体系 + +新建独立路由模块,与后台管理路由隔离: + +```javascript +// ruoyi-ui/src/router/supplier.js +export const supplierRoutes = [ + { + path: '/supplier', + component: Layout, + hidden: true, // 不在管理后台侧边栏显示 + children: [ + { path: 'dashboard', component: () => import('@/views/supplier/dashboard'), meta: { title: '供应商首页' } }, + { path: 'rfq/pending', component: () => import('@/views/supplier/rfq-pending'), meta: { title: '可报项' } }, + { path: 'rfq/quoted', component: () => import('@/views/supplier/rfq-quoted'), meta: { title: '已报项' } }, + { path: 'quote/edit/:rfqId', component: () => import('@/views/supplier/quote-edit'), meta: { title: '报价填写' } }, + { path: 'profile', component: () => import('@/views/supplier/profile'), meta: { title: '我的信息' } }, + ] + } +]; +``` + +### 5.3 供应商首页 (`/supplier/dashboard`) + +``` +┌────────────────────────────────────────────────────────────┐ +│ 欢迎您,深圳市华顺达电子有限公司 │ +├──────────┬──────────┬──────────┬──────────┬───────────────┤ +│ 可报项 │ 已报项 │ 中标数 │ 中标率 │ 累计成交额 │ +│ 3 │ 12 │ 5 │ 41.7% │ ¥1,286,500 │ +├──────────┴──────────┴──────────┴──────────┴───────────────┤ +│ ⏰ 紧急提醒:RFQ-2026-003 报价截止还剩 2天! │ +│ 📋 最新中标的报价单:RFQ-2026-001 (2026-01-15中标) │ +└────────────────────────────────────────────────────────────┘ +``` + +### 5.4 可报项 (`/supplier/rfq/pending`) + +**数据来源**:`biz_rfq_supplier` WHERE `supplier_id = ?` AND `status = 'published'` AND `quote_deadline > NOW()` + +**列表字段**: +| 字段 | 说明 | +|------|------| +| RFQ编号 | biz_rfq.rfq_no | +| 甲方/项目 | biz_rfq.client_name / project_name | +| 报价截止日 | biz_rfq.quote_deadline (红色<3天) | +| 物料数量 | biz_rfq_item COUNT | +| 操作 | 立即报价(按钮) | + +**紧急提醒**:截止前24小时发送站内信(复用RuoYi消息中心) + +### 5.5 已报项 (`/supplier/rfq/quoted`) + +**数据来源**:`biz_quotation` WHERE `supplier_id = ?` + +**列表字段**: +| 字段 | 说明 | +|------|------| +| RFQ编号 | rfq_no | +| 报价日期 | quotation.create_time | +| 物料数量 | quotation_item COUNT | +| 报价总额 | quotation.total_amount | +| 状态 | pending(待开标)/won(已中标)/lost(未中标) | +| 操作 | 查看详情 / 修改报价(截止前可改) | + +### 5.6 报价填写界面 (`/supplier/quote/edit/:rfqId`) + +采用**分步表单**: + +``` +Step 1 → 物料清单确认 (只读展示RFQ物料) +Step 2 → 逐项填价 (核心步骤) +Step 3 → 预览提交 +``` + +**Step 2 填价界面**: + +``` +物料清单表格: +┌──────────┬────────┬──────┬──────┬──────────┬────────┬──────────┐ +│ 物料名称 │ 规格 │ 数量 │ 单位 │ 单价(元)* │ 交期(周)│ 备注 │ +├──────────┼────────┼──────┼──────┼──────────┼────────┼──────────┤ +│ PLC控制器 │ CPU... │ 5 │ 套 │ [___] │ [___] │ [______] │ +│ 变频器 │ 三相...│ 8 │ 台 │ [___] │ [___] │ [______] │ +│ 电源模块 │ 24V... │ 20 │ 台 │ [___] │ [___] │ [______] │ +└──────────┴────────┴──────┴──────┴──────────┴────────┴──────────┘ + 含税/未税切换: [●含税] [○未税] 自动计算增值税13% +``` + +**关键交互**: +- 必填校验:单价 > 0,交期 ≤ RFQ要求 +- 智能提示:当输入单价低于该物料历史最低价的80%时 → 警告弹窗"报价异常偏低,请确认" +- 附件上传:产品彩页、资质证书、型式试验报告(新表`biz_quotation_attachment`) +- 自动保存草稿(LocalStorage + 后端每3分钟自动保存) +- 提交前预览比价结果(提示"您的报价在当前排名第X/共Y家") + +### 5.7 供应商端API + +| 接口 | 方法 | 说明 | +|------|------|------| +| `/supplier/dashboard/stats` | GET | 统计数据总览 | +| `/supplier/rfq/pending` | GET | 可报项列表(分页) | +| `/supplier/rfq/quoted` | GET | 已报项列表(分页) | +| `/supplier/quote/draft/{rfqId}` | GET | 获取草稿报价 | +| `/supplier/quote/save-draft` | POST | 保存报价草稿 | +| `/supplier/quote/submit` | POST | 提交报价 | +| `/supplier/quote/{id}/attachments` | POST | 上传附件 | +| `/supplier/profile` | GET/PUT | 供应商信息维护 | + +--- + +## 六、板块五:甲方报价单 + +### 6.1 现有基础 + +`biz_client_quote` 已有基础CRUD,`biz_client_quote_item` 已有明细表。现有页面已支持基本的新建/编辑/PDF导出。 + +### 6.2 数据模型增强 + +```sql +-- 增强甲方报价单 +ALTER TABLE biz_client_quote ADD COLUMN ( + rfq_id BIGINT COMMENT '关联内部RFQ', + cost_total DECIMAL(18,4) COMMENT '内部成本合计(供应商中标价汇总)', + margin_rate DECIMAL(5,2) COMMENT '毛利率%', + quote_version INT DEFAULT 1 COMMENT '报价版本号', + parent_quote_id BIGINT COMMENT '父报价单ID(版本迭代)', + project_name VARCHAR(200) COMMENT '项目名称', + validity_date DATETIME COMMENT '报价有效期', + payment_terms VARCHAR(500) COMMENT '付款条件', + delivery_terms VARCHAR(500) COMMENT '交货条款', + status VARCHAR(20) COMMENT 'draft/sent/accepted/rejected/revised', + margin_rate_setting DECIMAL(5,2) DEFAULT 15.00 COMMENT '加价系数(%)', + tax_rate DECIMAL(4,2) DEFAULT 13.00 COMMENT '税率(%)' +); + +-- 新建甲方报价-物料-供应商关联表(记录每个物料选定的供应商) +CREATE TABLE biz_client_quote_item_source ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + quote_item_id BIGINT NOT NULL COMMENT 'biz_client_quote_item.id', + supplier_id BIGINT COMMENT '选定的供应商ID', + supplier_quote_id BIGINT COMMENT '供应商报价单ID(biz_quotation.quotation_id)', + unit_cost DECIMAL(18,4) COMMENT '供应商中标单价(含税)', + selected_reason VARCHAR(500) COMMENT '选择该供应商原因', + internal_note TEXT COMMENT '内部备注', + create_by VARCHAR(64), + create_time DATETIME, + update_by VARCHAR(64), + update_time DATETIME, + KEY idx_quote_item (quote_item_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='甲方报价物料来源'; +``` + +### 6.3 业务流程图 + +``` +┌──────────────┐ +│ 甲方询价需求 │ +└──────┬───────┘ + ▼ +┌──────────────────┐ +│ 创建甲方报价单 │ ← 手动输入甲方需求物料 +│ (biz_client_quote)│ +└──────┬───────────┘ + ▼ +┌──────────────────┐ +│ 生成内部RFQ │ ← 从甲方物料自动拆解为RFQ +│ (点击"发起询价") │ 按品类分多个子RFQ +└──────┬───────────┘ + ▼ +┌──────────────────┐ +│ 指派供应商报价 │ ← 每个子RFQ指派不同供应商 +│ (供应商端报价) │ 变频器→A/B/C, 电缆→D/E +└──────┬───────────┘ + ▼ +┌──────────────────┐ +│ 比价选择供应商 │ ← 使用现有智慧比价引擎 +│ (选定最优方案) │ +└──────┬───────────┘ + ▼ +┌──────────────────┐ +│ 成本回填 │ ← 自动回填选中供应商价格到 +│ (自动/手动同步) │ biz_client_quote_item_source +└──────┬───────────┘ + ▼ +┌──────────────────┐ +│ 计算对外报价 │ ← 成本 × (1 + 加价系数) +│ 生成PDF → 发送甲方 │ 可手动调整覆盖 +└──────────────────┘ +``` + +### 6.4 甲方报价单详情页重构 + +``` +甲方报价单详情页 (/bid/clientquote/detail/:id) +├── 顶部操作栏 +│ ├── 保存草稿 | 导出PDF | 发送甲方 | 版本迭代 +│ └── 状态标签(draft/sent/accepted/rejected) +│ +├── 基本信息卡片 +│ ├── 客户名称 | 项目名称 | 有效期 | 币种 +│ ├── 关联RFQ(下拉选择) | 合同号 +│ └── 付款条件 | 交货条款 +│ +├── 物料清单表格(可编辑) +│ ├── 行数据:序号 | 类别 | 物料名称 | 品牌 | 型号规格 +│ │ | 数量 | 单位 | 供应商中标价(成本) +│ │ | 加价系数 | 对外含税单价 | 小计 +│ ├── 操作:添加行 | 删除行 | 批量导入 +│ └── 特殊列:询价状态(未询价/报价中/已回价/已定价) +│ └── 已定价 → 显示供应商名称,点击查看来源 +│ └── 未询价 → 点击"发起询价"→ 弹出选择供应商 → 生成子RFQ +│ +├── 右侧成本汇总面板(固定) +│ ├── 物料成本合计: ¥XXX (自动汇总供应商中标价) +│ ├── 加价系数: 15% (可调整) +│ ├── 对外报价(含税): ¥XXX = 成本 × (1 + 加价系数) +│ ├── 预计毛利率: XX.X% (实时计算) +│ └── 操作按钮:同步最新采购价 | 重新计算 +│ +├── Tab: 智能选型对比 +│ └── 选中物料 → 弹出对比窗口 → 展示同规格多品牌对比 +│ → 一键替换物料型号和成本 +│ +└── Tab: 历史版本 + └── 版本列表(通过parent_quote_id关联) + → 版本对比(高亮显示差异) +``` + +### 6.5 子RFQ生成逻辑 + +```java +// 从甲方报价单生成内部RFQ +@PostMapping("/bid/clientquote/{id}/generateRfq") +public AjaxResult generateSubRfq(@PathVariable Long id, @RequestBody GenerateRfqRequest req) { + // 1. 获取甲方报价单主表 + // 2. 根据选中的行物料,按category_id分组 + // 如: 变频器类一组,PLC类一组,电缆类一组 + // 3. 为每组创建子RFQ: + // - rfq_title = 甲方报价单项目名 + "(" + 类别名称 + ")" + // - deadline = 甲方报价单有效期前7天 + // - parent_client_quote_id = 甲方报价单ID + // 4. 将选中物料复制到biz_rfq_item + // 5. 指派供应商(从req.supplier_ids) + // 6. 返回生成的RFQ ID列表 +} +``` + +### 6.6 成本回填机制 + +**自动回填触发点**: +1. 采购单确认时(`biz_purchase_order.status → 'confirmed'`) +2. 甲方报价单页面手动点击"同步最新采购价" + +**回填逻辑**: +```java +// 自动回填 +@PostMapping("/bid/clientquote/{id}/syncCost") +public AjaxResult syncCost(@PathVariable Long id) { + // 1. 获取所有子RFQ的最新成交报价 + // 2. 将选中供应商的成交价写入biz_client_quote_item_source + // 3. 更新biz_client_quote.cost_total + // 4. 重新计算margin_rate + // 5. 记录价格变动日志 +} +``` + +**价格变动日志表**: +```sql +CREATE TABLE biz_price_change_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + source_type VARCHAR(20) COMMENT '来源类型(quotation/client_quote)', + source_id BIGINT COMMENT '来源ID', + material_id BIGINT COMMENT '物料ID', + old_price DECIMAL(18,4), + new_price DECIMAL(18,4), + change_reason VARCHAR(500) COMMENT '变更原因', + operator VARCHAR(64), + create_time DATETIME +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='价格变动日志'; +``` + +### 6.7 两个报价历史 + +**历史1:我方给甲方的报价历史** +- 数据源:`biz_client_quote` 通过 `parent_quote_id` 形成版本链 +- 功能:版本对比 → 选择两个版本高亮显示价格差异 + +**历史2:供应商给我方的报价历史** +- 数据源:`biz_quotation_item` 中该物料的历史记录 +- 功能:在甲方报价单物料行点击"查看成本来源" → 抽屉展示时间轴 + +--- + +## 七、报价单管理与指派系统 + +### 7.1 报价单详情页 (`/bid/rfq/detail/:id`) + +``` +RFQ详情页 (/bid/rfq/detail/:id) +├── 顶部:基础信息(合同号/甲方/截止日/状态) +├── 左侧:已邀请供应商列表 +│ ├── 供应商名称 | 报价状态(未报价/已报价/已逾期) +│ ├── 已报价 → 显示报价金额及操作(查看详情) +│ └── 未报价 → 显示"催办"按钮(发送通知) +├── 右侧:物料明细及各家报价对比表格 +│ ├── 与XLSX Sheet 10-14格式一致 +│ ├── 行:物料,列:各供应商单价(最低价绿色高亮) +│ └── 差额/差价自动计算 +├── 底部操作栏 +│ ├── 确认中标 → 弹出选择中标供应商对话框 +│ ├── 重新询价 → 复制当前RFQ生成新版本 +│ ├── 导出比价报告(PDF) → 复用现有导出功能 +│ └── 关闭询价 +``` + +### 7.2 供应商报价填写界面(供应商端) + +见5.6节详细描述。 + +### 7.3 比价报告PDF + +模板格式参考XLSX Sheet 10-14,包含: +- 表头:RFQ编号、项目名称、日期 +- 物料对比表:每行展示各供应商报价、最低价标记 +- 推荐方案:综合评分推荐最优供应商 +- 统计摘要:总价对比、节省金额 + +--- + +## 八、电气设备数据初始化方案 + +### 8.1 数据范围 + +利用XLSX Sheet 20-31的型号库数据,预置如下初始数据: + +| 品类 | 型号数量 | 数据来源Sheet | 对应品牌 | +|------|---------|--------------|---------| +| 变频器 | ~322 | 31_品牌汇总 | 汇川/禾望/西门子/ABB | +| 整流制动单元 | ~100 | 21_整流制动单元库 | 汇川/禾望/西门子 | +| PLC CPU | ~55 | 22_PLC_CPU型号库 | 西门子/三菱/欧姆龙 | +| PLC扩展模块 | ~98 | 23_PLC_扩展模块库 | 西门子/三菱/欧姆龙 | +| 低压电器 | ~75 | 24_低压电器型号库 | 正泰/施耐德 | +| 触摸屏 | ~20 | 25_触摸屏型号库 | 威纶通/昆仑通态/西门子 | +| 铜牌母线 | ~20 | 26_铜牌母线型号库 | TMY铜排 | +| 动力电缆 | ~23 | 27_电缆型号库 | YJV22系列 | +| 控制线 | ~21 | 28_控制线型号库 | KVVP系列 | +| 线槽 | ~18 | 29_线槽型号库 | PVC/钢制 | +| 工业网关 | ~12 | 30_网关型号库 | 汇川/研华 | +| **合计** | **~764** | | | + +### 8.2 供应商初始化 + +基于XLSX比价数据中的供应商,初始化以下供应商: + +| 供应商 | 供应品类 | 数据范围 | +|--------|---------|---------| +| A供应商(汇川/正泰等) | 变频器/整流/低压电器 | Sheet 10-14 | +| B供应商(禾望等) | 变频器/整流/PLC | Sheet 10-14 | +| C供应商(西门子/施耐德等) | 变频器/PLC/低压电器 | Sheet 10-14 | + +### 8.3 对比组初始化 + +根据Sheet 10-14比价数据,建立初始对比组: + +| 对比组 | 包含品牌 | 数据来源 | +|--------|---------|---------| +| 37kW 380V变频器 | 汇川MD500T37G / 禾望HV500-37G / 西门子G120 / ABB ACS880 | Sheet 10 | +| 55kW 380V变频器 | 汇川MD500T55G / 禾望HV500-55G / 西门子G120 PM240 | Sheet 10 | +| 整流单元75kW | MDR100T75 / HBD-075 / BLM-075 | Sheet 11 | +| CPU 1515-2 PN | 三家供应商报价对比 | Sheet 12 | +| 断路器NXM-125S | 正泰/施耐德/其他 | Sheet 13 | +| 动力电缆YJV 3×70+1×35 | 三家供应商报价对比 | Sheet 14 | + +### 8.4 导入策略 + +**方案一:SQL脚本导入(推荐首批)** +- 将型号库数据编写为 `INSERT` 语句 +- 写入 `sql/demo_data.sql` 或新建 `sql/excel_import_data.sql` +- 每个物料生成 `material_code` (如 `M-EL-001`) + +**方案二:Excel批量导入功能(后续维护)** +- 通过 `/bid/material/import` 接口 +- 上传Excel文件 → EasyExcel解析 → 数据校验 → 批量写入 +- 提供下载导入模板功能 + +--- + +## 九、开发优先级与里程碑 + +### 第一阶段:基础数据层(第1-2周) + +| 优先级 | 任务 | 涉及文件 | +|--------|------|---------| +| P0 | 物料表字段扩展 + 性能参数JSON动态表单 | `biz_material` + 前端物料表单 | +| P0 | 物料分类树+表格联动 | 复用现有 `BizMaterialCategoryController` | +| P1 | 物料详情页基础框架 + Tab1(供应商历史报价) | 新建 `material/detail.vue` | +| P1 | 供应商-物料关系表 + 供货清单Tab | 新建 `biz_supplier_material` | +| P1 | 物料横向对比组表 + 维护界面 | 新建 `biz_material_comparison` | +| P2 | Excel电气设备型号库数据导入(首批~764条) | 扩充 `demo_data.sql` | + +### 第二阶段:业务流程层(第3-5周) + +| 优先级 | 任务 | 涉及文件 | +|--------|------|---------| +| P0 | RFQ增强(合同号/甲方/截止日/指派界面) | `biz_rfq` 扩展 + RFQ详情页重构 | +| P0 | 供应商门户独立路由 + 可报项/已报项列表 | 新建 `views/supplier/*` | +| P0 | 供应商报价填写界面(分步表单) | 新建 `supplier/quote-edit.vue` | +| P1 | 供应商账号管理(账号创建/权限分配) | `sys_user` user_type扩展 | +| P1 | 甲方报价单增强(子RFQ生成) | `BizClientQuoteController` | +| P1 | 成本回填机制(自动+手动触发) | 新建 `biz_client_quote_item_source` | +| P2 | 物料详情Tab2(甲方历史报价) | 扩展 `material/detail.vue` | + +### 第三阶段:智能分析层(第6-8周) + +| 优先级 | 任务 | 涉及文件 | +|--------|------|---------| +| P1 | 物料详情Tab3(横向同比+推荐算法) | 扩展 `material/detail.vue` | +| P1 | 甲方报价单智能选型对比 | `BizComparisonService` 扩展 | +| P2 | 价格趋势ECharts折线图(物料详情页) | 物料详情右栏 | +| P2 | 供应商报价历史趋势ECharts | 供应商详情Tab4 | +| P2 | 价格预警机制(高于均价15%红色高亮) | 前端表格渲染 | +| P3 | 比价报告PDF增强 | 复用现有JSPDF导出 | + +### 第四阶段:优化完善(第9-10周) + +| 优先级 | 任务 | 涉及文件 | +|--------|------|---------| +| P2 | 版本对比(甲方报价单历史版本diff) | 扩展 `client-quote` | +| P2 | 批量导入Excel型号库(维护界面) | `/bid/material/import` | +| P3 | 供应商端多语言/国际化 | i18n配置 | +| P3 | 性能优化(物料列表大数据量分页) | 后端分页+前端虚拟滚动 | +| P3 | Docker部署配置更新 | `deploy/` | + +--- + +## 十、关键接口清单 + +### 物料模块 +| 接口 | 方法 | 说明 | 优先级 | +|------|------|------|--------| +| `/bid/material/detail/{id}` | GET | 物料详情+历史报价摘要 | P0 | +| `/bid/material/{id}/supplier-quotes` | GET | 供应商历史报价清单 | P0 | +| `/bid/material/{id}/client-quotes` | GET | 我方给甲方历史报价 | P1 | +| `/bid/material/{id}/comparison` | GET | 横向对比数据 | P1 | +| `/bid/material/manufacturer/list` | GET | 厂家下拉列表(去重) | P0 | +| `/bid/material/import` | POST | Excel批量导入 | P1 | +| `/bid/material/export` | GET | 导出模板 | P1 | +| `/bid/material/suggest` | GET | 型号智能联想 | P2 | + +### 供应商模块 +| 接口 | 方法 | 说明 | 优先级 | +|------|------|------|--------| +| `/bid/supplier/{id}/materials` | GET | 供货清单(分页) | P0 | +| `/bid/supplier/{id}/materials` | POST | 添加供应物料 | P1 | +| `/bid/supplier/{id}/quotes` | GET | 报价单管理列表 | P1 | +| `/bid/supplier/{id}/price-trend` | GET | 历史报价趋势 | P2 | +| `/bid/supplier/{id}/accounts` | GET | 供应商账号列表 | P1 | +| `/bid/supplier/{id}/accounts` | POST | 创建供应商账号 | P2 | + +### RFQ模块 +| 接口 | 方法 | 说明 | 优先级 | +|------|------|------|--------| +| `/bid/rfq/{id}/assign` | POST | 指派供应商 | P0 | +| `/bid/rfq/{id}/comparison` | GET | 比价结果(现有增强) | P0 | +| `/bid/rfq/{id}/bid-report` | GET | 导出比价报告PDF | P1 | +| `/bid/rfq/{id}/winner` | POST | 确认中标供应商 | P1 | + +### 供应商端 +| 接口 | 方法 | 说明 | 优先级 | +|------|------|------|--------| +| `/supplier/dashboard/stats` | GET | 统计数据总览 | P0 | +| `/supplier/rfq/pending` | GET | 可报项列表 | P0 | +| `/supplier/rfq/quoted` | GET | 已报项列表 | P0 | +| `/supplier/quote/draft/{rfqId}` | GET | 获取草稿报价 | P0 | +| `/supplier/quote/save-draft` | POST | 保存报价草稿 | P0 | +| `/supplier/quote/submit` | POST | 提交报价 | P0 | +| `/supplier/quote/{id}/attachments` | POST | 上传附件 | P1 | + +### 甲方报价单 +| 接口 | 方法 | 说明 | 优先级 | +|------|------|------|--------| +| `/bid/clientquote/{id}/generateRfq` | POST | 生成子RFQ | P0 | +| `/bid/clientquote/{id}/syncCost` | POST | 同步采购成本 | P1 | +| `/bid/clientquote/{id}/compareSpec` | GET | 智能选型对比 | P1 | +| `/bid/clientquote/{id}/versions` | GET | 历史版本列表 | P2 | +| `/bid/clientquote/version-compare` | POST | 版本对比diff | P2 | +| `/bid/clientquote/{id}/export-pdf` | GET | 导出PDF | P0(现有) | + +--- + +## 十一、权限与安全设计 + +### 11.1 权限矩阵 + +| 角色 | 物料 | 供应商 | RFQ | 供应商报价 | 比价 | 甲方报价 | 供应商门户 | +|------|------|--------|-----|-----------|------|---------|-----------| +| 管理员 | CRUD | CRUD | CRUD | CRUD | 查看 | CRUD | 不可访问 | +| 采购员 | 查看 | 查看/编辑 | CRUD | 查看 | 查看/操作 | 查看 | 不可访问 | +| 销售员 | 查看 | 查看 | 查看 | 查看 | 查看 | 创建/编辑 | 不可访问 | +| 供应商 | 查看(仅关联) | 查看(仅自己) | 查看(受邀) | 查看(仅自己) | 不可见 | 不可见 | 报价/查看 | + +### 11.2 数据权限 + +- **租户隔离**:所有业务表已有 `tenant_id`,查询SQL必须带 `tenant_id = ?` +- **供应商隔离**:供应商账号 `user_type=2`,所有查询追加 `supplier_id = ?` +- **价格脱敏**:供应商看不到其他供应商的报价价格(但可以看到自己的排名) + +### 11.3 安全措施 + +- **价格字段加密**:敏感价格字段在数据库中使用AES加密存储,接口返回时按角色脱敏 +- **乐观锁防并发**:`biz_quotation` 增加 `version` 字段,供应商报价提交时CAS检查 +- **操作日志**:所有CRUD操作使用RuoYi `@Log` 注解记录 +- **文件上传校验**:限制附件类型(pdf/jpg/png),大小≤10MB + +--- + +## 附录:Excel数据对照表 + +### XLSX → 系统表映射 + +| Excel Sheet | 对应系统表 | 说明 | +|------------|-----------|------| +| 01_项目报价单 | `biz_client_quote` + `biz_client_quote_item` | 甲方报价模板映射 | +| 02_报价汇总 | `biz_client_quote` (汇总字段) | 汇总逻辑直接实现 | +| 10-14_比价表 | `biz_quotation` + `biz_comparison`(已有) | 比价数据初始化来源 | +| 20-30_型号库 | `biz_material` | 初始物料数据(764条) | +| 31_品牌汇总 | 统计查询 | 直接SQL统计实现 | + +### XLSX比价表 → 系统比价引擎字段映射 + +| Excel列 | 系统字段 | 说明 | +|---------|---------|------| +| A供应商型号 | quotation_item.material_name/spec | 报价物料 | +| A供应商报价 | quotation_item.unit_price | 供应商A报价单价 | +| B供应商型号 | quotation_item.material_name/spec | 报价物料 | +| B供应商报价 | quotation_item.unit_price | 供应商B报价单价 | +| 最低价 | BizComparisonVO.minPrice | 当前最低价(系统自动计算) | +| 推荐 | BizComparisonVO.recommendedSupplier | 评分最优推荐 | + +--- + +> 本文档基于PPT《报价比对系统》(6页) + XLSX《电气自动化设备综合管理系统_V1》(27Sheet) + 现有项目源码(RuoYi-Vue v3.9.2, 12个已完成模块)综合分析生成,可直接作为迭代开发的技术参考。 +> +> 最后更新:2026-05-27 diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizMaterialController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizMaterialController.java index 14ebc917..17a4f4ae 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizMaterialController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizMaterialController.java @@ -54,4 +54,65 @@ public class BizMaterialController extends BaseController { public AjaxResult remove(@PathVariable Long[] materialIds) { return toAjax(service.deleteBizMaterialByIds(materialIds)); } + + // ========== 物料详情页接口 ========== + + @PreAuthorize("@ss.hasPermi('bid:material:detail')") + @GetMapping("/{id}/supplier-quotes") + public AjaxResult supplierQuotes(@PathVariable Long id) { + return success(service.selectSupplierQuotesByMaterialId(id)); + } + + @PreAuthorize("@ss.hasPermi('bid:material:detail')") + @GetMapping("/{id}/client-quotes") + public AjaxResult clientQuotes(@PathVariable Long id) { + return success(service.selectClientQuotesByMaterialId(id)); + } + + @GetMapping("/manufacturer/list") + public AjaxResult manufacturerList() { + return success(service.selectManufacturerList()); + } + + // ========== 物料横向对比 ========== + + @PreAuthorize("@ss.hasPermi('bid:material:list')") + @PostMapping("/compare") + public AjaxResult compare(@RequestBody List materialIds) { + if (materialIds == null || materialIds.isEmpty()) { + return error("请至少选择两个物料进行对比"); + } + if (materialIds.size() > 10) { + return error("一次最多对比10个物料"); + } + return success(service.compareMaterials(materialIds)); + } + + // ========== 同类型物料横向对比 ========== + + @PreAuthorize("@ss.hasPermi('bid:material:list')") + @GetMapping("/selectable-for-comparison") + public AjaxResult getSelectableMaterials() { + return success(service.selectMaterialsWithSupplierQuotes()); + } + + @PreAuthorize("@ss.hasPermi('bid:material:list')") + @GetMapping("/same-name/{materialName}") + public AjaxResult getSameNameMaterials(@PathVariable String materialName, + @RequestParam(required = false) Long excludeId) { + List list = service.selectMaterialsByExactName(materialName, excludeId); + return success(list); + } + + @PreAuthorize("@ss.hasPermi('bid:material:list')") + @PostMapping("/quote-comparison") + public AjaxResult getQuoteComparison(@RequestBody List materialIds) { + if (materialIds == null || materialIds.isEmpty()) { + return error("请至少选择一个物料"); + } + if (materialIds.size() > 10) { + return error("一次最多对比10个物料"); + } + return success(service.selectSupplierQuoteComparison(materialIds)); + } } diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-admin/src/main/resources/application-druid.yml index bcfad3ea..aeb74fc9 100644 --- a/ruoyi-admin/src/main/resources/application-druid.yml +++ b/ruoyi-admin/src/main/resources/application-druid.yml @@ -8,7 +8,7 @@ spring: master: url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root - password: password + password: 135827 # 从库数据源 slave: # 从数据源开关/默认关闭 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizMaterial.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizMaterial.java index 919ced33..8f48f510 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizMaterial.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizMaterial.java @@ -9,7 +9,6 @@ public class BizMaterial extends BaseEntity { private String materialCode; private String materialName; private String spec; - private String modelNo; private String unit; private String brand; private String description; @@ -17,6 +16,12 @@ public class BizMaterial extends BaseEntity { // search helper private String categoryName; + // 新增字段 + private String performanceParams; + private String material; + private String purpose; + private String imageUrl; + public Long getMaterialId() { return materialId; } public void setMaterialId(Long materialId) { this.materialId = materialId; } public Long getTenantId() { return tenantId; } @@ -29,8 +34,6 @@ public class BizMaterial extends BaseEntity { public void setMaterialName(String materialName) { this.materialName = materialName; } public String getSpec() { return spec; } public void setSpec(String spec) { this.spec = spec; } - public String getModelNo() { return modelNo; } - public void setModelNo(String modelNo) { this.modelNo = modelNo; } public String getUnit() { return unit; } public void setUnit(String unit) { this.unit = unit; } public String getBrand() { return brand; } @@ -41,4 +44,12 @@ public class BizMaterial extends BaseEntity { public void setStatus(String status) { this.status = status; } public String getCategoryName() { return categoryName; } public void setCategoryName(String categoryName) { this.categoryName = categoryName; } + public String getPerformanceParams() { return performanceParams; } + public void setPerformanceParams(String performanceParams) { this.performanceParams = performanceParams; } + public String getMaterial() { return material; } + public void setMaterial(String material) { this.material = material; } + public String getPurpose() { return purpose; } + public void setPurpose(String purpose) { this.purpose = purpose; } + public String getImageUrl() { return imageUrl; } + public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizMaterialMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizMaterialMapper.java index 4e4906b0..d7e5a866 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizMaterialMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizMaterialMapper.java @@ -1,7 +1,9 @@ package com.ruoyi.system.mapper.bid; import com.ruoyi.system.domain.bid.BizMaterial; +import org.apache.ibatis.annotations.Param; import java.util.List; +import java.util.Map; public interface BizMaterialMapper { List selectBizMaterialList(BizMaterial query); @@ -10,4 +12,21 @@ public interface BizMaterialMapper { int updateBizMaterial(BizMaterial record); int deleteBizMaterialById(Long id); int deleteBizMaterialByIds(Long[] ids); + + // 物料详情页 + List> selectSupplierQuotesByMaterialId(Long materialId); + + // 批量物料对比 + List selectBizMaterialByIds(List materialIds); + List> selectSupplierPriceSummaryByMaterialIds(List materialIds); + List> selectBestSupplierOfferByMaterialIds(List materialIds); + List> selectClientQuotesByMaterialId(Long materialId); + List selectManufacturerList(); + + // 同类型物料横向对比 + List selectMaterialsWithSupplierQuotes(); + List> selectSupplierQuoteComparison(List materialIds); + + // 根据物料名称精确匹配(同名称不同规格/品牌对比) + List selectMaterialsByExactName(@Param("materialName") String materialName, @Param("excludeId") Long excludeId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizMaterialService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizMaterialService.java index f80ba5dc..3adf125a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizMaterialService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizMaterialService.java @@ -2,6 +2,7 @@ package com.ruoyi.system.service.bid; import com.ruoyi.system.domain.bid.BizMaterial; import java.util.List; +import java.util.Map; public interface IBizMaterialService { List selectBizMaterialList(BizMaterial query); @@ -10,4 +11,18 @@ public interface IBizMaterialService { int updateBizMaterial(BizMaterial record); int deleteBizMaterialById(Long id); int deleteBizMaterialByIds(Long[] ids); + + List> selectSupplierQuotesByMaterialId(Long materialId); + List> selectClientQuotesByMaterialId(Long materialId); + List selectManufacturerList(); + + // 批量物料对比 + Map compareMaterials(List materialIds); + + // 同类型物料横向对比 + List selectMaterialsWithSupplierQuotes(); + List> selectSupplierQuoteComparison(List materialIds); + + // 根据物料名称精确匹配(同名称不同规格/品牌对比) + List selectMaterialsByExactName(String materialName, Long excludeId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizMaterialServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizMaterialServiceImpl.java index 6a88457c..99e88024 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizMaterialServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizMaterialServiceImpl.java @@ -5,7 +5,8 @@ import com.ruoyi.system.mapper.bid.BizMaterialMapper; import com.ruoyi.system.service.bid.IBizMaterialService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; @Service public class BizMaterialServiceImpl implements IBizMaterialService { @@ -41,4 +42,70 @@ public class BizMaterialServiceImpl implements IBizMaterialService { public int deleteBizMaterialByIds(Long[] ids) { return mapper.deleteBizMaterialByIds(ids); } + + @Override + public List> selectSupplierQuotesByMaterialId(Long materialId) { + return mapper.selectSupplierQuotesByMaterialId(materialId); + } + + @Override + public List> selectClientQuotesByMaterialId(Long materialId) { + return mapper.selectClientQuotesByMaterialId(materialId); + } + + @Override + public List selectManufacturerList() { + return mapper.selectManufacturerList(); + } + + @Override + public Map compareMaterials(List materialIds) { + if (materialIds == null || materialIds.isEmpty()) { + return Collections.emptyMap(); + } + + // 1. 获取物料基本信息 + List materials = mapper.selectBizMaterialByIds(materialIds); + + // 2. 获取供应商报价汇总 + List> priceSummaries = mapper.selectSupplierPriceSummaryByMaterialIds(materialIds); + Map> priceMap = new HashMap<>(); + for (Map row : priceSummaries) { + Long mid = ((Number) row.get("material_id")).longValue(); + priceMap.put(mid, row); + } + + // 3. 获取最优报价详情 + List> bestOffers = mapper.selectBestSupplierOfferByMaterialIds(materialIds); + Map> bestOfferMap = new HashMap<>(); + for (Map row : bestOffers) { + Long mid = ((Number) row.get("material_id")).longValue(); + bestOfferMap.put(mid, row); + } + + Map result = new HashMap<>(); + result.put("materials", materials); + result.put("priceMap", priceMap); + result.put("bestOfferMap", bestOfferMap); + + return result; + } + + @Override + public List selectMaterialsWithSupplierQuotes() { + return mapper.selectMaterialsWithSupplierQuotes(); + } + + @Override + public List> selectSupplierQuoteComparison(List materialIds) { + if (materialIds == null || materialIds.isEmpty()) { + return Collections.emptyList(); + } + return mapper.selectSupplierQuoteComparison(materialIds); + } + + @Override + public List selectMaterialsByExactName(String materialName, Long excludeId) { + return mapper.selectMaterialsByExactName(materialName, excludeId); + } } diff --git a/ruoyi-system/src/main/resources/mapper/bid/BizMaterialMapper.xml b/ruoyi-system/src/main/resources/mapper/bid/BizMaterialMapper.xml index 5eb5298d..073bda8f 100644 --- a/ruoyi-system/src/main/resources/mapper/bid/BizMaterialMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/bid/BizMaterialMapper.xml @@ -9,7 +9,6 @@ - @@ -18,27 +17,40 @@ + + + + - INSERT INTO biz_material(tenant_id,category_id,material_code,material_name,spec,model_no,unit,brand,description,status,create_by,create_time) - VALUES(#{tenantId},#{categoryId},#{materialCode},#{materialName},#{spec},#{modelNo},#{unit},#{brand},#{description},#{status},#{createBy},NOW()) + INSERT INTO biz_material(tenant_id,category_id,material_code,material_name,spec,unit,brand, + description,status,performance_params,material,purpose,image_url,create_by,create_time) + VALUES(#{tenantId},#{categoryId},#{materialCode},#{materialName},#{spec},#{unit},#{brand}, + #{description},#{status},#{performanceParams},#{material},#{purpose},#{imageUrl},#{createBy},NOW()) @@ -47,12 +59,15 @@ material_name=#{materialName}, material_code=#{materialCode}, spec=#{spec}, - model_no=#{modelNo}, unit=#{unit}, brand=#{brand}, description=#{description}, category_id=#{categoryId}, status=#{status}, + performance_params=#{performanceParams}, + material=#{material}, + purpose=#{purpose}, + image_url=#{imageUrl}, update_by=#{updateBy}, update_time=NOW() WHERE material_id=#{materialId} @@ -63,4 +78,129 @@ DELETE FROM biz_material WHERE material_id IN #{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-ui/src/api/bid/material.js b/ruoyi-ui/src/api/bid/material.js index 24bad0b0..33548ce8 100644 --- a/ruoyi-ui/src/api/bid/material.js +++ b/ruoyi-ui/src/api/bid/material.js @@ -1,7 +1,25 @@ import request from '@/utils/request' const baseUrl = '/bid/material' + export const listMaterial = (params) => request({ url: baseUrl + '/list', method: 'get', params }) export const getMaterial = (id) => request({ url: baseUrl + '/' + id, method: 'get' }) export const addMaterial = (data) => request({ url: baseUrl, method: 'post', data }) export const updateMaterial = (data) => request({ url: baseUrl, method: 'put', data }) export const delMaterial = (ids) => request({ url: baseUrl + '/' + ids, method: 'delete' }) + +// 物料详情页 +export const getSupplierQuotes = (id) => request({ url: baseUrl + '/' + id + '/supplier-quotes', method: 'get' }) +export const getClientQuotes = (id) => request({ url: baseUrl + '/' + id + '/client-quotes', method: 'get' }) +export const listManufacturer = () => request({ url: baseUrl + '/manufacturer/list', method: 'get' }) +export const compareMaterials = (data) => request({ url: baseUrl + '/compare', method: 'post', data }) + +// 同类型物料横向对比 +export const getSelectableMaterials = () => request({ url: baseUrl + '/selectable-for-comparison', method: 'get' }) +export const getQuoteComparison = (data) => request({ url: baseUrl + '/quote-comparison', method: 'post', data }) + +// 同名称不同规格/品牌对比 +export const getSameNameMaterials = (materialName, excludeId) => request({ + url: baseUrl + '/same-name/' + encodeURIComponent(materialName), + method: 'get', + params: excludeId ? { excludeId } : undefined +}) diff --git a/ruoyi-ui/src/assets/styles/index.scss b/ruoyi-ui/src/assets/styles/index.scss index bb87292c..f5278563 100644 --- a/ruoyi-ui/src/assets/styles/index.scss +++ b/ruoyi-ui/src/assets/styles/index.scss @@ -176,3 +176,28 @@ aside { margin-bottom: 10px; } } + +/* ========================================== + 表格展示优化 - 表头略大于数据,字体优化 + ========================================== */ +.el-table thead th { + font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + font-size: 14px; + font-weight: 600; + color: #303133; +} + +.el-table__body td { + font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + font-size: 13px; + color: #606266; +} + +.el-table__body .el-table__row { + height: 44px; +} + +.el-table--border th, +.el-table--border td { + padding: 6px 8px; +} diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js index 2dd6e790..60f2a6e6 100644 --- a/ruoyi-ui/src/router/index.js +++ b/ruoyi-ui/src/router/index.js @@ -98,6 +98,20 @@ export const constantRoutes = [ // 动态路由,基于用户权限动态去加载 export const dynamicRoutes = [ + { + path: '/bid/material/detail', + component: Layout, + hidden: true, + permissions: ['bid:material:detail'], + children: [ + { + path: '', + component: () => import('@/views/bid/material/detail'), + name: 'MaterialDetail', + meta: { title: '物料详情', activeMenu: '/bid/material' } + } + ] + }, { path: '/system/user-auth', component: Layout, diff --git a/ruoyi-ui/src/views/bid/comparison/index.vue b/ruoyi-ui/src/views/bid/comparison/index.vue index 5133a413..a5227804 100644 --- a/ruoyi-ui/src/views/bid/comparison/index.vue +++ b/ruoyi-ui/src/views/bid/comparison/index.vue @@ -74,7 +74,7 @@ export default { }, resetQuery() { this.queryParams = { pageNum: 1, pageSize: 10, rfqNo: null, rfqTitle: null }; this.getList(); }, goCompare(row) { - this.$router.push({ path: "/procurement/comparison/detail", query: { rfqId: row.rfqId } }); + this.$router.push({ path: "/bid/comparison/detail", query: { rfqId: row.rfqId } }); }, goRfqDetail(row) { this.$router.push({ path: "/procurement/rfq/detail", query: { rfqId: row.rfqId } }); diff --git a/ruoyi-ui/src/views/bid/material/components/BasicInfoTab.vue b/ruoyi-ui/src/views/bid/material/components/BasicInfoTab.vue new file mode 100644 index 00000000..ebb20d7a --- /dev/null +++ b/ruoyi-ui/src/views/bid/material/components/BasicInfoTab.vue @@ -0,0 +1,330 @@ + + + + + diff --git a/ruoyi-ui/src/views/bid/material/components/ClientQuoteTab.vue b/ruoyi-ui/src/views/bid/material/components/ClientQuoteTab.vue new file mode 100644 index 00000000..5aab7181 --- /dev/null +++ b/ruoyi-ui/src/views/bid/material/components/ClientQuoteTab.vue @@ -0,0 +1,53 @@ + + + diff --git a/ruoyi-ui/src/views/bid/material/components/CompareSection.vue b/ruoyi-ui/src/views/bid/material/components/CompareSection.vue new file mode 100644 index 00000000..509ff63e --- /dev/null +++ b/ruoyi-ui/src/views/bid/material/components/CompareSection.vue @@ -0,0 +1,719 @@ + + + + + diff --git a/ruoyi-ui/src/views/bid/material/components/DetailHeader.vue b/ruoyi-ui/src/views/bid/material/components/DetailHeader.vue new file mode 100644 index 00000000..33ca3aae --- /dev/null +++ b/ruoyi-ui/src/views/bid/material/components/DetailHeader.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue b/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue new file mode 100644 index 00000000..1909f12c --- /dev/null +++ b/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue @@ -0,0 +1,235 @@ + + + + + diff --git a/ruoyi-ui/src/views/bid/material/detail.vue b/ruoyi-ui/src/views/bid/material/detail.vue new file mode 100644 index 00000000..2947675f --- /dev/null +++ b/ruoyi-ui/src/views/bid/material/detail.vue @@ -0,0 +1,456 @@ + + + + + diff --git a/ruoyi-ui/src/views/bid/material/index.vue b/ruoyi-ui/src/views/bid/material/index.vue index 1c89cb90..75f52970 100644 --- a/ruoyi-ui/src/views/bid/material/index.vue +++ b/ruoyi-ui/src/views/bid/material/index.vue @@ -7,6 +7,11 @@ + + + + + - - - - - - - - - + + + + + + + + + + + + - + @@ -51,7 +71,8 @@ - + + @@ -72,29 +93,64 @@ - - - + + + - - - + + + + + + + + - - + + - - + + + + + + +
+ 添加参数 + + + + + + + + + + + + + + +
+
@@ -108,7 +164,7 @@ + + diff --git a/sql/20250527/01_material_alter.sql b/sql/20250527/01_material_alter.sql new file mode 100644 index 00000000..ea0ed467 --- /dev/null +++ b/sql/20250527/01_material_alter.sql @@ -0,0 +1,53 @@ +-- ======================================================== +-- 物料信息模块数据库扩展脚本 +-- 日期: 2025-05-27 +-- 说明: 根据智采系统-物料信息需求扩展biz_material表 +-- ======================================================== + +-- 1. 扩展物料表字段 +-- 注意: spec字段保持为"规格型号"不变 +-- 注意: remark字段保持不变 +-- 注意: brand字段改为"厂家/品牌" + +-- 使用存储过程判断字段是否存在,避免IF NOT EXISTS语法错误 +DELIMITER // + +CREATE PROCEDURE AddColumnIfNotExists(IN tableName VARCHAR(64), IN colName VARCHAR(64), IN colDef VARCHAR(255)) +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = tableName + AND column_name = colName + ) THEN + SET @sql = CONCAT('ALTER TABLE ', tableName, ' ADD COLUMN ', colName, ' ', colDef); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + END IF; +END // + +DELIMITER ; + +-- 添加性能参数字段 +CALL AddColumnIfNotExists('biz_material', 'performance_params', "TEXT COMMENT '性能参数(JSON格式)'"); + +-- 添加材质字段 +CALL AddColumnIfNotExists('biz_material', 'material', "VARCHAR(100) DEFAULT '' COMMENT '材质(铜/铝合金/PVC等)'"); + +-- 添加用途字段 +CALL AddColumnIfNotExists('biz_material', 'purpose', "VARCHAR(500) DEFAULT '' COMMENT '用途'"); + +-- 添加物料图片URL字段 +CALL AddColumnIfNotExists('biz_material', 'image_url', "VARCHAR(500) DEFAULT '' COMMENT '物料图片URL'"); + +-- 删除存储过程 +DROP PROCEDURE IF EXISTS AddColumnIfNotExists; + +-- 2. 修改brand字段注释为"厂家/品牌" +ALTER TABLE biz_material MODIFY COLUMN brand VARCHAR(100) COMMENT '厂家/品牌'; + +-- 3. 添加物料详情页菜单配置(使用INSERT IGNORE避免重复) +INSERT IGNORE INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +VALUES +(2011, '物料详情', 2001, 1, 'detail', 'bid/material/detail', NULL, 1, 0, 'C', '1', '0', 'bid:material:detail', '#', 'admin', NOW(), '', '', ''); diff --git a/sql/20260527/01_material_extension.sql b/sql/20260527/01_material_extension.sql new file mode 100644 index 00000000..1f331753 --- /dev/null +++ b/sql/20260527/01_material_extension.sql @@ -0,0 +1,52 @@ +-- ======================================================== +-- 物料信息模块数据库扩展脚本(二期) +-- 日期: 2026-05-27 +-- 说明: +-- 1. 新增字段: performance_params, material, purpose, image_url +-- 2. 修改 brand 字段注释为"厂家/品牌" +-- 3. 添加物料详情页菜单配置 +-- ======================================================== + +DELIMITER // + +CREATE PROCEDURE AddColumnIfNotExists(IN tableName VARCHAR(64), IN colName VARCHAR(64), IN colDef VARCHAR(255)) +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = tableName + AND column_name = colName + ) THEN + SET @sql = CONCAT('ALTER TABLE ', tableName, ' ADD COLUMN ', colName, ' ', colDef); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + END IF; +END // + +DELIMITER ; + +-- 添加性能参数字段(JSON格式存储) +CALL AddColumnIfNotExists('biz_material', 'performance_params', "TEXT COMMENT '性能参数(JSON格式)'"); + +-- 添加材质字段 +CALL AddColumnIfNotExists('biz_material', 'material', "VARCHAR(100) DEFAULT '' COMMENT '材质(铜/铝合金/PVC等)'"); + +-- 添加用途字段 +CALL AddColumnIfNotExists('biz_material', 'purpose', "VARCHAR(500) DEFAULT '' COMMENT '用途'"); + +-- 添加物料图片URL字段 +CALL AddColumnIfNotExists('biz_material', 'image_url', "VARCHAR(500) DEFAULT '' COMMENT '物料图片URL'"); + +-- 删除存储过程 +DROP PROCEDURE IF EXISTS AddColumnIfNotExists; + +-- 修改brand字段注释为"厂家/品牌" +ALTER TABLE biz_material MODIFY COLUMN brand VARCHAR(100) COMMENT '厂家/品牌'; + +-- 添加物料详情页菜单配置 +INSERT IGNORE INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +VALUES +(2011, '物料详情', 2001, 1, 'detail', 'bid/material/detail', NULL, 1, 0, 'C', '1', '0', 'bid:material:detail', '#', 'admin', NOW(), '', '', ''), +(2012, '物料新增', 2001, 2, 'add', 'bid/material/add', NULL, 1, 0, 'C', '1', '0', 'bid:material:add', '#', 'admin', NOW(), '', '', ''), +(2013, '物料修改', 2001, 3, 'edit', 'bid/material/edit', NULL, 1, 0, 'C', '1', '0', 'bid:material:edit', '#', 'admin', NOW(), '', '', ''); diff --git a/sql/bid_tables.sql b/sql/bid_tables.sql index 78087a69..2059fcc2 100644 --- a/sql/bid_tables.sql +++ b/sql/bid_tables.sql @@ -230,6 +230,7 @@ VALUES (2003,'报价请求',2000,3,'rfq','bid/rfq/index',NULL,1,0,'C','0','0','bid:rfq:list','form','admin',NOW(),'','',''), (2004,'供应商报价',2000,4,'quotation','bid/quotation/index',NULL,1,0,'C','0','0','bid:quotation:list','money','admin',NOW(),'','',''), (2005,'智慧比价',2000,5,'comparison','bid/comparison/index',NULL,1,0,'C','0','0','bid:comparison:list','chart','admin',NOW(),'','',''), +(2051,'比价详情',2005,1,'detail','bid/comparison/detail',NULL,1,0,'C','1','0','bid:comparison:detail','#','admin',NOW(),'','',''), (2006,'采购单',2000,6,'purchaseorder','bid/purchaseorder/index',NULL,1,0,'C','0','0','bid:purchaseorder:list','shopping','admin',NOW(),'','',''), (2007,'供应商评价',2000,7,'evaluation','bid/evaluation/index',NULL,1,0,'C','0','0','bid:evaluation:list','star','admin',NOW(),'','',''), (2008,'订单异议',2000,8,'objection','bid/objection/index',NULL,1,0,'C','0','0','bid:objection:list','warning','admin',NOW(),'','',''), diff --git a/sql/client_quote_fix.sql b/sql/client_quote_fix.sql new file mode 100644 index 00000000..7f6126f9 --- /dev/null +++ b/sql/client_quote_fix.sql @@ -0,0 +1,34 @@ +CREATE TABLE IF NOT EXISTS biz_client_quote ( + quote_id BIGINT NOT NULL AUTO_INCREMENT, + tenant_id BIGINT NOT NULL DEFAULT 1, + quote_no VARCHAR(50) DEFAULT '', + client_name VARCHAR(200) DEFAULT '', + rfq_id BIGINT DEFAULT NULL, + rfq_no VARCHAR(50) DEFAULT '', + rfq_title VARCHAR(200) DEFAULT '', + status VARCHAR(20) DEFAULT 'draft', + validity_date DATETIME DEFAULT NULL, + total_amount DECIMAL(15,4) DEFAULT 0, + currency VARCHAR(10) DEFAULT 'CNY', + remark TEXT, + create_by VARCHAR(64) DEFAULT '', + create_time DATETIME, + update_time DATETIME, + PRIMARY KEY (quote_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='甲方报价单'; + +CREATE TABLE IF NOT EXISTS biz_client_quote_item ( + item_id BIGINT NOT NULL AUTO_INCREMENT, + quote_id BIGINT NOT NULL, + material_name VARCHAR(200) DEFAULT '', + spec VARCHAR(500) DEFAULT '', + model_no VARCHAR(200) DEFAULT '', + unit VARCHAR(50) DEFAULT '', + quantity DECIMAL(15,4) DEFAULT 0, + cost_price DECIMAL(15,4) DEFAULT 0, + unit_price DECIMAL(15,4) DEFAULT 0, + total_price DECIMAL(15,4) DEFAULT 0, + delivery_days INT DEFAULT 0, + remark VARCHAR(500) DEFAULT '', + PRIMARY KEY (item_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='甲方报价明细';