Files
atlas-seller-kit/docs/integrations/ozon-seller-api/02-category-tree.md
T
2026-09-20 15:23:44 +08:00

259 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 类目树查询 API
> 官方文档:https://docs.ozon.ru/api/seller/zh/#operation/DescriptionCategoryAPI_GetTree
---
## 接口信息
| 项 | 值 |
|---|---|
| 方法 | POST |
| 路径 | `/v1/description-category/tree` |
| 鉴权 | 需要 `Client-Id` + `Api-Key` |
| 用途 | 获取 Ozon 商品类目树(选择类目后才能发布商品) |
---
## 请求
### 请求体
```json
{
"language": "RU"
}
```
### 参数说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| language | string | 可选 | 语言代码:`DEFAULT`(默认俄文)、`RU`(俄文)、`EN`(英文)、`TR`(土耳其文)、`ZH_HANS`(简体中文) |
---
## 响应
### 成功响应(200)
```json
{
"result": [
{
"description_category_id": 17000001,
"category_name": "Дом и сад",
"type_id": 0,
"type_name": "",
"disabled": true,
"children": [
{
"description_category_id": 17000002,
"category_name": "Сувениры и подарки",
"type_id": 0,
"type_name": "",
"disabled": true,
"children": [
{
"description_category_id": 17032010,
"category_name": "Копилки",
"type_id": 93770,
"type_name": "Копилка",
"disabled": false,
"children": []
}
]
}
]
}
]
}
```
### 字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| description_category_id | integer | **类目 ID**(发布商品时必填) |
| category_name | string | 类目名称 |
| type_id | integer | **商品类型 ID**(发布商品时必填,与 category_id 配对) |
| type_name | string | 商品类型名称 |
| disabled | boolean | **是否可建品**。`true` = 当前节点不可用于建品;`false` = 可用于建品(通常是末级类目) |
| children | array | 子类目(递归结构) |
> **类型叶子例外**:Ozon 的最后一层可能只返回 `type_name`、`type_id`、`disabled` 和空 `children`,而不重复返回 `description_category_id`、`category_name`。此时它属于最近的父类目:缓存时应继承父类目的类目 ID,展示名称使用 `type_name`,发布时使用“父类目 `description_category_id` + 叶子 `type_id`”。
---
## 关键约束
1. **只有可发布的末级类目可建品**:选择结果必须是没有 `children` 且 `disabled=false` 的节点
2. **必须配对使用**:发布时需同时提供 `description_category_id` + `type_id`
3. **层级结构**:`children` 是递归结构,类目可有三级或更深层级;不能假定只有两层,也不能只展开一层
---
## 使用场景
### 场景 1:前端类目选择器
```
① 请求类目树(language=RU,给俄文用户看)
② 递归展开树形结构
③ 所有有子节点的目录都保持可展开;不要把目录节点映射为组件的 disabled
④ 仅允许选择没有子节点且 disabled=false 的节点
⑤ 选中后保存 description_category_id + type_id
```
### 场景 2:Atlas 平台级参考缓存(目标架构,未实施)
```
① 按平台的定时任务用 Atlas 专用参考源凭据拉取完整类目树(Ozon 首期 `ZH_HANS`)
② 原子更新该平台共享目录;同平台门店读取同一份树,不建门店覆盖层
③ 同步失败保留上次成功版本,由后台任务重试并告警
④ 用户选类目时只查 Atlas 缓存,不频繁调 Ozon API
```
---
## 示例代码
### Python(服务端缓存)
```python
import httpx
from typing import List, Dict, Any
async def fetch_category_tree(
client_id: str,
api_key: str,
language: str = "DEFAULT"
) -> List[Dict[str, Any]]:
"""拉取类目树并返回扁平化列表"""
headers = {
"Client-Id": client_id,
"Api-Key": api_key,
"Content-Type": "application/json"
}
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post(
"https://api-seller.ozon.ru/v1/description-category/tree",
headers=headers,
json={"language": language}
)
resp.raise_for_status()
data = resp.json()
# 递归扁平化;不要限制层级数。
def flatten(nodes: List[Dict], level: int = 0, parent_id: int = 0):
flat = []
for node in nodes:
flat.append({
"description_category_id": node["description_category_id"],
"parent_id": parent_id,
"category_name": node["category_name"],
"type_id": node["type_id"],
"type_name": node["type_name"],
"disabled": node["disabled"],
"level": level,
"lang": language
})
if node.get("children"):
flat.extend(flatten(
node["children"],
level + 1,
node["description_category_id"]
))
return flat
return flatten(data.get("result", []))
```
### TypeScript(前端选择器)
> 以下嵌套 `CategoryNode` 和 `/api/categories/tree` 是早期资料中的概念示例,不是当前 Atlas 联调契约。当前商品编辑器从 `GET /api/product-platform-profiles/{profile_id}/category-options` 读取带 `parent_id` 的平台级扁平节点,再在前端重建树;请以[商品编辑与发布 API](../../api/product-editor-and-publishing.md)为准。
```typescript
interface CategoryNode {
description_category_id: number;
category_name: string;
type_id: number;
type_name: string;
disabled: boolean;
children: CategoryNode[];
}
async function fetchCategoryTree(language = 'RU'): Promise<CategoryNode[]> {
const resp = await fetch('/api/categories/tree?lang=' + language);
const data = await resp.json();
return data.result;
}
// 转为 antd Cascader 数据结构。目录永远不能设为 disabled,
// 否则用户无法继续展开到下一级。
function toTreeData(nodes: CategoryNode[]): any[] {
return nodes.map(node => {
const hasChildren = node.children.length > 0;
return {
value: `${node.description_category_id}-${node.type_id}`,
label: node.category_name,
isLeaf: !hasChildren,
// 仅不可发布的叶子不可选择;目录节点必须可展开。
disabled: !hasChildren && node.disabled,
children: hasChildren ? toTreeData(node.children) : undefined,
data: {
description_category_id: node.description_category_id,
type_id: node.type_id
}
};
});
}
```
---
## 缓存策略
Atlas 已按 [`platform-product-reference-catalog.md`](../../architecture/platform-product-reference-catalog.md) 为每个平台分别维护共享目录:定时自动同步与系统管理员手动触发共用异步任务,失败保留上次成功版本;商品编辑器只读 Atlas 平台缓存。同平台的门店不再各自复制类目树,本阶段也不维护门店差异层。
---
## 常见问题
### Q1: 类目树很大吗?
**A**: 完整树在一次响应中以递归 `children` 返回;具体节点数和响应大小以实际同步记录为准,后续从 Atlas 缓存读取。
### Q2: 多久更新一次?
**A**: Ozon 接口未规定 Atlas 的缓存 TTL。Atlas 固定在最近一次成功后 7 天自动同步完整树,并提供系统管理员手动排队同步入口;失败不会更新成功时间或清空旧树。
### Q3: 不同语言的类目树结构一样吗?
**A**: 接口支持语言参数,不应未经验证就假定各语言的 ID 和翻译映射完全相同。当前 Worker 使用 Ozon 平台参考源统一缓存 `ZH_HANS`,同平台所有门店共用。前端不能携带平台或门店密钥直连 Ozon。
### Q4: `type_id=0` 是什么意思?
**A**: 目录节点通常 `type_id=0`,但前端不能据此把所有目录设为 disabled,否则它们无法展开。是否允许提交必须同时判断:它是叶子节点、`disabled=false`,并且有可用的 `type_id`。
---
## Atlas 当前集成
- **Worker**:使用系统后台配置的平台参考源凭据调用 Ozon,递归持久化完整 `children` 树及父子关系;同一平台活动任务按作用域合并。
- **API**:按当前平台返回缓存的扁平节点(包含 `parent_id`);不会将 `Client-Id` 或 `Api-Key` 返回给浏览器。
- **前端**:根据 `parent_id` 重建任意深度的 Cascader;目录可展开,只有可发布的叶子能写入商品草稿。
- **调试**:若需要查看 Ozon 原始响应,应由受权限保护的服务端调试能力获取并脱敏展示;浏览器不得直接用门店密钥请求 Ozon。
- **同步维护**:完整树每 7 天自动同步,也可由系统管理员手动触发;树任务不自动展开为所有类型属性或字典任务。
- **发布边界**:当前发布预检校验所选本地类目仍活动,但尚未对树级新鲜度创建刷新任务;该边界需在真正发布 job 接入前确认或补齐。
---
## 相关文档
- [03-category-attributes.md](./03-category-attributes.md) —— 获取类目属性
- [平台商品参考目录](../../architecture/platform-product-reference-catalog.md) —— 平台级数据归属
- [平台目录缓存刷新方案](../../architecture/platform-catalog-cache-refresh-plan.md) —— 每周树同步和属性/字典按需刷新
- [商品编辑与发布 API](../../api/product-editor-and-publishing.md) —— 编辑器类目读取和发布预检