# BusinessZone.tsx 文档 ## 文件职责 `BusinessZone` 是业务功能导航菜单组件,负责: 1. **业务功能导航**:展示系统主要业务功能入口(患者管理、检查、图像处理、打印等) 2. **权限控制**:根据当前位置和数据状态动态计算按钮可用性 3. **层级菜单**:支持一级菜单和子菜单(如患者管理包含注册、任务列表等) 4. **国际化支持**:所有菜单项标签支持多语言 5. **视觉反馈**:高亮当前选中的菜单项 ## 实现方式 ### 1. 技术栈 - **React**:组件化开发 - **Redux**:全局状态管理(业务流程、权限、数据选择状态) - **react-intl**:国际化(FormattedMessage) - **Ant Design**:Flex 布局 - **权限系统**:`permissionMap` 模块的权限计算 ### 2. 核心数据流 ``` Redux State (currentKey, dataState) ↓ getBtnAvailability() ↓ btnAvailability 对象 ↓ useItems() Hook ↓ items 菜单配置 ↓ 渲染菜单按钮 ``` ### 3. 菜单结构 ``` BusinessZone ├── 患者管理 (patient_management) - 可展开 │ ├── 注册 (register) │ ├── 任务列表 (worklist) │ ├── 历史列表 (historylist) │ ├── 归档列表 (archivelist) │ ├── 回收站 (bin) │ └── 输出列表 (outputlist) ├── 检查 (exam) ├── ———— (分隔线) ├── 图像处理 (process) └── 打印 (print) ``` ## 实现思路 ### 1. 动态权限计算 根据当前业务流程位置和数据状态计算每个按钮的可用性: ```typescript // 1. 获取当前位置 const currentKey = useSelector(state => state.BusinessFlow.currentKey); // 2. 根据位置获取数据状态 const dataState: DataState = useSelector((state: RootState) => { if (currentKey === 'worklist') { return { hasSelection: state.workSelection.selectedIds.length > 0, hasExposedImage: /* ... */ }; } // ... 其他位置 }); // 3. 计算按钮可用性 const btnAvailability = getBtnAvailability(currentKey, dataState); ``` **权限计算逻辑**: - 不同的业务流程位置(LocationKey)有不同的权限规则 - 某些操作需要数据状态支持(如选择了项目、有曝光图像等) - `getBtnAvailability` 函数封装了复杂的权限逻辑 ### 2. 菜单配置生成 使用自定义 Hook `useItems` 生成菜单配置: ```typescript function useItems(btnAvailability: Record) { return [ { key: 'patient_management', label: , icon: 'Registration', disabled: !btnAvailability['patient_management'], children: [/* 子菜单 */] }, // ... 其他菜单项 ]; } ``` **设计优势**: - 集中管理菜单配置 - 权限状态自动绑定到 disabled 属性 - 支持国际化标签 - 支持分隔线和层级结构 ### 3. 层级菜单展开/收起 使用局部状态控制子菜单的显示: ```typescript const [floatingMenuVisible, setFloatingMenuVisible] = useState(false); const handlePatientManagementClick = () => { setFloatingMenuVisible(!floatingMenuVisible); }; ``` **交互流程**: 1. 点击"患者管理" → 切换 `floatingMenuVisible` 状态 2. 渲染条件:`floatingMenuVisible && <子菜单>` 3. 子菜单项点击 → 调用 `onMenuClick` 回调 ### 4. 当前菜单高亮 通过动态生成 className 实现当前菜单项的视觉高亮: ```typescript const buttonClassNameGenerator = ( itemkey: string, currentkey: string ): string => { const originalName = 'w-full max-w-full whitespace-nowrap ...'; if (itemkey === currentkey) { return originalName + ' border border-red-500 '; } return originalName; }; ``` ### 5. 文本溢出处理 菜单按钮使用多层溢出控制确保文本不会撑破布局: ```typescript // IconButton 样式 style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} // 内部 span 样式 ``` **技巧**: - 外层容器 `overflow: hidden` 限制边界 - `textOverflow: ellipsis` 显示省略号 - `whiteSpace: nowrap` 禁止换行 - `flex: 1` + `minWidth: 0` 允许弹性收缩 ## 边界 ### 输入 - **Props**: - `onMenuClick?: (key: string) => void`:菜单项点击回调 - **Redux State**: - `currentKey`:当前业务流程标识(BusinessFlowSlice) - `workSelection.selectedIds`:任务列表选择状态 - `historySelection.selectedIds`:历史列表选择状态 - `bodyPositionList.exposureStatus`:曝光状态 - `permission.triggerPermissionCalc`:权限重新计算触发器 ### 输出 - **渲染输出**:业务功能菜单,包括: - 一级菜单按钮 - 子菜单按钮(患者管理展开时) - 分隔线 - 当前菜单高亮 - 禁用状态显示 - **事件派发**: - `onMenuClick(key)`:通知父组件切换业务流程 ### 职责边界 #### 负责 - ✅ 业务功能菜单的渲染 - ✅ 根据权限计算按钮可用性 - ✅ 子菜单的展开/收起交互 - ✅ 当前菜单项的视觉反馈 - ✅ 国际化标签显示 - ✅ 文本溢出处理 #### 不负责 - ❌ 权限规则的定义(由 `permissionMap` 模块负责) - ❌ 业务流程的实际切换(由父组件处理 onMenuClick) - ❌ 数据状态的维护(由各自的 Redux slice 负责) - ❌ 图标的加载和渲染(由 Icon 组件负责) - ❌ 国际化文本的翻译(由 react-intl 和语言包负责) ## 涉及概念 ### 1. 权限控制(Permission Control) 根据用户角色、当前状态、数据条件等因素动态控制功能可用性。 **实现方式**: ```typescript const btnAvailability = getBtnAvailability( currentKey as LocationKey, dataState ); disabled: !btnAvailability['exam']; ``` **关键点**: - 位置相关:不同位置有不同的权限规则 - 数据相关:某些操作需要数据支持(如选择、曝光) - 集中计算:权限逻辑集中在 `permissionMap` 模块 ### 2. 国际化(Internationalization, i18n) 支持多语言界面,根据用户语言设置显示对应文本。 **使用方式**: ```typescript ``` **组成部分**: - `id`:翻译键,在语言包中查找 - `defaultMessage`:找不到翻译时的默认文本 ### 3. 自定义 Hook 将组件逻辑提取为可复用的 Hook 函数。 **示例**: ```typescript function useItems(btnAvailability: Record) { return [ /* 菜单配置 */ ]; } ``` **优势**: - 分离关注点:UI 渲染和数据逻辑分离 - 可测试性:可以单独测试 Hook - 可读性:主组件代码更简洁 ### 4. 条件渲染(Conditional Rendering) 根据状态或条件决定是否渲染元素。 **方式**: ```typescript // 三元运算符 {item.type === 'divider' ?
: } // 逻辑与运算符 {item.key === 'patient_management' && floatingMenuVisible && } ``` ### 5. 动态 ClassName 根据条件动态生成 CSS 类名。 **实现**: ```typescript const buttonClassNameGenerator = (itemkey: string, currentkey: string) => { const base = 'w-full ...'; return itemkey === currentkey ? base + ' border border-red-500' : base; }; ``` **应用**: - 当前菜单高亮 - 不同状态的样式 - 响应式样式 ### 6. 状态提升(Lifting State Up) 子菜单的展开状态在本组件维护,而菜单选择状态由父组件通过 Redux 维护。 **分工**: - 本地状态:UI 交互状态(展开/收起) - 全局状态:业务状态(当前选择的菜单) ### 7. Flexbox 布局 使用 Flex 容器实现垂直菜单布局。 ```typescript ``` **关键属性**: - `vertical`:垂直方向排列 - `flex-grow`:占据剩余空间 - `overflow-y-auto`:内容溢出时显示滚动条 - `min-h-0`:允许收缩到最小高度 ### 8. 数据驱动的禁用状态 按钮的可用性完全由数据驱动,而非硬编码。 **流程**: ``` 数据状态变化 → 权限重新计算 → disabled 属性更新 → UI 自动更新 ``` ### 9. 选择器优化(Selector Optimization) 使用 `useSelector` 订阅 Redux 状态,只在相关状态变化时重新渲染。 **示例**: ```typescript // 订阅特定状态切片 const currentKey = useSelector( (state: RootState) => state.BusinessFlow.currentKey ); // 触发器模式:订阅触发权限重新计算 useSelector((state: RootState) => state.permission.triggerPermissionCalc); ``` ## 注意事项 ### 1. 调试代码未清理 代码中包含多个 `console.log` 语句: ```typescript disabled: console.log(`我要看看exam对应的值:${!btnAvailability['exam']}`), !btnAvailability['exam']; ``` **问题**: - 影响代码可读性 - 生产环境不应有调试日志 - 使用逗号表达式比较晦涩 **改进建议**:移除或使用专门的日志系统 ### 2. 注释代码未清理 文件中有大量被注释掉的代码: ```typescript // const [visibleItems, setVisibleItems] = useState(items); // const businessZoneRef = useRef(null); // useEffect(() => { ... } ``` **建议**:使用版本控制系统管理代码历史,移除无用注释 ### 3. 默认消息不规范 国际化的 `defaultMessage` 使用了非标准文本: ```typescript defaultMessage={'语言包中没有定义patient的翻译文本'} ``` **问题**: - 不是有效的回退文本 - 用户看到会困惑 **改进建议**:使用英文或有意义的默认文本 ### 4. 按钮禁用逻辑问题 子菜单按钮的禁用状态使用的是父菜单的 `item.disabled`: ```typescript ``` **潜在问题**:子菜单项无法独立控制禁用状态 ### 5. 数据状态计算可优化 `dataState` 的计算逻辑有重复代码,可以提取为独立函数。 ### 6. 触发器订阅用途不明确 ```typescript useSelector((state: RootState) => state.permission.triggerPermissionCalc); ``` 这个订阅没有使用返回值,仅用于触发重新渲染。更好的方式是明确说明这个订阅的用途。 ### 7. 图标名称重复使用 许多菜单项都使用 'Registration' 图标,可能是占位符,需要更新为正确的图标。 ## 相关文件 - `src/domain/permissionMap.ts`:权限规则定义和计算逻辑 - `src/states/BusinessFlowSlice.ts`:业务流程状态管理 - `src/states/workSelection.ts`:任务列表选择状态 - `src/states/historySelection.ts`:历史列表选择状态 - `src/states/bodyPositionList.ts`:体位列表和曝光状态 - `src/states/permission.ts`:权限状态管理 - `src/components/IconButton.tsx`:图标按钮组件 - `src/components/Icon/index.tsx`:图标组件 - `src/assets/i18n/`:国际化语言包