From 1c0cdde9ada5898096940b639f08c8a134fde183 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 7 May 2026 11:08:57 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E8=B4=A8=E6=8E=A7=E4=B8=B4=E5=BA=8A?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms/components/DicomCanvas.vue | 60 +- .../reading/dicoms/components/DicomViewer.vue | 21 +- .../MRIPDFFAdvance/QuestionForm.vue | 864 ++++++++++++++++++ .../MRIPDFFAdvance/QuestionList.vue | 624 +++++++++++++ .../FixedCircleRoi/FixedCircleRoiTool.js | 347 +++++++ .../components/uploadPetClinicalData.vue | 3 +- .../qc-check/components/qualityAssurance.vue | 2 +- 7 files changed, 1906 insertions(+), 15 deletions(-) create mode 100644 src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue create mode 100644 src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue create mode 100644 src/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool.js diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue index e4ac3899..926304e1 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue @@ -146,6 +146,7 @@ import BidirectionalTool from '@/views/trials/trials-panel/reading/dicoms/tools/ import ArrowAnnotateTool from '@/views/trials/trials-panel/reading/dicoms/tools/ArrowAnnotate/ArrowAnnotateTool' import RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/RectangleRoiTool' import ProbeTool from '@/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool' +import FixedCircleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool' // import OrientationMarkersTool from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/OrientationMarkersTool' import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool' import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString' @@ -260,7 +261,7 @@ export default { series: '', ToolStateManager: null, renderedMeasured: [], - measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe'], + measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe', 'FixedCircleRoi'], measureData: [], selectedLesion: null, activeTool: 0, // 0:enable 1:passive 2:active @@ -584,6 +585,13 @@ export default { e.stopPropagation() e.preventDefault() } + } else if (this.CriterionType === 22 && this.activeToolName === 'Probe' && this.readingTaskState < 2) { + if (!(e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME1' || e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME2')) { + this.$alert(this.$t('trials:MRIPDFF:message:message5')) + e.stopImmediatePropagation() + e.stopPropagation() + e.preventDefault() + } } }, pointNearTool(e) { @@ -593,7 +601,9 @@ export default { var toolType = this.measuredTools[m] const toolState = ToolStateManager.getImageIdToolState(image.imageId, toolType) if (toolState) { - var toolObj = new cornerstoneTools[`${toolType}Tool`]() + const toolClass = this.getToolClassByType(toolType) + if (!toolClass) continue + var toolObj = new toolClass() var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse')) if (i > -1 && this.disabledMarks.length > 0 && this.disabledMarks.indexOf(toolState.data[i].remark) > -1) { return true @@ -783,7 +793,9 @@ export default { var toolType = this.measuredTools[m] const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType) if (toolState) { - var toolObj = new cornerstoneTools[`${toolType}Tool`]() + const toolClass = this.getToolClassByType(toolType) + if (!toolClass) continue + var toolObj = new toolClass() var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse')) if (i > -1) { @@ -1019,7 +1031,9 @@ export default { var toolType = this.measuredTools[t] const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType) if (!toolState) continue - var toolObj = new cornerstoneTools[`${toolType}Tool`]() + const toolClass = this.getToolClassByType(toolType) + if (!toolClass) continue + var toolObj = new toolClass() var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse')) if (i > -1) { var idx = this.measureData.findIndex(item => item.MeasureData && item.MeasureData.data && item.MeasureData.data.uuid === toolState.data[i].uuid) @@ -1046,7 +1060,7 @@ export default { measureData.wc = Math.round(viewport.voi.windowCenter) measureData.data.active = false var criterionType = parseInt(localStorage.getItem('CriterionType')) - if (criterionType === 21) { + if (criterionType === 21 || criterionType === 22) { measureData.tableQuestionId = this.measureData[idx].TableQuestionId } this.$emit('modifyMeasureData', { measureData, questionInfo }) @@ -1057,6 +1071,15 @@ export default { } } }, + getToolClassByType(toolType) { + if (toolType === 'Length') return LengthTool + if (toolType === 'Bidirectional') return BidirectionalTool + if (toolType === 'ArrowAnnotate') return ArrowAnnotateTool + if (toolType === 'RectangleRoi') return RectangleRoiTool + if (toolType === 'Probe') return ProbeTool + if (toolType === 'FixedCircleRoi') return FixedCircleRoiTool + return cornerstoneTools[`${toolType}Tool`] + }, loadImageStack(dicomSeries) { return new Promise(resolve => { this.isInitWwwc = true @@ -1169,8 +1192,22 @@ export default { // Add the tool const toolName = toolBtn.getAttribute('data-tool') const apiTool = cornerstoneTools[`${toolName}Tool`] - if (apiTool) { - const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, apiTool) + let toolClass = apiTool + if (toolName === 'Length') { + toolClass = LengthTool + } else if (toolName === 'Bidirectional') { + toolClass = BidirectionalTool + } else if (toolName === 'ArrowAnnotate') { + toolClass = ArrowAnnotateTool + } else if (toolName === 'RectangleRoi') { + toolClass = RectangleRoiTool + } else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) { + toolClass = ProbeTool + } else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 22)) { + toolClass = FixedCircleRoiTool + } + if (toolClass) { + const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, toolClass) if (!toolAlreadyAddedToElement) { if (toolName === 'Length') { @@ -1183,8 +1220,10 @@ export default { cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } }) } else if (toolName === 'RectangleRoi') { cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } }) - } else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 21) { + } else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) { cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } }) + } else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 22) { + cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { radius: 5, unit: 'mm', handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } }) } else { cornerstoneTools.addToolForElement(element, apiTool) } @@ -1528,7 +1567,7 @@ export default { measureData.wc = Math.round(viewport.voi.windowCenter) measureData.data.active = false var criterionType = parseInt(localStorage.getItem('CriterionType')) - if (criterionType === 21) { + if (criterionType === 21 || criterionType === 22) { measureData.tableQuestionId = this.measureData[idx].TableQuestionId } this.$emit('modifyMeasureData', { measureData, questionInfo }) @@ -1982,7 +2021,8 @@ export default { 'CobbAngle', 'Angle', 'Bidirectional', - 'FreehandRoi' + 'FreehandRoi', + 'FixedCircleRoi' ] for (let i = 0; i < toolROITypes.length; i++) { const toolROIType = toolROITypes[i] 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 cbd3f60f..cce7ce21 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue @@ -492,6 +492,10 @@ :question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum" :is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo" @handleReadingChart="handleReadingChart" /> +

Developing...

@@ -689,6 +693,7 @@ import LuganoWithoutPETQuestionList from './LuganoWithoutPET/QuestionList' import IVUSList from './IVUS/QuestionList' import OCTList from './OCT/QuestionList' import MRIPDFF from './MRIPDFF/QuestionList' +import MRIPDFFAdvance from './MRIPDFFAdvance/QuestionList' import CustomWwwcForm from './CustomWwwcForm' import Manuals from './Manuals' import Hotkeys from './Hotkeys' @@ -725,6 +730,7 @@ export default { IVUSList, OCTList, MRIPDFF, + MRIPDFFAdvance, 'download-dicom-and-nonedicom': downloadDicomAndNonedicom, 'upload-dicom-and-nonedicom': uploadDicomAndNonedicom, SignForm @@ -1012,6 +1018,10 @@ export default { this.measuredTools = [{ toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: '' }] + } else if (this.CriterionType === 22) { + this.measuredTools = [{ + toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: '' + }] } this.rotateList[0] = '1' this.colorList[0] = '' @@ -1126,7 +1136,12 @@ export default { DicomEvent.$on('addAnnotation', async obj => { this.tmpData = Object.assign({}, obj.question) // await this.imageLocation(obj.locateInfo) - this.setToolActive('Probe', true, null, 'tableQuestion') + if (this.CriterionType === 21) { + this.setToolActive('Probe', true, null, 'tableQuestion') + } else if (this.CriterionType === 22) { + this.setToolActive('Probe', true, null, 'tableQuestion') + } + }) window.addEventListener('beforeunload', () => { if (this.petctWindow) { @@ -2160,7 +2175,7 @@ export default { }, // 添加标记 setMeasureData(data) { - if (this.CriterionType === 21) { + if (this.CriterionType === 21 || this.CriterionType === 22) { if (this.tmpData) { data.tableQuestionId = this.tmpData.Id data.tableQuestionMark = this.tmpData.QuestionMark @@ -2174,7 +2189,7 @@ export default { }, // 修改标记 modifyMeasureData(data) { - if (this.CriterionType === 21 && data.measureData.tableQuestionId) { + if ((this.CriterionType === 21 || this.CriterionType === 22) && data.measureData.tableQuestionId) { this.$refs['measurementList'].modifyMeasuredData(data) } else { this.$refs['measurementList'].modifyMeasuredData(data) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue new file mode 100644 index 00000000..11315cae --- /dev/null +++ b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue @@ -0,0 +1,864 @@ + + + diff --git a/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue new file mode 100644 index 00000000..16e0c915 --- /dev/null +++ b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue @@ -0,0 +1,624 @@ + + + diff --git a/src/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool.js b/src/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool.js new file mode 100644 index 00000000..b400be40 --- /dev/null +++ b/src/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool.js @@ -0,0 +1,347 @@ +import * as cornerstoneTools from 'cornerstone-tools' +import * as cornerstone from 'cornerstone-core' +import getCircleCoords from '../CircleRoi/getCircleCoords' +const EVENTS = cornerstoneTools.EVENTS +const getPixelSpacing = cornerstoneTools.importInternal('util/getPixelSpacing') +const triggerEvent = cornerstoneTools.import('util/triggerEvent') +const external = cornerstoneTools.external +const getToolState = cornerstoneTools.getToolState +const toolStyle = cornerstoneTools.toolStyle +const toolColors = cornerstoneTools.toolColors +const getModule = cornerstoneTools.getModule +const getNewContext = cornerstoneTools.import('drawing/getNewContext') +const draw = cornerstoneTools.import('drawing/draw') +const setShadow = cornerstoneTools.import('drawing/setShadow') +const drawCircle = cornerstoneTools.import('drawing/drawCircle') +const drawHandles = cornerstoneTools.import('drawing/drawHandles') +const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox') +const getROITextBoxCoords = cornerstoneTools.import('util/getROITextBoxCoords') +const numbersWithCommas = cornerstoneTools.import('util/numbersWithCommas') + +/** + * @public + * @class FixedCircleRoiTool + * @memberof Tools.Annotation + * @classdesc Tool for drawing circular regions of interest with a fixed radius, and measuring + * the statistics of the enclosed pixels. + * @extends Tools.Annotation.CircleRoiTool + */ +export default class FixedCircleRoiTool extends cornerstoneTools.CircleRoiTool { + constructor(props = {}) { + const defaultProps = { + name: 'FixedCircleRoi', + configuration: { + radius: 10, // Default radius in units (mm by default) + unit: 'mm', // 'mm' or 'px' + centerPointRadius: 0, + renderDashed: false, + drawHandlesOnHover: false, + handleRadius: 0, + digits: 1, + }, + }; + super(props, defaultProps); + + // Explicitly set name to ensure it is defined + this.name = 'FixedCircleRoi'; + + // Manually merge configuration to ensure props override defaults + if (props && props.configuration) { + this.configuration = Object.assign( + {}, + this.configuration || defaultProps.configuration, + props.configuration + ); + } + } + + createNewMeasurement(eventData) { + const measurementData = super.createNewMeasurement(eventData); + + if (!measurementData) { + return; + } + + const { image } = eventData; + // Fallback if configuration is missing + if (!this.configuration) { + console.warn( + 'FixedCircleRoiTool: configuration missing, using defaults' + ); + this.configuration = { radius: 10, unit: 'mm' }; + } + + const config = this.configuration; + let radiusPixels = config.radius; + + if (config.unit === 'mm') { + const pixelSpacing = getPixelSpacing(image); + console.log( + 'FixedCircleRoiTool: PixelSpacing retrieved:', + pixelSpacing + ); + + const { colPixelSpacing } = pixelSpacing; + + if (colPixelSpacing && colPixelSpacing > 0) { + radiusPixels = config.radius / colPixelSpacing; + } else { + console.warn( + 'FixedCircleRoiTool: Invalid pixel spacing, treating radius as pixels' + ); + } + } + + // Ensure radiusPixels is a valid number + if (isNaN(radiusPixels)) { + console.warn( + 'FixedCircleRoiTool: radiusPixels is NaN, defaulting to 10px' + ); + radiusPixels = 10; + } + + // Set end handle position based on calculated radius pixels + measurementData.handles.end.x = + measurementData.handles.start.x + radiusPixels; + measurementData.handles.end.y = measurementData.handles.start.y; + + console.log( + 'FixedCircleRoiTool created measurement:', + JSON.parse(JSON.stringify(measurementData)) + ); + + // Invalidate to trigger stats calculation + measurementData.invalidated = true; + + return measurementData; + } + + /** + * Overwrite the addNewMeasurement method to prevent the default behavior + * of resizing the circle on mouse drag immediately after creation. + */ + addNewMeasurement(evt, interactionType) { + const eventData = evt.detail; + if ( + !eventData || + !eventData.currentPoints || + !eventData.currentPoints.image + ) { + console.warn( + 'FixedCircleRoiTool: Invalid eventData supplied to addNewMeasurement' + ); + return; + } + + const element = eventData.element; + + // 1. Create the measurement data (which already has the fixed radius) + const measurementData = this.createNewMeasurement(eventData); + + if (!measurementData) return; + + // 2. Add it to the tool state + cornerstoneTools.addToolState(element, this.name, measurementData); + + // 3. Ensure stats are available for completion listeners (e.g. mean value consumers). + if (!measurementData.cachedStats && eventData.image) { + this.updateCachedStats(eventData.image, element, measurementData) + } + + // 4. Update the image to show the new annotation + cornerstone.updateImage(element); + + // 5. Manually emit completion event since we bypass default drag-finish flow. + triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, { + toolName: this.name, + element, + measurementData, + }) + + // 6. Do NOT attach mouse/touch event listeners for resizing. + // The circle is created with fixed size and placed immediately. + } + + handleSelectedCallback(evt, measurementData, handle, interactionType = 'mouse') { + // Lock circle radius by preventing start/end handle drag. + if (measurementData && measurementData.handles) { + const { start, end } = measurementData.handles + if (handle === start || handle === end) { + evt.stopImmediatePropagation?.() + evt.preventDefault?.() + return + } + } + + super.handleSelectedCallback(evt, measurementData, handle, interactionType) + } + + pointNearTool(element, data, coords, interactionType = 'mouse') { + const isNearDefault = super.pointNearTool(element, data, coords, interactionType) + if (isNearDefault) { + return true + } + if (!data || !data.handles || !data.handles.start || !data.handles.end) { + return false + } + + const centerCanvas = external.cornerstone.pixelToCanvas(element, data.handles.start) + const edgeCanvas = external.cornerstone.pixelToCanvas(element, data.handles.end) + const radius = external.cornerstoneMath.point.distance(centerCanvas, edgeCanvas) + const distanceToCenter = external.cornerstoneMath.point.distance(centerCanvas, coords) + + return distanceToCenter <= radius + } + + renderToolData(evt) { + const toolData = getToolState(evt.currentTarget, this.name) + + if (!toolData) { + return + } + + const getDistance = external.cornerstoneMath.point.distance + const eventData = evt.detail + const { image, element, canvasContext } = eventData + const lineWidth = toolStyle.getToolWidth() + const { + handleRadius, + drawHandlesOnHover, + hideHandlesIfMoving, + renderDashed, + centerPointRadius, + } = this.configuration + const newContext = getNewContext(canvasContext.canvas) + const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image) + const lineDash = getModule('globalConfiguration').configuration.lineDash + + const seriesModule = + external.cornerstone.metaData.get('generalSeriesModule', image.imageId) || + {} + const modality = seriesModule.modality + const hasPixelSpacing = rowPixelSpacing && colPixelSpacing + + draw(newContext, context => { + for (let i = 0; i < toolData.data.length; i++) { + const data = toolData.data[i] + + if (data.visible === false) { + continue + } + + const color = toolColors.getColorIfActive(data) + const handleOptions = { + color, + handleRadius, + drawHandlesIfActive: drawHandlesOnHover, + hideHandlesIfMoving, + } + + setShadow(context, this.configuration) + + const startCanvas = external.cornerstone.pixelToCanvas( + element, + data.handles.start + ) + const endCanvas = external.cornerstone.pixelToCanvas( + element, + data.handles.end + ) + const radius = getDistance(startCanvas, endCanvas) + + const circleOptions = { color } + if (renderDashed) { + circleOptions.lineDash = lineDash + } + + drawCircle( + context, + element, + data.handles.start, + radius, + circleOptions, + 'pixel' + ) + + if (centerPointRadius && radius > 3 * centerPointRadius) { + drawCircle( + context, + element, + data.handles.start, + centerPointRadius, + circleOptions, + 'pixel' + ) + } + + if (data.handles) { + data.handles.start.drawnIndependently = true + data.handles.end.drawnIndependently = true + } + drawHandles(context, eventData, data.handles, handleOptions) + + if (data.invalidated === true) { + if (data.cachedStats) { + this.throttledUpdateCachedStats(image, element, data) + } else { + this.updateCachedStats(image, element, data) + } + } + + if (!data.handles.textBox.hasMoved) { + const defaultCoords = getROITextBoxCoords( + eventData.viewport, + data.handles + ) + Object.assign(data.handles.textBox, defaultCoords) + } + + const textBoxContent = [] + console.log(data) + if (data.remark) { + textBoxContent.push(data.remark) + } + + const digits = this.configuration.digits || 1 + if (!image.color && data.cachedStats && Number.isFinite(data.cachedStats.mean)) { + const unit = modality === 'CT' && this.configuration.showHounsfieldUnits !== false ? 'HU' : '' + const meanText = numbersWithCommas(data.cachedStats.mean.toFixed(digits)) + textBoxContent.push(unit ? `Mean: ${meanText} ${unit}` : `Mean: ${meanText}`) + } + + if (!textBoxContent.length) { + continue + } + + const textBoxAnchorPoints = handles => + findTextBoxAnchorPoints(handles.start, handles.end) + + drawLinkedTextBox( + context, + element, + data.handles.textBox, + textBoxContent, + data.handles, + textBoxAnchorPoints, + color, + lineWidth, + 20, + true + ) + + data.unit = modality === 'CT' && this.configuration.showHounsfieldUnits !== false ? 'HU' : '' + } + }) + } +} + +function findTextBoxAnchorPoints(startHandle, endHandle) { + const { left, top, width, height } = getCircleCoords(startHandle, endHandle) + + return [ + { x: left + width / 2, y: top }, + { x: left, y: top + height / 2 }, + { x: left + width / 2, y: top + height }, + { x: left + width, y: top + height / 2 }, + ] +} diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue b/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue index 5ed6a82a..57740b24 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue @@ -512,7 +512,8 @@ export default { } }, mounted() { - this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit + console.log(this.allowAddOrEdit,this.isPatientFormAllowEdit ) + this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit this.getClinicalData() }, methods: { diff --git a/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue b/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue index 6620aad8..ca1aab84 100644 --- a/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue +++ b/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue @@ -921,7 +921,7 @@ - + From af97e2b4edebead60ad94f1103eb4c35e1f96b4f Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 7 May 2026 12:16:01 +0800 Subject: [PATCH 2/4] =?UTF-8?q?crc=E4=BF=AE=E6=94=B9pt=E4=B8=B4=E5=BA=8A?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Dicom/DicomViewer.vue | 2 +- .../visit/crc-upload/components/studyInfo.vue | 10 ++++++++-- .../visit/crc-upload/components/uploadDicomFiles2.vue | 8 +++++++- .../crc-upload/components/uploadPetClinicalData.vue | 1 - 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/Dicom/DicomViewer.vue b/src/components/Dicom/DicomViewer.vue index 41c39b9c..583b303a 100644 --- a/src/components/Dicom/DicomViewer.vue +++ b/src/components/Dicom/DicomViewer.vue @@ -496,7 +496,7 @@ export default { this.colormapsList = cornerstone.colors.getColormapsList() this.currentDicomCanvas = this.$refs['dicomCanvas0'] this.type = this.$route.query.type - this.isEdit = parseInt(this.$route.query.showDelete) + this.isEdit = parseInt(this.$route.query.showDelete) || parseInt(this.$route.query.showEdit) }, beforeDestroy() { clearPTClinicalDataCache() diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue b/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue index 4886d9c3..47dfcc74 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue @@ -151,7 +151,7 @@ - + @@ -309,8 +309,14 @@ export default { // 预览影像 handleViewStudy(row) { var token = getToken() + let path = '' + if (this.hasPermi(['trials:trials-panel:visit:crc-upload:edit'])) { + path = `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study&showEdit=${(this.data.SubmitState * 1 < 2 || (this.data.SubmitState === 2 && this.data.IsQCConfirmedReupload)) ? 1 : 0}` + } else { + path = `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study` + } const routeData = this.$router.resolve({ - path: `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study`, + path: path }) var newWindow = window.open(routeData.href, '_blank') this.$emit('setOpenWindow', newWindow) diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue b/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue index 11cedab5..9b25e7bf 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue @@ -791,8 +791,14 @@ export default { // 预览单个检查影像 handleViewStudy(row) { var token = getToken() + let path = '' + if (this.hasPermi(['trials:trials-panel:visit:crc-upload:edit'])) { + path = `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study&showEdit=${!(!this.isAfresh && this.data.SubmitState === 2 && this.data.SubmitTime) ? 1 : 0}` + } else { + path = `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study` + } const routeData = this.$router.resolve({ - path: `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study`, + path: path, }) window.open(routeData.href, '_blank') }, diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue b/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue index 57740b24..ed6a8c8d 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue @@ -512,7 +512,6 @@ export default { } }, mounted() { - console.log(this.allowAddOrEdit,this.isPatientFormAllowEdit ) this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit this.getClinicalData() }, From 09e9c62f3c4a60eebb61753f9c2fa5a67c6d734b Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 7 May 2026 13:52:28 +0800 Subject: [PATCH 3/4] =?UTF-8?q?pt=E4=B8=B4=E5=BA=8A=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E5=8F=96=E6=B6=88=E7=82=B9=E5=87=BBmodal?= =?UTF-8?q?=E5=85=B3=E9=97=ADDialog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms/components/DicomCanvas.vue | 2 +- .../MRIPDFFAdvance/QuestionForm.vue | 2 - .../MRIPDFFAdvance/QuestionList.vue | 2 - .../reading/dicoms/tools/Probe/ProbeTool.js | 43 +++++++++++++++++-- .../visit/crc-upload/components/studyInfo.vue | 2 +- .../components/uploadDicomFiles2.vue | 2 +- .../visit/qc-check/components/dicomFiles.vue | 2 +- .../qc-check/components/qualityAssurance.vue | 2 +- 8 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue index 926304e1..1c2022a1 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue @@ -1223,7 +1223,7 @@ export default { } else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) { cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } }) } else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 22) { - cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { radius: 5, unit: 'mm', handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } }) + cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, unit: 'mm', handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } }) } else { cornerstoneTools.addToolForElement(element, apiTool) } diff --git a/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue index 11315cae..b6a654cd 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionForm.vue @@ -385,13 +385,11 @@ export default { }, setMeasureData(measureData, isInit = false) { return new Promise(resolve => { - console.log('setMeasureData', measureData) if (!measureData || (measureData && measureData.tableQuestionId !== this.activeQuestionId)) { resolve() } var data = {} // 创建标记 - console.log('setMeasureData', measureData) if (!measureData.data.remark) { // 维护标记信息 measureData.data.remark = this.getLesionName(this.orderMark, this.activeQuestionMark) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue index 16e0c915..a3a722bc 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/MRIPDFFAdvance/QuestionList.vue @@ -432,7 +432,6 @@ export default { } }, modifyMeasuredData(measureObj) { - console.log('modifyMeasuredData') if (measureObj.questionInfo) { this.activeItem.activeCollapseId = measureObj.questionInfo.QuestionId this.activeItem.activeRowIndex = String(measureObj.questionInfo.RowIndex) @@ -443,7 +442,6 @@ export default { }, // 设置测量数据 setMeasuredData(measureData) { - console.log('setMeasuredData') if (this.activeItem.activeCollapseId) { // 判断是否存在测量数据 this.$nextTick(() => { diff --git a/src/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool.js b/src/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool.js index a8224bbc..65baf902 100644 --- a/src/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool.js +++ b/src/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool.js @@ -1,4 +1,6 @@ import * as cornerstoneTools from 'cornerstone-tools' +const EVENTS = cornerstoneTools.EVENTS +const triggerEvent = cornerstoneTools.import('util/triggerEvent') const external = cornerstoneTools.external // State const getToolState = cornerstoneTools.getToolState @@ -87,7 +89,7 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool { return { visible: true, - active: true, + active: false, color: undefined, invalidated: true, handles: { @@ -100,8 +102,8 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool { end: { x: eventData.currentPoints.image.x, y: eventData.currentPoints.image.y, - highlight: true, - active: true, + highlight: false, + active: false, radius: 0 }, // textBox: { @@ -125,6 +127,41 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool { }; } + addNewMeasurement(evt, interactionType) { + const eventData = evt.detail + if (!eventData || !eventData.currentPoints || !eventData.currentPoints.image) { + return + } + + const { element, image } = eventData + const measurementData = this.createNewMeasurement(eventData) + + if (!measurementData) { + return + } + + // Click-to-place and finish immediately; avoid default drag listeners. + measurementData.active = false + if (measurementData.handles && measurementData.handles.end) { + measurementData.handles.end.active = false + measurementData.handles.end.highlight = false + } + + cornerstoneTools.addToolState(element, this.name, measurementData) + + if (!measurementData.cachedStats && image) { + this.updateCachedStats(image, element, measurementData) + } + + external.cornerstone.updateImage(element) + + triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, { + toolName: this.name, + element, + measurementData + }) + } + /** * * diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue b/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue index 47dfcc74..0ccde59d 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue @@ -150,7 +150,7 @@ - + diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue b/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue index 9b25e7bf..ea97a047 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/uploadDicomFiles2.vue @@ -423,7 +423,7 @@ - + diff --git a/src/views/trials/trials-panel/visit/qc-check/components/dicomFiles.vue b/src/views/trials/trials-panel/visit/qc-check/components/dicomFiles.vue index 087fca9e..f69003dc 100644 --- a/src/views/trials/trials-panel/visit/qc-check/components/dicomFiles.vue +++ b/src/views/trials/trials-panel/visit/qc-check/components/dicomFiles.vue @@ -78,7 +78,7 @@ - + diff --git a/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue b/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue index ca1aab84..958bca3c 100644 --- a/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue +++ b/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue @@ -920,7 +920,7 @@ - + From 6a345e35cdd5707a28ca5b0b488d220c2889cd8d Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 7 May 2026 13:59:31 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=88=97=E5=AE=BD?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trials-panel/visit/crc-upload/components/studyInfo.vue | 2 +- .../trials-panel/visit/qc-check/components/dicomFiles.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue b/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue index 0ccde59d..2219867a 100644 --- a/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue +++ b/src/views/trials/trials-panel/visit/crc-upload/components/studyInfo.vue @@ -55,7 +55,7 @@ - +