From 9f62f4ba9c942a30661ad799e5b3d607b39b49c6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 8 Jan 2026 09:30:36 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=B7=B2=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E6=B5=81=E6=B0=B4=E7=BA=BF=E4=BB=BB=E5=8A=A1=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=98=BE=E7=A4=BA=E4=B8=BA=E5=BE=85=E6=8E=A5=E5=8D=95?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/TaskHall.vue | 24 +- 第三方素材API接口文档2.0.md | 554 ++++++++++++++++++++++++++++++++ 2 files changed, 566 insertions(+), 12 deletions(-) create mode 100644 第三方素材API接口文档2.0.md diff --git a/frontend/src/views/TaskHall.vue b/frontend/src/views/TaskHall.vue index 1aa6c69..a749902 100644 --- a/frontend/src/views/TaskHall.vue +++ b/frontend/src/views/TaskHall.vue @@ -4502,7 +4502,16 @@ const getTaskStatusText = (status: string, task?: any) => { return '已驳回' } - // 2. 检查是否正在审核中 + // 2. 已完成任务(必须优先判断,避免被其他条件覆盖) + if (status === 'completed') { + // productIdFilled为0或undefined表示未填写 + if (!task.productIdFilled || task.productIdFilled === 0) { + return '待填写ID' + } + return '已完结' + } + + // 3. 检查是否正在审核中 if (task.approvalStatus === 'pending_demand_approval') { return '待部门审核' } @@ -4510,7 +4519,7 @@ const getTaskStatusText = (status: string, task?: any) => { return '待接单审核' } - // 3. 流水线任务且已审核通过,根据是否有接收人显示不同状态 + // 4. 流水线任务且已审核通过,根据是否有接收人显示不同状态 if (task.isPipeline === 1 && task.approvalStatus === 'approved') { if (task.receiverId) { return '进行中' @@ -4519,7 +4528,7 @@ const getTaskStatusText = (status: string, task?: any) => { } } - // 4. 普通任务已审核通过但status还是draft,修正显示 + // 5. 普通任务已审核通过但status还是draft,修正显示 if (task.approvalStatus === 'approved' && status === 'draft') { if (task.receiverId) { return '进行中' @@ -4527,15 +4536,6 @@ const getTaskStatusText = (status: string, task?: any) => { return '待接单' } } - - // 5. 已完成任务:检查是否已填写商品ID - if (status === 'completed') { - // productIdFilled为0或undefined表示未填写 - if (!task.productIdFilled || task.productIdFilled === 0) { - return '待填写ID' - } - return '已完结' - } } const statusMap: Record = { diff --git a/第三方素材API接口文档2.0.md b/第三方素材API接口文档2.0.md new file mode 100644 index 0000000..dc1c34f --- /dev/null +++ b/第三方素材API接口文档2.0.md @@ -0,0 +1,554 @@ +# 素材平台 - 外部接口文档 + +> 本文档供外部任务系统对接使用 + +## 概述 + +素材平台提供外部接口,允许任务系统通过任务号查询、下载和删除各类素材(包括产品全案、3D场景、详情页、主图视频等所有素材类型)。 + +### 基础信息 + +- **接口地址**: `https://3d.yydd.ai/api/external/` +- **鉴权方式**: API Key(请求头 `X-API-Key`) +- **数据格式**: JSON + +### API Key 获取与配置 + +#### 获取 API Key + +1. **登录素材平台管理后台** + - 访问:`https://3d.yydd.ai/admin/api-keys` + - 需要**超级管理员**或**系统管理员**权限 + +2. **创建 API Key** + - 点击「创建 API Key」按钮 + - 输入密钥名称(如:任务系统、生产环境等) + - 点击确认后,系统会生成一个 32 位的 API Key + - **重要**:API Key 仅在创建时显示一次,请立即复制保存 + +3. **管理 API Key** + - 查看列表:可查看所有已创建的 API Key(仅显示前 16 位) + - 启用/禁用:可以临时禁用某个 API Key,无需删除 + - 删除:删除后该 API Key 将永久失效 + +#### 使用 API Key + +在调用接口时,需要在请求头中携带 API Key: + +``` +X-API-Key: your-api-key-here +``` + +#### 安全建议 + +- ✅ 妥善保管 API Key,不要泄露给他人 +- ✅ 不同环境(开发、测试、生产)使用不同的 API Key +- ✅ 定期检查 API Key 的使用情况 +- ✅ 如发现泄露,立即禁用或删除该 API Key +- ❌ 不要将 API Key 提交到代码仓库 +- ❌ 不要在前端代码中硬编码 API Key + +### 调用流程 + +``` +1. 任务系统生成任务号(如 TASK202601030184) +2. 员工在素材平台上传素材时填入任务号(所有素材类型都支持任务号) +3. 员工在任务系统点击「完成」 +4. 任务系统调用查询接口获取素材详情和下载链接 +5. 任务系统通过下载链接获取文件 +6. (可选)任务完成后调用删除接口清理素材 +``` + +### 支持的素材类型 + +接口支持所有素材类型,包括但不限于: +- 产品全案 +- 3D场景 +- 详情页 +- 详情模板 +- 主图视频 +- 安装视频 +- 种草视频 +- 音乐 +- 标准模型 +- 其他所有素材类型 + +**注意**:不同素材类型返回的数据结构略有不同: +- **产品全案**:返回 `assets` 结构(包含 main、sku、detail、psd 分类) +- **其他类型**:返回 `files` 结构(统一文件列表) + +--- + +## 接口列表 + +### 1. 查询素材详情 + +通过任务号查询素材详情,获取下载链接。 + +**请求** + +``` +GET /api/external/product-assets?taskNo={任务号} +``` + +**请求头** + +| 参数 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| X-API-Key | string | 是 | API 访问密钥 | +| Content-Type | string | 否 | application/json(GET 请求通常不需要) | + +**请求参数** + +| 参数 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| taskNo | string | 是 | 任务号,格式:TASK + 12-18位数字,或 TASK + 12-18位数字 + -2位子任务号(如 TASK202601071437194808-01) | + +**完整请求示例** + +```bash +# cURL 示例 +curl -X GET \ + 'https://3d.yydd.ai/api/external/product-assets?taskNo=TASK202601030184' \ + -H 'X-API-Key: b78af0ec58a078105f63aaca3256918f' +``` + +```http +GET /api/external/product-assets?taskNo=TASK202601030184 HTTP/1.1 +Host: 3d.yydd.ai +X-API-Key: b78af0ec58a078105f63aaca3256918f +``` + +**响应示例(成功 - 产品全案)** + +```json +{ + "success": true, + "data": { + "taskNo": "TASK202601030184", + "productModel": "YYD-001", + "categoryName": "天猫旗舰店", + "sceneName": "客厅场景", + "status": "fetched", + "createdAt": "2026-01-03T10:00:00.000Z", + "updatedAt": "2026-01-03T10:30:00.000Z", + "assets": { + "main": [ + { + "id": "asset-uuid-1", + "url": "https://s3.yydd.ai/...", + "downloadUrl": "https://3d.yydd.ai/api/external/download?token=xxx", + "fileName": "主图1.jpg", + "fileSize": 1024000 + } + ], + "sku": [ + { + "id": "asset-uuid-2", + "url": "https://s3.yydd.ai/...", + "downloadUrl": "https://3d.yydd.ai/api/external/download?token=xxx", + "fileName": "SKU白色.jpg", + "fileSize": 512000 + } + ], + "detail": [ + { + "id": "asset-uuid-3", + "url": "https://s3.yydd.ai/...", + "downloadUrl": "https://3d.yydd.ai/api/external/download?token=xxx", + "fileName": "详情1.jpg", + "fileSize": 2048000, + "sortOrder": 0 + } + ], + "psd": [ + { + "id": "asset-uuid-5", + "url": "uploads/product-package/xxx/psd/psd-xxx.psd", + "downloadUrl": "https://3d.yydd.ai/api/external/download?token=xxx", + "fileName": "源文件1.psd", + "fileSize": 52428800 + } + ] + }, + "downloadUrls": { + "all": "https://3d.yydd.ai/api/external/download?token=xxx", + "main": "https://3d.yydd.ai/api/external/download?token=xxx", + "sku": "https://3d.yydd.ai/api/external/download?token=xxx", + "detail": "https://3d.yydd.ai/api/external/download?token=xxx", + "psd": "https://3d.yydd.ai/api/external/download?token=xxx" + } + } +} +``` + +**响应示例(成功 - 其他素材类型)** + +```json +{ + "success": true, + "data": { + "taskNo": "TASK202601030185", + "productModel": "YYD-002", + "categoryName": "天猫旗舰店", + "sceneName": "客厅场景", + "status": "fetched", + "createdAt": "2026-01-03T10:00:00.000Z", + "updatedAt": "2026-01-03T10:30:00.000Z", + "files": [ + { + "id": "material-uuid-1", + "url": "https://s3.yydd.ai/...", + "downloadUrl": "https://3d.yydd.ai/api/external/download?token=xxx", + "fileName": "material.zip", + "fileSize": 52428800 + } + ], + "downloadUrls": { + "all": "https://3d.yydd.ai/api/external/download?token=xxx" + } + } +} +``` + +**响应字段说明** + +| 字段 | 类型 | 说明 | +|-----|------|------| +| taskNo | string | 任务号 | +| productModel | string | SPU型号 | +| categoryName | string | 店铺名称 | +| sceneName | string | 场景类别(可能为空) | +| status | string | 状态:completed/fetched | +| assets | object | **仅产品全案类型**:资产分类对象(包含 main、sku、detail、psd) | +| files | array | **仅非产品全案类型**:文件列表(统一结构) | +| downloadUrls.all | string | **所有类型**:全部文件下载链接 | +| downloadUrls.main | string | **仅产品全案**:主图打包下载链接 | +| downloadUrls.sku | string | **仅产品全案**:SKU图打包下载链接 | +| downloadUrls.detail | string | **仅产品全案**:详情图打包下载链接 | +| downloadUrls.psd | string/null | **仅产品全案**:PSD批量下载链接(已废弃,请使用单个PSD文件的downloadUrl) | + +**资产对象字段说明(产品全案)** + +每个资产对象包含以下字段: + +| 字段 | 类型 | 说明 | +|-----|------|------| +| id | string | 资产唯一标识符 | +| url | string | 资源URL(S3地址或本地路径,仅用于预览) | +| downloadUrl | string | 下载链接(带Token,24小时有效) | +| fileName | string | 文件名 | +| fileSize | number | 文件大小(字节) | +| sortOrder | number | 排序序号(仅详情图有此字段) | + +**文件对象字段说明(其他素材类型)** + +每个文件对象包含以下字段: + +| 字段 | 类型 | 说明 | +|-----|------|------| +| id | string | 素材唯一标识符 | +| url | string | 资源URL(S3地址或本地路径,仅用于预览) | +| downloadUrl | string | 下载链接(带Token,24小时有效) | +| fileName | string | 文件名 | +| fileSize | number | 文件大小(字节) | +| duration | number | 视频/音频时长(秒,仅视频/音频类型有此字段) | + +**响应示例(失败)** + +```json +{ + "success": false, + "error": { + "code": "TASK_NOT_FOUND", + "message": "任务号不存在" + } +} +``` + +--- + +### 2. 下载文件 + +通过下载链接获取文件。 + +**请求** + +``` +GET /api/external/download?token={下载令牌} +``` + +**请求参数** + +| 参数 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| token | string | 是 | 下载令牌(从查询接口获取,已包含素材ID、下载类型、资源ID等信息) | + +**说明** + +- 下载令牌(token)已包含所有必要信息(素材ID、下载类型、资源ID等) +- 单个PSD文件的下载链接中,token 已包含对应的 assetId 信息,无需额外 URL 参数 +- 打包下载链接会自动下载对应类型的所有文件 +- 下载链接有效期为 24 小时,过期后需重新调用查询接口获取新链接 + +**完整请求示例** + +```bash +# cURL 示例 - 打包下载(全部) +curl -X GET \ + 'https://3d.yydd.ai/api/external/download?token=xxx' \ + -o 'assets.zip' + +# cURL 示例 - 下载单个PSD文件(使用PSD资源的downloadUrl) +curl -X GET \ + 'https://3d.yydd.ai/api/external/download?token=xxx' \ + -o 'source.psd' +``` + +```http +GET /api/external/download?token=xxx HTTP/1.1 +Host: 3d.yydd.ai +``` + +**响应** + +- 成功:返回文件流(Content-Type 根据文件类型设置) +- 打包下载:返回 ZIP 文件 + +**响应头示例** + +``` +Content-Type: application/zip +Content-Disposition: attachment; filename="TASK202601030184-all.zip" +``` + +**错误响应** + +```json +{ + "success": false, + "error": { + "code": "TOKEN_EXPIRED", + "message": "下载链接已过期,请重新查询获取新链接" + } +} +``` + +--- + +### 3. 删除素材 + +删除指定任务号的素材(软删除)。 + +**请求** + +``` +DELETE /api/external/product-assets?taskNo={任务号} +``` + +**请求头** + +| 参数 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| X-API-Key | string | 是 | API 访问密钥 | +| Content-Type | string | 否 | application/json(DELETE 请求通常不需要) | + +**请求参数** + +| 参数 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| taskNo | string | 是 | 任务号 | + +**完整请求示例** + +```bash +# cURL 示例 +curl -X DELETE \ + 'https://3d.yydd.ai/api/external/product-assets?taskNo=TASK202601030184' \ + -H 'X-API-Key: b78af0ec58a078105f63aaca3256918f' +``` + +```http +DELETE /api/external/product-assets?taskNo=TASK202601030184 HTTP/1.1 +Host: 3d.yydd.ai +X-API-Key: b78af0ec58a078105f63aaca3256918f +``` + +**响应示例(成功)** + +```json +{ + "success": true, + "message": "素材已删除", + "data": { + "taskNo": "TASK202601030184", + "deletedAt": "2026-01-03T15:00:00.000Z" + } +} +``` + +--- + +## 错误码 + +| 错误码 | HTTP状态码 | 说明 | +|-------|-----------|------| +| INVALID_API_KEY | 401 | API Key 无效或缺失 | +| TASK_NOT_FOUND | 404 | 任务号不存在 | +| MATERIAL_DELETED | 410 | 素材已被删除 | +| TOKEN_EXPIRED | 401 | 下载令牌已过期(有效期24小时) | +| INVALID_TOKEN | 401 | 下载令牌无效 | +| INVALID_TASK_NO | 400 | 任务号格式错误 | +| SERVER_ERROR | 500 | 服务器内部错误 | + +--- + +## 注意事项 + +### 下载链接有效期 + +- 下载链接(downloadUrl)有效期为 **24小时** +- 过期后需重新调用查询接口获取新链接 +- 建议在下载前先调用查询接口获取最新链接 + +### 任务号格式 + +- 基础格式:`TASK` + 12-18位数字 +- 子任务格式:`TASK` + 12-18位数字 + `-` + 3位数字 +- 示例: + - 基础任务号(12位):`TASK202601030184` + - 基础任务号(18位):`TASK202601071437194808` + - 子任务号:`TASK202601071437194808-001` +- 任务号在系统中唯一,重复上传会报错 + +### 任务状态说明 + +| 状态 | 说明 | +|-----|------| +| completed | 素材上传完成,等待获取 | +| fetched | 已被外部系统查询过 | + +首次查询成功后,状态会从 `completed` 变为 `fetched`。 + +### 打包下载说明 + +- `downloadUrls.all` 包含:主图 + SKU图 + 详情图(**不含PSD**) +- 如需下载 PSD,请单独使用 `downloadUrls.psd` +- ZIP 文件内按文件夹分类:`main/`、`sku/`、`detail/` + +### 调用频率限制 + +- 建议单个 API Key 每分钟不超过 60 次请求 +- 超出限制可能返回 429 错误 + +--- + +## 示例代码 + +### Node.js + +```javascript +const axios = require('axios'); + +const API_BASE = 'https://3d.yydd.ai/api/external'; +const API_KEY = 'b78af0ec58a078105f63aaca3256918f'; + +// 查询素材 +async function queryAssets(taskNo) { + const response = await axios.get(`${API_BASE}/product-assets`, { + params: { taskNo }, + headers: { 'X-API-Key': API_KEY } + }); + return response.data; +} + +// 下载文件 +async function downloadFile(downloadUrl, savePath) { + const response = await axios.get(downloadUrl, { + responseType: 'stream' + }); + const writer = fs.createWriteStream(savePath); + response.data.pipe(writer); + return new Promise((resolve, reject) => { + writer.on('finish', resolve); + writer.on('error', reject); + }); +} + +// 使用示例 +async function main() { + const result = await queryAssets('TASK202601030184'); + if (result.success) { + // 下载全部(不含PSD) + await downloadFile(result.data.downloadUrls.all, './assets.zip'); + // 下载PSD + if (result.data.downloadUrls.psd) { + await downloadFile(result.data.downloadUrls.psd, './source.psd'); + } + } +} +``` + +### Python + +```python +import requests + +API_BASE = 'https://3d.yydd.ai/api/external' +API_KEY = 'b78af0ec58a078105f63aaca3256918f' + +def query_assets(task_no): + response = requests.get( + f'{API_BASE}/product-assets', + params={'taskNo': task_no}, + headers={'X-API-Key': API_KEY} + ) + return response.json() + +def download_file(download_url, save_path): + response = requests.get(download_url, stream=True) + with open(save_path, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) + +# 使用示例 +result = query_assets('TASK202601030184') +if result['success']: + download_file(result['data']['downloadUrls']['all'], './assets.zip') +``` + +--- + +## API Key 管理 + +### 管理页面 + +- **访问地址**: `https://3d.yydd.ai/admin/api-keys` +- **权限要求**: 超级管理员或系统管理员 + +### 功能说明 + +| 功能 | 说明 | +|-----|------| +| 创建 API Key | 创建新的 API Key,创建后立即显示完整密钥(仅显示一次) | +| 查看列表 | 查看所有 API Key,显示名称、状态、最后使用时间等信息 | +| 启用/禁用 | 临时禁用 API Key,禁用后无法调用接口,可随时重新启用 | +| 删除 | 永久删除 API Key,删除后无法恢复 | + +### API Key 格式 + +- 长度:32 位随机字符串 +- 示例:`a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6` +- 唯一性:每个 API Key 在系统中唯一 + +--- + +## 联系方式 + +如有问题,请联系素材平台管理员获取 API Key 或技术支持。 + +--- + +*文档版本: 1.2* +*更新日期: 2026-01-07* +*更新内容: 更新实际接口地址和 API Key 示例* \ No newline at end of file