Sfoglia il codice sorgente

fix (1.28.0 -> 1.28.1): 修复bug 161 - 体位操作按钮根据产品类型条件渲染

- 新增 BodyPositionActionButtons 组件,提供添加、删除、复制体位按钮
- 修改 BodyPositionList 组件,根据 productName 为 'VETDROS' 条件渲染操作按钮
- 对于 VETDROS 产品显示完整的操作按钮组,其他产品显示原有的添加按钮
- 确保体位操作功能根据产品类型正确显示,提升用户界面一致性

改动文件:
- src/pages/exam/components/BodyPositionList.tsx
- src/pages/exam/components/BodyPositionActionButtons.tsx
dengdx 2 settimane fa
parent
commit
92288fcfe5

+ 15 - 0
CHANGELOG.md

@@ -2,6 +2,21 @@
 
 本项目的所有重要变更都将记录在此文件中。
 
+## [1.28.1] - 2025-12-25 17:59
+
+### 修复 (Fixed)
+- **修复bug 161 - 体位操作按钮根据产品类型条件渲染**
+  - 新增 BodyPositionActionButtons 组件,提供添加、删除、复制体位按钮
+  - 修改 BodyPositionList 组件,根据 productName 为 'VETDROS' 条件渲染操作按钮
+  - 对于 VETDROS 产品显示完整的操作按钮组,其他产品显示原有的添加按钮
+  - 确保体位操作功能根据产品类型正确显示,提升用户界面一致性
+
+**改动文件:**
+- src/pages/exam/components/BodyPositionList.tsx
+- src/pages/exam/components/BodyPositionActionButtons.tsx
+
+---
+
 ## [1.28.0] - 2025-12-25 17:37
 
 ### 新增 (Added)

+ 2 - 2
config/dev.ts

@@ -21,14 +21,14 @@ export default {
     devServer: {
       proxy: {
         '/dr': {
-          target: 'http://192.168.110.13:6001', // 你的后端服务地址
+          target: 'http://192.168.110.245:6001', // 你的后端服务地址
           changeOrigin: true, // 允许跨域
           // pathRewrite: {
           //   '^/dr/api': '' // 可选,用于重写路径
           // }
         },
         '/mqtt': {
-          target: 'ws://192.168.110.13:8083', // MQTT WebSocket 服务地址
+          target: 'ws://192.168.110.245:8083', // MQTT WebSocket 服务地址
           changeOrigin: true,
           ws: true, // 启用 WebSocket 代理
           // pathRewrite: {

+ 1 - 1
package.json

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

+ 154 - 0
src/pages/exam/components/BodyPositionActionButtons.tsx

@@ -0,0 +1,154 @@
+import React, { useState } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import { Button, Tooltip, message } from 'antd';
+import { useIntl } from 'react-intl';
+import { RootState, AppDispatch } from '../../../states/store';
+import { deleteBodyPosition } from '../../../API/patient/viewActions';
+import { copyPositionThunk } from '../../../states/exam/examWorksCacheSlice';
+import {
+  removeBodyPositionBySopInstanceUid,
+  setByIndex,
+} from '../../../states/exam/bodyPositionListSlice';
+import Icon from '@/components/Icon';
+import AppendViewModal from './AppendViewModal';
+
+const BodyPositionActionButtons: React.FC = () => {
+  const intl = useIntl();
+  const dispatch = useDispatch<AppDispatch>();
+
+  const selectedBodyPosition = useSelector(
+    (state: RootState) => state.bodyPositionList.selectedBodyPosition
+  );
+  const bodyPositions = useSelector(
+    (state: RootState) => state.bodyPositionList.bodyPositions
+  );
+
+  const [isAppendModalOpen, setIsAppendModalOpen] = useState(false);
+
+  const addBodyPositionClick = (): void => {
+    console.log('[BodyPositionActionButtons] Add button clicked');
+    console.log(
+      '[BodyPositionActionButtons] selectedBodyPosition:',
+      selectedBodyPosition
+    );
+    if (!selectedBodyPosition) {
+      message.warning('请先选择一个体位');
+      return;
+    }
+    console.log('[BodyPositionActionButtons] Opening append modal');
+    setIsAppendModalOpen(true);
+  };
+
+  const handleDelete = async () => {
+    if (!selectedBodyPosition) {
+      message.warning('请先选择一个体位');
+      return;
+    }
+
+    // 检查体位数量,至少保留一个
+    if (bodyPositions.length <= 1) {
+      message.warning('至少需要保留一个体位,无法删除');
+      return;
+    }
+
+    console.log(
+      `选中的体位:${JSON.stringify(selectedBodyPosition)}`
+    );
+    if (selectedBodyPosition.sop_instance_uid) {
+      try {
+        await deleteBodyPosition(selectedBodyPosition.sop_instance_uid);
+        dispatch(
+          removeBodyPositionBySopInstanceUid(
+            selectedBodyPosition.sop_instance_uid
+          )
+        );
+        dispatch(setByIndex(0));
+        message.success('体位删除成功');
+      } catch (error) {
+        console.error('Error deleting body position:', error);
+        message.error('删除体位失败');
+      }
+    }
+  };
+
+  const handleCopy = () => {
+    const instanceUid =
+      selectedBodyPosition?.study_instance_uid ?? '';
+    console.log('Copying position for instance UID:', instanceUid);
+    console.log(
+      `${JSON.stringify(selectedBodyPosition)}`
+    );
+    if (instanceUid) {
+      dispatch(copyPositionThunk({ instanceUid }));
+    } else {
+      message.warning('无法获取体位信息');
+    }
+  };
+
+  return (
+    <>
+      <div className="flex justify-center gap-2">
+        <Tooltip title={intl.formatMessage({ id: 'exam.action.addMorePositions' })}>
+          <Button
+            style={{ width: '1.5rem', height: '1.5rem' }}
+            icon={
+              <Icon
+                module="module-exam"
+                name="btn_AppendView"
+                userId="base"
+                theme="default"
+                size="2x"
+                state="normal"
+              />
+            }
+            onClick={addBodyPositionClick}
+          />
+        </Tooltip>
+
+        <Tooltip title={intl.formatMessage({ id: 'exam.action.deletePosition' })}>
+          <Button
+            style={{ width: '1.5rem', height: '1.5rem' }}
+            icon={
+              <Icon
+                module="module-exam"
+                name="btn_DeleteView"
+                userId="base"
+                theme="default"
+                size="2x"
+                state="normal"
+              />
+            }
+            onClick={handleDelete}
+          />
+        </Tooltip>
+
+        <Tooltip title={intl.formatMessage({ id: 'exam.action.copyPosition' })}>
+          <Button
+            style={{ width: '1.5rem', height: '1.5rem' }}
+            icon={
+              <Icon
+                module="module-exam"
+                name="btn_Copy"
+                userId="base"
+                theme="default"
+                size="2x"
+                state="normal"
+              />
+            }
+            onClick={handleCopy}
+          />
+        </Tooltip>
+      </div>
+
+      <AppendViewModal
+        open={isAppendModalOpen}
+        onCancel={() => setIsAppendModalOpen(false)}
+        onSuccess={() => {
+          setIsAppendModalOpen(false);
+        }}
+      />
+    </>
+  );
+};
+
+export default BodyPositionActionButtons;

+ 20 - 14
src/pages/exam/components/BodyPositionList.tsx

@@ -13,6 +13,7 @@ import {
   autoSelectFirstBodyPosition,
 } from '@/domain/exam/bodyPositionSelection';
 import AppendViewModal from './AppendViewModal';
+import BodyPositionActionButtons from './BodyPositionActionButtons';
 
 interface BodyPositionListProps {
   layout: 'horizontal' | 'vertical';
@@ -64,6 +65,7 @@ const BodyPositionList: React.FC<BodyPositionListProps> = ({
   const selectedBodyPosition = useSelector(
     (state: RootState) => state.bodyPositionList.selectedBodyPosition
   );
+  const productName = useSelector((state: RootState) => state.product.productName);
 
   // 🔧 修复:使用 ref 跟踪是否已经执行过初始化
   // 避免在 judgeImage 等操作导致 bodyPositions 引用改变时重复执行
@@ -178,23 +180,27 @@ const BodyPositionList: React.FC<BodyPositionListProps> = ({
       </div>
 
       {showAddButton && (
-        <Tooltip title={intl.formatMessage({ id: 'exam.action.addMorePositions' })}>
-          <div
-            className="mx-auto cursor-pointer"
-            style={{ width: '50%' }}
-            onClick={addBodyPositionClick}
-          >
+        productName === 'VETDROS' ? (
+          <BodyPositionActionButtons />
+        ) : (
+          <Tooltip title={intl.formatMessage({ id: 'exam.action.addMorePositions' })}>
             <div
-              style={{
-                stroke: 'var(--color-primary)',
-                strokeWidth: 0.5,
-                color: 'var(--color-text)',
-              }}
+              className="mx-auto cursor-pointer"
+              style={{ width: '50%' }}
+              onClick={addBodyPositionClick}
             >
-              <AppendViewIcon className="w-full h-full hover:opacity-100 " />
+              <div
+                style={{
+                  stroke: 'var(--color-primary)',
+                  strokeWidth: 0.5,
+                  color: 'var(--color-text)',
+                }}
+              >
+                <AppendViewIcon className="w-full h-full hover:opacity-100 " />
+              </div>
             </div>
-          </div>
-        </Tooltip>
+          </Tooltip>
+        )
       )}
 
       <AppendViewModal