Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
commit
a7337a347b
|
|
@ -496,7 +496,7 @@ export default {
|
|||
this.colormapsList = cornerstone.colors.getColormapsList()
|
||||
this.currentDicomCanvas = this.$refs['dicomCanvas0']
|
||||
this.type = this.$route.query.type
|
||||
this.isEdit = parseInt(this.$route.query.showDelete)
|
||||
this.isEdit = parseInt(this.$route.query.showDelete) || parseInt(this.$route.query.showEdit)
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearPTClinicalDataCache()
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ import BidirectionalTool from '@/views/trials/trials-panel/reading/dicoms/tools/
|
|||
import ArrowAnnotateTool from '@/views/trials/trials-panel/reading/dicoms/tools/ArrowAnnotate/ArrowAnnotateTool'
|
||||
import RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/RectangleRoiTool'
|
||||
import ProbeTool from '@/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool'
|
||||
import FixedCircleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool'
|
||||
// import OrientationMarkersTool from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/OrientationMarkersTool'
|
||||
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
|
||||
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
||||
|
|
@ -260,7 +261,7 @@ export default {
|
|||
series: '',
|
||||
ToolStateManager: null,
|
||||
renderedMeasured: [],
|
||||
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe'],
|
||||
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe', 'FixedCircleRoi'],
|
||||
measureData: [],
|
||||
selectedLesion: null,
|
||||
activeTool: 0, // 0:enable 1:passive 2:active
|
||||
|
|
@ -584,6 +585,13 @@ export default {
|
|||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}
|
||||
} else if (this.CriterionType === 22 && this.activeToolName === 'Probe' && this.readingTaskState < 2) {
|
||||
if (!(e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME1' || e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME2')) {
|
||||
this.$alert(this.$t('trials:MRIPDFF:message:message5'))
|
||||
e.stopImmediatePropagation()
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
},
|
||||
pointNearTool(e) {
|
||||
|
|
@ -593,7 +601,9 @@ export default {
|
|||
var toolType = this.measuredTools[m]
|
||||
const toolState = ToolStateManager.getImageIdToolState(image.imageId, toolType)
|
||||
if (toolState) {
|
||||
var toolObj = new cornerstoneTools[`${toolType}Tool`]()
|
||||
const toolClass = this.getToolClassByType(toolType)
|
||||
if (!toolClass) continue
|
||||
var toolObj = new toolClass()
|
||||
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||
if (i > -1 && this.disabledMarks.length > 0 && this.disabledMarks.indexOf(toolState.data[i].remark) > -1) {
|
||||
return true
|
||||
|
|
@ -783,7 +793,9 @@ export default {
|
|||
var toolType = this.measuredTools[m]
|
||||
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
||||
if (toolState) {
|
||||
var toolObj = new cornerstoneTools[`${toolType}Tool`]()
|
||||
const toolClass = this.getToolClassByType(toolType)
|
||||
if (!toolClass) continue
|
||||
var toolObj = new toolClass()
|
||||
|
||||
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||
if (i > -1) {
|
||||
|
|
@ -1019,7 +1031,9 @@ export default {
|
|||
var toolType = this.measuredTools[t]
|
||||
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
||||
if (!toolState) continue
|
||||
var toolObj = new cornerstoneTools[`${toolType}Tool`]()
|
||||
const toolClass = this.getToolClassByType(toolType)
|
||||
if (!toolClass) continue
|
||||
var toolObj = new toolClass()
|
||||
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||
if (i > -1) {
|
||||
var idx = this.measureData.findIndex(item => item.MeasureData && item.MeasureData.data && item.MeasureData.data.uuid === toolState.data[i].uuid)
|
||||
|
|
@ -1046,7 +1060,7 @@ export default {
|
|||
measureData.wc = Math.round(viewport.voi.windowCenter)
|
||||
measureData.data.active = false
|
||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||
if (criterionType === 21) {
|
||||
if (criterionType === 21 || criterionType === 22) {
|
||||
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
||||
}
|
||||
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
||||
|
|
@ -1057,6 +1071,15 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
getToolClassByType(toolType) {
|
||||
if (toolType === 'Length') return LengthTool
|
||||
if (toolType === 'Bidirectional') return BidirectionalTool
|
||||
if (toolType === 'ArrowAnnotate') return ArrowAnnotateTool
|
||||
if (toolType === 'RectangleRoi') return RectangleRoiTool
|
||||
if (toolType === 'Probe') return ProbeTool
|
||||
if (toolType === 'FixedCircleRoi') return FixedCircleRoiTool
|
||||
return cornerstoneTools[`${toolType}Tool`]
|
||||
},
|
||||
loadImageStack(dicomSeries) {
|
||||
return new Promise(resolve => {
|
||||
this.isInitWwwc = true
|
||||
|
|
@ -1169,8 +1192,22 @@ export default {
|
|||
// Add the tool
|
||||
const toolName = toolBtn.getAttribute('data-tool')
|
||||
const apiTool = cornerstoneTools[`${toolName}Tool`]
|
||||
if (apiTool) {
|
||||
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, apiTool)
|
||||
let toolClass = apiTool
|
||||
if (toolName === 'Length') {
|
||||
toolClass = LengthTool
|
||||
} else if (toolName === 'Bidirectional') {
|
||||
toolClass = BidirectionalTool
|
||||
} else if (toolName === 'ArrowAnnotate') {
|
||||
toolClass = ArrowAnnotateTool
|
||||
} else if (toolName === 'RectangleRoi') {
|
||||
toolClass = RectangleRoiTool
|
||||
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) {
|
||||
toolClass = ProbeTool
|
||||
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 22)) {
|
||||
toolClass = FixedCircleRoiTool
|
||||
}
|
||||
if (toolClass) {
|
||||
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, toolClass)
|
||||
|
||||
if (!toolAlreadyAddedToElement) {
|
||||
if (toolName === 'Length') {
|
||||
|
|
@ -1183,8 +1220,10 @@ export default {
|
|||
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
||||
} else if (toolName === 'RectangleRoi') {
|
||||
cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
||||
} else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 21) {
|
||||
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) {
|
||||
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
||||
} else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 22) {
|
||||
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, unit: 'mm', handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
||||
} else {
|
||||
cornerstoneTools.addToolForElement(element, apiTool)
|
||||
}
|
||||
|
|
@ -1528,7 +1567,7 @@ export default {
|
|||
measureData.wc = Math.round(viewport.voi.windowCenter)
|
||||
measureData.data.active = false
|
||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||
if (criterionType === 21) {
|
||||
if (criterionType === 21 || criterionType === 22) {
|
||||
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
||||
}
|
||||
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
||||
|
|
@ -1982,7 +2021,8 @@ export default {
|
|||
'CobbAngle',
|
||||
'Angle',
|
||||
'Bidirectional',
|
||||
'FreehandRoi'
|
||||
'FreehandRoi',
|
||||
'FixedCircleRoi'
|
||||
]
|
||||
for (let i = 0; i < toolROITypes.length; i++) {
|
||||
const toolROIType = toolROITypes[i]
|
||||
|
|
|
|||
|
|
@ -492,6 +492,10 @@
|
|||
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
||||
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
||||
@handleReadingChart="handleReadingChart" />
|
||||
<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">
|
||||
Developing...
|
||||
</h2>
|
||||
|
|
@ -689,6 +693,7 @@ import LuganoWithoutPETQuestionList from './LuganoWithoutPET/QuestionList'
|
|||
import IVUSList from './IVUS/QuestionList'
|
||||
import OCTList from './OCT/QuestionList'
|
||||
import MRIPDFF from './MRIPDFF/QuestionList'
|
||||
import MRIPDFFAdvance from './MRIPDFFAdvance/QuestionList'
|
||||
import CustomWwwcForm from './CustomWwwcForm'
|
||||
import Manuals from './Manuals'
|
||||
import Hotkeys from './Hotkeys'
|
||||
|
|
@ -725,6 +730,7 @@ export default {
|
|||
IVUSList,
|
||||
OCTList,
|
||||
MRIPDFF,
|
||||
MRIPDFFAdvance,
|
||||
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
||||
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
||||
SignForm
|
||||
|
|
@ -1012,6 +1018,10 @@ export default {
|
|||
this.measuredTools = [{
|
||||
toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: ''
|
||||
}]
|
||||
} else if (this.CriterionType === 22) {
|
||||
this.measuredTools = [{
|
||||
toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: ''
|
||||
}]
|
||||
}
|
||||
this.rotateList[0] = '1'
|
||||
this.colorList[0] = ''
|
||||
|
|
@ -1126,7 +1136,12 @@ export default {
|
|||
DicomEvent.$on('addAnnotation', async obj => {
|
||||
this.tmpData = Object.assign({}, obj.question)
|
||||
// await this.imageLocation(obj.locateInfo)
|
||||
this.setToolActive('Probe', true, null, 'tableQuestion')
|
||||
if (this.CriterionType === 21) {
|
||||
this.setToolActive('Probe', true, null, 'tableQuestion')
|
||||
} else if (this.CriterionType === 22) {
|
||||
this.setToolActive('Probe', true, null, 'tableQuestion')
|
||||
}
|
||||
|
||||
})
|
||||
window.addEventListener('beforeunload', () => {
|
||||
if (this.petctWindow) {
|
||||
|
|
@ -2160,7 +2175,7 @@ export default {
|
|||
},
|
||||
// 添加标记
|
||||
setMeasureData(data) {
|
||||
if (this.CriterionType === 21) {
|
||||
if (this.CriterionType === 21 || this.CriterionType === 22) {
|
||||
if (this.tmpData) {
|
||||
data.tableQuestionId = this.tmpData.Id
|
||||
data.tableQuestionMark = this.tmpData.QuestionMark
|
||||
|
|
@ -2174,7 +2189,7 @@ export default {
|
|||
},
|
||||
// 修改标记
|
||||
modifyMeasureData(data) {
|
||||
if (this.CriterionType === 21 && data.measureData.tableQuestionId) {
|
||||
if ((this.CriterionType === 21 || this.CriterionType === 22) && data.measureData.tableQuestionId) {
|
||||
this.$refs['measurementList'].modifyMeasuredData(data)
|
||||
} else {
|
||||
this.$refs['measurementList'].modifyMeasuredData(data)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,862 @@
|
|||
<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 => {
|
||||
if (!measureData || (measureData && measureData.tableQuestionId !== this.activeQuestionId)) {
|
||||
resolve()
|
||||
}
|
||||
var data = {}
|
||||
// 创建标记
|
||||
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,622 @@
|
|||
<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) {
|
||||
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) {
|
||||
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 },
|
||||
]
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import * as cornerstoneTools from 'cornerstone-tools'
|
||||
const EVENTS = cornerstoneTools.EVENTS
|
||||
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
|
||||
const external = cornerstoneTools.external
|
||||
// State
|
||||
const getToolState = cornerstoneTools.getToolState
|
||||
|
|
@ -87,7 +89,7 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool {
|
|||
|
||||
return {
|
||||
visible: true,
|
||||
active: true,
|
||||
active: false,
|
||||
color: undefined,
|
||||
invalidated: true,
|
||||
handles: {
|
||||
|
|
@ -100,8 +102,8 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool {
|
|||
end: {
|
||||
x: eventData.currentPoints.image.x,
|
||||
y: eventData.currentPoints.image.y,
|
||||
highlight: true,
|
||||
active: true,
|
||||
highlight: false,
|
||||
active: false,
|
||||
radius: 0
|
||||
},
|
||||
// textBox: {
|
||||
|
|
@ -125,6 +127,41 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool {
|
|||
};
|
||||
}
|
||||
|
||||
addNewMeasurement(evt, interactionType) {
|
||||
const eventData = evt.detail
|
||||
if (!eventData || !eventData.currentPoints || !eventData.currentPoints.image) {
|
||||
return
|
||||
}
|
||||
|
||||
const { element, image } = eventData
|
||||
const measurementData = this.createNewMeasurement(eventData)
|
||||
|
||||
if (!measurementData) {
|
||||
return
|
||||
}
|
||||
|
||||
// Click-to-place and finish immediately; avoid default drag listeners.
|
||||
measurementData.active = false
|
||||
if (measurementData.handles && measurementData.handles.end) {
|
||||
measurementData.handles.end.active = false
|
||||
measurementData.handles.end.highlight = false
|
||||
}
|
||||
|
||||
cornerstoneTools.addToolState(element, this.name, measurementData)
|
||||
|
||||
if (!measurementData.cachedStats && image) {
|
||||
this.updateCachedStats(image, element, measurementData)
|
||||
}
|
||||
|
||||
external.cornerstone.updateImage(element)
|
||||
|
||||
triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
|
||||
toolName: this.name,
|
||||
element,
|
||||
measurementData
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
<!-- 上传时间 -->
|
||||
<el-table-column prop="UploadedTime" :label="$t('trials:uploadedDicoms:table:uploadedTime')" sortable
|
||||
min-width="120" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common:action:action')" min-width="100">
|
||||
<el-table-column :label="$t('common:action:action')" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<!-- 预览 -->
|
||||
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
|
||||
|
|
@ -150,8 +150,8 @@
|
|||
</div>
|
||||
</el-dialog>
|
||||
<!--pet-ct临床数据上传-->
|
||||
<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" />
|
||||
<el-dialog v-if="petVisible" :close-on-click-modal="false" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="(data.SubmitState * 1 < 2 || (data.SubmitState === 2 && data.IsQCConfirmedReupload)) && hasPermi(['trials:trials-panel:visit:crc-upload:edit'])" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -309,8 +309,14 @@ export default {
|
|||
// 预览影像
|
||||
handleViewStudy(row) {
|
||||
var token = getToken()
|
||||
let path = ''
|
||||
if (this.hasPermi(['trials:trials-panel:visit:crc-upload:edit'])) {
|
||||
path = `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study&showEdit=${(this.data.SubmitState * 1 < 2 || (this.data.SubmitState === 2 && this.data.IsQCConfirmedReupload)) ? 1 : 0}`
|
||||
} else {
|
||||
path = `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study`
|
||||
}
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study`,
|
||||
path: path
|
||||
})
|
||||
var newWindow = window.open(routeData.href, '_blank')
|
||||
this.$emit('setOpenWindow', newWindow)
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@
|
|||
<DicomPreview :uid="uid" :studyList="uploadQueues" />
|
||||
</el-dialog>
|
||||
<!--pet-ct临床数据上传-->
|
||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||
<el-dialog v-if="petVisible" :show-close="true" :close-on-click-modal="false" :visible.sync="petVisible" append-to-body>
|
||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="studyData" :allow-add-or-edit="true"
|
||||
@getStudyInfo="getStudyInfo" />
|
||||
</el-dialog>
|
||||
|
|
@ -791,8 +791,14 @@ export default {
|
|||
// 预览单个检查影像
|
||||
handleViewStudy(row) {
|
||||
var token = getToken()
|
||||
let path = ''
|
||||
if (this.hasPermi(['trials:trials-panel:visit:crc-upload:edit'])) {
|
||||
path = `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study&showEdit=${!(!this.isAfresh && this.data.SubmitState === 2 && this.data.SubmitTime) ? 1 : 0}`
|
||||
} else {
|
||||
path = `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study`
|
||||
}
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study`,
|
||||
path: path,
|
||||
})
|
||||
window.open(routeData.href, '_blank')
|
||||
},
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit
|
||||
this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit
|
||||
this.getClinicalData()
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
<!-- 上传时间 -->
|
||||
<el-table-column prop="UploadedTime" :label="$t('trials:audit:table:studyUploadTime')" min-width="80"
|
||||
show-overflow-tooltip sortable />
|
||||
<el-table-column :label="$t('common:action:action')" min-width="100" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" min-width="100">
|
||||
<template slot-scope="scope">
|
||||
<!-- 预览 -->
|
||||
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
</el-table-column>
|
||||
</el-table>
|
||||
<!--pet-ct临床数据预览-->
|
||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||
<el-dialog v-if="petVisible" :close-on-click-modal="false" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -920,8 +920,8 @@
|
|||
<!-- </el-button>-->
|
||||
</div>
|
||||
<!--petct临床数据预览-->
|
||||
<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"/>
|
||||
<el-dialog v-if="petVisible" :close-on-click-modal="false" :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="!isAudit || SecondReviewState > 0 || isAuditToEdit" :isAudit="isAuditToEdit" @close="petVisible = false"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue