# API Contracts: 商品规格 **Feature**: 013-food-spec | **Date**: 2026-07-15 > 接口风格沿用 foodie 现有:`@Anonymous` + 自定义 `@Auth`(JWT),返回 `AjaxResult`/`TableDataInfo`,fastjson 拼装。价格单位与 `pos_food.price` 一致(decimal)。 ## 一、规格管理(新建 FoodSpecController,基路径 `/chanting/foodSpec`) | Method | Path | 入参 | 出参 | 说明 | |--------|------|------|------|------| | GET | /foodSpecPageList | token,pageNum,pageSize,mdId,language | IPage(每条带 foodSpecsItems) | 规格组分页 | | POST | /saveFoodSpec | @RequestBody List(含级联 foodSpecsItems) | AjaxResult | 新增/编辑规格组+级联值 | | GET | /getSpecs | id | FoodSpecs(带 foodSpecsItems) | 规格详情 | | GET | /deleteFoodSpec | id | AjaxResult | 软删除(is_delete=1) | | GET | /getAvailableSpecsList | mdId,language | List(is_open=1 & is_delete=0,带 foodSpecsItems) | 商品编辑页选规格用 | | GET | /changeOpen | id,isOpen | AjaxResult | 启停规格组 | | GET | /changeSpecValueOpen | id,isOpen | AjaxResult | 启停规格值 | ### 保存请求体示例(POST /saveFoodSpec) ```json [ { "id": 0, "title": "甜度", "type": "1", "state": "1", "language": "zh", "mdId": 3, "sort": 0, "isOpen": true, "foodSpecsItems": [ { "id": 0, "name": "无糖", "price": 0, "note": "", "isOpen": true }, { "id": 0, "name": "全糖", "price": 0, "isOpen": true } ] } ] ``` ## 二、商品接口规格部分(改 PosFoodController,基路径 `/chanting/food`) ### 1. 保存商品 POST /setposfood(及后台 add/edit) 请求体 `PosFood` 复用/增加: - `foodSpecs: List` —— 所选规格组(写 `food_spec_relation`) - `sku: JSONArray` —— 规格精简 JSON(toString 写 `pos_food.food_sku`) 后端处理(setposfood 与 add/edit 共用同一私有方法): 1. 保存商品本身。 2. 删除该 `food_id` 的旧关联,按 `foodSpecs[*].id` 批量插入新关联。 3. `sku.toString()` 写入 `food_sku`。 ### 2. 商品详情 GET /getfood?id= 响应在商品对象上增加: - `foodSpecs` —— 结构化规格(仅启用,明细字段名 `foodSpecsItems`) - `foodSku` —— 兼容 JSON(明细字段名统一为 `foodSpecsItems`) ### 3. 商品列表(需注入规格的接口) - GET /getidlist(商家端分类列表) - GET /stallFoodList(C 端摊位扫码列表) - GET /foodSearch(搜索) 均批量注入 `foodSpecs` + `foodSku`(批量查关联/规格组/规格值 + 内存分组,避免 N+1)。 > 后台管理 GET /list、GET /{id} 为管理用途,本期不强制返回规格结构(可不含),以降低改动面。 ### 列表/详情响应规格结构示例 ```json { "id": 100, "name": "珍珠奶茶", "price": 20.00, "foodSpecs": [ { "id": 7, "title": "甜度", "type": "1", "state": "1", "mdId": 3, "sort": 0, "isOpen": true, "foodSpecsItems": [ { "id": 15, "parentId": 7, "name": "无糖", "price": 0, "isOpen": true }, { "id": 16, "parentId": 7, "name": "全糖", "price": 0, "isOpen": true } ] } ], "foodSku": [ { "id": 7, "title": "甜度", "foodSpecsItems": [ "..." ] } ] } ``` ## 三、计价契约 - 顾客选定规格值集合 S,实付单价 = `pos_food.price` + Σ(`S.price`)。 - 该加价和 = 订单快照 `otherPrice` = 促销算价 `specPrice`(三者统一来源)。