Преглед изворни кода

feat: 实现图像测量面板功能

- 新增 src/pages/view/components/MeasurementPanel.tsx 测量面板组件
- 修改 src/states/panelSwitchSliceForView.ts 添加测量面板状态管理
- 修改 src/pages/view/components/FunctionArea.tsx 更新测量按钮切换逻辑
- 修改 src/pages/view/components/OperationPanel.tsx 集成测量面板渲染

包含基础测量、专业测量和宠物专用测量共22个功能按钮
sw пре 2 недеља
родитељ
комит
fd7f0293f6

+ 8 - 1
src/pages/view/components/FunctionArea.tsx

@@ -3,6 +3,7 @@ import { Button, Flex } from 'antd';
 import '@/themes/truncateText.css';
 import { useDispatch } from 'react-redux';
 import { setAction } from '@/states/view/functionAreaSlice';
+import { switchToMeasurementPanel } from '@/states/panelSwitchSliceForView';
 import Icon from '@/components/Icon';
 
 const FunctionButton = ({
@@ -17,7 +18,13 @@ const FunctionButton = ({
   const dispatch = useDispatch();
 
   const handleButtonClick = () => {
-    dispatch(setAction(action));
+    if (action === 'Image Measurement') {
+      // 切换到测量面板
+      dispatch(switchToMeasurementPanel());
+    } else {
+      // 其他功能按钮保持原有逻辑
+      dispatch(setAction(action));
+    }
   };
 
   return (

+ 237 - 0
src/pages/view/components/MeasurementPanel.tsx

@@ -0,0 +1,237 @@
+import React from 'react';
+import { Layout, Button, Typography, Divider, Flex } from 'antd';
+import { ArrowLeftOutlined } from '@ant-design/icons';
+import { useDispatch } from 'react-redux';
+import { switchToOperationPanel } from '../../../states/panelSwitchSliceForView';
+import Icon from '@/components/Icon';
+import '@/themes/truncateText.css';
+
+const { Header, Content } = Layout;
+const { Title, Text } = Typography;
+
+const FunctionButton = ({
+  title,
+  action,
+  iconName,
+}: {
+  title: string;
+  action: string;
+  iconName: string;
+}) => {
+  const handleMeasurementAction = (action: string) => {
+    console.log(`执行测量操作: ${action}`);
+    // 这里可以添加具体的测量逻辑
+  };
+
+  return (
+    <Button
+      onClick={() => handleMeasurementAction(action)}
+      icon={
+        iconName ? (
+          <Icon
+            module="module-process"
+            name={iconName}
+            userId="base"
+            theme="default"
+            size="2x"
+            state="normal"
+          />
+        ) : undefined
+      }
+      style={{
+        width: '1.5rem',
+        height: '1.5rem',
+        padding: 0,
+      }}
+      title={title}
+      className="truncate-text"
+    >
+      {/* {title} */}
+    </Button>
+  );
+};
+
+const MeasurementPanel = () => {
+  const dispatch = useDispatch();
+
+  const handleReturn = () => {
+    dispatch(switchToOperationPanel());
+  };
+
+  return (
+    <Layout className="h-full">
+      {/* 顶部导航栏 */}
+      <Header
+        style={{
+          display: 'flex',
+          alignItems: 'center',
+          padding: '0 16px',
+        }}
+      >
+        <Button
+          type="text"
+          icon={<ArrowLeftOutlined />}
+          onClick={handleReturn}
+        />
+        <Title level={5} style={{ margin: 0, lineHeight: '48px' }}>
+          图像测量
+        </Title>
+      </Header>
+
+      {/* 主体内容 */}
+      <Content
+        style={{ padding: '16px', maxHeight: '100%', overflowY: 'auto' }}
+      >
+        {/* 基础测量组 */}
+        <div style={{ marginBottom: '24px' }}>
+          <Text
+            strong
+            style={{ fontSize: '14px', marginBottom: '12px', display: 'block' }}
+          >
+            基础测量
+          </Text>
+          <Flex wrap gap="small" align="center" justify="start" className="p-1">
+            <FunctionButton
+              title="线段测量"
+              action="线段测量"
+              iconName="LineMeasurement"
+            />
+            <FunctionButton
+              title="角度测量"
+              action="角度测量"
+              iconName="AngleMeasurement"
+            />
+            <FunctionButton
+              title="清除测量"
+              action="清除测量"
+              iconName="ClearMeasurement"
+            />
+            <FunctionButton
+              title="测量校正"
+              action="测量校正"
+              iconName="MeasurementCalibration"
+            />
+          </Flex>
+          <div style={{ marginTop: '8px', fontSize: '12px', color: '#666' }}>
+            说明:要选择测量标记,即线段测量标记
+          </div>
+        </div>
+
+        <Divider />
+
+        {/* 专业测量组 */}
+        <div style={{ marginBottom: '24px' }}>
+          <Text
+            strong
+            style={{ fontSize: '14px', marginBottom: '12px', display: 'block' }}
+          >
+            专业测量
+          </Text>
+          <Flex wrap gap="small" align="center" justify="start" className="p-1">
+            <FunctionButton
+              title="Cobb角"
+              action="Cobb角"
+              iconName="CobbAngle"
+            />
+          </Flex>
+        </div>
+
+        <Divider />
+
+        {/* 宠物专用测量组 */}
+        <div style={{ marginBottom: '24px' }}>
+          <Text
+            strong
+            style={{ fontSize: '14px', marginBottom: '12px', display: 'block' }}
+          >
+            宠物专用测量
+          </Text>
+          <Flex wrap gap="small" align="center" justify="start" className="p-1">
+            <FunctionButton
+              title="髋臼水平角"
+              action="髋臼水平角"
+              iconName=""
+            />
+            <FunctionButton
+              title="胫骨平台夹角"
+              action="胫骨平台夹角"
+              iconName=""
+            />
+            <FunctionButton
+              title="髋关节牵引指数"
+              action="髋关节牵引指数"
+              iconName=""
+            />
+            <FunctionButton
+              title="髋关节水平角"
+              action="髋关节水平角"
+              iconName=""
+            />
+            <FunctionButton title="心锥比" action="心锥比" iconName="" />
+            <FunctionButton
+              title="胫骨平台骨切开术"
+              action="胫骨平台骨切开术"
+              iconName=""
+            />
+            <FunctionButton
+              title="胫骨结节前移术"
+              action="胫骨结节前移术"
+              iconName=""
+            />
+            <FunctionButton
+              title="胫骨结节前移术5点测量法"
+              action="胫骨结节前移术5点测量法"
+              iconName=""
+            />
+            <FunctionButton
+              title="水平截骨术"
+              action="水平截骨术"
+              iconName=""
+            />
+            <FunctionButton
+              title="股骨头覆盖率"
+              action="股骨头覆盖率"
+              iconName=""
+            />
+            <FunctionButton
+              title="髋臼背覆盖"
+              action="髋臼背覆盖"
+              iconName=""
+            />
+            <FunctionButton
+              title="拆线长度测量"
+              action="拆线长度测量"
+              iconName=""
+            />
+            <FunctionButton
+              title="多边形长度测量"
+              action="多边形长度测量"
+              iconName=""
+            />
+            <FunctionButton title="找圆心" action="找圆心" iconName="" />
+            <FunctionButton title="找中线" action="找中线" iconName="" />
+            <FunctionButton title="找中点" action="找中点" iconName="" />
+            <FunctionButton
+              title="直线垂直倾斜度"
+              action="直线垂直倾斜度"
+              iconName=""
+            />
+            <FunctionButton
+              title="直线水平倾斜度"
+              action="直线水平倾斜度"
+              iconName=""
+            />
+            <FunctionButton
+              title="矩形区域灰度"
+              action="矩形区域灰度"
+              iconName=""
+            />
+            <FunctionButton title="直线灰度" action="直线灰度" iconName="" />
+          </Flex>
+        </div>
+      </Content>
+    </Layout>
+  );
+};
+
+export default MeasurementPanel;

+ 35 - 18
src/pages/view/components/OperationPanel.tsx

@@ -1,9 +1,9 @@
-import React from 'react';
 import { Layout } from 'antd';
 import { useSelector } from 'react-redux';
 import FunctionArea from './FunctionArea';
 import TransferArea from './TransferArea';
 import SendPanelForView from '../../output/SendPanelForView';
+import MeasurementPanel from './MeasurementPanel';
 import { RootState } from '../../../states/store';
 
 const { Content, Footer } = Layout;
@@ -13,23 +13,40 @@ const OperationPanel = () => {
     (state: RootState) => state.panelSwitchForView.currentPanel
   );
 
-  return (
-    <Layout className="h-full">
-      {currentPanel === 'OperationPanel' ? (
-        <>
-          <Content>
-            <FunctionArea />
-          </Content>
-          <Footer className="p-1">
-            <div>Image State Control</div>
-            <TransferArea />
-          </Footer>
-        </>
-      ) : (
-        <SendPanelForView />
-      )}
-    </Layout>
-  );
+  const renderPanel = () => {
+    switch (currentPanel) {
+      case 'OperationPanel':
+        return (
+          <>
+            <Content>
+              <FunctionArea />
+            </Content>
+            <Footer className="p-1">
+              <div>Image State Control</div>
+              <TransferArea />
+            </Footer>
+          </>
+        );
+      case 'SendPanel':
+        return <SendPanelForView />;
+      case 'MeasurementPanel':
+        return <MeasurementPanel />;
+      default:
+        return (
+          <>
+            <Content>
+              <FunctionArea />
+            </Content>
+            <Footer className="p-1">
+              <div>Image State Control</div>
+              <TransferArea />
+            </Footer>
+          </>
+        );
+    }
+  };
+
+  return <Layout className="h-full">{renderPanel()}</Layout>;
 };
 
 export default OperationPanel;

+ 9 - 3
src/states/panelSwitchSliceForView.ts

@@ -1,7 +1,7 @@
 import { createSlice } from '@reduxjs/toolkit';
 
 interface PanelSwitchStateForView {
-  currentPanel: 'OperationPanel' | 'SendPanel';
+  currentPanel: 'OperationPanel' | 'SendPanel' | 'MeasurementPanel';
 }
 
 const initialState: PanelSwitchStateForView = {
@@ -18,9 +18,15 @@ const panelSwitchSliceForView = createSlice({
     switchToSendPanel: (state) => {
       state.currentPanel = 'SendPanel';
     },
+    switchToMeasurementPanel: (state) => {
+      state.currentPanel = 'MeasurementPanel';
+    },
   },
 });
 
-export const { switchToOperationPanel, switchToSendPanel } =
-  panelSwitchSliceForView.actions;
+export const {
+  switchToOperationPanel,
+  switchToSendPanel,
+  switchToMeasurementPanel,
+} = panelSwitchSliceForView.actions;
 export default panelSwitchSliceForView.reducer;