# 5-19 接口优化 本文档说明 **2026-05-19** 对美国版接口的变更。 1. **`/api/app/label-multiple-option`**:`optionCode` **取消必填**(见 [label-multiple-option-optionCode](#label-multiple-option-optioncode-可选))。 2. **`/api/app/product`**:新增/编辑/列表/详情支持 **`codeValue`、`buttonAppearance`、`categoryPhotoUrl`**(见 [product-appearance](#product-按钮展示字段))。 3. **`GET /api/app/us-app-labeling/labeling-tree`**:第三级产品卡片返回上述三字段(见 [us-app-labeling-tree-product](#us-app-labeling-tree-产品展示字段))。 --- ## label-multiple-option optionCode 可选 **应用服务**:`LabelMultipleOptionAppService` **影响接口**:`POST /api/app/label-multiple-option`、`PUT /api/app/label-multiple-option/{id}`(列表/详情出参展示同步) ### 变更说明 | 项 | 变更前 | 变更后 | |----|--------|--------| | **optionCode** | 必填;空则报「多选项编码和名称不能为空」 | **可选**;可不传、传 `null` 或 `""` | | **optionName** | 必填 | 仍必填 | | **落库** | — | 未填编码时 `OptionCode` 存 **空字符串** | | **列表/详情出参** | 原样返回库值 | 编码为空时 **`optionCode` 显示「无」** | | **唯一性** | 编码或名称重复即报错 | 有编码时:编码 **或** 名称重复报错;**无编码**时仅校验 **名称** 不重复 | ### 新增 / 编辑入参(节选) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | optionCode | string | **否** | 多选项编码 | | optionName | string | **是** | 多选项名称 | | optionValuesJson | string | 否 | 选项值 JSON | | state | bool | 否 | 默认 `true` | | regionIds / groupIds / locationIds | string[] | 否 | Region·Location 范围(规则同 5-18) | ### 请求示例(无编码) ```http POST /api/app/label-multiple-option Content-Type: application/json Authorization: Bearer {token} ``` ```json { "optionName": "Allergens", "optionValuesJson": "[\"Peanuts\",\"Dairy\"]", "state": true, "orderNum": 1, "availabilityType": "ALL" } ``` ### 请求示例(仍可有编码) ```json { "optionCode": "OPT_ALLERGENS", "optionName": "Allergens", "state": true } ``` ### 出参示例 ```json { "id": "...", "optionCode": "无", "optionName": "Allergens", "optionValuesJson": "[\"Peanuts\",\"Dairy\"]", "state": true } ``` ### 联调注意 | 现象 | 处理 | |------|------| | 仍报「编码和名称不能为空」 | 确认已部署含本变更的后端;仅需保证 **optionName** 非空 | | 无编码时名称重复 | 正常:仅按 **optionName** 判重 | | 多条均无编码 | 允许;彼此以 **optionName** 区分,勿重复名称 | | 列表 keyword | 仍匹配 `optionCode`、`optionName` | > Region/Location 多选、列表筛选等完整说明见 `5-18接口优化.md` → label-multiple-option 章节。 --- ## product 按钮展示字段 **应用服务**:`ProductAppService` **表**:`fl_product` **DDL 脚本**:`美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/scripts/fl_product_add_appearance_columns.sql` ### 库表核对(2026-05-19) **`fl_product` 须包含下列列**(管理端保存与 App 四级树读取同源)。若库中尚无,执行下方 DDL;已执行可跳过。 | 列名 | 类型 | 说明 | |------|------|------| | `DisplayText` | varchar(100) NULL | 按钮展示文案(远程分支字段) | | `CodeValue` | varchar(100) NULL | 条码/编码值 | | `ButtonAppearance` | varchar(512) NOT NULL DEFAULT `'["TEXT"]'` | 按钮外观 JSON | | `CategoryPhotoUrl` | varchar(512) NULL | 与 appearance 同序的展示值 JSON | ```sql ALTER TABLE `fl_product` ADD COLUMN `DisplayText` varchar(100) NULL COMMENT '按钮展示文案' AFTER `ProductImageUrl`, ADD COLUMN `CodeValue` varchar(100) NULL COMMENT '条码/编码值' AFTER `DisplayText`, ADD COLUMN `ButtonAppearance` varchar(512) NOT NULL DEFAULT '["TEXT"]' COMMENT '按钮外观 JSON' AFTER `CodeValue`, ADD COLUMN `CategoryPhotoUrl` varchar(512) NULL COMMENT '展示值 JSON' AFTER `ButtonAppearance`; ``` ### 影响接口 | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/app/product?SkipCount=1&MaxResultCount=10` | 列表 `items[]` 增加三字段 | | GET | `/api/app/product/{id}` | 详情增加三字段 | | POST | `/api/app/product` | Body 可传三字段 | | PUT | `/api/app/product/{id}` | Body 可传三字段 | | PUT | `/api/app/product/update-products-bulk` | `items[]` 与单条 PUT 字段一致 | ### 入参(新增/编辑 Body 节选) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | codeValue | string | 否 | 按钮 TEXT 展示文案等;空则库内 NULL,出参 **「无」** | | buttonAppearance | string / string[] | 否 | `TEXT`/`COLOR`/`IMAGE` 或 JSON 数组;未传默认 `["TEXT"]` | | categoryPhotoUrl | string | 否 | 与 `buttonAppearance` **同序** 的 JSON 数组(TEXT=文案、COLOR=色值、IMAGE=URL);规则同 **product-category** | 其余字段(`productName`、`productCode`、`categoryId`、`locationIds`、`partnerId`、`groupIds` 等)不变,见 `5-17` / 标签模块产品章节。 ### 请求示例 ```http POST /api/app/product Content-Type: application/json Authorization: Bearer {token} ``` ```json { "productName": "Organic Milk", "productCode": "PRD_001", "categoryId": "分类Guid", "codeValue": "MILK", "buttonAppearance": ["TEXT", "COLOR"], "categoryPhotoUrl": "[\"MILK\",\"#10B981\"]", "state": true, "partnerId": "fl_partner主键", "groupIds": ["fl_group主键"], "locationIds": ["门店Guid"] } ``` ### 列表 `GET /api/app/product` ```http GET /api/app/product?SkipCount=1&MaxResultCount=10 Authorization: Bearer {token} ``` 可选 Query(与改造前一致):`keyword`、`state`、`partnerId`、`groupId`、`locationId`、`sorting`。 **`items[]` 每条均包含下列三字段**(与详情一致;无值时 `codeValue` 为 **「无」**): | 字段 | 类型 | 说明 | |------|------|------| | codeValue | string | 按钮展示文案;库内 NULL/空 → **「无」** | | buttonAppearance | string | 落库 JSON,默认 `["TEXT"]` | | categoryPhotoUrl | string? | 展示值 JSON;未配置可为 `null` | **列表响应示例** ```json { "pageIndex": 1, "pageSize": 10, "totalCount": 1, "totalPages": 1, "items": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "productCode": "PRD_001", "productName": "Organic Milk", "categoryId": "分类Guid", "categoryName": "Dairy", "productImageUrl": "https://cdn.example.com/milk.png", "codeValue": "MILK", "buttonAppearance": "[\"TEXT\",\"COLOR\"]", "categoryPhotoUrl": "[\"MILK\",\"#10B981\"]", "state": true, "noOfLabels": 3 } ] } ``` ### 详情 `GET /api/app/product/{id}` 出参(节选) | 字段 | 说明 | |------|------| | codeValue | 同列表 | | buttonAppearance | 同列表 | | categoryPhotoUrl | 同列表 | ### 与 product-category 的关系 语义与 **`fl_product_category`** 的 `displayText` / `buttonAppearance` / `categoryPhotoUrl` 一致;产品表使用 **`codeValue`** 命名以区分业务字段。规范化逻辑复用 `CategoryAppearanceStorageHelper`。 ### 联调注意 | 现象 | 处理 | |------|------| | 保存报列不存在 | 先执行上文 DDL | | buttonAppearance 报格式错误 | 须为合法 JSON 或单值 `TEXT`/`COLOR`/`IMAGE` | | 批量导入 Excel | 当前导入模板**未**含三字段;仅 Web API 表单写入 | --- ## us-app-labeling-tree 产品展示字段 **应用服务**:`UsAppLabelingAppService.GetLabelingTreeAsync` **接口**:`GET /api/app/us-app-labeling/labeling-tree?locationId={guid}` **数据来源**:`fl_product`(与 Web **`POST/PUT /api/app/product`** 写入字段一致;App 树接口本身不提供产品新增/编辑) ### 出参位置 四级树 **第三级** `productCategories[].products[]`(`UsAppLabelingProductNodeDto`)每条产品卡片增加: | 字段 | 类型 | 说明 | |------|------|------| | codeValue | string | `fl_product.CodeValue`;空为 **「无」** | | buttonAppearance | string | `fl_product.ButtonAppearance` JSON,默认 `["TEXT"]` | | categoryPhotoUrl | string? | `fl_product.CategoryPhotoUrl` | > **第二级** `productCategories[]` 仍为 **产品分类**(`fl_product_category`)的 `displayText` / `buttonAppearance` / `categoryPhotoUrl`,勿与产品级字段混淆。 ### 请求示例 ```http GET /api/app/us-app-labeling/labeling-tree?locationId=3a212211-3b01-d66f-a804-125c0cee3bf0 Authorization: Bearer {token} ``` ### 响应片段(第三级产品) ```json { "id": "标签分类Id", "categoryName": "Prepared Foods", "productCategories": [ { "categoryId": "产品分类Id", "name": "Sandwiches", "products": [ { "productId": "3a212211-3b01-d66f-a804-125c0cee3bf0", "productName": "Turkey Club", "productCode": "PRD_001", "codeValue": "TURKEY", "buttonAppearance": "[\"TEXT\",\"COLOR\"]", "categoryPhotoUrl": "[\"TURKEY\",\"#F59E0B\"]", "labelTypes": [] } ] } ] } ``` ### 产品新增/编辑(Web) App 端展示依赖管理端维护产品: | 方法 | 路径 | |------|------| | POST | `/api/app/product` | | PUT | `/api/app/product/{id}` | Body 字段见 [product 按钮展示字段](#product-按钮展示字段)。 ### 联调注意 | 现象 | 处理 | |------|------| | 接口报错 `当前账号未绑定该门店` | App 账号须在 `userlocation` 绑定该 `locationId`;**平台管理员**(`admin` / `*:*:*`)可不绑定直接查 | | HTTP 200 但前端 Request failed | 看 Response 里 `succeeded` 与 `error.message`;常见为库缺 `fl_product.DisplayText` 列,执行 `fl_product_add_display_text_only.sql` | | 树中三字段全空/默认 | 检查是否已对产品在 Web 保存过三字段;`fl_product` 列是否存在 | | 仅有 `productCode` 无 `codeValue` | `subtitle` 仍用 `productCode`;`codeValue` 独立字段需单独维护 | | keyword 搜索 | 树 Query `keyword` 匹配产品名、`CodeValue`、`DisplayText` 及分类/标签名 | > 树空数据、门店绑定、`SPECIFIED` 分类等见 `5-18接口优化.md` → us-app-labeling-tree 章节。 --- ## 修订记录 | 日期 | 说明 | |------|------| | 2026-05-19 | label-multiple-option:optionCode 取消必填;空编码出参显示「无」;无编码时仅按名称判重 | | 2026-05-19 | product:新增/编辑/列表/详情 codeValue、buttonAppearance、categoryPhotoUrl;DDL `fl_product_add_appearance_columns.sql` | | 2026-05-19 | us-app labeling-tree:第三级 products[] 返回 codeValue、buttonAppearance、categoryPhotoUrl(读 fl_product) | | 2026-05-19 | 合并冲突修复:去重 fl_product/DTO 重复字段;ProductAppService 统一 ApplyProductAppearanceToEntity;RbacRole DTO 补 AccessPermissionCodes |