Jelajahi Sumber

fix (1.34.8 -> 1.34.9): 修复复制体位功能

- 在 examWorksCacheSlice.ts 中重构 copyPositionThunk,从简单的图像复制扩展为完整的体位复制流程
- 集成 appendBodyPositionToStudy API 调用,添加选中的体位信息获取和验证
- 实现新体位数据处理,添加完善的状态管理和错误处理
- 优化用户体验,提升复制操作的稳定性和反馈

改动文件:
- src/states/exam/examWorksCacheSlice.ts
dengdx 2 minggu lalu
induk
melakukan
5df0cf5bac
4 mengubah file dengan 226 tambahan dan 17 penghapusan
  1. 13 0
      CHANGELOG.md
  2. 1 1
      package.json
  3. 88 16
      src/states/exam/examWorksCacheSlice.ts
  4. 124 0
      tatus

+ 13 - 0
CHANGELOG.md

@@ -2,6 +2,19 @@
 
 本项目的所有重要变更都将记录在此文件中。
 
+## [1.34.9] - 2025-12-30 18:17
+
+### 修复 (Fixed)
+- **修复复制体位功能** - 重构 copyPositionThunk,支持完整的体位复制流程
+  - 从简单的图像复制扩展为完整的体位追加API调用
+  - 集成选中的体位信息获取和验证
+  - 添加新体位数据处理和状态管理
+  - 优化错误处理和用户提示信息
+  - 确保UI正确同步更新新复制的体位
+
+**改动文件:**
+- src/states/exam/examWorksCacheSlice.ts
+
 ## [1.34.8] - 2025-12-30 16:45
 
 ### 修复 (Fixed)

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "zsis",
-  "version": "1.34.8",
+  "version": "1.34.9",
   "private": true,
   "description": "医学成像系统",
   "main": "main.js",

+ 88 - 16
src/states/exam/examWorksCacheSlice.ts

@@ -1,9 +1,13 @@
 import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
 import { Task as Work } from '@/domain/work';
 import { copyImage } from '@/API/patient/workActions';
+import { appendBodyPositionToStudy, AppendViewRequest } from '@/API/exam/appendBodyPosition';
 import { dview } from '@/domain/dview';
-import { addViewsToBodyPosition } from './bodyPositionListSlice';
+import { addViewsToBodyPosition, addBodyPosition } from './bodyPositionListSlice';
+import { ExtendedBodyPosition } from './bodyPositionListSlice';
+import { fetchViewDetail } from '@/API/patient/viewActions';
 import { message } from 'antd';
+import { RootState } from '../store';
 
 interface ExamWorksCacheState {
   works: Work[];
@@ -52,23 +56,91 @@ export const { addWork, removeWork, clearWorks, setLoading, addDviews } =
   examWorksCacheSlice.actions;
 export const copyPositionThunk = createAsyncThunk(
   'examWorksCache/copyPosition',
-  async ({ instanceUid }: { instanceUid: string }, { dispatch }) => {
+  async ({ instanceUid }: { instanceUid: string }, { dispatch, getState }) => {
     dispatch(setLoading(true));
     try {
-      const dviews: dview[] = await copyImage(instanceUid);
-      // const dviews: dview[] = response.data.series.flatMap((series: any) =>
-      //   series.images.map((image: any) => ({
-      //     view_id: image.view_id,
-      //     series_instance_uid: image.series_instance_uid,
-      //     study_instance_uid: image.study_instance_uid,
-      //     study_id: image.study_id,
-      //     procedure_id: series.procedure_id,
-      //     view_description: image.view_description,
-      //     view_type: image.view_id // Assuming view_type is the same as view_id
-      //   }))
-      // );
-      dispatch(addDviews({ instanceUid, dviews }));
-      dispatch(addViewsToBodyPosition({ instanceUid, dviews }));
+      // 获取当前选中的体位信息
+      const state = getState() as RootState;
+      const selectedBodyPosition = state.bodyPositionList.selectedBodyPosition;
+
+      if (!selectedBodyPosition) {
+        throw new Error('未找到选中的体位信息');
+      }
+
+      // 构建追加体位的请求
+      const request: AppendViewRequest = {
+        study_id: selectedBodyPosition.work.StudyID,
+        views: [{
+          view_id: selectedBodyPosition.view_id,
+          procedure_id: selectedBodyPosition.procedure_id || '',
+        }],
+      };
+
+      console.log('[copyPositionThunk] Copying position with request:', request);
+
+      // 调用追加体位接口
+      const response = await appendBodyPositionToStudy(request);
+
+      // 处理响应,将新创建的体位添加到状态管理中
+      const newBodyPositions: ExtendedBodyPosition[] = [];
+
+      for (const series of response.data.series) {
+        for (const image of series.images) {
+          // 获取完整的 view 详情
+          const viewDetail = await fetchViewDetail(image.view_id);
+
+          const dviewData: dview = {
+            view_id: image.view_id,
+            series_instance_uid: image.series_instance_uid,
+            study_instance_uid: image.study_instance_uid,
+            study_id: image.study_id,
+            procedure_id: series.procedure_id,
+            view_description: image.view_description,
+            view_type: image.view_id,
+            PrimarySopUID: image.sop_instance_uid,
+            thumbnail_file: image.image_file_path,
+            image_file: image.image_file_path,
+            image_file_path: image.image_file_path,
+            expose_status: 'Unexposed',
+            judged_status: image.judged_status,
+          };
+
+          const extendedBodyPosition: ExtendedBodyPosition = {
+            ...viewDetail,
+            collimator_length:
+              viewDetail.config_object.DX?.CollimatorSizeLength ||
+              viewDetail.config_object?.Common?.CollimatorSizeLength ||
+              0,
+            collimator_width:
+              viewDetail.config_object.DX?.CollimatorSizeWidth ||
+              viewDetail.config_object?.Common?.CollimatorSizeWidth ||
+              0,
+            sid: '',
+            patient_name: selectedBodyPosition.patient_name,
+            patient_id: selectedBodyPosition.patient_id,
+            registration_number: selectedBodyPosition.registration_number,
+            study_description: selectedBodyPosition.study_description,
+            body_position_image: viewDetail.view_icon_name,
+            work: selectedBodyPosition.work,
+            study_instance_uid: selectedBodyPosition.study_instance_uid,
+            sop_instance_uid: image.sop_instance_uid,
+            series_instance_uid: image.series_instance_uid,
+            secondary_sop_uid: image.secondary_sop_uid,
+            study_id: image.study_id,
+            dview: dviewData,
+          };
+
+          newBodyPositions.push(extendedBodyPosition);
+        }
+      }
+
+      // 将新体位添加到 bodyPositionList
+      for (const bodyPosition of newBodyPositions) {
+        dispatch(addBodyPosition(bodyPosition));
+      }
+
+      message.success(`复制体位成功`);
+
     } catch (error) {
       console.error('Error in copyPositionThunk:', error);
       message.error(`复制体位失败 ${error.message}`, 3);

+ 124 - 0
tatus

@@ -0,0 +1,124 @@
+diff --git a/src/states/exam/examWorksCacheSlice.ts b/src/states/exam/examWorksCacheSlice.ts
+index faff66a..58ce8de 100644
+--- a/src/states/exam/examWorksCacheSlice.ts
++++ b/src/states/exam/examWorksCacheSlice.ts
+@@ -1,8 +1,11 @@
+ import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
+ import { Task as Work } from '@/domain/work';
+ import { copyImage } from '@/API/patient/workActions';
++import { appendBodyPositionToStudy, AppendViewRequest } from '@/API/exam/appendBodyPosition';
+ import { dview } from '@/domain/dview';
+-import { addViewsToBodyPosition } from './bodyPositionListSlice';
++import { addViewsToBodyPosition, addBodyPosition } from './bodyPositionListSlice';
++import { ExtendedBodyPosition } from './bodyPositionListSlice';
++import { fetchViewDetail } from '@/API/patient/viewActions';
+ import { message } from 'antd';
+ 
+ interface ExamWorksCacheState {
+@@ -52,23 +55,91 @@ export const { addWork, removeWork, clearWorks, setLoading, addDviews } =
+   examWorksCacheSlice.actions;
+ export const copyPositionThunk = createAsyncThunk(
+   'examWorksCache/copyPosition',
+-  async ({ instanceUid }: { instanceUid: string }, { dispatch }) => {
++  async ({ instanceUid }: { instanceUid: string }, { dispatch, getState }) => {
+     dispatch(setLoading(true));
+     try {
+-      const dviews: dview[] = await copyImage(instanceUid);
+-      // const dviews: dview[] = response.data.series.flatMap((series: any) =>
+-      //   series.images.map((image: any) => ({
+-      //     view_id: image.view_id,
+-      //     series_instance_uid: image.series_instance_uid,
+-      //     study_instance_uid: image.study_instance_uid,
+-      //     study_id: image.study_id,
+-      //     procedure_id: series.procedure_id,
+-      //     view_description: image.view_description,
+-      //     view_type: image.view_id // Assuming view_type is the same as view_id
+-      //   }))
+-      // );
+-      dispatch(addDviews({ instanceUid, dviews }));
+-      dispatch(addViewsToBodyPosition({ instanceUid, dviews }));
++      // 获取当前选中的体位信息
++      const state = getState() as any;
++      const selectedBodyPosition = state.bodyPositionList.selectedBodyPosition;
++
++      if (!selectedBodyPosition) {
++        throw new Error('未找到选中的体位信息');
++      }
++
++      // 构建追加体位的请求
++      const request: AppendViewRequest = {
++        study_id: selectedBodyPosition.work.StudyID,
++        views: [{
++          view_id: selectedBodyPosition.view_id,
++          procedure_id: selectedBodyPosition.procedure_id || '',
++        }],
++      };
++
++      console.log('[copyPositionThunk] Copying position with request:', request);
++
++      // 调用追加体位接口
++      const response = await appendBodyPositionToStudy(request);
++
++      // 处理响应,将新创建的体位添加到状态管理中
++      const newBodyPositions: ExtendedBodyPosition[] = [];
++
++      for (const series of response.data.series) {
++        for (const image of series.images) {
++          // 获取完整的 view 详情
++          const viewDetail = await fetchViewDetail(image.view_id);
++
++          const dviewData: dview = {
++            view_id: image.view_id,
++            series_instance_uid: image.series_instance_uid,
++            study_instance_uid: image.study_instance_uid,
++            study_id: image.study_id,
++            procedure_id: series.procedure_id,
++            view_description: image.view_description,
++            view_type: image.view_id,
++            PrimarySopUID: image.sop_instance_uid,
++            thumbnail_file: image.image_file_path,
++            image_file: image.image_file_path,
++            image_file_path: image.image_file_path,
++            expose_status: 'Unexposed',
++            judged_status: image.judged_status,
++          };
++
++          const extendedBodyPosition: ExtendedBodyPosition = {
++            ...viewDetail,
++            collimator_length:
++              viewDetail.config_object.DX?.CollimatorSizeLength ||
++              viewDetail.config_object?.Common?.CollimatorSizeLength ||
++              0,
++            collimator_width:
++              viewDetail.config_object.DX?.CollimatorSizeWidth ||
++              viewDetail.config_object?.Common?.CollimatorSizeWidth ||
++              0,
++            sid: '',
++            patient_name: selectedBodyPosition.patient_name,
++            patient_id: selectedBodyPosition.patient_id,
++            registration_number: selectedBodyPosition.registration_number,
++            study_description: selectedBodyPosition.study_description,
++            body_position_image: viewDetail.view_icon_name,
++            work: selectedBodyPosition.work,
++            study_instance_uid: selectedBodyPosition.study_instance_uid,
++            sop_instance_uid: image.sop_instance_uid,
++            series_instance_uid: image.series_instance_uid,
++            secondary_sop_uid: image.secondary_sop_uid,
++            study_id: image.study_id,
++            dview: dviewData,
++          };
++
++          newBodyPositions.push(extendedBodyPosition);
++        }
++      }
++
++      // 将新体位添加到 bodyPositionList
++      for (const bodyPosition of newBodyPositions) {
++        dispatch(addBodyPosition(bodyPosition));
++      }
++
++      message.success(`复制体位成功`);
++
+     } catch (error) {
+       console.error('Error in copyPositionThunk:', error);
+       message.error(`复制体位失败 ${error.message}`, 3);