# 产品模块 Categories(类别)接口对接说明(美国版) ## 概述 本模块用于平台端(H5)Products → **Categories** 页签的数据对接。 - **模块**:`food-labeling-us` - **接口前缀**:宿主统一前缀为 `/api/app` - **分类表**:`fl_product_category` - **关联字段**:`fl_product.category_id` → `fl_product_category.id` - **外观字段(字符串落库,内容为 JSON 文本)**: - `ButtonAppearance`(`buttonAppearance`):如 `["TEXT","COLOR"]`、仅图片 `["IMAGE"]`、或合法 JSON 对象/数组;兼容历史单行 `TEXT`/`COLOR`/`IMAGE`(保存时会规范为 JSON 数组,如 `["TEXT"]`)。 - `CategoryPhotoUrl`(`categoryPhotoUrl`):与外观配合的**展示数据**,同样为 **JSON 字符串**(如 `["Prep","#10B981"]`、图片 URL 数组等);若传入**非 JSON** 的纯文本(如旧数据中的 `#EC4899` 或 `/picture/...`),后端会序列化为合法 JSON 字符串再存储。列表/详情/App 树**原样返回**库中字符串,由前端解析。 > 说明:本文以 Swagger 为准(本地示例:`http://localhost:19001/swagger`,搜索 `ProductCategory`)。 --- ## 接口 1:类别分页列表 ### HTTP - **方法**:`GET` - **路径**:`/api/app/product-category` - **鉴权**:需要登录(Header:`Authorization: Bearer {token}`) ### 入参(Query 参数) | 参数名 | 类型 | 必填 | 说明 | |------|------|------|------| | `skipCount` | number | 是 | 跳过条数(分页) | | `maxResultCount` | number | 是 | 每页条数(分页) | | `sorting` | string | 否 | 排序字段(如 `OrderNum desc`),不传则按 `OrderNum desc, CreationTime desc` | | `keyword` | string | 否 | 模糊搜索(匹配 `CategoryCode/CategoryName`) | | `state` | boolean | 否 | 启用状态过滤 | ### 请求示例 ```http GET /api/app/product-category?skipCount=0&maxResultCount=10&keyword=Prep HTTP/1.1 Host: localhost:19001 Authorization: Bearer eyJhbGciOi... ``` ### 出参(PagedResultWithPageDto) | 字段 | 类型 | 说明 | |------|------|------| | `pageIndex` | number | 当前页(从 1 开始) | | `pageSize` | number | 每页条数 | | `totalCount` | number | 总数 | | `totalPages` | number | 总页数 | | `items` | array | 当前页数据 | `items[]` 字段: | 字段 | 类型 | 说明 | |------|------|------| | `id` | string | 主键 | | `categoryCode` | string | 类别编码 | | `categoryName` | string | 类别名称 | | `displayText` | string \| null | 按钮展示文案(空可回退 `categoryName`) | | `categoryPhotoUrl` | string \| null | 分类展示数据,**JSON 格式字符串**(含义由前端与 `buttonAppearance` 约定) | | `buttonAppearance` | string | 按钮外观,**JSON 格式字符串**(见上文「外观字段」) | | `availabilityType` | string | `ALL` / `SPECIFIED`(门店可用范围) | | `state` | boolean | 是否启用 | | `orderNum` | number | 排序 | | `lastEdited` | string | 最后编辑时间 | ### 响应示例 ```json { "pageIndex": 1, "pageSize": 10, "totalCount": 1, "totalPages": 1, "items": [ { "id": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f", "categoryCode": "CAT_PREP", "categoryName": "Prep", "displayText": "Prep", "categoryPhotoUrl": "[\"Prep\",\"#10B981\"]", "buttonAppearance": "[\"TEXT\",\"COLOR\"]", "availabilityType": "ALL", "state": true, "orderNum": 100, "lastEdited": "2026-03-25 12:30:10" } ] } ``` --- ## 接口 2:类别详情 ### HTTP - **方法**:`GET` - **路径**:`/api/app/product-category/{id}` ### 请求示例 ```http GET /api/app/product-category/a2696b9e-2277-11f1-b4c6-00163e0c7c4f HTTP/1.1 Host: localhost:19001 Authorization: Bearer eyJhbGciOi... ``` ### 响应示例(ProductCategoryGetOutputDto) ```json { "id": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f", "categoryCode": "CAT_PREP", "categoryName": "Prep", "displayText": "Prep", "categoryPhotoUrl": "[\"Prep\",\"#10B981\"]", "buttonAppearance": "[\"TEXT\",\"COLOR\"]", "availabilityType": "ALL", "locationIds": [], "state": true, "orderNum": 100 } ``` --- ## 接口 3:新增类别 ### HTTP - **方法**:`POST` - **路径**:`/api/app/product-category` - **Content-Type**:`application/json` ### 入参(Body JSON:ProductCategoryCreateInputVo) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `categoryCode` | string | 是 | 类别编码(唯一) | | `categoryName` | string | 是 | 类别名称(唯一) | | `displayText` | string \| null | 否 | 按钮展示文案 | | `categoryPhotoUrl` | string \| null | 否 | **JSON 字符串**;与 `buttonAppearance` 配合(见概述)。纯路径等非 JSON 文本会被后端包成 JSON 字符串存储。 | | `buttonAppearance` | string | 否 | **JSON 字符串**;未传或空白时后端默认 `["TEXT"]`。兼容传 `TEXT`/`COLOR`/`IMAGE` 单行(会规范为 `["TEXT"]` 等)。非法非 JSON 且非上述三者时报错。 | | `availabilityType` | string | 否 | `ALL`(默认)或 `SPECIFIED` | | `locationIds` | string[] | 条件 | `availabilityType=SPECIFIED` 时必填且至少 1 个门店 Id | | `state` | boolean | 否 | 是否启用(默认 true) | | `orderNum` | number | 否 | 排序(默认 0) | ### 请求示例 ```json { "categoryCode": "CAT_PREP", "categoryName": "Prep", "displayText": "Prep", "buttonAppearance": "[\"TEXT\",\"COLOR\"]", "categoryPhotoUrl": "[\"Prep\",\"#10B981\"]", "availabilityType": "ALL", "locationIds": [], "state": true, "orderNum": 100 } ``` --- ## 接口 4:编辑类别 ### HTTP - **方法**:`PUT` - **路径**:`/api/app/product-category/{id}` - **Content-Type**:`application/json` ### 请求示例 ```json { "categoryCode": "CAT_PREP", "categoryName": "Prep", "displayText": "Prep", "buttonAppearance": "[\"TEXT\",\"COLOR\"]", "categoryPhotoUrl": "[\"Prep\",\"#10B981\"]", "availabilityType": "ALL", "locationIds": [], "state": true, "orderNum": 100 } ``` --- ## 接口 5:删除类别(逻辑删除) ### HTTP - **方法**:`DELETE` - **路径**:`/api/app/product-category/{id}` ### 约束 - 若该类别已被 `fl_product` 引用(`fl_product.CategoryId = id`),删除会失败并返回友好提示:`该类别已被产品引用,无法删除`。 ### 请求示例 ```http DELETE /api/app/product-category/a2696b9e-2277-11f1-b4c6-00163e0c7c4f HTTP/1.1 Host: localhost:19001 Authorization: Bearer eyJhbGciOi... ``` --- ## 配套:类别图片上传接口 类别图片上传接口见文档: - `项目相关文档/平台端Categories图片上传接口说明.md` 推荐前端流程: 1. 调用上传接口 `POST /api/app/picture/category/upload` 拿到响应 `url` 2. 新增/编辑类别时:若采用 **JSON** 存展示数据,将 `url` 写入你方约定的 JSON 结构(例如 `["IMAGE","/picture/..."]`);若仍传**纯路径字符串**,后端会将其序列化为 JSON 字符串再入库(与仅图片场景兼容)。