فهرست منبع

docs: 添加急诊流程文档,详细说明token获取与传递机制 in docs/实现/急诊流程.md

sw 1 هفته پیش
والد
کامیت
fe3ae3758c
1فایلهای تغییر یافته به همراه469 افزوده شده و 0 حذف شده
  1. 469 0
      docs/实现/急诊流程.md

+ 469 - 0
docs/实现/急诊流程.md

@@ -0,0 +1,469 @@
+# 急诊流程 - Token 获取与传递机制
+
+## 概述
+
+本文档详细说明了系统中急诊模式的完整逻辑,包括 guest token 的获取、存储、传递机制以及急诊操作的完整流程。
+
+## 1. Token 的来源(初始化阶段)
+
+### 相关文件
+
+- `src/API/softwareInfo.ts` - API 调用
+- `src/states/productSlice.ts` - Redux 状态管理
+
+### 获取流程
+
+在系统启动时,通过 `initializeProductState` thunk 自动获取软件信息:
+
+```typescript
+// API 调用
+GET / pub / software_info;
+
+// 返回数据结构
+interface SoftwareInfo {
+  guest: string; // 用于急诊访问数据的 token
+  FPD: string;
+  GEN: string;
+  language: string[];
+  product: string;
+  sn: string;
+  server: Record<string, any>;
+}
+```
+
+### 存储到 Redux
+
+```typescript
+// productSlice.ts
+export const initializeProductState = createAsyncThunk(
+  'product/initializeProductState',
+  async () => {
+    const softwareInfo = await fetchSoftwareInfo();
+    return {
+      productName: softwareInfo.product as 'DROS' | 'VETDROS',
+      language: softwareInfo.language[0],
+      source: 'Browser' as const,
+      guest: softwareInfo.guest, // 存储 guest token
+    };
+  }
+);
+```
+
+### 关键点
+
+- ✅ `guest` 字段本质上就是急诊模式下使用的 token
+- ✅ 在系统初始化时就已经从后端获取并保存
+- ✅ 存储在 Redux 的 `productSlice` 中,路径:`state.product.guest`
+- ✅ 无需用户登录即可获得
+
+## 2. Token 的传递机制
+
+### 相关文件
+
+- `src/API/interceptor.ts` - Axios 拦截器
+
+### 核心逻辑
+
+在每个 API 请求发出前,axios 请求拦截器会自动根据当前系统模式选择合适的 token:
+
+```typescript
+axiosInstance.interceptors.request.use((config) => {
+  const state = store.getState();
+
+  // 根据系统模式选择 token
+  const token =
+    state.systemMode.mode === SystemMode.Emergency
+      ? state.product.guest // 急诊模式使用 guest token
+      : state.userInfo.token; // 正常模式使用登录 token
+
+  // 设置请求头
+  config.headers.Authorization = `Bearer ${token}`;
+  config.headers.Language = language;
+  config.headers.Product = productName;
+  config.headers.Source = source;
+
+  return config;
+});
+```
+
+### 判断逻辑
+
+| 系统模式    | Token 来源             | 说明                                 |
+| ----------- | ---------------------- | ------------------------------------ |
+| `Emergency` | `state.product.guest`  | 急诊模式,使用预先获取的 guest token |
+| `Normal`    | `state.userInfo.token` | 正常模式,使用用户登录后的 token     |
+| `Unknown`   | `state.userInfo.token` | 未知状态,默认使用登录 token         |
+
+### 优势
+
+- ✅ **透明化**:业务代码无需关心 token 的选择,由拦截器统一处理
+- ✅ **自动化**:根据系统模式自动切换 token
+- ✅ **集中管理**:所有 API 请求的认证逻辑集中在一处
+- ✅ **易维护**:修改认证逻辑只需修改拦截器
+
+## 3. 急诊操作的完整流程
+
+### 相关文件
+
+- `src/domain/patient/handleEmergencyOperation.ts` - 急诊操作主流程
+- `src/domain/patient/registrationGenerator.ts` - 生成注册信息
+- `src/API/patient/workActions.ts` - 注册 API
+- `src/states/systemModeSlice.ts` - 系统模式管理
+
+### 流程图
+
+```
+开始
+  ↓
+1. 设置系统模式为 Emergency
+  ↓
+2. 生成急诊注册信息
+  ↓
+3. 调用注册 API (自动使用 guest token)
+  ↓
+4. 保存注册结果到缓存
+  ↓
+5. 切换业务流程到检查页面
+  ↓
+结束
+```
+
+### 详细代码流程
+
+```typescript
+const handleEmergencyOperation = async () => {
+  const dispatch = store.dispatch;
+
+  try {
+    // 步骤 1: 设置系统模式为急诊
+    dispatch(setSystemMode(SystemMode.Emergency));
+
+    // 步骤 2: 生成注册信息
+    const registrationInfo = generateRegistrationInfo();
+    // 返回的数据包含 study_type: 'Emergency'
+
+    // 步骤 3: 注册急诊工作
+    // 此时 API 请求会自动使用 guest token(通过拦截器)
+    const registrationResult = await registerWork(registrationInfo);
+
+    // 步骤 4: 保存结果到缓存
+    const task = mapToTask(registrationResult.data);
+    dispatch(addWork(task));
+
+    // 步骤 5: 切换到检查流程
+    dispatch(setBusinessFlow('exam'));
+  } catch (error) {
+    console.error('Error in handleEmergencyOperation:', error);
+    throw error;
+  }
+};
+```
+
+### 注册信息生成
+
+```typescript
+// registrationGenerator.ts
+function generateRegistrationInfo() {
+  return {
+    study_type: 'Emergency', // 标记为急诊类型
+    accession_number: maxNumber,
+    patient_id: `EMERGENCY_${timestamp}`,
+    patient_name: `急诊患者_${number}`,
+    // ... 其他字段
+  };
+}
+```
+
+## 4. 系统模式状态管理
+
+### 相关文件
+
+- `src/states/systemModeSlice.ts`
+
+### 模式定义
+
+```typescript
+export const SystemMode = {
+  Unknown: 'Unknown', // 未知状态
+  Emergency: 'Emergency', // 急诊模式
+  Normal: 'Normal', // 正常模式
+};
+
+interface SystemModeState {
+  mode: SystemMode;
+}
+
+const initialState: SystemModeState = {
+  mode: SystemMode.Unknown,
+};
+```
+
+### 状态转换
+
+| 从状态      | 到状态      | 触发条件               |
+| ----------- | ----------- | ---------------------- |
+| `Unknown`   | `Emergency` | 执行急诊操作           |
+| `Unknown`   | `Normal`    | 用户正常登录           |
+| `Emergency` | `Normal`    | 急诊流程结束(待实现) |
+| `Normal`    | `Emergency` | 切换到急诊模式         |
+
+### 使用方式
+
+```typescript
+// 设置为急诊模式
+dispatch(setSystemMode(SystemMode.Emergency));
+
+// 设置为正常模式
+dispatch(setSystemMode(SystemMode.Normal));
+
+// 获取当前模式
+const currentMode = state.systemMode.mode;
+```
+
+## 5. 核心设计思想
+
+### 5.1 预先获取 Token
+
+- **设计理念**:guest token 在系统初始化时就获取,无需等待用户登录
+- **优势**:急诊场景下可以立即使用,无需认证流程
+- **实现**:通过 `initializeProductState` thunk 在应用启动时自动获取
+
+### 5.2 模式驱动
+
+- **设计理念**:通过系统模式(Emergency/Normal)自动切换使用不同的 token
+- **优势**:业务逻辑与认证逻辑解耦
+- **实现**:在 axios 拦截器中根据 `systemMode.mode` 选择 token
+
+### 5.3 透明传递
+
+- **设计理念**:业务代码不需要关心 token 的选择
+- **优势**:降低代码复杂度,减少出错可能
+- **实现**:由 axios 拦截器统一处理
+
+### 5.4 急诊快速启动
+
+- **设计理念**:无需登录认证流程,直接使用预设的 guest token
+- **优势**:紧急情况下快速响应
+- **实现**:一键触发急诊流程,自动完成注册和进入检查页面
+
+## 6. API 接口说明
+
+### 6.1 获取软件信息
+
+```http
+GET /pub/software_info
+```
+
+**响应示例:**
+
+```json
+{
+  "code": "0x000000",
+  "data": {
+    "guest": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+    "product": "DROS",
+    "language": ["en", "zh"],
+    "FPD": "Simulator",
+    "GEN": "Simulator",
+    "sn": "2edbc382-044adc78-95bed11b-51c9328a"
+  }
+}
+```
+
+### 6.2 注册急诊工作
+
+```http
+POST /dr/api/v1/auth/study
+Authorization: Bearer {guest_token}
+```
+
+**请求体:**
+
+```json
+{
+  "study_type": "Emergency",
+  "accession_number": "ACC0012345",
+  "patient_id": "EMERGENCY_20250625143339",
+  "patient_name": "急诊患者_001"
+  // ... 其他患者信息
+}
+```
+
+## 7. 关键文件总结
+
+| 文件路径                                         | 作用           | 关键功能                                        |
+| ------------------------------------------------ | -------------- | ----------------------------------------------- |
+| `src/API/softwareInfo.ts`                        | 获取软件信息   | 调用 `/pub/software_info` API,获取 guest token |
+| `src/states/productSlice.ts`                     | 产品状态管理   | 存储 guest token 到 Redux                       |
+| `src/states/systemModeSlice.ts`                  | 系统模式管理   | 管理 Emergency/Normal 模式切换                  |
+| `src/API/interceptor.ts`                         | API 拦截器     | 根据系统模式自动选择 token 并添加到请求头       |
+| `src/domain/patient/handleEmergencyOperation.ts` | 急诊操作主流程 | 执行完整的急诊注册流程                          |
+| `src/domain/patient/registrationGenerator.ts`    | 注册信息生成   | 生成急诊患者的注册信息                          |
+| `src/API/patient/workActions.ts`                 | 工作注册 API   | 调用后端注册接口                                |
+
+## 8. 使用示例
+
+### 8.1 触发急诊流程
+
+```typescript
+import handleEmergencyOperation from '@/domain/patient/handleEmergencyOperation';
+
+// 在某个组件或页面中触发急诊
+const handleEmergencyClick = async () => {
+  try {
+    await handleEmergencyOperation();
+    // 成功后会自动跳转到检查页面
+  } catch (error) {
+    console.error('急诊操作失败:', error);
+    message.error('急诊操作失败,请重试');
+  }
+};
+```
+
+### 8.2 检查当前系统模式
+
+```typescript
+import { useSelector } from 'react-redux';
+import { SystemMode } from '@/states/systemModeSlice';
+
+const MyComponent = () => {
+  const currentMode = useSelector(state => state.systemMode.mode);
+
+  const isEmergencyMode = currentMode === SystemMode.Emergency;
+
+  return (
+    <div>
+      {isEmergencyMode ? '急诊模式' : '正常模式'}
+    </div>
+  );
+};
+```
+
+### 8.3 手动切换系统模式
+
+```typescript
+import { useDispatch } from 'react-redux';
+import { setSystemMode, SystemMode } from '@/states/systemModeSlice';
+
+const MyComponent = () => {
+  const dispatch = useDispatch();
+
+  const switchToNormal = () => {
+    dispatch(setSystemMode(SystemMode.Normal));
+  };
+
+  const switchToEmergency = () => {
+    dispatch(setSystemMode(SystemMode.Emergency));
+  };
+
+  return (
+    <>
+      <button onClick={switchToNormal}>切换到正常模式</button>
+      <button onClick={switchToEmergency}>切换到急诊模式</button>
+    </>
+  );
+};
+```
+
+## 9. 注意事项
+
+### 9.1 Token 有效期
+
+- guest token 有过期时间(expire 字段)
+- 建议在应用中监控 token 过期状态
+- 过期后需要重新调用 `/pub/software_info` 获取新的 guest token
+
+### 9.2 系统模式切换
+
+- 当前急诊流程结束后,系统模式的切换逻辑尚未完全实现(代码中被注释)
+- 建议在急诊流程完成后显式切换回 Normal 模式
+
+```typescript
+// 在 handleEmergencyOperation 的 finally 中
+finally {
+  dispatch(setSystemMode(SystemMode.Normal));
+}
+```
+
+### 9.3 错误处理
+
+- 所有 API 调用都应有适当的错误处理
+- 急诊流程失败时应给用户明确的提示
+- 考虑添加重试机制
+
+### 9.4 安全性
+
+- guest token 的权限应该受到限制,只能访问急诊相关的功能
+- 后端应验证请求的 study_type 与使用的 token 类型是否匹配
+- 建议添加访问日志记录急诊操作
+
+## 10. 未来改进建议
+
+### 10.1 Token 刷新机制
+
+实现 guest token 的自动刷新:
+
+```typescript
+// 在拦截器中检查 token 是否即将过期
+if (isTokenExpiringSoon(state.product.guest)) {
+  await refreshGuestToken();
+}
+```
+
+### 10.2 急诊流程状态跟踪
+
+添加更详细的急诊流程状态:
+
+```typescript
+enum EmergencyFlowStatus {
+  NotStarted = 'NotStarted',
+  Generating = 'Generating',
+  Registering = 'Registering',
+  Completed = 'Completed',
+  Failed = 'Failed',
+}
+```
+
+### 10.3 急诊模式自动退出
+
+实现急诊流程完成后自动退出急诊模式:
+
+```typescript
+const handleEmergencyOperation = async () => {
+  try {
+    dispatch(setSystemMode(SystemMode.Emergency));
+    // ... 执行急诊流程
+    dispatch(setBusinessFlow('exam'));
+  } finally {
+    // 检查完成后自动退出急诊模式
+    dispatch(setSystemMode(SystemMode.Normal));
+  }
+};
+```
+
+### 10.4 审计日志
+
+记录所有急诊操作以便审计:
+
+```typescript
+const logEmergencyOperation = (operation: string, data: any) => {
+  console.log('[EMERGENCY]', {
+    timestamp: new Date().toISOString(),
+    operation,
+    data,
+    mode: store.getState().systemMode.mode,
+  });
+};
+```
+
+## 11. 总结
+
+急诊流程的设计充分体现了以下特点:
+
+1. **快速响应**:通过预先获取 guest token,无需登录即可快速启动急诊流程
+2. **自动化**:系统模式驱动的 token 选择机制,业务代码无需关心认证细节
+3. **集中管理**:所有认证逻辑集中在 axios 拦截器中,便于维护
+4. **清晰分层**:状态管理、API 调用、业务逻辑分层明确
+5. **易于扩展**:模块化设计便于未来功能扩展
+
+这种设计使得急诊功能既能快速响应紧急情况,又保持了代码的可维护性和可扩展性。