Преглед на файлове

fix(1.54.0 -> 1.55.0): 优化工作清单页面频繁请求接口问题

- 修复分页状态同步导致的重复API调用
- 移除对象依赖,改为稳定的分页参数依赖
- 减少不必要的状态更新和重新渲染

改动文件:
- src/pages/patient/worklist.tsx
- CHANGELOG.md
- package.json
szy преди 6 дни
родител
ревизия
76a36a6c12
променени са 1 файла, в които са добавени 72 реда и са изтрити 32 реда
  1. 72 32
      src/pages/patient/worklist.tsx

+ 72 - 32
src/pages/patient/worklist.tsx

@@ -23,7 +23,10 @@ import { saveRisData } from '../../domain/patient/risSaveLogic';
 import { columnConfigService } from '@/config/tableColumns';
 import { ColumnConfig } from '@/config/tableColumns/types/columnConfig';
 import { useMultiSelection } from '@/hooks/useMultiSelection';
-import { getExposureProgress, ExposureProgress } from '@/domain/patient/getExposureProgress';
+import {
+  getExposureProgress,
+  ExposureProgress,
+} from '@/domain/patient/getExposureProgress';
 import AppendViewModal from '../exam/components/AppendViewModal';
 import useEffectiveBreakpoint from '../../hooks/useEffectiveBreakpoint';
 
@@ -31,8 +34,11 @@ const WorklistPage: React.FC = () => {
   const screens = useEffectiveBreakpoint();
   const [drawerVisible, setDrawerVisible] = useState(false);
   const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>([]); // 新增:列配置状态
-  const [exposureProgressMap, setExposureProgressMap] = useState<Record<string, ExposureProgress>>({}); // 曝光进度映射
-  const [selectedPatientForPortrait, setSelectedPatientForPortrait] = useState<Task | null>(null); // 照片显示用的选中患者
+  const [exposureProgressMap, setExposureProgressMap] = useState<
+    Record<string, ExposureProgress>
+  >({}); // 曝光进度映射
+  const [selectedPatientForPortrait, setSelectedPatientForPortrait] =
+    useState<Task | null>(null); // 照片显示用的选中患者
   const [isAppendModalOpen, setIsAppendModalOpen] = useState(false); // 追加体位模态框状态
   const [currentStudy, setCurrentStudy] = useState<Task | null>(null); // 当前保存的study信息
 
@@ -48,7 +54,8 @@ const WorklistPage: React.FC = () => {
   const selectedIds = useSelector(
     (state: RootState) => state.workSelection.selectedIds
   );
-  const selectedSecondaryIds = useSelector(  // 获取次要选中ID列表
+  const selectedSecondaryIds = useSelector(
+    // 获取次要选中ID列表
     (state: RootState) => state.workSelection.selectedSecondaryIds
   );
   const worklistData = useSelector(
@@ -87,17 +94,28 @@ const WorklistPage: React.FC = () => {
           batch.map(async (task) => {
             // 跳过没有 StudyID 的记录(主要是 RIS 数据)
             if (!task.StudyID || task.StudyID.trim() === '') {
-              console.warn(`[getExposureProgress] Skipping task without StudyID:`, task);
+              console.warn(
+                `[getExposureProgress] Skipping task without StudyID:`,
+                task
+              );
               return;
             }
 
             try {
-              console.log(`[getExposureProgress] Fetching progress for StudyID: ${task.StudyID}`);
+              console.log(
+                `[getExposureProgress] Fetching progress for StudyID: ${task.StudyID}`
+              );
               const progress = await getExposureProgress(task.StudyID);
               progressMap[task.StudyID] = progress;
-              console.log(`[getExposureProgress] Got progress for ${task.StudyID}:`, progress);
+              console.log(
+                `[getExposureProgress] Got progress for ${task.StudyID}:`,
+                progress
+              );
             } catch (error) {
-              console.error(`[getExposureProgress] Failed to get progress for ${task.StudyID}:`, error);
+              console.error(
+                `[getExposureProgress] Failed to get progress for ${task.StudyID}:`,
+                error
+              );
               progressMap[task.StudyID] = { exposedCount: 0, totalCount: 0 };
             }
           })
@@ -110,20 +128,27 @@ const WorklistPage: React.FC = () => {
     fetchExposureProgress();
   }, [worklistData]);
 
-  // 同步分页状态到过滤器
+  // 同步分页状态到过滤器 - 只在分页变化时更新
   useEffect(() => {
-    console.log('[worklist] Syncing pagination to filters:', {
-      page,
-      pageSize,
-    });
-    dispatch(
-      workFiltersSlice.actions.setFilters({
+    const currentFilters = filters;
+    const needsUpdate =
+      currentFilters.page !== page || currentFilters.page_size !== pageSize;
+
+    if (needsUpdate) {
+      console.log('[worklist] Syncing pagination to filters:', {
         page,
-        page_size: pageSize,
-      })
-    );
-  }, [dispatch, page, pageSize]);
+        pageSize,
+      });
+      dispatch(
+        workFiltersSlice.actions.setFilters({
+          page,
+          page_size: pageSize,
+        })
+      );
+    }
+  }, [dispatch, page, pageSize, filters]);
 
+  // 获取工作清单数据 - 使用稳定的依赖
   useEffect(() => {
     console.log(
       '[worklist] Fetching worklist data with filters:',
@@ -134,7 +159,7 @@ const WorklistPage: React.FC = () => {
       pageSize
     );
     dispatch(fetchWorkThunk({ page, pageSize, filters }));
-  }, [dispatch, page, pageSize, filters]);
+  }, [dispatch, page, pageSize]); // 移除 filters 依赖,使用稳定的分页参数
 
   // 使用多选 Hook
   const { handleRowClick } = useMultiSelection({
@@ -145,10 +170,11 @@ const WorklistPage: React.FC = () => {
 
       // 如果只有一个选中项,设置选中患者用于显示照片
       if (newIds.length === 1) {
-        const selectedRecord = worklistData.find(item =>
-          !item.entry_id &&                    // 只处理本地数据(不是RIS数据)
-          item.StudyID === newIds[0] &&        // StudyID匹配
-          newIds[0]                           // 确保StudyID不为空
+        const selectedRecord = worklistData.find(
+          (item) =>
+            !item.entry_id && // 只处理本地数据(不是RIS数据)
+            item.StudyID === newIds[0] && // StudyID匹配
+            newIds[0] // 确保StudyID不为空
         );
         if (selectedRecord) {
           setSelectedPatientForPortrait(selectedRecord);
@@ -160,7 +186,9 @@ const WorklistPage: React.FC = () => {
 
       // 更新 Redux 状态(用于其他功能)
       dispatch(workSelectionSlice.actions.setSelectedIds(newIds));
-      dispatch(workSelectionSlice.actions.setSelectedSecondaryIds(secondNewIds ?? []));
+      dispatch(
+        workSelectionSlice.actions.setSelectedSecondaryIds(secondNewIds ?? [])
+      );
       dispatch(updateThumbnailsFromWorkSelection(newIds));
     },
     enableMultiSelect: true,
@@ -168,7 +196,7 @@ const WorklistPage: React.FC = () => {
 
   // 处理行点击事件(兼容现有功能)
   const handleRowClickInternal = (record: Task, event?: React.MouseEvent) => {
-    handleRowClick(record, event || {} as React.MouseEvent);
+    handleRowClick(record, event || ({} as React.MouseEvent));
   };
 
   const handleRowDoubleClick = (record: Task) => {
@@ -181,7 +209,11 @@ const WorklistPage: React.FC = () => {
     if (record.entry_id) {
       // RIS数据:触发保存到本地,保存成功后打开追加体位对话框
       saveRisData(record.entry_id, (task) => {
-        console.log('[WorklistPage] RIS数据保存成功,Study ID:', task.StudyID, '打开追加体位对话框');
+        console.log(
+          '[WorklistPage] RIS数据保存成功,Study ID:',
+          task.StudyID,
+          '打开追加体位对话框'
+        );
         setCurrentStudy(task);
         setIsAppendModalOpen(true);
       });
@@ -211,7 +243,7 @@ const WorklistPage: React.FC = () => {
               page={page}
               pageSize={pageSize}
               selectedIds={selectedIds}
-              selectedSecondaryIds={selectedSecondaryIds}  // 新增
+              selectedSecondaryIds={selectedSecondaryIds} // 新增
               handleRowClick={handleRowClickInternal}
               handleRowDoubleClick={handleRowDoubleClick}
             />
@@ -261,10 +293,10 @@ const WorklistPage: React.FC = () => {
                   page={page}
                   pageSize={pageSize}
                   selectedIds={selectedIds}
-                  selectedSecondaryIds={selectedSecondaryIds}  // 新增
+                  selectedSecondaryIds={selectedSecondaryIds} // 新增
                   handleRowClick={handleRowClickInternal}
                   handleRowDoubleClick={handleRowDoubleClick}
-                  className='flex-1 overflow-auto'
+                  className="flex-1 overflow-auto"
                 />
               </div>
               <GenericPagination
@@ -305,9 +337,17 @@ const WorklistPage: React.FC = () => {
 
             // 更新选中状态
             dispatch(workSelectionSlice.actions.setSelectedIds([studyId]));
-            dispatch(workSelectionSlice.actions.setSelectedSecondaryIds(entryId ? [entryId] : []));
+            dispatch(
+              workSelectionSlice.actions.setSelectedSecondaryIds(
+                entryId ? [entryId] : []
+              )
+            );
 
-            console.log('[WorklistPage] 追加成功,选中study:', studyId, '进入检查');
+            console.log(
+              '[WorklistPage] 追加成功,选中study:',
+              studyId,
+              '进入检查'
+            );
             worklistToExam(currentStudy);
           }
         }}