Browse Source

定义体位详情对应的slice,绑定UI元素与slice数据,完善api层面view的定义,实现点击体位列表中的元素后更新体位详情组件展示的内容,使体位详情显示被点击体位的信息

dengdx 1 month ago
parent
commit
8eb937379e

+ 24 - 1
src/API/patient/viewActions.ts

@@ -19,7 +19,30 @@ export interface View {
   work_station_id: number;
   work_station_id: number;
   apr_id: string;
   apr_id: string;
   img_proc_id: string;
   img_proc_id: string;
-  // config_object: any;
+  config_object: {
+    DX: {
+      WorkStationID: string;
+      PatientOrientationRow: string;
+      PatientOrientationColumn: string;
+      ImageLaterality: string;
+      ImageRotate: string;
+      CollimatorSizeLength: string;
+      CollimatorSizeWidth: string;
+      CollimatorSize: string;
+      CollimatorCenter: string;
+      CollimatorFilter: string;
+      CollimatorNoChange: boolean;
+      StandPos: string;
+      ImageHorizontalFlip: string;
+      LabelStyle: string;
+      LabelPosition: string;
+      RatioFactorThickness: number;
+      RatioFactorWeight: number;
+      RatioFactorSize: number;
+      RatioFactorLength: number;
+      TargetEXI: number;
+    };
+  };
   sort: number;
   sort: number;
   is_enabled: boolean;
   is_enabled: boolean;
   product: string;
   product: string;

+ 19 - 9
src/pages/exam/components/BodyPositionDetail.tsx

@@ -1,33 +1,41 @@
 import React from 'react';
 import React from 'react';
+import { useSelector } from 'react-redux';
 import { Card, Row, Col, Typography, Image } from 'antd';
 import { Card, Row, Col, Typography, Image } from 'antd';
 import CollimatorIcon from '../../../assets/imgs/Collimator_normal.png';
 import CollimatorIcon from '../../../assets/imgs/Collimator_normal.png';
 import SidIcon from '../../../assets/imgs/SID.png';
 import SidIcon from '../../../assets/imgs/SID.png';
+import { RootState } from '@/states/store';
 
 
 const { Title, Text } = Typography;
 const { Title, Text } = Typography;
 
 
 const BodyPositionDetail: React.FC = () => {
 const BodyPositionDetail: React.FC = () => {
+  const bodyPositionDetail = useSelector(
+    (state: RootState) => state.bodyPositionDetail
+  );
+
   return (
   return (
     <Card className="p-4">
     <Card className="p-4">
       <Row gutter={[16, 16]}>
       <Row gutter={[16, 16]}>
         {/* 第一行 : 患者姓名*/}
         {/* 第一行 : 患者姓名*/}
         <Col span={24} className="text-center">
         <Col span={24} className="text-center">
-          <Title level={4}>Patient Name</Title>
+          <Title level={4}>{bodyPositionDetail.patient_name}</Title>
         </Col>
         </Col>
         {/* 第二行 :患者id,登记号,study描述*/}
         {/* 第二行 :患者id,登记号,study描述*/}
         <Col span={8}>
         <Col span={8}>
-          <Text>Patient ID: 12345</Text>
+          <Text>Patient ID: {bodyPositionDetail.patient_id}</Text>
         </Col>
         </Col>
         <Col span={8}>
         <Col span={8}>
-          <Text>Registration Number: 67890</Text>
+          <Text>
+            Registration Number: {bodyPositionDetail.registration_number}
+          </Text>
         </Col>
         </Col>
         <Col span={8}>
         <Col span={8}>
-          <Text>Study Description: Example Study</Text>
+          <Text>Study Description: {bodyPositionDetail.study_description}</Text>
         </Col>
         </Col>
         {/* 第三行 :体位示意图*/}
         {/* 第三行 :体位示意图*/}
         <Col span={24}>
         <Col span={24}>
           <div className="flex justify-center">
           <div className="flex justify-center">
             <img
             <img
-              src="../../../assets/imgs/logo-v3.jpg"
+              src={bodyPositionDetail.body_position_image}
               alt="Body Position"
               alt="Body Position"
               className="w-64"
               className="w-64"
             />
             />
@@ -35,22 +43,24 @@ const BodyPositionDetail: React.FC = () => {
         </Col>
         </Col>
         {/* 第四行 :体位描述*/}
         {/* 第四行 :体位描述*/}
         <Col span={24}>
         <Col span={24}>
-          <Text>View Description: Example View</Text>
+          <Text>View Description: {bodyPositionDetail.view_description}</Text>
         </Col>
         </Col>
         {/* 第五行 :设备信息*/}
         {/* 第五行 :设备信息*/}
         <Col span={24}>
         <Col span={24}>
           <div className="flex items-center">
           <div className="flex items-center">
             <Image src={CollimatorIcon} alt="Logo" height={'100%'} />
             <Image src={CollimatorIcon} alt="Logo" height={'100%'} />
-            <Text>Collimator Length: 100mm</Text>
+            <Text>
+              Collimator Length: {bodyPositionDetail.collimator_length}
+            </Text>
             <br />
             <br />
-            <Text>Collimator Width: 50mm</Text>
+            <Text>Collimator Width: {bodyPositionDetail.collimator_width}</Text>
           </div>
           </div>
         </Col>
         </Col>
         {/* 第六行 */}
         {/* 第六行 */}
         <Col span={24}>
         <Col span={24}>
           <div className="flex items-center">
           <div className="flex items-center">
             <Image src={SidIcon} alt="Logo" className="mr-2" height={'100%'} />
             <Image src={SidIcon} alt="Logo" className="mr-2" height={'100%'} />
-            <Text>SID: 1200mm</Text>
+            <Text>SID: {bodyPositionDetail.sid}</Text>
           </div>
           </div>
         </Col>
         </Col>
       </Row>
       </Row>

+ 40 - 29
src/pages/exam/components/BodyPositionList.tsx

@@ -1,9 +1,13 @@
 import React from 'react';
 import React from 'react';
 import { useSelector, useDispatch } from 'react-redux';
 import { useSelector, useDispatch } from 'react-redux';
 import { useEffect } from 'react';
 import { useEffect } from 'react';
-import { setBodyPositions } from '../../../states/exam/bodyPositionListSlice';
+import {
+  setBodyPositions,
+  ExtendedBodyPosition,
+} from '../../../states/exam/bodyPositionListSlice';
+import { setBodyPositionDetail } from '../../../states/exam/bodyPositionDetailSlice';
 import { RootState } from '../../../states/store';
 import { RootState } from '../../../states/store';
-import { Button } from 'antd';
+import { Button, message } from 'antd';
 import { PlusOutlined } from '@ant-design/icons';
 import { PlusOutlined } from '@ant-design/icons';
 import ImageViewer from './ImageViewer';
 import ImageViewer from './ImageViewer';
 import { getViewIconUrl } from '../../../API/bodyPosition';
 import { getViewIconUrl } from '../../../API/bodyPosition';
@@ -14,6 +18,25 @@ interface BodyPositionListProps {
 
 
 const BodyPositionList: React.FC<BodyPositionListProps> = ({ layout }) => {
 const BodyPositionList: React.FC<BodyPositionListProps> = ({ layout }) => {
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+
+  const handleImageClick = (bodyPosition: ExtendedBodyPosition) => {
+    message.info(`Clicked on ${bodyPosition.view_name}`);
+    dispatch(
+      setBodyPositionDetail({
+        view_name: bodyPosition.view_name,
+        view_description: bodyPosition.view_description,
+        view_icon_name: bodyPosition.view_icon_name,
+        patient_name: bodyPosition.patient_name,
+        patient_id: bodyPosition.patient_id,
+        registration_number: bodyPosition.registration_number,
+        study_description: bodyPosition.study_description,
+        body_position_image: bodyPosition.body_position_image,
+        collimator_length: bodyPosition.collimator_length,
+        collimator_width: bodyPosition.collimator_width,
+        sid: bodyPosition.sid,
+      })
+    );
+  };
   const bodyPositions = useSelector(
   const bodyPositions = useSelector(
     (state: RootState) => state.bodyPositionList.bodyPositions
     (state: RootState) => state.bodyPositionList.bodyPositions
   );
   );
@@ -31,33 +54,20 @@ const BodyPositionList: React.FC<BodyPositionListProps> = ({ layout }) => {
     alert(
     alert(
       `${works.length} works found == ${works[0].Views.length} views in the first work`
       `${works.length} works found == ${works[0].Views.length} views in the first work`
     );
     );
-    const bodyPositions = works
-      .flatMap((work) => work.Views)
-      .map((view) => ({
-        internal_id: view.internal_id,
-        view_id: view.view_id,
-        view_name: view.view_name,
-        view_name_local: view.view_name_local,
-        view_other_name: view.view_other_name,
-        view_description: view.view_description,
-        view_position: view.view_position,
-        application: view.application,
-        anatomic_region: view.anatomic_region,
-        patient_type: view.patient_type,
-        body_part_id: view.body_part_id,
-        view_icon_name: view.view_icon_name,
-        view_big_icon_name: view.view_big_icon_name,
-        view_coach_name: view.view_coach_name,
-        modality: view.modality,
-        work_station_id: view.work_station_id,
-        apr_id: view.apr_id,
-        img_proc_id: view.img_proc_id,
-        sort: view.sort,
-        is_enabled: view.is_enabled,
-        product: view.product,
-        is_pre_install: view.is_pre_install,
-        procedure_id: view.procedure_id,
-      }));
+    const bodyPositions: ExtendedBodyPosition[] = works.flatMap((work) =>
+      work.Views.map((view) => ({
+        ...view,
+        // ...work,
+        collimator_length: view.config_object.DX.CollimatorSizeLength || 0,
+        collimator_width: view.config_object.DX.CollimatorSizeWidth || 0,
+        sid: '', //todo 这里还缺少值的来源
+        patient_name: work.PatientName,
+        patient_id: work.PatientID,
+        registration_number: work.AccessionNumber,
+        study_description: work.StudyDescription,
+        body_position_image: view.view_icon_name,
+      }))
+    );
     dispatch(setBodyPositions(bodyPositions));
     dispatch(setBodyPositions(bodyPositions));
   }, [works, dispatch]);
   }, [works, dispatch]);
 
 
@@ -70,6 +80,7 @@ const BodyPositionList: React.FC<BodyPositionListProps> = ({ layout }) => {
           key={index}
           key={index}
           src={getViewIconUrl(bodyPosition.view_icon_name)}
           src={getViewIconUrl(bodyPosition.view_icon_name)}
           className="image-viewer-item"
           className="image-viewer-item"
+          onClick={() => handleImageClick(bodyPosition)}
         />
         />
       ))}
       ))}
       <Button
       <Button

+ 8 - 2
src/pages/exam/components/ImageViewer.tsx

@@ -5,12 +5,18 @@ interface ImageViewerProps {
   src: string;
   src: string;
   alt?: string;
   alt?: string;
   className?: string;
   className?: string;
+  onClick?: () => void;
 }
 }
 
 
-const ImageViewer: React.FC<ImageViewerProps> = ({ src, alt, className }) => {
+const ImageViewer: React.FC<ImageViewerProps> = ({
+  src,
+  alt,
+  className,
+  onClick,
+}) => {
   return (
   return (
     <div className={`image-viewer ${className}`}>
     <div className={`image-viewer ${className}`}>
-      <Image src={src} alt={alt} />
+      <Image src={src} alt={alt} onClick={onClick} preview={false} />
     </div>
     </div>
   );
   );
 };
 };

+ 50 - 0
src/states/exam/bodyPositionDetailSlice.ts

@@ -0,0 +1,50 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+interface BodyPositionDetailState {
+  view_name: string;
+  view_description: string;
+  view_icon_name: string;
+  patient_name: string;
+  patient_id: string;
+  registration_number: string;
+  study_description: string;
+  body_position_image: string;
+  collimator_length: string | number;
+  collimator_width: string | number;
+  sid: string;
+  // Add other relevant fields as needed
+}
+
+const initialState: BodyPositionDetailState = {
+  view_name: '',
+  view_description: '',
+  view_icon_name: '',
+  patient_name: '',
+  patient_id: '',
+  registration_number: '',
+  study_description: '',
+  body_position_image: '',
+  collimator_length: '',
+  collimator_width: '',
+  sid: '',
+  // Initialize other fields as needed
+};
+
+const bodyPositionDetailSlice = createSlice({
+  name: 'bodyPositionDetail',
+  initialState,
+  reducers: {
+    setBodyPositionDetail: (
+      state,
+      action: PayloadAction<BodyPositionDetailState>
+    ) => {
+      return {
+        ...state,
+        ...action.payload,
+      };
+    },
+  },
+});
+
+export const { setBodyPositionDetail } = bodyPositionDetailSlice.actions;
+export default bodyPositionDetailSlice.reducer;

+ 20 - 5
src/states/exam/bodyPositionListSlice.ts

@@ -1,8 +1,19 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import {View as BodyPosition} from '../../API/patient/viewActions';
+import { View as BodyPosition } from '../../API/patient/viewActions';
+
+export interface ExtendedBodyPosition extends BodyPosition {
+  patient_name: string;
+  patient_id: string;
+  registration_number: string;
+  study_description: string;
+  body_position_image: string;
+  collimator_length: number | string;
+  collimator_width: number | string;
+  sid: string;
+}
 
 
 interface BodyPositionListState {
 interface BodyPositionListState {
-  bodyPositions: BodyPosition[];
+  bodyPositions: ExtendedBodyPosition[];
 }
 }
 
 
 const initialState: BodyPositionListState = {
 const initialState: BodyPositionListState = {
@@ -13,14 +24,18 @@ const bodyPositionListSlice = createSlice({
   name: 'bodyPositionList',
   name: 'bodyPositionList',
   initialState,
   initialState,
   reducers: {
   reducers: {
-    addBodyPosition: (state, action: PayloadAction<BodyPosition>) => {
+    addBodyPosition: (state, action: PayloadAction<ExtendedBodyPosition>) => {
       state.bodyPositions.push(action.payload);
       state.bodyPositions.push(action.payload);
     },
     },
-    setBodyPositions: (state, action: PayloadAction<BodyPosition[]>) => {
+    setBodyPositions: (
+      state,
+      action: PayloadAction<ExtendedBodyPosition[]>
+    ) => {
       state.bodyPositions = action.payload;
       state.bodyPositions = action.payload;
     },
     },
   },
   },
 });
 });
 
 
-export const { addBodyPosition, setBodyPositions } = bodyPositionListSlice.actions;
+export const { addBodyPosition, setBodyPositions } =
+  bodyPositionListSlice.actions;
 export default bodyPositionListSlice.reducer;
 export default bodyPositionListSlice.reducer;

+ 2 - 0
src/states/store.ts

@@ -9,6 +9,7 @@ import BusinessFlowReducer from './BusinessFlowSlice';
 import systemModeReducer from './systemModeSlice';
 import systemModeReducer from './systemModeSlice';
 import examWorksCacheReducer from './exam/examWorksCacheSlice';
 import examWorksCacheReducer from './exam/examWorksCacheSlice';
 import bodyPositionListReducer from './exam/bodyPositionListSlice';
 import bodyPositionListReducer from './exam/bodyPositionListSlice';
+import bodyPositionDetailReducer from './exam/bodyPositionDetailSlice';
 import {
 import {
   workEntitiesSlice,
   workEntitiesSlice,
   workFiltersSlice,
   workFiltersSlice,
@@ -29,6 +30,7 @@ const store = configureStore({
     systemMode: systemModeReducer,
     systemMode: systemModeReducer,
     examWorksCache: examWorksCacheReducer,
     examWorksCache: examWorksCacheReducer,
     bodyPositionList: bodyPositionListReducer,
     bodyPositionList: bodyPositionListReducer,
+    bodyPositionDetail: bodyPositionDetailReducer,
     workEntities: workEntitiesSlice.reducer,
     workEntities: workEntitiesSlice.reducer,
     workFilters: workFiltersSlice.reducer,
     workFilters: workFiltersSlice.reducer,
     workPagination: workPaginationSlice.reducer,
     workPagination: workPaginationSlice.reducer,