# 数据导入 API 文档 ## POST /api/prices/import 批量导入钢材价格数据到数据库。 ### 请求格式 **Content-Type:** `application/json` **请求体:** ```json { "prices": [ { "price_id": "2008067775216672769", "goods_material": "HPB300", "goods_spec": "Φ8", "partsname_name": "螺纹钢", "productarea_name": "昆钢", "price_source": "我的钢铁", "price_region": "昆明", "pntree_name": "钢筋", "price_date": "2026-01-05T10:30:00.000Z", "make_price": 3800, "hang_price": 3850, "last_make_price": 3750, "last_hang_price": 3800, "make_price_updw": "↑50", "hang_price_updw": "↑50", "operator_code": "OP001", "operator_name": "张三" } ] } ``` ### 字段说明 #### 必填字段 | 字段名 | 类型 | 说明 | 示例 | |--------|------|------|------| | `goods_material` | string | 材质牌号 | `"HPB300"` | | `goods_spec` | string | 规格型号 | `"Φ8"` | | `partsname_name` | string | 品名 | `"螺纹钢"` | | `productarea_name` | string | 产地/钢厂 | `"昆钢"` | | `price_source` | string | 价格来源 | `"我的钢铁"` | | `price_region` | string | 价格地区 | `"昆明"` | | `price_date` | string | 价格日期(ISO 8601) | `"2026-01-05T10:30:00.000Z"` | | `hang_price` | number | 挂牌价(元/吨) | `3850` | #### 可选字段 | 字段名 | 类型 | 说明 | 默认值 | 示例 | |--------|------|------|--------|------| | `price_id` | string | 价格唯一ID(为空时自动生成) | `null` | `"2008067775216672769"` | | `pntree_name` | string | 分类名称 | `"钢筋"` | `"钢筋"` | | `make_price` | number | 钢厂价(元/吨) | `null` | `3800` | | `last_make_price` | number | 上次钢厂价 | `null` | `3750` | | `last_hang_price` | number | 上次挂牌价 | `null` | `3800` | | `make_price_updw` | string | 钢厂价涨跌 | `null` | `"↑50"` | | `hang_price_updw` | string | 挂牌价涨跌 | `null` | `"↑50"` | | `operator_code` | string | 操作员代码 | `null` | `"OP001"` | | `operator_name` | string | 操作员名称 | `null` | `"张三"` | #### 自动生成字段 以下字段由系统自动生成,无需传入: - `id` - 自增主键 - `created_at` - 创建时间 - `updated_at` - 更新时间 ### price_id 自动生成规则 如果传入的数据中 `price_id` 为空或不存在,系统会基于以下字段生成 MD5 哈希值: ``` {goods_material}-{goods_spec}-{price_region}-{price_source}-{price_date} ``` **示例:** ``` HPB300-Φ8-昆明-我的钢铁-2026-01-05T10:30:00.000Z ↓ MD5 哈希 a1b2c3d4e5f6...(32 位十六进制字符串) ``` 这样可以确保相同业务数据不会重复插入。 ### 响应格式 #### 成功响应 **HTTP Status:** `200 OK` ```json { "success": true, "message": "成功导入 100 条数据", "data": { "imported": 100, "total": 105, "validCount": 100, "errorCount": 5, "errors": [ { "index": 3, "data": { ... }, "reasons": { "missing": ["hang_price"], "invalid": [ { "field": "price_date", "expected": "valid Date", "received": "invalid-date" } ] } } ] } } ``` #### 失败响应 **HTTP Status:** `200 OK` (业务失败) ```json { "success": false, "message": "没有有效的数据可以导入", "data": { "total": 10, "imported": 0, "errors": [ { "index": 0, "data": { ... }, "reasons": { "missing": ["goods_material", "hang_price"], "invalid": [] } } ] } } ``` #### 服务器错误 **HTTP Status:** `500 Internal Server Error` ```json { "success": false, "error": "数据库连接失败" } ``` ### 数据验证规则 #### 必填字段验证 - 所有必填字段不能为空、null 或 undefined - 字符串字段长度不能为 0 #### 数据类型验证 | 字段 | 允许的类型 | 验证规则 | |------|-----------|----------| | `hang_price` | `number` | 必须是有效数字,不能为 NaN | | `make_price` | `number` \| `null` | 如果存在,必须是有效数字 | | `last_make_price` | `number` \| `null` | 如果存在,必须是有效数字 | | `last_hang_price` | `number` \| `null` | 如果存在,必须是有效数字 | | `price_date` | `string` \| `Date` | 必须是有效的日期格式 | ### 错误处理 #### 数据格式错误 如果传入的数据不符合格式要求: ```json { "success": false, "message": "无效的数据格式", "error": "数据必须是数组格式" } ``` #### 缺少必填字段 如果某条记录缺少必填字段,该记录会被跳过,错误信息会返回在响应中: ```json { "success": true, "message": "成功导入 95 条数据,5 条数据因格式错误被跳过", "data": { "imported": 95, "total": 100, "validCount": 95, "errorCount": 5, "errors": [ { "index": 10, "data": { "goods_material": "HPB300" }, "reasons": { "missing": ["goods_spec", "hang_price", "price_date"], "invalid": [] } } ] } } ``` ### 使用示例 #### JavaScript (Fetch API) ```javascript const response = await fetch('http://localhost:3000/api/prices/import', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prices: [ { goods_material: 'HPB300', goods_spec: 'Φ8', partsname_name: '螺纹钢', productarea_name: '昆钢', price_source: '我的钢铁', price_region: '昆明', price_date: '2026-01-05T10:30:00.000Z', hang_price: 3850 } ] }) }); const result = await response.json(); console.log(result); ``` #### cURL ```bash curl -X POST http://localhost:3000/api/prices/import \ -H "Content-Type: application/json" \ -d '{ "prices": [ { "goods_material": "HPB300", "goods_spec": "Φ8", "partsname_name": "螺纹钢", "productarea_name": "昆钢", "price_source": "我的钢铁", "price_region": "昆明", "price_date": "2026-01-05T10:30:00.000Z", "hang_price": 3850 } ] }' ``` ### 注意事项 1. **批量限制**:建议单次导入不超过 1000 条记录 2. **重复数据处理**:使用 `ON DUPLICATE KEY UPDATE` 机制自动更新已存在的记录 3. **事务处理**:每次批量插入是一个事务,失败会回滚 4. **错误详情**:响应中最多返回前 10 个错误详情 5. **price_id 唯一性**:系统会自动确保 price_id 的唯一性,无需手动处理 ### 完整字段对照表 | 数据库字段 | JSON 字段 | 必填 | 类型 | 说明 | |-----------|-----------|------|------|------| | `price_id` | `price_id` | ❌ | string | 价格唯一ID | | `goods_material` | `goods_material` | ✅ | string | 材质牌号 | | `goods_spec` | `goods_spec` | ✅ | string | 规格型号 | | `partsname_name` | `partsname_name` | ✅ | string | 品名 | | `productarea_name` | `productarea_name` | ✅ | string | 产地/钢厂 | | `price_source` | `price_source` | ✅ | string | 价格来源 | | `price_region` | `price_region` | ✅ | string | 价格地区 | | `pntree_name` | `pntree_name` | ❌ | string | 分类名称 | | `price_date` | `price_date` | ✅ | string | 价格日期 | | `make_price` | `make_price` | ❌ | number | 钢厂价 | | `hang_price` | `hang_price` | ✅ | number | 挂牌价 | | `last_make_price` | `last_make_price` | ❌ | number | 上次钢厂价 | | `last_hang_price` | `last_hang_price` | ❌ | number | 上次挂牌价 | | `make_price_updw` | `make_price_updw` | ❌ | string | 钢厂价涨跌 | | `hang_price_updw` | `hang_price_updw` | ❌ | string | 挂牌价涨跌 | | `operator_code` | `operator_code` | ❌ | string | 操作员代码 | | `operator_name` | `operator_name` | ❌ | string | 操作员名称 | | `created_at` | - | - | - | 自动生成 | | `updated_at` | - | - | - | 自动生成 |