From 7266d0a4f5d48d205687698ba67bdce7e7a6514e Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Fri, 8 May 2026 15:04:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=88=AA=E5=9B=BE=E6=9B=B4=E6=94=B9=E5=8F=8A?= =?UTF-8?q?=E9=95=BF=E7=9F=AD=E5=BE=84=E5=B7=A5=E5=85=B7=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms/components/DicomViewer.vue | 120 +++++++++++++++--- .../tools/Bidirectional/BidirectionalTool.js | 5 +- 2 files changed, 104 insertions(+), 21 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue index cce7ce21..94f84f8c 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue @@ -915,7 +915,13 @@ export default { fullScreenWidth: window.innerWidth - 570 + 'px', fullScreenHeight: window.innerHeight - 130 + 'px', - ManualsClose: false + ManualsClose: false, + screenshotCache: { + key: '', + at: 0, + base64: '' + }, + screenshotInFlight: null } }, @@ -1051,30 +1057,27 @@ export default { console.log('getMeasureData') }) DicomEvent.$on('getScreenshots', async (measuredData, callback) => { - if (this.currentDicomCanvasIndex > -1) { + if (this.currentDicomCanvasIndex <= -1 || typeof callback !== 'function') return + const shouldRelocate = this.shouldRelocateBeforeScreenshot(measuredData) + if (shouldRelocate) { await this.imageLocation(measuredData) - if (!measuredData.isMarked) { - callback() - return - } - setTimeout(async () => { - // var base64Str = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getScreenshots() - const divForDownloadViewport = document.querySelector( - `div[data-canvas-uid="dicomCanvas${this.currentDicomCanvasIndex}"]` - ) - var canvas = await html2canvas(divForDownloadViewport) - var base64Str = canvas.toDataURL('image/png', 1) - console.log('getScreenshots') - callback(base64Str) - }, 50) } + if (!measuredData || !measuredData.isMarked) { + callback() + return + } + const cacheKey = this.getScreenshotCacheKey(measuredData) + const base64Str = await this.getOrCaptureScreenshot(cacheKey) + callback(base64Str) }) DicomEvent.$on('imageLocation', async (measuredData) => { return new Promise(async resolve => { if (!measuredData) return - await this.imageLocation(measuredData) - - console.log('imageLocation') + // await this.imageLocation(measuredData) + const shouldRelocate = this.shouldRelocateBeforeScreenshot(measuredData) + if (shouldRelocate) { + await this.imageLocation(measuredData) + } resolve() }) }) @@ -1710,6 +1713,85 @@ export default { } }) }, + shouldRelocateBeforeScreenshot(measuredData) { + if (!measuredData) return false + const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0] + if (!currentCanvas || !currentCanvas.stack) return true + const currentStack = currentCanvas.stack + if (currentStack.visitTaskId !== measuredData.visitTaskId) return true + + // 当前序列与病灶目标序列一致时,避免重复 imageLocation 引发的重载等待 + const targetSeries = this.getSeriesInfoByMark(measuredData.visitTaskId, measuredData) + if (!targetSeries) return false + if (currentStack.seriesId !== targetSeries.seriesId) return true + if (typeof targetSeries.imageIdIndex === 'number' && + targetSeries.imageIdIndex !== currentStack.currentImageIdIndex) { + return true + } + return false + }, + getScreenshotCacheKey(measuredData) { + const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0] + const currentStack = currentCanvas && currentCanvas.stack ? currentCanvas.stack : {} + return [ + this.currentDicomCanvasIndex, + currentStack.visitTaskId || '', + currentStack.seriesId || '', + typeof currentStack.currentImageIdIndex === 'number' ? currentStack.currentImageIdIndex : '', + measuredData.visitTaskId || '', + measuredData.questionId || '', + measuredData.rowIndex || '', + measuredData.lesionName || '', + measuredData.isMarked ? 1 : 0 + ].join('|') + }, + async getOrCaptureScreenshot(cacheKey) { + const now = Date.now() + if (this.screenshotCache.key === cacheKey && + this.screenshotCache.base64 && + now - this.screenshotCache.at < 1500) { + return this.screenshotCache.base64 + } + if (this.screenshotInFlight && this.screenshotInFlight.key === cacheKey) { + return this.screenshotInFlight.promise + } + const promise = this.captureActiveViewportScreenshot() + .then((base64) => { + this.screenshotCache = { + key: cacheKey, + at: Date.now(), + base64: base64 || '' + } + return base64 + }) + .finally(() => { + if (this.screenshotInFlight && this.screenshotInFlight.key === cacheKey) { + this.screenshotInFlight = null + } + }) + this.screenshotInFlight = { key: cacheKey, promise } + return promise + }, + async captureActiveViewportScreenshot() { + // const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0] + await this.$nextTick() + const divForDownloadViewport = document.querySelector( + `div[data-canvas-uid="dicomCanvas${this.currentDicomCanvasIndex}"]` + ) + if (divForDownloadViewport) { + try { + const canvas = await html2canvas(divForDownloadViewport, { + logging: false, + useCORS: true, + scale: 1 + }) + return canvas.toDataURL('image/png') + } catch (e) { + console.log(e) + } + } + return '' + }, setToolToTarget(obj) { if (obj.readingTaskState < 2 && obj.markTool && !obj.isMarked) { if (this.activeTool) { diff --git a/src/views/trials/trials-panel/reading/dicoms/tools/Bidirectional/BidirectionalTool.js b/src/views/trials/trials-panel/reading/dicoms/tools/Bidirectional/BidirectionalTool.js index d84b291c..14dd749e 100644 --- a/src/views/trials/trials-panel/reading/dicoms/tools/Bidirectional/BidirectionalTool.js +++ b/src/views/trials/trials-panel/reading/dicoms/tools/Bidirectional/BidirectionalTool.js @@ -15,7 +15,7 @@ import createNewMeasurement from './createNewMeasurement' */ export default class BidirectionalTool extends cornerstoneTools.BidirectionalTool { - constructor(props) { + constructor(props = {}) { const defaultProps = { name: 'Bidirectional', configuration: { @@ -25,7 +25,8 @@ export default class BidirectionalTool extends cornerstoneTools.BidirectionalToo super(props, defaultProps) this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 50) - this.digits = isNaN(parseInt(props.configuration.digits)) ? 2 : props.configuration.digits + const digits = props?.configuration?.digits + this.digits = isNaN(parseInt(digits)) ? 2 : digits this.createNewMeasurement = createNewMeasurement.bind(this) this.renderToolData = renderToolData.bind(this) }