wangxiaoshuang 2026-05-07 15:20:18 +08:00
commit a7337a347b
12 changed files with 1963 additions and 28 deletions

View File

@ -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()

View File

@ -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]

View File

@ -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)

View File

@ -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 01访/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)
// base64ascii
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>

View File

@ -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>

View File

@ -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 },
]
}

View File

@ -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
})
}
/**
*
*

View File

@ -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)

View File

@ -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')
},

View File

@ -512,7 +512,7 @@ export default {
}
},
mounted() {
this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit
this.isPatientFormCanEdit = this.allowAddOrEdit || this.isPatientFormAllowEdit
this.getClinicalData()
},
methods: {

View File

@ -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>

View File

@ -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>