irc_web/src/views/trials/trials-panel/reading/dicoms/components/Questions.vue

557 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div v-loading="loading" class="ecrf-wrapper">
<el-form
v-if="questions.length > 0"
ref="questions"
size="small"
:model="questionForm"
>
<QuestionItem
v-for="question of questions"
:key="question.Id"
:question="question"
:question-form="questionForm"
:reading-task-state="readingTaskState"
:is-first-change-task="isFirstChangeTask"
:visit-task-id="visitTaskId"
@setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData"
@addAnnotation="addAnnotation"
@removeAnnotation="removeAnnotation"
@locateAnnotation="locateAnnotation"
/>
<el-form-item v-if="readingTaskState < 2 && !isFirstChangeTask">
<div style="text-align:right">
<el-button size="mini" :disabled="!questionFormChangeState" :type="questionFormChangeState ? 'primary' : null" @click="handleSave">{{ $t('common:button:save') }}</el-button>
</div>
</el-form-item>
</el-form>
</div>
</template>
<script>
// import { uploadPrintscreen } from '@/api/reading'
import { saveImageQuality, getSplenicState,getSplenicVerify } from '@/api/trials'
import QuestionItem from './QuestionItem'
import DicomEvent from './DicomEvent'
import { mapGetters } from 'vuex'
import store from '@/store'
export default {
name: 'ECRF',
components: {
QuestionItem
},
props: {
questionFormChangeState: {
type: Boolean,
default: false
},
questionFormChangeNum: {
type: Number,
default: 0
},
isFirstChangeTask: {
type: Boolean,
default: false
},
groupClassify: {
type: Number,
default: null
},
isQulityIssues: {
type: Boolean,
default: true
},
},
data() {
return {
loading: false,
questions: [],
questionForm: {},
readingTaskState: 2,
visitTaskId: '',
imageQualityId: '',
measurements: [],
spleenStatusId: '',
spleenLengthId: '',
isBaseLineTask: false,
criterionType: null,
spleenInfo:null,
calculateSpleenStatus:''
}
},
computed: {
...mapGetters(['visitTaskList', 'currentReadingTaskState'])
},
watch: {
questionForm: {
deep: true,
immediate: false,
handler(v) {
if(this.isQulityIssues){
DicomEvent.$emit('questionFormChange', true)
}
// if(this.criterionType === 2 && this.groupClassify === 3 && this.calculateSpleenStatus && this.calculateSpleenStatus !== this.questionForm[this.spleenStatusId]){
// for (let i = 0; i < this.questions[0].Childrens.length; i++) {
// if (this.questions[0].Childrens[i].QuestionType === 49) {
// this.questions[0].Childrens[i].ShowQuestion = 2
// break
// }
// }
// }
}
},
currentReadingTaskState: {
immediate: true,
handler(val) {
if (val) {
this.readingTaskState = val
}
}
}
},
mounted() {
this.criterionType = parseInt(localStorage.getItem('CriterionType'))
DicomEvent.$on('setReadingState', readingTaskState => {
this.readingTaskState = readingTaskState
})
DicomEvent.$on('handleSaveQuestions', readingTaskState => {
this.handleSave()
})
},
beforeDestroy() {
DicomEvent.$off('setReadingState')
},
methods: {
async getQuestions(visitTaskId) {
this.visitTaskId = visitTaskId
// const loading = this.$loading({ fullscreen: true })
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
this.questions = []
if (idx > -1) {
this.isBaseLineTask = this.visitTaskList[idx].IsBaseLineTask
this.readingTaskState = this.visitTaskList[idx].ReadingTaskState
var questions = this.visitTaskList[idx].Questions
if (this.groupClassify === 3) {
this.measurements = []
this.visitTaskList[idx].QuestionMarkInfoList.forEach(i => {
if (i.MeasureData) {
i.MeasureData = JSON.parse(i.MeasureData)
}
this.measurements.push(i)
})
if(this.readingTaskState < 2 && !this.isBaseLineTask && !this.spleenInfo){
const { Result } = await getSplenicVerify(visitTaskId)
this.spleenInfo = Result
}
}
for (var i = 0; i < questions.length; i++) {
var v = questions[i]
v.IsBaseLineTask = this.isBaseLineTask
if (v.Type === 'group' && v.GroupClassify !== this.groupClassify) continue
if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary') {
this.$set(this.questionForm, v.Id, v.Answer ? v.Answer : null)
if (v.QuestionType === 44) {
// 影像质量评估
this.imageQualityId = v.Id
// store.dispatch('reading/setImageQuality', v.Answer ? v.Answer : null)
}
if (v.QuestionType === 49) {
// 脾脏状态
this.spleenStatusId = v.Id
}
if (v.QuestionType === 48) {
// 脾脏长度
this.spleenLengthId = v.Id
this.calculateSpleenStatus = ''
this.setSpleenStatus(this.questionForm[this.spleenLengthId])
}
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
}
this.questions.push(v)
}
// this.questions = questions
}
// loading.close()
},
setChild(obj) {
obj.forEach(i => {
i.IsBaseLineTask = this.isBaseLineTask
if (i.Type !== 'group' && i.Type !== 'summary' && i.Id) {
this.$set(this.questionForm, i.Id, i.Answer ? i.Answer : null)
if (i.QuestionType === 44) {
// 影响质量评估
this.imageQualityId = i.Id
// store.dispatch('reading/setImageQuality', i.Answer ? i.Answer : null)
}
if (i.QuestionType === 49) {
// 脾脏状态
this.spleenStatusId = i.Id
}
if (i.QuestionType === 48) {
// 脾脏长度
this.spleenLengthId = i.Id
}
}
if (i.Childrens && i.Childrens.length > 0) {
this.setChild(i.Childrens)
}
})
},
handleSave() {
this.$refs['questions'].validate(async(valid) => {
if (!valid) return
// lugano标准校验脾脏状态是否符合要求
if (this.criterionType === 2 && this.groupClassify === 3) {
var currentSpleenStatus = this.questionForm[this.spleenStatusId]
var currentSpleenLength = this.questionForm[this.spleenLengthId]
currentSpleenStatus = isNaN(parseInt(currentSpleenStatus)) ? null : parseInt(currentSpleenStatus)
var idx = this.measurements.findIndex(i => i.QuestionType === 48)
if (currentSpleenLength && currentSpleenStatus === 5) {
// '脾脏状态为不可评估,不需要添加标记!'
this.$alert(this.$t('trials:lugano:message:validSpleen1'), this.$t('trials:lugano:fusionDialog:warning'), {
callback: _ => {}
})
}else if(currentSpleenLength === 5 && idx> -1 && this.measurements[idx].MeasureData){
// 若有标记,状态不可为“无法评估”
this.$alert(this.$t('trials:lugano:message:validSpleen1'), this.$t('trials:lugano:fusionDialog:warning'), {
callback: _ => {}
})
}else{
this.saveQuestionsList()
}
} else {
this.saveQuestionsList()
}
// this.saveQuestionsList()
})
},
async saveQuestionsList() {
this.loading = true
var answers = []
var imageQuality = null
if (this.groupClassify === 3) {
await this.uploadScreenshot()
}
for (const k in this.questionForm) {
answers.push({ id: k, answer: this.questionForm[k] })
if (k === this.imageQualityId) {
imageQuality = this.questionForm[k]
}
}
var params = {
visitTaskId: this.visitTaskId,
answers: answers
}
if (this.groupClassify === 3) {
var questionMarkInfoList = []
this.measurements.forEach(item => {
var i = Object.assign({}, item)
if (i.MeasureData) {
i.MeasureData = JSON.stringify(i.MeasureData)
}
questionMarkInfoList.push(i)
})
params.questionMarkInfoList = questionMarkInfoList
}
saveImageQuality(params).then(async res => {
this.$message.success(this.$t('common:message:savedSuccessfully'))
var trialId = this.$route.query.trialId
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: trialId, visitTaskId: this.visitTaskId })
this.getQuestions(this.visitTaskId)
this.loading = false
if(this.isQulityIssues){
DicomEvent.$emit('questionFormChange', false)
}
DicomEvent.$emit('getReportInfo', true)
DicomEvent.$emit('readingPageUpdate', {})
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
if (idx > -1 && !this.visitTaskList[idx].IsBaseLineTask) {
if (parseInt(imageQuality) === 2) {
this.$confirm(this.$t('trials:reading:warnning:unableEvaluate'), '', {
type: 'warning'
}).then(() => {
store.dispatch('reading/setImageQuality', imageQuality)
DicomEvent.$emit('handleImageQualityAbnormal')
}).catch(() => {
})
}
}
}).catch(() => {
this.loading = false
})
},
async getSplenicState() {
try {
var spleenLength = this.questionForm[this.spleenLengthId]
spleenLength = isNaN(parseFloat(spleenLength)) ? 0 : parseFloat(spleenLength)
const result = await getSplenicState(this.visitTaskId, spleenLength)
return { isSuccess: true, result: result.Result }
} catch (e) {
return { isSuccess: false, result: e }
}
},
// 上传截图
async uploadScreenshot() {
for (let i = 0; i < this.measurements.length; i++) {
if (this.measurements[i].pictureBaseStr) {
var pictureObj = await this.uploadScreenshots(`${new Date().getTime()}`, this.measurements[i].pictureBaseStr)
this.measurements[i].PicturePath = pictureObj.isSuccess ? pictureObj.result.url : ''
this.measurements[i].pictureBaseStr = ''
}
}
},
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}/Visit/${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 })
},
addAnnotation(obj) {
const { Id, QuestionType } = obj
this.currentQsId = Id
var idx = this.measurements.findIndex(i => i.QuestionId === Id)
var orderMarkName = QuestionType === 48 ? 'Spleen' : ''
if (idx === -1) {
// 脾脏长度(48); 肝脏血池SUVmax(51); 纵膈血池SUVmax(52)
this.measurements.push({ QuestionId: Id, QuestionType: QuestionType, StudyId: '', SeriesId: '', InstanceId: '', MarkTool: '', PicturePath: '', NumberOfFrames: '', MeasureData: '', OrderMarkName: orderMarkName })
}
// 脾脏长度 直径测量
this.$emit('setNonTargetMeasurementStatus', { status: true })
DicomEvent.$emit('imageLocation', { questionId: Id, visitTaskId: this.visitTaskId, lesionName: orderMarkName, markTool: 'Length', readingTaskState: this.readingTaskState, isMarked: false })
},
async removeAnnotation(obj) {
const { Id } = obj
var idx = this.measurements.findIndex(i => i.QuestionId === Id)
if (idx === -1) return
this.$set(this.questionForm, Id, '')
if (this.measurements[idx].QuestionType === 48){
this.$set(this.questionForm, this.spleenStatusId, '')
}
await store.dispatch('reading/removeNonTargetMeasuredData', { visitTaskId: this.visitTaskId, measureData: this.measurements[idx].MeasureData, questionId: Id })
this.measurements.splice(idx, 1)
DicomEvent.$emit('getMeasureData')
},
locateAnnotation(obj) {
const { Id } = obj
var idx = this.measurements.findIndex(i => i.QuestionId === Id)
if (idx === -1) return
const measureObj = this.measurements[idx]
DicomEvent.$emit('imageLocation', { questionId: Id, visitTaskId: this.visitTaskId, lesionName: measureObj.OrderMarkName, markTool: measureObj.MarkTool, readingTaskState: this.readingTaskState, isMarked: !!measureObj.MeasureData })
},
setMeasuredData(measurement) {
var idx = -1
if (this.currentQsId) {
// 新增
idx = this.measurements.findIndex(i => i.QuestionId === this.currentQsId)
this.currentQsId = ''
} else {
// 编辑
idx = this.measurements.findIndex(i => i.OrderMarkName === measurement.data.remark)
}
if (idx === -1) return
var remark = this.measurements[idx].QuestionType === 48 ? 'Spleen' : ''
measurement.data.remark = remark
this.measurements[idx].StudyId = measurement.studyId
this.measurements[idx].SeriesId = measurement.seriesId
this.measurements[idx].InstanceId = measurement.instanceId
this.measurements[idx].MarkTool = measurement.type
this.measurements[idx].NumberOfFrames = isNaN(parseInt(measurement.frame)) ? 0 : measurement.frame
this.measurements[idx].MeasureData = measurement
this.measurements[idx].pictureBaseStr = measurement.pictureBaseStr
measurement.pictureBaseStr = ''
// 添加标记
var data = {
Id: '',
IsDicomReading: true,
StudyId: measurement.studyId,
InstanceId: measurement.instanceId,
SeriesId: measurement.seriesId,
MeasureData: measurement,
QuestionId: this.measurements[idx].QuestionId,
RowIndex: null,
RowId: null,
VisitTaskId: this.visitTaskId,
OrderMarkName: measurement.data.remark,
frame: isNaN(parseInt(measurement.frame)) ? 0 : measurement.frame
}
if (measurement.type === 'Length') {
const length = measurement.data.length ? measurement.data.length : null
this.$set(this.questionForm, this.measurements[idx].QuestionId, length || null)
if (this.measurements[idx].QuestionType === 48){
this.calculateSpleenStatus = ''
this.setSpleenStatus(length)
}
// if (this.measurements[idx].QuestionType === 48 && length <= 130 && this.isBaseLineTask) {
// // 脾脏状态设置默认值为正常
// this.$set(this.questionForm, this.spleenStatusId, '1')
// }
// if (this.measurements[idx].QuestionType === 48 && length > 130 && this.isBaseLineTask) {
// // 脾脏状态设置默认值为肿大
// this.$set(this.questionForm, this.spleenStatusId, '6')
// }
}
store.dispatch('reading/addOrUpdateNonTargetMeasuredData', { visitTaskId: this.visitTaskId, data: data })
if(this.isQulityIssues){
DicomEvent.$emit('questionFormChange', true)
}
},
setSpleenStatus(length){
if(length){
if(this.isBaseLineTask){
// 直径≤130mm时系统默认脾脏状态为“正常”
if(length <= 130){
this.$set(this.questionForm, this.spleenStatusId, '1')
this.calculateSpleenStatus = '1'
}
// 直径>130mm时系统默认脾脏状态为“肿大”
if(length > 130){
this.$set(this.questionForm, this.spleenStatusId, '6')
this.calculateSpleenStatus = '6'
}
}else{
// 与基线相比脾垂直径变化值
var diffFromBaseline = length - this.spleenInfo.BaseLineSpleenLength
var percentFormBaseline = 0
if(this.spleenInfo.BaseLineSpleenLength){
percentFormBaseline = length * 100 / (this.spleenInfo.BaseLineSpleenLength - 130)
}
if(this.spleenInfo.BaseLineSpleenLength > 130 && diffFromBaseline >= 10 && percentFormBaseline > 50){
// 1、基线 垂直径>130 mm
// 2、与基线相比脾垂直径变化值≥10 mm
// 3、与基线相比脾肿大增加的百分比>50
// 系统默认脾脏状态为“显著增大”
this.$set(this.questionForm, this.spleenStatusId, '4')
this.calculateSpleenStatus = '4'
}else if( this.spleenInfo.BaseLineSpleenLength <= 130 && diffFromBaseline >= 20 && length > 130){
// 1、基线垂直径≤130mm
// 2、与基线相比脾垂直径变化值≥20 mm
// 3、当前垂直径>130 mm
// 系统默认脾脏状态为“显著增大”
this.$set(this.questionForm, this.spleenStatusId, '4')
this.calculateSpleenStatus = '4'
}else if( this.spleenInfo.BaseLineSpleenLength > 130 && this.spleenInfo.LowSpleenLength <= 130 && diffFromBaseline >= 20 && length > 130){
// 1、基线 垂直径>130 mm
// 2、当前访视的前面访视中 存在垂直径≤130mm
// 3、与最低点相比脾脏垂直径的增加值≥20 mm
// 4、当前垂直径>130 mm
// 系统默认脾脏状态为“显著增大”
this.$set(this.questionForm, this.spleenStatusId, '4')
this.calculateSpleenStatus = '4'
}else if(length < 130){
// 当前访视的垂直径≤130mm
// 系统默认脾脏状态为“正常”
this.$set(this.questionForm, this.spleenStatusId, '1')
this.calculateSpleenStatus = '1'
}else if(this.spleenInfo.BaseLineState === '6' && percentFormBaseline < -50){
// 1、基线期 状态为“肿大”
// 2、与基线相比脾肿大增加的百分比小于-50
// 系统默认脾脏状态为“部分缓解”
this.$set(this.questionForm, this.spleenStatusId, '2')
this.calculateSpleenStatus = '2'
}else{
this.$set(this.questionForm, this.spleenStatusId, '3')
this.calculateSpleenStatus = '3'
}
}
}
},
resetFormItemData(v) {
this.questionForm[v] = null
if (v === this.spleenLengthId) {
var spleenStatus = this.questionForm[this.spleenStatusId]
spleenStatus = isNaN(parseInt(spleenStatus)) ? null : parseInt(spleenStatus)
if (spleenStatus === 5) {
this.removeAnnotation({ Id: this.spleenLengthId })
}
}
},
setFormItemData(obj) {
this.questionForm[obj.key] = obj.val
}
}
}
</script>
<style lang="scss" scoped>
.ecrf-wrapper{
/deep/ .el-form-item__label{
color: #c3c3c3;
}
/deep/ .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
/deep/ .el-textarea__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
/deep/ .el-form-item{
display: flex;
flex-direction: row;
justify-content: flex-start;
flex-wrap: wrap;
}
/deep/ .el-form-item__content{
flex: 1;
}
/deep/ .el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
.el-form-item__content
.el-select{
width: 100%;
}
}
</style>