Sfoglia il codice sorgente

Merge remote changes, use remote config/dev.ts

sw 1 settimana fa
parent
commit
92359e4624

+ 2 - 2
config/dev.ts

@@ -11,7 +11,7 @@ export default {
     stats: true,
   },
   defineConstants: {
-    MQTT_BROKER_URL_FROM_WEBPACK: '"ws://192.168.110.112:8083/mqtt"',
+    MQTT_BROKER_URL_FROM_WEBPACK: '"ws://101.43.219.60:8083/mqtt"',
   },
   mini: {},
   h5: {
@@ -20,7 +20,7 @@ export default {
     devServer: {
       proxy: {
         '/dr': {
-          target: 'http://192.168.110.112:6001', // 你的后端服务地址
+          target: 'http://101.43.219.60:7700', // 你的后端服务地址
           changeOrigin: true, // 允许跨域
           // pathRewrite: {
           //   '^/dr/api': '' // 可选,用于重写路径

+ 35 - 16
src/domain/patient/worklistToExam.ts

@@ -11,18 +11,25 @@ import {
   setBodyPositions,
 } from '../../states/exam/bodyPositionListSlice';
 
-const worklistToExam = async (task: Task) => {
-  const dispatch = store.dispatch;
+/**
+ * 准备一个或多个 work 的详细数据用于检查
+ * @param works - 单个 Task 对象或 Task 数组
+ * @returns 包含完整 Views 数据的 Task 数组
+ */
+export const prepareWorksForExam = async (
+  works: Task | Task[]
+): Promise<Task[]> => {
+  // 统一转为数组处理
+  const workArray = Array.isArray(works) ? works : [works];
 
-  try {
-    // Fetch task details from the backend todo 在worklistTable中实现,触发fetchThunk,可以显示 loading
-    const taskDetails = await fetchTaskDetails(task.StudyID);
-
-    // Map the fetched task details to the Task type
-    const updatedTask: Task = {
-      ...task,
-      Views: taskDetails.series.flatMap<dview>(
-        (series: Series) =>
+  // 并行获取所有 work 的详细数据
+  const preparedWorks = await Promise.all(
+    workArray.map(async (work) => {
+      const taskDetails = await fetchTaskDetails(work.StudyID);
+
+      return {
+        ...work,
+        Views: taskDetails.series.flatMap<dview>((series: Series) =>
           series.images.map<dview>(
             (image: XImage) =>
               ({
@@ -36,12 +43,24 @@ const worklistToExam = async (task: Task) => {
                 PrimarySopUID: image.sop_instance_uid,
                 expose_status: image.expose_status,
                 image_file_path: image.image_file_path,
-                image_file: image.image_file_path, // Assuming image_file is the same as image_file
-                thumbnail_file: image.thumbnail_file || '', // Assuming thumbnail_file is optional
+                image_file: image.image_file_path,
+                thumbnail_file: image.thumbnail_file || '',
               }) satisfies dview
-          ) //转换为dview类型的实例时严格匹配
-      ),
-    };
+          )
+        ),
+      } as Task;
+    })
+  );
+
+  return preparedWorks;
+};
+
+const worklistToExam = async (task: Task) => {
+  const dispatch = store.dispatch;
+
+  try {
+    // 使用公共函数准备数据
+    const [updatedTask] = await prepareWorksForExam(task);
 
     // Clear existing works in the cache
     dispatch(clearWorks());

+ 23 - 3
src/domain/patient/worklistToExam.ts.md

@@ -8,12 +8,23 @@
 
 通过**异步函数**从后端获取任务详情,构建完整的 Task 对象并缓存,然后切换业务流程或转换为体位列表。
 
+**核心公共函数**:`prepareWorksForExam` - 支持单个或多个 Task 的数据准备,使用 Promise.all 并行处理以提高性能,可供其他模块(如 middleware)复用。
+
 ## 实现思路
 
+### prepareWorksForExam(公共数据准备函数)
+
+1. **参数统一**:接受单个 Task 或 Task 数组,统一转为数组处理
+2. **并行处理**:使用 Promise.all 并行调用 fetchTaskDetails 获取所有任务的详细数据
+3. **数据转换**:为每个任务构建完整的 Task 对象,展平 series/images 为 Views 数组
+4. **返回结果**:返回包含完整 Views 数据的 Task 数组
+5. **性能优化**:相比串行处理,并行获取多个任务详情可显著提升性能
+6. **可复用性**:供 worklistToExam、middleware 等多个模块使用
+
 ### worklistToExam(单任务进入检查)
 
-1. **获取详情**:调用 fetchTaskDetails API 获取任务的完整数据(包含 series 和 images)
-2. **构建 Task**:合并基础 task 和获取的详情,展平 series/images 为 Views 数组
+1. **调用公共函数**:使用 prepareWorksForExam 准备数据(传入单个 Task
+2. **解构结果**:从返回的数组中解构第一个元素获取准备好的 Task
 3. **清空缓存**:使用 clearWorks 清空旧的检查缓存
 4. **添加任务**:将完整的 Task 添加到 examWorksCacheSlice
 5. **切换流程**:设置业务流程为 exam,进入检查页面
@@ -51,12 +62,21 @@
 - ✅ 负责构建完整的 Task 对象
 - ✅ 负责管理检查缓存
 - ✅ 负责批量任务的处理
+- ✅ 提供公共的数据准备函数供其他模块使用(prepareWorksForExam)
 - ❌ 不负责设备初始化
 - ❌ 不负责图像的加载
 - ❌ 不负责用户权限验证
 
 ## 涉及概念
 
+**数据准备公共化(prepareWorksForExam)**:将重复的数据获取和转换逻辑抽取为公共函数,提高代码复用性和可维护性
+
+**并行处理优化**:使用 Promise.all 并行获取多个任务详情,相比串行处理可显著提升批量处理性能
+
+**灵活参数设计**:prepareWorksForExam 支持单个或多个 Task 输入,自动适配不同场景的需求
+
+**未来扩展支持**:函数设计上支持多选 study 进入检查的场景,为未来功能扩展奠定基础
+
 **工作列表到检查(worklistToExam)**:从任务清单选择任务进入检查流程
 
 **批量处理(worklistToProcess)**:选择多个已完成的任务批量进入图像处理流程
@@ -71,6 +91,6 @@
 
 **类型安全**:使用 satisfies 确保构建的 dview 对象符合类型定义
 
-**异步批处理**:使用 for 循环串行处理多个任务,确保顺序和数据完整性
+**跨模块复用**:prepareWorksForExam 被 worklistToExam 和 businessFlowMiddleware 共同使用,避免代码重复
 
 **TODO 注释**:代码注释提到在 worklistTable 中实现 fetchThunk 以显示 loading 状态

+ 55 - 14
src/states/businessFlowMiddlewareLogic.ts

@@ -10,9 +10,13 @@ import {
   setBodyPositions,
   transformWorksToBodyPositions,
 } from './exam/bodyPositionListSlice';
-import { worklistToProcess } from '@/domain/patient/worklistToExam';
+import {
+  worklistToProcess,
+  prepareWorksForExam,
+} from '@/domain/patient/worklistToExam';
 import { executeRegisterLogic } from '@/domain/patient/registerLogic';
 import registerToExam from '@/domain/patient/registerToExam';
+import { addWork, clearWorks } from './exam/examWorksCacheSlice';
 
 let continueBusinessFlow = '';
 
@@ -50,20 +54,57 @@ const businessFlowMiddlewareLogic: Middleware =
         return;
       }
       if (currentKey === 'worklist' || currentKey === 'history') {
-        //进入检查之前准备数据
         const state = store.getState();
-        const works = state.examWorksCache.works;
-        await transformWorksToBodyPositions(works)
-          .then((bodyPositions) => {
-            store.dispatch(setBodyPositions(bodyPositions));
-          })
-          .catch((error) => {
-            console.error(
-              '[businessFlowMiddleware] Transform works to body positions failed:',
-              error
-            );
-            return; // 阻止进入exam
-          });
+
+        // 获取选中的 study
+        const selectedIds =
+          currentKey === 'worklist'
+            ? state.workSelection.selectedIds
+            : state.historySelection.selectedIds;
+
+        const entitiesData =
+          currentKey === 'worklist'
+            ? state.workEntities.data
+            : state.historyEntities.data;
+
+        if (selectedIds.length === 0) {
+          console.warn('[businessFlowMiddleware] No study selected for exam');
+          return; // 阻止进入 exam
+        }
+
+        const selectedWork = entitiesData.find(
+          (work) => work.StudyID === selectedIds[0]
+        );
+
+        if (!selectedWork) {
+          console.error('[businessFlowMiddleware] Selected study not found');
+          return; // 阻止进入 exam
+        }
+
+        try {
+          // 使用公共函数准备数据
+          const [updatedTask] = await prepareWorksForExam(selectedWork);
+
+          // 清空并更新缓存
+          store.dispatch(clearWorks());
+          store.dispatch(addWork(updatedTask));
+
+          // 转换为 body positions
+          const bodyPositions = await transformWorksToBodyPositions([
+            updatedTask,
+          ]);
+          store.dispatch(setBodyPositions(bodyPositions));
+
+          console.log(
+            `[businessFlowMiddleware] Successfully prepared ${bodyPositions.length} body positions for exam`
+          );
+        } catch (error) {
+          console.error(
+            '[businessFlowMiddleware] Failed to prepare data for exam:',
+            error
+          );
+          return; // 阻止进入 exam
+        }
       }
 
       // 进入检查前,如果是从register来的,则判断数据合法性,执行注册等逻辑