RIS_AUTO_SYNC_DESIGN.md 10 KB

RIS自动同步功能设计文档

📋 功能概述

RIS自动同步功能用于定期从RIS系统同步患者和检查数据到本地系统,确保worklist中显示最新的检查任务信息。

🎯 功能需求

核心需求

  1. 自动同步机制

    • 根据配置的时间间隔自动触发同步
    • 仅在worklist页面激活时启用
    • 支持手动触发同步
  2. 配置管理

    • 从后端获取RIS配置信息
    • 支持启用/禁用自动同步
    • 可配置同步间隔(分钟)
  3. 数据同步

    • 调用syncRis API同步RIS数据
    • 同步后自动刷新worklist

🏗️ 系统架构

1. 参与者

组件层级

- Pages层
  └── src/pages/patient/worklist.tsx (主页面)
  
- Components层  
  ├── src/components/RisSyncStatus.tsx (同步状态显示)
  └── src/pages/patient/components/ActionPanel.tsx (操作面板)

- Hooks层
  └── src/hooks/useRisAutoSync.ts (自动同步Hook)

- Services层
  └── src/services/risSync/RisSyncService.ts (同步服务)

- Redux层
  └── src/states/patient/ris/risSyncSlice.ts (状态管理)

- API层
  ├── src/API/patient/risActions.ts (RIS API接口)
  └── src/API/patient/workActions.ts (工作列表API)

类和方法

// RisSyncService类
- startAutoSync(): 启动自动同步
- stopAutoSync(): 停止自动同步  
- syncOnce(): 执行单次同步
- updateConfig(): 更新配置

// useRisAutoSync Hook
- 管理同步生命周期
- 处理页面切换逻辑

// risSyncSlice
- setSyncConfig: 设置同步配置
- setSyncStatus: 设置同步状态
- setLastSyncTime: 设置最后同步时间
- setSyncError: 设置同步错误

🔄 交互流程

sequenceDiagram
    participant User
    participant Worklist
    participant Hook as useRisAutoSync
    participant Service as RisSyncService
    participant API
    participant Redux
    
    User->>Worklist: 进入worklist页面
    Worklist->>Hook: 初始化自动同步
    Hook->>API: getRisConfig()
    API-->>Hook: 返回配置
    Hook->>Redux: 保存配置
    
    alt 自动同步启用
        Hook->>Service: startAutoSync(interval)
        loop 每N分钟
            Service->>API: syncRis()
            API-->>Service: 同步结果
            Service->>API: fetchTaskList()
            API-->>Service: 任务列表
            Service->>Redux: 更新数据
            Redux-->>Worklist: 刷新显示
        end
    end
    
    User->>Worklist: 手动同步
    Worklist->>Service: syncOnce()
    Service->>API: syncRis()
    API-->>Service: 同步结果
    Service->>API: fetchTaskList()
    API-->>Service: 任务列表
    Service->>Redux: 更新数据
    
    User->>Worklist: 离开页面
    Worklist->>Hook: 清理
    Hook->>Service: stopAutoSync()

📊 数据流

graph TD
    A[RIS系统] -->|API调用| B[syncRis接口]
    B --> C[同步数据到本地]
    C --> D[fetchTaskList接口]
    D --> E[获取混合数据]
    E --> F[Redux Store更新]
    F --> G[Worklist组件]
    G --> H[UI展示]
    
    I[配置API] --> J[getRisConfig]
    J --> K[Redux配置状态]
    K --> L[自动同步控制]
    L --> B

🗄️ 数据结构

RIS同步状态

interface RisSyncState {
  // 配置信息
  config: {
    mwl_enable: boolean;           // RIS是否启用
    mwl_refresh_enable: boolean;   // 自动刷新是否启用
    mwl_refresh_interval: number;  // 刷新间隔(分钟)
  } | null;
  
  // 同步状态
  syncStatus: 'idle' | 'syncing' | 'success' | 'error';
  lastSyncTime: string | null;     // 最后同步时间
  nextSyncTime: string | null;     // 下次同步时间
  syncCount: number;                // 同步条目数
  
  // 错误信息
  error: {
    message: string;
    timestamp: string;
  } | null;
  
  // 控制状态
  isAutoSyncActive: boolean;        // 自动同步是否激活
  isManuallySyncing: boolean;       // 是否正在手动同步
}

混合任务数据

interface Task {
  // 基础字段
  StudyID: string;
  PatientID: string;
  PatientName: string;
  AccessionNumber: string;
  
  // RIS特有字段
  entry_id?: string;               // RIS条目ID
  scheduled?: {                    // 调度信息
    scheduled_ae_title: string;
    scheduled_performing_physician_name: string;
    scheduled_procedure_step_id: string;
  };
  protocol_code?: Array<{          // 协议代码
    code_value: string;
    code_meaning: string;
  }>;
  
  // 其他字段...
}

🚀 执行流程

起点:用户进入worklist页面

flowchart TD
    Start[用户进入worklist页面] --> Check{检查currentKey}
    Check -->|是worklist| InitSync[初始化同步]
    Check -->|否| NoSync[不启动同步]
    
    InitSync --> GetConfig[获取RIS配置]
    GetConfig --> CheckEnable{检查是否启用}
    CheckEnable -->|启用| SetupTimer[设置定时器]
    CheckEnable -->|禁用| ShowDisabled[显示禁用状态]
    
    SetupTimer --> FirstSync[立即执行首次同步]
    FirstSync --> WaitInterval[等待间隔时间]
    WaitInterval --> AutoSync[执行自动同步]
    AutoSync --> UpdateUI[更新界面]
    UpdateUI --> WaitInterval
    
    ShowDisabled --> End[结束]
    NoSync --> End

同步执行流程

flowchart TD
    SyncStart[开始同步] --> SetStatus[设置同步中状态]
    SetStatus --> GetTimeRange[获取时间范围]
    GetTimeRange --> CallSyncAPI[调用syncRis API]
    
    CallSyncAPI -->|成功| SaveCount[保存同步数量]
    CallSyncAPI -->|失败| HandleError[处理错误]
    
    SaveCount --> FetchList[调用fetchTaskList]
    FetchList -->|成功| UpdateStore[更新Redux Store]
    FetchList -->|失败| HandleError
    
    UpdateStore --> SetSuccess[设置成功状态]
    HandleError --> SetError[设置错误状态]
    
    SetSuccess --> UpdateTime[更新同步时间]
    SetError --> LogError[记录错误日志]
    
    UpdateTime --> SyncEnd[同步结束]
    LogError --> SyncEnd

🧪 测试方案

1. 功能测试场景

场景1:自动同步启用测试

前置条件:
- RIS配置已启用自动同步
- 同步间隔设置为1分钟

测试步骤:
1. 进入worklist页面
2. 观察是否立即触发首次同步
3. 等待1分钟
4. 验证是否自动触发下次同步

预期结果:
- 首次同步成功执行
- 每分钟自动同步一次
- UI显示最新同步时间

场景2:手动同步测试

测试步骤:
1. 进入worklist页面
2. 点击手动同步按钮
3. 观察同步状态变化

预期结果:
- 按钮显示加载状态
- 同步完成后刷新列表
- 显示同步成功提示

场景3:页面切换测试

测试步骤:
1. 在worklist页面启动自动同步
2. 切换到其他页面
3. 等待同步间隔时间
4. 返回worklist页面

预期结果:
- 离开页面时停止同步
- 其他页面不触发同步
- 返回时重新启动同步

2. 边界测试

  • 网络异常:模拟网络断开,验证错误处理
  • 配置异常:RIS未启用时的行为
  • 并发同步:手动和自动同步冲突处理
  • 长时间运行:验证内存泄漏和定时器清理

🐛 潜在问题及解决方案

1. 内存泄漏风险

问题:定时器未正确清理 解决

useEffect(() => {
  const timer = setInterval(sync, interval);
  return () => clearInterval(timer); // 清理定时器
}, []);

2. 并发同步冲突

问题:手动和自动同步同时触发 解决:使用状态锁防止并发

if (isSyncing) {
  message.warning('正在同步中,请稍后再试');
  return;
}

3. 页面切换状态丢失

问题:切换页面后同步状态重置 解决:将同步状态存储在Redux中持久化

4. 同步失败重试

问题:单次失败导致长时间无数据 解决:实现指数退避重试机制

const retryWithBackoff = async (fn, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await sleep(Math.pow(2, i) * 1000);
    }
  }
};

📝 实施步骤

  1. 创建基础结构 (Day 1)

    • 创建risSyncSlice
    • 创建RisSyncService类
    • 创建useRisAutoSync Hook
  2. 集成到worklist (Day 2)

    • 修改worklist.tsx集成Hook
    • 添加同步状态UI组件
    • 添加手动同步按钮
  3. 完善功能 (Day 3)

    • 实现错误处理
    • 添加重试机制
    • 优化性能
  4. 测试验证 (Day 4)

    • 单元测试
    • 集成测试
    • 用户验收测试

🔧 配置示例

// 默认配置
const DEFAULT_CONFIG = {
  mwl_enable: true,
  mwl_refresh_enable: true,
  mwl_refresh_interval: 5, // 默认5分钟
};

// 同步时间范围(当天)
const getSyncTimeRange = () => {
  const now = new Date();
  const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
  
  return {
    start_time: startOfDay.toISOString().replace('Z', '+08:00'),
    end_time: endOfDay.toISOString().replace('Z', '+08:00'),
  };
};

📚 依赖关系

graph LR
    A[worklist.tsx] --> B[useRisAutoSync]
    B --> C[RisSyncService]
    C --> D[risActions API]
    C --> E[workActions API]
    B --> F[risSyncSlice]
    F --> G[Redux Store]
    A --> H[RisSyncStatus组件]
    H --> F

🎨 UI设计

同步状态显示

  • 位置:worklist页面顶部工具栏
  • 显示内容:
    • 同步状态图标(旋转/静止)
    • 最后同步时间
    • 下次同步倒计时
    • 手动同步按钮

错误提示

  • 使用Antd Message组件
  • 显示错误原因和重试建议

📈 性能优化

  1. 防抖处理:避免频繁触发同步
  2. 缓存机制:缓存配置信息减少API调用
  3. 批量更新:合并多个状态更新减少渲染
  4. 懒加载:仅在需要时加载同步服务

🔒 安全考虑

  1. 权限验证:确保用户有同步权限
  2. 数据验证:验证同步数据的完整性
  3. 错误隔离:同步失败不影响其他功能
  4. 日志记录:记录关键操作用于审计

文档版本:1.0.0 更新日期:2025-01-31 作者:系统架构师