|
@@ -0,0 +1,206 @@
|
|
|
+import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
|
|
|
+import { dview } from '@/domain/dview';
|
|
|
+import { Task } from '@/domain/work';
|
|
|
+import { workSelectionSlice } from './workSlice';
|
|
|
+import { historySelectionSlice } from './history';
|
|
|
+import { fetchTaskDetails } from '@/API/patient/workActions';
|
|
|
+import { fetchViewDetail } from '@/API/patient/viewActions';
|
|
|
+import { Series } from '@/domain/series';
|
|
|
+import { XImage } from '@/domain/xImage';
|
|
|
+import { getExposedImageUrl, getViewIconUrl } from '@/API/bodyPosition';
|
|
|
+
|
|
|
+interface ThumbnailListState {
|
|
|
+ thumbnails: dview[];
|
|
|
+ loading: boolean;
|
|
|
+ error: string | null;
|
|
|
+}
|
|
|
+
|
|
|
+const initialState: ThumbnailListState = {
|
|
|
+ thumbnails: [],
|
|
|
+ loading: false,
|
|
|
+ error: null,
|
|
|
+};
|
|
|
+
|
|
|
+async function getAllDView(selectedIds: string[]) {
|
|
|
+ const allViews: dview[] = [];
|
|
|
+ for (const taskId of selectedIds) {
|
|
|
+ try {
|
|
|
+ // 通过 API 获取任务详情
|
|
|
+ const taskDetails = await fetchTaskDetails(taskId);
|
|
|
+
|
|
|
+ // 将获取的数据转换为 dview 类型
|
|
|
+ const views = await Promise.all(
|
|
|
+ taskDetails.series.flatMap<Promise<dview>>((series: Series) =>
|
|
|
+ series.images.map<Promise<dview>>(async (image: XImage) => {
|
|
|
+ // 获取view详情以获得view_icon_name
|
|
|
+ let viewDetail;
|
|
|
+ try {
|
|
|
+ viewDetail = await fetchViewDetail(image.view_id);
|
|
|
+ } catch (error) {
|
|
|
+ console.error(
|
|
|
+ `Error fetching view detail for ${image.view_id}:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ viewDetail = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 基于expose_status设置thumbnail_file
|
|
|
+ const thumbnail_file =
|
|
|
+ image.expose_status === 'Exposed'
|
|
|
+ ? getExposedImageUrl(image.sop_instance_uid)
|
|
|
+ : viewDetail?.view_icon_name
|
|
|
+ ? getViewIconUrl(viewDetail.view_icon_name)
|
|
|
+ : '';
|
|
|
+
|
|
|
+ return {
|
|
|
+ view_id: image.view_id,
|
|
|
+ series_instance_uid: series.series_instance_uid,
|
|
|
+ study_instance_uid: taskDetails.study_instance_uid,
|
|
|
+ study_id: taskDetails.study_id,
|
|
|
+ procedure_id: series.procedure_id,
|
|
|
+ view_description: image.view_description,
|
|
|
+ view_type: '',
|
|
|
+ PrimarySopUID: image.sop_instance_uid,
|
|
|
+ expose_status: image.expose_status,
|
|
|
+ image_file_path: image.image_file_path,
|
|
|
+ image_file: image.image_file_path,
|
|
|
+ thumbnail_file,
|
|
|
+ } satisfies dview;
|
|
|
+ })
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
+ allViews.push(...views);
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`Error fetching details for task ${taskId}:`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return allViews;
|
|
|
+}
|
|
|
+
|
|
|
+// 创建 thunk 来处理工作列表选中项变化
|
|
|
+export const updateThumbnailsFromWorkSelection = createAsyncThunk(
|
|
|
+ 'thumbnailList/updateFromWorkSelection',
|
|
|
+ async (selectedIds: string[]) => {
|
|
|
+ if (selectedIds.length === 0) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ const allViews: dview[] = getAllDView(selectedIds) as unknown as dview[];
|
|
|
+
|
|
|
+ return allViews;
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
+// 创建 thunk 来处理历史列表选中项变化
|
|
|
+export const updateThumbnailsFromHistorySelection = createAsyncThunk(
|
|
|
+ 'thumbnailList/updateFromHistorySelection',
|
|
|
+ async (selectedIds: string[]) => {
|
|
|
+ if (selectedIds.length === 0) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ const allViews: dview[] = getAllDView(selectedIds) as unknown as dview[];
|
|
|
+
|
|
|
+ return allViews;
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
+const thumbnailListSlice = createSlice({
|
|
|
+ name: 'thumbnailList',
|
|
|
+ initialState,
|
|
|
+ reducers: {
|
|
|
+ setThumbnails: (state, action: PayloadAction<dview[]>) => {
|
|
|
+ state.thumbnails = action.payload;
|
|
|
+ state.loading = false;
|
|
|
+ state.error = null;
|
|
|
+ },
|
|
|
+ setLoading: (state, action: PayloadAction<boolean>) => {
|
|
|
+ state.loading = action.payload;
|
|
|
+ },
|
|
|
+ setError: (state, action: PayloadAction<string>) => {
|
|
|
+ state.error = action.payload;
|
|
|
+ state.loading = false;
|
|
|
+ },
|
|
|
+ clearThumbnails: (state) => {
|
|
|
+ state.thumbnails = [];
|
|
|
+ state.loading = false;
|
|
|
+ state.error = null;
|
|
|
+ },
|
|
|
+ updateThumbnailsFromSelection: (
|
|
|
+ state,
|
|
|
+ action: PayloadAction<{ selectedIds: string[]; tasksData: Task[] }>
|
|
|
+ ) => {
|
|
|
+ const { selectedIds, tasksData } = action.payload;
|
|
|
+
|
|
|
+ if (selectedIds.length === 0) {
|
|
|
+ state.thumbnails = [];
|
|
|
+ state.loading = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 找到选中的任务并提取所有视图
|
|
|
+ const selectedTasks = tasksData.filter((task) =>
|
|
|
+ selectedIds.includes(task.StudyID)
|
|
|
+ );
|
|
|
+
|
|
|
+ const allViews = selectedTasks.flatMap((task) => task.Views || []);
|
|
|
+ state.thumbnails = allViews;
|
|
|
+ state.loading = false;
|
|
|
+ state.error = null;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ extraReducers: (builder) => {
|
|
|
+ builder
|
|
|
+ // eslint-disable-next-line
|
|
|
+ .addCase(workSelectionSlice.actions.setSelectedIds, (state, action) => {
|
|
|
+
|
|
|
+ state.loading = true;
|
|
|
+ })
|
|
|
+ // eslint-disable-next-line
|
|
|
+ .addCase(historySelectionSlice.actions.setSelectedIds, (state, action) => {
|
|
|
+ state.loading = true;
|
|
|
+ }
|
|
|
+ )
|
|
|
+ .addCase(updateThumbnailsFromWorkSelection.pending, (state) => {
|
|
|
+ state.loading = true;
|
|
|
+ })
|
|
|
+ .addCase(updateThumbnailsFromWorkSelection.fulfilled, (state, action) => {
|
|
|
+ state.thumbnails = action.payload;
|
|
|
+ state.loading = false;
|
|
|
+ state.error = null;
|
|
|
+ })
|
|
|
+ .addCase(updateThumbnailsFromWorkSelection.rejected, (state, action) => {
|
|
|
+ state.loading = false;
|
|
|
+ state.error = action.error.message || 'Failed to update thumbnails';
|
|
|
+ })
|
|
|
+ .addCase(updateThumbnailsFromHistorySelection.pending, (state) => {
|
|
|
+ state.loading = true;
|
|
|
+ })
|
|
|
+ .addCase(
|
|
|
+ updateThumbnailsFromHistorySelection.fulfilled,
|
|
|
+ (state, action) => {
|
|
|
+ state.thumbnails = action.payload;
|
|
|
+ state.loading = false;
|
|
|
+ state.error = null;
|
|
|
+ }
|
|
|
+ )
|
|
|
+ .addCase(
|
|
|
+ updateThumbnailsFromHistorySelection.rejected,
|
|
|
+ (state, action) => {
|
|
|
+ state.loading = false;
|
|
|
+ state.error = action.error.message || 'Failed to update thumbnails';
|
|
|
+ }
|
|
|
+ );
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+export const {
|
|
|
+ setThumbnails,
|
|
|
+ setLoading,
|
|
|
+ setError,
|
|
|
+ clearThumbnails,
|
|
|
+ updateThumbnailsFromSelection,
|
|
|
+} = thumbnailListSlice.actions;
|
|
|
+export default thumbnailListSlice.reducer;
|