irc_web/src/views/trials/trials-panel/visit/qc-check/components/qualityAssurance.vue

2264 lines
74 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="qa-wrapper">
<div class="qa-content" style="position: relative">
<div
v-if="existsManual"
style="position: absolute; right: 20px; top: 10px; z-index: 9"
>
<el-button type="text" @click="openManuals">{{
$t("trials:reading:button:handbooks")
}}</el-button>
</div>
<!-- 所有检查信息 -->
<el-card shadow="hover" style="min-height: 600px">
<el-tabs v-model="activeName" type="card">
<!-- DICOM影像 -->
<el-tab-pane
v-if="data.DicomStudyCount > 0"
:label="$t('trials:audit:tab:dicoms')"
name="dicom"
>
<el-row>
<el-col :span="12">
<!-- 检查信息 -->
<h3>{{ $t("trials:audit:title:dicoms") }}</h3>
</el-col>
<el-col :span="12">
<div
v-show="isHaveFirstGiveMedicineDate"
style="text-align: right"
>
<!-- 访视窗口期 -->
<h4>
{{ $t("trials:audit:tip:visitWindow") }}:
<span v-if="!!baseDate" style="font-weight: normal">
{{ `${upperLimit}~${lowerLimit}` }}
</span>
<!-- 访视基准日期或窗口未设置 -->
<span v-else>{{
$t("trials:audit:tip:visitWindowNotSet")
}}</span>
</h4>
</div>
</el-col>
</el-row>
<div style="text-align: right">
<!-- 预览所有影像 -->
<el-button
size="small"
type="primary"
style="margin-left: 10px"
@click="handleViewImages"
>
{{ $t("trials:audit:button:previewAllDiocms") }}
</el-button>
<!-- 预览阅片影像 -->
<el-button
size="small"
type="primary"
style="margin-left: 10px"
@click="handleViewReadingImages"
>
{{ $t("trials:audit:button:previewReadingDiocms") }}
</el-button>
</div>
<el-table :data="studyList" :row-class-name="tableRowClassName">
<!-- 检查编号 -->
<el-table-column
prop="StudyCode"
:label="$t('trials:audit:table:studyId')"
/>
<!-- 检查类型 -->
<el-table-column
prop="ModalityForEdit"
:label="$t('trials:audit:table:modality')"
/>
<!-- 检查类型 -->
<el-table-column
prop="Modalities"
:label="$t('trials:audit:table:modality1')"
/>
<!-- 检查部位 -->
<el-table-column
prop="BodyPartForEdit"
:label="$t('trials:audit:table:bodyPart')"
>
<template slot-scope="scope">
{{ getBodyPart(scope.row.BodyPartForEdit) }}
</template>
</el-table-column>
<!-- 序列数量 -->
<el-table-column
prop="SeriesCount"
:label="$t('trials:audit:table:seriesCount')"
/>
<!-- 图像数量 -->
<el-table-column
prop="InstanceCount"
:label="$t('trials:audit:table:instanceCount')"
/>
<!-- 检查日期 -->
<el-table-column
prop="StudyTime"
:label="$t('trials:audit:table:studyDate')"
>
<template slot-scope="scope">
<el-tooltip
class="item"
effect="dark"
:content="$t('trials:audit:message:qsOverWindow')"
placement="bottom"
>
<i
v-if="
isHaveFirstGiveMedicineDate &&
!!baseDate &&
scope.row.StudyTime &&
(moment(scope.row.StudyTime).format('YYYY-MM-DD') >
lowerLimit ||
moment(scope.row.StudyTime).format('YYYY-MM-DD') <
upperLimit)
"
class="el-icon-warning"
style="color: #f44336; font-size: 16px"
/>
</el-tooltip>
<span>{{
scope.row.StudyTime
? moment(scope.row.StudyTime).format("YYYY-MM-DD")
: ""
}}</span>
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
icon="el-icon-view"
:title="$t('trials:audit:action:preview')"
circle
:disabled="scope.row.IsDeleted"
@click="handlePreviewStudy(scope.row)"
/>
<!-- 编辑 -->
<el-button
icon="el-icon-edit-outline"
:title="$t('trials:audit:action:edit')"
circle
:disabled="isAudit || scope.row.IsDeleted"
@click="handleEditStudy(scope.row)"
/>
<!-- 预览PET-CT数据 -->
<el-button
type="primary"
icon="el-icon-document tip-i"
:title="$t('trials:audit:tab:clinicalData')"
v-if="
['PT、CT', 'CT、PT', 'PET-CT'].includes(
scope.row.Modalities
) && IsHaveStudyClinicalData
"
circle
:disabled="scope.row.IsDeleted"
@click="handlePreviewClinicalData(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<!-- 序列信息 -->
<h3>{{ $t("trials:audit:title:series") }}</h3>
<el-table :data="seriesList" :row-class-name="tableRowClassName">
<!-- 序列号 -->
<el-table-column
prop="SeriesNumber"
:label="$t('trials:audit:table:seriesId')"
/>
<!-- 检查编号 -->
<el-table-column
prop="StudyCode"
:label="$t('trials:audit:table:seriesOfStudyId')"
/>
<!-- 检查类型 -->
<el-table-column
prop="Modality"
:label="$t('trials:audit:table:seriesModality')"
show-overflow-tooltip
/>
<!-- 图像数量 -->
<el-table-column
prop="InstanceCount"
:label="$t('trials:audit:table:seriesOfInstanceCount')"
/>
<!-- 检查日期 -->
<el-table-column
prop="SeriesTime"
:label="$t('trials:audit:table:seriesOfStudyDate')"
show-overflow-tooltip
>
<template slot-scope="scope">
{{
scope.row.StudyTime
? moment(scope.row.StudyTime).format("YYYY-MM-DD")
: ""
}}
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column
prop="CreateTime"
:label="$t('trials:audit:table:seriesOfUploadedDate')"
show-overflow-tooltip
/>
<!-- 是否阅片 -->
<el-table-column
prop="IsReading"
:label="$t('trials:audit:table:isReading')"
>
<template slot-scope="scope">
<el-switch
v-model="scope.row.IsReading"
:disabled="scope.row.IsDeleted || isAudit"
@change="changeReadingStatus($event, scope.row)"
:active-text="$fd('YesOrNo', true)"
:inactive-text="$fd('YesOrNo', false)"
/>
</template>
</el-table-column>
<!-- 是否删除 复审时删除的序列不可再次编辑 -->
<el-table-column
prop="IsDeleted"
:label="$t('trials:audit:table:isDelete')"
>
<template slot-scope="scope">
<el-switch
v-model="scope.row.IsDeleted"
:disabled="isAudit"
@change="changeDeleteStatus($event, scope.row)"
:active-text="$fd('YesOrNo', true)"
:inactive-text="$fd('YesOrNo', false)"
/>
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
icon="el-icon-view"
:title="$t('trials:audit:action:seriesPreview')"
circle
:disabled="scope.row.IsDeleted"
@click="handlePreviewInstance(scope.row)"
/>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 非DICOM影像 -->
<el-tab-pane
v-if="data.NoneDicomStudyCount > 0"
:label="$t('trials:audit:tab:nonDicoms')"
name="none-dicom"
>
<el-row>
<!-- 检查信息 -->
<el-col :span="12"
><h3>{{ $t("trials:audit:title:nonDicomsTitle") }}</h3></el-col
>
<el-col :span="12">
<div
v-show="isHaveFirstGiveMedicineDate"
style="text-align: right"
>
<!-- 访视窗口期 -->
<h4>
{{ $t("trials:audit:tip:nonDicomsVisitWindow") }}:
<span v-if="!!baseDate" style="font-weight: normal">
{{ `${upperLimit}~${lowerLimit}` }}
</span>
<!-- 访视基准日期或窗口未设置 -->
<span v-else>{{
$t("trials:audit:tip:visitWindowNotSet")
}}</span>
</h4>
</div>
</el-col>
</el-row>
<div style="text-align: right">
<!-- 预览 -->
<el-button
size="small"
:disabled="noneDicomStudyList.length === 0"
type="primary"
style="margin-left: 10px"
@click="handleViewAllNoneDicoms"
>
{{ $t("trials:audit:tip:nonDicomsPreviewAll") }}
</el-button>
</div>
<el-table :data="noneDicomStudyList">
<!-- 检查编号 -->
<el-table-column
prop="CodeView"
:label="$t('trials:audit:table:nonDicomsStudyId')"
/>
<!-- 检查类型 -->
<el-table-column
prop="Modality"
:label="$t('trials:audit:table:nonDicomsModality')"
/>
<!-- 检查部位 -->
<el-table-column
prop="BodyPart"
:label="$t('trials:audit:table:nonDicomsBodypart')"
>
<template slot-scope="scope">
{{ getBodyPart(scope.row.BodyPart) }}
</template>
</el-table-column>
<!-- 文件 -->
<el-table-column
prop="FileCount"
:label="$t('trials:audit:table:nonDicomsFileCount')"
>
<template slot-scope="scope">
<el-popover
v-if="scope.row.FileCount"
trigger="click"
placement="bottom"
>
<el-table
:data="scope.row.NoneDicomStudyFileList"
height="300"
size="small"
>
<!-- 文件名称 -->
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column
:label="$t('common:action:action')"
width="120"
>
<template slot-scope="files">
<!-- 预览 -->
<el-button
type="text"
@click.native.prevent="previewFile(files.row)"
>
{{ $t("trials:audit:button:nonDicomsPreview") }}
</el-button>
</template>
</el-table-column>
</el-table>
<div slot="reference" class="name-wrapper">
<el-button type="text">
{{ scope.row.FileCount }}
</el-button>
</div>
</el-popover>
<span v-else>{{ scope.row.FileCount }}</span>
</template>
</el-table-column>
<!-- 检查日期 -->
<el-table-column
prop="ImageDate"
:label="$t('trials:audit:table:nonDicomsStudyDate')"
>
<template slot-scope="scope">
<i
v-if="
isHaveFirstGiveMedicineDate &&
!!baseDate &&
scope.row.ImageDate &&
(moment(scope.row.ImageDate).format('YYYY-MM-DD') >
lowerLimit ||
moment(scope.row.ImageDate).format('YYYY-MM-DD') <
upperLimit)
"
class="el-icon-warning"
style="color: #f44336; font-size: 16px"
/>
<span>{{
moment(scope.row.ImageDate).format("YYYY-MM-DD")
}}</span>
</template>
</el-table-column>
<!-- 更新时间 -->
<el-table-column
prop="UpdateTime"
:label="$t('trials:audit:table:nonDicomsUpdateTime')"
/>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
icon="el-icon-view"
:title="$t('trials:audit:button:nonDicomsPreview')"
circle
:disabled="scope.row.FileCount === 0"
@click.native.prevent="
handlePreviewNoneDicomFiles(scope.row)
"
/>
<!-- 编辑 -->
<el-button
icon="el-icon-edit-outline"
:title="$t('trials:audit:button:nonDicomsEdit')"
circle
:disabled="isAudit"
@click.native.prevent="handleEditNoneDicomInfo(scope.row)"
/>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 临床数据 -->
<!-- data.IsBaseLine && relationInfo.TrialClinicalInformationTransmissionEnum*1>0 && data.IsHaveClinicalData -->
<el-tab-pane
v-if="data.IsHaveClinicalData"
:label="$t('trials:audit:tab:clinicalData')"
name="clinical-data"
>
<ClinicalData
v-if="Object.keys(subjectClinicalData).length > 0"
:data="data"
style="margin-top: 5px"
:subject-clinical-data="subjectClinicalData"
:enum-type="
relationInfo.TrialClinicalInformationTransmissionEnum * 1
"
:subject-visit-id="data.Id"
:is-audit="isAudit"
:subject-id="data.SubjectId"
/>
</el-tab-pane>
</el-tabs>
</el-card>
<!-- 审核问题 -->
<!-- select/input/textarea/radio -->
<el-card shadow="hover" style="margin-top: 10px">
<!-- 审核问题 -->
<h3>{{ $t("trials:audit:title:questions") }}</h3>
<div v-if="qCQuestionAnswerList.length > 0" style="overflow-y: auto">
<QuestionForm
ref="questions"
:trial-id="trialId"
:subject-visit-id="data.Id"
:qc-process-enum="data.QCProcessEnum"
:current-q-c-enum="currentQCType"
:answers="qCQuestionAnswerList"
:is-audit="isAudit"
/>
</div>
<!-- 暂无数据 -->
<h3 v-else>{{ $t("trials:audit:message:noData") }}</h3>
</el-card>
<!-- 发起质疑 -->
<el-dialog
v-if="qcVisible"
:title="$t('trials:audit:dialogTitle:question')"
:visible.sync="qcVisible"
:close-on-click-modal="false"
append-to-body
custom-class="base-dialog-wrapper"
width="1000px"
>
<div
style="
padding: 10px;
border: 1px solid #e0e0e0;
max-height: 650px;
overflow-y: auto;
"
>
<el-form
v-if="qcVisible"
ref="qcForm"
:model="qcForm"
label-width="180px"
size="small"
>
<el-form-item :label="$t('trials:audit:form:questionContent')">
<!-- :header-row-style="{display:'none'}" -->
<el-table :data="qcForm.qcContent" style="width: 100%">
<el-table-column prop="isSelect" label="" width="40">
<template slot-scope="scope">
<el-checkbox v-model="scope.row.isSelect" />
</template>
</el-table-column>
<el-table-column prop="keyName" label="" width="180">
<template slot-scope="scope">
<span v-html="scope.row.keyName"></span>
</template>
</el-table-column>
<!-- 问题总结 -->
<el-table-column
prop="keyValue"
:label="$t('trials:audit:form:questionSummary')"
>
<template slot-scope="scope">
<el-input
v-show="scope.row.keyValue || scope.row.isSelect"
v-model="scope.row.keyValue"
type="textarea"
:rows="4"
size="mini"
/>
</template>
</el-table-column>
<!-- 行动事项 -->
<el-table-column
prop="ActionContent"
:label="$t('trials:audit:form:actionMatters')"
>
<template slot-scope="scope">
<el-input
v-show="scope.row.actionContent || scope.row.isSelect"
v-model="scope.row.actionContent"
type="textarea"
:rows="4"
size="mini"
/>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item :label="$t('trials:audit:form:questionDeadline')">
<el-date-picker
v-model="qcForm.deadlineTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
size="small"
clearable
default-time="23:59:59"
style="width: 100%"
/>
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<!-- 取消 -->
<el-button
:disabled="btnLoading"
size="small"
type="primary"
@click="qcVisible = false"
>
{{ $t("common:button:cancel") }}
</el-button>
<!-- 保存 -->
<el-button
size="small"
type="primary"
:loading="btnLoading"
@click="handleSaveQC"
>
{{ $t("common:button:save") }}
</el-button>
</div>
</el-dialog>
<!-- 历史质疑 -->
<el-dialog
v-if="historyVisible"
:visible.sync="historyVisible"
:close-on-click-modal="false"
custom-class="base-dialog-wrapper"
append-to-body
width="80%"
:title="$t('trials:audit:dialogTitle:historicalQuestions')"
>
<div style="text-align: right">
<el-button
icon="el-icon-refresh-left"
circle
:title="$t('trials:audit:button:refreshHistoryQs')"
@click="getHistoryInfo"
/>
</div>
<el-table
v-loading="historyLoading"
:data="historyList"
style="width: 100%"
height="500"
>
<!-- 质疑编号 -->
<el-table-column
prop="ChallengeCode"
:label="$t('trials:qcQuality:table:challengeCode')"
width="100"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-button
:style="{ color: scope.row.IsClosed ? '' : 'red' }"
type="text"
@click="handleReply(scope.row)"
>{{ scope.row.ChallengeCode }}</el-button
>
</template>
</el-table-column>
<!-- 质疑状态 -->
<el-table-column
prop="IsClosed"
:label="$t('trials:qcQuality:table:isClosed')"
width="80"
show-overflow-tooltip
>
<template slot-scope="scope">
{{ $fd("IsClosed", scope.row.IsClosed) }}
</template>
</el-table-column>
<!-- 创建时间 -->
<el-table-column
prop="CreateTime"
:label="$t('trials:qcQuality:table:createTime')"
width="150"
show-overflow-tooltip
/>
<!-- 创建人 -->
<el-table-column
prop="CreateUserName"
:label="$t('trials:qcQuality:table:organizer')"
width="100"
show-overflow-tooltip
/>
<!-- 领取人 -->
<el-table-column
prop="CurrentActionUserName"
:label="$t('trials:qcCheck:table:crrentUser')"
width="100"
show-overflow-tooltip
/>
<!-- 最新消息时间 -->
<el-table-column
prop="LatestMsgTime"
:label="$t('trials:qcQuality:table:latestMsgTime')"
width="200"
show-overflow-tooltip
/>
<!-- 重传状态 -->
<el-table-column
prop="ReuploadEnum"
:label="$t('trials:qcQuality:table:reUploadStatus')"
show-overflow-tooltip
width="180"
sortable="custom"
>
<template slot-scope="scope">
<span v-if="scope.row.ReuploadEnum === 0">--</span>
<el-tag v-else-if="scope.row.ReuploadEnum === 1" type="danger">{{
$fd("ReuploadEnum", scope.row.ReuploadEnum)
}}</el-tag>
<el-tag v-else-if="scope.row.ReuploadEnum === 2" type="warning">{{
$fd("ReuploadEnum", scope.row.ReuploadEnum)
}}</el-tag>
<el-tag v-else-if="scope.row.ReuploadEnum === 3" type="primary">{{
$fd("ReuploadEnum", scope.row.ReuploadEnum)
}}</el-tag>
</template>
</el-table-column>
<!-- 重传完成时间 -->
<el-table-column
prop="ReUploadedTime"
:label="$t('trials:qcQuality:table:reUploadTime')"
show-overflow-tooltip
width="260"
sortable="custom"
/>
<!-- 处理截止日期 -->
<el-table-column
prop="DeadlineTime"
:label="$t('trials:qcQuality:table:deadline')"
width="160"
show-overflow-tooltip
/>
<!-- 是否超限 -->
<el-table-column
prop="IsOverTime"
:label="$t('trials:qcQuality:table:isOverTime')"
width="160"
show-overflow-tooltip
>
<template slot-scope="scope">
{{ $fd("YesOrNo", scope.row.IsOverTime) }}
</template>
</el-table-column>
<!-- 关闭时间 -->
<el-table-column
prop="ClosedTime"
:label="$t('trials:qcQuality:table:closingTime')"
min-width="150"
show-overflow-tooltip
/>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
min-width="160"
>
<template slot-scope="scope">
<!-- 回复 -->
<el-button
type="text"
:disabled="scope.row.IsClosed || isAudit"
@click="handleReply(scope.row)"
>
{{ $t("trials:qcQuality:action:reply") }}
</el-button>
<!-- 关闭 -->
<el-button
type="text"
:disabled="scope.row.IsClosed || isAudit"
@click="handleCloseQC(scope.row)"
>
{{ $t("trials:qcQuality:action:close") }}
</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 质疑记录 -->
<el-dialog
v-if="chatVisible"
:visible.sync="chatVisible"
:close-on-click-modal="false"
custom-class="base-dialog-wrapper"
append-to-body
width="800px"
:title="
$t('trials:qcQuality:dialogTitle:reply') +
`(${currentQCRow.SubjectCode} ${currentQCRow.VisitName})`
"
>
<chat-form
:data="currentQCRow"
:sign-text="relationInfo.TrialImageQCSignText"
:clinical-enum="relationInfo.ClinicalInformationTransmissionEnum"
@close="chatVisible = false"
@getDialogList="getDialogList"
/>
</el-dialog>
<!-- 更新检查拍片部位信息 -->
<el-dialog
v-if="editStudyInfoVisible"
:title="$t('trials:audit:action:edit')"
:visible.sync="editStudyInfoVisible"
:close-on-click-modal="false"
append-to-body
custom-class="base-dialog-wrapper"
width="600px"
>
<div
style="
padding: 10px;
border: 1px solid #e0e0e0;
max-height: 650px;
overflow-y: auto;
"
>
<el-form ref="studyForm" :model="studyForm" label-width="100px">
<!-- 检查编号 -->
<el-form-item :label="$t('trials:audit:table:studyId')">
<el-input v-model="studyForm.StudyCode" disabled />
</el-form-item>
<!-- 检查类型 -->
<el-form-item
v-if="studyForm.IsDicomData"
:label="$t('trials:audit:table:modality')"
>
<el-input v-model="studyForm.Modalities" disabled />
</el-form-item>
<!-- 检查类型 -->
<el-form-item
v-else
:label="$t('trials:audit:table:modality')"
prop="Modalities"
:rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
},
]"
>
<el-radio-group v-model="studyForm.Modality">
<el-radio
v-for="m in trialModalitys"
v-show="m !== ''"
:key="m"
:label="m"
style="margin-bottom: 15px"
/>
</el-radio-group>
</el-form-item>
<!-- 检查部位 -->
<el-form-item
:label="$t('trials:audit:table:bodyPart')"
prop="BodyPartForEdit"
:rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
},
]"
>
<el-checkbox-group v-model="studyForm.BodyPartForEdit">
<el-checkbox
v-for="bodyPart in trialBodyPartTypes"
:key="bodyPart"
:label="bodyPart"
>{{
$fd("Bodypart", bodyPart, "Code", BodyPart, "Name")
}}</el-checkbox
>
</el-checkbox-group>
</el-form-item>
<!-- 序列数量 -->
<el-form-item :label="$t('trials:audit:table:seriesCount')">
<el-input v-model="studyForm.SeriesCount" disabled />
</el-form-item>
<!-- 图像数量 -->
<el-form-item
v-if="studyForm.InstanceCount"
:label="$t('trials:audit:table:instanceCount')"
>
<el-input v-model="studyForm.InstanceCount" disabled />
</el-form-item>
<!-- 检查日期 -->
<el-form-item :label="$t('trials:audit:table:studyDate')">
<el-date-picker
v-model="studyForm.StudyTime"
disabled
type="date"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button
:disabled="btnLoading"
size="small"
type="primary"
@click="editStudyInfoVisible = false"
>
{{ $t("common:button:cancel") }}
</el-button>
<el-button
:loading="btnLoading"
size="small"
type="primary"
@click="handleUpdateStudyInfo"
>
{{ $t("common:button:save") }}
</el-button>
</div>
</el-dialog>
<!-- 审核签名 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
append-to-body
custom-class="base-dialog-wrapper"
>
<div slot="title">
<span style="font-size: 18px">{{
$t("common:dialogTitle:sign")
}}</span>
<span style="font-size: 12px; margin-left: 5px">{{
`(${$t("common:label:sign")}${currentUser})`
}}</span>
</div>
<SignForm
ref="signForm"
:sign-code-enum="signCode"
:subject-visit-id="data.Id"
@closeDialog="closeSignDialog"
/>
</el-dialog>
<!-- 编辑非Dicom文件 -->
<el-dialog
v-if="editNoneDicomVisible"
:title="$t('trials:audit:button:nonDicomsEdit')"
:visible.sync="editNoneDicomVisible"
:close-on-click-modal="false"
append-to-body
custom-class="base-dialog-wrapper"
width="600px"
>
<div
style="
padding: 10px;
border: 1px solid #e0e0e0;
max-height: 650px;
overflow-y: auto;
"
>
<el-form
ref="noneDicomForm"
:model="noneDicomForm"
label-width="100px"
>
<!-- 检查编号 -->
<el-form-item :label="$t('trials:audit:table:nonDicomsStudyId')">
<el-input v-model="noneDicomForm.CodeView" disabled />
</el-form-item>
<!-- 检查类型 -->
<el-form-item
:label="$t('trials:audit:table:nonDicomsModality')"
prop="Modality"
:rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
},
]"
>
<el-radio-group v-model="noneDicomForm.Modality">
<el-radio
v-for="m in trialModalitys"
v-show="m !== ''"
:key="m"
:label="m"
style="margin-bottom: 15px"
/>
</el-radio-group>
</el-form-item>
<!-- 检查部位 -->
<el-form-item
:label="$t('trials:audit:table:nonDicomsBodypart')"
prop="BodyParts"
:rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
},
]"
>
<el-checkbox-group v-model="noneDicomForm.BodyParts">
<el-checkbox
v-for="bodyPart in trialBodyPartTypes"
:key="bodyPart"
:label="bodyPart"
>{{
$fd("Bodypart", bodyPart, "Code", BodyPart, "Name")
}}</el-checkbox
>
</el-checkbox-group>
</el-form-item>
<!-- 检查日期 -->
<el-form-item
:label="$t('trials:audit:table:nonDicomsStudyDate')"
prop="ImageDate"
>
<el-date-picker
v-model="noneDicomForm.ImageDate"
disabled
type="date"
:picker-options="pickerOption"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button
:disabled="btnLoading"
size="small"
type="primary"
@click="editNoneDicomVisible = false"
>
{{ $t("common:button:cancel") }}
</el-button>
<el-button
:loading="btnLoading"
size="small"
type="primary"
@click="handleUpdateNoneDicomInfo"
>
{{ $t("common:button:save") }}
</el-button>
</div>
</el-dialog>
<!-- 关闭质疑 -->
<el-dialog
v-if="closeQuestionVisible"
:visible.sync="closeQuestionVisible"
:close-on-click-modal="false"
append-to-body
custom-class="base-dialog-wrapper"
width="600px"
:title="$t('trials:qcQuality:dialogTitle:closeQuestion')"
>
<div
style="
padding: 10px;
border: 1px solid #e0e0e0;
max-height: 650px;
overflow-y: auto;
"
>
<el-form
ref="closeQuestionForm"
:model="closeQuestionForm"
size="small"
label-width="120px"
>
<el-form-item
:label="$t('trials:qcQuality:label:closeReason')"
prop="Type"
:rules="[
{ required: true, message: $t('common:ruleMessage:select') },
]"
>
<el-radio-group v-model="closeQuestionForm.Type">
<!-- 问题已解决 -->
<el-radio :label="1">{{
$t("trials:qcQuality:radio:reason1")
}}</el-radio>
<!-- 问题无法解决强制关闭质疑 -->
<el-radio :label="2">{{
$t("trials:qcQuality:radio:reason2")
}}</el-radio>
<!-- &lt;!&ndash; 其他 &ndash;&gt;-->
<!-- <el-radio :label="3">{{ $t('trials:qcQuality:radio:reason3') }}</el-radio>-->
</el-radio-group>
</el-form-item>
<el-form-item
v-if="closeQuestionForm.Type === 2"
:label="$t('trials:consistencyCheck:label:closereason')"
prop="Remake"
:rules="[
{ required: true, message: $t('common:ruleMessage:specify') },
]"
>
<el-input
v-model="closeQuestionForm.Remake"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
/>
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button
:disabled="closeBtnLoading"
size="small"
type="primary"
@click="closeQuestionVisible = false"
>
{{ $t("common:button:cancel") }}
</el-button>
<el-button
:loading="closeBtnLoading"
size="small"
type="primary"
@click="handleCloseQuestion"
>
{{ $t("common:button:save") }}
</el-button>
</div>
</el-dialog>
<!-- 预览单个图像 -->
<el-dialog
v-if="imgObj.visible"
:visible.sync="imgObj.visible"
:title="$t('trials:uploadNonDicoms:dialogTitle:preview')"
append-to-body
width="565px"
>
<div
v-loading="imgObj.loading"
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<el-image
:src="`${OSSclientConfig.basePath}${imgObj.url}`"
crossorigin="anonymous"
fit="fit"
style="height: 500px; width: 500px"
@error="imgObj.loading = false"
@load="imgObj.loading = false"
/>
</div>
</el-dialog>
</div>
<div class="function-wrapper">
<!-- 保存 -->
<el-button
:disabled="isAudit"
size="small"
type="primary"
round
@click="handleSave"
>
{{ $t("trials:audit:button:save") }}
</el-button>
<!-- 发质疑 -->
<el-button
:disabled="isAudit"
size="small"
type="primary"
round
@click="handleQC"
>
{{ $t("trials:audit:button:question") }}
</el-button>
<!-- 历史质疑 -->
<el-button size="small" type="primary" round @click="handleHistoryQC">
{{
`${$t("trials:audit:button:historicalQuestions")}(${
relationInfo.TotalChallengeCount !== undefined
? relationInfo.TotalChallengeCount
: 0
}, ${
relationInfo.NotClosedChallengeCount !== undefined
? relationInfo.NotClosedChallengeCount
: 0
})`
}}
</el-button>
<!-- 审核通过 -->
<el-button
:disabled="isAudit"
size="small"
type="primary"
round
@click="handleQCState(8)"
>
{{ $t("trials:audit:button:auditPassed") }}
</el-button>
<!-- 审核终止 -->
<!-- <el-button :disabled="isAudit" size="small" type="primary" round @click="handleQCState(7)">-->
<!-- {{ $t('trials:audit:button:auditFailed') }}-->
<!-- </el-button>-->
</div>
<!--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>
</div>
</template>
<script>
import {
collectNextIQCQuality,
getNextIQCQuality,
getVisitQCInfo,
getQCQuestionAnswerList,
getHistoryChallengeList,
getVisitQCStudyAndSeriesList,
getNoneDicomStudyList,
verifyCanQCPassedOrFailed,
verifyQCCanAddChallenge,
setSeriesStatus,
addOrUpdateNoneDicomStudy,
addOrUpdateQCQuestionAnswerList,
addOrUpdateQCChallenge,
closeQCChallenge,
updateModality,
getQCChallengeDialogList,
} from "@/api/trials";
import { qCPassedOrFailed } from "@/api/trials/visit";
import { getBasicDataSelects } from "@/api/dictionary/dictionary";
import ChatForm from "./chatForm";
import QuestionForm from "./questions";
import moment from "moment";
import ClinicalData from "./clinicalData";
import SignForm from "@/views/trials/components/newSignForm";
import { getToken } from "@/utils/auth";
import const_ from "@/const/sign-code";
import uploadPetClinicalData from "@/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue";
export default {
name: "QualityAssurance",
components: {
ChatForm,
ClinicalData,
QuestionForm,
SignForm,
uploadPetClinicalData,
},
props: {
data: {
type: Object,
default() {
return {};
},
},
disabled: {
type: Boolean,
default: false,
},
qType: {
type: Number,
default: 1,
},
},
data() {
return {
activeName: this.data.DicomStudyCount > 0 ? "dicom" : "none-dicom",
questionForm: {},
qCQuestionAnswerList: [],
studyList: [],
seriesList: [],
relationInfo: {},
noneDicomStudyList: [],
qcForm: {
subjectVisitId: "",
challengeType: "",
content: "",
actionContent: "",
deadlineTime: "",
qcContent: "",
},
qcVisible: false,
chatVisible: false,
loading: false,
btnLoading: false,
historyVisible: false,
historyList: [],
historyLoading: false,
editStudyInfoVisible: false,
studyForm: {
StudyCode: "",
IsDicomData: true,
Modalities: "",
BodyPartForEdit: [],
SeriesCount: null,
StudyTime: "",
},
currentQCRow: {},
isAudit: false, // 审核过之后功能按钮禁用标识
qcType: "",
trialBodyPartTypes: [],
trialModalitys: [],
signVisible: false,
signCode: "",
auditState: null,
currentNoneDicomId: "",
editNoneDicomVisible: false,
noneDicomForm: {
Id: "",
CodeView: "",
BodyParts: [],
Modality: "",
ImageDate: "",
},
subjectClinicalData: {},
moment,
currentQCType: null,
currentUser: zzSessionStorage.getItem("userName"),
pickerOption: {
disabledDate: (time) => {
return time.getTime() > Date.now();
},
},
isHaveFirstGiveMedicineDate: false,
baseDate: "",
upperLimit: "", // 超期上限
lowerLimit: "", // 超期下限
closeQuestionForm: {
Id: "",
SubjectVisitId: "",
Type: null,
Reason: "",
Remake: "",
},
closeBtnLoading: false,
closeQuestionVisible: false,
trialId: "",
dictionaryList: {},
currentSeriesIsReading: false,
currentSeriesIsDeleted: false,
imgObj: { url: "", visible: false, loading: false },
open: null,
existsManual: false,
// pet-ct临床数据
petVisible: false,
rowData: {},
IsHaveStudyClinicalData: false,
BodyPart: {},
};
},
async mounted() {
this.BodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId);
if (this.disabled) {
this.isAudit = true;
this.currentQCType = this.qType;
} else {
this.currentQCType = this.data.AuditState < 6 ? 1 : 2;
}
window.addEventListener("message", this.receiveMsg);
this.trialId = this.$route.query.trialId;
this.getQCInfo();
this.getDicData();
// this.handleViewImages()
// this.handleViewAllNoneDicoms()
},
beforeDestroy() {
if (this.open) {
this.open.close();
}
},
methods: {
// 获取QC界面基本信息
getQCInfo() {
this.loading = true;
getVisitQCInfo(this.data.Id, this.data.QCProcessEnum, this.currentQCType)
.then((res) => {
this.existsManual = res.Result.ExistsManual;
this.qCQuestionAnswerList = res.Result.QCQuestionAnswerList;
this.IsHaveStudyClinicalData = res.Result.IsHaveStudyClinicalData;
this.studyList = res.Result.StudyList;
this.seriesList = res.Result.SeriesList;
this.noneDicomStudyList = res.Result.NoneDicomStudyList;
this.relationInfo = res.Result.RelationInfo;
this.trialBodyPartTypes = this.relationInfo.TrialBodyPartTypes
? this.relationInfo.TrialBodyPartTypes.trim().split("|")
: [];
this.trialModalitys = this.relationInfo.TrialModalitys
? this.relationInfo.TrialModalitys.trim().split("|")
: [];
this.subjectClinicalData = res.Result.SubjectClinicalData;
this.baseDate = res.Result.RelationInfo.SubjectFirstGiveMedicineTime;
if (this.baseDate) {
const uDay =
res.Result.RelationInfo.VisitDay * 1 +
res.Result.RelationInfo.VisitWindowLeft * 1;
this.upperLimit = moment(this.baseDate, "YYYY-MM-DD")
.add(uDay, "days")
.format("YYYY-MM-DD");
const lDay =
res.Result.RelationInfo.VisitDay * 1 +
res.Result.RelationInfo.VisitWindowRight * 1;
this.lowerLimit = moment(this.baseDate, "YYYY-MM-DD")
.add(lDay, "days")
.format("YYYY-MM-DD");
}
this.isHaveFirstGiveMedicineDate =
res.Result.RelationInfo.IsHaveFirstGiveMedicineDate;
this.loading = false;
})
.catch(() => {
this.loading = false;
});
},
// 刷新审核问题列表
getCheckList() {
this.loading = true;
getQCQuestionAnswerList(
this.trialId,
this.data.Id,
this.data.QCProcessEnum,
this.currentQCType
)
.then((res) => {
this.loading = false;
res.Result.forEach((element, index) => {
// this.qCQuestionAnswerList
this.$set(this.qCQuestionAnswerList[index], "Id", element.Id);
});
})
.catch(() => {
this.loading = false;
});
},
// 保存审核问题
handleSave(isMessage) {
return new Promise((resolve) => {
this.$refs["questions"]
.submit()
.then((res) => {
var answerList = [];
res.forEach((item) => {
var index = this.qCQuestionAnswerList.findIndex(
(v) => v.TrialQCQuestionConfigureId === item.Id
);
if (index > -1) {
answerList.push({
id: this.qCQuestionAnswerList[index].Id,
answer: item.answer,
trialQCQuestionConfigureId: item.Id,
});
}
});
this.loading = true;
addOrUpdateQCQuestionAnswerList(
this.trialId,
this.data.Id,
this.data.QCProcessEnum,
this.currentQCType,
answerList
)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
if (isMessage !== true) {
this.$message.success(
this.$t("common:message:savedSuccessfully")
);
}
this.getCheckList();
resolve(true);
}
})
.catch(() => {
this.loading = false;
resolve(false);
});
})
.catch(() => {
this.loading = false;
resolve(false);
});
});
},
// 保存质疑
handleSaveQC() {
this.$refs["qcForm"].validate((valid) => {
if (!valid) return;
this.btnLoading = true;
this.qcForm.subjectVisitId = this.data.Id;
var contents = [];
var types = [];
var actions = [];
this.qcForm.qcContent.forEach((item) => {
if (item.isSelect) {
types.push(`${item.keyName}`);
var str = `${item.keyName} <br>`;
if (item.keyValue) {
// 问题总结
str = `${str}${this.$t("trials:audit:form:questionSummary")}${
item.keyValue
}<br>`;
}
if (item.actionContent) {
// 行动事项
actions.push(`${item.actionContent}`);
str = `${str}${this.$t("trials:audit:form:actionMatters")}${
item.actionContent
}<br>`;
}
contents.push(str);
}
});
if (contents.length === 0) {
// 质疑内容不能为空!
this.$alert(this.$t("trials:audit:message:qsContentIsNull"));
this.btnLoading = false;
return;
} else {
this.qcForm.content = contents.join("|");
this.qcForm.challengeType = types.join("|");
this.qcForm.actionContent = actions.join("|");
}
var params = {
challengeType: this.qcForm.challengeType,
subjectVisitId: this.qcForm.subjectVisitId,
content: this.qcForm.content,
actionContent: this.qcForm.actionContent,
reuploadEnum: 0,
deadlineTime: this.qcForm.deadlineTime,
};
addOrUpdateQCChallenge(
this.trialId,
this.data.QCProcessEnum,
this.currentQCType,
params
)
.then((res) => {
this.btnLoading = false;
if (res.IsSuccess) {
this.$message.success(
this.$t("common:message:savedSuccessfully")
);
this.qcVisible = false;
this.relationInfo.TotalChallengeCount++;
this.relationInfo.NotClosedChallengeCount++;
}
})
.catch(() => {
this.btnLoading = false;
});
});
},
// 打开发起质疑弹窗
handleQC() {
this.loading = true;
// 检验qc审核问题是否保存否则不允许发质疑
verifyQCCanAddChallenge(this.trialId, this.data.Id, this.currentQCType)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
this.renderQCForm();
}
})
.catch(() => {
this.loading = false;
});
},
handleQCVerify() {
this.loading = true;
return new Promise((resolve) => {
verifyQCCanAddChallenge(this.trialId, this.data.Id, this.currentQCType)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
resolve(true);
} else {
resolve(false);
}
})
.catch(() => {
this.loading = false;
resolve(false);
});
});
},
// 渲染发质疑窗口
renderQCForm() {
var contents = [];
const challengeType = this.dictionaryList["ChallengeType"];
challengeType.forEach((i) => {
contents.push({ keyName: i.Value, keyValue: "", isSelect: false });
});
var isHyperwindow = false;
if (this.isHaveFirstGiveMedicineDate && !!this.baseDate) {
isHyperwindow = this.isHyperwindow();
}
if (isHyperwindow) {
contents.push({
keyName: this.$t("trials:audit:message:qsOverWindow"),
keyValue: `${this.$t("trials:audit:message:qsOverWindow1")}${
this.upperLimit
}~${this.lowerLimit}${this.$t(
"trials:audit:message:qsOverWindow2"
)}${moment(this.relationInfo.EarliestScanDate).format(
"YYYY-MM-DD"
)}~${moment(this.relationInfo.LatestScanDate).format(
"YYYY-MM-DD"
)},${this.$t("trials:audit:message:qsOverWindow3")}`,
isSelect: false,
actionContent: this.$t("trials:audit:message:qsOverWindow4"),
});
}
this.qcForm.qcContent = contents;
const day = this.relationInfo.TrialChangeDefalutDays;
this.qcForm.deadlineTime = moment()
.add(day * 1, "days")
.format("YYYY-MM-DD HH:mm:ss");
this.qcVisible = true;
},
isHyperwindow() {
var isHyperwindow = false;
if (
this.relationInfo.EarliestScanDate < this.upperLimit ||
this.relationInfo.LatestScanDate > this.lowerLimit
) {
isHyperwindow = true;
}
return isHyperwindow;
},
// 获取字典数据
getDicData() {
getBasicDataSelects(["ChallengeType"]).then((res) => {
this.dictionaryList = { ...res.Result };
});
},
// 打开历史质疑弹窗
handleHistoryQC() {
this.historyVisible = true;
this.getHistoryInfo();
},
// 获取历史质疑记录
getHistoryInfo() {
this.historyLoading = true;
getHistoryChallengeList(
this.data.Id,
this.data.QCProcessEnum,
this.currentQCType
)
.then((res) => {
this.historyList = res.Result;
this.historyLoading = false;
})
.catch(() => {
this.historyLoading = false;
});
},
// 回复质疑
handleReply(row) {
this.historyLoading = true;
getQCChallengeDialogList(row.Id)
.then((res) => {
this.historyLoading = false;
if (res.IsSuccess) {
if (res.Result.length > 0) {
Object.assign(row, res.Result[0]);
}
this.currentQCRow = { ...row };
this.chatVisible = true;
}
})
.catch(() => {
this.historyLoading = false;
});
},
getDialogList() {
this.historyLoading = true;
getQCChallengeDialogList(this.currentQCRow.Id)
.then((res) => {
this.historyLoading = false;
if (res.IsSuccess && res.Result.length > 0) {
var i = this.historyList.findIndex(
(item) => item.Id === this.currentQCRow.Id
);
if (i > -1) {
this.currentQCRow = Object.assign(
this.historyList[i],
res.Result[0]
);
}
}
})
.catch(() => {
this.historyLoading = false;
});
},
// 关闭质疑
handleCloseQuestion() {
this.$refs["closeQuestionForm"].validate((valid) => {
if (!valid) return;
this.closeBtnLoading = true;
if (this.closeQuestionForm.Type === 1) {
// 问题已解决
this.closeQuestionForm.Reason = this.$t(
"trials:qcQuality:message:problemSolved"
);
} else if (this.closeQuestionForm.Type === 2) {
// 问题无法解决强制关闭质疑,已提醒中心下次注意
this.closeQuestionForm.Reason = `${this.$t(
"trials:qcQuality:message:problemNotSolved"
)}<br/><br/>${this.$t("trials:consistencyCheck:label:closereason")}:${
this.closeQuestionForm.Remake
}`;
}
var params = {
TrialId: this.data.TrialId,
QcChallengeId: this.closeQuestionForm.Id,
SubjectVisitId: this.data.Id,
CloseEnum: this.closeQuestionForm.Type,
CloseReason: this.closeQuestionForm.Reason,
};
closeQCChallenge(params)
.then((res) => {
this.closeBtnLoading = false;
if (res.IsSuccess) {
this.getHistoryInfo();
this.$message.success(
this.$t("trials:qcQuality:message:closedSuccessfully")
);
this.closeQuestionVisible = false;
this.relationInfo.NotClosedChallengeCount--;
}
})
.catch(() => {
this.closeBtnLoading = false;
});
});
},
// 打开关闭质疑框并初始化
handleCloseQC(row) {
this.closeQuestionForm = Object.assign(this.closeQuestionForm, row);
this.closeQuestionForm.CurrentQCType = this.currentQCType;
this.closeQuestionForm.AuditState = this.data.AuditState;
this.closeQuestionForm.TrialQCProcess = this.data.QCProcessEnum;
this.closeQuestionForm.Type = null;
this.closeQuestionForm.Reason = "";
this.closeQuestionForm.Remake = "";
this.closeQuestionVisible = true;
},
// 打开质疑记录弹窗
handleQCInfo(row) {
this.currentQCRow = { ...row };
this.chatVisible = true;
},
changeReadingStatus(callback, row) {
let statusStr = "";
if (callback) {
statusStr = this.$t("trials:audit:label:setSeriesReading");
row.IsReading = false;
} else {
statusStr = this.$t("trials:audit:label:setSeriesNotReading");
row.IsReading = true;
}
var message = this.$t("trials:audit:message:changeSeriesStatus").replace(
"xxx",
statusStr
);
message = message.replace("yyy", this.$fd("YesOrNo", !row.IsReading));
this.$confirm(message, {
distinguishCancelAndClose: true,
type: "warning",
})
.then(() => {
const state = row.IsReading ? 1 : 2;
this.loading = true;
setSeriesStatus(
this.trialId,
this.data.Id,
row.StudyId,
row.Id,
state
)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
this.$message.success(
this.$t("common:message:savedSuccessfully")
);
this.getStudyInfo();
}
})
.catch(() => {
this.loading = false;
});
})
.catch(() => {});
},
changeDeleteStatus(callback, row) {
let statusStr = "";
if (callback) {
statusStr = this.$t("trials:audit:label:setSeriesDeleted");
row.IsDeleted = false;
} else {
statusStr = this.$t("trials:audit:label:setSeriesNotDelete");
row.IsDeleted = true;
}
var message = this.$t("trials:audit:message:changeSeriesStatus").replace(
"xxx",
statusStr
);
message = message.replace("yyy", this.$fd("YesOrNo", !row.IsDeleted));
this.$confirm(message, {
distinguishCancelAndClose: true,
type: "warning",
})
.then(() => {
const state = row.IsDeleted ? 5 : 4;
this.loading = true;
setSeriesStatus(
this.trialId,
this.data.Id,
row.StudyId,
row.Id,
state
)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
this.$message.success(
this.$t("common:message:savedSuccessfully")
);
this.getStudyInfo();
}
})
.catch(() => {
this.loading = false;
});
})
.catch(() => {});
},
receiveMsg(event) {
if (event.data.type === "refreshSeriesList") {
this.getStudyInfo();
}
},
// 刷新检查新
getStudyInfo() {
this.loading = true;
getVisitQCStudyAndSeriesList(this.data.Id)
.then((res) => {
this.loading = false;
this.studyList = res.Result.StudyList;
this.seriesList = res.Result.SeriesList;
})
.catch(() => {
this.loading = false;
});
},
// 设置qc通过/不通过
async handleQCState(auditState) {
if (auditState === 7) {
this.signCode = this.getSignCode(auditState);
this.signVisible = true;
this.auditState = auditState;
return;
}
if (auditState === 8) {
var isgo = true;
var isgoList = [];
this.studyList.forEach((v) => {
if (!v.BodyPartForEdit) {
isgo = false;
isgoList.push(v.StudyCode);
}
});
if (!isgo) {
// `请补充检查${isgoList.toString()}的检查部位!`
this.$confirm(
this.$t("trials:qcQuality:title:title1").replace(
"xxx",
isgoList.join("、 ")
),
"",
{
showCancelButton: false,
}
);
return;
}
}
this.loading = true;
var isVerify = await this.handleSave(true);
if (!isVerify) {
return;
}
// 验证是否关闭所有质疑
verifyCanQCPassedOrFailed(this.trialId, this.data.Id)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
this.signCode = this.getSignCode(auditState);
this.signVisible = true;
this.auditState = auditState;
}
})
.catch(() => {
this.loading = false;
});
},
getSignCode(auditState) {
if (this.relationInfo.TrialQCProcessEnum === 1 && auditState === 8) {
// 单审通过
const { QCSingleReviewPassed } = const_.processSignature;
return QCSingleReviewPassed;
} else if (
this.relationInfo.TrialQCProcessEnum === 1 &&
auditState === 7
) {
// 单审不通过
const { QCSingleReviewFailed } = const_.processSignature;
return QCSingleReviewFailed;
} else if (
this.relationInfo.TrialQCProcessEnum === 2 &&
auditState === 8 &&
this.currentQCType === 1
) {
// 初审通过
const { PreliminaryReviewOfQCPassed } = const_.processSignature;
return PreliminaryReviewOfQCPassed;
} else if (
this.relationInfo.TrialQCProcessEnum === 2 &&
auditState === 7 &&
this.currentQCType === 1
) {
// 初审不通过
const { PreliminaryReviewOfQCFailed } = const_.processSignature;
return PreliminaryReviewOfQCFailed;
} else if (
this.relationInfo.TrialQCProcessEnum === 2 &&
auditState === 8 &&
this.currentQCType === 2
) {
// 复审通过
const { SecondaryReviewOfQCPassed } = const_.processSignature;
return SecondaryReviewOfQCPassed;
} else if (
this.relationInfo.TrialQCProcessEnum === 2 &&
auditState === 7 &&
this.currentQCType === 2
) {
// 复审不通过
const { SecondaryReviewOfQCFailed } = const_.processSignature;
return SecondaryReviewOfQCFailed;
}
},
// 关闭签名框
closeSignDialog(isSign, signInfo) {
if (isSign) {
this.setQCStatus(signInfo);
} else {
this.signVisible = false;
}
},
// 设置qc审核状态
async setQCStatus(signInfo) {
this.loading = true;
var params = {
data: {
TrialId: this.trialId,
SubjectVisitId: this.data.Id,
AuditState: this.auditState,
},
signInfo: signInfo,
};
qCPassedOrFailed(params)
.then((res) => {
this.loading = false;
if (res.IsSuccess) {
this.$refs["signForm"].btnLoading = false;
this.signVisible = false;
this.$message.success(this.$t("common:message:savedSuccessfully"));
// this.getQCInfo()
this.isAudit = true;
this.$forceUpdate();
getNextIQCQuality({
trialId: this.trialId,
SubjectId: this.data.SubjectId,
}).then((res) => {
if (res.Result && res.Result.VisitId) {
this.$confirm(
this.$t("trials:qcQuality:title:title2", "", {
showCancelButton: false,
})
).then(() => {
collectNextIQCQuality({
trialId: this.trialId,
SubjectId: this.data.SubjectId,
}).then((res) => {
this.$emit("getList");
this.$emit("nextTask", res.Result.VisitId);
});
});
} else {
// 没有后续质控任务
this.$emit("getList");
this.$confirm(this.$t("trials:qcQuality:title:closeQCDialog"))
.then(() => {
this.$emit("close");
})
.catch(() => {});
}
});
}
})
.catch(() => {
this.loading = false;
this.$refs["signForm"].btnLoading = false;
});
},
getNextQCInfo() {
// '是否确认进入下一个质控任务?'
var message = this.$t("trials:qcQuality:title:title2");
this.$confirm(message, {
type: "warning",
distinguishCancelAndClose: true,
})
.then(() => {
this.loading = true;
this.$emit("nextTask");
})
.catch((action) => {
this.loading = false;
});
},
// 设置已删除序列行样式
tableRowClassName({ row, rowIndex }) {
if (row.IsDeleted) {
return "delete-row";
} else {
return "";
}
},
// 打开检查信息编辑框
handleEditStudy(row) {
this.editStudyInfoVisible = true;
this.studyForm = { ...row };
var bodyPart = [];
if (this.studyForm.BodyPartForEdit.indexOf("|") !== -1) {
bodyPart = this.studyForm.BodyPartForEdit.split("|");
} else if (this.studyForm.BodyPartForEdit !== "") {
bodyPart.push(this.studyForm.BodyPartForEdit);
}
this.$set(this.studyForm, "Modality", row.ModalityForEdit);
// this.studyForm.Modality = row.ModalityForEdit
this.studyForm.BodyPartForEdit = bodyPart;
},
// 更新拍片部位/拍片类型信息
handleUpdateStudyInfo() {
this.$refs["studyForm"].validate((valid) => {
if (!valid) return;
this.btnLoading = true;
this.studyForm.BodyPart = this.studyForm.BodyPartForEdit.join("|");
// this.studyForm.Modality = this.studyForm.Modalities
var params = {
id: this.studyForm.StudyId,
subjectVisitId: this.data.Id,
type: 1,
modality: this.studyForm.Modality,
bodyPart: this.studyForm.BodyPart,
};
updateModality(this.data.TrialId, params)
.then((res) => {
this.btnLoading = false;
if (res.IsSuccess) {
this.getStudyInfo();
this.$message.success(
this.$t("common:message:savedSuccessfully")
);
this.editStudyInfoVisible = false;
}
})
.catch(() => {
this.btnLoading = false;
});
});
},
// 设置重传时刷新历史质疑列表及影响指控列表
refreshList() {
// 如果是复审时候设置重传,需要将当前审核状态设置为初审,且刷新页面数据并关闭历史质疑和质疑记录窗口
if (this.currentQCType === 2) {
this.currentQCType = 1;
// this.getQCInfo()
this.getHistoryInfo();
} else {
// 如果是初审时候设置重传,不影响
this.getHistoryInfo();
}
this.$emit("getList");
},
// 打开非Dicom信息编辑框
handleEditNoneDicomInfo(row) {
const { CodeView, Id, BodyPart, Modality, ImageDate } = { ...row };
this.noneDicomForm.CodeView = CodeView;
this.noneDicomForm.Id = Id;
this.noneDicomForm.BodyPart = BodyPart;
this.noneDicomForm.Modality = Modality;
this.noneDicomForm.ImageDate = ImageDate;
this.noneDicomForm.BodyParts = BodyPart.split(", ");
this.editNoneDicomVisible = true;
},
// 更新非Dicom部位/拍片类型信息
handleUpdateNoneDicomInfo() {
this.$refs.noneDicomForm.validate((valid) => {
if (!valid) return;
this.btnLoading = true;
this.noneDicomForm.BodyPart = this.noneDicomForm.BodyParts.join(", ");
this.noneDicomForm.TrialId = this.trialId;
this.noneDicomForm.TrialSiteId = this.data.TrialSiteId;
this.noneDicomForm.SubjectId = this.data.SubjectId;
this.noneDicomForm.SubjectVisitId = this.data.Id;
addOrUpdateNoneDicomStudy(this.noneDicomForm)
.then((res) => {
this.btnLoading = false;
if (res.IsSuccess) {
this.getNoneDicomList();
this.$message.success(
this.$t("common:message:savedSuccessfully")
);
this.editNoneDicomVisible = false;
}
})
.catch(() => {
this.btnLoading = false;
});
});
},
// 获取非Dicom检查信息
getNoneDicomList() {
this.loading = true;
getNoneDicomStudyList(this.data.Id)
.then((res) => {
this.noneDicomStudyList = res.Result;
this.loading = false;
})
.catch(() => {
this.loading = false;
});
},
// 预览文件
previewFile(row) {
// window.open(row.FullFilePath, '_blank')
this.imgObj.url = row.FullFilePath;
this.imgObj.loading = true;
this.imgObj.visible = true;
},
// 预览所有影像
handleViewImages() {
if (this.open) {
this.open.close();
}
var token = getToken();
const routeData = this.$router.resolve({
path: `/showvisitdicoms?trialId=${this.data.TrialId}&visitInfo=${
this.data.VisitName
}(${this.data.VisitNum})&subjectVisitId=${this.data.Id}&showDelete=${
this.isAudit ? 0 : 1
}&TokenKey=${token}`,
});
this.open = window.open(routeData.href, "_blank");
},
// 预览阅片影像
handleViewReadingImages() {
if (this.open) {
this.open.close();
}
var token = getToken();
const routeData = this.$router.resolve({
path: `/showvisitdicoms?trialId=${this.data.TrialId}&visitInfo=${this.data.VisitName}(${this.data.VisitNum})&subjectVisitId=${this.data.Id}&isReading=1&TokenKey=${token}`,
});
this.open = window.open(routeData.href, "_blank");
},
// 预览临床数据
handlePreviewClinicalData(row) {
this.rowData = row;
this.petVisible = true;
},
// 预览某个检查
handlePreviewStudy(row) {
if (this.open) {
this.open.close();
}
var token = getToken();
const routeData = this.$router.resolve({
path: `/showdicom?trialId=${this.trialId}&subjectVisitId=${
this.data.Id
}&studyId=${row.StudyId}&showDelete=${
this.isAudit ? 0 : 1
}&TokenKey=${token}&type=Study`,
});
this.open = window.open(routeData.href, "_blank");
},
// 预览某个序列
handlePreviewInstance(row) {
try {
if (this.open) {
this.open.close();
}
var token = getToken();
const routeData = this.$router.resolve({
path: `/showdicom?trialId=${this.trialId}&studyId=${
row.StudyId
}&studyCode=${row.StudyCode}&modality=${row.Modality}&seriesId=${
row.Id
}&seriesNumber=${row.SeriesNumber}&showDelete=${
this.isAudit ? 0 : 1
}&subjectVisitId=${
this.data.Id
}&type=Series&TokenKey=${token}&description=${row.Description}`,
});
this.open = window.open(routeData.href, "_blank");
} catch (e) {
console.log(e);
}
},
// 预览所有检查下非Dicom文件
handleViewAllNoneDicoms() {
if (this.open) {
this.open.close();
}
// this.previewAllNoneDicomVisible = true
var token = getToken();
const routeData = this.$router.resolve({
path: `/showNoneDicoms?subjectVisitId=${this.data.Id}&TokenKey=${token}`,
});
this.open = window.open(routeData.href, "_blank");
},
// 预览单个检查下非Dicom文件
handlePreviewNoneDicomFiles(row) {
if (this.open) {
this.open.close();
}
var token = getToken();
const routeData = this.$router.resolve({
path: `/showNoneDicoms?subjectVisitId=${this.data.Id}&studyId=${row.Id}&TokenKey=${token}`,
});
this.open = window.open(routeData.href, "_blank");
},
getBodyPart(bodyPart) {
if (!bodyPart) return "";
var separator = ",";
if (bodyPart.indexOf("|") > -1) {
separator = "|";
} else if (bodyPart.indexOf(",") > -1) {
separator = ",";
} else if (bodyPart.indexOf("") > -1) {
separator = "";
}
var arr = bodyPart.split(separator);
var newArr = arr.map((i) => {
return this.$fd("Bodypart", i.trim(), "Code", this.BodyPart, "Name");
});
return newArr.join(" | ");
},
openManuals() {
this.$emit("openManuals");
},
},
};
</script>
<style lang="scss" scoped>
.qa-wrapper {
display: flex;
flex-flow: column;
height: 100%;
border: 1px solid #fff;
padding: 10px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
.function-wrapper {
text-align: right;
}
.qa-content {
flex: 1;
margin-top: 10px;
overflow-y: auto;
}
/deep/ .delete-row {
text-decoration-line: line-through;
color: #c0c4cc;
}
/deep/ .el-card {
padding: 10px;
}
}
::v-deep .tip-i {
&::before {
color: #fff !important;
}
}
</style>