Prechádzať zdrojové kódy

专业方案和延年圣手方案的列表和详情

jiapu 2 mesiacov pred
rodič
commit
fcc8ec0325

+ 0 - 61
AGENTS.md

@@ -1,61 +0,0 @@
-# 项目协作规则
-
-## 基本原则
-
-- 修改代码前先阅读相关文件,遵循现有项目结构、命名和实现风格。
-- 保持改动聚焦,只处理当前任务相关内容,不做无关重构。
-- 不要覆盖或回滚用户已有改动,除非用户明确要求。
-- 不要提交日志、临时文件、构建产物或本地环境配置。
-
-## 运行与构建
-
-- 前端构建优先使用:
-  `npm run build`
-- 如果需要运行前端开发服务,先查看现有脚本和端口配置,再启动对应命令。
-- 如果需要运行后端服务或测试,先查看后端目录中的 Maven/Gradle 配置,再选择合适命令。
-- 运行命令失败时,需要说明失败原因和已尝试的验证方式。
-
-## 修改限制
-
-- 不要修改以下本地配置文件,除非用户明确要求:
-  `code/backend/src/main/resources/application-dev.yml`
-- 不要提交以下内容:
-  `code/backend/logs/**`
-  `logs/
-- 涉及用户数据、方案、穴位、经络、调理内容时,要优先保证已有数据兼容性。
-- 涉及中医术语、穴位定位和方案描述时,要保持表述准确、谨慎。
-
-## 测试与验证
-
-- 前端代码改动后,优先运行:
-  `npm run build`
-- 后端代码改动后,优先运行相关单元测试或项目已有验证命令。
-- 如果改动范围较小且没有合适测试,也需要进行静态检查或说明未运行测试的原因。
-
-## Git 规则
-
-- 不要自动执行 `git push`,除非用户明确要求。
-- 不要使用破坏性 Git 命令,例如 `git reset --hard`、`git checkout -- <file>`,除非用户明确要求。
-- 提交前检查暂存内容,避免把本地配置、日志或无关文件加入提交。
-- 如果用户要求提交,提交信息优先使用中文,并简洁描述本次改动。
-- 不要将.cursor文件夹和.idea文件夹提交到git
-- Git 仓库: http://git.iwintrue.com/liaoxg/ajy
-- 同事分支:liyu_2026_04_07
-- 我的分支:jiapu_aijiuyi
-- 项目路径(仓库内): code/aijiuyi
-- Git 用户名: jiapu
-- 分支: jiapu_aijiuyi
-- 拉取代码规则:将同事分支的openspec文件夹下的所有文件(不包括openspec目录)同步到我的code目录下。
-- git提交日志:在每次提交的时候要询问我,如果我选择空白,则你可以自己总结边写日志
-- 提交代码规则:application-dev.yml文件默认不参与git提交。
-
-## 回复要求
-
-- 完成修改后,简要说明改了哪些文件、做了什么验证。
-- 如果有未完成事项、测试无法运行或需要用户决策的地方,需要明确说明。
-- 语言:和我对话,思考的时候使用中文。
-
-## 项目信息
-- 项目名称: aijiuyi
-- 可以读取并使用application.yml、application-dev.yml中的datasource属性
-- 所有问题都以dev环境为准,并且你可以随时查看我的dev环境数据库,但是没有编写权限。如果你要编辑数据库,需要征求我的同意

+ 498 - 85
code/app对接接口说明.md

@@ -20,14 +20,18 @@
 | 5 | 新增用户自定义方案 | `POST` | `/api/app/custom-plan` | 当前用户新增一个自定义模式方案(含穴位步骤),后端强制设置 modeType=3、authorType=2、authorId=当前用户 |
 | 6 | 查询当前用户的自定义方案列表 | `GET` | `/api/app/custom-plan/list` | 通过 Token 获取当前 APP 账号下创作人属于自己的自定义模式方案基本信息列表(不含穴位步骤),如需详情请调用第 7 个接口 |
 | 7 | 查询用户自定义方案详情 | `GET` | `/api/app/custom-plan/{id}` | 查询当前用户自己的某个自定义方案详情,校验方案归属,含穴位步骤列表 |
-| 8 | 修改用户自定义方案 | `PUT` | `/api/app/custom-plan` | 当前用户修改自己的自定义方案(含穴位步骤),仅允许修改创作人为当前用户、模式为自定义模式的方案 |
-| 9 | 删除用户自定义方案 | `DELETE` | `/api/app/custom-plan/{id}` | 当前用户删除自己的自定义方案,仅允许删除创作人为当前用户、模式为自定义模式的方案 |
-| 10 | 查询群组成员列表 | `GET` | `/api/app/group/{groupId}/members` | 查询指定家庭设备群组下的成员列表,仅返回当前 APP 账号所属群组的成员 |
-| 11 | 新增群组成员 | `POST` | `/api/app/group/{groupId}/members` | 当前 APP 账号向指定家庭设备群组添加新成员(包含用户档案信息),需校验群组归属 |
-| 12 | 修改群组成员 | `PUT` | `/api/app/group/{groupId}/members/{profileId}` | 当前 APP 账号修改指定群组下已有成员的用户档案信息,需校验群组归属 |
-| 13 | 删除群组成员 | `DELETE` | `/api/app/group/{groupId}/members/{profileId}` | 当前 APP 账号从指定家庭设备群组中移除成员(软删除),需校验群组归属且禁止删除自身 |
-| 14 | 查询当前账号个人资料 | `GET` | `/api/app/user/profile` | 通过 Token 获取当前 APP 账号对应的个人资料(昵称、头像、用户档案等),适用于家庭设备和公共设备 |
-| 15 | 修改当前账号个人资料 | `PUT` | `/api/app/user/profile` | 通过 Token 修改当前 APP 账号对应的个人资料,部分字段(昵称/头像)更新到 `app_user` 表,其余字段(体型、地址等)更新到 `user_profile` 表,适用于家庭设备和公共设备 |
+| 8 | 查询专业模式方案列表 | `GET` | `/api/app/professional-plan/list` | 通过 Token 获取专业模式(`modeType=2`)系统方案基本信息列表,所有 APP 用户共享同一份方案,仅返回已发布方案;如需详情请调用第 9 个接口 |
+| 9 | 查询专业模式方案详情 | `GET` | `/api/app/professional-plan/{id}` | 查询专业模式方案详情,校验模式为专业模式且已发布,含穴位步骤列表 |
+| 10 | 查询延年圣手模式方案列表 | `GET` | `/api/app/master-plan/list` | 通过 Token 获取延年圣手模式(`modeType=4`)系统方案基本信息列表,所有 APP 用户共享同一份方案,仅返回已发布方案;如需详情请调用第 11 个接口 |
+| 11 | 查询延年圣手模式方案详情 | `GET` | `/api/app/master-plan/{id}` | 查询延年圣手模式方案详情,校验模式为延年圣手模式且已发布,含穴位步骤列表 |
+| 12 | 修改用户自定义方案 | `PUT` | `/api/app/custom-plan` | 当前用户修改自己的自定义方案(含穴位步骤),仅允许修改创作人为当前用户、模式为自定义模式的方案 |
+| 13 | 删除用户自定义方案 | `DELETE` | `/api/app/custom-plan/{id}` | 当前用户删除自己的自定义方案,仅允许删除创作人为当前用户、模式为自定义模式的方案 |
+| 14 | 查询群组成员列表 | `GET` | `/api/app/group/{groupId}/members` | 查询指定家庭设备群组下的成员列表,仅返回当前 APP 账号所属群组的成员 |
+| 15 | 新增群组成员 | `POST` | `/api/app/group/{groupId}/members` | 当前 APP 账号向指定家庭设备群组添加新成员(包含用户档案信息),需校验群组归属 |
+| 16 | 修改群组成员 | `PUT` | `/api/app/group/{groupId}/members/{profileId}` | 当前 APP 账号修改指定群组下已有成员的用户档案信息,需校验群组归属 |
+| 17 | 删除群组成员 | `DELETE` | `/api/app/group/{groupId}/members/{profileId}` | 当前 APP 账号从指定家庭设备群组中移除成员(软删除),需校验群组归属且禁止删除自身 |
+| 18 | 查询当前账号个人资料 | `GET` | `/api/app/user/profile` | 通过 Token 获取当前 APP 账号对应的个人资料(昵称、头像、用户档案等),适用于家庭设备和公共设备 |
+| 19 | 修改当前账号个人资料 | `PUT` | `/api/app/user/profile` | 通过 Token 修改当前 APP 账号对应的个人资料,部分字段(昵称/头像)更新到 `app_user` 表,其余字段(体型、地址等)更新到 `user_profile` 表,适用于家庭设备和公共设备 |
 ## 3. 接口详情
 
 ### 3.1 查询用户背部产品穴位坐标列表
@@ -809,21 +813,432 @@ curl -X GET "http://localhost:18888/api/app/custom-plan/1001" \
 - 不会返回其他用户创作的方案、系统预设方案(`modeType=1/2/4`)的详情。
 - APP 在编辑方案前应先调用本接口获取最新数据。
 
-### 3.8 修改用户自定义方案
+### 3.8 查询专业模式方案列表
 
 #### 3.8.1 接口用途
 
+用于 APP 端查询专业模式(`modeType=2`)的系统方案列表。
+
+专业模式方案由后台预置并在所有 APP 用户间共享,**没有用户差异**:例如方案 ABC 存在时,所有登录的 APP 用户都能看到 ABC 三个方案,不会因为账号不同而出现不同结果。
+
+当前场景:APP 中"专业模式"页面展示系统预置的方案列表(驱寒、祛湿、祛风、化瘀、活血、化痰、养颜、扶阳等),供用户选择使用。
+
+> 本接口**只返回方案基本信息**,不包含穴位步骤。查看方案详情(含穴位步骤)请使用第 9 个接口 `GET /api/app/professional-plan/{id}`。
+
+#### 3.8.2 请求信息
+
+- 请求方式:`GET`
+- URI:`/api/app/professional-plan/list`
+- 完整示例:`http://localhost:18888/api/app/professional-plan/list`
+
+#### 3.8.3 请求参数
+
+无查询参数。后端通过 `Authorization` 请求头中的 Token 校验登录态,并按 `modeType=2`、`status=1`(已发布)返回专业模式方案列表,不区分用户。
+
+#### 3.8.4 调用示例
+
+```http
+GET /api/app/professional-plan/list HTTP/1.1
+Host: localhost:18888
+Authorization: Bearer <token>
+```
+
+```bash
+curl -X GET "http://localhost:18888/api/app/professional-plan/list" \
+  -H "Authorization: Bearer <token>"
+```
+
+#### 3.8.5 返回示例
+
+```json
+{
+  "code": 200,
+  "message": "操作成功",
+  "data": [
+    {
+      "id": 10001,
+      "planCode": "S002",
+      "name": "专业驱寒方案",
+      "modeType": 2,
+      "effectType": "驱寒",
+      "symptoms": "怕冷,手脚冰凉,畏寒",
+      "applicableGender": 0,
+      "ageMin": 1,
+      "ageMax": 120,
+      "description": "针对阳虚畏寒人群的基础驱寒方案。",
+      "authorId": 1,
+      "authorName": "ADMIN",
+      "authorType": 1,
+      "useCount": 0,
+      "avgRating": null,
+      "lastUseTime": null,
+      "status": 1,
+      "createTime": "2026-06-01 09:00:00",
+      "updateTime": "2026-06-01 09:00:00"
+    },
+    {
+      "id": 10002,
+      "planCode": "S003",
+      "name": "专业祛湿方案",
+      "modeType": 2,
+      "effectType": "祛湿",
+      "symptoms": "困倦,湿重,食欲差",
+      "applicableGender": 0,
+      "ageMin": 1,
+      "ageMax": 120,
+      "description": "围绕脾胃与膀胱经调理的祛湿方案。",
+      "authorId": 1,
+      "authorName": "ADMIN",
+      "authorType": 1,
+      "useCount": 0,
+      "avgRating": null,
+      "lastUseTime": null,
+      "status": 1,
+      "createTime": "2026-06-01 09:00:00",
+      "updateTime": "2026-06-01 09:00:00"
+    }
+  ]
+}
+```
+
+#### 3.8.6 字段说明
+
+| 字段名 | 类型 | 说明 |
+| --- | --- | --- |
+| `id` | `number` | 方案 ID,对应 `plan.id` |
+| `planCode` | `string` | 方案编码 |
+| `name` | `string` | 方案名称 |
+| `modeType` | `number` | 模式类型,本接口固定返回 `2`(专业模式) |
+| `effectType` | `string` | 作用类型:驱寒/祛湿/祛风/化瘀/活血/化痰/养颜/扶阳 |
+| `symptoms` | `string` | 适用症状(逗号分隔) |
+| `applicableGender` | `number` | 适用人群:`0=不限`,`1=仅男`,`2=仅女` |
+| `ageMin` | `number` | 适用年龄最小值(岁) |
+| `ageMax` | `number` | 适用年龄最大值(岁) |
+| `description` | `string` | 方案描述 |
+| `authorId` | `number` | 创作人 ID |
+| `authorName` | `string` | 创作人名称(系统预置为 `ADMIN`) |
+| `authorType` | `number` | 创作人类型:`1=管理员`,`2=用户`,`3=专家`,系统预置方案固定为 `1` |
+| `useCount` | `number` | 使用人数 |
+| `avgRating` | `number/null` | 平均评分 |
+| `lastUseTime` | `string/null` | 最后使用时间 |
+| `status` | `number` | 状态:本接口固定返回 `1`(已发布) |
+| `createTime` | `string` | 创建时间 |
+| `updateTime` | `string` | 更新时间 |
+
+#### 3.8.7 备注
+
+- 本接口**不返回**穴位步骤列表(`steps`),仅返回方案基本信息。如需查看方案详情和穴位步骤,请调用第 9 个接口 `GET /api/app/professional-plan/{id}`。
+- 本接口返回的方案对**所有 APP 用户共享**,不因账号不同而出现不同结果。
+- 后端按 `modeType=2`、`status=1`(已发布)、`deleted=0` 严格过滤,不会返回草稿、已下架或已删除的方案,也不会返回一键艾灸(`modeType=1`)、自定义模式(`modeType=3`)、延年圣手(`modeType=4`)的方案。
+- 结果按 `effectType` 升序、`id` 升序返回,相同作用类型下按 ID 顺序展示。
+
+### 3.9 查询专业模式方案详情
+
+#### 3.9.1 接口用途
+
+用于 APP 端查询专业模式(`modeType=2`)的某个系统方案详情,含穴位步骤列表。
+
+#### 3.9.2 请求信息
+
+- 请求方式:`GET`
+- URI:`/api/app/professional-plan/{id}`
+- 完整示例:`http://localhost:18888/api/app/professional-plan/10001`
+
+#### 3.9.3 请求参数
+
+| 参数名 | 类型 | 是否必填 | 说明 | 示例 |
+| --- | --- | --- | --- | --- |
+| `id` | `number` | 是 | 方案 ID,对应 `plan.id`,通过路径参数传递 | `10001` |
+
+#### 3.9.4 调用示例
+
+```http
+GET /api/app/professional-plan/10001 HTTP/1.1
+Host: localhost:18888
+Authorization: Bearer <token>
+```
+
+```bash
+curl -X GET "http://localhost:18888/api/app/professional-plan/10001" \
+  -H "Authorization: Bearer <token>"
+```
+
+#### 3.9.5 返回示例
+
+```json
+{
+  "code": 200,
+  "message": "操作成功",
+  "data": {
+    "id": 10001,
+    "planCode": "S002",
+    "name": "专业驱寒方案",
+    "modeType": 2,
+    "symptoms": "怕冷,手脚冰凉,畏寒",
+    "applicableGender": 0,
+    "ageMin": 1,
+    "ageMax": 120,
+    "description": "针对阳虚畏寒人群的基础驱寒方案。",
+    "useCount": 0,
+    "avgRating": null,
+    "status": 1,
+    "createTime": "2026-06-01 09:00:00",
+    "updateTime": "2026-06-01 09:00:00",
+    "steps": [
+      {
+        "id": 20001,
+        "planId": 10001,
+        "stepOrder": 1,
+        "acupointId": 1,
+        "acupointName": "大椎穴",
+        "side": 1,
+        "temperature": 44.00,
+        "duration": 8,
+        "techniqueId": 3,
+        "techniqueName": "雀啄灸",
+        "remark": "驱寒起始"
+      }
+    ]
+  }
+}
+```
+
+#### 3.9.6 字段说明
+
+方案基本信息字段(`id`、`planCode`、`name`、`modeType`、`effectType`、`symptoms`、`applicableGender`、`ageMin`、`ageMax`、`description`、`authorId`、`authorName`、`authorType`、`useCount`、`avgRating`、`lastUseTime`、`status`、`createTime`、`updateTime`)定义同 3.8.6 节。
+
+`steps` 穴位步骤列表字段定义同 3.7.6 节。
+
+#### 3.9.7 失败返回示例
+
+方案不存在、非专业模式、未发布或已删除:
+
+```json
+{
+  "code": 1700,
+  "message": "方案不存在",
+  "data": null
+}
+```
+
+#### 3.9.8 备注
+
+- 越权校验在 Service 层完成:仅当 `modeType=2`、`status=1`(已发布)、`deleted=0` 同时满足时才返回方案详情,否则按"方案不存在"处理。
+- 本接口为只读,不会修改任何数据。
+- 方案对所有 APP 用户开放,任意登录用户均可查询。
+- 不会返回自定义模式(`modeType=3`)、一键艾灸(`modeType=1`)、延年圣手(`modeType=4`)的方案详情,防止越权访问。
+
+### 3.10 查询延年圣手模式方案列表
+
+#### 3.10.1 接口用途
+
+用于 APP 端查询延年圣手模式(`modeType=4`)的系统方案列表。
+
+延年圣手模式方案由后台预置并在所有 APP 用户间共享,**没有用户差异**:例如方案 XYZ 存在时,所有登录的 APP 用户都能看到 XYZ 三个方案。
+
+当前场景:APP 中"延年圣手"页面展示系统预置方案列表,供用户选择使用。
+
+> 本接口**只返回方案基本信息**,不包含穴位步骤。查看方案详情(含穴位步骤)请使用第 11 个接口 `GET /api/app/master-plan/{id}`。
+
+#### 3.10.2 请求信息
+
+- 请求方式:`GET`
+- URI:`/api/app/master-plan/list`
+- 完整示例:`http://localhost:18888/api/app/master-plan/list`
+
+#### 3.10.3 请求参数
+
+无查询参数。后端通过 `Authorization` 请求头中的 Token 校验登录态,并按 `modeType=4`、`status=1`(已发布)返回延年圣手模式方案列表,不区分用户。
+
+#### 3.10.4 调用示例
+
+```http
+GET /api/app/master-plan/list HTTP/1.1
+Host: localhost:18888
+Authorization: Bearer <token>
+```
+
+```bash
+curl -X GET "http://localhost:18888/api/app/master-plan/list" \
+  -H "Authorization: Bearer <token>"
+```
+
+#### 3.10.5 返回示例
+
+```json
+{
+  "code": 200,
+  "message": "操作成功",
+  "data": [
+    {
+      "id": 20001,
+      "planCode": "M001",
+      "name": "延年圣手·扶阳固本",
+      "modeType": 4,
+      "effectType": "",
+      "symptoms": "腰膝酸软,畏寒肢冷",
+      "applicableGender": 0,
+      "ageMin": 18,
+      "ageMax": 80,
+      "description": "针对中老年体虚人群的延年圣手方案。",
+      "authorId": 1,
+      "authorName": "ADMIN",
+      "authorType": 1,
+      "useCount": 0,
+      "avgRating": null,
+      "lastUseTime": null,
+      "status": 1,
+      "createTime": "2026-06-01 09:00:00",
+      "updateTime": "2026-06-01 09:00:00"
+    }
+  ]
+}
+```
+
+#### 3.10.6 字段说明
+
+| 字段名 | 类型 | 说明 |
+| --- | --- | --- |
+| `id` | `number` | 方案 ID,对应 `plan.id` |
+| `planCode` | `string` | 方案编码 |
+| `name` | `string` | 方案名称 |
+| `modeType` | `number` | 模式类型,本接口固定返回 `4`(延年圣手) |
+| `effectType` | `string` | 作用类型,延年圣手模式可为空字符串 |
+| `symptoms` | `string` | 适用症状(逗号分隔) |
+| `applicableGender` | `number` | 适用人群:`0=不限`,`1=仅男`,`2=仅女` |
+| `ageMin` | `number/null` | 适用年龄最小值(岁) |
+| `ageMax` | `number/null` | 适用年龄最大值(岁) |
+| `description` | `string` | 方案描述 |
+| `authorId` | `number` | 创作人 ID |
+| `authorName` | `string` | 创作人名称 |
+| `authorType` | `number` | 创作人类型 |
+| `useCount` | `number` | 使用人数 |
+| `avgRating` | `number/null` | 平均评分 |
+| `lastUseTime` | `string/null` | 最后使用时间 |
+| `status` | `number` | 状态:本接口固定返回 `1`(已发布) |
+| `createTime` | `string` | 创建时间 |
+| `updateTime` | `string` | 更新时间 |
+
+#### 3.10.7 备注
+
+- 本接口**不返回**穴位步骤列表(`steps`),仅返回方案基本信息。如需查看方案详情和穴位步骤,请调用第 11 个接口 `GET /api/app/master-plan/{id}`。
+- 本接口返回的方案对**所有 APP 用户共享**,不因账号不同而出现不同结果。
+- 后端按 `modeType=4`、`status=1`(已发布)、`deleted=0` 严格过滤,不会返回草稿、已下架或已删除的方案,也不会返回一键艾灸(`modeType=1`)、专业模式(`modeType=2`)、自定义模式(`modeType=3`)的方案。
+- 结果按 `id` 升序返回。
+
+### 3.11 查询延年圣手模式方案详情
+
+#### 3.11.1 接口用途
+
+用于 APP 端查询延年圣手模式(`modeType=4`)的某个系统方案详情,含穴位步骤列表。
+
+#### 3.11.2 请求信息
+
+- 请求方式:`GET`
+- URI:`/api/app/master-plan/{id}`
+- 完整示例:`http://localhost:18888/api/app/master-plan/20001`
+
+#### 3.11.3 请求参数
+
+| 参数名 | 类型 | 是否必填 | 说明 | 示例 |
+| --- | --- | --- | --- | --- |
+| `id` | `number` | 是 | 方案 ID,对应 `plan.id`,通过路径参数传递 | `20001` |
+
+#### 3.11.4 调用示例
+
+```http
+GET /api/app/master-plan/20001 HTTP/1.1
+Host: localhost:18888
+Authorization: Bearer <token>
+```
+
+```bash
+curl -X GET "http://localhost:18888/api/app/master-plan/20001" \
+  -H "Authorization: Bearer <token>"
+```
+
+#### 3.11.5 返回示例
+
+```json
+{
+  "code": 200,
+  "message": "操作成功",
+  "data": {
+    "id": 20001,
+    "planCode": "M001",
+    "name": "延年圣手·扶阳固本",
+    "modeType": 4,
+    "symptoms": "腰膝酸软,畏寒肢冷",
+    "applicableGender": 0,
+    "ageMin": 18,
+    "ageMax": 80,
+    "description": "针对中老年体虚人群的延年圣手方案。",
+    "useCount": 0,
+    "avgRating": null,
+    "status": 1,
+    "createTime": "2026-06-01 09:00:00",
+    "updateTime": "2026-06-01 09:00:00",
+    "steps": [
+      {
+        "id": 30001,
+        "planId": 20001,
+        "stepOrder": 1,
+        "acupointId": 8,
+        "acupointName": "肾俞穴",
+        "side": 4,
+        "temperature": 44.00,
+        "duration": 10,
+        "techniqueId": 2,
+        "techniqueName": "温和灸",
+        "remark": "补肾扶阳"
+      }
+    ]
+  }
+}
+```
+
+#### 3.11.6 字段说明
+
+方案基本信息字段(`id`、`planCode`、`name`、`modeType`、`effectType`、`symptoms`、`applicableGender`、`ageMin`、`ageMax`、`description`、`authorId`、`authorName`、`authorType`、`useCount`、`avgRating`、`lastUseTime`、`status`、`createTime`、`updateTime`)定义同 3.10.6 节。
+
+`steps` 穴位步骤列表字段定义同 3.7.6 节。
+
+#### 3.11.7 失败返回示例
+
+方案不存在、非延年圣手模式、未发布或已删除:
+
+```json
+{
+  "code": 1700,
+  "message": "方案不存在",
+  "data": null
+}
+```
+
+#### 3.11.8 备注
+
+- 越权校验在 Service 层完成:仅当 `modeType=4`、`status=1`(已发布)、`deleted=0` 同时满足时才返回方案详情,否则按"方案不存在"处理。
+- 本接口为只读,不会修改任何数据。
+- 方案对所有 APP 用户开放,任意登录用户均可查询。
+- 不会返回自定义模式(`modeType=3`)、一键艾灸(`modeType=1`)、专业模式(`modeType=2`)的方案详情,防止越权访问。
+
+
+
+### 3.12 修改用户自定义方案
+
+#### 3.12.1 接口用途
+
 用于 APP 端让用户修改自己创建的自定义模式方案,包括方案基本信息和穴位步骤列表。
 
 请求体格式与"新增用户自定义方案"接口(`POST /api/app/custom-plan`,见 3.5 节)保持一致,仅多一个 `id` 字段。`steps` 结构、字段含义、必填/可选规则完全相同。
 
-#### 3.8.2 请求信息
+#### 3.12.2 请求信息
 
 - 请求方式:`PUT`
 - URI:`/api/app/custom-plan`
 - 完整示例:`http://localhost:18888/api/app/custom-plan`
 
-#### 3.8.3 请求参数
+#### 3.12.3 请求参数
 
 请求体格式:`application/json`
 
@@ -852,7 +1267,7 @@ curl -X GET "http://localhost:18888/api/app/custom-plan/1001" \
 
 > 说明:请求体中**无需**传 `id`(步骤)、`planId`、`stepOrder`、`acupointName`、`techniqueName` 等字段,后端会按 `steps` 数组顺序自动重排 `stepOrder`(从 1 开始),并通过 `acupointId` 自动带出 `acupointName`、`techniqueName`。
 
-#### 3.8.4 调用示例
+#### 3.12.4 调用示例
 
 ```http
 PUT /api/app/custom-plan HTTP/1.1
@@ -897,7 +1312,7 @@ curl -X PUT "http://localhost:18888/api/app/custom-plan" \
   -d '{"id":1001,"name":"我的祛湿方案","symptoms":"关节酸痛,乏力","applicableGender":0,"ageMin":18,"ageMax":60,"description":"针对湿气重的人群定制","status":1,"steps":[{"acupointId":371,"side":1,"temperature":42.00,"duration":10,"techniqueId":1,"remark":"核心穴位"},{"acupointId":362,"side":1,"temperature":42.00,"duration":10,"techniqueId":1,"remark":""}]}'
 ```
 
-#### 3.8.5 成功返回示例
+#### 3.12.5 成功返回示例
 
 ```json
 {
@@ -907,7 +1322,7 @@ curl -X PUT "http://localhost:18888/api/app/custom-plan" \
 }
 ```
 
-#### 3.8.6 失败返回示例
+#### 3.12.6 失败返回示例
 
 方案不存在或非当前用户创建的自定义方案:
 
@@ -939,7 +1354,7 @@ curl -X PUT "http://localhost:18888/api/app/custom-plan" \
 }
 ```
 
-#### 3.8.7 备注
+#### 3.12.7 备注
 
 - 本接口需要 APP 登录后的 Token,不接受后台管理员 Token。
 - 后端会自动校验 `modeType=3`、`authorType=2`、`authorId=当前用户ID`,不满足时按"方案不存在"处理,避免越权。
@@ -947,27 +1362,27 @@ curl -X PUT "http://localhost:18888/api/app/custom-plan" \
 - 方案名称全局唯一,修改时不能与其他方案(包含其他用户创建的方案)重名。
 - 穴位必须处于启用状态(`acupoint.status=1`)才能被引用。
 - `modeType`、`effectType`、`planCode`、`authorId`、`authorName`、`authorType`、`useCount`、`avgRating` 等字段为系统字段,APP 传入也会被忽略,不允许用户修改。
-### 3.9 删除用户自定义方案
+### 3.13 删除用户自定义方案
 
-#### 3.9.1 接口用途
+#### 3.13.1 接口用途
 
 用于 APP 端用户删除自己的自定义方案。
 
 后端校验方案归属(`modeType=3`、`authorType=2`、`authorId=当前用户ID`),仅允许删除自己的自定义方案。删除为物理删除,会同步删除方案下的穴位步骤。
 
-#### 3.9.2 请求信息
+#### 3.13.2 请求信息
 
 - 请求方式:`DELETE`
 - URI:`/api/app/custom-plan/{id}`
 - 完整示例:`http://localhost:18888/api/app/custom-plan/2067138786800111618`
 
-#### 3.9.3 请求参数
+#### 3.13.3 请求参数
 
 | 参数名 | 类型 | 是否必填 | 说明 | 示例 |
 | --- | --- | --- | --- | --- |
 | `id` | `number` | 是 | 方案 ID,对应 `plan.id`,通过路径参数传递 | `2067138786800111618` |
 
-#### 3.9.4 调用示例
+#### 3.13.4 调用示例
 
 ```http
 DELETE /api/app/custom-plan/2067138786800111618 HTTP/1.1
@@ -980,7 +1395,7 @@ curl -X DELETE "http://localhost:18888/api/app/custom-plan/2067138786800111618"
   -H "Authorization: Bearer <token>"
 ```
 
-#### 3.9.5 返回示例
+#### 3.13.5 返回示例
 
 ```json
 {
@@ -990,7 +1405,7 @@ curl -X DELETE "http://localhost:18888/api/app/custom-plan/2067138786800111618"
 }
 ```
 
-#### 3.9.6 失败返回示例
+#### 3.13.6 失败返回示例
 
 方案不存在或不属于当前用户:
 
@@ -1002,33 +1417,33 @@ curl -X DELETE "http://localhost:18888/api/app/custom-plan/2067138786800111618"
 }
 ```
 
-#### 3.9.7 备注
+#### 3.13.7 备注
 
 - 删除为物理删除,不可恢复,请谨慎操作。
 - 仅允许删除创作人为当前用户的自定义模式方案,不存在或不属于当前用户的方案均返回 `1700` 错误。
 - 删除方案时会同步删除该方案下的所有穴位步骤。
 
-### 3.10 查询群组成员列表
+### 3.14 查询群组成员列表
 
-#### 3.10.1 接口用途
+#### 3.14.1 接口用途
 
 用于 APP 端查询指定家庭设备群组下的所有成员列表。
 
 后端会校验当前 APP 账号是否属于该家庭设备群组(`device_group_member.app_user_id = 当前账号ID`),仅返回当前账号所属群组的成员,越权或群组不存在时返回 `403` 错误。
 
-#### 3.10.2 请求信息
+#### 3.14.2 请求信息
 
 - 请求方式:`GET`
 - URI:`/api/app/group/{groupId}/members`
 - 完整示例:`http://localhost:18888/api/app/group/2001/members`
 
-#### 3.10.3 请求参数
+#### 3.14.3 请求参数
 
 | 参数名 | 类型 | 是否必填 | 说明 | 示例 |
 | --- | --- | --- | --- | --- |
 | `groupId` | `number` | 是 | 家庭设备群组 ID,对应 `device_group.id`,通过路径参数传递 | `2001` |
 
-#### 3.10.4 调用示例
+#### 3.14.4 调用示例
 
 ```http
 GET /api/app/group/2001/members HTTP/1.1
@@ -1041,7 +1456,7 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
   -H "Authorization: Bearer <token>"
 ```
 
-#### 3.10.5 返回示例
+#### 3.14.5 返回示例
 
 ```json
 {
@@ -1101,7 +1516,7 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
 }
 ```
 
-#### 3.10.6 字段说明
+#### 3.14.6 字段说明
 
 | 字段名 | 类型 | 说明 |
 | --- | --- | --- |
@@ -1132,7 +1547,7 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
 | `userCategoryId` | `number/null` | 用户分类 ID |
 | `profile` | `object` | 嵌套的完整用户档案对象,字段同上 |
 
-#### 3.10.7 失败返回示例
+#### 3.14.7 失败返回示例
 
 群组不存在或当前账号无权访问:
 
@@ -1144,7 +1559,7 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
 }
 ```
 
-#### 3.10.8 备注
+#### 3.14.8 备注
 
 - 越权校验在 Service 层完成,仅当 `device_group_member.app_user_id = 当前账号ID` 且 `status = 1` 时才返回成员列表。
 - 本接口不返回分页结构,按 `joinTime` 升序返回所有启用成员。
@@ -1152,9 +1567,9 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
 - 该接口只服务于家庭设备(`deviceType=1`)对应的群组,公共设备(`deviceType=2`)没有群组概念。
 - 不会返回 `status=0`(已移除)的成员记录。
 
-### 3.11 新增群组成员
+### 3.15 新增群组成员
 
-#### 3.11.1 接口用途
+#### 3.15.1 接口用途
 
 用于 APP 端让当前登录账号向指定的家庭设备群组添加新成员。
 
@@ -1169,13 +1584,13 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
 - 若手机号未注册,自动创建新 APP 账号和用户档案
 - 自动维护 `user_device` 绑定记录和 `user_acupoint` 穴位对照表(档案完整时)
 
-#### 3.11.2 请求信息
+#### 3.15.2 请求信息
 
 - 请求方式:`POST`
 - URI:`/api/app/group/{groupId}/members`
 - 完整示例:`http://localhost:18888/api/app/group/2001/members`
 
-#### 3.11.3 请求参数
+#### 3.15.3 请求参数
 
 请求体格式:`application/json`
 
@@ -1200,7 +1615,7 @@ curl -X GET "http://localhost:18888/api/app/group/2001/members" \
 | `fingerWidth3` | `number` | 否 | 三寸指宽(cm),男 4.5~8.0,女 4.0~7.0 | `6.50` |
 | `acupointTableId` | `number` | 否 | 已存在的穴位对照表 ID,一般由后端自动生成,无需传入 | `null` |
 
-#### 3.11.4 调用示例
+#### 3.15.4 调用示例
 
 ```http
 POST /api/app/group/2001/members HTTP/1.1
@@ -1235,7 +1650,7 @@ curl -X POST "http://localhost:18888/api/app/group/2001/members" \
   -d '{"name":"李四","gender":1,"age":30,"phone":"13900139000","provinceCode":"440000","cityCode":"440300","districtCode":"440305","address":"广东省深圳市南山区","shoulderWidth":42.50,"bodyHeight":85.00,"spineLength":48.00,"height":175.00,"weight":70.00,"fingerWidth1":2.20,"fingerWidth15":3.20,"fingerWidth3":6.50}'
 ```
 
-#### 3.11.5 返回示例
+#### 3.15.5 返回示例
 
 ```json
 {
@@ -1271,7 +1686,7 @@ curl -X POST "http://localhost:18888/api/app/group/2001/members" \
 }
 ```
 
-#### 3.11.6 失败返回示例
+#### 3.15.6 失败返回示例
 
 群组不存在或当前账号无权访问:
 
@@ -1323,7 +1738,7 @@ curl -X POST "http://localhost:18888/api/app/group/2001/members" \
 }
 ```
 
-#### 3.11.7 备注
+#### 3.15.7 备注
 
 - 越权校验在 Service 层完成,仅当 `device_group_member.app_user_id = 当前账号ID` 且 `status = 1` 时才允许新增。
 - 当 `phone` 已注册时,后端会自动关联已有 APP 账号;当 `phone` 未注册时,后端会自动创建新 APP 账号(`appId` 格式:`AJY` + 8 位数字)。
@@ -1333,9 +1748,9 @@ curl -X POST "http://localhost:18888/api/app/group/2001/members" \
 - 后端会自动维护新增成员与群组对应设备的 `user_device` 绑定记录。
 - `name` 字段必填且不可为空字符串。
 
-### 3.12 修改群组成员
+### 3.16 修改群组成员
 
-#### 3.12.1 接口用途
+#### 3.16.1 接口用途
 
 用于 APP 端让当前登录账号修改指定家庭设备群组下已有成员的用户档案信息。
 
@@ -1345,22 +1760,22 @@ curl -X POST "http://localhost:18888/api/app/group/2001/members" \
 - 手机号、APP 账号在同一群组内不能与其他成员冲突
 - 指宽数据需符合性别对应的合理范围
 
-#### 3.12.2 请求信息
+#### 3.16.2 请求信息
 
 - 请求方式:`PUT`
 - URI:`/api/app/group/{groupId}/members/{profileId}`
 - 完整示例:`http://localhost:18888/api/app/group/2001/members/124`
 
-#### 3.12.3 请求参数
+#### 3.16.3 请求参数
 
 | 参数名 | 类型 | 是否必填 | 说明 | 示例 |
 | --- | --- | --- | --- | --- |
 | `groupId` | `number` | 是 | 家庭设备群组 ID,对应 `device_group.id`,通过路径参数传递 | `2001` |
 | `profileId` | `number` | 是 | 成员的用户档案 ID,对应 `user_profile.id`,通过路径参数传递 | `124` |
 
-请求体格式:`application/json`,字段定义与 3.11.3 节"新增群组成员"完全一致,包括 `name`(必填)、`gender`、`age`、`phone`、`userCategoryId`、`address`、`shoulderWidth`、`bodyHeight`、`spineLength`、`height`、`weight`、`fingerWidth1`、`fingerWidth15`、`fingerWidth3`、`acupointTableId` 等字段。
+请求体格式:`application/json`,字段定义与 3.15.3 节"新增群组成员"完全一致,包括 `name`(必填)、`gender`、`age`、`phone`、`userCategoryId`、`address`、`shoulderWidth`、`bodyHeight`、`spineLength`、`height`、`weight`、`fingerWidth1`、`fingerWidth15`、`fingerWidth3`、`acupointTableId` 等字段。
 
-#### 3.12.4 调用示例
+#### 3.16.4 调用示例
 
 ```http
 PUT /api/app/group/2001/members/124 HTTP/1.1
@@ -1391,7 +1806,7 @@ curl -X PUT "http://localhost:18888/api/app/group/2001/members/124" \
   -d '{"name":"李四","gender":1,"age":31,"phone":"13900139000","shoulderWidth":42.50,"bodyHeight":85.00,"spineLength":48.00,"height":175.00,"weight":71.00,"fingerWidth1":2.20,"fingerWidth15":3.20,"fingerWidth3":6.50}'
 ```
 
-#### 3.12.5 返回示例
+#### 3.16.5 返回示例
 
 ```json
 {
@@ -1423,7 +1838,7 @@ curl -X PUT "http://localhost:18888/api/app/group/2001/members/124" \
 }
 ```
 
-#### 3.12.6 失败返回示例
+#### 3.16.6 失败返回示例
 
 群组不存在或当前账号无权访问:
 
@@ -1475,19 +1890,19 @@ curl -X PUT "http://localhost:18888/api/app/group/2001/members/124" \
 }
 ```
 
-#### 3.12.7 备注
+#### 3.16.7 备注
 
 - 越权校验在 Service 层完成,仅当 `device_group_member.app_user_id = 当前账号ID` 且 `status = 1` 时才允许修改。
-- 请求体字段语义与 3.11 节"新增群组成员"完全一致,区别在于"修改"语义:未传字段会以"覆盖式"方式写入数据库(`null` 即清空)。
+- 请求体字段语义与 3.15 节"新增群组成员"完全一致,区别在于"修改"语义:未传字段会以"覆盖式"方式写入数据库(`null` 即清空)。
 - 修改手机号时若该手机号已注册 APP 账号,会自动关联;未注册则保持原关联或自动创建。
 - 修改 `phone` 字段后,会同步更新 `device_group_member.app_user_id`。
 - 当修改后档案完整时,后端会自动重新生成穴位对照表。
 - 后端会自动维护成员与群组对应设备的 `user_device` 绑定记录。
 - `name` 字段必填。
 
-### 3.13 删除群组成员
+### 3.17 删除群组成员
 
-#### 3.13.1 接口用途
+#### 3.17.1 接口用途
 
 用于 APP 端让当前登录账号从指定的家庭设备群组中移除成员。
 
@@ -1498,20 +1913,20 @@ curl -X PUT "http://localhost:18888/api/app/group/2001/members/124" \
 
 删除采用软删除方式:将 `device_group_member.status` 置为 `0`,保留历史数据。
 
-#### 3.13.2 请求信息
+#### 3.17.2 请求信息
 
 - 请求方式:`DELETE`
 - URI:`/api/app/group/{groupId}/members/{profileId}`
 - 完整示例:`http://localhost:18888/api/app/group/2001/members/124`
 
-#### 3.13.3 请求参数
+#### 3.17.3 请求参数
 
 | 参数名 | 类型 | 是否必填 | 说明 | 示例 |
 | --- | --- | --- | --- | --- |
 | `groupId` | `number` | 是 | 家庭设备群组 ID,对应 `device_group.id`,通过路径参数传递 | `2001` |
 | `profileId` | `number` | 是 | 待移除成员的用户档案 ID,对应 `user_profile.id`,通过路径参数传递 | `124` |
 
-#### 3.13.4 调用示例
+#### 3.17.4 调用示例
 
 ```http
 DELETE /api/app/group/2001/members/124 HTTP/1.1
@@ -1524,7 +1939,7 @@ curl -X DELETE "http://localhost:18888/api/app/group/2001/members/124" \
   -H "Authorization: Bearer <token>"
 ```
 
-#### 3.13.5 返回示例
+#### 3.17.5 返回示例
 
 ```json
 {
@@ -1534,7 +1949,7 @@ curl -X DELETE "http://localhost:18888/api/app/group/2001/members/124" \
 }
 ```
 
-#### 3.13.6 失败返回示例
+#### 3.17.6 失败返回示例
 
 群组不存在或当前账号无权访问:
 
@@ -1566,18 +1981,18 @@ curl -X DELETE "http://localhost:18888/api/app/group/2001/members/124" \
 }
 ```
 
-#### 3.13.7 备注
+#### 3.17.7 备注
 
 - 越权校验在 Service 层完成,仅当 `device_group_member.app_user_id = 当前账号ID` 且 `status = 1` 时才允许删除。
 - 禁止删除 `app_user_id = 当前账号ID` 的成员记录,避免误操作把当前账号从群组中移除。
 - 删除为软删除(`status = 0`),不会物理删除 `device_group_member` 表记录,便于审计和恢复。
-- 删除后该成员将不再出现在"查询群组成员列表"接口(3.10 节)的返回结果中。
+- 删除后该成员将不再出现在"查询群组成员列表"接口(3.14 节)的返回结果中。
 - 本接口不会级联删除用户的 `user_profile` 档案或 `user_device` 绑定记录;如需彻底清理用户档案,请使用其他档案管理接口。
-- 已删除的成员记录若需要重新加入群组,请使用"新增群组成员"接口(3.11 节)重新创建。
+- 已删除的成员记录若需要重新加入群组,请使用"新增群组成员"接口(3.15 节)重新创建。
 
-### 3.14 查询当前账号个人资料
+### 3.18 查询当前账号个人资料
 
-#### 3.14.1 接口用途
+#### 3.18.1 接口用途
 
 用于 APP 端通过 Token 获取当前登录 APP 账号对应的个人资料。
 
@@ -1585,17 +2000,17 @@ curl -X DELETE "http://localhost:18888/api/app/group/2001/members/124" \
 
 本接口**不区分家庭设备和公共设备**,所有登录后的 APP 账号均可调用。
 
-#### 3.14.2 请求信息
+#### 3.18.2 请求信息
 
 - 请求方式:`GET`
 - URI:`/api/app/user/profile`
 - 完整示例:`http://localhost:18888/api/app/user/profile`
 
-#### 3.14.3 请求参数
+#### 3.18.3 请求参数
 
 无路径参数、无查询参数、无请求体。请求头需携带登录后的 Token。
 
-#### 3.14.4 调用示例
+#### 3.18.4 调用示例
 
 ```http
 GET /api/app/user/profile HTTP/1.1
@@ -1608,7 +2023,7 @@ curl -X GET "http://localhost:18888/api/app/user/profile" \
   -H "Authorization: Bearer <token>"
 ```
 
-#### 3.14.5 返回示例
+#### 3.18.5 返回示例
 
 ```json
 {
@@ -1646,7 +2061,7 @@ curl -X GET "http://localhost:18888/api/app/user/profile" \
 }
 ```
 
-#### 3.14.6 字段说明
+#### 3.18.6 字段说明
 
 | 字段名 | 类型 | 说明 |
 | --- | --- | --- |
@@ -1678,7 +2093,7 @@ curl -X GET "http://localhost:18888/api/app/user/profile" \
 | `userCategoryId` | `number/null` | 用户分类 ID,对应 `user_category.id` |
 | `profileComplete` | `boolean` | 用户档案是否已补全设备使用所需资料(`name`/`gender`/`age`/`shoulderWidth`/`bodyHeight`/`spineLength` 均已填写) |
 
-#### 3.14.7 失败返回示例
+#### 3.18.7 失败返回示例
 
 未登录或 Token 无效:
 
@@ -1700,16 +2115,16 @@ APP 账号不存在或已禁用:
 }
 ```
 
-#### 3.14.8 备注
+#### 3.18.8 备注
 
 - 本接口不接受任何参数,仅通过 Token 识别当前账号;不允许通过 `userId`、`appUserId`、`profileId` 等参数指定他人档案。
 - 若当前账号下无用户档案(`user_profile`),后端会自动创建一份以 `app_user_id` 关联的空档案,保证返回数据完整。
 - 响应中 `profileId` 与 `id` 内容一致,便于前端按不同字段名取值。
-- 该接口与"修改个人资料"(3.15 节)配套使用,修改后建议重新调用本接口刷新页面数据。
+- 该接口与"修改个人资料"(3.19 节)配套使用,修改后建议重新调用本接口刷新页面数据。
 
-### 3.15 修改当前账号个人资料
+### 3.19 修改当前账号个人资料
 
-#### 3.15.1 接口用途
+#### 3.19.1 接口用途
 
 用于 APP 端通过 Token 修改当前登录 APP 账号对应的个人资料。
 
@@ -1721,13 +2136,13 @@ APP 账号不存在或已禁用:
 
 本接口**不区分家庭设备和公共设备**,所有登录后的 APP 账号均可调用,是用户在公共设备场景下修改自己资料的主入口。
 
-#### 3.15.2 请求信息
+#### 3.19.2 请求信息
 
 - 请求方式:`PUT`
 - URI:`/api/app/user/profile`
 - 完整示例:`http://localhost:18888/api/app/user/profile`
 
-#### 3.15.3 请求参数
+#### 3.19.3 请求参数
 
 请求体格式:`application/json`
 
@@ -1754,7 +2169,7 @@ APP 账号不存在或已禁用:
 | `fingerWidth3` | `number/null` | 否 | 三寸指宽(cm),男 4.5~8.0,女 4.0~7.0 | `6.50` |
 | `acupointTableId` | `number/null` | 否 | 已存在的穴位对照表 ID,一般由后端自动生成,无需传入 | `null` |
 
-#### 3.15.4 调用示例
+#### 3.19.4 调用示例
 
 ```http
 PUT /api/app/user/profile HTTP/1.1
@@ -1791,7 +2206,7 @@ curl -X PUT "http://localhost:18888/api/app/user/profile" \
   -d '{"nickname":"张三","avatar":"https://cdn.example.com/avatar/17320687382.png","name":"张三","gender":1,"age":35,"phone":"13800138000","shoulderWidth":42.50,"bodyHeight":85.00,"spineLength":48.00,"height":175.00,"weight":70.00,"fingerWidth1":2.20,"fingerWidth15":3.20,"fingerWidth3":6.50}'
 ```
 
-#### 3.15.5 返回示例
+#### 3.19.5 返回示例
 
 ```json
 {
@@ -1829,7 +2244,7 @@ curl -X PUT "http://localhost:18888/api/app/user/profile" \
 }
 ```
 
-#### 3.15.6 失败返回示例
+#### 3.19.6 失败返回示例
 
 未登录或 Token 无效:
 
@@ -1871,19 +2286,17 @@ APP 账号不存在或已禁用:
 }
 ```
 
-#### 3.15.7 备注
+#### 3.19.7 备注
 
 - 本接口不接受路径参数与查询参数,仅通过 Token 识别当前账号;不允许通过 `userId`/`appUserId`/`profileId` 等参数修改他人档案。
-- 该接口与"修改群组成员"(3.12 节)的区别:
-  - 3.12 节需要 `groupId` + `profileId`,**仅服务家庭设备群组**,用于在群组维度编辑成员资料;
-  - 3.15 节只需要 Token,**同时适用于家庭设备和公共设备**,用于当前账号修改自己的资料;
-  - 公共设备场景下**不能**调用 3.12 节(无 `groupId`),应改用本接口。
+- 该接口与"修改群组成员"(3.16 节)的区别:
+  - 3.16 节需要 `groupId` + `profileId`,**仅服务家庭设备群组**,用于在群组维度编辑成员资料;
+  - 3.19 节只需要 Token,**同时适用于家庭设备和公共设备**,用于当前账号修改自己的资料;
+  - 公共设备场景下**不能**调用 3.16 节(无 `groupId`),应改用本接口。
 - 字段更新语义:
   - `nickname` / `avatar`:仅在传入非空字符串时更新到 `app_user` 表;
   - 其余字段:仅在传入非 `null` 时更新到 `user_profile` 表(`phone` 还会进行手机号格式校验)。
 - 当修改后档案完整时(`name`/`gender`/`age`/`shoulderWidth`/`bodyHeight`/`spineLength` 均已填写),后端会自动重新生成穴位对照表。
 - 不会影响 `device_group` 或 `user_device` 绑定关系,仅修改账号与档案自身数据。
-- 与"查询个人资料"(3.14 节)配套使用,修改成功后可直接复用返回结果刷新页面。
-
-
+- 与"查询个人资料"(3.18 节)配套使用,修改成功后可直接复用返回结果刷新页面。
 

+ 58 - 6
code/backend/src/main/java/com/aijiuyi/admin/controller/AppPlanController.java

@@ -17,9 +17,11 @@ import java.util.List;
 /**
  * App端用户自定义方案 Controller
  * 提供用户对自己自定义模式方案的增删改查接口
+ * 同时提供专业模式(modeType=2)和延年圣手模式(modeType=4)系统方案的查询接口,
+ * 这两类方案由后台预置并在所有用户间共享,无用户差异
  */
 @RestController
-@RequestMapping("/app/custom-plan")
+@RequestMapping("/app")
 public class AppPlanController {
 
     @Autowired
@@ -31,7 +33,7 @@ public class AppPlanController {
      * @param dto 方案信息
      * @return 方案ID
      */
-    @PostMapping
+    @PostMapping("/custom-plan")
     @Log(value = "新增用户自定义方案", module = "App方案", operationType = OperationType.INSERT)
     public Result<Long> create(@RequestBody @Valid PlanSaveDTO dto) {
         Long userId = RequestContext.getUserId();
@@ -44,7 +46,7 @@ public class AppPlanController {
      *
      * @return 方案列表
      */
-    @GetMapping("/list")
+    @GetMapping("/custom-plan/list")
     @Log(value = "查询用户自定义方案列表", module = "App方案", operationType = OperationType.QUERY)
     public Result<List<Plan>> list() {
         Long userId = RequestContext.getUserId();
@@ -57,7 +59,7 @@ public class AppPlanController {
      * @param id 方案ID
      * @return 方案详情
      */
-    @GetMapping("/{id}")
+    @GetMapping("/custom-plan/{id}")
     @Log(value = "查询用户自定义方案详情", module = "App方案", operationType = OperationType.QUERY)
     public Result<AppPlanVO> detail(@PathVariable Long id) {
         Long userId = RequestContext.getUserId();
@@ -70,7 +72,7 @@ public class AppPlanController {
      * @param dto 方案信息
      * @return 操作结果
      */
-    @PutMapping
+    @PutMapping("/custom-plan")
     @Log(value = "修改用户自定义方案", module = "App方案", operationType = OperationType.UPDATE)
     public Result<Void> update(@RequestBody @Valid PlanSaveDTO dto) {
         Long userId = RequestContext.getUserId();
@@ -84,11 +86,61 @@ public class AppPlanController {
      * @param id 方案ID
      * @return 操作结果
      */
-    @DeleteMapping("/{id}")
+    @DeleteMapping("/custom-plan/{id}")
     @Log(value = "删除用户自定义方案", module = "App方案", operationType = OperationType.DELETE)
     public Result<Void> delete(@PathVariable Long id) {
         Long userId = RequestContext.getUserId();
         planService.deleteUserPlan(id, userId);
         return Result.success();
     }
+
+    /**
+     * 查询专业模式方案列表(modeType=2)
+     * 所有用户共享,无用户差异,仅返回已发布状态、不含穴位步骤的方案基本信息
+     * 查看方案详情请调用 {@link #professionalPlanDetail(Long)}
+     *
+     * @return 专业模式方案列表
+     */
+    @GetMapping("/professional-plan/list")
+    @Log(value = "查询专业模式方案列表", module = "App方案", operationType = OperationType.QUERY)
+    public Result<List<Plan>> listProfessionalPlans() {
+        return Result.success(planService.listProfessionalPlans());
+    }
+
+    /**
+     * 查询专业模式方案详情(含穴位步骤)
+     *
+     * @param id 方案ID
+     * @return 专业模式方案详情
+     */
+    @GetMapping("/professional-plan/{id}")
+    @Log(value = "查询专业模式方案详情", module = "App方案", operationType = OperationType.QUERY)
+    public Result<AppPlanVO> professionalPlanDetail(@PathVariable Long id) {
+        return Result.success(planService.getProfessionalPlanDetail(id));
+    }
+
+    /**
+     * 查询延年圣手模式方案列表(modeType=4)
+     * 所有用户共享,无用户差异,仅返回已发布状态、不含穴位步骤的方案基本信息
+     * 查看方案详情请调用 {@link #masterPlanDetail(Long)}
+     *
+     * @return 延年圣手模式方案列表
+     */
+    @GetMapping("/master-plan/list")
+    @Log(value = "查询延年圣手模式方案列表", module = "App方案", operationType = OperationType.QUERY)
+    public Result<List<Plan>> listMasterPlans() {
+        return Result.success(planService.listMasterPlans());
+    }
+
+    /**
+     * 查询延年圣手模式方案详情(含穴位步骤)
+     *
+     * @param id 方案ID
+     * @return 延年圣手模式方案详情
+     */
+    @GetMapping("/master-plan/{id}")
+    @Log(value = "查询延年圣手模式方案详情", module = "App方案", operationType = OperationType.QUERY)
+    public Result<AppPlanVO> masterPlanDetail(@PathVariable Long id) {
+        return Result.success(planService.getMasterPlanDetail(id));
+    }
 }

+ 32 - 0
code/backend/src/main/java/com/aijiuyi/admin/service/PlanService.java

@@ -145,4 +145,36 @@ public interface PlanService extends IService<Plan> {
      * @param userId 用户ID
      */
     void deleteUserPlan(Long planId, Long userId);
+
+    /**
+     * 查询专业模式方案列表(modeType=2,所有用户共享,无差异)
+     * 仅返回已发布(status=1)的方案;不含穴位步骤,如需步骤请调用 {@link #getProfessionalPlanDetail(Long)}
+     *
+     * @return 专业模式方案列表
+     */
+    List<Plan> listProfessionalPlans();
+
+    /**
+     * 查询专业模式方案详情(含穴位步骤),校验 modeType=2
+     *
+     * @param planId 方案ID
+     * @return 专业模式方案详情
+     */
+    AppPlanVO getProfessionalPlanDetail(Long planId);
+
+    /**
+     * 查询延年圣手模式方案列表(modeType=4,所有用户共享,无差异)
+     * 仅返回已发布(status=1)的方案;不含穴位步骤,如需步骤请调用 {@link #getMasterPlanDetail(Long)}
+     *
+     * @return 延年圣手模式方案列表
+     */
+    List<Plan> listMasterPlans();
+
+    /**
+     * 查询延年圣手模式方案详情(含穴位步骤),校验 modeType=4
+     *
+     * @param planId 方案ID
+     * @return 延年圣手模式方案详情
+     */
+    AppPlanVO getMasterPlanDetail(Long planId);
 }

+ 73 - 0
code/backend/src/main/java/com/aijiuyi/admin/service/impl/PlanServiceImpl.java

@@ -629,4 +629,77 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
         planStepMapper.delete(new LambdaQueryWrapper<PlanStep>().eq(PlanStep::getPlanId, planId));
         LogUtil.info(PlanServiceImpl.class, "用户[{}]删除自定义方案[{}]", userId, planId);
     }
+
+    /**
+     * 查询专业模式方案列表(modeType=2,已发布状态)
+     * 所有用户共享,不区分用户,按 effectType 升序保证驱寒/祛湿等顺序稳定
+     *
+     * @return 专业模式方案列表
+     */
+    @Override
+    public List<Plan> listProfessionalPlans() {
+        return lambdaQuery()
+                .eq(Plan::getModeType, MODE_TYPE_PROFESSIONAL)
+                .eq(Plan::getStatus, 1)
+                .orderByAsc(Plan::getEffectType)
+                .orderByAsc(Plan::getId)
+                .list();
+    }
+
+    /**
+     * 查询专业模式方案详情(含穴位步骤),校验 modeType=2 且状态为已发布
+     *
+     * @param planId 方案ID
+     * @return 专业模式方案详情
+     */
+    @Override
+    public AppPlanVO getProfessionalPlanDetail(Long planId) {
+        return getSystemPlanDetail(planId, MODE_TYPE_PROFESSIONAL);
+    }
+
+    /**
+     * 查询延年圣手模式方案列表(modeType=4,已发布状态)
+     * 所有用户共享,按 ID 升序保证顺序稳定
+     *
+     * @return 延年圣手模式方案列表
+     */
+    @Override
+    public List<Plan> listMasterPlans() {
+        return lambdaQuery()
+                .eq(Plan::getModeType, MODE_TYPE_MASTER)
+                .eq(Plan::getStatus, 1)
+                .orderByAsc(Plan::getId)
+                .list();
+    }
+
+    /**
+     * 查询延年圣手模式方案详情(含穴位步骤),校验 modeType=4 且状态为已发布
+     *
+     * @param planId 方案ID
+     * @return 延年圣手模式方案详情
+     */
+    @Override
+    public AppPlanVO getMasterPlanDetail(Long planId) {
+        return getSystemPlanDetail(planId, MODE_TYPE_MASTER);
+    }
+
+    /**
+     * 通用系统方案详情查询:校验 modeType 与已发布状态,避免 APP 通过其他端点越权访问
+     *
+     * @param planId   方案ID
+     * @param modeType 期望的模式类型(专业模式/延年圣手)
+     * @return 方案详情
+     */
+    private AppPlanVO getSystemPlanDetail(Long planId, int modeType) {
+        Plan plan = getById(planId);
+        if (plan == null
+                || !Integer.valueOf(modeType).equals(plan.getModeType())
+                || !Integer.valueOf(1).equals(plan.getStatus())) {
+            throw new BusinessException(ResultCode.PLAN_NOT_FOUND);
+        }
+        AppPlanVO vo = new AppPlanVO();
+        BeanUtils.copyProperties(plan, vo);
+        vo.setSteps(getStepsByPlanId(planId));
+        return vo;
+    }
 }