质控临床数据更改
parent
8ff9e3b232
commit
1c0cdde9ad
|
|
@ -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 ArrowAnnotateTool from '@/views/trials/trials-panel/reading/dicoms/tools/ArrowAnnotate/ArrowAnnotateTool'
|
||||||
import RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/RectangleRoiTool'
|
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 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 OrientationMarkersTool from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/OrientationMarkersTool'
|
||||||
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
|
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
|
||||||
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
||||||
|
|
@ -260,7 +261,7 @@ export default {
|
||||||
series: '',
|
series: '',
|
||||||
ToolStateManager: null,
|
ToolStateManager: null,
|
||||||
renderedMeasured: [],
|
renderedMeasured: [],
|
||||||
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe'],
|
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe', 'FixedCircleRoi'],
|
||||||
measureData: [],
|
measureData: [],
|
||||||
selectedLesion: null,
|
selectedLesion: null,
|
||||||
activeTool: 0, // 0:enable 1:passive 2:active
|
activeTool: 0, // 0:enable 1:passive 2:active
|
||||||
|
|
@ -584,6 +585,13 @@ export default {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
e.preventDefault()
|
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) {
|
pointNearTool(e) {
|
||||||
|
|
@ -593,7 +601,9 @@ export default {
|
||||||
var toolType = this.measuredTools[m]
|
var toolType = this.measuredTools[m]
|
||||||
const toolState = ToolStateManager.getImageIdToolState(image.imageId, toolType)
|
const toolState = ToolStateManager.getImageIdToolState(image.imageId, toolType)
|
||||||
if (toolState) {
|
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'))
|
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) {
|
if (i > -1 && this.disabledMarks.length > 0 && this.disabledMarks.indexOf(toolState.data[i].remark) > -1) {
|
||||||
return true
|
return true
|
||||||
|
|
@ -783,7 +793,9 @@ export default {
|
||||||
var toolType = this.measuredTools[m]
|
var toolType = this.measuredTools[m]
|
||||||
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
||||||
if (toolState) {
|
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'))
|
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
|
|
@ -1019,7 +1031,9 @@ export default {
|
||||||
var toolType = this.measuredTools[t]
|
var toolType = this.measuredTools[t]
|
||||||
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
||||||
if (!toolState) continue
|
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'))
|
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
var idx = this.measureData.findIndex(item => item.MeasureData && item.MeasureData.data && item.MeasureData.data.uuid === toolState.data[i].uuid)
|
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.wc = Math.round(viewport.voi.windowCenter)
|
||||||
measureData.data.active = false
|
measureData.data.active = false
|
||||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||||
if (criterionType === 21) {
|
if (criterionType === 21 || criterionType === 22) {
|
||||||
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
||||||
}
|
}
|
||||||
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
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) {
|
loadImageStack(dicomSeries) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.isInitWwwc = true
|
this.isInitWwwc = true
|
||||||
|
|
@ -1169,8 +1192,22 @@ export default {
|
||||||
// Add the tool
|
// Add the tool
|
||||||
const toolName = toolBtn.getAttribute('data-tool')
|
const toolName = toolBtn.getAttribute('data-tool')
|
||||||
const apiTool = cornerstoneTools[`${toolName}Tool`]
|
const apiTool = cornerstoneTools[`${toolName}Tool`]
|
||||||
if (apiTool) {
|
let toolClass = apiTool
|
||||||
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, 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 (!toolAlreadyAddedToElement) {
|
||||||
if (toolName === 'Length') {
|
if (toolName === 'Length') {
|
||||||
|
|
@ -1183,8 +1220,10 @@ export default {
|
||||||
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
||||||
} else if (toolName === 'RectangleRoi') {
|
} else if (toolName === 'RectangleRoi') {
|
||||||
cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
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 } })
|
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 {
|
} else {
|
||||||
cornerstoneTools.addToolForElement(element, apiTool)
|
cornerstoneTools.addToolForElement(element, apiTool)
|
||||||
}
|
}
|
||||||
|
|
@ -1528,7 +1567,7 @@ export default {
|
||||||
measureData.wc = Math.round(viewport.voi.windowCenter)
|
measureData.wc = Math.round(viewport.voi.windowCenter)
|
||||||
measureData.data.active = false
|
measureData.data.active = false
|
||||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||||
if (criterionType === 21) {
|
if (criterionType === 21 || criterionType === 22) {
|
||||||
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
||||||
}
|
}
|
||||||
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
||||||
|
|
@ -1982,7 +2021,8 @@ export default {
|
||||||
'CobbAngle',
|
'CobbAngle',
|
||||||
'Angle',
|
'Angle',
|
||||||
'Bidirectional',
|
'Bidirectional',
|
||||||
'FreehandRoi'
|
'FreehandRoi',
|
||||||
|
'FixedCircleRoi'
|
||||||
]
|
]
|
||||||
for (let i = 0; i < toolROITypes.length; i++) {
|
for (let i = 0; i < toolROITypes.length; i++) {
|
||||||
const toolROIType = toolROITypes[i]
|
const toolROIType = toolROITypes[i]
|
||||||
|
|
|
||||||
|
|
@ -492,6 +492,10 @@
|
||||||
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
||||||
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
||||||
@handleReadingChart="handleReadingChart" />
|
@handleReadingChart="handleReadingChart" />
|
||||||
|
<MRIPDFFAdvance v-else-if="CriterionType === 22" ref="measurementList"
|
||||||
|
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
||||||
|
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
||||||
|
@handleReadingChart="handleReadingChart" />
|
||||||
<h2 v-else style="color:#ddd">
|
<h2 v-else style="color:#ddd">
|
||||||
Developing...
|
Developing...
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -689,6 +693,7 @@ import LuganoWithoutPETQuestionList from './LuganoWithoutPET/QuestionList'
|
||||||
import IVUSList from './IVUS/QuestionList'
|
import IVUSList from './IVUS/QuestionList'
|
||||||
import OCTList from './OCT/QuestionList'
|
import OCTList from './OCT/QuestionList'
|
||||||
import MRIPDFF from './MRIPDFF/QuestionList'
|
import MRIPDFF from './MRIPDFF/QuestionList'
|
||||||
|
import MRIPDFFAdvance from './MRIPDFFAdvance/QuestionList'
|
||||||
import CustomWwwcForm from './CustomWwwcForm'
|
import CustomWwwcForm from './CustomWwwcForm'
|
||||||
import Manuals from './Manuals'
|
import Manuals from './Manuals'
|
||||||
import Hotkeys from './Hotkeys'
|
import Hotkeys from './Hotkeys'
|
||||||
|
|
@ -725,6 +730,7 @@ export default {
|
||||||
IVUSList,
|
IVUSList,
|
||||||
OCTList,
|
OCTList,
|
||||||
MRIPDFF,
|
MRIPDFF,
|
||||||
|
MRIPDFFAdvance,
|
||||||
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
||||||
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
||||||
SignForm
|
SignForm
|
||||||
|
|
@ -1012,6 +1018,10 @@ export default {
|
||||||
this.measuredTools = [{
|
this.measuredTools = [{
|
||||||
toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: ''
|
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.rotateList[0] = '1'
|
||||||
this.colorList[0] = ''
|
this.colorList[0] = ''
|
||||||
|
|
@ -1126,7 +1136,12 @@ export default {
|
||||||
DicomEvent.$on('addAnnotation', async obj => {
|
DicomEvent.$on('addAnnotation', async obj => {
|
||||||
this.tmpData = Object.assign({}, obj.question)
|
this.tmpData = Object.assign({}, obj.question)
|
||||||
// await this.imageLocation(obj.locateInfo)
|
// 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', () => {
|
window.addEventListener('beforeunload', () => {
|
||||||
if (this.petctWindow) {
|
if (this.petctWindow) {
|
||||||
|
|
@ -2160,7 +2175,7 @@ export default {
|
||||||
},
|
},
|
||||||
// 添加标记
|
// 添加标记
|
||||||
setMeasureData(data) {
|
setMeasureData(data) {
|
||||||
if (this.CriterionType === 21) {
|
if (this.CriterionType === 21 || this.CriterionType === 22) {
|
||||||
if (this.tmpData) {
|
if (this.tmpData) {
|
||||||
data.tableQuestionId = this.tmpData.Id
|
data.tableQuestionId = this.tmpData.Id
|
||||||
data.tableQuestionMark = this.tmpData.QuestionMark
|
data.tableQuestionMark = this.tmpData.QuestionMark
|
||||||
|
|
@ -2174,7 +2189,7 @@ export default {
|
||||||
},
|
},
|
||||||
// 修改标记
|
// 修改标记
|
||||||
modifyMeasureData(data) {
|
modifyMeasureData(data) {
|
||||||
if (this.CriterionType === 21 && data.measureData.tableQuestionId) {
|
if ((this.CriterionType === 21 || this.CriterionType === 22) && data.measureData.tableQuestionId) {
|
||||||
this.$refs['measurementList'].modifyMeasuredData(data)
|
this.$refs['measurementList'].modifyMeasuredData(data)
|
||||||
} else {
|
} else {
|
||||||
this.$refs['measurementList'].modifyMeasuredData(data)
|
this.$refs['measurementList'].modifyMeasuredData(data)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,864 @@
|
||||||
|
<template>
|
||||||
|
<el-form v-if="isRender" ref="measurementForm" v-loading="loading" :model="questionForm" size="mini"
|
||||||
|
class="measurement-form">
|
||||||
|
<div class="base-dialog-body">
|
||||||
|
<div style="display: flex;justify-content: space-between;">
|
||||||
|
<h3 v-if="questionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
|
||||||
|
<!-- {{ lesionName }} -->
|
||||||
|
</h3>
|
||||||
|
<!-- 关闭 -->
|
||||||
|
<div>
|
||||||
|
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="handleClose" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item v-for="qs in questions" v-show="qs.ShowQuestion !== 2" :key="qs.Id" :label="`${qs.QuestionName}`"
|
||||||
|
:prop="qs.Id" :rules="[
|
||||||
|
{
|
||||||
|
required: (qs.IsRequired === 0 || (qs.IsRequired === 1 && qs.RelevanceId && (String(questionForm[qs.RelevanceId]) === qs.RelevanceValue)) || (qs.QuestionMark === 6 && questionForm.IsCanEditPosition === true) || (questionForm.IsCanEditPosition && qs.QuestionMark === 10)) && qs.Type !== 'group' && qs.Type !== 'summary',
|
||||||
|
message: ['radio', 'select', 'checkbox'].includes(qs.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||||
|
},
|
||||||
|
]" style="flex-wrap: wrap">
|
||||||
|
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<template
|
||||||
|
v-if="(qs.Type === 'input' || qs.Type === 'number') && (qs.QuestionMark === 1101 || qs.QuestionMark === 1102 || qs.QuestionMark === 1103 || qs.QuestionMark === 1107)">
|
||||||
|
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;">
|
||||||
|
<el-input v-model="questionForm[qs.Id]" disabled style="width: 100px;">
|
||||||
|
<template v-if="qs.Unit" slot="append">
|
||||||
|
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<!-- 测量 -->
|
||||||
|
<el-button
|
||||||
|
v-if="questionForm[isMeasurableId] && parseInt(questionForm[isMeasurableId]) === 1 && !questionForm[qs.Id] && readingTaskState !== 2"
|
||||||
|
size="mini" type="text" @click="addAnnotation(qs)">
|
||||||
|
{{ $t('trials:MRIPDFF:button:measure') }}
|
||||||
|
</el-button>
|
||||||
|
<!-- 清除标记 -->
|
||||||
|
<el-button v-if="getAnnotationStatus(qs) && readingTaskState !== 2" size="mini" type="text"
|
||||||
|
style="margin-left: 0px" @click="removeAnnotation(qs)">
|
||||||
|
{{ $t('trials:MRIPDFF:button:clear') }}
|
||||||
|
</el-button>
|
||||||
|
<!-- 返回 -->
|
||||||
|
<el-button v-if="questionForm[qs.Id]" size="mini" type="text" style="margin-left: 0px"
|
||||||
|
@click="locateAnnotation(qs)">
|
||||||
|
{{ $t('trials:MRIPDFF:button:return') }}
|
||||||
|
</el-button>
|
||||||
|
<!-- 保存 -->
|
||||||
|
<el-button
|
||||||
|
v-if="questionForm[isMeasurableId] && parseInt(questionForm[isMeasurableId]) === 1 && questionForm[qs.Id] && readingTaskState !== 2"
|
||||||
|
size="mini" type="text" style="margin-left: 0px" @click="saveAnnotation(qs)">
|
||||||
|
<!-- 未保存 -->
|
||||||
|
<el-tooltip v-if="getAnnotationSaveEnum(qs) === 0" class="item" effect="dark"
|
||||||
|
:content="$t('trials:reading:button:unsaved')" placement="bottom">
|
||||||
|
<i class="el-icon-warning" style="color:red" />
|
||||||
|
</el-tooltip>
|
||||||
|
{{ $t('common:button:save') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="qs.Type === 'input' || qs.Type === 'number'">
|
||||||
|
<div style="display: flex;justify-content: space-between;">
|
||||||
|
<el-input v-model="questionForm[qs.Id]" :disabled="!isCurrentTask || readingTaskState >= 2"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="(qs.QuestionMark === 0 || qs.QuestionMark === 1) && qs.Unit" slot="append">
|
||||||
|
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<svg-icon v-if="qs.ShowChartTypeEnum > 0" icon-class="readingChart" class="svg-icon svg-readingChart"
|
||||||
|
@click.stop="(e) => handleReadingChart({
|
||||||
|
e,
|
||||||
|
data: {
|
||||||
|
TableQuestionId: qs.Id,
|
||||||
|
RowIndex: questionForm.RowIndex,
|
||||||
|
QuestionName: qs.QuestionName
|
||||||
|
}
|
||||||
|
})" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 多行文本输入框 -->
|
||||||
|
<el-input v-else-if="qs.Type === 'textarea'" v-model="questionForm[qs.Id]" type="textarea"
|
||||||
|
:autosize="{ minRows: 2, maxRows: 4 }" :disabled="!isCurrentTask || readingTaskState >= 2"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })" />
|
||||||
|
<!-- 下拉框 -->
|
||||||
|
|
||||||
|
<el-select v-else-if="qs.Type === 'select'" v-model="questionForm[qs.Id]" filterable
|
||||||
|
:placeholder="$t('common:placeholder:select')"
|
||||||
|
:disabled="!isCurrentTask || readingTaskState >= 2 || qs.QuestionMark === 1106"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="qs.TableQuestionType === 1">
|
||||||
|
<el-option v-for="item in organList" :key="item.Id" :label="item[qs.DataTableColumn]"
|
||||||
|
:value="item[qs.DataTableColumn]" />
|
||||||
|
</template>
|
||||||
|
<template v-else-if="qs.DictionaryCode">
|
||||||
|
<el-option v-for="item of $d[qs.DictionaryCode]" :key="item.id" :value="item.value" :label="item.label" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-option v-for="val in qs.TypeValue.split('|')" :key="val" :label="val" :value="val" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</el-select>
|
||||||
|
<!-- 单选 -->
|
||||||
|
<el-radio-group v-else-if="qs.Type === 'radio'" v-model="questionForm[qs.Id]"
|
||||||
|
:disabled="!isCurrentTask || readingTaskState >= 2 || (qs.QuestionMark === 1105 && isDisabledMeasurableRadio)"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="qs.DictionaryCode.length > 0">
|
||||||
|
<el-radio v-for="item in $d[qs.DictionaryCode]" :key="item.id" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="qs.options.length > 0">
|
||||||
|
<el-radio v-for="val in qs.options.split('|')" :key="val" :label="val">
|
||||||
|
{{ val }}
|
||||||
|
</el-radio>
|
||||||
|
</template>
|
||||||
|
</el-radio-group>
|
||||||
|
<div style="display: flex;justify-content: space-between;" v-else-if="qs.Type === 'calculation'">
|
||||||
|
<!-- 自动计算 -->
|
||||||
|
<el-input v-model="questionForm[qs.Id]" disabled @change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="qs.Unit" slot="append">
|
||||||
|
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<svg-icon v-if="qs.ShowChartTypeEnum > 0" icon-class="readingChart" class="svg-icon svg-readingChart"
|
||||||
|
@click.stop="(e) => handleReadingChart({
|
||||||
|
e,
|
||||||
|
data: {
|
||||||
|
TableQuestionId: qs.Id,
|
||||||
|
RowIndex: questionForm.RowIndex,
|
||||||
|
QuestionName: qs.QuestionName
|
||||||
|
}
|
||||||
|
})" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isCurrentTask && readingTaskState < 2" class="base-dialog-footer"
|
||||||
|
style="text-align:right;margin-top:10px;">
|
||||||
|
<!-- 保存 -->
|
||||||
|
<el-button size="mini" @click="handleSave">
|
||||||
|
{{ $t('common:button:save') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
// import { submitTableQuestion } from '@/api/trials'
|
||||||
|
import { saveTableQuestionMark, submitTaskRowInfo, deleteTableQuestionMark, deleteSingleTableQuestionMark } from '@/api/reading'
|
||||||
|
import DicomEvent from './../DicomEvent'
|
||||||
|
import store from '@/store'
|
||||||
|
import * as cornerstone from 'cornerstone-core'
|
||||||
|
export default {
|
||||||
|
name: 'MeasurementForm',
|
||||||
|
props: {
|
||||||
|
questions: {
|
||||||
|
type: Array,
|
||||||
|
default() { return [] }
|
||||||
|
},
|
||||||
|
answers: {
|
||||||
|
type: Object,
|
||||||
|
default() { return {} }
|
||||||
|
},
|
||||||
|
lesionType: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
visitTaskId: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
parentQsId: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isCurrentTask: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
readingTaskState: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isBaseLineTask: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
orderMark: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
questionName: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
rowIndex: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tableQuestions: {
|
||||||
|
type: Array,
|
||||||
|
default() { return [] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
questionForm: {},
|
||||||
|
loading: false,
|
||||||
|
trialId: '',
|
||||||
|
originalQuestionForm: {},
|
||||||
|
isRender: false,
|
||||||
|
lesionName: '',
|
||||||
|
lesionMark: '',
|
||||||
|
activeQuestionId: '',
|
||||||
|
activeQuestionMark: '',
|
||||||
|
markList: [],
|
||||||
|
digitPlaces: 2,
|
||||||
|
isMeasurableId: '',
|
||||||
|
isExitsMarks: false,
|
||||||
|
isDisabledMeasurableRadio: false,
|
||||||
|
liverSeg: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.trialId = this.$route.query.trialId
|
||||||
|
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||||
|
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||||
|
this.initForm()
|
||||||
|
DicomEvent.$on('handleImageQualityAbnormal', () => {
|
||||||
|
this.setState()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
DicomEvent.$off('handleImageQualityAbnormal')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleReadingChart(e) {
|
||||||
|
this.$emit('handleReadingChart', e)
|
||||||
|
},
|
||||||
|
async initForm() {
|
||||||
|
this.isRender = false
|
||||||
|
this.isMeasurableId = this.getQuestionId(1105)
|
||||||
|
// const loading = this.$loading({ fullscreen: true })
|
||||||
|
this.questions.forEach(item => {
|
||||||
|
if (this.answers.hasOwnProperty(item.Id)) {
|
||||||
|
let val = this.answers[item.Id]
|
||||||
|
if (item.DictionaryCode) {
|
||||||
|
val = isNaN(parseInt(this.answers[item.Id])) ? this.answers[item.Id] : parseInt(this.answers[item.Id])
|
||||||
|
}
|
||||||
|
this.$set(this.questionForm, item.Id, val)
|
||||||
|
} else {
|
||||||
|
this.$set(this.questionForm, item.Id, '')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$set(this.questionForm, 'MeasureData', this.answers.MeasureData ? JSON.parse(this.answers.MeasureData) : '')
|
||||||
|
this.$set(this.questionForm, 'RowIndex', this.answers.RowIndex ? this.answers.RowIndex : '')
|
||||||
|
this.$set(this.questionForm, 'RowId', this.answers.RowId ? this.answers.RowId : '')
|
||||||
|
// 如果存在标记且是否可测量为否,则将是否可测量更改为是
|
||||||
|
if (this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
const arr = JSON.parse(this.answers.TableQuestionMarkList)
|
||||||
|
const isExitsMarks = arr.findIndex(i => i.MeasureData) > -1
|
||||||
|
if (isExitsMarks && parseInt(this.questionForm[this.isMeasurableId]) === 0) {
|
||||||
|
this.$set(this.questionForm, this.isMeasurableId, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// saveTypeEnum 0:未保存过(新建病灶);1:已保存,信息不完整(随访初始化病灶/分裂病灶,通过状态判断);2:已保存,信息完整
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
const mean = this.getQuestionVal(1104)
|
||||||
|
if (this.questionForm.saveTypeEnum !== 1 && this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', parseInt(isMeasurable) === 1 && isNaN(parseFloat(mean)) ? 1 : 2)
|
||||||
|
}
|
||||||
|
this.lesionName = this.getLesionInfo(this.orderMark, this.rowIndex)
|
||||||
|
this.lesionMark = this.getLesionName(this.orderMark, 1101)
|
||||||
|
this.originalQuestionForm = { ...this.questionForm }
|
||||||
|
this.markList = []
|
||||||
|
this.isExitsMarks = false
|
||||||
|
this.isDisabledMeasurableRadio = false
|
||||||
|
const seg = this.getQuestionVal(1106)
|
||||||
|
this.liverSeg = this.$fd('LiverSegmentation', seg)
|
||||||
|
if (this.answers.TableQuestionMarkList) {
|
||||||
|
const arr = JSON.parse(this.answers.TableQuestionMarkList)
|
||||||
|
arr.map(i => {
|
||||||
|
if (i.MeasureData) {
|
||||||
|
this.isExitsMarks = true
|
||||||
|
if (!isNaN(parseInt(isMeasurable)) && parseInt(isMeasurable) === 1 && this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
this.isDisabledMeasurableRadio = true
|
||||||
|
}
|
||||||
|
i.MeasureData = JSON.parse(i.MeasureData)
|
||||||
|
}
|
||||||
|
this.markList.push({ tableQuestionId: i.TableQuestionId, measureData: i, saveEnum: 1 })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const newMean = this.getMean()
|
||||||
|
if (newMean !== mean) {
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, newMean || '')
|
||||||
|
}
|
||||||
|
if (this.questionForm.saveTypeEnum === 1 && this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
this.setQuestions()
|
||||||
|
}
|
||||||
|
this.isRender = true
|
||||||
|
// loading.close()
|
||||||
|
},
|
||||||
|
getLesionName(orderMark, questionMark) {
|
||||||
|
// 根据肝脏分段枚举和第一次(或第二次或第三次)测量问题标识定义标记名称
|
||||||
|
// I II III IV V VI VII VIII
|
||||||
|
// L-I-01 L-I-02 L-I-03
|
||||||
|
// L-II-01 L-II-02 L-II-03
|
||||||
|
const segArr = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII']
|
||||||
|
let lessionName = ''
|
||||||
|
const segmentId = this.getQuestionId(1106)
|
||||||
|
let segmentVal = this.answers[segmentId]
|
||||||
|
segmentVal = segmentVal ? parseInt(segmentVal) : null
|
||||||
|
if (segmentVal) {
|
||||||
|
const i = questionMark === 1101 ? '01' : questionMark === 1102 ? '02' : questionMark === 1103 ? '03' : questionMark === 1107 ? '04' : ''
|
||||||
|
lessionName = `${orderMark}-${segArr[segmentVal - 1]}-${i}`
|
||||||
|
}
|
||||||
|
return lessionName
|
||||||
|
},
|
||||||
|
getLesionInfo(orderMark, rowIndex) {
|
||||||
|
var arr = []
|
||||||
|
var lessionName = ''
|
||||||
|
var rowIndexArr = rowIndex.split('.')
|
||||||
|
var x = parseInt(rowIndexArr[0])
|
||||||
|
var y = parseInt(rowIndexArr[1])
|
||||||
|
if (y > 0) {
|
||||||
|
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
|
||||||
|
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
|
||||||
|
arr.push(lessionName)
|
||||||
|
} else {
|
||||||
|
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
|
||||||
|
arr.push(lessionName)
|
||||||
|
}
|
||||||
|
return arr.join(' ')
|
||||||
|
},
|
||||||
|
getQuestionId(questionMark) {
|
||||||
|
var idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
|
||||||
|
if (idx > -1) {
|
||||||
|
return this.questions[idx].Id
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async formItemChange(v, qs) {
|
||||||
|
// 维护平均值、是否可测量等信息
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
const mean = this.getQuestionVal(1104)
|
||||||
|
if (qs.QuestionMark === 1101 || qs.QuestionMark === 1102 || qs.QuestionMark === 1103 || qs.QuestionMark === 1107) {
|
||||||
|
const newMean = this.getMean()
|
||||||
|
if (newMean !== mean) {
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, newMean || '')
|
||||||
|
}
|
||||||
|
} else if (qs.QuestionMark === 1105) {
|
||||||
|
if (!v) {
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, 'NE')
|
||||||
|
} else {
|
||||||
|
const mean = this.getMean()
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, mean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setQuestions()
|
||||||
|
},
|
||||||
|
getMean() {
|
||||||
|
let mean = null
|
||||||
|
let isMeasurable = this.getQuestionVal(1105)
|
||||||
|
isMeasurable = !isNaN(parseInt(isMeasurable)) ? parseInt(isMeasurable) : null
|
||||||
|
const l1 = this.getQuestionVal(1101)
|
||||||
|
const l2 = this.getQuestionVal(1102)
|
||||||
|
const l3 = this.getQuestionVal(1103)
|
||||||
|
const l4 = this.getQuestionVal(1107)
|
||||||
|
if (isMeasurable && !isNaN(parseFloat(l1)) && !isNaN(parseFloat(l2)) && !isNaN(parseFloat(l3)) && !isNaN(parseFloat(l4))) {
|
||||||
|
const sum = l1 + l2 + l3 + l4
|
||||||
|
mean = sum / 4
|
||||||
|
return parseFloat(mean.toFixed(this.digitPlaces))
|
||||||
|
} else if (isMeasurable === 0) {
|
||||||
|
return 'NE'
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
// const val = measureData.data.cachedStats.mean / 10
|
||||||
|
let val = parseFloat(measureData?.data?.cachedStats?.mean)
|
||||||
|
if (isNaN(val)) {
|
||||||
|
resolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// let imagePixelModule = cornerstone.metaData.get('imagePixelModule', measureData.imageId)
|
||||||
|
if (measureData.largestPixelValue >= 500) {
|
||||||
|
val = val / 10
|
||||||
|
}
|
||||||
|
this.$set(this.questionForm, measureData.tableQuestionId, val.toFixed(this.digitPlaces))
|
||||||
|
data = {
|
||||||
|
Id: '',
|
||||||
|
StudyId: measureData.studyId,
|
||||||
|
InstanceId: measureData.instanceId,
|
||||||
|
SeriesId: measureData.seriesId,
|
||||||
|
MeasureData: measureData,
|
||||||
|
QuestionId: this.parentQsId,
|
||||||
|
RowIndex: this.questionForm.RowIndex,
|
||||||
|
RowId: this.questionForm.RowId,
|
||||||
|
VisitTaskId: this.visitTaskId,
|
||||||
|
NumberOfFrames: isNaN(parseInt(measureData.frame)) ? 0 : measureData.frame,
|
||||||
|
frame: isNaN(parseInt(measureData.frame)) ? 0 : measureData.frame,
|
||||||
|
OrderMarkName: measureData.data.remark,
|
||||||
|
TableQuestionId: measureData.tableQuestionId
|
||||||
|
}
|
||||||
|
store.dispatch('reading/addMeasuredData', { visitTaskId: this.visitTaskId, data: data })
|
||||||
|
let mean = this.getQuestionVal(1104)
|
||||||
|
const newMean = this.getMean()
|
||||||
|
if (newMean !== mean) {
|
||||||
|
mean = newMean
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, newMean || '')
|
||||||
|
}
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
DicomEvent.$emit('refreshStudyListMeasureData')
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === measureData.tableQuestionId)
|
||||||
|
if (i === -1) {
|
||||||
|
this.markList.push({ tableQuestionId: measureData.tableQuestionId, measureData: data, saveEnum: 0 })
|
||||||
|
} else {
|
||||||
|
this.markList[i].saveEnum = 0
|
||||||
|
this.markList[i].measureData = data
|
||||||
|
}
|
||||||
|
if (!isNaN(parseInt(isMeasurable)) && parseInt(isMeasurable) === 1) {
|
||||||
|
this.isDisabledMeasurableRadio = true
|
||||||
|
}
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
this.setQuestions()
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addAnnotation(qs) {
|
||||||
|
// 判断是否有测量数据未保存
|
||||||
|
const i = this.markList.findIndex(i => i.saveEnum === 0)
|
||||||
|
if (i > -1 && this.markList[i].measureData && this.markList[i].measureData.MeasureData) {
|
||||||
|
this.$alert(this.$t('trials:MRIPDFF:message:message3'))
|
||||||
|
// this.$message.warning(this.$t('trials:MRIPDFF:message:message3'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const orderMarkName = this.getLesionName(this.orderMark, qs.QuestionMark)
|
||||||
|
this.activeQuestionId = qs.Id
|
||||||
|
this.activeQuestionMark = qs.QuestionMark
|
||||||
|
DicomEvent.$emit('addAnnotation', { question: qs, locateInfo: { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: orderMarkName, lesionType: null, markTool: 'Probe', readingTaskState: this.readingTaskState, isMarked: true } })
|
||||||
|
},
|
||||||
|
getAnnotationSaveEnum(qs) {
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === qs.Id)
|
||||||
|
if (i > -1) {
|
||||||
|
return this.markList[i].saveEnum
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAnnotationStatus(qs) {
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === qs.Id)
|
||||||
|
if (i > -1 && this.markList[i].measureData && this.markList[i].measureData.MeasureData) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getIsExitsMarks() {
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
if (!isNaN(parseInt(isMeasurable)) && parseInt(isMeasurable) === 1) {
|
||||||
|
return this.markList.findIndex(i => i.measureData && i.measureData.MeasureData) > -1
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async removeAnnotation(qs) {
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === qs.Id)
|
||||||
|
DicomEvent.$emit('imageLocation', { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: this.markList[i].measureData.OrderMarkName, lesionType: null, markTool: 'Probe', readingTaskState: this.readingTaskState, isMarked: true })
|
||||||
|
// 是否确认清除标记?
|
||||||
|
const confirm = await this.$confirm(
|
||||||
|
this.$t('trials:reading:warnning:msg47'),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
distinguishCancelAndClose: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (confirm !== 'confirm') return
|
||||||
|
|
||||||
|
const measureData = Object.assign({}, this.markList[i].measureData)
|
||||||
|
if (measureData.Id) {
|
||||||
|
await deleteSingleTableQuestionMark({ Id: measureData.Id }, 11)
|
||||||
|
}
|
||||||
|
// 移除缓存中的measureData
|
||||||
|
await store.dispatch('reading/removeMeasuredData', { visitTaskId: this.visitTaskId, measureData: measureData, questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, orderMarkName: measureData.OrderMarkName })
|
||||||
|
DicomEvent.$emit('getMeasureData')
|
||||||
|
this.markList[i].measureData = null
|
||||||
|
this.markList[i].saveEnum = 0
|
||||||
|
// 清除测量值、清除平均值
|
||||||
|
this.$set(this.questionForm, this.markList[i].tableQuestionId, '')
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, '')
|
||||||
|
this.isDisabledMeasurableRadio = this.getIsExitsMarks()
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
this.setQuestions()
|
||||||
|
},
|
||||||
|
locateAnnotation(qs) {
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === qs.Id)
|
||||||
|
const measureData = this.markList[i].measureData
|
||||||
|
// 定位
|
||||||
|
var markTool = 'Probe'
|
||||||
|
var readingTaskState = this.readingTaskState
|
||||||
|
var isMarked = !!measureData
|
||||||
|
DicomEvent.$emit('imageLocation', { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: measureData.OrderMarkName, lesionType: null, markTool, readingTaskState, isMarked })
|
||||||
|
},
|
||||||
|
setQuestions() {
|
||||||
|
const mean = this.getQuestionVal(1104)
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
this.$emit('resetQuestions', { mean, isMeasurable, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
|
||||||
|
},
|
||||||
|
async saveAnnotation(qs) {
|
||||||
|
const loading = this.$loading({ fullscreen: true })
|
||||||
|
try {
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === qs.Id)
|
||||||
|
let params = {}
|
||||||
|
if (i > -1 && this.markList[i].measureData && this.markList[i].measureData.MeasureData) {
|
||||||
|
const measureData = this.markList[i].measureData.MeasureData
|
||||||
|
const tableQuestionId = this.markList[i].tableQuestionId
|
||||||
|
if (this.questionForm[tableQuestionId] > 100) {
|
||||||
|
const confirm = await this.$confirm(
|
||||||
|
this.$t('trials:MRIPDFF:message:message4'),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
distinguishCancelAndClose: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (confirm !== 'confirm') return
|
||||||
|
}
|
||||||
|
// 上传截图
|
||||||
|
|
||||||
|
DicomEvent.$emit('getScreenshots', { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: measureData.OrderMarkName, lesionType: null, isMarked: !!measureData }, async val => {
|
||||||
|
params = Object.assign({}, this.markList[i].measureData)
|
||||||
|
if (val) {
|
||||||
|
const pictureObj = await this.uploadScreenshots(`${new Date().getTime()}`, val)
|
||||||
|
params.PicturePath = pictureObj.isSuccess ? this.$getObjectName(pictureObj.result.url) : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Answer = this.questionForm[tableQuestionId]
|
||||||
|
params.MeasureData = JSON.stringify(this.markList[i].measureData.MeasureData)
|
||||||
|
loading.close()
|
||||||
|
this.saveTableQuestionInfo(params, qs)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
params = {
|
||||||
|
Answer: '',
|
||||||
|
VisitTaskId: this.visitTaskId,
|
||||||
|
QuestionId: this.parentQsId,
|
||||||
|
InstanceId: '',
|
||||||
|
SeriesId: '',
|
||||||
|
StudyId: '',
|
||||||
|
MarkTool: '',
|
||||||
|
PicturePath: '',
|
||||||
|
NumberOfFrames: 0,
|
||||||
|
MeasureData: '',
|
||||||
|
QuestionType: 0,
|
||||||
|
OrderMarkName: '',
|
||||||
|
RowId: this.questionForm.RowId,
|
||||||
|
TableQuestionId: qs.Id,
|
||||||
|
RowIndex: this.questionForm.RowIndex
|
||||||
|
}
|
||||||
|
loading.close()
|
||||||
|
this.saveTableQuestionInfo(params, qs)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async saveTableQuestionInfo(params, qs) {
|
||||||
|
const loading = this.$loading({ fullscreen: true })
|
||||||
|
try {
|
||||||
|
const res = await saveTableQuestionMark(params, 11)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
// 保存后设置保存状态
|
||||||
|
const i = this.markList.findIndex(i => i.tableQuestionId === qs.Id)
|
||||||
|
this.markList[i].saveEnum = 1
|
||||||
|
// 保存病灶
|
||||||
|
const j = this.markList.findIndex(i => !(i.saveEnum === 1 && i.measureData && i.measureData.MeasureData))
|
||||||
|
if (j === -1) {
|
||||||
|
const answers = []
|
||||||
|
const reg = new RegExp(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/)
|
||||||
|
for (const k in this.questionForm) {
|
||||||
|
if (reg.test(k)) {
|
||||||
|
if (answers.findIndex(i => i.tableQuestionId === k) === -1) {
|
||||||
|
answers.push({ tableQuestionId: k, answer: this.questionForm[k] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const params = {
|
||||||
|
questionId: this.parentQsId,
|
||||||
|
rowId: this.questionForm.RowId,
|
||||||
|
rowIndex: this.answers.RowIndex,
|
||||||
|
visitTaskId: this.visitTaskId,
|
||||||
|
trialId: this.trialId,
|
||||||
|
answerList: answers,
|
||||||
|
isDicomReading: true
|
||||||
|
}
|
||||||
|
const res = await submitTaskRowInfo(params, 11)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 2)
|
||||||
|
this.originalQuestionForm = { ...this.questionForm }
|
||||||
|
this.$set(this.questionForm, 'RowId', res.Result.RowId)
|
||||||
|
this.setQuestions()
|
||||||
|
DicomEvent.$emit('getReportInfo', true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 保存成功
|
||||||
|
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||||
|
// 刷新表格、刷新标记信息
|
||||||
|
this.$emit('getReadingQuestionAndAnswer')
|
||||||
|
DicomEvent.$emit('setMeasuredToolsPassive')
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
returnFloat(num) {
|
||||||
|
if (num) return
|
||||||
|
var value = Math.round(parseFloat(num) * 100) / 100
|
||||||
|
var s = value.toString().split('.')
|
||||||
|
if (s.length === 1) {
|
||||||
|
value = value.toString() + '.00'
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (s.length > 1) {
|
||||||
|
if (s[1].length < 2) {
|
||||||
|
value = value.toString() + '0'
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getQuestionVal(questionMark) {
|
||||||
|
const idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
|
||||||
|
if (idx > -1) {
|
||||||
|
const questionId = this.questions[idx].Id
|
||||||
|
const answer = this.questionForm[questionId]
|
||||||
|
if (isNaN(parseFloat(answer))) {
|
||||||
|
return answer
|
||||||
|
} else {
|
||||||
|
return parseFloat(answer)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async uploadScreenshots(fileName, file) {
|
||||||
|
try {
|
||||||
|
file = this.convertBase64ToBlob(file)
|
||||||
|
var trialId = this.$route.query.trialId
|
||||||
|
var subjectId = this.$route.query.trialId
|
||||||
|
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
|
||||||
|
return { isSuccess: true, result: result }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return { isSuccess: false, result: e }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
convertBase64ToBlob(imageEditorBase64) {
|
||||||
|
var base64Arr = imageEditorBase64.split(',')
|
||||||
|
var imgtype = ''
|
||||||
|
var base64String = ''
|
||||||
|
if (base64Arr.length > 1) {
|
||||||
|
// 如果是图片base64,去掉头信息
|
||||||
|
base64String = base64Arr[1]
|
||||||
|
imgtype = base64Arr[0].substring(
|
||||||
|
base64Arr[0].indexOf(':') + 1,
|
||||||
|
base64Arr[0].indexOf(';')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 将base64解码
|
||||||
|
var bytes = atob(base64String)
|
||||||
|
// var bytes = base64;
|
||||||
|
var bytesCode = new ArrayBuffer(bytes.length)
|
||||||
|
// 转换为类型化数组
|
||||||
|
var byteArray = new Uint8Array(bytesCode)
|
||||||
|
|
||||||
|
// 将base64转换为ascii码
|
||||||
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
|
byteArray[i] = bytes.charCodeAt(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成Blob对象(文件对象)
|
||||||
|
return new Blob([bytesCode], { type: imgtype })
|
||||||
|
},
|
||||||
|
async handleSave() {
|
||||||
|
try {
|
||||||
|
const valid = await this.$refs.measurementForm.validate()
|
||||||
|
if (!valid) return
|
||||||
|
if (parseInt(this.questionForm[this.isMeasurableId]) === 1) {
|
||||||
|
// 检验是否有标记为保存
|
||||||
|
const i = this.markList.findIndex(i => i.saveEnum === 0)
|
||||||
|
if (i > -1) {
|
||||||
|
// 请先保存标注信息!
|
||||||
|
this.$alert(this.$t('trials:MRIPDFF:message:message1'))
|
||||||
|
// this.$message.warning(this.$t('trials:MRIPDFF:message:message1'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 不可测量时,清空测量值,平均值
|
||||||
|
// '是否确认不可测量?'
|
||||||
|
const confirm = await this.$confirm(
|
||||||
|
this.$t('trials:MRIPDFF:message:message2'),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
distinguishCancelAndClose: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (confirm !== 'confirm') return
|
||||||
|
const l1Id = this.getQuestionId(1101)
|
||||||
|
this.$set(this.questionForm, l1Id, '')
|
||||||
|
const l2Id = this.getQuestionId(1102)
|
||||||
|
this.$set(this.questionForm, l2Id, '')
|
||||||
|
const l3Id = this.getQuestionId(1103)
|
||||||
|
this.$set(this.questionForm, l3Id, '')
|
||||||
|
const l4Id = this.getQuestionId(1107)
|
||||||
|
this.$set(this.questionForm, l4Id, '')
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, meanId, 'NE')
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = this.$loading({ fullscreen: true })
|
||||||
|
|
||||||
|
try {
|
||||||
|
// let isResetMarks = this.markList.findIndex(i=>i.measureData && i.measureData.MeasureData) > -1 ? true : false
|
||||||
|
if (parseInt(this.questionForm[this.isMeasurableId]) === 0 && this.isExitsMarks) {
|
||||||
|
await deleteTableQuestionMark({ rowId: this.questionForm.RowId }, 11)
|
||||||
|
this.markList.forEach(i => {
|
||||||
|
if (i.measureData && i.measureData.MeasureData) {
|
||||||
|
i.measureData = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.isExitsMarks = false
|
||||||
|
}
|
||||||
|
var answers = []
|
||||||
|
var reg = new RegExp(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/)
|
||||||
|
for (const k in this.questionForm) {
|
||||||
|
if (reg.test(k)) {
|
||||||
|
if (answers.findIndex(i => i.tableQuestionId === k) === -1) {
|
||||||
|
answers.push({ tableQuestionId: k, answer: this.questionForm[k] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
questionId: this.parentQsId,
|
||||||
|
rowId: this.questionForm.RowId,
|
||||||
|
rowIndex: this.answers.RowIndex,
|
||||||
|
visitTaskId: this.visitTaskId,
|
||||||
|
trialId: this.trialId,
|
||||||
|
answerList: answers,
|
||||||
|
isDicomReading: true
|
||||||
|
}
|
||||||
|
const res = await submitTaskRowInfo(params, 11)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
// 保存成功!
|
||||||
|
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 2)
|
||||||
|
this.originalQuestionForm = { ...this.questionForm }
|
||||||
|
this.$set(this.questionForm, 'RowId', res.Result.RowId)
|
||||||
|
this.setQuestions()
|
||||||
|
this.$emit('close')
|
||||||
|
DicomEvent.$emit('getReportInfo', true)
|
||||||
|
DicomEvent.$emit('setMeasuredToolsPassive')
|
||||||
|
// await store.dispatch('reading/refreshMeasuredData', this.visitTaskId)
|
||||||
|
// DicomEvent.$emit('getMeasureData')
|
||||||
|
this.$emit('getReadingQuestionAndAnswer')
|
||||||
|
}
|
||||||
|
loading.close()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleClose() {
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
setState() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
// 是否要将是否可测量设置为否?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.measurement-form {
|
||||||
|
::v-deep .el-form-item__label {
|
||||||
|
color: #c3c3c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-input .el-input__inner {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #ddd;
|
||||||
|
border: 1px solid #5e5e5e;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item__content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-input.is-disabled .el-input__inner {
|
||||||
|
background-color: #646464a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-select.is-disabled .el-input__inner {
|
||||||
|
background-color: #646464a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-button--mini,
|
||||||
|
.el-button--mini.is-round {
|
||||||
|
padding: 7px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-input-group__append,
|
||||||
|
.el-input-group__prepend {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__content .el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-width1 {
|
||||||
|
width: calc(100% - 60px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-width2 {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,624 @@
|
||||||
|
<template>
|
||||||
|
<div class="measurement-wrapper">
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="basic-info">
|
||||||
|
<h3 v-if="isReadingShowSubjectInfo">
|
||||||
|
<span v-if="subjectCode">{{ subjectCode }} </span>
|
||||||
|
<span style="margin-left:5px;">{{ taskBlindName }}</span>
|
||||||
|
</h3>
|
||||||
|
<div v-if="readingTaskState < 2">
|
||||||
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')"
|
||||||
|
placement="bottom">
|
||||||
|
<i class="el-icon-refresh-left" @click="resetMeasuredData" />
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 非测量问题 -->
|
||||||
|
<div class="lesions">
|
||||||
|
<Questions ref="ecrf" :groupClassify="1" :question-form-change-state="questionFormChangeState"
|
||||||
|
:question-form-change-num="questionFormChangeNum" @handleReadingChart="handleReadingChart" />
|
||||||
|
</div>
|
||||||
|
<!-- 测量问题 -->
|
||||||
|
<template>
|
||||||
|
<div v-for="(qs, index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper">
|
||||||
|
<h4 v-if="qs.Type === 'group'" style="color: #ddd;padding: 5px 0px;margin: 0;">
|
||||||
|
{{ language === 'en' ? qs.GroupEnName : qs.GroupName }}
|
||||||
|
</h4>
|
||||||
|
<div class="lesion_list">
|
||||||
|
<div v-for="item in qs.Childrens" v-show="!(isBaseLineTask && item.LesionType === 2)" :key="item.Id">
|
||||||
|
<div v-if="item.Type === 'table'" class="flex-row" style="margin:3px 0;">
|
||||||
|
<div class="title">{{ item.QuestionName }}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="color: #ddd;text-align: left;padding: 5px 10px;border-bottom: 1px solid #5a5a5a; font-size: 15px;">
|
||||||
|
<el-row>
|
||||||
|
<!-- 分段 -->
|
||||||
|
<el-col :span="14">{{ $t('trials:MRIPDFF:label:col1') }}</el-col>
|
||||||
|
<!-- 是否可测量 -->
|
||||||
|
<!-- <el-col :span="7">{{$t('trials:MRIPDFF:label:col2')}}</el-col> -->
|
||||||
|
<!-- 平均值 -->
|
||||||
|
<el-col :span="7">{{ $t('trials:MRIPDFF:label:col3') }}</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-collapse v-if="item.Type === 'table' && item.TableQuestions" v-model="activeName" accordion
|
||||||
|
@change="handleCollapseChange">
|
||||||
|
<el-collapse-item v-for="(q, i) in item.TableQuestions.Answers" :key="`${item.Id}_${q.RowIndex}`"
|
||||||
|
:name="`${item.Id}_${q.RowIndex}`"
|
||||||
|
@contextmenu.prevent.native="collapseRightClick($event, q, item.Id, q.RowIndex)">
|
||||||
|
<template slot="title">
|
||||||
|
<div style="width:300px;position: relative;"
|
||||||
|
:style="{ color: (activeName === item.Id + q.RowIndex ? '#ffeb3b' : '#fff') }">
|
||||||
|
|
||||||
|
{{ getLesionName(item.TableQuestions.Questions, q) }}
|
||||||
|
<!-- 未保存 -->
|
||||||
|
<el-tooltip
|
||||||
|
v-if="readingTaskState < 2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) === 0"
|
||||||
|
class="item" effect="dark" :content="$t('trials:reading:button:unsaved')" placement="bottom">
|
||||||
|
<i class="el-icon-warning" style="color:red" />
|
||||||
|
</el-tooltip>
|
||||||
|
<!-- 信息不完整 -->
|
||||||
|
<el-tooltip
|
||||||
|
v-if="readingTaskState < 2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) === 1"
|
||||||
|
class="item" effect="dark" :content="$t('trials:reading:button:incompleteInfor')"
|
||||||
|
placement="bottom">
|
||||||
|
<i class="el-icon-warning" style="color:#ff9800" />
|
||||||
|
</el-tooltip>
|
||||||
|
<div style="position: absolute;right: 0px;top: 2px;">
|
||||||
|
<!-- white-space: nowrap;overflow: hidden;text-overflow: ellipsis; -->
|
||||||
|
<div style="font-size: 13px;width:110px;height: 30px;">
|
||||||
|
<!-- <div style="display: inline-block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width:95px">
|
||||||
|
{{ $fd('ReadingYesOrNo', parseInt(item.TableQuestions.Answers[i].isMeasurable)) }}
|
||||||
|
</div> -->
|
||||||
|
<div
|
||||||
|
style="display: inline-block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width:50px">
|
||||||
|
{{ isNaN(parseFloat(item.TableQuestions.Answers[i].mean)) ?
|
||||||
|
item.TableQuestions.Answers[i].mean : `${item.TableQuestions.Answers[i].mean}%` }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<QuestionForm :ref="`${item.Id}_${q.RowIndex}`" :questions="item.TableQuestions.Questions"
|
||||||
|
:answers="item.TableQuestions.Answers[i]" :lesion-type="item.LesionType"
|
||||||
|
:order-mark="item.OrderMark" :table-questions="tableQuestions" :row-index="String(q.RowIndex)"
|
||||||
|
:question-name="item.QuestionName" :parent-qs-id="item.Id" :visit-task-id="visitTaskId"
|
||||||
|
:is-current-task="isCurrentTask" :reading-task-state="readingTaskState"
|
||||||
|
:is-base-line-task="isBaseLineTask" @getReadingQuestionAndAnswer="getReadingQuestionAndAnswer"
|
||||||
|
@resetQuestions="resetQuestions" @close="close" @handleReadingChart="handleReadingChart" />
|
||||||
|
</el-collapse-item>
|
||||||
|
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { resetReadingTask } from '@/api/reading'
|
||||||
|
import DicomEvent from './../DicomEvent'
|
||||||
|
import store from '@/store'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
import Questions from './../Questions'
|
||||||
|
import QuestionForm from './QuestionForm'
|
||||||
|
export default {
|
||||||
|
name: 'MeasurementList',
|
||||||
|
components: {
|
||||||
|
Questions,
|
||||||
|
QuestionForm
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
isShow: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isReadingShowSubjectInfo: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
questionFormChangeState: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
questionFormChangeNum: {
|
||||||
|
type: Number,
|
||||||
|
default() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
questions: [],
|
||||||
|
activeName: '',
|
||||||
|
activeItem: {
|
||||||
|
activeRowIndex: null,
|
||||||
|
activeCollapseId: null
|
||||||
|
},
|
||||||
|
visitTaskId: '',
|
||||||
|
isCurrentTask: false,
|
||||||
|
loading: false,
|
||||||
|
unSaveTargets: [],
|
||||||
|
temporaryLesions: [],
|
||||||
|
readingTaskState: 2,
|
||||||
|
isBaseLineTask: false,
|
||||||
|
taskBlindName: '',
|
||||||
|
tableQuestions: [],
|
||||||
|
isFirstRender: false,
|
||||||
|
CriterionType: null,
|
||||||
|
subjectCode: '',
|
||||||
|
liverSegmentId: '',
|
||||||
|
liverSegmentDicCode: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['visitTaskList', 'language', 'lastCanvasTaskId', 'currentReadingTaskState'])
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
lastCanvasTaskId: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val) {
|
||||||
|
this.initList()
|
||||||
|
}
|
||||||
|
console.log('lastCanvasTaskId', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentReadingTaskState: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val) {
|
||||||
|
this.readingTaskState = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// this.subjectCode = this.$router.currentRoute.query.subjectCode
|
||||||
|
this.subjectCode = localStorage.getItem('subjectCode')
|
||||||
|
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||||
|
DicomEvent.$on('setCollapseActive', measureData => {
|
||||||
|
this.setCollapseActive(measureData)
|
||||||
|
console.log('setCollapseActive')
|
||||||
|
})
|
||||||
|
DicomEvent.$on('getAllUnSaveLesions', (callback) => {
|
||||||
|
var list = this.getAllUnSaveLesions()
|
||||||
|
callback(list)
|
||||||
|
console.log('getAllUnSaveLesions')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
DicomEvent.$off('setCollapseActive')
|
||||||
|
DicomEvent.$off('getUnSaveTarget')
|
||||||
|
DicomEvent.$off('getAllUnSaveLesions')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleReadingChart(e) {
|
||||||
|
this.$emit('handleReadingChart', e)
|
||||||
|
},
|
||||||
|
async initList() {
|
||||||
|
var i = this.visitTaskList.findIndex(i => i.VisitTaskId === this.lastCanvasTaskId)
|
||||||
|
if (i > -1) {
|
||||||
|
this.visitTaskId = this.visitTaskList[i].VisitTaskId
|
||||||
|
this.taskBlindName = this.visitTaskList[i].TaskBlindName
|
||||||
|
this.readingTaskState = this.visitTaskList[i].ReadingTaskState
|
||||||
|
this.isBaseLineTask = this.visitTaskList[i].IsBaseLineTask
|
||||||
|
this.isCurrentTask = this.visitTaskList[i].IsCurrentTask
|
||||||
|
this.activeName = ''
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
if (!this.visitTaskList[i].IsInit) {
|
||||||
|
var loading = this.$loading({ fullscreen: true })
|
||||||
|
var triald = this.trialId = this.$router.currentRoute.query.trialId
|
||||||
|
if (!this.visitTaskList[i].measureDataInit) {
|
||||||
|
await store.dispatch('reading/getMeasuredData', this.visitTaskList[i].VisitTaskId)
|
||||||
|
}
|
||||||
|
if (!this.visitTaskList[i].studyListInit) {
|
||||||
|
await store.dispatch('reading/getStudyInfo', { trialId: triald, subjectVisitId: this.visitTaskList[i].VisitId, visitTaskId: this.visitTaskList[i].VisitTaskId, taskBlindName: this.visitTaskList[i].TaskBlindName })
|
||||||
|
}
|
||||||
|
if (!this.visitTaskList[i].readingQuestionsInit) {
|
||||||
|
await store.dispatch('reading/getReadingQuestionAndAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
|
||||||
|
}
|
||||||
|
if (!this.visitTaskList[i].questionsInit) {
|
||||||
|
await store.dispatch('reading/getDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
|
||||||
|
}
|
||||||
|
|
||||||
|
await store.dispatch('reading/setStatus', { visitTaskId: this.visitTaskList[i].VisitTaskId })
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
this.questions = this.visitTaskList[i].ReadingQuestions
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs['ecrf'].getQuestions(this.visitTaskId)
|
||||||
|
this.getTableQuestions()
|
||||||
|
this.tableQuestions.forEach(item => {
|
||||||
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
|
this.$refs[refName] && this.$refs[refName][0].initForm()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async resetQuestions(obj) {
|
||||||
|
this.setQuestions(this.questions, obj)
|
||||||
|
await store.dispatch('reading/setReadingQuestionAndAnswer', { questions: this.questions, visitTaskId: this.visitTaskId })
|
||||||
|
|
||||||
|
this.getTableQuestions()
|
||||||
|
},
|
||||||
|
setQuestions(questions, obj) {
|
||||||
|
questions.forEach(item => {
|
||||||
|
if (item.Type === 'table' && item.Id === obj.questionId) {
|
||||||
|
var idx = item.TableQuestions.Answers.findIndex(i => i.RowIndex === obj.rowIndex)
|
||||||
|
item.TableQuestions.Answers[idx].isMeasurable = obj.isMeasurable
|
||||||
|
item.TableQuestions.Answers[idx].mean = obj.mean
|
||||||
|
item.TableQuestions.Answers[idx].saveTypeEnum = obj.saveTypeEnum
|
||||||
|
|
||||||
|
for (const i in obj.anwsers) {
|
||||||
|
if (i === 'MeasureData' && obj.anwsers[i]) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
item.TableQuestions.Answers[idx][i] = String(obj.anwsers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.setQuestions(item.Childrens, obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getQuestions(questions) {
|
||||||
|
questions.forEach(item => {
|
||||||
|
if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
|
||||||
|
item.TableQuestions.Answers.forEach(answerObj => {
|
||||||
|
let isMeasurable = this.getQuestionAnswer(item.TableQuestions.Questions, 1105, answerObj)
|
||||||
|
this.$set(answerObj, 'isMeasurable', isMeasurable)
|
||||||
|
this.$set(answerObj, 'mean', this.getQuestionAnswer(item.TableQuestions.Questions, 1104, answerObj))
|
||||||
|
if (answerObj.RowId) {
|
||||||
|
this.$set(answerObj, 'saveTypeEnum', isNaN(parseInt(isMeasurable)) ? 1 : 2)
|
||||||
|
} else {
|
||||||
|
this.$set(answerObj, 'saveTypeEnum', 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.getQuestions(item.Childrens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return questions
|
||||||
|
},
|
||||||
|
getTableQuestions() {
|
||||||
|
this.tableQuestions = []
|
||||||
|
this.questions.map(item => {
|
||||||
|
if (item.Type === 'table') {
|
||||||
|
this.tableQuestions.push(item)
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.getTableQuestionsChild(item.Childrens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getTableQuestionsChild(obj) {
|
||||||
|
obj.map(item => {
|
||||||
|
if (item.Type === 'table') {
|
||||||
|
this.tableQuestions.push(item)
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.getTableQuestionsChild(item.Childrens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshReadingQuestionAndAnswer(type) {
|
||||||
|
if (type === 0) {
|
||||||
|
// 删除
|
||||||
|
this.activeName = ''
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getReadingQuestionAndAnswer(this.visitTaskId)
|
||||||
|
},
|
||||||
|
getReadingQuestionAndAnswer(showLoading = true) {
|
||||||
|
return new Promise(async resolve => {
|
||||||
|
try {
|
||||||
|
let loading = null
|
||||||
|
if (showLoading) {
|
||||||
|
loading = this.$loading({ fullscreen: true })
|
||||||
|
}
|
||||||
|
await store.dispatch('reading/refreshReadingQuestionAndAnswer', { trialId: this.$router.currentRoute.query.trialId, visitTaskId: this.visitTaskId }).then(() => {
|
||||||
|
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||||
|
if (idx > -1) {
|
||||||
|
if (this.visitTaskList[idx].ReadingQuestions.length > 0) {
|
||||||
|
this.questions = this.visitTaskList[idx].ReadingQuestions
|
||||||
|
}
|
||||||
|
this.readingTaskState = this.visitTaskList[idx].ReadingTaskState
|
||||||
|
this.isBaseLineTask = this.visitTaskList[idx].IsBaseLineTask
|
||||||
|
this.isCurrentTask = this.visitTaskList[idx].IsCurrentTask
|
||||||
|
}
|
||||||
|
this.getTableQuestions()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.tableQuestions.forEach(item => {
|
||||||
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
|
this.$refs[refName] && this.$refs[refName][0].initForm()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await store.dispatch('reading/refreshMeasuredData', this.visitTaskId)
|
||||||
|
DicomEvent.$emit('getMeasureData')
|
||||||
|
|
||||||
|
loading ? loading.close() : ''
|
||||||
|
resolve()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
loading ? loading.close() : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getQuestionAnswer(questions, questionMark, answers) {
|
||||||
|
var idx = questions.findIndex(i => i.QuestionMark === questionMark)
|
||||||
|
if (idx > -1) {
|
||||||
|
var questionId = questions[idx].Id
|
||||||
|
return answers[questionId]
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isCanActiveTool(toolName) {
|
||||||
|
return { isCanActiveTool: true, reason: '' }
|
||||||
|
},
|
||||||
|
|
||||||
|
checkToolCanActive(toolName) {
|
||||||
|
return { isCanActiveTool: true, reason: '' }
|
||||||
|
},
|
||||||
|
|
||||||
|
getLesionName(questions, q) {
|
||||||
|
let liverSegmentStr = ''
|
||||||
|
if (!this.liverSegmentId) {
|
||||||
|
let i = questions.findIndex(i => i.QuestionMark === 1106)
|
||||||
|
if (i === -1) return
|
||||||
|
this.liverSegmentId = questions[i].Id
|
||||||
|
this.liverSegmentDicCode = questions[i].DictionaryCode
|
||||||
|
}
|
||||||
|
if (q && q[this.liverSegmentId]) {
|
||||||
|
liverSegmentStr = this.$fd(this.liverSegmentDicCode, parseInt(q[this.liverSegmentId]))
|
||||||
|
}
|
||||||
|
return liverSegmentStr
|
||||||
|
},
|
||||||
|
handleCollapseChange(val) {
|
||||||
|
if (this.activeName) {
|
||||||
|
var arr = this.activeName.split('_')
|
||||||
|
this.activeItem.activeRowIndex = arr[1]
|
||||||
|
this.activeItem.activeCollapseId = arr[0]
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
if (this.$refs[refName][0].questionForm.IsDicomReading !== false) {
|
||||||
|
var markTool = this.$refs[refName][0].currentMarkTool
|
||||||
|
var readingTaskState = this.readingTaskState
|
||||||
|
var isMarked = !!this.$refs[refName][0].questionForm.MeasureData
|
||||||
|
DicomEvent.$emit('imageLocation', { questionId: this.activeItem.activeCollapseId, rowIndex: this.activeItem.activeRowIndex, visitTaskId: this.visitTaskId, lesionName: this.$refs[refName][0].lesionMark, lesionType: this.$refs[refName][0].lesionType, markTool, readingTaskState, isMarked })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collapseRightClick(e, obj, activeCollapseId, activeRowIndex) {
|
||||||
|
if (obj.IsDicomReading !== false) {
|
||||||
|
const refName = `${activeCollapseId}_${activeRowIndex}`
|
||||||
|
DicomEvent.$emit('imageLocation', { questionId: activeCollapseId, rowIndex: activeRowIndex, visitTaskId: this.visitTaskId, lesionName: this.$refs[refName][0].lesionMark, lesionType: this.$refs[refName][0].lesionType })
|
||||||
|
}
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
setCollapseActive(measureData) {
|
||||||
|
if (measureData) {
|
||||||
|
if (this.activeItem.activeRowIndex === measureData.RowIndex && this.activeItem.activeCollapseId === measureData.QuestionId) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
this.activeItem.activeCollapseId = measureData.QuestionId
|
||||||
|
this.activeItem.activeRowIndex = measureData.RowIndex
|
||||||
|
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifyMeasuredData(measureObj) {
|
||||||
|
console.log('modifyMeasuredData')
|
||||||
|
if (measureObj.questionInfo) {
|
||||||
|
this.activeItem.activeCollapseId = measureObj.questionInfo.QuestionId
|
||||||
|
this.activeItem.activeRowIndex = String(measureObj.questionInfo.RowIndex)
|
||||||
|
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
this.$refs[refName][0].setMeasureData(measureObj.measureData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 设置测量数据
|
||||||
|
setMeasuredData(measureData) {
|
||||||
|
console.log('setMeasuredData')
|
||||||
|
if (this.activeItem.activeCollapseId) {
|
||||||
|
// 判断是否存在测量数据
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
if (!this.$refs[refName][0].questionForm.MeasureData || (this.$refs[refName][0].questionForm && this.$refs[refName][0].questionForm.MeasureData && measureData.data.uuid === this.$refs[refName][0].questionForm.MeasureData.data.uuid)) {
|
||||||
|
this.$refs[refName][0].setMeasureData(measureData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async close(questionsObj) {
|
||||||
|
if (questionsObj) {
|
||||||
|
this.getReadingQuestionAndAnswer(questionsObj.visitTaskId)
|
||||||
|
}
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
this.activeName = ''
|
||||||
|
},
|
||||||
|
getECRFQuestions(obj) {
|
||||||
|
this.$refs['ecrf'].getQuestions(obj.visitTaskId)
|
||||||
|
},
|
||||||
|
async resetMeasuredData() {
|
||||||
|
const confirm = await this.$confirm(
|
||||||
|
this.$t('trials:dicomReading:message:confirmReset1'),
|
||||||
|
this.$t('trials:dicomReading:message:confirmReset2'),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
distinguishCancelAndClose: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (confirm !== 'confirm') return
|
||||||
|
const loading = this.$loading({ fullscreen: true })
|
||||||
|
try {
|
||||||
|
const res = await resetReadingTask({ visitTaskId: this.visitTaskId })
|
||||||
|
this.loading = false
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
// 刷新标注、表单、报告页信息
|
||||||
|
this.activeName = ''
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
await this.getReadingQuestionAndAnswer(this.visitTaskId)
|
||||||
|
const triald = this.$router.currentRoute.query.trialId
|
||||||
|
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskId })
|
||||||
|
this.$refs['ecrf'].getQuestions(this.visitTaskId, true)
|
||||||
|
DicomEvent.$emit('getMeasureData')
|
||||||
|
DicomEvent.$emit('getReportInfo', true)
|
||||||
|
DicomEvent.$emit('refreshStudyListMeasureData')
|
||||||
|
}
|
||||||
|
loading.close()
|
||||||
|
} catch (e) {
|
||||||
|
loading.close()
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAllUnSaveLesions() {
|
||||||
|
var arr = []
|
||||||
|
this.tableQuestions.map(item => {
|
||||||
|
if (item.TableQuestions && item.TableQuestions.Answers) {
|
||||||
|
item.TableQuestions.Answers.map(t => {
|
||||||
|
const refName = `${item.Id}_${t.RowIndex}`
|
||||||
|
if (this.$refs[refName] && this.$refs[refName][0] && this.$refs[refName][0].questionForm.saveTypeEnum !== 2) {
|
||||||
|
var lessionName = this.$refs[refName][0].liverSeg
|
||||||
|
arr.push({ lessionName: lessionName, rowIndex: t.RowIndex, questionId: item.Id })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.measurement-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
// overflow: hidden;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.basic-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #ddd;
|
||||||
|
padding: 5px 0px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
padding: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 15px;
|
||||||
|
border: 1px solid #938b8b;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon:hover {
|
||||||
|
background-color: #607d8b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #424242;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesion_list {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse {
|
||||||
|
border-bottom: none;
|
||||||
|
border-top: none;
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item {
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #ddd;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__header {
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #ddd;
|
||||||
|
border-bottom-color: #5a5a5a;
|
||||||
|
padding-left: 5px;
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__wrap {
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__content {
|
||||||
|
width: 260px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
// border: 1px solid #ffeb3b;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
z-index: 1;
|
||||||
|
color: #ddd;
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -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 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -512,7 +512,8 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit
|
console.log(this.allowAddOrEdit,this.isPatientFormAllowEdit )
|
||||||
|
this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit
|
||||||
this.getClinicalData()
|
this.getClinicalData()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -921,7 +921,7 @@
|
||||||
</div>
|
</div>
|
||||||
<!--petct临床数据预览-->
|
<!--petct临床数据预览-->
|
||||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" :isPatientFormAllowEdit="isAuditToEdit" :isAudit="isAuditToEdit" @close="petVisible = false"/>
|
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" :isPatientFormAllowEdit="!isAudit || SecondReviewState > 0 || isAuditToEdit" :isAudit="isAuditToEdit" @close="petVisible = false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue