354 lines
11 KiB
Markdown
354 lines
11 KiB
Markdown
# 数据源标识系统说明
|
||
|
||
## 概述
|
||
|
||
为了清晰区分来自三个不同接口的数据,我们为每个数据源添加了明确的标识字段。这样可以:
|
||
|
||
1. **清晰区分数据来源** - 知道数据来自哪个接口
|
||
2. **便于数据筛选** - 按数据源查询和统计
|
||
3. **数据溯源** - 追踪数据的采集方式(本地文件或 API)
|
||
4. **避免数据混淆** - 即使数据相似也能区分来源
|
||
|
||
## 数据源配置
|
||
|
||
### 三个接口的标识
|
||
|
||
| 接口端点 | 数据来源 | 标识码 | 颜色标签 | 描述 |
|
||
|---------|---------|--------|---------|------|
|
||
| `DEFAULT` | 云南钢协 | `YUNNAN_STEEL_ASSOC` | 🔴 #FF6B6B | 云南钢协指导价(API) |
|
||
| `BACKUP` | 我的钢铁 | `MY_STEEL` | 🔵 #4ECDC4 | 我的钢铁网价格(API) |
|
||
| `EXTENDED` | 德钢指导价 | `DE_STEEL_FACTORY` | 🟢 #95E1D3 | 德钢钢厂指导价(API) |
|
||
|
||
### 本地文件映射
|
||
|
||
| 文件名 | 数据来源 | 标识码 | 颜色标签 | 描述 |
|
||
|-------|---------|--------|---------|------|
|
||
| `刚协指导价.json` | 云南钢协 | `YUNNAN_STEEL_ASSOC` | 🔴 #FF6B6B | 云南钢协指导价 |
|
||
| `钢材网架.json` | 我的钢铁 | `MY_STEEL` | 🔵 #4ECDC4 | 我的钢铁网价格 |
|
||
| `钢厂指导价.json` | 德钢指导价 | `DE_STEEL_FACTORY` | 🟢 #95E1D3 | 德钢钢厂指导价 |
|
||
|
||
## 数据库字段说明
|
||
|
||
### 新增字段
|
||
|
||
```sql
|
||
-- 数据源代码(唯一标识)
|
||
price_source_code VARCHAR(32) NOT NULL
|
||
-- 可能的值: 'YUNNAN_STEEL_ASSOC', 'MY_STEEL', 'DE_STEEL_FACTORY'
|
||
|
||
-- 数据源描述
|
||
price_source_desc VARCHAR(64) NOT NULL
|
||
-- 例如: '云南钢协指导价(API)', '我的钢铁网价格(API)'
|
||
|
||
-- 数据来源标识
|
||
data_origin VARCHAR(32) NOT NULL
|
||
-- 格式:
|
||
-- - 'LOCAL_FILE' - 从本地文件导入
|
||
-- - 'API:DEFAULT' - 从 DEFAULT 接口导入
|
||
-- - 'API:BACKUP' - 从 BACKUP 接口导入
|
||
-- - 'API:EXTENDED' - 从 EXTENDED 接口导入
|
||
```
|
||
|
||
### 完整表结构
|
||
|
||
```sql
|
||
CREATE TABLE prices (
|
||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||
price_id VARCHAR(64) UNIQUE NOT NULL,
|
||
goods_material VARCHAR(32) NOT NULL,
|
||
goods_spec VARCHAR(16) NOT NULL,
|
||
partsname_name VARCHAR(32) NOT NULL,
|
||
productarea_name VARCHAR(64) NOT NULL,
|
||
|
||
-- 数据源标识字段
|
||
price_source VARCHAR(32) NOT NULL, -- 原有字段:价格来源名称
|
||
price_source_code VARCHAR(32) NOT NULL, -- 新增:数据源代码
|
||
price_source_desc VARCHAR(64) NOT NULL, -- 新增:数据源描述
|
||
data_origin VARCHAR(32) NOT NULL, -- 新增:数据来源标识
|
||
|
||
price_region VARCHAR(32) NOT NULL,
|
||
pntree_name VARCHAR(32) NOT NULL,
|
||
price_date DATETIME NOT NULL,
|
||
make_price INT DEFAULT NULL,
|
||
hang_price INT NOT NULL,
|
||
last_make_price INT DEFAULT NULL,
|
||
last_hang_price INT DEFAULT NULL,
|
||
make_price_updw VARCHAR(8) DEFAULT NULL,
|
||
hang_price_updw VARCHAR(8) DEFAULT NULL,
|
||
operator_code VARCHAR(16) DEFAULT NULL,
|
||
operator_name VARCHAR(32) DEFAULT NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
-- 索引
|
||
INDEX idx_price_date (price_date),
|
||
INDEX idx_region_material (price_region, goods_material),
|
||
INDEX idx_source_date (price_source, price_date),
|
||
INDEX idx_source_code (price_source_code), -- 新增:按数据源代码查询
|
||
INDEX idx_data_origin (data_origin), -- 新增:按数据来源查询
|
||
INDEX idx_goods_spec (goods_spec)
|
||
);
|
||
```
|
||
|
||
## 使用示例
|
||
|
||
### 1. 数据库迁移(为现有表添加新字段)
|
||
|
||
```bash
|
||
npm run db:migrate
|
||
```
|
||
|
||
**输出示例:**
|
||
```
|
||
🔄 开始数据库迁移:添加数据源标识字段
|
||
|
||
✅ 数据源字段迁移成功
|
||
|
||
============================================================
|
||
✅ 数据库迁移完成!
|
||
============================================================
|
||
|
||
📊 新增字段说明:
|
||
- price_source_code: 数据源代码(YUNNAN_STEEL_ASSOC / MY_STEEL / DE_STEEL_FACTORY)
|
||
- price_source_desc: 数据源描述
|
||
- data_origin: 数据来源标识(LOCAL_FILE 或 API:ENDPOINT)
|
||
|
||
🎨 数据源标识:
|
||
🔴 YUNNAN_STEEL_ASSOC - 云南钢协指导价(DEFAULT 接口)
|
||
🔵 MY_STEEL - 我的钢铁网价格(BACKUP 接口)
|
||
🟢 DE_STEEL_FACTORY - 德钢钢厂指导价(EXTENDED 接口)
|
||
```
|
||
|
||
### 2. 从 API 接口导入数据(带标识)
|
||
|
||
```bash
|
||
# 导入云南钢协数据(DEFAULT 接口)
|
||
node scripts/import-data.js single-api DEFAULT
|
||
|
||
# 导入我的钢铁数据(BACKUP 接口)
|
||
node scripts/import-data.js single-api BACKUP
|
||
|
||
# 导入德钢指导价数据(EXTENDED 接口)
|
||
node scripts/import-data.js single-api EXTENDED
|
||
|
||
# 从所有 API 接口导入
|
||
npm run db:import:api
|
||
```
|
||
|
||
**导入过程示例:**
|
||
```
|
||
🌐 正在从 API 接口获取数据: DEFAULT
|
||
📊 数据源: 云南钢协指导价(API)
|
||
🏷️ 标识码: YUNNAN_STEEL_ASSOC
|
||
🎨 标签: #FF6B6B
|
||
📅 查询参数: {
|
||
"startDate": "2025-01-06",
|
||
"endDate": "2026-01-06",
|
||
"page": 1,
|
||
"pageSize": 100000
|
||
}
|
||
🔐 正在获取 Token...
|
||
✅ Token 获取成功
|
||
🔄 切换到接口: 默认钢材价格查询
|
||
Page ID: PG-D615-D8E2-2FD84B8D
|
||
Menu ID: MK-A8B8-109E-13D34116
|
||
✅ 解析到 1250 条有效数据
|
||
进度: 1000/1250 条
|
||
进度: 1250/1250 条
|
||
✅ 成功导入 1250 条数据
|
||
```
|
||
|
||
### 3. 从本地文件导入数据(带标识)
|
||
|
||
```bash
|
||
# 从本地文件导入
|
||
npm run db:import:local
|
||
```
|
||
|
||
**导入过程示例:**
|
||
```
|
||
📄 正在读取本地文件: 刚协指导价.json
|
||
📊 数据源: 云南钢协指导价
|
||
🏷️ 标识码: YUNNAN_STEEL_ASSOC
|
||
🎨 标签: #FF6B6B
|
||
✅ 解析到 900 条有效数据
|
||
进度: 900/900 条
|
||
✅ 成功导入 900 条数据
|
||
```
|
||
|
||
## 数据查询示例
|
||
|
||
### SQL 查询
|
||
|
||
#### 1. 查询所有数据源统计
|
||
|
||
```sql
|
||
SELECT
|
||
price_source_code AS '数据源代码',
|
||
price_source_desc AS '数据源描述',
|
||
data_origin AS '数据来源',
|
||
COUNT(*) AS '记录数',
|
||
AVG(hang_price) AS '平均价格',
|
||
MIN(hang_price) AS '最低价格',
|
||
MAX(hang_price) AS '最高价格'
|
||
FROM prices
|
||
GROUP BY price_source_code, price_source_desc, data_origin
|
||
ORDER BY price_source_code;
|
||
```
|
||
|
||
**结果示例:**
|
||
```
|
||
+---------------------+----------------------+----------------+----------+----------+----------+----------+
|
||
| 数据源代码 | 数据源描述 | 数据来源 | 记录数 | 平均价格 | 最低价格 | 最高价格 |
|
||
+---------------------+----------------------+----------------+----------+----------+----------+----------+
|
||
| YUNNAN_STEEL_ASSOC | 云南钢协指导价(API) | API:DEFAULT | 1250 | 4500.50 | 3800 | 5200 |
|
||
| YUNNAN_STEEL_ASSOC | 云南钢协指导价 | LOCAL_FILE | 900 | 4480.30 | 3850 | 5180 |
|
||
| MY_STEEL | 我的钢铁网价格(API) | API:BACKUP | 850 | 4420.80 | 3700 | 5150 |
|
||
| MY_STEEL | 我的钢铁网价格 | LOCAL_FILE | 211 | 4400.60 | 3750 | 5120 |
|
||
| DE_STEEL_FACTORY | 德钢钢厂指导价(API)| API:EXTENDED | 15000 | 4550.20 | 3900 | 5300 |
|
||
| DE_STEEL_FACTORY | 德钢钢厂指导价 | LOCAL_FILE | 29987 | 4530.90 | 3880 | 5280 |
|
||
+---------------------+----------------------+----------------+----------+----------+----------+----------+
|
||
```
|
||
|
||
#### 2. 按数据源筛选
|
||
|
||
```sql
|
||
-- 查询云南钢协的数据
|
||
SELECT * FROM prices
|
||
WHERE price_source_code = 'YUNNAN_STEEL_ASSOC'
|
||
ORDER BY price_date DESC;
|
||
|
||
-- 查询从 API 导入的数据
|
||
SELECT * FROM prices
|
||
WHERE data_origin LIKE 'API:%'
|
||
ORDER BY price_date DESC;
|
||
|
||
-- 查询特定接口的数据
|
||
SELECT * FROM prices
|
||
WHERE data_origin = 'API:DEFAULT'
|
||
ORDER BY price_date DESC;
|
||
```
|
||
|
||
#### 3. 对比不同数据源的价格
|
||
|
||
```sql
|
||
SELECT
|
||
DATE(price_date) AS '日期',
|
||
price_source_code AS '数据源',
|
||
AVG(hang_price) AS '平均价格'
|
||
FROM prices
|
||
WHERE DATE(price_date) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
|
||
GROUP BY DATE(price_date), price_source_code
|
||
ORDER BY DATE(price_date), price_source_code;
|
||
```
|
||
|
||
### Node.js 查询
|
||
|
||
```javascript
|
||
// 查询特定数据源的数据
|
||
const yunnanSteelPrices = await Price.search({
|
||
material: 'HRB400E',
|
||
startDate: '2025-01-01',
|
||
endDate: '2025-01-31'
|
||
});
|
||
|
||
// 过滤云南钢协数据
|
||
const filtered = yunnanSteelPrices.filter(item =>
|
||
item.price_source_code === 'YUNNAN_STEEL_ASSOC'
|
||
);
|
||
|
||
// 按数据源分组统计
|
||
const statsBySource = await Price.getStats({
|
||
/* 可以扩展 getStats 方法支持按数据源统计 */
|
||
});
|
||
```
|
||
|
||
## API 接口返回数据格式
|
||
|
||
导入数据时,每条记录将包含以下标识字段:
|
||
|
||
```json
|
||
{
|
||
"price_id": "abc123...",
|
||
"goods_material": "HRB400E",
|
||
"goods_spec": "Φ18",
|
||
"partsname_name": "螺纹钢",
|
||
"productarea_name": "云南德胜",
|
||
"price_source": "云南钢协",
|
||
"price_source_code": "YUNNAN_STEEL_ASSOC", // 数据源代码
|
||
"price_source_desc": "云南钢协指导价(API)", // 数据源描述
|
||
"data_origin": "API:DEFAULT", // 数据来源标识
|
||
"price_region": "昆明",
|
||
"pntree_name": "钢筋",
|
||
"price_date": "2025-01-06 00:00:00",
|
||
"make_price": 4450,
|
||
"hang_price": 4500,
|
||
"last_make_price": 4400,
|
||
"last_hang_price": 4450,
|
||
"make_price_updw": "+50",
|
||
"hang_price_updw": "+50"
|
||
}
|
||
```
|
||
|
||
## 颜色标签使用建议
|
||
|
||
这些颜色标签可以在前端界面中使用,帮助用户直观区分数据来源:
|
||
|
||
```javascript
|
||
const SOURCE_COLORS = {
|
||
YUNNAN_STEEL_ASSOC: '#FF6B6B', // 红色 - 云南钢协
|
||
MY_STEEL: '#4ECDC4', // 蓝绿色 - 我的钢铁
|
||
DE_STEEL_FACTORY: '#95E1D3' // 绿色 - 德钢指导价
|
||
};
|
||
|
||
// 在 React/Vue 等前端框架中使用
|
||
<div style={{ color: SOURCE_COLORS[item.price_source_code] }}>
|
||
{item.price_source_desc}
|
||
</div>
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **唯一性**: `price_source_code` 是数据源的唯一标识,建议在业务逻辑中使用
|
||
2. **兼容性**: 原有的 `price_source` 字段保留,用于显示中文名称
|
||
3. **索引优化**: 已为 `price_source_code` 和 `data_origin` 添加索引,查询性能更好
|
||
4. **数据迁移**: 如果已有数据,运行迁移脚本会自动添加新字段并设置默认值
|
||
|
||
## 故障排查
|
||
|
||
### 问题 1: 迁移后新字段为空
|
||
|
||
**原因**: 旧数据没有标识字段信息
|
||
|
||
**解决方案**:
|
||
```sql
|
||
-- 更新旧数据的标识字段
|
||
UPDATE prices SET
|
||
price_source_code = CASE
|
||
WHEN price_source = '云南钢协' THEN 'YUNNAN_STEEL_ASSOC'
|
||
WHEN price_source = '我的钢铁' THEN 'MY_STEEL'
|
||
WHEN price_source = '德钢指导价' THEN 'DE_STEEL_FACTORY'
|
||
ELSE 'UNKNOWN'
|
||
END,
|
||
price_source_desc = price_source,
|
||
data_origin = 'LOCAL_FILE'
|
||
WHERE data_origin = '' OR data_origin IS NULL;
|
||
```
|
||
|
||
### 问题 2: 导入数据时字段未填充
|
||
|
||
**原因**: 导入脚本版本过旧
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 确保使用最新的 import-data.js
|
||
git pull origin main
|
||
npm run db:import:api
|
||
```
|
||
|
||
## 相关文档
|
||
|
||
- [导入脚本使用说明](../scripts/README-IMPORT.md)
|
||
- [API 接口文档](../docs/IMPORT_API.md)
|
||
- [数据库设计文档](../docs/DATABASE_SCHEMA.md)
|