From ae536a7fc43dbfa50404235522b40a9ff5dd0010 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Wed, 3 Dec 2025 16:52:52 +0800 Subject: [PATCH] =?UTF-8?q?mpr=E9=98=85=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms3D/components/ReadPage.vue | 111 ++++++++++++------ .../dicoms3D/components/VolumeViewport.vue | 33 +++--- .../components/customize/QuestionFormItem.vue | 9 +- .../components/customize/QuestionList.vue | 9 +- 4 files changed, 107 insertions(+), 55 deletions(-) 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 b831618b..d5c07bdd 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -161,7 +161,7 @@ -
@@ -308,7 +308,7 @@
s.StudyId === annotation.studyId) if (sIdx > -1) { @@ -2709,18 +2710,37 @@ export default { obj.IsMarked = true obj.MeasureData = annotation } + if (annotation.from === 'MPR' && checkFrom) { + obj = Object.assign({}, seriesList[seriesIdx]) + obj.SliceIndex = annotation?.metadata?.sliceIndex + obj.IsMarked = true + obj.MeasureData = annotation + } + } } return obj }, - viewCustomAnnotationSeries(obj) { + async viewCustomAnnotationSeries(obj) { const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId) if (i === -1) return const studyList = this.visitTaskList[i].StudyList - const series = this.getMarkedSeries(studyList, obj.annotation) + const series = this.getMarkedSeries(studyList, obj.annotation, true) if (series) { - this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].setSeriesInfo(series, true) - this.activeViewportIndex = i + this.activeViewportIndex = this.cells.length - 1 + if (obj.annotation.from === 'MPR') { + let res = await this.openMPRViewport(series) + let viewPlaneNormal = obj.annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',') + if (viewPlaneNormal === '0,0,-1') { + this.activeViewportIndex = 0 + } else if (viewPlaneNormal === '0,-1,0') { + this.activeViewportIndex = 1 + } else if (viewPlaneNormal === '1,0,0') { + this.activeViewportIndex = 2 + } + if (!res) return false + } + this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true) this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex) } }, @@ -2728,17 +2748,29 @@ export default { const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId) if (i === -1) return const studyList = this.visitTaskList[i].StudyList - const series = this.getMarkedSeries(studyList, obj.annotation) + const series = this.getMarkedSeries(studyList, obj.annotation, true) if (series) { - this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].setSeriesInfo(series, true) - this.activeViewportIndex = i + this.activeViewportIndex = this.cells.length - 1 + if (obj.annotation.from === 'MPR') { + let viewPlaneNormal = obj.annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',') + if (viewPlaneNormal === '0,0,-1') { + this.activeViewportIndex = 0 + } else if (viewPlaneNormal === '0,-1,0') { + this.activeViewportIndex = 1 + } else if (viewPlaneNormal === '1,0,0') { + this.activeViewportIndex = 2 + } + } + this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true) this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex) - const divForDownloadViewport = document.querySelector( - `div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]` - ) - const canvas = await html2canvas(divForDownloadViewport) - const base64Str = canvas.toDataURL('image/png', 1) - callback(base64Str) + setTimeout(async () => { + const divForDownloadViewport = document.querySelector( + `div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]` + ) + const canvas = await html2canvas(divForDownloadViewport) + const base64Str = canvas.toDataURL('image/png', 1) + callback(base64Str) + }, 500) } }, async getScreenshots(measureData, callback) { @@ -3090,24 +3122,29 @@ export default { this.$refs[id][0].voiChange(v) }) }, - async openMPRViewport() { - this.isMPR = true - this.rows = 2 - this.cols = 2 - this.loading = true - this.loadingText = this.$t('trials:lugano:message:loadVolumes') - const series = this.$refs[`viewport-${this.activeViewportIndex}`][0].series - this.activeViewportIndex = 0 - this.$refs[`viewport-0`][0].setSeriesInfo(series) - this.$refs[`viewport-1`][0].setSeriesInfo(series) - this.$refs[`viewport-2`][0].setSeriesInfo(series) - this.$refs[`viewport-3`][0].setSeriesInfo(series) - await this.getVolume(series) - this.loading = false - this.loadingText = null - this.$refs[`viewport-volume-0`][0].setSeriesInfo(Object.assign({ orientation: 'AXIAL' }, series)) - this.$refs[`viewport-volume-1`][0].setSeriesInfo(Object.assign({ orientation: 'CORONAL' }, series)) - this.$refs[`viewport-volume-2`][0].setSeriesInfo(Object.assign({ orientation: 'SAGITTAL' }, series)) + async openMPRViewport(data = null) { + return new Promise(async (resolve, reject) => { + if (this.isMPR) return resolve(true) + this.isMPR = true + this.rows = 3 + this.cols = 1 + this.loading = true + this.loadingText = this.$t('trials:lugano:message:loadVolumes') + const series = data ? data : this.$refs[`viewport-${this.activeViewportIndex}`][0].series + this.activeViewportIndex = 0 + // this.$refs[`viewport-0`][0].setSeriesInfo(series) + // this.$refs[`viewport-1`][0].setSeriesInfo(series) + // this.$refs[`viewport-2`][0].setSeriesInfo(series) + // this.$refs[`viewport-3`][0].setSeriesInfo(series) + await this.getVolume(series) + this.loading = false + this.loadingText = null + this.$refs[`viewport-volume-0`][0].setSeriesInfo(Object.assign({ orientation: 'AXIAL' }, series)) + this.$refs[`viewport-volume-1`][0].setSeriesInfo(Object.assign({ orientation: 'CORONAL' }, series)) + this.$refs[`viewport-volume-2`][0].setSeriesInfo(Object.assign({ orientation: 'SAGITTAL' }, series)) + resolve(false) + }) + }, async handleFusion(data) { try { @@ -3570,7 +3607,7 @@ export default { } .grid-cell-3 { - grid-column: 2 / 3; + grid-column: 0 / 3; grid-row: 1 / 3; } diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue index e5145bf8..dfc02285 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue @@ -11,7 +11,7 @@ {{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
Series: #{{ series.SeriesNumber }}
-
Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}
+
Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}
{{ series.Modality }}
@@ -40,10 +40,10 @@
Location: {{ `${Number(imageInfo.location).toFixed(digitPlaces)} mm` - }}
-
Slice Thickness: {{ - `${Number(series.SliceThickness).toFixed(digitPlaces)} mm` - }}
+ }}
+
Slice Thickness: {{ + `${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm` + }}
WW/WL: {{ imageInfo.wwwc }}
@@ -117,7 +117,8 @@ export default { location: null, sliceThickness: null, wwwc: null, - total: 0 + total: 0, + sliceThickness: 0 }, digitPlaces: 2, orientationMarkers: [], @@ -194,21 +195,24 @@ export default { this.imageInfo.zoom = zoom.toFixed(4) let imageIds = viewport.getImageIds(this.volumeId) let imageId = imageIds[0] - if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId() + // if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId() if (imageId) { const imagePlaneModule = metaData.get('imagePlaneModule', imageId) if (this.series.orientation === 'AXIAL') { this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}` this.imageInfo.location = imagePlaneModule.sliceLocation this.imageInfo.total = imageIds.length + this.imageInfo.sliceThickness = imagePlaneModule.sliceThickness } if (this.series.orientation === 'CORONAL') { this.imageInfo.size = `${imagePlaneModule.columns}*${imageIds.length}` this.imageInfo.total = imagePlaneModule.rows + this.imageInfo.sliceThickness = imagePlaneModule.rowPixelSpacing } if (this.series.orientation === 'SAGITTAL') { this.imageInfo.size = `${imagePlaneModule.rows}*${imageIds.length}` this.imageInfo.total = imagePlaneModule.columns + this.imageInfo.sliceThickness = imagePlaneModule.columnPixelSpacing } this.getOrientationMarker() @@ -395,15 +399,16 @@ export default { }) this.loading = false }, - async setSeriesInfo(obj) { + async setSeriesInfo(obj, isLocate = false) { try { let data = obj - if (this.series && data.Id === this.series.Id && data.Description === this.series.Description) { + if (this.series && data.Id === this.series.Id && data.Description === this.series.Description && !isLocate) { data.SliceIndex = this.series.SliceIndex } - this.series = {} const renderingEngine = getRenderingEngine(this.renderingEngineId) const viewport = renderingEngine.getViewport(this.viewportId) + if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); + this.series = {} this.volumeId = data.SeriesInstanceUid this.series = { ...data } viewport @@ -456,8 +461,8 @@ export default { clickSlider(e) { const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight this.sliderInfo.height = height - let sliceIdx = Math.trunc(this.series.Stack.length * height / 100) - sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx + let sliceIdx = Math.trunc(this.imageInfo.total * height / 100) + sliceIdx = sliceIdx >= this.imageInfo.total ? this.imageInfo.total : sliceIdx < 0 ? 0 : sliceIdx const renderingEngine = getRenderingEngine(this.renderingEngineId) const viewport = renderingEngine.getViewport( this.viewportId @@ -486,8 +491,8 @@ export default { if (delta < 0) return if (delta > boxHeight) return const height = delta * 100 / boxHeight - let sliceIdx = Math.trunc(this.series.Stack.length * height / 100) - sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx + let sliceIdx = Math.trunc(this.imageInfo.total * height / 100) + sliceIdx = sliceIdx >= this.imageInfo.total ? this.imageInfo.total - 1 : sliceIdx < 0 ? 0 : sliceIdx this.sliderInfo.height = height const renderingEngine = getRenderingEngine(this.renderingEngineId) const viewport = renderingEngine.getViewport( diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionFormItem.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionFormItem.vue index 35b368f1..a7102075 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionFormItem.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionFormItem.vue @@ -1244,9 +1244,14 @@ export default { }, getAnnotationProp(annotation, prop) { if (!annotation) return - const referencedImageId = annotation?.metadata?.referencedImageId + let referencedImageId = null + if (annotation.from) { + referencedImageId = `${annotation?.metadata?.volumeId}?sliceIndex=${annotation?.metadata?.sliceIndex}&viewPlaneNormal=${annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')}` + } else { + referencedImageId = annotation?.metadata?.referencedImageId + } if (!referencedImageId) return null - const cacheKey = `imageId:${referencedImageId}` + const cacheKey = annotation.from ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}` const cachedStats = annotation.data?.cachedStats?.[cacheKey] const hasProp = cachedStats && Object.prototype.hasOwnProperty.call(cachedStats, prop) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionList.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionList.vue index fe18dbc1..775f3ae9 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionList.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionList.vue @@ -943,9 +943,14 @@ export default { }, getAnnotationProp(annotation, prop) { if (!annotation || !prop) return - const referencedImageId = annotation?.metadata?.referencedImageId + let referencedImageId = null + if (annotation.from) { + referencedImageId = `${annotation?.metadata?.volumeId}?sliceIndex=${annotation?.metadata?.sliceIndex}&viewPlaneNormal=${annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')}` + } else { + referencedImageId = annotation?.metadata?.referencedImageId + } if (!referencedImageId) return null - const cacheKey = `imageId:${referencedImageId}` + const cacheKey = annotation.from ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}` const cachedStats = annotation.data?.cachedStats?.[cacheKey] const hasProp = cachedStats && Object.prototype.hasOwnProperty.call(cachedStats, prop)