RectCropPanel.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import React from 'react';
  2. import { Layout, Button, Typography, Flex } from 'antd';
  3. import { ArrowLeftOutlined } from '@ant-design/icons';
  4. import { useIntl } from 'react-intl';
  5. import { useDispatch, useSelector } from 'react-redux';
  6. import { switchToOperationPanel } from '../../../states/panelSwitchSliceForView';
  7. import {
  8. setCropAction,
  9. setRatio,
  10. type CropAction,
  11. type CropRatio,
  12. } from '../../../states/view/rectCropPanelSlice';
  13. import { RootState } from '../../../states/store';
  14. import Icon from '@/components/Icon';
  15. import '@/themes/truncateText.css';
  16. const { Header, Content } = Layout;
  17. const { Title, Text } = Typography;
  18. // 功能按钮组件
  19. const FunctionButton = ({
  20. title,
  21. action,
  22. iconName,
  23. }: {
  24. title: string;
  25. action: string;
  26. iconName?: string;
  27. }) => {
  28. const dispatch = useDispatch();
  29. const handleCropAction = (action: string) => {
  30. console.log(`执行裁剪操作: ${action}`);
  31. dispatch(setCropAction(action as CropAction));
  32. };
  33. return (
  34. <Button
  35. onClick={() => handleCropAction(action)}
  36. icon={
  37. iconName ? (
  38. <Icon
  39. module="module-process"
  40. name={iconName}
  41. userId="base"
  42. theme="default"
  43. size="2x"
  44. state="normal"
  45. />
  46. ) : undefined
  47. }
  48. style={{
  49. width: '1.5rem',
  50. height: '1.5rem',
  51. padding: 0,
  52. }}
  53. title={title}
  54. className="truncate-text"
  55. >
  56. {!iconName && <span style={{ fontSize: '10px' }}>{title}</span>}
  57. </Button>
  58. );
  59. };
  60. // 比例按钮组件
  61. const RatioButton = ({
  62. ratio,
  63. isSelected,
  64. }: {
  65. ratio: CropRatio;
  66. isSelected: boolean;
  67. }) => {
  68. const dispatch = useDispatch();
  69. const handleClick = () => {
  70. dispatch(setRatio(ratio));
  71. };
  72. return (
  73. <Button
  74. onClick={handleClick}
  75. style={{
  76. width: '100%',
  77. height: '40px',
  78. fontSize: '14px',
  79. backgroundColor: isSelected ? '#3a3a3a' : '#2a2a2a',
  80. color: '#fff',
  81. borderColor: isSelected ? '#555' : '#444',
  82. }}
  83. >
  84. {ratio}
  85. </Button>
  86. );
  87. };
  88. const RectCropPanel = () => {
  89. const intl = useIntl();
  90. const dispatch = useDispatch();
  91. const selectedRatio = useSelector(
  92. (state: RootState) => state.rectCropPanel.selectedRatio
  93. );
  94. const handleReturn = () => {
  95. dispatch(switchToOperationPanel());
  96. };
  97. // 比例数据,按两列排列
  98. const ratios: CropRatio[] = [
  99. '8x10',
  100. '10x8',
  101. '10x12',
  102. '12x10',
  103. '10x14',
  104. '14x10',
  105. '11x14',
  106. '14x11',
  107. '14x17',
  108. '17x14',
  109. '14x14',
  110. '17x17',
  111. ];
  112. return (
  113. <Layout className="h-full">
  114. {/* 顶部导航栏 */}
  115. <Header
  116. style={{
  117. display: 'flex',
  118. alignItems: 'center',
  119. padding: '0 16px',
  120. }}
  121. >
  122. <Button
  123. type="text"
  124. icon={<ArrowLeftOutlined />}
  125. onClick={handleReturn}
  126. />
  127. <Title level={5} style={{ margin: 0, lineHeight: '48px' }}>
  128. {intl.formatMessage({ id: 'rectCropPanel.title' })}
  129. </Title>
  130. </Header>
  131. {/* 主体内容 */}
  132. <Content
  133. style={{ padding: '16px', maxHeight: '100%', overflowY: 'auto' }}
  134. >
  135. {/* 功能按钮区域 */}
  136. <div style={{ marginBottom: '24px' }}>
  137. <Flex wrap gap="small" align="center" justify="start" className="p-1">
  138. <FunctionButton title={intl.formatMessage({ id: 'rectCropPanel.cropImage' })} action="裁剪图像" />
  139. <FunctionButton title={intl.formatMessage({ id: 'rectCropPanel.undoMask' })} action="撤销遮线框" />
  140. <FunctionButton title={intl.formatMessage({ id: 'rectCropPanel.addMask' })} action="添加Mask" />
  141. <FunctionButton title={intl.formatMessage({ id: 'rectCropPanel.deleteMask' })} action="删除Mask" />
  142. <FunctionButton title={intl.formatMessage({ id: 'rectCropPanel.recalculateEXI' })} action="重新计算EXI" />
  143. </Flex>
  144. </div>
  145. {/* 尺寸比例选择区域 */}
  146. <div style={{ marginBottom: '24px' }}>
  147. <div
  148. style={{
  149. display: 'grid',
  150. gridTemplateColumns: '1fr 1fr',
  151. gap: '8px',
  152. }}
  153. >
  154. {ratios.map((ratio) => (
  155. <RatioButton
  156. key={ratio}
  157. ratio={ratio}
  158. isSelected={selectedRatio === ratio}
  159. />
  160. ))}
  161. </div>
  162. </div>
  163. </Content>
  164. </Layout>
  165. );
  166. };
  167. export default RectCropPanel;