Explorar o código

feat(openspec): 创建穴位定位功能提案

- 提取需求文档中的穴位定位相关需求
- 识别12个常用穴位及其坐标关系
- 设计基于体型的穴位坐标计算算法
- 规划经络图可视化组件架构
- 定义API接口和数据模型

角色: [需求工程师] + [系统分析员]
liaoxg hai 5 meses
pai
achega
5ccad5a904

+ 262 - 0
openspec/changes/acupoint-location/design.md

@@ -0,0 +1,262 @@
+# 设计方案:穴位定位功能
+
+## 架构设计
+
+### 数据流
+
+```
+用户信息录入 → 体型数据处理 → 穴位坐标计算 → 经络图渲染 → 艾灸执行
+     │              │              │              │
+     │              │              │              ▼
+     │              │              │        穴位选择/定制
+     │              │              │              │
+     └──────────────┴──────────────┴──────────────┘
+                          ↕
+                    穴位数据库
+```
+
+### 技术选型
+
+| 层级 | 技术 | 理由 |
+|------|------|------|
+| 前端可视化 | Canvas + SVG | 经络图绘制,支持缩放、点击交互 |
+| 状态管理 | Zustand | 穴位选择状态,轻量高效 |
+| 数据格式 | JSON + 静态资源 | 穴位数据存储,易于维护 |
+| 坐标计算 | TypeScript | 类型安全,精度控制 |
+| API | RESTful | 与现有架构一致 |
+
+## 数据模型
+
+### 穴位数据结构
+
+```typescript
+// 穴位定义
+interface Acupoint {
+  id: string;           // 穴位编号
+  name: string;         // 穴位名称
+  pinyin: string;       // 拼音
+  meridian: string;     // 所属经络
+  location: {           // 定位描述
+    anatomical: string; // 解剖位置描述
+    relative: string;   // 相对位置描述(如:大椎穴下3寸)
+  };
+  offset: {             // 相对于大椎穴的偏移(基于标准体型)
+    x: number;          // 横向偏移(cm)
+    y: number;          // 纵向偏移(cm)
+  };
+  effects: string[];    // 功效(驱寒、祛风等)
+  contraindications: string[]; // 禁忌
+}
+
+// 用户体型数据
+interface BodyData {
+  userId: string;
+  gender: 'male' | 'female';
+  age: number;
+  height: number;       // cm
+  weight: number;       // kg
+  shoulderHeight?: number; // 肩高(传感器检测)
+  shoulderWidth?: number;  // 肩宽(传感器检测)
+}
+
+// 计算后的穴位位置
+interface CalculatedAcupoint {
+  acupointId: string;
+  position: {
+    x: number;          // 实际坐标(cm)
+    y: number;
+  };
+  confidence: number;   // 置信度 0-1
+}
+```
+
+### 穴位数据库(初始数据)
+
+```typescript
+const ACUPOINT_DATABASE: Acupoint[] = [
+  {
+    id: 'dazhui',
+    name: '大椎穴',
+    pinyin: 'dazhui',
+    meridian: '督脉',
+    location: {
+      anatomical: '第七颈椎棘突下凹陷中',
+      relative: '基准穴位,位于背部最高点'
+    },
+    offset: { x: 0, y: 0 },
+    effects: ['驱寒', '祛湿', '解表', '清热'],
+    contraindications: ['孕妇慎用']
+  },
+  {
+    id: 'shenzhu',
+    name: '身柱穴',
+    pinyin: 'shenzhu',
+    meridian: '督脉',
+    location: {
+      anatomical: '第三胸椎棘突下凹陷中',
+      relative: '大椎穴下3寸'
+    },
+    offset: { x: 0, y: -7.5 },
+    effects: ['止咳平喘', '安神'],
+    contraindications: []
+  },
+  // ... 其他穴位
+];
+```
+
+## 穴位坐标计算算法
+
+### 基于体型的缩放因子
+
+```typescript
+function calculateScaleFactor(bodyData: BodyData): { x: number; y: number } {
+  // 标准体型参考(中国成年人平均)
+  const STANDARD = {
+    male: { height: 170, weight: 65, shoulderWidth: 42 },
+    female: { height: 158, weight: 55, shoulderWidth: 36 }
+  };
+
+  const ref = STANDARD[bodyData.gender];
+
+  // 高度缩放因子
+  const heightScale = bodyData.height / ref.height;
+
+  // 宽度缩放因子(肩宽与身高正相关)
+  const estimatedShoulderWidth = bodyData.shoulderWidth || 
+    (bodyData.gender === 'male' ? bodyData.height * 0.247 : bodyData.height * 0.228);
+  const widthScale = estimatedShoulderWidth / ref.shoulderWidth;
+
+  return { x: widthScale, y: heightScale };
+}
+
+function calculateAcupointPosition(
+  acupoint: Acupoint,
+  bodyData: BodyData
+): CalculatedAcupoint {
+  const scale = calculateScaleFactor(bodyData);
+
+  // 应用缩放因子
+  const position = {
+    x: acupoint.offset.x * scale.x,
+    y: acupoint.offset.y * scale.y
+  };
+
+  // 置信度计算(基于数据完整性)
+  let confidence = 0.8; // 基础置信度
+  if (bodyData.shoulderHeight) confidence += 0.1;
+  if (bodyData.shoulderWidth) confidence += 0.1;
+
+  return { acupointId: acupoint.id, position, confidence };
+}
+```
+
+## API 设计
+
+### 端点
+
+| 方法 | 路径 | 描述 |
+|------|------|------|
+| GET | `/api/acupoints` | 获取所有穴位列表 |
+| GET | `/api/acupoints/:id` | 获取单个穴位详情 |
+| POST | `/api/acupoints/calculate` | 计算用户穴位位置 |
+| POST | `/api/acupoints/recommend` | 基于症状推荐穴位 |
+| GET | `/api/acupoints/meridian/:name` | 获取某经络的所有穴位 |
+
+### 请求/响应示例
+
+```typescript
+// POST /api/acupoints/calculate
+// Request
+{
+  "userId": "user_001",
+  "bodyData": {
+    "gender": "male",
+    "height": 175,
+    "weight": 70
+  }
+}
+
+// Response
+{
+  "userId": "user_001",
+  "basePoint": {
+    "id": "dazhui",
+    "name": "大椎穴",
+    "position": { "x": 0, "y": 0 }
+  },
+  "acupoints": [
+    {
+      "acupointId": "shenzhu",
+      "name": "身柱穴",
+      "position": { "x": 0, "y": -7.72 },
+      "confidence": 0.8
+    },
+    // ...
+  ]
+}
+```
+
+## 前端组件设计
+
+### 组件结构
+
+```
+src/components/
+├── MeridianGraph/
+│   ├── MeridianGraph.tsx      # 经络图主组件
+│   ├── AcupointMarker.tsx     # 穴位标记点
+│   ├── AcupointTooltip.tsx    # 穴位信息浮层
+│   └── MeridianGraph.types.ts
+├── AcupointSelector/
+│   ├── AcupointSelector.tsx   # 穴位选择器
+│   ├── AcupointCard.tsx       # 穴位卡片
+│   └── AcupointFilter.tsx     # 穴位筛选
+└── AcupointRecommendation/
+    ├── SymptomInput.tsx       # 症状输入
+    └── RecommendationList.tsx # 推荐列表
+```
+
+### 经络图组件
+
+```tsx
+// MeridianGraph.tsx
+interface MeridianGraphProps {
+  acupoints: CalculatedAcupoint[];
+  selectedIds: string[];
+  onSelect: (id: string) => void;
+  mode: 'view' | 'select' | 'edit';
+}
+
+export function MeridianGraph({ acupoints, selectedIds, onSelect, mode }: MeridianGraphProps) {
+  // 人体背部轮廓 SVG
+  // 穴位点击交互
+  // 缩放和平移
+  // 穴位高亮显示
+}
+```
+
+## 实施步骤
+
+### Wave 1: 数据层
+1. 创建穴位数据库 JSON
+2. 实现坐标计算算法
+3. 编写单元测试
+
+### Wave 2: API 层
+1. 创建 `/api/acupoints` 路由
+2. 实现计算和推荐接口
+3. API 文档
+
+### Wave 3: 前端可视化
+1. 经络图 SVG 组件
+2. 穴位交互逻辑
+3. 穴位选择器组件
+
+### Wave 4: 集成
+1. 与用户信息模块集成
+2. 与艾灸方案模块集成
+3. 端到端测试
+
+## 回滚策略
+
+每个 Wave 完成后提交 Git,可随时回退到上一稳定状态。

+ 88 - 0
openspec/changes/acupoint-location/proposal.md

@@ -0,0 +1,88 @@
+# 提案:穴位定位功能
+
+## 背景
+
+根据 `需求材料/艾灸椅功能定义-最新.xlsx` 文档,45°艾灸椅需要实现智能穴位定位功能:
+
+### 需求文档关键内容
+
+1. **体形检测**(行648-658):
+   - 产品配备传感装置可自动检测用户肩高及肩宽
+   - 为算法提供穴位定位基准
+   - 带艾灸功能模式下,用户点击"开始"后开始自动检测
+
+2. **穴位定位**(行660-670):
+   - 根据体型数据,判断用户"大椎穴"位置
+   - 以"大椎穴"为起点,为艾灸方案各穴位提供坐标参数
+   - 注:目前只能实现检测肩高,穴位定位需要借助用户录入体形数据
+
+3. **支持的穴位**(从灸方参数中提取):
+   | 穴位名称 | 出现场景 |
+   |---------|----------|
+   | 大椎穴 | 一键艾灸、驱寒、祛湿 |
+   | 身柱穴 | 一键艾灸 |
+   | 至阳穴 | 一键艾灸、扶阳 |
+   | 命门穴 | 一键艾灸、扶阳 |
+   | 腰阳关穴 | 一键艾灸 |
+   | 风门穴 | 祛风 |
+   | 秉风穴 | 祛风 |
+   | 膈俞穴 | 化瘀、活血 |
+   | 八髎穴 | 化瘀 |
+   | 肺俞穴 | 化痰、养颜 |
+   | 脾俞穴 | 养颜 |
+   | 肾俞穴 | 养颜 |
+
+4. **用户信息要求**(行1008-1018):
+   - 用户需录入:名称、性别、年龄、身高、体重、指纹
+   - 身高:40-190cm(两位小数)
+   - 体重:10-150kg(两位小数)
+   - 每个用户至少录入两个有效指纹
+
+## 目标
+
+实现基于用户体型数据 + 肩高检测的智能穴位定位系统,支持:
+- 自动计算各穴位相对于大椎穴的坐标偏移
+- 在经络图上可视化展示穴位位置
+- 为用户提供穴位选择和定制功能
+
+## 范围
+
+### 核心功能
+1. 穴位数据库管理(中医标准数据)
+2. 体型数据驱动的穴位坐标计算
+3. 经络图可视化交互
+4. AI 辅助穴位推荐(基于症状)
+
+### 不在范围内
+- 摄像头图像识别(硬件限制)
+- 实时穴位跟踪
+- 多人同时艾灸
+
+## 预期成果
+
+- [ ] 穴位数据库(12个常用穴位)
+- [ ] 穴位坐标计算算法
+- [ ] 经络图可视化组件
+- [ ] 症状-穴位推荐逻辑
+- [ ] API 接口设计
+
+## 依赖
+
+- 用户信息管理模块
+- 艾灸方案执行模块
+- 中医标准穴位数据(GB/T 12346-2006)
+
+## 风险评估
+
+| 风险 | 概率 | 影响 | 缓解措施 |
+|------|------|------|----------|
+| 穴位定位精度不足 | 高 | 高 | 结合用户反馈微调,提供手动校准 |
+| 穴位数据标准化困难 | 中 | 中 | 参考国家标准,与中医专家确认 |
+| 用户录入数据误差 | 中 | 中 | 提供可视化引导,智能纠错 |
+
+## 验收标准
+
+1. 用户输入身高、体重后,系统能计算并展示 12 个穴位位置
+2. 经络图支持点击穴位查看详情(名称、功效、位置说明)
+3. 用户选择症状后,系统能推荐合适的穴位组合
+4. 穴位坐标误差在 ±2cm 范围内(基于用户体型数据)

+ 80 - 0
openspec/changes/acupoint-location/tasks.md

@@ -0,0 +1,80 @@
+# 任务清单:穴位定位功能
+
+## Wave 1: 数据层
+
+- [ ] 创建 `packages/shared/src/data/acupoints.json` 穴位数据库
+- [ ] 创建 `packages/shared/src/types/acupoint.ts` 类型定义
+- [ ] 创建 `packages/shared/src/utils/acupointCalculator.ts` 坐标计算算法
+- [ ] 编写穴位计算单元测试
+- [ ] 编写数据验证测试
+
+## Wave 2: API 层
+
+- [ ] 创建 `apps/api/src/routes/acupoints.ts` 路由
+- [ ] 实现 `GET /api/acupoints` 获取穴位列表
+- [ ] 实现 `GET /api/acupoints/:id` 获取单个穴位
+- [ ] 实现 `POST /api/acupoints/calculate` 计算穴位位置
+- [ ] 实现 `POST /api/acupoints/recommend` 症状推荐
+- [ ] 创建 API 文档
+
+## Wave 3: 前端可视化
+
+- [ ] 创建 `apps/web/src/components/MeridianGraph/` 目录
+- [ ] 实现 `MeridianGraph.tsx` 经络图主组件
+- [ ] 实现 `AcupointMarker.tsx` 穴位标记点
+- [ ] 实现 `AcupointTooltip.tsx` 穴位信息浮层
+- [ ] 创建 `apps/web/src/components/AcupointSelector/` 目录
+- [ ] 实现 `AcupointSelector.tsx` 穴位选择器
+- [ ] 实现 `AcupointCard.tsx` 穴位卡片
+- [ ] 创建经络图 SVG 资源
+
+## Wave 4: 集成
+
+- [ ] 创建 Zustand store: `useAcupointStore`
+- [ ] 集成用户信息模块
+- [ ] 集成艾灸方案模块
+- [ ] 创建穴位定位页面
+- [ ] 端到端测试
+
+## Wave 5: 验收
+
+- [ ] 验证 12 个穴位坐标计算正确
+- [ ] 验证经络图交互功能
+- [ ] 验证症状推荐逻辑
+- [ ] 验证与艾灸方案集成
+- [ ] 归档变更 `/opsx:archive acupoint-location`
+
+## 数据准备
+
+需要准备的穴位数据(12个):
+
+| ID | 穴位名称 | 相对大椎穴偏移 | 功效 |
+|----|----------|---------------|------|
+| dazhui | 大椎穴 | (0, 0) | 驱寒、祛湿、解表 |
+| shenzhu | 身柱穴 | (0, -7.5cm) | 止咳平喘、安神 |
+| zhiyang | 至阳穴 | (0, -15cm) | 宽胸理气 |
+| mingmen | 命门穴 | (0, -30cm) | 补肾壮阳 |
+| yaoyangguan | 腰阳关穴 | (0, -35cm) | 强腰健肾 |
+| fengmen | 风门穴 | (±4cm, -3cm) | 祛风解表 |
+| bingfeng | 秉风穴 | (±6cm, -8cm) | 祛风散寒 |
+| geshu | 膈俞穴 | (±4cm, -17cm) | 活血化瘀 |
+| baliao | 八髎穴 | (0, -33cm) | 调理下焦 |
+| feishu | 肺俞穴 | (±4cm, -10cm) | 化痰止咳 |
+| pishu | 脾俞穴 | (±4cm, -20cm) | 健脾养血 |
+| shenshu | 肾俞穴 | (±4cm, -22cm) | 补肾益气 |
+
+## 技能需求
+
+| 技能 | 用途 | 状态 |
+|------|------|------|
+| test-driven-development | TDD 开发 | 需安装 Superpowers |
+| design-taste-frontend | UI 设计 | 已安装 |
+| verification-before-completion | 验收测试 | 需安装 Superpowers |
+
+## 验收标准
+
+- [ ] `pnpm test` 全部通过
+- [ ] 穴位坐标误差 ≤ 2cm
+- [ ] 经络图支持点击、缩放
+- [ ] 症状推荐覆盖率 80%+
+- [ ] API 响应时间 < 200ms