design.md 6.6 KB

设计方案:穴位定位功能

架构设计

数据流

用户信息录入 → 体型数据处理 → 穴位坐标计算 → 经络图渲染 → 艾灸执行
     │              │              │              │
     │              │              │              ▼
     │              │              │        穴位选择/定制
     │              │              │              │
     └──────────────┴──────────────┴──────────────┘
                          ↕
                    穴位数据库

技术选型

层级 技术 理由
前端可视化 Canvas + SVG 经络图绘制,支持缩放、点击交互
状态管理 Zustand 穴位选择状态,轻量高效
数据格式 JSON + 静态资源 穴位数据存储,易于维护
坐标计算 TypeScript 类型安全,精度控制
API RESTful 与现有架构一致

数据模型

穴位数据结构

// 穴位定义
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
}

穴位数据库(初始数据)

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: []
  },
  // ... 其他穴位
];

穴位坐标计算算法

基于体型的缩放因子

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 获取某经络的所有穴位

请求/响应示例

// 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 # 推荐列表

经络图组件

// 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,可随时回退到上一稳定状态。