# 供应商画像

> 运营后台供应商列表/详情右侧抽屉：基础信息与标签编辑、经营概览与履约售后（近7/30天环比）、处罚明细、品类看板及明细、统计口径文案

- 类型：前端对接
- 分类：供应商
- 端：运营后台
- 后端服务：admin
- 状态：已上测
- 测试分支：bulky-test/admin
- 更新：2026-10-28
- 网页版：https://doc.xfun.fun/supplier-profile-api

## 总览

交互以原型 `供应商画像-V1.1.html` 为准。所有接口在运营后台服务（admin）下，需登录 token。

| \# | 接口 | 用途 | 何时调 |
|----|----|----|----|
| ① | `POST /supplier/profile/base` | 头部基础信息 + 标签 | 打开抽屉；保存标签后可用 ⑦ 的返回直接刷新 |
| ② | `POST /supplier/profile/metrics` | 经营概览 + 履约与售后（**7 天、30 天一次返回**） | 打开抽屉 |
| ③ | `POST /supplier/profile/punishPage` | 处罚明细弹窗（分页） | 点「查看明细」/翻页 |
| ④ | `POST /supplier/profile/category` | 品类数据（主营/优选/品质优选）Top3、在售主力花材 Top3、增长最快品类 Top3 | 打开抽屉 |
| ⑤ | `POST /supplier/profile/categoryPage` | 品类数据明细 / 在售主力花材明细弹窗（排序 + 分页） | 点「查看明细」/切换/排序/翻页 |
| ⑥ | `POST /purchaser/userTag/list`（已有） | 系统标签库 | 打开「编辑标签」弹窗 |
| ⑦ | `POST /supplier/profile/tagSave` | 保存标签（已有标签 + 新建标签一次提交） | 点「保存标签」 |

## 通用约定

- 全部 `POST` + JSON，返回 `{ "code": 0, "msg": "success", "data": … }`；`code != 0` 时 `msg` 直接 toast。
- **数据截至**：所有统计截至 **昨天**（今天的场次不算），用出参 `statDate` 展示「数据截至 2026.10.25」。
- **统计窗口**：近 N 天 = `[statDate-N+1, statDate]`；上 N 天 = 紧挨着的前 N 天，不重叠。按 **场次日期**统计。
- 统计数据后端按天缓存，当天内重复打开数字不变（标签、处罚明细不缓存）。
- 金额单位 **元**；比率字段单位为 **%**，后端保留 2 位，**前端展示 1 位**；扎数为整数（JSON 数字）。
- 时间格式 `yyyy-MM-dd HH:mm:ss`，日期 `yyyy-MM-dd`。
- 分页出参统一为 `{ index, size, total, records }`；入参用 `pageNum`，`pageSize` 固定 10（可不传）。

## 加载时序

点「画像」 → 并发 ① base + ② metrics + ④ category → 7/30 天切换：纯前端切 ② 的 `"7"`/ `"30"`，默认近 7 天

「处罚次数 · 查看明细」 → ③ `period` = 当前履约卡片选中的 7/30

「品类数据 · 查看明细」 → ⑤ `viewType` = 当前分段（main/prefer/quality） → 「在售主力花材 · 查看明细」 → ⑤ `viewType=active`

「编辑标签」 → ⑥ 拉标签库（过滤 type=2） → 前端维护草稿 → 「保存标签」调 ⑦

## 枚举

#### 标签分类 tagCategory（按分类显示不同颜色徽标）

| code         | 名称     | 原型样式类                               |
|--------------|----------|------------------------------------------|
| `risk`       | 风险预警 | `sp-tag-risk`                            |
| `attention`  | 需关注   | `sp-tag-attention`                       |
| `action`     | 需行动   | `sp-tag-action`                          |
| `profile`    | 客户画像 | `sp-tag-profile`                         |
| `preference` | 偏好标签 | `sp-tag-preference`                      |
| `promotion`  | 推广属性 | `sp-tag-promotion`                       |
| `other`      | 其他     | `sp-tag-other`（未知 code 也按其他显示） |

#### 合作状态 cooperateStatus

直接展示 `cooperateStatusName` 即可：0 未认证 / 1 待审核 / 2 正常 / 3 审核不通过 / 4 已清退 / 5 已冻结 / -100 已删除。

#### 品类视图 viewType

`main` 主营品类 · `prefer` 优选 · `quality` 品质优选 · `active` 在售主力花材

#### 等级 rankNum

1~6 对应 A/B/C/D/E/O，可拼在商品名后（如「红玫瑰 A级」）。

## 接口

### POST /supplier/profile/base · 基础信息与标签

#### 入参

```json
{ "supplierId": 10002 }
```

#### 出参 data

| 字段 | 类型 | 说明 |
|----|----|----|
| `statDate` | date | 数据截至日（昨天） |
| `supplierId` / `supplierName` | long / string | 供应商 ID / 名称 |
| `loginTel` | string | 手机号 |
| `cooperateStatus` / `cooperateStatusName` | int / string | 合作状态，见枚举 |
| `enterTime` | datetime | 入驻时间（审核通过时间，无则注册时间），展示到日期 |
| `lastSellTime` | datetime \| null | 最近动销时间；null 显示「—」 |
| `tagList[]` | array | 全部标签（≤ 8 个）：`tagId`、`tagName`、`tagCategory` |

```json
{
  "statDate": "2026-10-25", "supplierId": 10002, "supplierName": "云岭花卉合作社",
  "loginTel": "18756300314", "cooperateStatus": 2, "cooperateStatusName": "正常",
  "enterTime": "2024-03-18 10:00:00", "lastSellTime": "2026-10-25 14:26:00",
  "tagList": [ { "supplierId": 10002, "tagId": 1, "tagName": "玫瑰主供", "tagCategory": "profile" } ]
}
```

### POST /supplier/profile/metrics · 经营概览 + 履约与售后

#### 入参

```json
{ "supplierId": 10002 }
```

#### 出参结构

`business`、`service` 都是以 **"7"**、**"30"**（字符串）为 key 的对象。带环比的指标统一为 **指标对象**：

| 指标对象字段 | 说明 |
|----|----|
| `current` | 近 N 天值 |
| `previous` | 上 N 天值（展示「上N天xx」） |
| `delta` | 环比。**数量/金额类**：百分比（%）；**比率类**：百分点差。`previous=0` 的数量/金额类为 `null`，显示「—」 |

#### business\["7" \| "30"\]（经营概览）

| 字段         | 页面文案      | 单位 | delta 类型 |
|--------------|---------------|------|------------|
| `sellDays`   | 近N天动销天数 | 天   | %          |
| `sellNum`    | 近N天销售扎数 | 扎   | %          |
| `sellAmount` | 近N天销售金额 | 元   | %          |

#### service\["7" \| "30"\]（履约与售后）

| 字段 | 页面文案 | 类型 | 说明 |
|----|----|----|----|
| `afterSaleAmount` | 近N天售后金额 | 指标对象 | 元；delta 为 % |
| `afterSaleRate` | 近N天售后率 | 指标对象 | %；delta 为 **百分点**（「↑ 0.3 个百分点」） |
| `afterSaleNum` / `afterSaleCount` | 售后率下方「· 1,459 扎 / 86 单」 | number | 近 N 天售后扎数 / 售后单数（无环比） |
| `lackRate` | 近N天缺货率 | 指标对象 | %；delta 为百分点 |
| `lowerRankRate` | 近N天降级率 | 指标对象 | %；delta 为百分点 |
| `punishCount` | 近N天处罚次数 | number | 无环比；旁边「查看明细」 |

#### 顶层

`statDate` 数据截至日；`totalPunishCount` 历史累计处罚次数（不随 7/30 变化）。

```json
{
  "statDate": "2026-10-25",
  "business": {
    "7":  { "sellDays": { "current": 6, "previous": 5, "delta": 20.0 },
            "sellNum":  { "current": 9200, "previous": 8100, "delta": 13.6 },
            "sellAmount": { "current": 138000.00, "previous": 123000.00, "delta": 12.2 } },
    "30": { ... }
  },
  "service": {
    "7":  { "afterSaleAmount": { "current": 4680.00, "previous": 4440.00, "delta": 5.4 },
            "afterSaleRate":   { "current": 2.70, "previous": 2.90, "delta": -0.2 },
            "afterSaleNum": 320, "afterSaleCount": 19,
            "lackRate":      { "current": 0.90, "previous": 1.20, "delta": -0.3 },
            "lowerRankRate": { "current": 0.60, "previous": 0.80, "delta": -0.2 },
            "punishCount": 4 },
    "30": { ... }
  },
  "totalPunishCount": 27
}
```

### POST /supplier/profile/punishPage · 处罚明细

#### 入参

| 字段         | 必填 | 说明                                                 |
|--------------|------|------------------------------------------------------|
| `supplierId` | 是   |                                                      |
| `period`     | 否   | 只允许 `7` / `30`，默认 30；传履约卡片当前选中的周期 |
| `pageNum`    | 否   | 默认 1                                               |
| `pageSize`   | 否   | 固定 10，传其他值会报错                              |

#### records\[\]（按处罚时间倒序）

| 字段 | 说明 | 页面列 |
|----|----|----|
| `punishTypeName` | 处罚类型名称 | 处罚类型 |
| `punishTime` | 处罚时间 | 处罚时间（左对齐） |
| `punishPrice` | 处罚金额（元） | 处罚金额（左对齐） |
| `id` / `punishType` / `roundNo` / `orderSn` / `remark` | 处罚 ID / 类型 code / 场次 / 订单号 / 处罚描述 | 原型未展示，按需使用 |

```json
{ "index": 1, "size": 10, "total": 16, "records": [
  { "id": 1, "punishType": 1, "punishTypeName": "缺货处罚", "punishTime": "2026-10-18 09:32:00",
    "punishPrice": 800.00, "roundNo": "2026-10-18", "orderSn": "...", "remark": "..." } ] }
```

`total` 与指标里的 `punishCount`（同周期）一致；弹窗副标题「共 N 条 · 每页 10 条」用 `total`。

### POST /supplier/profile/category · 品类看板

#### 入参

```json
{ "supplierId": 10002 }
```

#### 出参 data

| 字段 | 说明 |
|----|----|
| `main` / `prefer` / `quality` | 品类数据三个分段的 Top3（近30天销售扎数降序），元素为 **商品对象** |
| `active` | 在售主力花材 Top3（近7天销售扎数降序）；其中 `sellNum` 为 **近7天**，`afterSaleRate` 为近30天 |
| `growth[]` | 增长最快品类 Top3（按 `diffNum` 降序，**含负增长**；近 14 天有销量的品类不足 3 个时不足 3 条）：`secondId`、`secondName` 品类名、`recentNum` 近7天、`previousNum` 上7天、`diffNum` 扎数差 |
| `mainTotal` / `preferTotal` / `qualityTotal` / `activeTotal` | 各视图完整条数（明细弹窗「共 N 个品类」也可直接用 ⑤ 的 total） |
| `statDate` | 数据截至日 |

#### 商品对象（④ ⑤ 共用）

| 字段 | 说明 |
|----|----|
| `productId` | 商品 ID |
| `productName` / `rankNum` | 商品名称 / 等级 |
| `sellNum` | 销售扎数（main/prefer/quality 近30天；active 近7天） |
| `afterSaleRate` | 近30天售后率（%） |
| `preferFlag` / `qualityFlag` | 当前是否优选 / 品质优选（1 是） |

```json
{
  "statDate": "2026-10-25",
  "main": [ { "productId": 1, "productName": "红玫瑰", "rankNum": 1, "sellNum": 12800, "afterSaleRate": 2.60, "preferFlag": 1, "qualityFlag": 0 } ],
  "prefer": [ ... ], "quality": [ ... ], "active": [ ... ],
  "growth": [ { "secondId": 9, "secondName": "绣球", "recentNum": 1760, "previousNum": 980, "diffNum": 780 } ],
  "mainTotal": 8, "preferTotal": 6, "qualityTotal": 6, "activeTotal": 6
}
```

### POST /supplier/profile/categoryPage · 品类明细

#### 入参

| 字段 | 必填 | 说明 |
|----|----|----|
| `supplierId` | 是 |  |
| `viewType` | 否 | `main`（默认）/ `prefer` / `quality` / `active` |
| `sortBy` | 否 | `sales` 按销售扎数（默认）/ `afterSaleRate` 按售后率；均为降序 |
| `pageNum` / `pageSize` | 否 | 同 ③，pageSize 固定 10 |

#### 出参

`{ index, size, total, records: [商品对象] }`。`sortBy=sales` 时第 1 页前 3 条与 ④ 的 Top3 一致。

### POST /purchaser/userTag/list · 系统标签库（已有接口）

无入参。返回全部标签 `[{ id, type, tagCategory, name }]`，**前端过滤 `type == 2`（供应商标签）**。

### POST /supplier/profile/tagSave · 保存标签

#### 入参

| 字段 | 必填 | 说明 |
|----|----|----|
| `supplierId` | 是 |  |
| `tagIdList` | 是 | 保存后该供应商的 **全部**已有标签 id（从标签库选的 + 原来保留的）；传 `[]` 表示清空 |
| `newTagList` | 否 | 手动新增的标签 `[{ name, tagCategory }]`；name 去首尾空格后 1~5 个字，tagCategory 必选 |

```json
{
  "supplierId": 10002,
  "tagIdList": [1, 5, 9],
  "newTagList": [ { "name": "冷链配送", "tagCategory": "other" } ]
}
```

#### 出参

供应商对象，取 `supplierTagList[]`（`tagId`、`tagName`、`tagCategory`）刷新抽屉头部标签。

#### 规则

- 覆盖式保存：请求里没有的旧标签会被移除。
- 合计最多 8 个（`tagIdList` + 新标签，去重后）。
- 新标签保存后自动进入系统标签库，下次打开 ⑥ 就能选到。
- 新标签名与库里已有的供应商标签同名时，**直接复用已有标签**（分类以库里为准），不会重复建。
- 只有点「保存标签」才调接口；编辑弹窗内的增删都是前端草稿。

#### 错误文案（直接 toast）

「每个供应商最多 8 个标签」「标签名称最多 5 个字」「标签名称不能为空」「请选择标签分类」「标签不存在或不是供应商标签:{id}」；5 秒内重复提交会报重复提交。

## 展示规则

- **抽屉标签**：最多显示 7 个，超出显示 `+N`（N = 总数 − 7）；无标签显示「暂无标签」；颜色按 `tagCategory`。
- **编辑标签弹窗**：提示「当前供应商已配置标签」「保存后生效」；草稿满 8 个时禁用标签库按钮和新增输入。
- **环比箭头**：`delta > 0` ↑、`< 0` ↓、`= 0` 持平；数量/金额类显示「↑ 11.0%」，比率类显示「↑ 0.3 个百分点」；`null` 显示「—」。涨跌配色由前端定（售后率、缺货率、降级率上涨应用警示色）。
- **7/30 切换**：经营概览、履约与售后两张卡片各自独立切换，默认 **近 7 天**；切换不请求接口。文案里的「近N天/上N天」随之变化（原型顶部固定写「近 30 天 对比上 30 天」的那一行请跟着切换或去掉）。
- **处罚明细弹窗**：标题「近N天处罚明细」，副标题「共 total 条 · 每页 10 条」，提示「处罚记录按处罚时间倒序展示」；高度按满页 10 行固定；处罚时间、金额左对齐。
- **品类数据卡片**：分段 主营品类 / 优选 / 品质优选；优选视图商品名后加「优选」徽标，品质优选视图加「品质优选」徽标，主营不加。
- **品类数据明细弹窗**：标题「品类数据明细」，弹窗内同样三段切换（切换时 `pageNum` 重置为 1，保持当前排序）；排序按钮「按近30天销售扎数」「按售后率」；高度固定，切换不跳动。
- **在售主力花材明细**：标题「在售主力花材明细」，无三段切换，`viewType=active`，排序按钮「按近7天销售扎数」「按售后率」。
- 数字千分位：扎数、金额前端格式化（`12,800 扎`、`¥729,300`）。

## 「统计口径」弹窗文案

抽屉右上角「统计口径」入口，静态文案（与后端实现一致，可直接使用）：

| 指标 | 口径 |
|----|----|
| 动销天数 | 统计周期内有交易的场次数 |
| 销售扎数 | 同供应商列表/详情「近30天销售扎数」口径（已付款、已发货、已完成订单的花材扎数） |
| 销售金额 | 统计周期内供货金额（以供货价计算） |
| 售后金额 | 统计周期内已发货订单产生的售后中，供应商承担的部分 |
| 售后率 | 售后金额 / 销售金额 |
| 缺货率 / 降级率 | 按花材数量统计：缺货或降级扎数 / 统计周期内销售扎数 |
| 处罚次数 | 统计处罚类型：缺货处罚、迟到处罚、城市仓处罚、换货未换、缺货补货、缺货不补、退货不补、退货补货、退货转代卖处罚、退货补货转代卖处罚、降一级处罚、降二级处罚、超时转代卖、迟到未配货、配错货处罚、其它 |
| 品类数据 | 主营品类：按近30天销售扎数排序，看板展示前 3，弹窗查看更多；优选：当前是优选的商品；品质优选：当前是品质优选的商品 |
| 在售主力花材 | 当前上架的商品，按近7天销售扎数排序，看板展示前 3，弹窗查看更多 |
| 增长最快品类 | 以 7 天为周期每天滚动，比较品种（不分等级）近 7 天与上 7 天的销售扎数，取增量最大的 3 个；没有增长的品类时也展示，增量为负数 |

统计周期均以昨天为截止日，今天的场次不计入。

## 联调注意

- 测试环境：运营后台测试服（bulky-test/admin），接口已部署，可直接联调。
- 测试库很多供应商近 60 天没有订单，指标会全是 0、`delta` 为 `null`、品类列表为空——属正常，请用近期有下单的供应商联调；空态请按原型做好「暂无数据」。
- 统计接口当天有缓存：测试同学当天补的订单/处罚，指标次日才变化；处罚明细（③）和标签（①⑦）是实时的，所以当天新增的处罚可能出现「明细条数 \> 指标次数」，次日恢复一致。
- `business`/ `service` 的 key 是字符串 `"7"`、`"30"`，不是数字下标。
- 比率字段后端 2 位小数（如 `2.70`），展示时 `toFixed(1)`。

> [!WARNING]
> 供应商不存在时 ①~⑤ 返回 `code != 0`（供应商不存在），toast 后关闭抽屉即可。
