# 追加体位 Modal 改造总结 ## 改造目标 将 `AppendViewModal` 从简单的体位列表展示改造为类似 register 页面的完整体位选择界面,包含过滤区域、体型结构交互、待选择区域和已选择区域。 ## 架构设计 ### 布局结构 ``` ┌─────────────────────────────────────────────────┐ │ Modal Header: "追加体位" │ ├──────────────┬──────────────┬───────────────────┤ │ │ │ │ │ 过滤区域 │ 体型结构 │ 待选择区域 │ │ (6 cols) │ (6 cols) │ (12 cols) │ │ │ │ │ │ │ ├───────────────────┤ │ │ │ 已选择区域 │ │ │ │ │ └──────────────┴──────────────┴───────────────────┘ │ Modal Footer: 取消 / 确认追加 (n) │ └─────────────────────────────────────────────────┘ ``` ### 组件层次 ``` AppendViewModal (主容器) ├── AppendViewFilterBar (过滤条) │ └── Segmented (协议/体位切换) ├── AppendBodyFilter (体型结构) │ ├── HumanBody (人体) │ └── AnimalBody (动物体) ├── AppendAvailableList (待选择列表) │ └── AppendViewCard[] (体位卡片) └── AppendSelectedList (已选择列表) └── Card[] (已选体位卡片) ``` ## 修改/新增文件 ### 1. 状态管理层 **src/states/exam/appendViewSlice.ts** (修改) 新增状态: - `currentSelectionType`: 'protocol' | 'view' - 当前选择类型 - `currentBodyPartId`: string | null - 当前身体部位ID 新增 actions: - `setSelectionType`: 切换协议/体位选择 - `setCurrentBodyPart`: 设置当前身体部位 ### 2. 组件层 **src/pages/exam/components/AppendViewFilterBar.tsx** (新建) 功能: - 提供协议/体位切换 (Segmented) - 切换时自动重新获取数据 - 与 appendView slice 集成 **src/pages/exam/components/AppendBodyFilter.tsx** (新建) 功能: - 显示 HumanBody 或 AnimalBody (根据产品类型) - 点击身体部位触发体位数据加载 - 高亮当前选中的身体部位 - 与 appendView slice 集成 **src/pages/exam/components/AppendAvailableList.tsx** (新建) 功能: - 显示可选择的体位列表 - 点击体位卡片添加到已选择列表 - 显示加载状态和空状态 - 复用 AppendViewCard 组件 **src/pages/exam/components/AppendSelectedList.tsx** (新建) 功能: - 显示已选择的体位列表 - 支持移除操作 (点击删除按钮) - 显示已选择数量 - 空状态提示 **src/pages/exam/components/AppendViewModal.tsx** (重构) 主要改动: - 采用三列布局 (6-6-12 分栏) - 右侧分为上下两部分 (待选择/已选择) - 移除旧的列表渲染逻辑 - 集成新的四个子组件 - Modal 宽度调整为 90% - 高度设置为 70vh ## 数据流 ### 初始化流程 1. Modal 打开 → `open` prop 变为 true 2. useEffect 检测到打开 → 初始化 `currentBodyPartId` 为当前检查的身体部位 3. AppendBodyFilter 根据 `currentBodyPartId` 高亮对应部位 4. 用户可以点击其他身体部位切换 ### 体位选择流程 1. 用户点击身体部位 → `setCurrentBodyPart(bodyPartId)` 2. 触发 `fetchAvailableViewsThunk` 获取该部位的体位 3. AppendAvailableList 显示可用体位列表 4. 用户点击体位卡片 → `toggleViewSelection(view)` 5. 体位添加到 `selectedViews` 6. AppendSelectedList 显示已选择的体位 7. 点击确认 → `appendViewsThunk` 追加体位到 Study ### 协议/体位切换流程 1. 用户切换 Segmented → `setSelectionType(type)` 2. 如果已选择身体部位 → 重新获取数据 3. 列表更新为对应类型的数据 ## 关键设计决策 ### 1. 状态管理分离 - appendView slice 专门管理追加体位相关的状态 - 不复用 register 页面的 viewSelection slice - 避免状态冲突和耦合 ### 2. 组件复用策略 - 新建组件而非直接复用 register 组件 - 保持组件职责清晰 - 便于独立维护和测试 ### 3. 用户体验优化 - 默认加载当前检查的身体部位 - 支持切换身体部位查看其他体位 - 已选择区域实时反馈 - 清晰的数量提示 ## 后续优化建议 1. **协议支持**:目前只实现了体位选择,协议选择功能可以后续添加 2. **搜索功能**:可在过滤区域添加搜索框 3. **批量操作**:支持全选/清空等批量操作 4. **响应式布局**:针对不同屏幕尺寸优化布局 5. **加载优化**:可以缓存已加载的身体部位数据 ## 测试要点 - [ ] Modal 打开时正确初始化身体部位 - [ ] 点击身体部位能正确加载体位列表 - [ ] 协议/体位切换功能正常 - [ ] 体位选择和移除功能正常 - [ ] 确认追加成功后正确更新 bodyPositionList - [ ] 取消操作正确清空选择状态 - [ ] 错误提示正常显示 - [ ] 加载状态正常显示