diff --git a/src/components/Dicom/DicomCanvas.vue b/src/components/Dicom/DicomCanvas.vue index 1d9f207a..45721380 100644 --- a/src/components/Dicom/DicomCanvas.vue +++ b/src/components/Dicom/DicomCanvas.vue @@ -79,16 +79,18 @@ import * as cornerstone from 'cornerstone-core' import * as cornerstoneMath from 'cornerstone-math' import * as cornerstoneTools from 'cornerstone-tools' +import metaDataProvider from '@/utils/metaDataProvider' const scroll = cornerstoneTools.import('util/scrollToIndex') import Hammer from 'hammerjs' import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString' import invertOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/invertOrientationString' -import calculateSUV from '@/views/trials/trials-panel/reading/dicoms/tools/calculateSUV' +const calculateSUV = cornerstoneTools.import('util/calculateSUV') // import requestPoolManager from '@/utils/request-pool' import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool' import Note_RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/Note_RectangleRoiTool' +let isMetaDataProviderAdded = false cornerstoneTools.external.cornerstone = cornerstone cornerstoneTools.external.Hammer = Hammer cornerstoneTools.external.cornerstoneMath = cornerstoneMath @@ -219,6 +221,11 @@ export default { // this.stack.instanceId = instanceId this.toolState.clipPlaying = false const element = this.$refs.canvas + if (!isMetaDataProviderAdded) { + // 注册自定义 metaDataProvider:统一 SUV 口径(优先接口,缺失回退 DICOM) + cornerstone.metaData.addProvider(metaDataProvider, 100000) + isMetaDataProviderAdded = true + } cornerstone.enable(element) cornerstoneTools.stopClip(this.canvas) this.toolState.clipPlaying = false @@ -388,7 +395,7 @@ export default { this.dicomInfo.age = data.string('x00101010') this.dicomInfo.sex = data.string('x00100040') this.dicomInfo.acc = data.string('x00080050') // 登记号 - this.dicomInfo.modality = data.string('x00080060') + this.dicomInfo.modality = (data.string('x00080060') || '').trim() this.dicomInfo.time = this.formatDicomDateTime( data.string('x00080020'), data.string('x00080030') diff --git a/src/components/Dicom/DicomViewer.vue b/src/components/Dicom/DicomViewer.vue index c446a914..d6485891 100644 --- a/src/components/Dicom/DicomViewer.vue +++ b/src/components/Dicom/DicomViewer.vue @@ -296,14 +296,14 @@
@@ -1108,3 +1139,46 @@ export default { background-color: #213a54; } + diff --git a/src/views/trials/trials-panel/reading/dicoms/customize/CustomizeDicomCanvas.vue b/src/views/trials/trials-panel/reading/dicoms/customize/CustomizeDicomCanvas.vue index eea7bdf4..92e832e6 100644 --- a/src/views/trials/trials-panel/reading/dicoms/customize/CustomizeDicomCanvas.vue +++ b/src/views/trials/trials-panel/reading/dicoms/customize/CustomizeDicomCanvas.vue @@ -1081,7 +1081,8 @@ export default { // resolve() // }) this.loading = true - cornerstone.metaData.addProvider(metaDataProvider, 1); + cornerstone.metaData.removeProvider(metaDataProvider) + cornerstone.metaData.addProvider(metaDataProvider, 100000) cornerstone.loadAndCacheImage(this.stack.imageIds[this.stack.currentImageIdIndex]) .then(async image => { if (this.stack.imageIds.indexOf(image.imageId) !== -1) { diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index 335e5b22..70f042bc 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -577,6 +577,7 @@ import colorMap from './colorMap.vue' import RectangleROITool from './tools/RectangleROITool' import ScaleOverlayTool from './tools/ScaleOverlayTool' import SegmentBidirectionalTool from './tools/SegmentBidirectionalTool' +import { setPTClinicalDataForInstance, clearPTClinicalDataCache } from '@/utils/ptClinicalDataCache' import FixedRadiusCircleROITool from './tools/FixedRadiusCircleROITool' import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom' import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom' @@ -1155,10 +1156,32 @@ export default { let keySeriesIndex = -1 const arr = res1.Result arr.forEach((study, studyIndex) => { + // 仅对 PT/PET study 缓存临床参数,供 3D SUV 计算链路覆盖原始 DICOM 元数据 + const ptClinicalData = { + PatientSex: study.PatientSex, + PatientWeight: study.PatientWeight, + RadionuclideTotalDose: study.RadionuclideTotalDose, + RadionuclideHalfLife: study.RadionuclideHalfLife, + RadiopharmaceuticalStartTime: study.RadiopharmaceuticalStartTime, + AcquisitionTime: study.AcquisitionTime + } + const isPtStudy = ['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities) + const hasPtClinicalData = + isPtStudy && + ( + ptClinicalData.PatientWeight !== null || + ptClinicalData.RadionuclideTotalDose !== null || + ptClinicalData.RadionuclideHalfLife !== null || + ptClinicalData.RadiopharmaceuticalStartTime !== null || + ptClinicalData.AcquisitionTime !== null + ) study.SeriesList.forEach((series, seriesIndex) => { const imageIds = [] const stack = [] series.InstanceInfoList.forEach((instance, instanceIndex) => { + if (hasPtClinicalData && ['PT', 'PET'].includes(String(series.Modality).toUpperCase())) { + setPTClinicalDataForInstance(instance.Id, ptClinicalData) + } if (study.IsCriticalSequence) { keyStudyIndex = studyIndex keySeriesIndex = seriesIndex @@ -4404,6 +4427,7 @@ export default { }, }, beforeDestroy() { + clearPTClinicalDataCache() DicomEvent.$off('isCanActiveNoneDicomTool') DicomEvent.$off('removeNoneDicomMeasureData') DicomEvent.$off('addNoneDicomMeasureData') diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/StudyList.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/StudyList.vue index 779e9e45..b5595516 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/StudyList.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/StudyList.vue @@ -76,7 +76,7 @@