platform-assistant/PRD-智能比价助手.md
Sisyphus 5a49a37235 docs: 项目交接文档 + 比价功能PRD + 数据维护脚本
- HANDOVER.md: 完整交接文档(架构/数据模型/API/业务流/已知坑/工作区状态/待办)
- PRD-智能比价助手.md: 比价功能产品需求文档(供外部平台参考)
- 数据维护脚本: 清理AI垃圾品类SQL、修复损坏标题SQL、线索重分类/重抓脚本
2026-09-30 09:35:05 +08:00

402 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 智能比价助手 - 产品需求文档 (PRD)
**版本**: v1.0
**日期**: 2025-08
**适用平台**: 参考设计文档,供其他平台二次开发/移植使用
**源项目**: 平台助手 - 智能比价助手模块
---
## 1. 产品概述
### 1.1 产品定位
**智能比价助手** 是面向采购场景的多供应商报价自动对齐与智能决策工具。核心价值:**将非结构化的供应商报价文件(Excel/CSV)转化为结构化可比价数据,通过算法自动生成最优采购方案(拆分/集中/限制供应商数),输出可执行的采购建议报告。**
### 1.2 核心用户场景
| 场景 | 痛点 | 解决方案 |
|------|------|----------|
| 采购员收到多家供应商报价单 | 格式不一、人工对齐耗时、易漏项 | 拖拽上传 → 自动解析 → 以商品名+规格自动对齐 |
| 不知道找哪家供应商最便宜 | 需人工逐行对比、易漏最优 | 自动计算每SKU最优/次优供应商、价差、降本率 |
| 纠结是集中采购还是拆分采购 | 缺量化依据、靠经验拍脑袋 | 三大策略对比:集中采购 / 无限制拆分 / 限制K家供应商 |
| 需向领导汇报采购方案 | 缺专业报告、数据支撑弱 | 一键生成含策略对比、SKU明细、供应商画像、降本测算的结构化报告 |
---
## 2. 系统架构
### 2.1 技术栈
| 层 | 技术选型 |
|----|----------|
| 后端框架 | NestJS 10 + TypeScript |
| 数据库 | SQLite (Prisma ORM) / 可替换为 PostgreSQL/MySQL |
| 文件解析 | Python 脚本 `parse_products.py` (pandas/openpyxl) |
| 前端框架 | Next.js 14 App Router + React 18 + Tailwind CSS 3 |
| 状态管理 | React useState + useEffect (SPA 无路由模式) |
| 文件上传 | Multer + FormData 拖拽上传 |
### 2.2 模块依赖
```
ComparisonModule
├── ComparisonController (REST API)
├── ComparisonService (核心业务逻辑)
├── PrismaModule (数据库)
└── (无外部服务依赖)
```
---
## 3. 数据模型
### 3.1 核心实体:Product (供应商报价条目)
```prisma
model Product {
id String @id @default(uuid())
name String // 商品名称(去重键核心字段)
spec String // 规格型号
unit String // 单位(个/吨/米/卷...)
price Float // 单价
quantity Int // 数量/采购量
category String // 品类(用于筛选/统计)
brand String? // 品牌
supplier String // 供应商名称(去重键辅助字段)
minOrder Int? // 起订量
imageUrl String? // 图片URL
status String @default("draft") // draft/published
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
```
### 3.2 聚合视图:ComparisonItem (比价分析输出)
```typescript
interface ComparisonItem {
productName: string; // 商品名(去重后)
spec: string; // 规格
category: string; // 品类
quantity: number; // 采购量(取该商品所有报价的最大值)
suppliers: SupplierInfo[]; // 去重后的供应商报价列表
bestPrice: number; // 最低价
bestSupplier: string; // 最优供应商名
hasSupplier: boolean; // 是否有有效供应商报价
savings: number; // 平均价 - 最优价(单价维度)
priceSpread: number; // 最高价 - 最低价(价差)
}
interface SupplierInfo {
id: string;
name: string;
price: number;
unit: string;
spec: string;
brand?: string;
minOrder?: number;
imageUrl?: string;
}
```
### 3.3 采购建议报告
```typescript
interface SuggestionReport {
// 核心汇总
totalItems: number; // 参与比价的SKU数
totalSplitCost: number; // 无限制拆分总价
savingsVsSingle: number; // 拆分 vs 单一供应商节省金额
savingsPctVsSingle: number; // 综合降本比例
bestSingleSupplier: { name, total }; // 单一供应商最优方案
// 策略维度
supplierRanking: { name, total, skuCount }[]; // 单一供应商总价排名
splitPicks: SplitPick[]; // 无限制拆分时每SKU最优分配
splitByCount: { // 限制K家供应商时的最优组合
2: StrategyResult;
3: StrategyResult;
4: StrategyResult;
};
// 可执行建议
recommendations: string[]; // 自然语言建议列表
}
```
---
## 4. 核心 API 设计
### 4.1 REST Endpoints
| 方法 | 路径 | 说明 | 请求/响应 |
|------|------|------|-----------|
| GET | `/api/comparison` | 获取所有商品分组比价数据 | 返回 `ComparisonItem[]` |
| POST | `/api/comparison/upload` | 上传供应商报价文件 | multipart/form-data: file + supplier |
| POST | `/api/comparison/suggestion` | 生成采购建议报告 | 返回 `SuggestionReport` |
### 4.2 请求/响应示例
**上传报价**
```bash
curl -X POST /api/comparison/upload \
-F "file=@quote.xlsx" \
-F "supplier=远东电缆"
```
```json
{ "count": 45, "supplier": "远东电缆" }
```
**获取建议**
```bash
curl -X POST /api/comparison/suggestion
```
```json
{
"totalItems": 12,
"totalSplitCost": 125600.00,
"savingsVsSingle": 18500.50,
"savingsPctVsSingle": 12.8,
"bestSingleSupplier": { "name": "远东电缆", "total": 144100.50 },
"supplierRanking": [
{ "name": "远东电缆", "total": 144100.50, "skuCount": 12 },
{ "name": "宝胜电缆", "total": 152300.00, "skuCount": 10 }
],
"splitPicks": [...],
"splitByCount": { "2": {...}, "3": {...}, "4": {...} },
"recommendations": [
"本次比价共涉及 12 个SKU,2 家供应商参与报价。",
"按SKU拆分下单比统一从「远东电缆」采购可再节省 ¥18500.50(降本 12.8%)。"
]
}
```
---
## 5. 核心算法逻辑
### 5.1 数据聚合与去重 (`getComparisonData`)
```typescript
// 核心步骤:
// 1. 读取所有 Product 记录
// 2. 按 name.trim().toLowerCase() 分组(商品名去重)
// 3. 组内按 supplier 去重 → 同一供应商保留最低价
// 4. 计算每组统计指标:
// - bestPrice / bestSupplier
// - savings = avgPrice - bestPrice
// - priceSpread = maxPrice - minPrice
```
**去重策略**:
- **商品级**:`name` 忽略大小写/首尾空格分组
- **供应商级**:组内按 `supplier` 去重,保留最低价
- **数量取最大值**:`quantity = max(所有报价的 quantity)`
### 5.2 无限制拆分策略 (`getSuggestion` → splitPicks)
每个 SKU 独立选择最低总价供应商:
```
对每个 SKU:
1. 计算各供应商总价 = price * quantity
2. 选总价最低者为最优
3. 次优 = 总价第二低者
4. 单品节省 = 次优总价 - 最优总价
```
**输出**:`splitPicks[]` + `totalSplitCost` + `supplierSplitCounts`(各供应商中标SKU数)
### 5.3 单一供应商策略 (`supplierRanking`)
```
对每个供应商:
总价 = Σ(该供应商所有SKU的 price * quantity)
SKU数 = 该供应商有报价的SKU数
按总价升序排序 → bestSingleSupplier = 第1名
```
### 5.4 限制 K 家供应商策略 (`splitByCount[K]`)
**组合枚举 + 贪心分配**:
```
输入:所有供应商名单 allNames,目标数量 K (2/3/4)
对于 allNames 中所有 C(n, K) 种组合:
对每个 SKU:
从组合中选价格最低的供应商
累加总价
记录总价最低的组合
```
**复杂度**:C(n, K) × m (SKU数)。n≤10, K≤4 时可接受(C(10,4)=210)。
**输出**:
- `bestSuppliers`: 实际使用的供应商列表(去除组合中未中标者)
- `totalCost`: 最优总价
- `assignments[]`: 每SKU的分配明细
- `supplierBreakdown`: 各供应商中标SKU数/金额占比
### 5.3 采购建议生成 (`recommendations`)
基于规则引擎生成自然语言建议:
1. **概况**:SKU数、供应商数
2. **拆分 vs 集中**:若 `savingsVsSingle > 0` → 推荐拆分 + 具体金额/比例
3. **优势供应商**:`supplierSplitCounts` Top 3
4. **最大价差SKU**:`splitPicks` 中 savings 最大者
5. **风险提示**:SKU>10 时提示交付协调风险
---
## 6. 前端交互流程
### 6.1 三步向导式交互
```
Step 1: 上传报价 (upload)
├── 输入供应商名称
├── 拖拽/点击上传 .xlsx/.xls/.csv
├── Python脚本解析 → 入库
└── 显示已上传供应商列表 + 报价条数
Step 2: 比价分析 (compare)
├── 表格展示:商品名 | 规格 | 数量 | 各供应商单价 | 最优价 | 价差
├── 最优价绿色高亮,缺报显示 "-"
├── 支持按价格/名称/节省金额排序
└── 无供应商对比数据单独展示
Step 3: 采购建议 (suggestion)
├── Hero汇总卡:拆分总价 / 节省金额 / 降本率
├── 策略对比卡:
│ ├── A方案:单一供应商(含供应商总价排名表)
│ └── B方案:拆分采购(含K家供应商选择器 K=2/3/4)
│ ├── 动态条形图:供应商中标SKU占比
│ └── 明细表:每SKU分配供应商/单价/数量/总价
├── SKU明细表:推荐供应商/单价/总价/次优总价/节省/降本率
├── 采购建议列表(自然语言)
└── 导出 CSV 报告
```
### 6.2 关键交互细节
| 交互 | 实现细节 |
|------|----------|
| 文件上传 | 拖拽区域 + 点击选择,支持 .xlsx/.xls/.csv,显示上传进度 |
| 供应商名称 | 必填校验,作为报价归属标识 |
| K值选择器 | 2/3/4 三按钮,单选互斥,支持取消选中回退无限制方案 |
| 表格高亮 | 最优价格绿色背景+粗体,价差红色显示 |
| 空状态处理 | 无数据/无对比数据分别展示占位提示 |
| 导出CSV | BOM头防乱码,含完整SKU明细列 |
---
## 7. 文件解析规范
### 7.1 支持格式
- `.xlsx` / `.xls` (Excel)
- `.csv` (逗号分隔)
### 7.2 必需列映射 (parse_products.py)
| 标准列名 | 别名/兼容 | 说明 |
|----------|-----------|------|
| `title` / `name` | 商品名称、产品名称 | 必填,作为去重主键 |
| `spec` | 规格、型号 | 可选 |
| `unit` | 单位 | 默认 "个" |
| `price` | 单价、价格 | 必填,数值型 |
| `quantity` | 数量、采购量 | 默认 1 |
| `category` | 品类、分类 | 默认 "未分类" |
| `brand` | 品牌 | 可选 |
| `minOrder` | 起订量 | 可选 |
### 7.3 解析脚本接口
```python
# scripts/parse_products.py
# 输入: 文件路径
# 输出: JSON 数组到 stdout
# 格式: [{"title": "...", "spec": "...", "price": 100, ...}, ...]
# 错误: 输出 {"error": "错误信息"} 到 stdout
```
---
## 8. 部署与运维
### 8.1 环境变量
```env
DATABASE_URL=file:./dev.db # SQLite文件路径
# 或 PostgreSQL: postgresql://user:pass@host:5432/db
```
### 8.2 启动命令
```bash
# 开发
npm run dev # 同时启动前端(3001) + 后端(4000)
npm run dev:api # 仅后端
npm run dev:web # 仅前端
# 生产部署
npm run build
bash scripts/deploy.sh # 一键构建+rsync+PM2重启
```
### 8.3 生产架构
```
Nginx (80/443)
├── /api/* → NestJS:4000
├── /uploads/* → 静态文件 /data/pingtai/uploads/
└── /* → Next.js:3001
PM2 管理: pingtai-api, pingtai-web
```
---
## 9. 扩展指南
### 9.1 新增策略维度
在 `ComparisonService.getSuggestion()` 中扩展:
1. 新增 `splitByCount[K]` 的 K 值
2. 或新增约束维度(如:按品牌集中、按地区集中、按最小起订量过滤)
3. 在 `recommendations` 中增加对应建议文案
### 9.2 多租户隔离
当前单租户设计,扩展多租户需:
- `Product` 增加 `tenantId` 字段 + 复合索引
- API 增加租户上下文中间件
- `getComparisonData` / `getSuggestion` 加 `where: { tenantId }`
### 9.3 报价有效期管理
- `Product` 增加 `validFrom` / `validTo` 字段
- 查询时过滤 `validTo >= now()`
- 前端增加"报价有效期"筛选器
### 9.4 供应商画像扩展
- 新增 `Supplier` 实体:资质、交付周期、历史履约率、质量评分
- 建议算法引入权重:`综合得分 = 价格权重*0.6 + 交付权重*0.2 + 质量权重*0.2`
---
## 10. 附录:关键代码路径速查
| 功能 | 文件路径 |
|------|----------|
| 比价数据聚合 | `apps/api/src/comparison/comparison.service.ts:12-69` |
| 采购建议核心算法 | `apps/api/src/comparison/comparison.service.ts:131-314` |
| K家供应商组合优化 | `apps/api/src/comparison/comparison.service.ts:254-314` |
| 报价文件上传解析 | `apps/api/src/comparison/comparison.service.ts:71-129` |
| Python解析脚本 | `scripts/parse_products.py` |
| 前端三步向导主页 | `apps/web/src/components/ComparisonPage.tsx` |
| 比价表格渲染 | `ComparisonPage.tsx:256-320` |
| 采购建议报告UI | `ComparisonPage.tsx:327-623` |
| 导出CSV逻辑 | `ComparisonPage.tsx:606-617` |
---
## 11. 迁移清单 (给目标平台)
- [ ] 复刻 `Product` 数据模型到目标数据库
- [ ] 移植 `parse_products.py` 适配目标平台的文件存储
- [ ] 实现 `ComparisonService` 核心类(去重、聚合、三大策略算法)
- [ ] 暴露 3 个 REST API 端点
- [ ] 实现前端三步向导页面(上传/比价/建议)
- [ ] 集成文件上传组件 + 进度反馈
- [ ] 实现 CSV 导出功能
- [ ] 补充单元测试:去重逻辑、K组合枚举、边界情况(单供应商、无报价SKU)
- [ ] 压力测试:1000 SKU × 10 供应商 × K=4 组合枚举性能
---
**文档结束** — 如有疑问可参考源码实现细节。建议先跑通核心算法单元测试,再集成前后端。