InvertContrastModal.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /**
  2. * InvertContrastModal - 反色对比Modal组件
  3. *
  4. * 完整布局:左侧缩略图列表 + 中间对比区域 + 底部工具栏
  5. */
  6. import React, { useEffect } from 'react';
  7. import { Modal } from 'antd';
  8. import * as cornerstone from '@cornerstonejs/core';
  9. import { useSelector, useDispatch } from 'react-redux';
  10. import { RootState, AppDispatch } from '@/states/store';
  11. import {
  12. selectIsModalOpen,
  13. selectSelectedPositions,
  14. closeInvertContrastModal,
  15. updateSelectedPositions
  16. } from '@/states/view/invertContrastSlice';
  17. import { StackViewerWithErrorBoundary, invertContrast } from './viewers/stack.image.viewer';
  18. import InvertContrastThumbnailList from './InvertContrastThumbnailList';
  19. import InvertContrastToolbar from './InvertContrastToolbar';
  20. const InvertContrastModal: React.FC = () => {
  21. const dispatch = useDispatch<AppDispatch>();
  22. const isOpen = useSelector(selectIsModalOpen);
  23. const selectedPositions = useSelector(selectSelectedPositions);
  24. const renderingEngineId = 'myRenderingEngine'; // 重用主渲染引擎
  25. // 获取左图和右图的URL
  26. const leftImageUrl = selectedPositions[0] || '';
  27. const rightImageUrl = selectedPositions[1] || selectedPositions[0] || ''; // 如果只有一个选择,右图和左图相同但应用反色
  28. const handleClose = () => {
  29. console.log('[InvertContrastModal] Closing modal');
  30. dispatch(closeInvertContrastModal());
  31. };
  32. // 应用反色效果的函数
  33. const applyInvertContrast = () => {
  34. const rightViewportId = 'invert-contrast-right';
  35. try {
  36. console.log(`[InvertContrastModal] Applying invert to ${rightViewportId} using renderingEngine ${renderingEngineId}`);
  37. invertContrast(rightViewportId);
  38. console.log('[InvertContrastModal] Invert applied successfully');
  39. } catch (error) {
  40. console.error('[InvertContrastModal] Failed to apply invert:', error);
  41. console.error('[InvertContrastModal] Error stack:', error.stack);
  42. }
  43. };
  44. // 工具栏事件处理
  45. const handleRotateLeft = () => {
  46. console.log('[InvertContrastModal] Rotate left clicked');
  47. // TODO: 实现旋转逻辑
  48. };
  49. const handleRotateRight = () => {
  50. console.log('[InvertContrastModal] Rotate right clicked');
  51. // TODO: 实现旋转逻辑
  52. };
  53. const handleHorizontalFlip = () => {
  54. console.log('[InvertContrastModal] Horizontal flip clicked');
  55. // TODO: 实现水平翻转逻辑
  56. };
  57. const handleVerticalFlip = () => {
  58. console.log('[InvertContrastModal] Vertical flip clicked');
  59. // TODO: 实现垂直翻转逻辑
  60. };
  61. const handleZoomIn = () => {
  62. console.log('[InvertContrastModal] Zoom in clicked');
  63. // TODO: 实现放大逻辑
  64. };
  65. const handleZoomOut = () => {
  66. console.log('[InvertContrastModal] Zoom out clicked');
  67. // TODO: 实现缩小逻辑
  68. };
  69. const handleReset = () => {
  70. console.log('[InvertContrastModal] Reset clicked');
  71. // TODO: 实现重置逻辑
  72. };
  73. if (!isOpen) {
  74. return null;
  75. }
  76. return (
  77. <Modal
  78. title="反色对比"
  79. open={isOpen}
  80. onCancel={handleClose}
  81. width="95vw"
  82. style={{
  83. top: 20,
  84. maxWidth: '95vw',
  85. }}
  86. bodyStyle={{
  87. height: '85vh',
  88. padding: 0,
  89. display: 'flex',
  90. flexDirection: 'column',
  91. }}
  92. footer={null}
  93. destroyOnClose // 关闭时销毁内容,避免状态残留
  94. maskClosable={false} // 防止点击遮罩关闭
  95. >
  96. {/* 主内容区域 */}
  97. <div style={{
  98. display: 'flex',
  99. flex: 1,
  100. height: 'calc(100% - 50px)', // 减去工具栏高度
  101. }}>
  102. {/* 左侧:缩略图列表 */}
  103. <div style={{
  104. width: '280px',
  105. borderRight: '1px solid #d9d9d9',
  106. backgroundColor: '#fafafa',
  107. }}>
  108. <InvertContrastThumbnailList />
  109. </div>
  110. {/* 右侧:对比区域 */}
  111. <div style={{
  112. flex: 1,
  113. display: 'grid',
  114. gridTemplateColumns: '1fr 1fr',
  115. gap: '8px',
  116. padding: '16px',
  117. backgroundColor: '#000',
  118. }}>
  119. {/* 左侧对比图 */}
  120. <div style={{
  121. border: '1px solid #d9d9d9',
  122. position: 'relative',
  123. display: 'flex',
  124. flexDirection: 'column',
  125. backgroundColor: '#000'
  126. }}>
  127. {leftImageUrl && (
  128. <div style={{ flex: 1, overflow: 'hidden' }}>
  129. <StackViewerWithErrorBoundary
  130. imageIndex={0}
  131. imageUrls={[leftImageUrl]}
  132. viewportId="invert-contrast-left"
  133. renderingEngineId={renderingEngineId}
  134. selected={false}
  135. />
  136. </div>
  137. )}
  138. </div>
  139. {/* 右侧反色图 */}
  140. <div style={{
  141. border: '1px solid #d9d9d9',
  142. position: 'relative',
  143. display: 'flex',
  144. flexDirection: 'column',
  145. backgroundColor: '#000'
  146. }}>
  147. {rightImageUrl && (
  148. <div style={{ flex: 1, overflow: 'hidden' }}>
  149. <StackViewerWithErrorBoundary
  150. imageIndex={0}
  151. imageUrls={[rightImageUrl]}
  152. viewportId="invert-contrast-right"
  153. renderingEngineId={renderingEngineId}
  154. selected={false}
  155. onSetStackStart={(viewportId, imageIds, imageIndex) => {
  156. console.log(`[${viewportId}] setStack 开始:`, { imageIds, imageIndex });
  157. }}
  158. onSetStackComplete={(viewportId, imageIds, imageIndex, duration, success) => {
  159. console.log(`[${viewportId}] setStack 完成:`, {
  160. imageIds,
  161. imageIndex,
  162. duration: `${duration.toFixed(2)}ms`,
  163. success
  164. });
  165. if (success) {
  166. // 图像栈设置成功,可以安全地应用反色
  167. applyInvertContrast();
  168. }
  169. }}
  170. />
  171. </div>
  172. )}
  173. </div>
  174. </div>
  175. </div>
  176. {/* 底部工具栏 */}
  177. <InvertContrastToolbar
  178. onRotateLeft={handleRotateLeft}
  179. onRotateRight={handleRotateRight}
  180. onHorizontalFlip={handleHorizontalFlip}
  181. onVerticalFlip={handleVerticalFlip}
  182. onZoomIn={handleZoomIn}
  183. onZoomOut={handleZoomOut}
  184. onReset={handleReset}
  185. />
  186. </Modal>
  187. );
  188. };
  189. export default InvertContrastModal;