|
@@ -0,0 +1,3500 @@
|
|
|
|
|
+# 数据清洗统一接口设计文档
|
|
|
|
|
+
|
|
|
|
|
+> 版本:v1.0.0
|
|
|
|
|
+> 更新日期:2025-01-01
|
|
|
|
|
+> 基础URL:`https://server-msq.fmode.cn`
|
|
|
|
|
+> 接口前缀:`/api/clean/`
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 目录
|
|
|
|
|
+
|
|
|
|
|
+- [1. 概述](#1-概述)
|
|
|
|
|
+- [2. 设计原则](#2-设计原则)
|
|
|
|
|
+- [3. 统一响应格式](#3-统一响应格式)
|
|
|
|
|
+- [4. 统一分页格式](#4-统一分页格式)
|
|
|
|
|
+- [5. 错误码定义](#5-错误码定义)
|
|
|
|
|
+- [6. 接口详细定义](#6-接口详细定义)
|
|
|
|
|
+ - [6.1 产品相关(跨平台)](#61-产品相关跨平台)
|
|
|
|
|
+ - [6.2 订单相关(Amazon)](#62-订单相关amazon)
|
|
|
|
|
+ - [6.3 商品管理(Amazon Listings)](#63-商品管理amazon-listings)
|
|
|
|
|
+ - [6.4 类目相关(Sorftime)](#64-类目相关sorftime)
|
|
|
|
|
+ - [6.5 关键词相关(Sorftime)](#65-关键词相关sorftime)
|
|
|
|
|
+ - [6.6 监控相关(Sorftime)](#66-监控相关sorftime)
|
|
|
|
|
+ - [6.7 TikTok 社交媒体(TikHub)](#67-tiktok-社交媒体tikhub)
|
|
|
|
|
+ - [6.8 卖家信息(Amazon)](#68-卖家信息amazon)
|
|
|
|
|
+ - [6.9 退货相关(Amazon)](#69-退货相关amazon)
|
|
|
|
|
+- [7. 前端调用示例](#7-前端调用示例)
|
|
|
|
|
+- [附录:数据来源映射总表](#附录数据来源映射总表)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 1. 概述
|
|
|
|
|
+
|
|
|
|
|
+本项目对接三个平台的 API:
|
|
|
|
|
+
|
|
|
|
|
+| 平台 | 模块路径 | 原始接口前缀 | 说明 |
|
|
|
|
|
+|------|---------|-------------|------|
|
|
|
|
|
+| Amazon SP-API | `modules/fmode-amazon-sp-api` | `/api/amazon/` | 订单、商品、目录、销售、卖家、退货等 |
|
|
|
|
|
+| Sorftime | `modules/fmode-sorftime-api` | `/api/sorftime/` | 产品分析、类目、关键词、监控等 |
|
|
|
|
|
+| TikHub | `modules/fmode-tikhub-api` | `/api/tikhub/` | TikTok 用户、视频、商品、广告等 |
|
|
|
|
|
+
|
|
|
|
|
+各平台返回的数据格式不统一,字段命名风格各异(PascalCase / snake_case / camelCase 混用),前端对接困难。本文档设计一套数据清洗后的统一接口,挂载在 `/api/clean/` 下,便于前端直接使用。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 2. 设计原则
|
|
|
|
|
+
|
|
|
|
|
+1. **统一响应格式**:所有接口返回 `{ code, message, data, timestamp }` 结构
|
|
|
|
|
+2. **跨平台数据标准化**:相同概念的数据(产品、订单、关键词)使用统一字段命名
|
|
|
|
|
+3. **分页统一**:列表接口统一使用 `{ items, total, page, pageSize, hasMore }` 结构
|
|
|
|
|
+4. **前端友好**:字段命名统一使用 `camelCase`,时间统一为 ISO 8601 格式
|
|
|
|
|
+5. **数据来源透明**:每条数据携带 `_source` 字段标识来源平台
|
|
|
|
|
+6. **向下兼容**:清洗层不修改原始 API 逻辑,仅做格式转换和聚合
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 3. 统一响应格式
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+/** 统一响应包装 */
|
|
|
|
|
+interface ApiResponse<T> {
|
|
|
|
|
+ /** 业务状态码,0 表示成功 */
|
|
|
|
|
+ code: number;
|
|
|
|
|
+ /** 状态描述 */
|
|
|
|
|
+ message: string;
|
|
|
|
|
+ /** 响应数据 */
|
|
|
|
|
+ data: T;
|
|
|
|
|
+ /** 响应时间戳 ISO 8601 */
|
|
|
|
|
+ timestamp: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+成功响应示例:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": { "..." : "..." },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+错误响应示例:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 40001,
|
|
|
|
|
+ "message": "缺少必填参数: keyword",
|
|
|
|
|
+ "data": null,
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 4. 统一分页格式
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+/** 统一分页响应 */
|
|
|
|
|
+interface PaginatedResponse<T> {
|
|
|
|
|
+ /** 数据列表 */
|
|
|
|
|
+ items: T[];
|
|
|
|
|
+ /** 总记录数 */
|
|
|
|
|
+ total: number;
|
|
|
|
|
+ /** 当前页码(从 1 开始) */
|
|
|
|
|
+ page: number;
|
|
|
|
|
+ /** 每页条数 */
|
|
|
|
|
+ pageSize: number;
|
|
|
|
|
+ /** 是否有更多数据 */
|
|
|
|
|
+ hasMore: boolean;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 统一分页请求参数 */
|
|
|
|
|
+interface PaginationParams {
|
|
|
|
|
+ /** 页码,默认 1 */
|
|
|
|
|
+ page?: number;
|
|
|
|
|
+ /** 每页条数,默认 20 */
|
|
|
|
|
+ pageSize?: number;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 5. 错误码定义
|
|
|
|
|
+
|
|
|
|
|
+| 错误码 | 说明 | HTTP 状态码 |
|
|
|
|
|
+|--------|------|------------|
|
|
|
|
|
+| 0 | 成功 | 200 |
|
|
|
|
|
+| 40001 | 缺少必填参数 | 400 |
|
|
|
|
|
+| 40002 | 参数格式错误 | 400 |
|
|
|
|
|
+| 40003 | 参数值超出范围 | 400 |
|
|
|
|
|
+| 40101 | 未授权(缺少认证信息) | 401 |
|
|
|
|
|
+| 40102 | 认证过期 | 401 |
|
|
|
|
|
+| 40301 | 无权访问该资源 | 403 |
|
|
|
|
|
+| 40401 | 资源不存在 | 404 |
|
|
|
|
|
+| 40901 | 请求冲突(重复操作) | 409 |
|
|
|
|
|
+| 42901 | 请求频率超限 | 429 |
|
|
|
|
|
+| 50001 | 服务器内部错误 | 500 |
|
|
|
|
|
+| 50002 | Amazon SP-API 调用失败 | 502 |
|
|
|
|
|
+| 50003 | Sorftime API 调用失败 | 502 |
|
|
|
|
|
+| 50004 | TikHub API 调用失败 | 502 |
|
|
|
|
|
+| 50005 | 数据清洗转换异常 | 500 |
|
|
|
|
|
+| 50301 | 上游服务不可用 | 503 |
|
|
|
|
|
+| 50401 | 上游服务响应超时 | 504 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 6. 接口详细定义
|
|
|
|
|
+
|
|
|
|
|
+### 6.1 产品相关(跨平台)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.1.1 `GET /api/clean/products/search` — 统一产品搜索
|
|
|
|
|
+
|
|
|
|
|
+聚合 Amazon Catalog Items 搜索 + Sorftime ProductQuery,返回统一格式的产品列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `CatalogItemsApi.searchCatalogItems` | `GET /api/amazon/catalog/items` |
|
|
|
|
|
+| Sorftime | `ProductApi.getProductQuery` | `POST /api/sorftime/forward` -> `/api/ProductQuery` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface ProductSearchParams extends PaginationParams {
|
|
|
|
|
+ /** 搜索关键词 */
|
|
|
|
|
+ keyword?: string;
|
|
|
|
|
+ /** ASIN 列表(逗号分隔) */
|
|
|
|
|
+ asins?: string;
|
|
|
|
|
+ /** 品牌名称 */
|
|
|
|
|
+ brand?: string;
|
|
|
|
|
+ /** 类目 ID */
|
|
|
|
|
+ categoryId?: string;
|
|
|
|
|
+ /** 数据来源:amazon | sorftime | all(默认 all) */
|
|
|
|
|
+ source?: 'amazon' | 'sorftime' | 'all';
|
|
|
|
|
+ /** 市场域名,如 amazon.com(Sorftime 需要) */
|
|
|
|
|
+ domain?: string;
|
|
|
|
|
+ /** Amazon MarketplaceId */
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanProduct {
|
|
|
|
|
+ /** 统一产品 ID(ASIN) */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 产品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 品牌 */
|
|
|
|
|
+ brand: string;
|
|
|
|
|
+ /** 主图 URL */
|
|
|
|
|
+ imageUrl: string;
|
|
|
|
|
+ /** 价格 */
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 评分(1-5) */
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ /** 评论数 */
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ /** 类目名称 */
|
|
|
|
|
+ category: string;
|
|
|
|
|
+ /** BSR 排名 */
|
|
|
|
|
+ bsrRank: number | null;
|
|
|
|
|
+ /** 数据来源平台 */
|
|
|
|
|
+ _source: 'amazon' | 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanProduct>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|----------------|------------------|
|
|
|
|
|
+| `id` | `asin` | `ASIN` |
|
|
|
|
|
+| `title` | `summaries[0].itemName` | `Title` |
|
|
|
|
|
+| `brand` | `summaries[0].brand` | `Brand` |
|
|
|
|
|
+| `imageUrl` | `images[0].images[0].link` | `ImageUrl` |
|
|
|
|
|
+| `price` | `summaries[0].price.amount` | `Price` |
|
|
|
|
|
+| `currency` | `summaries[0].price.currencyCode` | 根据 `domain` 推断 |
|
|
|
|
|
+| `rating` | — | `Rating` |
|
|
|
|
|
+| `reviewCount` | — | `Reviews` |
|
|
|
|
|
+| `category` | `salesRanks[0].displayGroupRanks[0].title` | `CategoryName` |
|
|
|
|
|
+| `bsrRank` | `salesRanks[0].displayGroupRanks[0].rank` | `BSR` |
|
|
|
|
|
+| `_source` | `'amazon'` | `'sorftime'` |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.1.2 `GET /api/clean/products/:id` — 统一产品详情
|
|
|
|
|
+
|
|
|
|
|
+聚合 Amazon CatalogItem 详情 + Sorftime ProductRequest,返回完整产品信息。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `CatalogItemsApi.getCatalogItem` | `GET /api/amazon/catalog/items/:asin` |
|
|
|
|
|
+| Sorftime | `ProductApi.getProductRequest` | `POST /api/sorftime/forward` -> `/api/ProductRequest` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = ASIN
|
|
|
|
|
+interface ProductDetailParams {
|
|
|
|
|
+ source?: 'amazon' | 'sorftime' | 'all';
|
|
|
|
|
+ domain?: string;
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+ /** 是否包含趋势数据(Sorftime,默认 false) */
|
|
|
|
|
+ includeTrend?: boolean;
|
|
|
|
|
+ trendStartDate?: string;
|
|
|
|
|
+ trendEndDate?: string;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanProductDetail extends CleanProduct {
|
|
|
|
|
+ /** 产品描述 */
|
|
|
|
|
+ description: string;
|
|
|
|
|
+ /** 商品特征/卖点列表 */
|
|
|
|
|
+ features: string[];
|
|
|
|
|
+ /** 尺寸信息 */
|
|
|
|
|
+ dimensions: {
|
|
|
|
|
+ length: number | null;
|
|
|
|
|
+ width: number | null;
|
|
|
|
|
+ height: number | null;
|
|
|
|
|
+ weight: number | null;
|
|
|
|
|
+ unit: string;
|
|
|
|
|
+ weightUnit: string;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ /** 变体列表 */
|
|
|
|
|
+ variants: Array<{
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ attributes: Record<string, string>;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 上架时间 */
|
|
|
|
|
+ listedAt: string | null;
|
|
|
|
|
+ /** 月销量估算(Sorftime) */
|
|
|
|
|
+ estimatedMonthlySales: number | null;
|
|
|
|
|
+ /** 月收入估算(Sorftime) */
|
|
|
|
|
+ estimatedMonthlyRevenue: number | null;
|
|
|
|
|
+ /** 卖家数量 */
|
|
|
|
|
+ sellerCount: number | null;
|
|
|
|
|
+ /** FBA 费用估算 */
|
|
|
|
|
+ fbaFee: number | null;
|
|
|
|
|
+ /** 趋势数据(需 includeTrend=true) */
|
|
|
|
|
+ trend: Array<{
|
|
|
|
|
+ date: string;
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ bsrRank: number | null;
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ sales: number | null;
|
|
|
|
|
+ }> | null;
|
|
|
|
|
+ /** 数据来源详情 */
|
|
|
|
|
+ _sources: Array<{
|
|
|
|
|
+ platform: 'amazon' | 'sorftime';
|
|
|
|
|
+ fetchedAt: string;
|
|
|
|
|
+ }>;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanProductDetail>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|----------------|------------------|
|
|
|
|
|
+| `description` | `summaries[0].itemDescription` | `Description` |
|
|
|
|
|
+| `features` | `summaries[0].bulletPoints` | `Features` |
|
|
|
|
|
+| `dimensions.length` | `dimensions[0].item.length.value` | — |
|
|
|
|
|
+| `dimensions.width` | `dimensions[0].item.width.value` | — |
|
|
|
|
|
+| `dimensions.height` | `dimensions[0].item.height.value` | — |
|
|
|
|
|
+| `dimensions.weight` | `dimensions[0].item.weight.value` | — |
|
|
|
|
|
+| `variants` | `relationships[0].variationTheme` | — |
|
|
|
|
|
+| `listedAt` | — | `DateFirstAvailable` |
|
|
|
|
|
+| `estimatedMonthlySales` | — | `MonthlySales` |
|
|
|
|
|
+| `estimatedMonthlyRevenue` | — | `MonthlyRevenue` |
|
|
|
|
|
+| `sellerCount` | — | `SellerNum` |
|
|
|
|
|
+| `fbaFee` | — | `FBAFee` |
|
|
|
|
|
+| `trend` | — | `TrendData[]` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "B0EXAMPLE1",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "brand": "ExampleBrand",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/example.jpg",
|
|
|
|
|
+ "price": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "rating": 4.5,
|
|
|
|
|
+ "reviewCount": 12580,
|
|
|
|
|
+ "category": "Electronics",
|
|
|
|
|
+ "bsrRank": 1523,
|
|
|
|
|
+ "description": "High quality wireless headphones with noise cancellation...",
|
|
|
|
|
+ "features": [
|
|
|
|
|
+ "Active Noise Cancellation",
|
|
|
|
|
+ "40-hour battery life",
|
|
|
|
|
+ "Bluetooth 5.3"
|
|
|
|
|
+ ],
|
|
|
|
|
+ "dimensions": {
|
|
|
|
|
+ "length": 18.5,
|
|
|
|
|
+ "width": 15.2,
|
|
|
|
|
+ "height": 7.8,
|
|
|
|
|
+ "weight": 250,
|
|
|
|
|
+ "unit": "cm",
|
|
|
|
|
+ "weightUnit": "g"
|
|
|
|
|
+ },
|
|
|
|
|
+ "variants": [
|
|
|
|
|
+ { "asin": "B0EXAMPLE2", "title": "Black", "attributes": { "color": "Black" } },
|
|
|
|
|
+ { "asin": "B0EXAMPLE3", "title": "White", "attributes": { "color": "White" } }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "listedAt": "2024-03-15T00:00:00.000Z",
|
|
|
|
|
+ "estimatedMonthlySales": 8500,
|
|
|
|
|
+ "estimatedMonthlyRevenue": 254915,
|
|
|
|
|
+ "sellerCount": 3,
|
|
|
|
|
+ "fbaFee": 5.42,
|
|
|
|
|
+ "trend": null,
|
|
|
|
|
+ "_source": "sorftime",
|
|
|
|
|
+ "_sources": [
|
|
|
|
|
+ { "platform": "amazon", "fetchedAt": "2025-01-01T12:00:00.000Z" },
|
|
|
|
|
+ { "platform": "sorftime", "fetchedAt": "2025-01-01T12:00:01.000Z" }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:01.500Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.1.3 `GET /api/clean/products/:id/sales` — 产品销量数据
|
|
|
|
|
+
|
|
|
|
|
+聚合 Amazon Sales 数据 + Sorftime AsinSalesVolume,返回产品销量统计。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `SalesApi.getOrderMetrics` | `GET /api/amazon/sales/orderMetrics` |
|
|
|
|
|
+| Sorftime | `ProductApi.getAsinSalesVolume` | `POST /api/sorftime/forward` -> `/api/AsinSalesVolume` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = ASIN
|
|
|
|
|
+interface ProductSalesParams {
|
|
|
|
|
+ source?: 'amazon' | 'sorftime' | 'all';
|
|
|
|
|
+ domain?: string;
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+ /** 时间粒度 */
|
|
|
|
|
+ granularity?: 'day' | 'week' | 'month';
|
|
|
|
|
+ /** 开始日期 ISO 8601 */
|
|
|
|
|
+ startDate: string;
|
|
|
|
|
+ /** 结束日期 ISO 8601 */
|
|
|
|
|
+ endDate: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanProductSales {
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ /** 统计周期 */
|
|
|
|
|
+ period: {
|
|
|
|
|
+ startDate: string;
|
|
|
|
|
+ endDate: string;
|
|
|
|
|
+ granularity: 'day' | 'week' | 'month';
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 汇总数据 */
|
|
|
|
|
+ summary: {
|
|
|
|
|
+ totalUnits: number;
|
|
|
|
|
+ totalRevenue: number;
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ averageDailyUnits: number;
|
|
|
|
|
+ averagePrice: number;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 时间序列数据 */
|
|
|
|
|
+ timeline: Array<{
|
|
|
|
|
+ date: string;
|
|
|
|
|
+ units: number;
|
|
|
|
|
+ revenue: number;
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ bsrRank: number | null;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ _source: 'amazon' | 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanProductSales>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|----------------|------------------|
|
|
|
|
|
+| `summary.totalUnits` | `orderMetrics[].unitCount` (求和) | `TotalSales` |
|
|
|
|
|
+| `summary.totalRevenue` | `orderMetrics[].totalSales.amount` (求和) | `TotalRevenue` |
|
|
|
|
|
+| `summary.currency` | `orderMetrics[].totalSales.currencyCode` | 根据 `domain` 推断 |
|
|
|
|
|
+| `timeline[].date` | `orderMetrics[].interval` (解析) | `SalesData[].Date` |
|
|
|
|
|
+| `timeline[].units` | `orderMetrics[].unitCount` | `SalesData[].Sales` |
|
|
|
|
|
+| `timeline[].revenue` | `orderMetrics[].totalSales.amount` | `SalesData[].Revenue` |
|
|
|
|
|
+| `timeline[].bsrRank` | — | `SalesData[].BSR` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "period": {
|
|
|
|
|
+ "startDate": "2025-01-01",
|
|
|
|
|
+ "endDate": "2025-01-31",
|
|
|
|
|
+ "granularity": "day"
|
|
|
|
|
+ },
|
|
|
|
|
+ "summary": {
|
|
|
|
|
+ "totalUnits": 8500,
|
|
|
|
|
+ "totalRevenue": 254915.00,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "averageDailyUnits": 274,
|
|
|
|
|
+ "averagePrice": 29.99
|
|
|
|
|
+ },
|
|
|
|
|
+ "timeline": [
|
|
|
|
|
+ { "date": "2025-01-01", "units": 280, "revenue": 8397.20, "price": 29.99, "bsrRank": 1520 },
|
|
|
|
|
+ { "date": "2025-01-02", "units": 265, "revenue": 7947.35, "price": 29.99, "bsrRank": 1535 }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.1.4 `GET /api/clean/products/:id/reviews` — 产品评论分析
|
|
|
|
|
+
|
|
|
|
|
+聚合 Amazon CustomerFeedback + Sorftime ProductReviewsQuery,返回产品评论统计与列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `SellersApi.getCustomerFeedback` | `GET /api/amazon/sellers/feedback` |
|
|
|
|
|
+| Sorftime | `ProductApi.getProductReviewsQuery` | `POST /api/sorftime/forward` -> `/api/ProductReviewsQuery` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = ASIN
|
|
|
|
|
+interface ProductReviewsParams extends PaginationParams {
|
|
|
|
|
+ source?: 'amazon' | 'sorftime' | 'all';
|
|
|
|
|
+ domain?: string;
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+ /** 评分筛选 1-5 */
|
|
|
|
|
+ rating?: number;
|
|
|
|
|
+ /** 排序方式 */
|
|
|
|
|
+ sortBy?: 'date' | 'rating' | 'helpful';
|
|
|
|
|
+ /** 排序方向 */
|
|
|
|
|
+ sortOrder?: 'asc' | 'desc';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanReviewSummary {
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ /** 评分分布 */
|
|
|
|
|
+ ratingDistribution: {
|
|
|
|
|
+ '1': number;
|
|
|
|
|
+ '2': number;
|
|
|
|
|
+ '3': number;
|
|
|
|
|
+ '4': number;
|
|
|
|
|
+ '5': number;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 平均评分 */
|
|
|
|
|
+ averageRating: number;
|
|
|
|
|
+ /** 总评论数 */
|
|
|
|
|
+ totalReviews: number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface CleanReview {
|
|
|
|
|
+ /** 评论 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 评论标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 评论内容 */
|
|
|
|
|
+ content: string;
|
|
|
|
|
+ /** 评分 1-5 */
|
|
|
|
|
+ rating: number;
|
|
|
|
|
+ /** 评论者名称 */
|
|
|
|
|
+ reviewer: string;
|
|
|
|
|
+ /** 评论日期 */
|
|
|
|
|
+ date: string;
|
|
|
|
|
+ /** 是否已验证购买 */
|
|
|
|
|
+ verifiedPurchase: boolean;
|
|
|
|
|
+ /** 有帮助数 */
|
|
|
|
|
+ helpfulCount: number;
|
|
|
|
|
+ /** 数据来源 */
|
|
|
|
|
+ _source: 'amazon' | 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<{ summary: CleanReviewSummary; reviews: PaginatedResponse<CleanReview> }>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|----------------|------------------|
|
|
|
|
|
+| `id` | `feedbackId` | `ReviewId` |
|
|
|
|
|
+| `title` | `title` | `Title` |
|
|
|
|
|
+| `content` | `comments` | `Content` |
|
|
|
|
|
+| `rating` | `rating` | `Rating` |
|
|
|
|
|
+| `reviewer` | `buyerName` | `Reviewer` |
|
|
|
|
|
+| `date` | `feedbackDate` | `Date` |
|
|
|
|
|
+| `verifiedPurchase` | `verified` | `VerifiedPurchase` |
|
|
|
|
|
+| `helpfulCount` | — | `HelpfulVotes` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "summary": {
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "ratingDistribution": { "1": 120, "2": 85, "3": 310, "4": 3200, "5": 8865 },
|
|
|
|
|
+ "averageRating": 4.5,
|
|
|
|
|
+ "totalReviews": 12580
|
|
|
|
|
+ },
|
|
|
|
|
+ "reviews": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "R1EXAMPLE",
|
|
|
|
|
+ "title": "Great headphones!",
|
|
|
|
|
+ "content": "Amazing sound quality and comfortable to wear...",
|
|
|
|
|
+ "rating": 5,
|
|
|
|
|
+ "reviewer": "John D.",
|
|
|
|
|
+ "date": "2025-01-10T00:00:00.000Z",
|
|
|
|
|
+ "verifiedPurchase": true,
|
|
|
|
|
+ "helpfulCount": 42,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 12580,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.1.5 `GET /api/clean/products/:id/similar` — 同类产品
|
|
|
|
|
+
|
|
|
|
|
+获取 Sorftime 同类产品实时数据。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `ProductApi.getSimilarProductRealtime` | `POST /api/sorftime/forward` -> `/api/SimilarProductRealtimeRequest` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = ASIN
|
|
|
|
|
+interface SimilarProductsParams extends PaginationParams {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 排序字段 */
|
|
|
|
|
+ sortBy?: 'price' | 'rating' | 'sales' | 'bsr';
|
|
|
|
|
+ sortOrder?: 'asc' | 'desc';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanSimilarProduct {
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 产品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 品牌 */
|
|
|
|
|
+ brand: string;
|
|
|
|
|
+ /** 主图 URL */
|
|
|
|
|
+ imageUrl: string;
|
|
|
|
|
+ /** 价格 */
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 评分 */
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ /** 评论数 */
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ /** BSR 排名 */
|
|
|
|
|
+ bsrRank: number | null;
|
|
|
|
|
+ /** 月销量估算 */
|
|
|
|
|
+ estimatedMonthlySales: number | null;
|
|
|
|
|
+ /** 与原产品的相似度评分 */
|
|
|
|
|
+ similarityScore: number | null;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanSimilarProduct>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `id` | `ASIN` |
|
|
|
|
|
+| `title` | `Title` |
|
|
|
|
|
+| `brand` | `Brand` |
|
|
|
|
|
+| `imageUrl` | `ImageUrl` |
|
|
|
|
|
+| `price` | `Price` |
|
|
|
|
|
+| `rating` | `Rating` |
|
|
|
|
|
+| `reviewCount` | `Reviews` |
|
|
|
|
|
+| `bsrRank` | `BSR` |
|
|
|
|
|
+| `estimatedMonthlySales` | `MonthlySales` |
|
|
|
|
|
+| `similarityScore` | `SimilarityScore` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "B0SIMILAR1",
|
|
|
|
|
+ "title": "Noise Cancelling Wireless Earbuds",
|
|
|
|
|
+ "brand": "CompetitorBrand",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/similar1.jpg",
|
|
|
|
|
+ "price": 34.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "rating": 4.3,
|
|
|
|
|
+ "reviewCount": 8920,
|
|
|
|
|
+ "bsrRank": 2105,
|
|
|
|
|
+ "estimatedMonthlySales": 6200,
|
|
|
|
|
+ "similarityScore": 0.92,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 25,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.2 订单相关(Amazon)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.2.1 `GET /api/clean/orders` — 订单列表
|
|
|
|
|
+
|
|
|
|
|
+获取 Amazon 订单列表,统一格式输出。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `OrdersApi.getOrders` | `GET /api/amazon/orders` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface OrderListParams extends PaginationParams {
|
|
|
|
|
+ /** 市场 ID */
|
|
|
|
|
+ marketplaceId: string;
|
|
|
|
|
+ /** 订单状态筛选 */
|
|
|
|
|
+ status?: 'pending' | 'unshipped' | 'shipped' | 'canceled' | 'unfulfillable';
|
|
|
|
|
+ /** 创建时间起始 ISO 8601 */
|
|
|
|
|
+ createdAfter?: string;
|
|
|
|
|
+ /** 创建时间截止 ISO 8601 */
|
|
|
|
|
+ createdBefore?: string;
|
|
|
|
|
+ /** 配送方式 */
|
|
|
|
|
+ fulfillmentChannel?: 'AFN' | 'MFN';
|
|
|
|
|
+ /** 排序方式 */
|
|
|
|
|
+ sortBy?: 'createdAt' | 'updatedAt' | 'totalAmount';
|
|
|
|
|
+ sortOrder?: 'asc' | 'desc';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanOrder {
|
|
|
|
|
+ /** 订单 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 订单状态 */
|
|
|
|
|
+ status: string;
|
|
|
|
|
+ /** 订单总金额 */
|
|
|
|
|
+ totalAmount: number;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 商品数量 */
|
|
|
|
|
+ itemCount: number;
|
|
|
|
|
+ /** 配送方式 AFN=FBA, MFN=自发货 */
|
|
|
|
|
+ fulfillmentChannel: 'AFN' | 'MFN';
|
|
|
|
|
+ /** 购买日期 */
|
|
|
|
|
+ createdAt: string;
|
|
|
|
|
+ /** 最后更新时间 */
|
|
|
|
|
+ updatedAt: string;
|
|
|
|
|
+ /** 发货地址(脱敏) */
|
|
|
|
|
+ shippingAddress: {
|
|
|
|
|
+ city: string;
|
|
|
|
|
+ state: string;
|
|
|
|
|
+ country: string;
|
|
|
|
|
+ postalCode: string;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ /** 市场 ID */
|
|
|
|
|
+ marketplaceId: string;
|
|
|
|
|
+ _source: 'amazon';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanOrder>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `AmazonOrderId` |
|
|
|
|
|
+| `status` | `OrderStatus` |
|
|
|
|
|
+| `totalAmount` | `OrderTotal.Amount` |
|
|
|
|
|
+| `currency` | `OrderTotal.CurrencyCode` |
|
|
|
|
|
+| `itemCount` | `NumberOfItemsShipped + NumberOfItemsUnshipped` |
|
|
|
|
|
+| `fulfillmentChannel` | `FulfillmentChannel` |
|
|
|
|
|
+| `createdAt` | `PurchaseDate` |
|
|
|
|
|
+| `updatedAt` | `LastUpdateDate` |
|
|
|
|
|
+| `shippingAddress.city` | `ShippingAddress.City` |
|
|
|
|
|
+| `shippingAddress.state` | `ShippingAddress.StateOrRegion` |
|
|
|
|
|
+| `shippingAddress.country` | `ShippingAddress.CountryCode` |
|
|
|
|
|
+| `shippingAddress.postalCode` | `ShippingAddress.PostalCode` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "111-1234567-1234567",
|
|
|
|
|
+ "status": "shipped",
|
|
|
|
|
+ "totalAmount": 59.98,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "itemCount": 2,
|
|
|
|
|
+ "fulfillmentChannel": "AFN",
|
|
|
|
|
+ "createdAt": "2025-01-15T08:30:00.000Z",
|
|
|
|
|
+ "updatedAt": "2025-01-16T14:20:00.000Z",
|
|
|
|
|
+ "shippingAddress": {
|
|
|
|
|
+ "city": "Seattle",
|
|
|
|
|
+ "state": "WA",
|
|
|
|
|
+ "country": "US",
|
|
|
|
|
+ "postalCode": "98101"
|
|
|
|
|
+ },
|
|
|
|
|
+ "marketplaceId": "ATVPDKIKX0DER",
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 156,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.2.2 `GET /api/clean/orders/:id` — 订单详情
|
|
|
|
|
+
|
|
|
|
|
+获取单个订单的完整信息,包含订单项明细。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `OrdersApi.getOrder` | `GET /api/amazon/orders/:orderId` |
|
|
|
|
|
+| Amazon | `OrdersApi.getOrderItems` | `GET /api/amazon/orders/:orderId/items` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = Amazon 订单号
|
|
|
|
|
+interface OrderDetailParams {
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanOrderDetail extends CleanOrder {
|
|
|
|
|
+ /** 订单项列表 */
|
|
|
|
|
+ items: Array<{
|
|
|
|
|
+ /** 订单项 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ /** SKU */
|
|
|
|
|
+ sku: string;
|
|
|
|
|
+ /** 商品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 数量 */
|
|
|
|
|
+ quantity: number;
|
|
|
|
|
+ /** 单价 */
|
|
|
|
|
+ unitPrice: number;
|
|
|
|
|
+ /** 小计 */
|
|
|
|
|
+ subtotal: number;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 商品图片 */
|
|
|
|
|
+ imageUrl: string | null;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 买家信息(脱敏) */
|
|
|
|
|
+ buyer: {
|
|
|
|
|
+ name: string | null;
|
|
|
|
|
+ email: string | null;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ /** 配送信息 */
|
|
|
|
|
+ shipping: {
|
|
|
|
|
+ service: string | null;
|
|
|
|
|
+ trackingNumber: string | null;
|
|
|
|
|
+ estimatedDelivery: string | null;
|
|
|
|
|
+ shippedAt: string | null;
|
|
|
|
|
+ deliveredAt: string | null;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ /** 支付信息 */
|
|
|
|
|
+ payment: {
|
|
|
|
|
+ method: string | null;
|
|
|
|
|
+ subtotal: number;
|
|
|
|
|
+ shippingFee: number;
|
|
|
|
|
+ tax: number;
|
|
|
|
|
+ discount: number;
|
|
|
|
|
+ total: number;
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanOrderDetail>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `items[].id` | `OrderItemId` |
|
|
|
|
|
+| `items[].asin` | `ASIN` |
|
|
|
|
|
+| `items[].sku` | `SellerSKU` |
|
|
|
|
|
+| `items[].title` | `Title` |
|
|
|
|
|
+| `items[].quantity` | `QuantityOrdered` |
|
|
|
|
|
+| `items[].unitPrice` | `ItemPrice.Amount / QuantityOrdered` |
|
|
|
|
|
+| `items[].subtotal` | `ItemPrice.Amount` |
|
|
|
|
|
+| `buyer.name` | `BuyerInfo.BuyerName` |
|
|
|
|
|
+| `buyer.email` | `BuyerInfo.BuyerEmail` |
|
|
|
|
|
+| `shipping.service` | `ShipmentServiceLevelCategory` |
|
|
|
|
|
+| `payment.subtotal` | `OrderTotal.Amount - ShippingPrice - Tax` |
|
|
|
|
|
+| `payment.shippingFee` | `ShippingPrice.Amount` |
|
|
|
|
|
+| `payment.tax` | `TaxCollection.Amount` |
|
|
|
|
|
+| `payment.total` | `OrderTotal.Amount` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "111-1234567-1234567",
|
|
|
|
|
+ "status": "shipped",
|
|
|
|
|
+ "totalAmount": 59.98,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "itemCount": 2,
|
|
|
|
|
+ "fulfillmentChannel": "AFN",
|
|
|
|
|
+ "createdAt": "2025-01-15T08:30:00.000Z",
|
|
|
|
|
+ "updatedAt": "2025-01-16T14:20:00.000Z",
|
|
|
|
|
+ "shippingAddress": {
|
|
|
|
|
+ "city": "Seattle",
|
|
|
|
|
+ "state": "WA",
|
|
|
|
|
+ "country": "US",
|
|
|
|
|
+ "postalCode": "98101"
|
|
|
|
|
+ },
|
|
|
|
|
+ "marketplaceId": "ATVPDKIKX0DER",
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "ITEM001",
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "sku": "WH-BT-001",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "quantity": 2,
|
|
|
|
|
+ "unitPrice": 29.99,
|
|
|
|
|
+ "subtotal": 59.98,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/example.jpg"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "buyer": {
|
|
|
|
|
+ "name": "J*** D***",
|
|
|
|
|
+ "email": null
|
|
|
|
|
+ },
|
|
|
|
|
+ "shipping": {
|
|
|
|
|
+ "service": "Expedited",
|
|
|
|
|
+ "trackingNumber": "TBA123456789",
|
|
|
|
|
+ "estimatedDelivery": "2025-01-18T00:00:00.000Z",
|
|
|
|
|
+ "shippedAt": "2025-01-16T10:00:00.000Z",
|
|
|
|
|
+ "deliveredAt": null
|
|
|
|
|
+ },
|
|
|
|
|
+ "payment": {
|
|
|
|
|
+ "method": "Other",
|
|
|
|
|
+ "subtotal": 59.98,
|
|
|
|
|
+ "shippingFee": 0,
|
|
|
|
|
+ "tax": 5.40,
|
|
|
|
|
+ "discount": 0,
|
|
|
|
|
+ "total": 65.38,
|
|
|
|
|
+ "currency": "USD"
|
|
|
|
|
+ },
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.2.3 `GET /api/clean/orders/metrics` — 订单统计
|
|
|
|
|
+
|
|
|
|
|
+获取 Amazon 销售订单指标汇总。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `SalesApi.getOrderMetrics` | `GET /api/amazon/sales/orderMetrics` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface OrderMetricsParams {
|
|
|
|
|
+ marketplaceId: string;
|
|
|
|
|
+ /** 时间粒度 */
|
|
|
|
|
+ granularity: 'day' | 'week' | 'month' | 'year';
|
|
|
|
|
+ /** 开始日期 ISO 8601 */
|
|
|
|
|
+ startDate: string;
|
|
|
|
|
+ /** 结束日期 ISO 8601 */
|
|
|
|
|
+ endDate: string;
|
|
|
|
|
+ /** 按 ASIN 筛选 */
|
|
|
|
|
+ asin?: string;
|
|
|
|
|
+ /** 按 SKU 筛选 */
|
|
|
|
|
+ sku?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanOrderMetrics {
|
|
|
|
|
+ /** 统计周期 */
|
|
|
|
|
+ period: {
|
|
|
|
|
+ startDate: string;
|
|
|
|
|
+ endDate: string;
|
|
|
|
|
+ granularity: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 汇总 */
|
|
|
|
|
+ summary: {
|
|
|
|
|
+ totalOrders: number;
|
|
|
|
|
+ totalUnits: number;
|
|
|
|
|
+ totalRevenue: number;
|
|
|
|
|
+ averageOrderValue: number;
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 时间序列 */
|
|
|
|
|
+ timeline: Array<{
|
|
|
|
|
+ date: string;
|
|
|
|
|
+ orders: number;
|
|
|
|
|
+ units: number;
|
|
|
|
|
+ revenue: number;
|
|
|
|
|
+ averageOrderValue: number;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ _source: 'amazon';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanOrderMetrics>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `summary.totalOrders` | `orderMetrics[].orderCount` (求和) |
|
|
|
|
|
+| `summary.totalUnits` | `orderMetrics[].unitCount` (求和) |
|
|
|
|
|
+| `summary.totalRevenue` | `orderMetrics[].totalSales.amount` (求和) |
|
|
|
|
|
+| `summary.averageOrderValue` | `totalRevenue / totalOrders` |
|
|
|
|
|
+| `summary.currency` | `orderMetrics[0].totalSales.currencyCode` |
|
|
|
|
|
+| `timeline[].date` | `orderMetrics[].interval` (解析) |
|
|
|
|
|
+| `timeline[].orders` | `orderMetrics[].orderCount` |
|
|
|
|
|
+| `timeline[].units` | `orderMetrics[].unitCount` |
|
|
|
|
|
+| `timeline[].revenue` | `orderMetrics[].totalSales.amount` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "period": {
|
|
|
|
|
+ "startDate": "2025-01-01",
|
|
|
|
|
+ "endDate": "2025-01-31",
|
|
|
|
|
+ "granularity": "week"
|
|
|
|
|
+ },
|
|
|
|
|
+ "summary": {
|
|
|
|
|
+ "totalOrders": 420,
|
|
|
|
|
+ "totalUnits": 680,
|
|
|
|
|
+ "totalRevenue": 20386.20,
|
|
|
|
|
+ "averageOrderValue": 48.54,
|
|
|
|
|
+ "currency": "USD"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timeline": [
|
|
|
|
|
+ { "date": "2025-01-01", "orders": 95, "units": 150, "revenue": 4497.00, "averageOrderValue": 47.34 },
|
|
|
|
|
+ { "date": "2025-01-08", "orders": 110, "units": 180, "revenue": 5398.20, "averageOrderValue": 49.07 },
|
|
|
|
|
+ { "date": "2025-01-15", "orders": 105, "units": 170, "revenue": 5098.30, "averageOrderValue": 48.56 },
|
|
|
|
|
+ { "date": "2025-01-22", "orders": 110, "units": 180, "revenue": 5392.70, "averageOrderValue": 49.02 }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.3 商品管理(Amazon Listings)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.3.1 `GET /api/clean/listings` — Listing 列表
|
|
|
|
|
+
|
|
|
|
|
+获取卖家的 Amazon Listing 列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `ListingsApi.getListingsItems` | `GET /api/amazon/listings` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface ListingListParams extends PaginationParams {
|
|
|
|
|
+ marketplaceId: string;
|
|
|
|
|
+ /** 按状态筛选 */
|
|
|
|
|
+ status?: 'active' | 'inactive' | 'incomplete';
|
|
|
|
|
+ /** 搜索关键词(标题/SKU/ASIN) */
|
|
|
|
|
+ keyword?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanListing {
|
|
|
|
|
+ /** SKU */
|
|
|
|
|
+ sku: string;
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ /** 商品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 主图 URL */
|
|
|
|
|
+ imageUrl: string | null;
|
|
|
|
|
+ /** 价格 */
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 状态 */
|
|
|
|
|
+ status: 'active' | 'inactive' | 'incomplete';
|
|
|
|
|
+ /** FBA 库存数量 */
|
|
|
|
|
+ fbaQuantity: number;
|
|
|
|
|
+ /** 自发货库存数量 */
|
|
|
|
|
+ fbmQuantity: number;
|
|
|
|
|
+ /** 创建时间 */
|
|
|
|
|
+ createdAt: string;
|
|
|
|
|
+ /** 最后更新时间 */
|
|
|
|
|
+ updatedAt: string;
|
|
|
|
|
+ /** 市场 ID */
|
|
|
|
|
+ marketplaceId: string;
|
|
|
|
|
+ _source: 'amazon';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanListing>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `sku` | `sku` |
|
|
|
|
|
+| `asin` | `summaries[0].asin` |
|
|
|
|
|
+| `title` | `summaries[0].itemName` |
|
|
|
|
|
+| `imageUrl` | `summaries[0].mainImage.link` |
|
|
|
|
|
+| `price` | `attributes.purchasable_offer[0].our_price[0].schedule[0].value_with_tax` |
|
|
|
|
|
+| `status` | `summaries[0].status[0]` |
|
|
|
|
|
+| `fbaQuantity` | `fulfillmentAvailability[0].quantity` (AFN) |
|
|
|
|
|
+| `fbmQuantity` | `fulfillmentAvailability[0].quantity` (MFN) |
|
|
|
|
|
+| `createdAt` | `summaries[0].createdDate` |
|
|
|
|
|
+| `updatedAt` | `summaries[0].lastUpdatedDate` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "sku": "WH-BT-001",
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/example.jpg",
|
|
|
|
|
+ "price": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "status": "active",
|
|
|
|
|
+ "fbaQuantity": 580,
|
|
|
|
|
+ "fbmQuantity": 0,
|
|
|
|
|
+ "createdAt": "2024-03-15T00:00:00.000Z",
|
|
|
|
|
+ "updatedAt": "2025-01-10T08:00:00.000Z",
|
|
|
|
|
+ "marketplaceId": "ATVPDKIKX0DER",
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 45,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.3.2 `GET /api/clean/listings/:sku` — Listing 详情
|
|
|
|
|
+
|
|
|
|
|
+获取单个 Listing 的完整信息。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `ListingsApi.getListingsItem` | `GET /api/amazon/listings/:sku` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: sku = 卖家 SKU
|
|
|
|
|
+interface ListingDetailParams {
|
|
|
|
|
+ marketplaceId: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanListingDetail extends CleanListing {
|
|
|
|
|
+ /** 商品描述 */
|
|
|
|
|
+ description: string | null;
|
|
|
|
|
+ /** 商品特征 */
|
|
|
|
|
+ features: string[];
|
|
|
|
|
+ /** 商品属性 */
|
|
|
|
|
+ attributes: Record<string, string>;
|
|
|
|
|
+ /** 变体信息 */
|
|
|
|
|
+ variants: Array<{
|
|
|
|
|
+ sku: string;
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ attributes: Record<string, string>;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 商品问题/警告 */
|
|
|
|
|
+ issues: Array<{
|
|
|
|
|
+ code: string;
|
|
|
|
|
+ message: string;
|
|
|
|
|
+ severity: 'error' | 'warning' | 'info';
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 配送信息 */
|
|
|
|
|
+ fulfillment: {
|
|
|
|
|
+ channel: 'AFN' | 'MFN';
|
|
|
|
|
+ quantity: number;
|
|
|
|
|
+ inboundShipments: number;
|
|
|
|
|
+ reservedQuantity: number;
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanListingDetail>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `description` | `attributes.product_description[0].value` |
|
|
|
|
|
+| `features` | `attributes.bullet_point[].value` |
|
|
|
|
|
+| `attributes` | `attributes.*` (扁平化) |
|
|
|
|
|
+| `variants` | `relationships[0].variationTheme` |
|
|
|
|
|
+| `issues[].code` | `issues[].code` |
|
|
|
|
|
+| `issues[].message` | `issues[].message` |
|
|
|
|
|
+| `issues[].severity` | `issues[].severity` |
|
|
|
|
|
+| `fulfillment.channel` | `fulfillmentAvailability[0].fulfillmentChannelCode` |
|
|
|
|
|
+| `fulfillment.quantity` | `fulfillmentAvailability[0].quantity` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "sku": "WH-BT-001",
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/example.jpg",
|
|
|
|
|
+ "price": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "status": "active",
|
|
|
|
|
+ "fbaQuantity": 580,
|
|
|
|
|
+ "fbmQuantity": 0,
|
|
|
|
|
+ "createdAt": "2024-03-15T00:00:00.000Z",
|
|
|
|
|
+ "updatedAt": "2025-01-10T08:00:00.000Z",
|
|
|
|
|
+ "marketplaceId": "ATVPDKIKX0DER",
|
|
|
|
|
+ "description": "Premium wireless headphones with active noise cancellation...",
|
|
|
|
|
+ "features": [
|
|
|
|
|
+ "Active Noise Cancellation",
|
|
|
|
|
+ "40-hour battery life",
|
|
|
|
|
+ "Bluetooth 5.3",
|
|
|
|
|
+ "Comfortable over-ear design"
|
|
|
|
|
+ ],
|
|
|
|
|
+ "attributes": {
|
|
|
|
|
+ "color": "Black",
|
|
|
|
|
+ "connectivity": "Bluetooth",
|
|
|
|
|
+ "brand": "ExampleBrand"
|
|
|
|
|
+ },
|
|
|
|
|
+ "variants": [
|
|
|
|
|
+ { "sku": "WH-BT-001-BK", "asin": "B0EXAMPLE1", "attributes": { "color": "Black" } },
|
|
|
|
|
+ { "sku": "WH-BT-001-WH", "asin": "B0EXAMPLE3", "attributes": { "color": "White" } }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "issues": [],
|
|
|
|
|
+ "fulfillment": {
|
|
|
|
|
+ "channel": "AFN",
|
|
|
|
|
+ "quantity": 580,
|
|
|
|
|
+ "inboundShipments": 200,
|
|
|
|
|
+ "reservedQuantity": 15
|
|
|
|
|
+ },
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.4 类目相关(Sorftime)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.4.1 `GET /api/clean/categories/tree` — 类目树
|
|
|
|
|
+
|
|
|
|
|
+获取 Sorftime 类目树结构。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `CategoryApi.getCategoryTree` | `POST /api/sorftime/forward` -> `/api/CategoryTree` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CategoryTreeParams {
|
|
|
|
|
+ /** 市场域名,如 amazon.com */
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 父类目 ID(不传则返回顶级类目) */
|
|
|
|
|
+ parentId?: string;
|
|
|
|
|
+ /** 展开层级深度,默认 1 */
|
|
|
|
|
+ depth?: number;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanCategory {
|
|
|
|
|
+ /** 类目 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 类目名称 */
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ /** 父类目 ID */
|
|
|
|
|
+ parentId: string | null;
|
|
|
|
|
+ /** 层级深度 */
|
|
|
|
|
+ level: number;
|
|
|
|
|
+ /** 子类目数量 */
|
|
|
|
|
+ childCount: number;
|
|
|
|
|
+ /** 该类目下产品数量估算 */
|
|
|
|
|
+ productCount: number | null;
|
|
|
|
|
+ /** 子类目列表 */
|
|
|
|
|
+ children: CleanCategory[];
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanCategory[]>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `id` | `CategoryId` |
|
|
|
|
|
+| `name` | `CategoryName` |
|
|
|
|
|
+| `parentId` | `ParentCategoryId` |
|
|
|
|
|
+| `level` | `Level` |
|
|
|
|
|
+| `childCount` | `ChildCount` |
|
|
|
|
|
+| `productCount` | `ProductCount` |
|
|
|
|
|
+| `children` | `Children[]` (递归映射) |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "172282",
|
|
|
|
|
+ "name": "Electronics",
|
|
|
|
|
+ "parentId": null,
|
|
|
|
|
+ "level": 0,
|
|
|
|
|
+ "childCount": 24,
|
|
|
|
|
+ "productCount": 5800000,
|
|
|
|
|
+ "children": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "172541",
|
|
|
|
|
+ "name": "Headphones, Earbuds & Accessories",
|
|
|
|
|
+ "parentId": "172282",
|
|
|
|
|
+ "level": 1,
|
|
|
|
|
+ "childCount": 8,
|
|
|
|
|
+ "productCount": 320000,
|
|
|
|
|
+ "children": [],
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.4.2 `GET /api/clean/categories/:id/products` — 类目热销产品
|
|
|
|
|
+
|
|
|
|
|
+获取指定类目下的热销产品列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `CategoryApi.getCategoryProducts` | `POST /api/sorftime/forward` -> `/api/CategoryProducts` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = 类目 ID
|
|
|
|
|
+interface CategoryProductsParams extends PaginationParams {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 排序字段 */
|
|
|
|
|
+ sortBy?: 'sales' | 'price' | 'rating' | 'bsr' | 'reviews';
|
|
|
|
|
+ sortOrder?: 'asc' | 'desc';
|
|
|
|
|
+ /** 价格范围 */
|
|
|
|
|
+ minPrice?: number;
|
|
|
|
|
+ maxPrice?: number;
|
|
|
|
|
+ /** 评分范围 */
|
|
|
|
|
+ minRating?: number;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanCategoryProduct {
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 产品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 品牌 */
|
|
|
|
|
+ brand: string;
|
|
|
|
|
+ /** 主图 URL */
|
|
|
|
|
+ imageUrl: string;
|
|
|
|
|
+ /** 价格 */
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 评分 */
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ /** 评论数 */
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ /** BSR 排名 */
|
|
|
|
|
+ bsrRank: number | null;
|
|
|
|
|
+ /** 月销量估算 */
|
|
|
|
|
+ estimatedMonthlySales: number | null;
|
|
|
|
|
+ /** 月收入估算 */
|
|
|
|
|
+ estimatedMonthlyRevenue: number | null;
|
|
|
|
|
+ /** 上架时间 */
|
|
|
|
|
+ listedAt: string | null;
|
|
|
|
|
+ /** 卖家数量 */
|
|
|
|
|
+ sellerCount: number | null;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanCategoryProduct>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `id` | `ASIN` |
|
|
|
|
|
+| `title` | `Title` |
|
|
|
|
|
+| `brand` | `Brand` |
|
|
|
|
|
+| `imageUrl` | `ImageUrl` |
|
|
|
|
|
+| `price` | `Price` |
|
|
|
|
|
+| `rating` | `Rating` |
|
|
|
|
|
+| `reviewCount` | `Reviews` |
|
|
|
|
|
+| `bsrRank` | `BSR` |
|
|
|
|
|
+| `estimatedMonthlySales` | `MonthlySales` |
|
|
|
|
|
+| `estimatedMonthlyRevenue` | `MonthlyRevenue` |
|
|
|
|
|
+| `listedAt` | `DateFirstAvailable` |
|
|
|
|
|
+| `sellerCount` | `SellerNum` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "B0EXAMPLE1",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "brand": "ExampleBrand",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/example.jpg",
|
|
|
|
|
+ "price": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "rating": 4.5,
|
|
|
|
|
+ "reviewCount": 12580,
|
|
|
|
|
+ "bsrRank": 1523,
|
|
|
|
|
+ "estimatedMonthlySales": 8500,
|
|
|
|
|
+ "estimatedMonthlyRevenue": 254915,
|
|
|
|
|
+ "listedAt": "2024-03-15T00:00:00.000Z",
|
|
|
|
|
+ "sellerCount": 3,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 500,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.4.3 `GET /api/clean/categories/:id/keywords` — 类目关键词
|
|
|
|
|
+
|
|
|
|
|
+获取指定类目下的热门关键词。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `CategoryApi.getCategoryKeywords` | `POST /api/sorftime/forward` -> `/api/CategoryKeywords` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = 类目 ID
|
|
|
|
|
+interface CategoryKeywordsParams extends PaginationParams {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 排序字段 */
|
|
|
|
|
+ sortBy?: 'searchVolume' | 'growth' | 'competition';
|
|
|
|
|
+ sortOrder?: 'asc' | 'desc';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanCategoryKeyword {
|
|
|
|
|
+ /** 关键词 */
|
|
|
|
|
+ keyword: string;
|
|
|
|
|
+ /** 月搜索量 */
|
|
|
|
|
+ searchVolume: number;
|
|
|
|
|
+ /** 搜索量增长率(百分比) */
|
|
|
|
|
+ growthRate: number | null;
|
|
|
|
|
+ /** 竞争度 0-1 */
|
|
|
|
|
+ competition: number | null;
|
|
|
|
|
+ /** 点击集中度 */
|
|
|
|
|
+ clickConcentration: number | null;
|
|
|
|
|
+ /** 关联产品数 */
|
|
|
|
|
+ productCount: number | null;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanCategoryKeyword>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `keyword` | `Keyword` |
|
|
|
|
|
+| `searchVolume` | `SearchVolume` |
|
|
|
|
|
+| `growthRate` | `GrowthRate` |
|
|
|
|
|
+| `competition` | `Competition` |
|
|
|
|
|
+| `clickConcentration` | `ClickConcentration` |
|
|
|
|
|
+| `productCount` | `ProductCount` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "keyword": "wireless headphones",
|
|
|
|
|
+ "searchVolume": 1250000,
|
|
|
|
|
+ "growthRate": 12.5,
|
|
|
|
|
+ "competition": 0.85,
|
|
|
|
|
+ "clickConcentration": 0.42,
|
|
|
|
|
+ "productCount": 50000,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "keyword": "bluetooth headphones noise cancelling",
|
|
|
|
|
+ "searchVolume": 680000,
|
|
|
|
|
+ "growthRate": 18.3,
|
|
|
|
|
+ "competition": 0.72,
|
|
|
|
|
+ "clickConcentration": 0.38,
|
|
|
|
|
+ "productCount": 28000,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 150,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.5 关键词相关(Sorftime)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.5.1 `GET /api/clean/keywords/search` — 关键词查询
|
|
|
|
|
+
|
|
|
|
|
+搜索关键词并返回搜索量、竞争度等数据。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `KeywordApi.getKeywordSearch` | `POST /api/sorftime/forward` -> `/api/KeywordSearch` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface KeywordSearchParams extends PaginationParams {
|
|
|
|
|
+ /** 搜索关键词 */
|
|
|
|
|
+ keyword: string;
|
|
|
|
|
+ /** 市场域名 */
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 匹配模式 */
|
|
|
|
|
+ matchType?: 'exact' | 'broad' | 'phrase';
|
|
|
|
|
+ /** 最小搜索量 */
|
|
|
|
|
+ minSearchVolume?: number;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanKeyword {
|
|
|
|
|
+ /** 关键词 */
|
|
|
|
|
+ keyword: string;
|
|
|
|
|
+ /** 月搜索量 */
|
|
|
|
|
+ searchVolume: number;
|
|
|
|
|
+ /** 搜索量趋势(近3个月) */
|
|
|
|
|
+ searchTrend: 'up' | 'down' | 'stable';
|
|
|
|
|
+ /** 搜索量增长率(百分比) */
|
|
|
|
|
+ growthRate: number | null;
|
|
|
|
|
+ /** 竞争度 0-1 */
|
|
|
|
|
+ competition: number | null;
|
|
|
|
|
+ /** 推荐出价(美元) */
|
|
|
|
|
+ suggestedBid: number | null;
|
|
|
|
|
+ /** 点击集中度 */
|
|
|
|
|
+ clickConcentration: number | null;
|
|
|
|
|
+ /** 关联产品数 */
|
|
|
|
|
+ productCount: number | null;
|
|
|
|
|
+ /** 相关关键词 */
|
|
|
|
|
+ relatedKeywords: string[];
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanKeyword>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `keyword` | `Keyword` |
|
|
|
|
|
+| `searchVolume` | `SearchVolume` |
|
|
|
|
|
+| `searchTrend` | 根据 `SearchVolumeHistory` 计算 |
|
|
|
|
|
+| `growthRate` | `GrowthRate` |
|
|
|
|
|
+| `competition` | `Competition` |
|
|
|
|
|
+| `suggestedBid` | `SuggestedBid` |
|
|
|
|
|
+| `clickConcentration` | `ClickConcentration` |
|
|
|
|
|
+| `productCount` | `ProductCount` |
|
|
|
|
|
+| `relatedKeywords` | `RelatedKeywords[]` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "keyword": "wireless headphones",
|
|
|
|
|
+ "searchVolume": 1250000,
|
|
|
|
|
+ "searchTrend": "up",
|
|
|
|
|
+ "growthRate": 12.5,
|
|
|
|
|
+ "competition": 0.85,
|
|
|
|
|
+ "suggestedBid": 2.35,
|
|
|
|
|
+ "clickConcentration": 0.42,
|
|
|
|
|
+ "productCount": 50000,
|
|
|
|
|
+ "relatedKeywords": ["bluetooth headphones", "wireless earbuds", "noise cancelling headphones"],
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 85,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.5.2 `GET /api/clean/keywords/:keyword/products` — 关键词产品排名
|
|
|
|
|
+
|
|
|
|
|
+获取指定关键词下的产品排名列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `KeywordApi.getKeywordProducts` | `POST /api/sorftime/forward` -> `/api/KeywordProducts` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: keyword = 关键词(需 URL 编码)
|
|
|
|
|
+interface KeywordProductsParams extends PaginationParams {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 排名类型 */
|
|
|
|
|
+ rankType?: 'organic' | 'sponsored' | 'all';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanKeywordProduct {
|
|
|
|
|
+ /** 排名位置 */
|
|
|
|
|
+ rank: number;
|
|
|
|
|
+ /** 排名类型 */
|
|
|
|
|
+ rankType: 'organic' | 'sponsored';
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 产品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 品牌 */
|
|
|
|
|
+ brand: string;
|
|
|
|
|
+ /** 主图 URL */
|
|
|
|
|
+ imageUrl: string;
|
|
|
|
|
+ /** 价格 */
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 评分 */
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ /** 评论数 */
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ /** BSR 排名 */
|
|
|
|
|
+ bsrRank: number | null;
|
|
|
|
|
+ /** 月销量估算 */
|
|
|
|
|
+ estimatedMonthlySales: number | null;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanKeywordProduct>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `rank` | `Position` |
|
|
|
|
|
+| `rankType` | `Type` (`organic` / `sponsored`) |
|
|
|
|
|
+| `id` | `ASIN` |
|
|
|
|
|
+| `title` | `Title` |
|
|
|
|
|
+| `brand` | `Brand` |
|
|
|
|
|
+| `imageUrl` | `ImageUrl` |
|
|
|
|
|
+| `price` | `Price` |
|
|
|
|
|
+| `rating` | `Rating` |
|
|
|
|
|
+| `reviewCount` | `Reviews` |
|
|
|
|
|
+| `bsrRank` | `BSR` |
|
|
|
|
|
+| `estimatedMonthlySales` | `MonthlySales` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "rank": 1,
|
|
|
|
|
+ "rankType": "organic",
|
|
|
|
|
+ "id": "B0EXAMPLE1",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "brand": "ExampleBrand",
|
|
|
|
|
+ "imageUrl": "https://m.media-amazon.com/images/I/example.jpg",
|
|
|
|
|
+ "price": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "rating": 4.5,
|
|
|
|
|
+ "reviewCount": 12580,
|
|
|
|
|
+ "bsrRank": 1523,
|
|
|
|
|
+ "estimatedMonthlySales": 8500,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 300,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.5.3 `GET /api/clean/keywords/reverse/:asin` — ASIN 反查关键词
|
|
|
|
|
+
|
|
|
|
|
+通过 ASIN 反查该产品排名的关键词列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `KeywordApi.getReverseAsin` | `POST /api/sorftime/forward` -> `/api/ReverseAsin` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: asin = ASIN
|
|
|
|
|
+interface ReverseAsinParams extends PaginationParams {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 最小搜索量筛选 */
|
|
|
|
|
+ minSearchVolume?: number;
|
|
|
|
|
+ /** 排序字段 */
|
|
|
|
|
+ sortBy?: 'searchVolume' | 'rank' | 'competition';
|
|
|
|
|
+ sortOrder?: 'asc' | 'desc';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanReverseKeyword {
|
|
|
|
|
+ /** 关键词 */
|
|
|
|
|
+ keyword: string;
|
|
|
|
|
+ /** 该 ASIN 在此关键词下的排名 */
|
|
|
|
|
+ rank: number;
|
|
|
|
|
+ /** 排名类型 */
|
|
|
|
|
+ rankType: 'organic' | 'sponsored';
|
|
|
|
|
+ /** 月搜索量 */
|
|
|
|
|
+ searchVolume: number;
|
|
|
|
|
+ /** 竞争度 0-1 */
|
|
|
|
|
+ competition: number | null;
|
|
|
|
|
+ /** 点击集中度 */
|
|
|
|
|
+ clickConcentration: number | null;
|
|
|
|
|
+ /** 搜索量增长率 */
|
|
|
|
|
+ growthRate: number | null;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanReverseKeyword>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `keyword` | `Keyword` |
|
|
|
|
|
+| `rank` | `Position` |
|
|
|
|
|
+| `rankType` | `Type` |
|
|
|
|
|
+| `searchVolume` | `SearchVolume` |
|
|
|
|
|
+| `competition` | `Competition` |
|
|
|
|
|
+| `clickConcentration` | `ClickConcentration` |
|
|
|
|
|
+| `growthRate` | `GrowthRate` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "keyword": "wireless headphones",
|
|
|
|
|
+ "rank": 5,
|
|
|
|
|
+ "rankType": "organic",
|
|
|
|
|
+ "searchVolume": 1250000,
|
|
|
|
|
+ "competition": 0.85,
|
|
|
|
|
+ "clickConcentration": 0.42,
|
|
|
|
|
+ "growthRate": 12.5,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "keyword": "bluetooth headphones noise cancelling",
|
|
|
|
|
+ "rank": 3,
|
|
|
|
|
+ "rankType": "organic",
|
|
|
|
|
+ "searchVolume": 680000,
|
|
|
|
|
+ "competition": 0.72,
|
|
|
|
|
+ "clickConcentration": 0.38,
|
|
|
|
|
+ "growthRate": 18.3,
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 420,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.5.4 `GET /api/clean/keywords/:keyword/trend` — 关键词趋势
|
|
|
|
|
+
|
|
|
|
|
+获取关键词的搜索量历史趋势数据。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `KeywordApi.getKeywordTrend` | `POST /api/sorftime/forward` -> `/api/KeywordTrend` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: keyword = 关键词(需 URL 编码)
|
|
|
|
|
+interface KeywordTrendParams {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 时间范围 */
|
|
|
|
|
+ period?: '3m' | '6m' | '12m' | '24m';
|
|
|
|
|
+ /** 时间粒度 */
|
|
|
|
|
+ granularity?: 'day' | 'week' | 'month';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanKeywordTrend {
|
|
|
|
|
+ /** 关键词 */
|
|
|
|
|
+ keyword: string;
|
|
|
|
|
+ /** 当前月搜索量 */
|
|
|
|
|
+ currentSearchVolume: number;
|
|
|
|
|
+ /** 搜索量变化率 */
|
|
|
|
|
+ changeRate: number;
|
|
|
|
|
+ /** 趋势方向 */
|
|
|
|
|
+ trend: 'up' | 'down' | 'stable';
|
|
|
|
|
+ /** 历史数据 */
|
|
|
|
|
+ history: Array<{
|
|
|
|
|
+ date: string;
|
|
|
|
|
+ searchVolume: number;
|
|
|
|
|
+ rank: number | null;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 季节性指数(1-12月) */
|
|
|
|
|
+ seasonality: Array<{
|
|
|
|
|
+ month: number;
|
|
|
|
|
+ index: number;
|
|
|
|
|
+ }> | null;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanKeywordTrend>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Sorftime 原始字段 |
|
|
|
|
|
+|-----------|------------------|
|
|
|
|
|
+| `keyword` | `Keyword` |
|
|
|
|
|
+| `currentSearchVolume` | `CurrentSearchVolume` |
|
|
|
|
|
+| `changeRate` | `ChangeRate` |
|
|
|
|
|
+| `trend` | 根据 `ChangeRate` 计算 |
|
|
|
|
|
+| `history[].date` | `History[].Date` |
|
|
|
|
|
+| `history[].searchVolume` | `History[].SearchVolume` |
|
|
|
|
|
+| `seasonality[].month` | `Seasonality[].Month` |
|
|
|
|
|
+| `seasonality[].index` | `Seasonality[].Index` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "keyword": "wireless headphones",
|
|
|
|
|
+ "currentSearchVolume": 1250000,
|
|
|
|
|
+ "changeRate": 12.5,
|
|
|
|
|
+ "trend": "up",
|
|
|
|
|
+ "history": [
|
|
|
|
|
+ { "date": "2024-11-01", "searchVolume": 980000, "rank": null },
|
|
|
|
|
+ { "date": "2024-12-01", "searchVolume": 1150000, "rank": null },
|
|
|
|
|
+ { "date": "2025-01-01", "searchVolume": 1250000, "rank": null }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "seasonality": [
|
|
|
|
|
+ { "month": 1, "index": 1.05 },
|
|
|
|
|
+ { "month": 2, "index": 0.92 },
|
|
|
|
|
+ { "month": 11, "index": 1.35 },
|
|
|
|
|
+ { "month": 12, "index": 1.58 }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.6 监控相关(Sorftime)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.6.1 `POST /api/clean/monitoring/bestseller/subscribe` — BS 榜单订阅
|
|
|
|
|
+
|
|
|
|
|
+订阅 Best Seller 榜单监控任务。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `MonitorApi.subscribeBestSeller` | `POST /api/sorftime/forward` -> `/api/BestSellerSubscribe` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface BestSellerSubscribeParams {
|
|
|
|
|
+ /** 市场域名 */
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 类目 ID */
|
|
|
|
|
+ categoryId: string;
|
|
|
|
|
+ /** 监控频率 */
|
|
|
|
|
+ frequency: 'hourly' | 'daily' | 'weekly';
|
|
|
|
|
+ /** 通知方式 */
|
|
|
|
|
+ notifyType?: 'email' | 'webhook' | 'none';
|
|
|
|
|
+ /** 通知地址 */
|
|
|
|
|
+ notifyUrl?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanSubscription {
|
|
|
|
|
+ /** 订阅任务 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 订阅类型 */
|
|
|
|
|
+ type: 'bestseller' | 'asin';
|
|
|
|
|
+ /** 状态 */
|
|
|
|
|
+ status: 'active' | 'paused' | 'expired';
|
|
|
|
|
+ /** 监控目标 */
|
|
|
|
|
+ target: {
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ categoryId?: string;
|
|
|
|
|
+ categoryName?: string;
|
|
|
|
|
+ asin?: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 监控频率 */
|
|
|
|
|
+ frequency: string;
|
|
|
|
|
+ /** 创建时间 */
|
|
|
|
|
+ createdAt: string;
|
|
|
|
|
+ /** 下次执行时间 */
|
|
|
|
|
+ nextRunAt: string;
|
|
|
|
|
+ _source: 'sorftime';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanSubscription>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "SUB_BS_001",
|
|
|
|
|
+ "type": "bestseller",
|
|
|
|
|
+ "status": "active",
|
|
|
|
|
+ "target": {
|
|
|
|
|
+ "domain": "amazon.com",
|
|
|
|
|
+ "categoryId": "172282",
|
|
|
|
|
+ "categoryName": "Electronics"
|
|
|
|
|
+ },
|
|
|
|
|
+ "frequency": "daily",
|
|
|
|
|
+ "createdAt": "2025-01-01T12:00:00.000Z",
|
|
|
|
|
+ "nextRunAt": "2025-01-02T12:00:00.000Z",
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.6.2 `GET /api/clean/monitoring/bestseller/tasks` — BS 榜单任务
|
|
|
|
|
+
|
|
|
|
|
+获取 Best Seller 榜单监控任务列表及结果。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `MonitorApi.getBestSellerTasks` | `POST /api/sorftime/forward` -> `/api/BestSellerTasks` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface BestSellerTasksParams extends PaginationParams {
|
|
|
|
|
+ /** 按状态筛选 */
|
|
|
|
|
+ status?: 'active' | 'paused' | 'expired';
|
|
|
|
|
+ domain?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanBestSellerTask extends CleanSubscription {
|
|
|
|
|
+ /** 最近一次执行结果 */
|
|
|
|
|
+ lastResult: {
|
|
|
|
|
+ executedAt: string;
|
|
|
|
|
+ /** 榜单产品列表(前 N 名) */
|
|
|
|
|
+ products: Array<{
|
|
|
|
|
+ rank: number;
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 与上次对比的变化 */
|
|
|
|
|
+ changes: {
|
|
|
|
|
+ newEntries: number;
|
|
|
|
|
+ removedEntries: number;
|
|
|
|
|
+ rankChanges: number;
|
|
|
|
|
+ };
|
|
|
|
|
+ } | null;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanBestSellerTask>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "SUB_BS_001",
|
|
|
|
|
+ "type": "bestseller",
|
|
|
|
|
+ "status": "active",
|
|
|
|
|
+ "target": {
|
|
|
|
|
+ "domain": "amazon.com",
|
|
|
|
|
+ "categoryId": "172282",
|
|
|
|
|
+ "categoryName": "Electronics"
|
|
|
|
|
+ },
|
|
|
|
|
+ "frequency": "daily",
|
|
|
|
|
+ "createdAt": "2025-01-01T12:00:00.000Z",
|
|
|
|
|
+ "nextRunAt": "2025-01-02T12:00:00.000Z",
|
|
|
|
|
+ "lastResult": {
|
|
|
|
|
+ "executedAt": "2025-01-01T12:00:00.000Z",
|
|
|
|
|
+ "products": [
|
|
|
|
|
+ { "rank": 1, "asin": "B0EXAMPLE1", "title": "Wireless Headphones", "price": 29.99, "rating": 4.5, "reviewCount": 12580 },
|
|
|
|
|
+ { "rank": 2, "asin": "B0EXAMPLE2", "title": "Bluetooth Speaker", "price": 39.99, "rating": 4.6, "reviewCount": 8900 }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "changes": {
|
|
|
|
|
+ "newEntries": 3,
|
|
|
|
|
+ "removedEntries": 2,
|
|
|
|
|
+ "rankChanges": 15
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 5,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": false
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.6.3 `POST /api/clean/monitoring/asin/subscribe` — ASIN 订阅
|
|
|
|
|
+
|
|
|
|
|
+订阅单个 ASIN 的数据变化监控。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Sorftime | `MonitorApi.subscribeAsin` | `POST /api/sorftime/forward` -> `/api/AsinSubscribe` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface AsinSubscribeParams {
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ /** 市场域名 */
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 监控频率 */
|
|
|
|
|
+ frequency: 'hourly' | 'daily' | 'weekly';
|
|
|
|
|
+ /** 监控指标 */
|
|
|
|
|
+ metrics: Array<'price' | 'bsr' | 'rating' | 'reviews' | 'sales' | 'sellers'>;
|
|
|
|
|
+ /** 通知方式 */
|
|
|
|
|
+ notifyType?: 'email' | 'webhook' | 'none';
|
|
|
|
|
+ /** 通知地址 */
|
|
|
|
|
+ notifyUrl?: string;
|
|
|
|
|
+ /** 变化阈值(百分比),超过阈值才通知 */
|
|
|
|
|
+ threshold?: number;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 响应: ApiResponse<CleanSubscription>
|
|
|
|
|
+// 复用 CleanSubscription 类型,target 中包含 asin 字段
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "SUB_ASIN_001",
|
|
|
|
|
+ "type": "asin",
|
|
|
|
|
+ "status": "active",
|
|
|
|
|
+ "target": {
|
|
|
|
|
+ "domain": "amazon.com",
|
|
|
|
|
+ "asin": "B0EXAMPLE1"
|
|
|
|
|
+ },
|
|
|
|
|
+ "frequency": "daily",
|
|
|
|
|
+ "createdAt": "2025-01-01T12:00:00.000Z",
|
|
|
|
|
+ "nextRunAt": "2025-01-02T12:00:00.000Z",
|
|
|
|
|
+ "_source": "sorftime"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.7 TikTok 社交媒体(TikHub)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.7.1 `GET /api/clean/tiktok/users/:uniqueId` — 用户资料
|
|
|
|
|
+
|
|
|
|
|
+获取 TikTok 用户公开资料信息。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| TikHub | `TikTokUserApi.getUserProfile` | `GET /api/tikhub/tiktok/user/profile` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: uniqueId = TikTok 用户名
|
|
|
|
|
+interface TikTokUserParams {
|
|
|
|
|
+ /** 无额外参数 */
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanTikTokUser {
|
|
|
|
|
+ /** 用户 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 用户名 */
|
|
|
|
|
+ uniqueId: string;
|
|
|
|
|
+ /** 昵称 */
|
|
|
|
|
+ nickname: string;
|
|
|
|
|
+ /** 头像 URL */
|
|
|
|
|
+ avatarUrl: string;
|
|
|
|
|
+ /** 个人简介 */
|
|
|
|
|
+ bio: string;
|
|
|
|
|
+ /** 是否已认证 */
|
|
|
|
|
+ verified: boolean;
|
|
|
|
|
+ /** 粉丝数 */
|
|
|
|
|
+ followerCount: number;
|
|
|
|
|
+ /** 关注数 */
|
|
|
|
|
+ followingCount: number;
|
|
|
|
|
+ /** 获赞数 */
|
|
|
|
|
+ likeCount: number;
|
|
|
|
|
+ /** 视频数 */
|
|
|
|
|
+ videoCount: number;
|
|
|
|
|
+ /** 主页链接 */
|
|
|
|
|
+ profileUrl: string;
|
|
|
|
|
+ /** 关联商业信息 */
|
|
|
|
|
+ commerce: {
|
|
|
|
|
+ /** 是否开通商品橱窗 */
|
|
|
|
|
+ hasShop: boolean;
|
|
|
|
|
+ /** 商品数量 */
|
|
|
|
|
+ productCount: number | null;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ _source: 'tikhub';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanTikTokUser>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | TikHub 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `user.id` |
|
|
|
|
|
+| `uniqueId` | `user.uniqueId` |
|
|
|
|
|
+| `nickname` | `user.nickname` |
|
|
|
|
|
+| `avatarUrl` | `user.avatarLarger` |
|
|
|
|
|
+| `bio` | `user.signature` |
|
|
|
|
|
+| `verified` | `user.verified` |
|
|
|
|
|
+| `followerCount` | `stats.followerCount` |
|
|
|
|
|
+| `followingCount` | `stats.followingCount` |
|
|
|
|
|
+| `likeCount` | `stats.heartCount` |
|
|
|
|
|
+| `videoCount` | `stats.videoCount` |
|
|
|
|
|
+| `commerce.hasShop` | `user.commerceUserInfo.commerceUser` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "6890000000000000000",
|
|
|
|
|
+ "uniqueId": "exampleuser",
|
|
|
|
|
+ "nickname": "Example Creator",
|
|
|
|
|
+ "avatarUrl": "https://p16-sign.tiktokcdn.com/example-avatar.jpg",
|
|
|
|
|
+ "bio": "Content creator | Product reviews",
|
|
|
|
|
+ "verified": true,
|
|
|
|
|
+ "followerCount": 1250000,
|
|
|
|
|
+ "followingCount": 320,
|
|
|
|
|
+ "likeCount": 45000000,
|
|
|
|
|
+ "videoCount": 580,
|
|
|
|
|
+ "profileUrl": "https://www.tiktok.com/@exampleuser",
|
|
|
|
|
+ "commerce": {
|
|
|
|
|
+ "hasShop": true,
|
|
|
|
|
+ "productCount": 25
|
|
|
|
|
+ },
|
|
|
|
|
+ "_source": "tikhub"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.7.2 `GET /api/clean/tiktok/videos/:id` — 视频详情
|
|
|
|
|
+
|
|
|
|
|
+获取 TikTok 视频详细信息。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| TikHub | `TikTokVideoApi.getVideoDetail` | `GET /api/tikhub/tiktok/video/detail` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = 视频 ID
|
|
|
|
|
+interface TikTokVideoParams {
|
|
|
|
|
+ /** 无额外参数 */
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanTikTokVideo {
|
|
|
|
|
+ /** 视频 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 视频描述 */
|
|
|
|
|
+ description: string;
|
|
|
|
|
+ /** 视频封面 URL */
|
|
|
|
|
+ coverUrl: string;
|
|
|
|
|
+ /** 视频播放 URL */
|
|
|
|
|
+ videoUrl: string;
|
|
|
|
|
+ /** 视频时长(秒) */
|
|
|
|
|
+ duration: number;
|
|
|
|
|
+ /** 创建时间 */
|
|
|
|
|
+ createdAt: string;
|
|
|
|
|
+ /** 作者信息 */
|
|
|
|
|
+ author: {
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ uniqueId: string;
|
|
|
|
|
+ nickname: string;
|
|
|
|
|
+ avatarUrl: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 互动数据 */
|
|
|
|
|
+ stats: {
|
|
|
|
|
+ playCount: number;
|
|
|
|
|
+ likeCount: number;
|
|
|
|
|
+ commentCount: number;
|
|
|
|
|
+ shareCount: number;
|
|
|
|
|
+ collectCount: number;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 标签列表 */
|
|
|
|
|
+ hashtags: string[];
|
|
|
|
|
+ /** 音乐信息 */
|
|
|
|
|
+ music: {
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ author: string;
|
|
|
|
|
+ duration: number;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ /** 关联商品(如有) */
|
|
|
|
|
+ products: Array<{
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ price: number | null;
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ imageUrl: string;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ _source: 'tikhub';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanTikTokVideo>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | TikHub 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `itemInfo.itemStruct.id` |
|
|
|
|
|
+| `description` | `itemInfo.itemStruct.desc` |
|
|
|
|
|
+| `coverUrl` | `itemInfo.itemStruct.video.cover` |
|
|
|
|
|
+| `videoUrl` | `itemInfo.itemStruct.video.playAddr` |
|
|
|
|
|
+| `duration` | `itemInfo.itemStruct.video.duration` |
|
|
|
|
|
+| `createdAt` | `itemInfo.itemStruct.createTime` (Unix → ISO) |
|
|
|
|
|
+| `author.id` | `itemInfo.itemStruct.author.id` |
|
|
|
|
|
+| `author.uniqueId` | `itemInfo.itemStruct.author.uniqueId` |
|
|
|
|
|
+| `stats.playCount` | `itemInfo.itemStruct.stats.playCount` |
|
|
|
|
|
+| `stats.likeCount` | `itemInfo.itemStruct.stats.diggCount` |
|
|
|
|
|
+| `stats.commentCount` | `itemInfo.itemStruct.stats.commentCount` |
|
|
|
|
|
+| `stats.shareCount` | `itemInfo.itemStruct.stats.shareCount` |
|
|
|
|
|
+| `stats.collectCount` | `itemInfo.itemStruct.stats.collectCount` |
|
|
|
|
|
+| `hashtags` | `itemInfo.itemStruct.textExtra[].hashtagName` |
|
|
|
|
|
+| `music.id` | `itemInfo.itemStruct.music.id` |
|
|
|
|
|
+| `music.title` | `itemInfo.itemStruct.music.title` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "7300000000000000000",
|
|
|
|
|
+ "description": "Best wireless headphones under $30! #tech #headphones #review",
|
|
|
|
|
+ "coverUrl": "https://p16-sign.tiktokcdn.com/example-cover.jpg",
|
|
|
|
|
+ "videoUrl": "https://v16-webapp.tiktok.com/example-video.mp4",
|
|
|
|
|
+ "duration": 45,
|
|
|
|
|
+ "createdAt": "2025-01-10T15:30:00.000Z",
|
|
|
|
|
+ "author": {
|
|
|
|
|
+ "id": "6890000000000000000",
|
|
|
|
|
+ "uniqueId": "exampleuser",
|
|
|
|
|
+ "nickname": "Example Creator",
|
|
|
|
|
+ "avatarUrl": "https://p16-sign.tiktokcdn.com/example-avatar.jpg"
|
|
|
|
|
+ },
|
|
|
|
|
+ "stats": {
|
|
|
|
|
+ "playCount": 2500000,
|
|
|
|
|
+ "likeCount": 185000,
|
|
|
|
|
+ "commentCount": 3200,
|
|
|
|
|
+ "shareCount": 12000,
|
|
|
|
|
+ "collectCount": 45000
|
|
|
|
|
+ },
|
|
|
|
|
+ "hashtags": ["tech", "headphones", "review"],
|
|
|
|
|
+ "music": {
|
|
|
|
|
+ "id": "7200000000000000000",
|
|
|
|
|
+ "title": "Original Sound",
|
|
|
|
|
+ "author": "exampleuser",
|
|
|
|
|
+ "duration": 45
|
|
|
|
|
+ },
|
|
|
|
|
+ "products": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "PROD001",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "price": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "imageUrl": "https://p16-sign.tiktokcdn.com/product1.jpg"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "_source": "tikhub"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.7.3 `GET /api/clean/tiktok/videos/:id/comments` — 视频评论
|
|
|
|
|
+
|
|
|
|
|
+获取 TikTok 视频评论列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| TikHub | `TikTokVideoApi.getVideoComments` | `GET /api/tikhub/tiktok/video/comments` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = 视频 ID
|
|
|
|
|
+interface TikTokCommentsParams extends PaginationParams {
|
|
|
|
|
+ /** 排序方式 */
|
|
|
|
|
+ sortBy?: 'likes' | 'date';
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanTikTokComment {
|
|
|
|
|
+ /** 评论 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 评论内容 */
|
|
|
|
|
+ content: string;
|
|
|
|
|
+ /** 评论时间 */
|
|
|
|
|
+ createdAt: string;
|
|
|
|
|
+ /** 点赞数 */
|
|
|
|
|
+ likeCount: number;
|
|
|
|
|
+ /** 回复数 */
|
|
|
|
|
+ replyCount: number;
|
|
|
|
|
+ /** 评论者信息 */
|
|
|
|
|
+ author: {
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ uniqueId: string;
|
|
|
|
|
+ nickname: string;
|
|
|
|
|
+ avatarUrl: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ _source: 'tikhub';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanTikTokComment>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | TikHub 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `cid` |
|
|
|
|
|
+| `content` | `text` |
|
|
|
|
|
+| `createdAt` | `create_time` (Unix → ISO) |
|
|
|
|
|
+| `likeCount` | `digg_count` |
|
|
|
|
|
+| `replyCount` | `reply_comment_total` |
|
|
|
|
|
+| `author.id` | `user.uid` |
|
|
|
|
|
+| `author.uniqueId` | `user.unique_id` |
|
|
|
|
|
+| `author.nickname` | `user.nickname` |
|
|
|
|
|
+| `author.avatarUrl` | `user.avatar_thumb` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "7300000000000000001",
|
|
|
|
|
+ "content": "Just bought these, they're amazing!",
|
|
|
|
|
+ "createdAt": "2025-01-10T16:00:00.000Z",
|
|
|
|
|
+ "likeCount": 520,
|
|
|
|
|
+ "replyCount": 12,
|
|
|
|
|
+ "author": {
|
|
|
|
|
+ "id": "6890000000000000001",
|
|
|
|
|
+ "uniqueId": "commenter1",
|
|
|
|
|
+ "nickname": "Happy Buyer",
|
|
|
|
|
+ "avatarUrl": "https://p16-sign.tiktokcdn.com/commenter1.jpg"
|
|
|
|
|
+ },
|
|
|
|
|
+ "_source": "tikhub"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 3200,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.7.4 `GET /api/clean/tiktok/shop/products/:id` — 商品详情
|
|
|
|
|
+
|
|
|
|
|
+获取 TikTok Shop 商品详情。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| TikHub | `TikTokShopApi.getProductDetail` | `GET /api/tikhub/tiktok/shop/product/detail` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = TikTok Shop 商品 ID
|
|
|
|
|
+interface TikTokShopProductParams {
|
|
|
|
|
+ /** 无额外参数 */
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanTikTokShopProduct {
|
|
|
|
|
+ /** 商品 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 商品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 商品描述 */
|
|
|
|
|
+ description: string;
|
|
|
|
|
+ /** 商品图片列表 */
|
|
|
|
|
+ images: string[];
|
|
|
|
|
+ /** 价格 */
|
|
|
|
|
+ price: number;
|
|
|
|
|
+ /** 原价 */
|
|
|
|
|
+ originalPrice: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 销量 */
|
|
|
|
|
+ soldCount: number;
|
|
|
|
|
+ /** 评分 */
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ /** 评论数 */
|
|
|
|
|
+ reviewCount: number | null;
|
|
|
|
|
+ /** 店铺信息 */
|
|
|
|
|
+ shop: {
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ rating: number | null;
|
|
|
|
|
+ followerCount: number;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** SKU 变体 */
|
|
|
|
|
+ skus: Array<{
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ price: number;
|
|
|
|
|
+ stock: number | null;
|
|
|
|
|
+ attributes: Record<string, string>;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 关联视频数 */
|
|
|
|
|
+ videoCount: number;
|
|
|
|
|
+ _source: 'tikhub';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanTikTokShopProduct>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | TikHub 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `product_id` |
|
|
|
|
|
+| `title` | `product_name` |
|
|
|
|
|
+| `description` | `description` |
|
|
|
|
|
+| `images` | `images[].url_list[0]` |
|
|
|
|
|
+| `price` | `price.min_price` / 100 |
|
|
|
|
|
+| `originalPrice` | `price.original_price` / 100 |
|
|
|
|
|
+| `soldCount` | `sold_count` |
|
|
|
|
|
+| `rating` | `star_rating.average` |
|
|
|
|
|
+| `reviewCount` | `star_rating.count` |
|
|
|
|
|
+| `shop.id` | `shop_info.shop_id` |
|
|
|
|
|
+| `shop.name` | `shop_info.shop_name` |
|
|
|
|
|
+| `skus[].id` | `skus[].sku_id` |
|
|
|
|
|
+| `skus[].name` | `skus[].sku_name` |
|
|
|
|
|
+| `skus[].price` | `skus[].price.original_price` / 100 |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "1729000000000000000",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones V5.3",
|
|
|
|
|
+ "description": "Premium wireless headphones with ANC...",
|
|
|
|
|
+ "images": [
|
|
|
|
|
+ "https://p16-oec-ttp.tiktokcdn.com/product1.jpg",
|
|
|
|
|
+ "https://p16-oec-ttp.tiktokcdn.com/product2.jpg"
|
|
|
|
|
+ ],
|
|
|
|
|
+ "price": 25.99,
|
|
|
|
|
+ "originalPrice": 49.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "soldCount": 15800,
|
|
|
|
|
+ "rating": 4.7,
|
|
|
|
|
+ "reviewCount": 2350,
|
|
|
|
|
+ "shop": {
|
|
|
|
|
+ "id": "SHOP001",
|
|
|
|
|
+ "name": "TechGadgets Official",
|
|
|
|
|
+ "rating": 4.8,
|
|
|
|
|
+ "followerCount": 85000
|
|
|
|
|
+ },
|
|
|
|
|
+ "skus": [
|
|
|
|
|
+ { "id": "SKU001", "name": "Black", "price": 25.99, "stock": 500, "attributes": { "color": "Black" } },
|
|
|
|
|
+ { "id": "SKU002", "name": "White", "price": 25.99, "stock": 320, "attributes": { "color": "White" } }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "videoCount": 45,
|
|
|
|
|
+ "_source": "tikhub"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.7.5 `GET /api/clean/tiktok/ads/:id` — 广告详情
|
|
|
|
|
+
|
|
|
|
|
+获取 TikTok 广告详情数据。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| TikHub | `TikTokAdsApi.getAdDetail` | `GET /api/tikhub/tiktok/ads/detail` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = 广告 ID
|
|
|
|
|
+interface TikTokAdParams {
|
|
|
|
|
+ /** 无额外参数 */
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanTikTokAd {
|
|
|
|
|
+ /** 广告 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 广告标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 广告描述 */
|
|
|
|
|
+ description: string;
|
|
|
|
|
+ /** 广告素材 URL */
|
|
|
|
|
+ mediaUrl: string;
|
|
|
|
|
+ /** 素材类型 */
|
|
|
|
|
+ mediaType: 'video' | 'image';
|
|
|
|
|
+ /** 广告主信息 */
|
|
|
|
|
+ advertiser: {
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ region: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 投放时间 */
|
|
|
|
|
+ startDate: string;
|
|
|
|
|
+ endDate: string | null;
|
|
|
|
|
+ /** 投放地区 */
|
|
|
|
|
+ targetRegions: string[];
|
|
|
|
|
+ /** 互动数据 */
|
|
|
|
|
+ stats: {
|
|
|
|
|
+ impressions: number | null;
|
|
|
|
|
+ clicks: number | null;
|
|
|
|
|
+ likeCount: number;
|
|
|
|
|
+ commentCount: number;
|
|
|
|
|
+ shareCount: number;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 落地页 URL */
|
|
|
|
|
+ landingPageUrl: string | null;
|
|
|
|
|
+ /** CTA 按钮文案 */
|
|
|
|
|
+ callToAction: string | null;
|
|
|
|
|
+ _source: 'tikhub';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanTikTokAd>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | TikHub 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `ad_id` |
|
|
|
|
|
+| `title` | `ad_title` |
|
|
|
|
|
+| `description` | `ad_text` |
|
|
|
|
|
+| `mediaUrl` | `video_url` 或 `image_url` |
|
|
|
|
|
+| `mediaType` | 根据素材类型判断 |
|
|
|
|
|
+| `advertiser.id` | `advertiser_id` |
|
|
|
|
|
+| `advertiser.name` | `advertiser_name` |
|
|
|
|
|
+| `advertiser.region` | `advertiser_region` |
|
|
|
|
|
+| `startDate` | `first_shown_date` |
|
|
|
|
|
+| `endDate` | `last_shown_date` |
|
|
|
|
|
+| `targetRegions` | `target_countries[]` |
|
|
|
|
|
+| `stats.likeCount` | `digg_count` |
|
|
|
|
|
+| `stats.commentCount` | `comment_count` |
|
|
|
|
|
+| `stats.shareCount` | `share_count` |
|
|
|
|
|
+| `landingPageUrl` | `landing_page_url` |
|
|
|
|
|
+| `callToAction` | `cta_text` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "AD_001",
|
|
|
|
|
+ "title": "Best Wireless Headphones 2025",
|
|
|
|
|
+ "description": "Experience premium sound quality at an unbeatable price!",
|
|
|
|
|
+ "mediaUrl": "https://v16-webapp.tiktok.com/ad-video.mp4",
|
|
|
|
|
+ "mediaType": "video",
|
|
|
|
|
+ "advertiser": {
|
|
|
|
|
+ "id": "ADV001",
|
|
|
|
|
+ "name": "TechGadgets Inc.",
|
|
|
|
|
+ "region": "US"
|
|
|
|
|
+ },
|
|
|
|
|
+ "startDate": "2025-01-01T00:00:00.000Z",
|
|
|
|
|
+ "endDate": null,
|
|
|
|
|
+ "targetRegions": ["US", "CA", "GB"],
|
|
|
|
|
+ "stats": {
|
|
|
|
|
+ "impressions": null,
|
|
|
|
|
+ "clicks": null,
|
|
|
|
|
+ "likeCount": 8500,
|
|
|
|
|
+ "commentCount": 320,
|
|
|
|
|
+ "shareCount": 1200
|
|
|
|
|
+ },
|
|
|
|
|
+ "landingPageUrl": "https://www.tiktok.com/shop/product/1729000000000000000",
|
|
|
|
|
+ "callToAction": "Shop Now",
|
|
|
|
|
+ "_source": "tikhub"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.8 卖家信息(Amazon)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.8.1 `GET /api/clean/sellers/account` — 卖家账户
|
|
|
|
|
+
|
|
|
|
|
+获取当前卖家的账户信息。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `SellersApi.getMarketplaceParticipations` | `GET /api/amazon/sellers/participations` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface SellerAccountParams {
|
|
|
|
|
+ /** 无额外参数 */
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanSellerAccount {
|
|
|
|
|
+ /** 卖家 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 卖家名称 */
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ /** 账户类型 */
|
|
|
|
|
+ accountType: 'individual' | 'professional';
|
|
|
|
|
+ /** 已开通的市场列表 */
|
|
|
|
|
+ marketplaces: Array<{
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ country: string;
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ isActive: boolean;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 主要市场 */
|
|
|
|
|
+ primaryMarketplace: {
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ country: string;
|
|
|
|
|
+ };
|
|
|
|
|
+ _source: 'amazon';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanSellerAccount>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `participation.sellerId` |
|
|
|
|
|
+| `name` | `marketplace.name` (主市场) |
|
|
|
|
|
+| `marketplaces[].id` | `marketplace.id` |
|
|
|
|
|
+| `marketplaces[].name` | `marketplace.name` |
|
|
|
|
|
+| `marketplaces[].country` | `marketplace.countryCode` |
|
|
|
|
|
+| `marketplaces[].domain` | `marketplace.domainName` |
|
|
|
|
|
+| `marketplaces[].isActive` | `participation.isParticipating` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "A1EXAMPLE",
|
|
|
|
|
+ "name": "ExampleBrand Store",
|
|
|
|
|
+ "accountType": "professional",
|
|
|
|
|
+ "marketplaces": [
|
|
|
|
|
+ { "id": "ATVPDKIKX0DER", "name": "Amazon.com", "country": "US", "domain": "amazon.com", "isActive": true },
|
|
|
|
|
+ { "id": "A2EUQ1WTGCTBG2", "name": "Amazon.ca", "country": "CA", "domain": "amazon.ca", "isActive": true },
|
|
|
|
|
+ { "id": "A1F83G8C2ARO7P", "name": "Amazon.co.uk", "country": "GB", "domain": "amazon.co.uk", "isActive": false }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "primaryMarketplace": {
|
|
|
|
|
+ "id": "ATVPDKIKX0DER",
|
|
|
|
|
+ "name": "Amazon.com",
|
|
|
|
|
+ "country": "US"
|
|
|
|
|
+ },
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.8.2 `GET /api/clean/sellers/marketplaces` — 市场列表
|
|
|
|
|
+
|
|
|
|
|
+获取卖家已开通的市场列表及状态。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `SellersApi.getMarketplaceParticipations` | `GET /api/amazon/sellers/participations` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface MarketplaceListParams {
|
|
|
|
|
+ /** 是否只返回已激活的市场 */
|
|
|
|
|
+ activeOnly?: boolean;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanMarketplace {
|
|
|
|
|
+ /** 市场 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 市场名称 */
|
|
|
|
|
+ name: string;
|
|
|
|
|
+ /** 国家代码 */
|
|
|
|
|
+ country: string;
|
|
|
|
|
+ /** 域名 */
|
|
|
|
|
+ domain: string;
|
|
|
|
|
+ /** 默认语言 */
|
|
|
|
|
+ language: string;
|
|
|
|
|
+ /** 默认货币 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 是否已激活 */
|
|
|
|
|
+ isActive: boolean;
|
|
|
|
|
+ /** 是否有 FBA 服务 */
|
|
|
|
|
+ hasFBA: boolean;
|
|
|
|
|
+ _source: 'amazon';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanMarketplace[]>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `marketplace.id` |
|
|
|
|
|
+| `name` | `marketplace.name` |
|
|
|
|
|
+| `country` | `marketplace.countryCode` |
|
|
|
|
|
+| `domain` | `marketplace.domainName` |
|
|
|
|
|
+| `language` | `marketplace.defaultLanguageCode` |
|
|
|
|
|
+| `currency` | `marketplace.defaultCurrencyCode` |
|
|
|
|
|
+| `isActive` | `participation.isParticipating` |
|
|
|
|
|
+| `hasFBA` | `participation.hasFulfillmentByAmazon` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "ATVPDKIKX0DER",
|
|
|
|
|
+ "name": "Amazon.com",
|
|
|
|
|
+ "country": "US",
|
|
|
|
|
+ "domain": "amazon.com",
|
|
|
|
|
+ "language": "en_US",
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "isActive": true,
|
|
|
|
|
+ "hasFBA": true,
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "A2EUQ1WTGCTBG2",
|
|
|
|
|
+ "name": "Amazon.ca",
|
|
|
|
|
+ "country": "CA",
|
|
|
|
|
+ "domain": "amazon.ca",
|
|
|
|
|
+ "language": "en_CA",
|
|
|
|
|
+ "currency": "CAD",
|
|
|
|
|
+ "isActive": true,
|
|
|
|
|
+ "hasFBA": true,
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 6.9 退货相关(Amazon)
|
|
|
|
|
+
|
|
|
|
|
+#### 6.9.1 `GET /api/clean/returns` — 退货列表
|
|
|
|
|
+
|
|
|
|
|
+获取 Amazon 退货/退款列表。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `FBAReturnsApi.getReturns` | `GET /api/amazon/fba/returns` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface ReturnListParams extends PaginationParams {
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+ /** 退货状态 */
|
|
|
|
|
+ status?: 'pending' | 'approved' | 'completed' | 'rejected';
|
|
|
|
|
+ /** 开始日期 */
|
|
|
|
|
+ startDate?: string;
|
|
|
|
|
+ /** 结束日期 */
|
|
|
|
|
+ endDate?: string;
|
|
|
|
|
+ /** 按 ASIN 筛选 */
|
|
|
|
|
+ asin?: string;
|
|
|
|
|
+ /** 按订单号筛选 */
|
|
|
|
|
+ orderId?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanReturn {
|
|
|
|
|
+ /** 退货 ID */
|
|
|
|
|
+ id: string;
|
|
|
|
|
+ /** 关联订单号 */
|
|
|
|
|
+ orderId: string;
|
|
|
|
|
+ /** ASIN */
|
|
|
|
|
+ asin: string;
|
|
|
|
|
+ /** SKU */
|
|
|
|
|
+ sku: string;
|
|
|
|
|
+ /** 商品标题 */
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ /** 退货数量 */
|
|
|
|
|
+ quantity: number;
|
|
|
|
|
+ /** 退货状态 */
|
|
|
|
|
+ status: string;
|
|
|
|
|
+ /** 退货原因 */
|
|
|
|
|
+ reason: string;
|
|
|
|
|
+ /** 退货原因详情 */
|
|
|
|
|
+ reasonDetail: string | null;
|
|
|
|
|
+ /** 退款金额 */
|
|
|
|
|
+ refundAmount: number | null;
|
|
|
|
|
+ /** 货币代码 */
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ /** 退货发起时间 */
|
|
|
|
|
+ createdAt: string;
|
|
|
|
|
+ /** 退货完成时间 */
|
|
|
|
|
+ completedAt: string | null;
|
|
|
|
|
+ /** 商品状态 */
|
|
|
|
|
+ itemCondition: string | null;
|
|
|
|
|
+ _source: 'amazon';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<PaginatedResponse<CleanReturn>>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**数据映射关系:**
|
|
|
|
|
+
|
|
|
|
|
+| 清洗后字段 | Amazon 原始字段 |
|
|
|
|
|
+|-----------|----------------|
|
|
|
|
|
+| `id` | `returnId` 或 `rmaId` |
|
|
|
|
|
+| `orderId` | `orderId` |
|
|
|
|
|
+| `asin` | `asin` |
|
|
|
|
|
+| `sku` | `sellerSKU` |
|
|
|
|
|
+| `title` | `productName` |
|
|
|
|
|
+| `quantity` | `quantity` |
|
|
|
|
|
+| `status` | `status` |
|
|
|
|
|
+| `reason` | `returnReason` |
|
|
|
|
|
+| `reasonDetail` | `customerComments` |
|
|
|
|
|
+| `refundAmount` | `refundAmount.Amount` |
|
|
|
|
|
+| `currency` | `refundAmount.CurrencyCode` |
|
|
|
|
|
+| `createdAt` | `returnRequestDate` |
|
|
|
|
|
+| `completedAt` | `returnClosedDate` |
|
|
|
|
|
+| `itemCondition` | `itemDisposition` |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "items": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": "RET001",
|
|
|
|
|
+ "orderId": "111-1234567-1234567",
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "sku": "WH-BT-001",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "quantity": 1,
|
|
|
|
|
+ "status": "completed",
|
|
|
|
|
+ "reason": "DEFECTIVE",
|
|
|
|
|
+ "reasonDetail": "Left ear speaker not working",
|
|
|
|
|
+ "refundAmount": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "createdAt": "2025-01-20T10:00:00.000Z",
|
|
|
|
|
+ "completedAt": "2025-01-25T14:30:00.000Z",
|
|
|
|
|
+ "itemCondition": "Damaged",
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "total": 23,
|
|
|
|
|
+ "page": 1,
|
|
|
|
|
+ "pageSize": 20,
|
|
|
|
|
+ "hasMore": true
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+#### 6.9.2 `GET /api/clean/returns/:id` — 退货详情
|
|
|
|
|
+
|
|
|
|
|
+获取单个退货记录的详细信息。
|
|
|
|
|
+
|
|
|
|
|
+**数据来源:**
|
|
|
|
|
+| 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|------|---------|---------|
|
|
|
|
|
+| Amazon | `FBAReturnsApi.getReturnDetail` | `GET /api/amazon/fba/returns/:returnId` |
|
|
|
|
|
+
|
|
|
|
|
+**请求参数:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// URL 参数: id = 退货 ID
|
|
|
|
|
+interface ReturnDetailParams {
|
|
|
|
|
+ marketplaceId?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应数据:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CleanReturnDetail extends CleanReturn {
|
|
|
|
|
+ /** 退货物流信息 */
|
|
|
|
|
+ shipping: {
|
|
|
|
|
+ carrier: string | null;
|
|
|
|
|
+ trackingNumber: string | null;
|
|
|
|
|
+ returnedAt: string | null;
|
|
|
|
|
+ receivedAt: string | null;
|
|
|
|
|
+ };
|
|
|
|
|
+ /** 退款明细 */
|
|
|
|
|
+ refundBreakdown: {
|
|
|
|
|
+ itemPrice: number;
|
|
|
|
|
+ shippingFee: number;
|
|
|
|
|
+ tax: number;
|
|
|
|
|
+ total: number;
|
|
|
|
|
+ currency: string;
|
|
|
|
|
+ } | null;
|
|
|
|
|
+ /** 处理记录 */
|
|
|
|
|
+ timeline: Array<{
|
|
|
|
|
+ date: string;
|
|
|
|
|
+ status: string;
|
|
|
|
|
+ description: string;
|
|
|
|
|
+ }>;
|
|
|
|
|
+ /** 替换订单号(如有) */
|
|
|
|
|
+ replacementOrderId: string | null;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应: ApiResponse<CleanReturnDetail>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例:**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "message": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": "RET001",
|
|
|
|
|
+ "orderId": "111-1234567-1234567",
|
|
|
|
|
+ "asin": "B0EXAMPLE1",
|
|
|
|
|
+ "sku": "WH-BT-001",
|
|
|
|
|
+ "title": "Wireless Bluetooth Headphones",
|
|
|
|
|
+ "quantity": 1,
|
|
|
|
|
+ "status": "completed",
|
|
|
|
|
+ "reason": "DEFECTIVE",
|
|
|
|
|
+ "reasonDetail": "Left ear speaker not working",
|
|
|
|
|
+ "refundAmount": 29.99,
|
|
|
|
|
+ "currency": "USD",
|
|
|
|
|
+ "createdAt": "2025-01-20T10:00:00.000Z",
|
|
|
|
|
+ "completedAt": "2025-01-25T14:30:00.000Z",
|
|
|
|
|
+ "itemCondition": "Damaged",
|
|
|
|
|
+ "shipping": {
|
|
|
|
|
+ "carrier": "UPS",
|
|
|
|
|
+ "trackingNumber": "1Z999AA10123456784",
|
|
|
|
|
+ "returnedAt": "2025-01-22T09:00:00.000Z",
|
|
|
|
|
+ "receivedAt": "2025-01-24T16:00:00.000Z"
|
|
|
|
|
+ },
|
|
|
|
|
+ "refundBreakdown": {
|
|
|
|
|
+ "itemPrice": 29.99,
|
|
|
|
|
+ "shippingFee": 0,
|
|
|
|
|
+ "tax": 2.70,
|
|
|
|
|
+ "total": 32.69,
|
|
|
|
|
+ "currency": "USD"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timeline": [
|
|
|
|
|
+ { "date": "2025-01-20T10:00:00.000Z", "status": "requested", "description": "退货申请已提交" },
|
|
|
|
|
+ { "date": "2025-01-20T10:05:00.000Z", "status": "approved", "description": "退货申请已批准" },
|
|
|
|
|
+ { "date": "2025-01-22T09:00:00.000Z", "status": "shipped", "description": "买家已寄出退货商品" },
|
|
|
|
|
+ { "date": "2025-01-24T16:00:00.000Z", "status": "received", "description": "仓库已收到退货商品" },
|
|
|
|
|
+ { "date": "2025-01-25T14:30:00.000Z", "status": "completed", "description": "退款已处理完成" }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "replacementOrderId": null,
|
|
|
|
|
+ "_source": "amazon"
|
|
|
|
|
+ },
|
|
|
|
|
+ "timestamp": "2025-01-01T12:00:00.000Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 7. 前端调用示例
|
|
|
|
|
+
|
|
|
|
|
+### 7.1 创建统一请求客户端
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
|
|
|
|
+
|
|
|
|
|
+/** 创建清洗接口专用客户端 */
|
|
|
|
|
+const cleanApiClient: AxiosInstance = axios.create({
|
|
|
|
|
+ baseURL: 'https://server-msq.fmode.cn/api/clean',
|
|
|
|
|
+ timeout: 30000,
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ },
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+/** 响应拦截器:统一错误处理 */
|
|
|
|
|
+cleanApiClient.interceptors.response.use(
|
|
|
|
|
+ (response: AxiosResponse<ApiResponse<any>>) => {
|
|
|
|
|
+ const { data } = response;
|
|
|
|
|
+ if (data.code !== 0) {
|
|
|
|
|
+ return Promise.reject(new CleanApiError(data.code, data.message));
|
|
|
|
|
+ }
|
|
|
|
|
+ return response;
|
|
|
|
|
+ },
|
|
|
|
|
+ (error) => {
|
|
|
|
|
+ if (error.response) {
|
|
|
|
|
+ const { data } = error.response;
|
|
|
|
|
+ return Promise.reject(
|
|
|
|
|
+ new CleanApiError(data?.code || error.response.status, data?.message || '请求失败')
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ return Promise.reject(new CleanApiError(50001, '网络连接失败'));
|
|
|
|
|
+ }
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+/** 自定义错误类 */
|
|
|
|
|
+class CleanApiError extends Error {
|
|
|
|
|
+ code: number;
|
|
|
|
|
+ constructor(code: number, message: string) {
|
|
|
|
|
+ super(message);
|
|
|
|
|
+ this.code = code;
|
|
|
|
|
+ this.name = 'CleanApiError';
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export { cleanApiClient, CleanApiError };
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.2 产品相关调用
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { cleanApiClient } from './cleanApiClient';
|
|
|
|
|
+
|
|
|
|
|
+/** 搜索产品 */
|
|
|
|
|
+async function searchProducts(keyword: string, page = 1) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get('/products/search', {
|
|
|
|
|
+ params: { keyword, page, pageSize: 20, source: 'all' },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // PaginatedResponse<CleanProduct>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取产品详情(聚合多平台) */
|
|
|
|
|
+async function getProductDetail(asin: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/products/${asin}`, {
|
|
|
|
|
+ params: { source: 'all', includeTrend: true, trendStartDate: '2024-10-01', trendEndDate: '2025-01-01' },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // CleanProductDetail
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取产品销量数据 */
|
|
|
|
|
+async function getProductSales(asin: string, startDate: string, endDate: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/products/${asin}/sales`, {
|
|
|
|
|
+ params: { startDate, endDate, granularity: 'day', source: 'sorftime' },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // CleanProductSales
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取同类产品 */
|
|
|
|
|
+async function getSimilarProducts(asin: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/products/${asin}/similar`, {
|
|
|
|
|
+ params: { domain: 'amazon.com', page: 1, pageSize: 10 },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // PaginatedResponse<CleanSimilarProduct>
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.3 订单相关调用
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+/** 获取订单列表 */
|
|
|
|
|
+async function getOrders(params: {
|
|
|
|
|
+ status?: string;
|
|
|
|
|
+ createdAfter?: string;
|
|
|
|
|
+ page?: number;
|
|
|
|
|
+}) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get('/orders', {
|
|
|
|
|
+ params: { marketplaceId: 'ATVPDKIKX0DER', pageSize: 20, ...params },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // PaginatedResponse<CleanOrder>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取订单详情 */
|
|
|
|
|
+async function getOrderDetail(orderId: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/orders/${orderId}`);
|
|
|
|
|
+ return data.data; // CleanOrderDetail
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取订单统计 */
|
|
|
|
|
+async function getOrderMetrics(startDate: string, endDate: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get('/orders/metrics', {
|
|
|
|
|
+ params: {
|
|
|
|
|
+ marketplaceId: 'ATVPDKIKX0DER',
|
|
|
|
|
+ granularity: 'week',
|
|
|
|
|
+ startDate,
|
|
|
|
|
+ endDate,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // CleanOrderMetrics
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.4 关键词相关调用
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+/** 搜索关键词 */
|
|
|
|
|
+async function searchKeywords(keyword: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get('/keywords/search', {
|
|
|
|
|
+ params: { keyword, domain: 'amazon.com', matchType: 'broad', page: 1, pageSize: 20 },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // PaginatedResponse<CleanKeyword>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** ASIN 反查关键词 */
|
|
|
|
|
+async function getReverseKeywords(asin: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/keywords/reverse/${asin}`, {
|
|
|
|
|
+ params: { domain: 'amazon.com', sortBy: 'searchVolume', sortOrder: 'desc' },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // PaginatedResponse<CleanReverseKeyword>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取关键词趋势 */
|
|
|
|
|
+async function getKeywordTrend(keyword: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/keywords/${encodeURIComponent(keyword)}/trend`, {
|
|
|
|
|
+ params: { domain: 'amazon.com', period: '12m', granularity: 'month' },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // CleanKeywordTrend
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.5 TikTok 相关调用
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+/** 获取 TikTok 用户资料 */
|
|
|
|
|
+async function getTikTokUser(uniqueId: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/tiktok/users/${uniqueId}`);
|
|
|
|
|
+ return data.data; // CleanTikTokUser
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取 TikTok 视频详情 */
|
|
|
|
|
+async function getTikTokVideo(videoId: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/tiktok/videos/${videoId}`);
|
|
|
|
|
+ return data.data; // CleanTikTokVideo
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取 TikTok 视频评论 */
|
|
|
|
|
+async function getTikTokComments(videoId: string, page = 1) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/tiktok/videos/${videoId}/comments`, {
|
|
|
|
|
+ params: { page, pageSize: 20, sortBy: 'likes' },
|
|
|
|
|
+ });
|
|
|
|
|
+ return data.data; // PaginatedResponse<CleanTikTokComment>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 获取 TikTok Shop 商品详情 */
|
|
|
|
|
+async function getTikTokShopProduct(productId: string) {
|
|
|
|
|
+ const { data } = await cleanApiClient.get(`/tiktok/shop/products/${productId}`);
|
|
|
|
|
+ return data.data; // CleanTikTokShopProduct
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.6 错误处理最佳实践
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { CleanApiError } from './cleanApiClient';
|
|
|
|
|
+
|
|
|
|
|
+async function fetchWithErrorHandling() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const products = await searchProducts('wireless headphones');
|
|
|
|
|
+ console.log('产品列表:', products.items);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ if (error instanceof CleanApiError) {
|
|
|
|
|
+ switch (error.code) {
|
|
|
|
|
+ case 40001:
|
|
|
|
|
+ console.error('参数错误:', error.message);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 40101:
|
|
|
|
|
+ case 40102:
|
|
|
|
|
+ console.error('认证失败,请重新登录');
|
|
|
|
|
+ // 跳转登录页
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 42901:
|
|
|
|
|
+ console.error('请求过于频繁,请稍后重试');
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 50002:
|
|
|
|
|
+ case 50003:
|
|
|
|
|
+ case 50004:
|
|
|
|
|
+ console.error('上游服务异常:', error.message);
|
|
|
|
|
+ // 显示降级提示
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ console.error('未知错误:', error.code, error.message);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.error('网络错误:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 附录:数据来源映射总表
|
|
|
|
|
+
|
|
|
|
|
+以下表格汇总了所有 `/api/clean/` 接口与原始平台接口的对应关系:
|
|
|
|
|
+
|
|
|
|
|
+| 清洗接口 | 方法 | 平台 | 原始接口 | 原始路由 |
|
|
|
|
|
+|---------|------|------|---------|---------|
|
|
|
|
|
+| `/api/clean/products/search` | GET | Amazon | `CatalogItemsApi.searchCatalogItems` | `GET /api/amazon/catalog/items` |
|
|
|
|
|
+| `/api/clean/products/search` | GET | Sorftime | `ProductApi.getProductQuery` | `POST /api/sorftime/forward` → `/api/ProductQuery` |
|
|
|
|
|
+| `/api/clean/products/:id` | GET | Amazon | `CatalogItemsApi.getCatalogItem` | `GET /api/amazon/catalog/items/:asin` |
|
|
|
|
|
+| `/api/clean/products/:id` | GET | Sorftime | `ProductApi.getProductRequest` | `POST /api/sorftime/forward` → `/api/ProductRequest` |
|
|
|
|
|
+| `/api/clean/products/:id/sales` | GET | Amazon | `SalesApi.getOrderMetrics` | `GET /api/amazon/sales/orderMetrics` |
|
|
|
|
|
+| `/api/clean/products/:id/sales` | GET | Sorftime | `ProductApi.getAsinSalesVolume` | `POST /api/sorftime/forward` → `/api/AsinSalesVolume` |
|
|
|
|
|
+| `/api/clean/products/:id/reviews` | GET | Amazon | `SellersApi.getCustomerFeedback` | `GET /api/amazon/sellers/feedback` |
|
|
|
|
|
+| `/api/clean/products/:id/reviews` | GET | Sorftime | `ProductApi.getProductReviewsQuery` | `POST /api/sorftime/forward` → `/api/ProductReviewsQuery` |
|
|
|
|
|
+| `/api/clean/products/:id/similar` | GET | Sorftime | `ProductApi.getSimilarProductRealtime` | `POST /api/sorftime/forward` → `/api/SimilarProductRealtimeRequest` |
|
|
|
|
|
+| `/api/clean/orders` | GET | Amazon | `OrdersApi.getOrders` | `GET /api/amazon/orders` |
|
|
|
|
|
+| `/api/clean/orders/:id` | GET | Amazon | `OrdersApi.getOrder` + `getOrderItems` | `GET /api/amazon/orders/:orderId` + `/items` |
|
|
|
|
|
+| `/api/clean/orders/metrics` | GET | Amazon | `SalesApi.getOrderMetrics` | `GET /api/amazon/sales/orderMetrics` |
|
|
|
|
|
+| `/api/clean/listings` | GET | Amazon | `ListingsApi.getListingsItems` | `GET /api/amazon/listings` |
|
|
|
|
|
+| `/api/clean/listings/:sku` | GET | Amazon | `ListingsApi.getListingsItem` | `GET /api/amazon/listings/:sku` |
|
|
|
|
|
+| `/api/clean/categories/tree` | GET | Sorftime | `CategoryApi.getCategoryTree` | `POST /api/sorftime/forward` → `/api/CategoryTree` |
|
|
|
|
|
+| `/api/clean/categories/:id/products` | GET | Sorftime | `CategoryApi.getCategoryProducts` | `POST /api/sorftime/forward` → `/api/CategoryProducts` |
|
|
|
|
|
+| `/api/clean/categories/:id/keywords` | GET | Sorftime | `CategoryApi.getCategoryKeywords` | `POST /api/sorftime/forward` → `/api/CategoryKeywords` |
|
|
|
|
|
+| `/api/clean/keywords/search` | GET | Sorftime | `KeywordApi.getKeywordSearch` | `POST /api/sorftime/forward` → `/api/KeywordSearch` |
|
|
|
|
|
+| `/api/clean/keywords/:keyword/products` | GET | Sorftime | `KeywordApi.getKeywordProducts` | `POST /api/sorftime/forward` → `/api/KeywordProducts` |
|
|
|
|
|
+| `/api/clean/keywords/reverse/:asin` | GET | Sorftime | `KeywordApi.getReverseAsin` | `POST /api/sorftime/forward` → `/api/ReverseAsin` |
|
|
|
|
|
+| `/api/clean/keywords/:keyword/trend` | GET | Sorftime | `KeywordApi.getKeywordTrend` | `POST /api/sorftime/forward` → `/api/KeywordTrend` |
|
|
|
|
|
+| `/api/clean/monitoring/bestseller/subscribe` | POST | Sorftime | `MonitorApi.subscribeBestSeller` | `POST /api/sorftime/forward` → `/api/BestSellerSubscribe` |
|
|
|
|
|
+| `/api/clean/monitoring/bestseller/tasks` | GET | Sorftime | `MonitorApi.getBestSellerTasks` | `POST /api/sorftime/forward` → `/api/BestSellerTasks` |
|
|
|
|
|
+| `/api/clean/monitoring/asin/subscribe` | POST | Sorftime | `MonitorApi.subscribeAsin` | `POST /api/sorftime/forward` → `/api/AsinSubscribe` |
|
|
|
|
|
+| `/api/clean/tiktok/users/:uniqueId` | GET | TikHub | `TikTokUserApi.getUserProfile` | `GET /api/tikhub/tiktok/user/profile` |
|
|
|
|
|
+| `/api/clean/tiktok/videos/:id` | GET | TikHub | `TikTokVideoApi.getVideoDetail` | `GET /api/tikhub/tiktok/video/detail` |
|
|
|
|
|
+| `/api/clean/tiktok/videos/:id/comments` | GET | TikHub | `TikTokVideoApi.getVideoComments` | `GET /api/tikhub/tiktok/video/comments` |
|
|
|
|
|
+| `/api/clean/tiktok/shop/products/:id` | GET | TikHub | `TikTokShopApi.getProductDetail` | `GET /api/tikhub/tiktok/shop/product/detail` |
|
|
|
|
|
+| `/api/clean/tiktok/ads/:id` | GET | TikHub | `TikTokAdsApi.getAdDetail` | `GET /api/tikhub/tiktok/ads/detail` |
|
|
|
|
|
+| `/api/clean/sellers/account` | GET | Amazon | `SellersApi.getMarketplaceParticipations` | `GET /api/amazon/sellers/participations` |
|
|
|
|
|
+| `/api/clean/sellers/marketplaces` | GET | Amazon | `SellersApi.getMarketplaceParticipations` | `GET /api/amazon/sellers/participations` |
|
|
|
|
|
+| `/api/clean/returns` | GET | Amazon | `FBAReturnsApi.getReturns` | `GET /api/amazon/fba/returns` |
|
|
|
|
|
+| `/api/clean/returns/:id` | GET | Amazon | `FBAReturnsApi.getReturnDetail` | `GET /api/amazon/fba/returns/:returnId` |
|