急诊流程.md 12 KB

急诊流程 - Token 获取与传递机制

概述

本文档详细说明了系统中急诊模式的完整逻辑,包括 guest token 的获取、存储、传递机制以及急诊操作的完整流程。

1. Token 的来源(初始化阶段)

相关文件

  • src/API/softwareInfo.ts - API 调用
  • src/states/productSlice.ts - Redux 状态管理

获取流程

在系统启动时,通过 initializeProductState thunk 自动获取软件信息:

// 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

// 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:

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. 切换业务流程到检查页面
  ↓
结束

详细代码流程

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;
  }
};

注册信息生成

// registrationGenerator.ts
function generateRegistrationInfo() {
  return {
    study_type: 'Emergency', // 标记为急诊类型
    accession_number: maxNumber,
    patient_id: `EMERGENCY_${timestamp}`,
    patient_name: `急诊患者_${number}`,
    // ... 其他字段
  };
}

4. 系统模式状态管理

相关文件

  • src/states/systemModeSlice.ts

模式定义

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 切换到急诊模式

使用方式

// 设置为急诊模式
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 获取软件信息

GET /pub/software_info

响应示例:

{
  "code": "0x000000",
  "data": {
    "guest": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "product": "DROS",
    "language": ["en", "zh"],
    "FPD": "Simulator",
    "GEN": "Simulator",
    "sn": "2edbc382-044adc78-95bed11b-51c9328a"
  }
}

6.2 注册急诊工作

POST /dr/api/v1/auth/study
Authorization: Bearer {guest_token}

请求体:

{
  "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 触发急诊流程

import handleEmergencyOperation from '@/domain/patient/handleEmergencyOperation';

// 在某个组件或页面中触发急诊
const handleEmergencyClick = async () => {
  try {
    await handleEmergencyOperation();
    // 成功后会自动跳转到检查页面
  } catch (error) {
    console.error('急诊操作失败:', error);
    message.error('急诊操作失败,请重试');
  }
};

8.2 检查当前系统模式

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 手动切换系统模式

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 模式
// 在 handleEmergencyOperation 的 finally 中
finally {
  dispatch(setSystemMode(SystemMode.Normal));
}

9.3 错误处理

  • 所有 API 调用都应有适当的错误处理
  • 急诊流程失败时应给用户明确的提示
  • 考虑添加重试机制

9.4 安全性

  • guest token 的权限应该受到限制,只能访问急诊相关的功能
  • 后端应验证请求的 study_type 与使用的 token 类型是否匹配
  • 建议添加访问日志记录急诊操作

10. 未来改进建议

10.1 Token 刷新机制

实现 guest token 的自动刷新:

// 在拦截器中检查 token 是否即将过期
if (isTokenExpiringSoon(state.product.guest)) {
  await refreshGuestToken();
}

10.2 急诊流程状态跟踪

添加更详细的急诊流程状态:

enum EmergencyFlowStatus {
  NotStarted = 'NotStarted',
  Generating = 'Generating',
  Registering = 'Registering',
  Completed = 'Completed',
  Failed = 'Failed',
}

10.3 急诊模式自动退出

实现急诊流程完成后自动退出急诊模式:

const handleEmergencyOperation = async () => {
  try {
    dispatch(setSystemMode(SystemMode.Emergency));
    // ... 执行急诊流程
    dispatch(setBusinessFlow('exam'));
  } finally {
    // 检查完成后自动退出急诊模式
    dispatch(setSystemMode(SystemMode.Normal));
  }
};

10.4 审计日志

记录所有急诊操作以便审计:

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. 易于扩展:模块化设计便于未来功能扩展

这种设计使得急诊功能既能快速响应紧急情况,又保持了代码的可维护性和可扩展性。