Browse Source

添加 矩形裁剪 ui

sw 2 days ago
parent
commit
8f516b2a9b

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

@@ -3,7 +3,7 @@ import { Button, Flex } from 'antd';
 import '@/themes/truncateText.css';
 import { useDispatch } from 'react-redux';
 import { setAction } from '@/states/view/functionAreaSlice';
-import { switchToMeasurementPanel, switchToMorePanel, switchToAdvancedProcessingPanel } from '@/states/panelSwitchSliceForView';
+import { switchToMeasurementPanel, switchToMorePanel, switchToAdvancedProcessingPanel, switchToRectCropPanel } from '@/states/panelSwitchSliceForView';
 import Icon from '@/components/Icon';
 import { showNotImplemented } from '@/utils/notificationHelper';
 
@@ -33,6 +33,9 @@ const FunctionButton = ({
     if (action === 'Image Measurement') {
       // 切换到测量面板
       dispatch(switchToMeasurementPanel());
+    } else if (action === 'Rectangle Crop') {
+      // 切换到矩形裁剪面板
+      dispatch(switchToRectCropPanel());
     } else if (action === 'More') {
       // 切换到更多功能面板
       dispatch(switchToMorePanel());
@@ -207,6 +210,11 @@ const FunctionArea = () => {
         action="Image Measurement"
         iconName="btn_Measurements"
       />
+      <FunctionButton
+        title="矩形裁剪"
+        action="Rectangle Crop"
+        iconName="btn_RectCrop"
+      />
       <FunctionButton title="More" action="More" iconName="btn_OtherSetting" />
     </Flex>
   );

+ 3 - 0
src/pages/view/components/OperationPanel.tsx

@@ -6,6 +6,7 @@ import SendPanelForView from '../../output/SendPanelForView';
 import MeasurementPanel from './MeasurementPanel';
 import MorePanel from './MorePanel';
 import AdvancedProcessingPanel from './AdvancedProcessingPanel';
+import RectCropPanel from './RectCropPanel';
 import ImageStateControl from './ImageStateControl';
 import { RootState } from '../../../states/store';
 
@@ -42,6 +43,8 @@ const OperationPanel = () => {
         return <MorePanel />;
       case 'AdvancedProcessingPanel':
         return <AdvancedProcessingPanel />;
+      case 'RectCropPanel':
+        return <RectCropPanel />;
       default:
         return (
           <Flex 

+ 179 - 0
src/pages/view/components/RectCropPanel.tsx

@@ -0,0 +1,179 @@
+import React from 'react';
+import { Layout, Button, Typography, Flex } from 'antd';
+import { ArrowLeftOutlined } from '@ant-design/icons';
+import { useDispatch, useSelector } from 'react-redux';
+import { switchToOperationPanel } from '../../../states/panelSwitchSliceForView';
+import {
+  setCropAction,
+  setRatio,
+  type CropAction,
+  type CropRatio,
+} from '../../../states/view/rectCropPanelSlice';
+import { RootState } from '../../../states/store';
+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 dispatch = useDispatch();
+
+  const handleCropAction = (action: string) => {
+    console.log(`执行裁剪操作: ${action}`);
+    dispatch(setCropAction(action as CropAction));
+  };
+
+  return (
+    <Button
+      onClick={() => handleCropAction(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"
+    >
+      {!iconName && <span style={{ fontSize: '10px' }}>{title}</span>}
+    </Button>
+  );
+};
+
+// 比例按钮组件
+const RatioButton = ({
+  ratio,
+  isSelected,
+}: {
+  ratio: CropRatio;
+  isSelected: boolean;
+}) => {
+  const dispatch = useDispatch();
+
+  const handleClick = () => {
+    dispatch(setRatio(ratio));
+  };
+
+  return (
+    <Button
+      onClick={handleClick}
+      style={{
+        width: '100%',
+        height: '40px',
+        fontSize: '14px',
+        backgroundColor: isSelected ? '#3a3a3a' : '#2a2a2a',
+        color: '#fff',
+        borderColor: isSelected ? '#555' : '#444',
+      }}
+    >
+      {ratio}
+    </Button>
+  );
+};
+
+const RectCropPanel = () => {
+  const dispatch = useDispatch();
+  const selectedRatio = useSelector(
+    (state: RootState) => state.rectCropPanel.selectedRatio
+  );
+
+  const handleReturn = () => {
+    dispatch(switchToOperationPanel());
+  };
+
+  // 比例数据,按两列排列
+  const ratios: CropRatio[] = [
+    '8x10',
+    '10x8',
+    '10x12',
+    '12x10',
+    '10x14',
+    '14x10',
+    '11x14',
+    '14x11',
+    '14x17',
+    '17x14',
+    '14x14',
+    '17x17',
+  ];
+
+  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' }}>
+          <Flex wrap gap="small" align="center" justify="start" className="p-1">
+            <FunctionButton title="裁剪图像" action="裁剪图像" />
+            <FunctionButton title="撤销遮线框" action="撤销遮线框" />
+            <FunctionButton title="添加Mask" action="添加Mask" />
+            <FunctionButton title="删除Mask" action="删除Mask" />
+            <FunctionButton title="重新计算EXI" action="重新计算EXI" />
+          </Flex>
+        </div>
+
+        {/* 尺寸比例选择区域 */}
+        <div style={{ marginBottom: '24px' }}>
+          <div
+            style={{
+              display: 'grid',
+              gridTemplateColumns: '1fr 1fr',
+              gap: '8px',
+            }}
+          >
+            {ratios.map((ratio) => (
+              <RatioButton
+                key={ratio}
+                ratio={ratio}
+                isSelected={selectedRatio === ratio}
+              />
+            ))}
+          </div>
+        </div>
+      </Content>
+    </Layout>
+  );
+};
+
+export default RectCropPanel;

+ 5 - 1
src/states/panelSwitchSliceForView.ts

@@ -1,7 +1,7 @@
 import { createSlice } from '@reduxjs/toolkit';
 
 interface PanelSwitchStateForView {
-  currentPanel: 'OperationPanel' | 'SendPanel' | 'MeasurementPanel' | 'MorePanel' | 'AdvancedProcessingPanel';
+  currentPanel: 'OperationPanel' | 'SendPanel' | 'MeasurementPanel' | 'MorePanel' | 'AdvancedProcessingPanel' | 'RectCropPanel';
 }
 
 const initialState: PanelSwitchStateForView = {
@@ -27,6 +27,9 @@ const panelSwitchSliceForView = createSlice({
     switchToAdvancedProcessingPanel: (state) => {
       state.currentPanel = 'AdvancedProcessingPanel';
     },
+    switchToRectCropPanel: (state) => {
+      state.currentPanel = 'RectCropPanel';
+    },
   },
 });
 
@@ -36,5 +39,6 @@ export const {
   switchToMeasurementPanel,
   switchToMorePanel,
   switchToAdvancedProcessingPanel,
+  switchToRectCropPanel,
 } = panelSwitchSliceForView.actions;
 export default panelSwitchSliceForView.reducer;

+ 2 - 0
src/states/store.ts

@@ -18,6 +18,7 @@ import { aprMiddleware } from './exam/aprSlice';
 import functionAreaReducer from './view/functionAreaSlice';
 import measurementPanelReducer from './view/measurementPanelSlice';
 import advancedProcessingPanelReducer from './view/advancedProcessingPanelSlice';
+import rectCropPanelReducer from './view/rectCropPanelSlice';
 import viewerContainerReducer from './view/viewerContainerSlice';
 import searchReducer from './patient/worklist/slices/searchSlice';
 import businessFlowMiddleware from './businessFlowMiddleware';
@@ -100,6 +101,7 @@ const store = configureStore({
     functionArea: functionAreaReducer,
     measurementPanel: measurementPanelReducer,
     advancedProcessingPanel: advancedProcessingPanelReducer,
+    rectCropPanel: rectCropPanelReducer,
     viewerContainer: viewerContainerReducer,
     workEntities: workEntitiesSlice.reducer,
     workFilters: workFiltersSlice.reducer,

+ 55 - 0
src/states/view/rectCropPanelSlice.ts

@@ -0,0 +1,55 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+export type CropAction =
+  | '裁剪图像'
+  | '撤销遮线框'
+  | '添加Mask'
+  | '删除Mask'
+  | '重新计算EXI';
+
+export type CropRatio =
+  | '8x10'
+  | '10x8'
+  | '10x12'
+  | '12x10'
+  | '10x14'
+  | '14x10'
+  | '11x14'
+  | '14x11'
+  | '14x17'
+  | '17x14'
+  | '14x14'
+  | '17x17';
+
+interface RectCropPanelState {
+  currentAction: CropAction | null;
+  selectedRatio: CropRatio | null;
+}
+
+const initialState: RectCropPanelState = {
+  currentAction: null,
+  selectedRatio: null,
+};
+
+const rectCropPanelSlice = createSlice({
+  name: 'rectCropPanel',
+  initialState,
+  reducers: {
+    setCropAction: (state, action: PayloadAction<CropAction>) => {
+      state.currentAction = action.payload;
+      console.log(`裁剪操作: ${action.payload}`);
+    },
+    setRatio: (state, action: PayloadAction<CropRatio>) => {
+      state.selectedRatio = action.payload;
+      console.log(`选择裁剪比例: ${action.payload}`);
+    },
+    clearCropState: (state) => {
+      state.currentAction = null;
+      state.selectedRatio = null;
+    },
+  },
+});
+
+export const { setCropAction, setRatio, clearCropState } =
+  rectCropPanelSlice.actions;
+export default rectCropPanelSlice.reducer;