自定义标准阅片交互更改

main
caiyiling 2025-06-06 17:25:23 +08:00
parent 8d5dfd0258
commit f98ea18205
6 changed files with 321 additions and 246 deletions

View File

@ -596,6 +596,8 @@ const {
// RectangleROITool,
PlanarFreehandROITool,
CircleROITool,
AngleTool,
CobbAngleTool,
EraserTool,
MIPJumpToClickTool,
VolumeRotateTool,
@ -1136,6 +1138,8 @@ export default {
cornerstoneTools.addTool(BidirectionalTool)
cornerstoneTools.addTool(ScaleOverlayTool)
cornerstoneTools.addTool(CircleROITool)
cornerstoneTools.addTool(AngleTool)
cornerstoneTools.addTool(CobbAngleTool)
cornerstoneTools.addTool(MIPJumpToClickTool)
cornerstoneTools.addTool(VolumeRotateTool)
@ -1183,6 +1187,12 @@ export default {
toolGroup.addTool(CircleROITool.toolName, {
getTextLines: this.getCircleROIToolTextLines
})
toolGroup.addTool(AngleTool.toolName, {
getTextLines: this.getAngleToolTextLines
})
toolGroup.addTool(CobbAngleTool.toolName, {
getTextLines: this.getCobbAngleToolTextLines
})
if (toolGroupId === 'viewport-fusion-3') {
toolGroup.addTool(VolumeRotateTool.toolName)
toolGroup.setToolActive(VolumeRotateTool.toolName, {
@ -1229,6 +1239,8 @@ export default {
toolGroup.setToolPassive(LengthTool.toolName)
toolGroup.setToolPassive(BidirectionalTool.toolName)
toolGroup.setToolPassive(CircleROITool.toolName)
toolGroup.setToolPassive(AngleTool.toolName)
toolGroup.setToolPassive(CobbAngleTool.toolName)
} else {
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
toolGroup.setToolEnabled(RectangleROITool.toolName)
@ -1236,6 +1248,8 @@ export default {
toolGroup.setToolEnabled(LengthTool.toolName)
toolGroup.setToolEnabled(BidirectionalTool.toolName)
toolGroup.setToolEnabled(CircleROITool.toolName)
toolGroup.setToolEnabled(AngleTool.toolName)
toolGroup.setToolEnabled(CobbAngleTool.toolName)
}
toolGroup.setToolPassive(EraserTool.toolName)
})
@ -1666,7 +1680,6 @@ export default {
}
const textLines = []
if (data.label) {
// textLines.push(data.label)
textLines.push(data.status ? `${data.label}(${data.status})` : data.label)
}
textLines.push(`${parseFloat(length).toFixed(this.digitPlaces)} ${unit}`)
@ -1688,7 +1701,9 @@ export default {
} = cachedVolumeStats || {}
const textLines = []
if (data.label) {
textLines.push(data.label)
}
if (area) {
const areaLine = isEmptyArea
? `Area: Oblique not supported`
@ -1743,6 +1758,9 @@ export default {
}
const textLines = []
if (data.label) {
textLines.push(data.label)
}
textLines.push(`Area: ${this.reRound(area, this.digitPlaces)} ${areaUnit}`)
textLines.push(`Mean: ${this.reRound(mean, this.digitPlaces)} ${modalityUnit}`)
@ -1756,11 +1774,8 @@ export default {
const { length, width, unit } = cachedStats[targetId]
const textLines = []
// if (label) {
// textLines.push(label);
// }
if (label) {
// textLines.push(label)
textLines.push(data.status ? `${label}(${data.status})` : label)
}
if (length === undefined) {
@ -1790,7 +1805,7 @@ export default {
const textLines = []
if (data.label) {
// textLines.push(data.label)
textLines.push(data.status ? `${data.label}(${data.status})` : data.label)
textLines.push(data.label)
}
if (radius) {
@ -1821,8 +1836,40 @@ export default {
return textLines
},
getAngleToolTextLines(data, targetId) {
const cachedVolumeStats = data.cachedStats[targetId]
const { angle } = cachedVolumeStats
if (angle === undefined) {
return
}
if (isNaN(angle)) {
return [`${angle}`]
}
const textLines = []
if (label) {
textLines.push(label)
}
textLines.push(`${angle.toFixed(this.digitPlaces)} ${String.fromCharCode(176)}`)
return textLines
},
getCobbAngleToolTextLines(data, targetId) {
const cachedVolumeStats = data.cachedStats[targetId]
const { angle } = cachedVolumeStats
if (angle === undefined) {
return
}
const textLines = []
if (label) {
textLines.push(label)
}
textLines.push(`${angle.toFixed(this.digitPlaces)} ${String.fromCharCode(176)}`)
return textLines
},
reRound(result, finalPrecision) {
if (result.includes(', ')) {
if (typeof result === 'string' && result.includes(', ')) {
const numStrs = result.split(', ')
const processed = numStrs.map(str => this.processSingle(str, finalPrecision))
return processed.join(', ')

View File

@ -232,9 +232,9 @@
<el-input
type="number"
@change="(val) => { formItemNumberChange(val, question) }"
@blur="!questionsMarkStatus[question.Id] ? handleBlur(questionForm[question.Id], questionForm, question.Id) : ()=>{}"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? ()=>{} : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question) "
v-model="questionForm[question.Id]"
:disabled="(questionsMarkStatus[question.Id] && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1"
:disabled="(questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1"
style="width: 150px;"
>
<template v-if="question.Unit !== 0" slot="append">
@ -243,7 +243,7 @@
</el-input>
<!-- 测量 -->
<el-button
v-if="readingTaskState < 2 && !questionsMarkStatus[question.Id]"
v-if="readingTaskState < 2 && (!questionsMarkStatus[question.Id].isMarked)"
size="mini"
type="text"
@click="operateImageMarker({operateStateEnum: 1, question})"
@ -252,7 +252,7 @@
</el-button>
<!-- 绑定 -->
<el-button
v-if="readingTaskState < 2 && !questionsMarkStatus[question.Id]"
v-if="readingTaskState < 2 && (!questionsMarkStatus[question.Id].isMarked)"
size="mini"
type="text"
@click="operateImageMarker({operateStateEnum: 0, question})"
@ -261,7 +261,7 @@
</el-button>
<!-- 查看 -->
<el-button
v-if="questionsMarkStatus[question.Id]"
v-if="questionsMarkStatus[question.Id].isMarked"
size="mini"
type="text"
@click="operateImageMarker({operateStateEnum: 2, question})"
@ -270,7 +270,7 @@
</el-button>
<!-- 更改 -->
<el-button
v-if="readingTaskState < 2 && questionsMarkStatus[question.Id]"
v-if="readingTaskState < 2 && (questionsMarkStatus[question.Id].isMarked)"
size="mini"
type="text"
@click="operateImageMarker({operateStateEnum: 3, question})"
@ -279,7 +279,7 @@
</el-button>
<!-- 移除 -->
<el-button
v-if="readingTaskState < 2 && questionsMarkStatus[question.Id]"
v-if="readingTaskState < 2 && (questionsMarkStatus[question.Id].isMarked)"
size="mini"
type="text"
@click="operateImageMarker({operateStateEnum: 4, question})"
@ -288,12 +288,12 @@
</el-button>
<!-- 保存 -->
<el-button
v-if="readingTaskState < 2 && questionsMarkStatus[question.Id]"
v-if="readingTaskState < 2 && !questionsMarkStatus[question.Id].isSaved"
size="mini"
type="text"
@click="operateImageMarker({operateStateEnum: 5, question})"
>
<el-tooltip v-if="questionsMarkStatus[question.Id] === 1" class="item" effect="dark" :content="$t('trials:reading:button:unsaved')" placement="bottom">
<el-tooltip v-if="!questionsMarkStatus[question.Id].isSaved" class="item" effect="dark" :content="$t('trials:reading:button:unsaved')" placement="bottom">
<i class="el-icon-warning" style="color:red" />
</el-tooltip>
保存
@ -601,6 +601,10 @@ export default {
handleBlur(value, a, b) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
},
handleMarkedQsBlur(value, a, b, question) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
this.$emit('operateImageMarker', {operateStateEnum: 6, question})
},
deleteTableCol(row, index) {
this.$confirm(this.$t('trials:uploadNonDicoms:message:msg1')).then(() => {
const loading = this.$loading({ fullscreen: true })

View File

@ -123,7 +123,7 @@ export default {
operateRowId: '',
imageTool: '',
imageToolAttribute: '',
questionsMarkStatus: {}, // 12
questionsMarkStatus: {},
digitPlaces: 2
}
},
@ -169,8 +169,8 @@ export default {
this.questions = res.Result.SinglePage
this.questionsMarkStatus = {}
this.questionMarkInfoList = res.OtherInfo.QuestionMarkInfoList.map(i => {
if (i.QuestionId && i.MeasureData) {
this.$set(this.questionsMarkStatus, i.QuestionId, 2)
if (i.QuestionId) {
this.$set(this.questionsMarkStatus, i.QuestionId, {isMarked: i.MeasureData !== '', isSaved: true})
}
if (typeof i.MeasureData === 'string' && i.MeasureData) {
i.MeasureData = JSON.parse(i.MeasureData)
@ -381,9 +381,12 @@ export default {
this.$set(this.questionForm, obj.question.Id, '')
const i = this.questionMarkInfoList.findIndex(i => i.QuestionId === obj.question.Id)
if (i > -1) {
this.questionMarkInfoList.splice(i, 1)
this.questionMarkInfoList[i].MeasureData = ''
this.questionMarkInfoList[i].StudyId = ''
this.questionMarkInfoList[i].SeriesId = ''
this.questionMarkInfoList[i].InstanceId = ''
}
this.$set(this.questionsMarkStatus, obj.question.Id, 0)
this.$set(this.questionsMarkStatus, obj.question.Id, {isMarked: false, isSaved: false})
} else if (obj.operateStateEnum === 5) {
//
this.loading = true
@ -404,12 +407,15 @@ export default {
}
await saveTaskQuestion(-10, params)
this.$set(this.questionsMarkStatus, obj.question.Id, 2)
this.$set(this.questionsMarkStatus, obj.question.Id, {isMarked: this.questionMarkInfoList[i].MeasureData ? true : false, isSaved: true})
this.loading = false
} catch (e) {
console.log(e)
this.loading = false
}
} else if (obj.operateStateEnum === 6) {
//
this.$set(this.questionsMarkStatus, obj.question.Id, {isMarked: false, isSaved: false})
}
},
async bindAnnotationToQuestion(annotation) {
@ -458,7 +464,7 @@ export default {
this.questionMarkInfoList[i].MeasureData = annotation
}
this.setAnswerToQuestion(annotation, this.operateQuestionId)
this.$set(this.questionsMarkStatus, this.operateQuestionId, 1)
this.$set(this.questionsMarkStatus, this.operateQuestionId, {isMarked: true, isSaved: false})
} catch (e) {
console.log(e)
}
@ -468,7 +474,7 @@ export default {
if (i === -1) return
this.questionMarkInfoList[i].measureData = annotation
this.setAnswerToQuestion(annotation, this.questionMarkInfoList[i].QuestionId)
this.$set(this.questionsMarkStatus, this.questionMarkInfoList[i].QuestionId, 1)
this.$set(this.questionsMarkStatus, this.questionMarkInfoList[i].QuestionId, {isMarked: true, isSaved: false})
},
setAnswerToQuestion(annotation, questionId) {
if (!questionId || !annotation) return

View File

@ -274,6 +274,24 @@ const config = {
'i18nKey': 'trials:reading:button:Circle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '角度工具',
'icon': 'angle',
'toolName': 'Angle',
'props': ['angle'],
'i18nKey': 'trials:reading:button:Angle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '角度工具',
'icon': 'cobb',
'toolName': 'CobbAngle',
'props': ['angle'],
'i18nKey': 'trials:reading:button:CobbAngle',
'isDisabled': false,
'disabledReason': ''
}
]
}

View File

@ -1095,7 +1095,7 @@ export default {
return textLines
},
reRound(result, finalPrecision) {
if (result.includes(', ')) {
if (typeof result === 'string' && result.includes(', ')) {
const numStrs = result.split(', ')
const processed = numStrs.map(str => this.processSingle(str, finalPrecision))
return processed.join(', ')