import { Row, Col, Select, InputNumber, Button, Switch, Divider, Tooltip, message, Flex, Modal, } from 'antd'; import ErrorMessage from '@/components/ErrorMessage'; import { patientSizes, PatientSize } from '../../states/patientSize'; import { WorkstationTypeLabels, WorkstationType } from '../../states/workstation'; import { FormattedMessage, useIntl } from 'react-intl'; import { useSelector, useDispatch, useStore } from 'react-redux'; import { deleteBodyPosition } from '../../API/patient/viewActions'; import { copyPositionThunk } from '../../states/exam/examWorksCacheSlice'; import { removeBodyPositionBySopInstanceUid, setByIndex, judgeImageThunk, } from '../../states/exam/bodyPositionListSlice'; import { RootState } from '../../states/store'; import { setAprConfig, setBodysize, setWorkstation, setThickness, setIsAECEnabled, updateAprParamsThunk, } from '../../states/exam/aprSlice'; import { workstationIdFromWorkstation } from '../../states/workstation'; import { AprParamsUpdateRequest } from '../../API/exam/APRActions'; import BodyPositionList from './components/BodyPositionList'; import BodyPositionDetail from './components/BodyPositionDetail'; import { AppDispatch } from '@/states/store'; import { useRef } from 'react'; import Icon from '@/components/Icon'; import ParaSettingCoordinator from '@/domain/exam/paraSettingCoordinator'; import { resetDevices } from '@/states/device/deviceSlice'; import { openCamera, closeCamera } from '@/states/exam/cameraSlice'; import CameraModal from '@/components/CameraModal'; const ContentAreaLarge = () => { const intl = useIntl(); const dispatch = useDispatch(); const isResetting = useSelector( (state: RootState) => state.device.status === 'loading' ); const store = useStore(); const aprConfig = useSelector((state: RootState) => state.apr.aprConfig); const bodysize = useSelector((state: RootState) => state.apr.bodysize); const workstation = useSelector((state: RootState) => state.apr.workstation); const thickness = useSelector((state: RootState) => state.apr.thickness); const isAECEnabled = useSelector( (state: RootState) => state.apr.isAECEnabled ); const currentExposureMode = useSelector( (state: RootState) => state.apr.currentExposureMode ); const productName = useSelector( (state: RootState) => state.product.productName ); const handleBodysizeChange = (key: string) => { const value = patientSizes[key as PatientSize]; // 获取对应的显示文本 console.log('体型 key:', key); // 例如: 'small' console.log('体型 value:', value); // 例如: 'Small' dispatch(setBodysize(value)); }; const handleWorkstationChange = (value: string) => { dispatch(setWorkstation(value)); }; const handleThicknessChange = (value: number | null) => { if (value !== null) { dispatch(setThickness(value)); } }; const handleAECChange = (checked: boolean) => { dispatch(setIsAECEnabled(checked)); }; const handleExposureModeChange = (value: string) => { ParaSettingCoordinator.setExposureMode(value); }; const handleResetParameters = async () => { try { await dispatch(resetDevices()); message.success(`重置高压发生器成功`); } catch (error) { console.error('Error resetting devices:', error); message.error(`重置高压发生器失败 ${error}`); } }; /** * 处理打开摄像头按钮点击事件 */ const handleOpenCamera = () => { // 获取当前选中体位的 study_id const currentStudyId = selectedBodyPosition?.study_id; if (!currentStudyId) { message.warning('请先选择一个体位'); return; } console.log('[handleOpenCamera] 打开摄像头,Study ID:', currentStudyId); // dispatch openCamera action,打开摄像头 dispatch(openCamera(currentStudyId)); }; /** * 处理拒绝图像按钮点击事件 */ const handleReject = async () => { if (!selectedBodyPosition) { message.warning('请先选择一个体位'); return; } Modal.confirm({ title: '确认拒绝', content: `确定要拒绝选中的图像吗?`, okText: '确认拒绝', cancelText: '取消', okButtonProps: { danger: true, 'data-testid': 'modal-confirm-delete' }, cancelButtonProps: { 'data-testid': 'modal-cancel-delete' }, centered: true, onOk: async () => { try { await dispatch( judgeImageThunk({ sopInstanceUid: selectedBodyPosition.sop_instance_uid, accept: false, }) ).unwrap(); message.success('图像已拒绝'); } catch (err) { console.error('拒绝图像失败:', err); message.error('拒绝图像失败'); } }, }); }; /** * 处理恢复图像按钮点击事件 */ const handleRestore = async () => { if (!selectedBodyPosition) { message.warning('请先选择一个体位'); return; } try { await dispatch( judgeImageThunk({ sopInstanceUid: selectedBodyPosition.sop_instance_uid, accept: true, }) ).unwrap(); message.success('图像已恢复'); } catch (err) { console.error('恢复图像失败:', err); message.error('恢复图像失败'); } }; /** * 处理保存参数按钮点击事件 */ const handleSaveParams = async () => { if (!selectedBodyPosition) { message.warning('请先选择一个体位'); return; } try { // 获取工作站ID - 将字符串转换为WorkstationType枚举 const workstationType = workstation as WorkstationType; const workStationId = workstationIdFromWorkstation( workstationType, productName ); // 构建请求参数 const request: AprParamsUpdateRequest = { work_station_id: workStationId, patient_size: bodysize, kV: aprConfig.kV, mA: aprConfig.mA, ms: aprConfig.ms, mAs: aprConfig.mAs, }; // 调用 updateAprParamsThunk await dispatch( updateAprParamsThunk({ id: selectedBodyPosition.view_id, request, }) ).unwrap(); message.success('参数保存成功'); } catch (err) { console.error('保存参数失败:', err); message.error('保存参数失败'); } }; // 1. 正常在顶层用 useSelector 订阅 const selectedBodyPosition = useSelector( (state: RootState) => state.bodyPositionList.selectedBodyPosition ); // 2. 用 ref 保存最新值(每次渲染都会更新) const positionRef = useRef(selectedBodyPosition); positionRef.current = selectedBodyPosition; // 3. 订阅 camera 状态 const cameraIsOpen = useSelector((state: RootState) => state.camera.isOpen); const cameraStudyId = useSelector( (state: RootState) => state.camera.currentStudyId ); // 4. 计算按钮可见性 const loading = useSelector( (state: RootState) => state.bodyPositionList.loading ); const exposeStatus = selectedBodyPosition?.dview.expose_status; const judgedStatus = selectedBodyPosition?.dview.judged_status || ''; const isExposed = exposeStatus === 'Exposed'; const isUnexposed = exposeStatus === 'Unexposed'; // 按钮可见性逻辑 const showRejectButton = isExposed && judgedStatus !== 'Reject'; const showRestoreButton = isExposed && judgedStatus === 'Reject'; const showSaveParamsButton = isUnexposed; const showDeleteButton = isUnexposed; return ( { if (info.type === 'up') { ParaSettingCoordinator.increaseThickness(); } else { ParaSettingCoordinator.decreaseThickness(); } }} /> {productName === 'DROS' && ( )}
{ if (info.type === 'up') { ParaSettingCoordinator.increaseMA(); } else { ParaSettingCoordinator.decreaseMA(); } return false; }} />
{ if (info.type === 'up') { ParaSettingCoordinator.increaseMS(); } else { ParaSettingCoordinator.decreaseMS(); } }} />
{ if (info.type === 'up') { ParaSettingCoordinator.increaseMAS(); } else { ParaSettingCoordinator.decreaseMAS(); } }} />
// dispatch(setAprConfig({ ...aprConfig, kV: value ?? 0 })) // } onStep={(value, info) => { if (info.type === 'up') { ParaSettingCoordinator.increaseKV(); } else { ParaSettingCoordinator.decreaseKV(); } }} />
{/*
dispatch(setAprConfig({ ...aprConfig, AECDensity: value ?? 0 })) } onStep={(value, info) => { if (info.type === 'up') { ParaSettingCoordinator.increaseDensity(); } else { ParaSettingCoordinator.decreaseDensity(); } }} />
*/}
} unCheckedChildren={} checked={isAECEnabled} onChange={handleAECChange} style={{ marginBottom: 8 }} />