4 Commits

Author SHA1 Message Date
wangxiaoshuang e0321bae72 影像预览问题解决
continuous-integration/drone/push Build encountered an error
2025-04-12 12:04:20 +08:00
wangxiaoshuang 1e720e399d 确认收入项,修改选项后,其他文件也改了
continuous-integration/drone/push Build encountered an error
2025-04-03 11:15:54 +08:00
wangxiaoshuang 1368397da9 项目总览—>上传记录:中心编号 查询条件,查询结果不对 2025-04-03 11:15:36 +08:00
wangxiaoshuang c8c049b5d0 DICOM影像中,存在Tag最大像素值、最小像素值等,但是和实际的数据统计结果不同 2025-04-03 11:15:22 +08:00
126 changed files with 6295 additions and 22857 deletions
+1 -2
View File
@@ -5,8 +5,7 @@ NODE_ENV = 'development'
VUE_APP_BASE_PATH = '/'
VUE_APP_IS_TEST = false
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://onlyoffice.test.extimaging.com"
# base api
VUE_APP_BASE_API = 'http://123.56.94.154:7000'
-3
View File
@@ -5,9 +5,6 @@ NODE_ENV = 'prod'
# base public path
VUE_APP_BASE_PATH = '/'
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://office.extimaging.com"
# 是否开启登陆限制 true:是 false:否
VUE_APP_LOGIN_FOR_PERMISSION = true
-2
View File
@@ -3,8 +3,6 @@ ENV = 'production'
NODE_ENV = 'production'
# base public path
VUE_APP_BASE_PATH = '/'
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://onlyoffice.test.extimaging.com"
VUE_APP_IS_TEST = true
-3
View File
@@ -4,9 +4,6 @@ NODE_ENV = 'production'
# base public path
VUE_APP_BASE_PATH = '/'
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://onlyoffice.test.extimaging.com"
# base public path
VUE_APP_BASE_PATH = '/'
+2 -2
View File
@@ -252,7 +252,7 @@ export default {
}
},
handleSave() {
this.$confirm(this.$t("i18n:confirm:updatei18n"))
this.$confirm('确定修改当前页面国际化内容?')
.then(() => {
batchAddOrUpdateFrontInternationalization(this.tableData).then(
async (res) => {
@@ -270,7 +270,7 @@ export default {
i18n.mergeLocaleMessage('zh', zhMessages)
i18n.mergeLocaleMessage('en', enMessages)
this.drawer = false
this.$message.success(this.$t("i18n:message:updatei18nSuccessfully"))
this.$message.success('国际化修改成功')
if (this.il8nExternal) {
this.$EventBus.$emit('il8nUpdate')
}
+1 -37
View File
@@ -212,20 +212,7 @@ export function getSystemDocumentList(param) {
data: param
})
}
export function publishSystemDocument(param) {
return request({
url: `/SystemDocument/publishSystemDocument`,
method: 'post',
data: param
})
}
export function outLineSystemDocument(param) {
return request({
url: `/SystemDocument/outLineSystemDocument`,
method: 'post',
data: param
})
}
export function addOrUpdateSystemDocument(param) {
return request({
url: `/SystemDocument/addOrUpdateSystemDocument`,
@@ -233,29 +220,6 @@ export function addOrUpdateSystemDocument(param) {
data: param
})
}
// 新增/修改通用培训附件
export function addOrUpdateSystemDocumentAttachment(param) {
return request({
url: `/SystemDocument/addOrUpdateSystemDocumentAttachment`,
method: 'post',
data: param
})
}
// 通用培训附件列表
export function getSystemDocumentAttachmentList(param) {
return request({
url: `/SystemDocument/getSystemDocumentAttachmentList`,
method: 'post',
data: param
})
}
// 删除通用培训附件
export function deleteSystemDocumentAttachment(systemDocumentAttachmentId) {
return request({
url: `/SystemDocument/deleteSystemDocumentAttachment/${systemDocumentAttachmentId}`,
method: 'delete',
})
}
export function deleteSystemDocument(id) {
return request({
-9
View File
@@ -178,15 +178,6 @@ export function pMTrainingRecordList_Export(data) {
data
})
}
// 导出系统培训记录
export function getSysDocumentConfirmList_Export(data) {
return requestDownload({
url: `/ExcelExport/getSysDocumentConfirmList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出影像指控
export function qCVisitList_Export(data) {
return requestDownload({
+1 -130
View File
@@ -1035,27 +1035,7 @@ export function getQCVisitList(param) {
data: param
})
}
export function getImageBackList(param) {
return request({
url: `/QCList/getImageBackList`,
method: 'post',
data: param
})
}
export function getImageBackApplyUserList(params) {
return request({
url: `/QCList/getImageBackApplyUserList`,
method: 'get',
params
})
}
export function auditImageBack(params) {
return request({
url: `/QCOperation/auditImageBack`,
method: 'put',
params
})
}
export function getQCChallengeList(param) {
return request({
url: `/QCList/getQCChallengeList`,
@@ -1619,13 +1599,6 @@ export function getDocumentConfirmList(param) {
data: param
})
}
export function getSysDocumentConfirmList(param) {
return request({
url: `/TrialDocument/getSysDocumentConfirmList`,
method: 'post',
data: param
})
}
export function getTrialUserSelect(trialId) {
return request({
url: `/TrialDocument/getTrialUserSelect/${trialId}`,
@@ -1640,13 +1613,6 @@ export function getTrialDocAndSystemDocType(trialId) {
})
}
export function getSysDocSignUserList() {
return request({
url: `/TrialDocument/getSysDocSignUserList`,
method: 'get'
})
}
export function updateSubjectStatus(param) {
return request({
url: `/Subject/updateSubjectStatus`,
@@ -3342,13 +3308,6 @@ export function getReReadingApplyToBeDoneList(param) {
data: param
})
}
export function getPMImageBackToBeDoneList(param) {
return request({
url: `/PersonalWorkstation/getPMImageBackToBeDoneList`,
method: 'post',
data: param
})
}
export function deleteClinicalForm(param) {
return request({
@@ -4036,91 +3995,3 @@ export function deleteTrialFileType(id) {
})
}
// 工作台-获取稽查文档
export function getAuditDocumentData(data) {
return request({
url: `/AuditDocument/getAuditDocumentData`,
method: 'post',
data
})
}
// 工作台-新增稽查文档
export function addAuditDocument(data) {
return request({
url: `/AuditDocument/addAuditDocument`,
method: 'post',
data
})
}
// 工作台-获取当前目录层级
export function getBreadcrumbData(data) {
return request({
url: `/AuditDocument/getBreadcrumbData`,
method: 'post',
data
})
}
// 工作台-修改稽查文档
export function updateAuditDocument(data) {
return request({
url: `/AuditDocument/updateAuditDocument`,
method: 'post',
data
})
}
// 工作台-删除稽查文档
export function deleteAuditDocument(data) {
return request({
url: `/AuditDocument/deleteAuditDocument`,
method: 'post',
data
})
}
// 工作台-稽查文档获取历史版本
export function getHistoricalVersion(data) {
return request({
url: `/AuditDocument/getHistoricalVersion`,
method: 'post',
data
})
}
// 工作台-稽查文档设置当前版本
export function setCurrentVersion(data) {
return request({
url: `/AuditDocument/setCurrentVersion`,
method: 'post',
data
})
}
// 工作台-稽查文档移动
export function movieFileOrFolder(data) {
return request({
url: `/AuditDocument/movieFileOrFolder`,
method: 'post',
data
})
}
// 工作台-稽查文档复制
export function copyFileOrFolder(data) {
return request({
url: `/AuditDocument/copyFileOrFolder`,
method: 'post',
data
})
}
// 工作台-稽查文档授权
export function setIsAuthorization(data) {
return request({
url: `/AuditDocument/setIsAuthorization`,
method: 'post',
data
})
}
// 工作台-稽查文档新增文件夹
export function addFolder(data) {
return request({
url: `/AuditDocument/addFolder`,
method: 'post',
data
})
}
+2 -2
View File
@@ -346,9 +346,9 @@ export function getReReadingOrBackInfluenceTaskList(taskId, isReReading, applyId
})
}
export function PMSetTaskBack(trialId, taskId, pmBackReason) {
export function PMSetTaskBack(trialId, taskId) {
return request({
url: `/VisitTask/PMSetTaskBack/${trialId}/${taskId}/${pmBackReason}`,
url: `/VisitTask/PMSetTaskBack/${trialId}/${taskId}`,
method: 'put'
})
}
-8
View File
@@ -287,12 +287,4 @@ export function forwardSVDicomImage(param) {
data: param
})
}
// crc、iqc申请影像退回
export function requestImageBack(params) {
return request({
url: `/QCOperation/requestImageBack`,
method: 'put',
params
})
}
-8
View File
@@ -209,11 +209,3 @@ export function loginSelectUserRole(params) {
params,
})
}
// 忽略异地登录
export function setIsIgnoreUncommonly(data) {
return request({
url: `/User/setIsIgnoreUncommonly`,
method: 'post',
data,
})
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

+15 -28
View File
@@ -1,28 +1,28 @@
<template>
<div class="preview-wrapper">
<iframe v-if="fileType.indexOf('jpg') !== -1 || fileType.indexOf('png') !== -1" frameborder="0" :src="filePath"
width="100%" height="100%" />
<iframe
v-if="fileType.indexOf('jpg') !== -1 || fileType.indexOf('png') !== -1"
frameborder="0"
:src="filePath"
width="100%"
height="100%"
/>
<!-- <embed v-else-if="fileType.indexOf('pdf') !== -1" :src="filePath+'#toolbar=0'" style="width: 100%; height: 100%"> -->
<!-- <iframe v-else-if="fileType.indexOf('pdf') !== -1" :src="filePath+'#toolbar=0'" width="100%" height="100%" frameborder="0" /> -->
<iframe v-else-if="fileType.indexOf('pdf') !== -1"
:src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${filePath}?userName=${currentUser}&COMPANY=${COMPANY}`"
width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
<iframe v-else-if="fileType.indexOf('pdf') !== -1" :src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${filePath}?userName=${currentUser}&COMPANY=${COMPANY}`" width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
<!-- <pdf-->
<!-- v-else-if="fileType.indexOf('pdf') !== -1"-->
<!-- :src="`/static/pdfjs/web/viewer.html?file=${filePath}`">-->
<!-- </pdf>-->
<iframe v-else
:src="`/static/onlyOffice/viewer.html?url=${OSSclientConfig.basePath}${filePath}?onlyOffice_url=${onlyOffice_url}&type=${fileType}&title=${title}&documentType=${documentType}&userName=${currentUser}`"
width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
<!-- <div v-else>
<div v-else>
{{ $t('common:message:downloadFile') }}
<el-link type="primary" @click="downLoadFile">{{ $t('common:button:download') }}</el-link>
</div> -->
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import DOCUMENTTYPE from "@/utils/onlyOffice_type.js"
export default {
name: 'PreviewFile',
computed: {
@@ -36,23 +36,12 @@ export default {
fileType: {
type: String,
required: true
},
title: {
type: String,
default: ''
},
}
},
data() {
return {
currentUser: zzSessionStorage.getItem('userName'),
COMPANY: process.env.VUE_APP_COMPANY_NAME,
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL
}
},
computed: {
documentType() {
console.log(DOCUMENTTYPE[`.${this.fileType}`], 'documentType')
return DOCUMENTTYPE[`.${this.fileType}`]
COMPANY:process.env.VUE_APP_COMPANY_NAME
}
},
mounted() {
@@ -73,16 +62,14 @@ export default {
}
</script>
<style lang="scss">
.preview-wrapper {
.preview-wrapper{
height: 100%;
width: 100%;
width:100%;
padding: 10px;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
-23
View File
@@ -1,23 +0,0 @@
import Vue from "vue";
import OnlyOffice from "./index.vue";
const PreviewConstructor = Vue.extend(OnlyOffice);
const onlyOffice = options => {
const { path, type, title } = options;
if (!path) throw `path is requred.but ${path}`
const id = `OnlyOffice_${new Date().getTime()}`;
const instance = new PreviewConstructor();
instance.id = id;
instance.vm = instance.$mount();
if (instance.vm.visible) return;
document.body.appendChild(instance.vm.$el);
instance.vm.open(path, type, title);
instance.vm.$on("closed", () => {
instance.vm.docEditor = null
document.body.removeChild(instance.vm.$el);
instance.vm.$destroy();
});
return instance.vm;
}
export default onlyOffice;
@@ -1,7 +0,0 @@
import OnlyOffice from "./index.vue";
import onlyOffice from "./fun";
export default Vue => {
Vue.component(OnlyOffice.name, OnlyOffice);
Vue.prototype.$onlyOffice = onlyOffice;
};
@@ -1,46 +0,0 @@
<template>
<el-dialog v-if="visible" :visible.sync="visible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper" @close="handleClose">
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<iframe v-if="visible"
:src="`/static/onlyOffice/viewer.html?url=${OSSclientConfig.basePath}${path}?onlyOffice_url=${onlyOffice_url}&type=${type}&title=${title}&documentType=${documentType}&userName=${currentUser}`"
width="100%" height="99%" frameborder="0" crossorigin="anonymous" />
</div>
</el-dialog>
</template>
<script>
import DOCUMENTTYPE from "@/utils/onlyOffice_type.js"
export default {
name: "OnlyOffice",
data() {
return {
visible: false,
path: null,
type: null,
title: null,
documentType: null,
currentUser: zzSessionStorage.getItem('userName'),
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL
};
},
methods: {
open(path, type, title) {
this.path = path;
this.type = type.toLowerCase();
this.documentType = DOCUMENTTYPE[`.${this.type}`]
this.title = title;
this.visible = true;
},
handleClose() {
this.$emit("closed");
},
},
};
</script>
<style lang="scss" scoped>
#placeholder {
width: 100%;
height: 100%;
}
</style>
@@ -8,25 +8,61 @@
</div>
</div>
<!--检查列表-->
<el-table :data="list" style="width: 100%" v-adaptive="{ bottomOffset: 60 }" :loading="loading"
@sort-change="handleSortByColumn" :default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
<el-table
:data="list"
style="width: 100%"
v-adaptive="{ bottomOffset: 60 }"
:loading="loading"
@sort-change="handleSortByColumn"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }"
>
<!--受试者-->
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')" />
<el-table-column
prop="SubjectCode"
:label="$t('upload:nonedicom:table:subject')"
/>
<!--任务名称-->
<el-table-column prop="TaskBlindName" :label="$t('upload:nonedicom:table:taskName')" sortable="custom" />
<el-table-column
prop="TaskBlindName"
:label="$t('upload:nonedicom:table:taskName')"
sortable="custom"
/>
<!--检查类型-->
<el-table-column prop="Modality" :label="$t('upload:nonedicom:table:molityType')" sortable="custom">
<el-table-column
prop="Modality"
:label="$t('upload:nonedicom:table:molityType')"
sortable="custom"
>
</el-table-column>
<!--检查部位-->
<el-table-column prop="BodyPart" :label="$t('upload:nonedicom:table:bodyPart')" sortable="custom" />
<el-table-column
prop="BodyPart"
:label="$t('upload:nonedicom:table:bodyPart')"
sortable="custom"
/>
<!--原文件数-->
<el-table-column prop="FileCount" :label="$t('upload:nonedicom:table:fileCount')">
<el-table-column
prop="FileCount"
:label="$t('upload:nonedicom:table:fileCount')"
>
<template slot-scope="scope">
<el-popover v-if="scope.row.FileCount" trigger="click" placement="bottom">
<el-popover
v-if="scope.row.FileCount"
trigger="click"
placement="bottom"
>
<el-table :data="scope.row.FileList" height="300" size="small">
<!-- 文件名称 -->
<el-table-column prop="FileName" :label="$t('trials:audit:table:nonDicomsFileName')" width="200" />
<el-table-column prop="FileSize" :label="$t('trials:audit:table:nonDicomsFileSize')" width="100">
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column
prop="FileSize"
:label="$t('trials:audit:table:nonDicomsFileSize')"
width="100"
>
<template slot-scope="scope">
<span>{{
scope.row.FileSize && scope.row.FileSize > 0
@@ -38,13 +74,27 @@
<el-table-column :label="$t('common:action:action')" width="120">
<template slot-scope="files">
<!-- 预览 -->
<viewer :ref="files.row.Path" style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]">
<el-button circle icon="el-icon-view" :title="$t('upload:nonedicom:button:preview')" :disabled="files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
" @click.native.prevent="previewFile(files.row)" />
<img v-show="false" crossorigin="anonymous" :src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image" />
<viewer
:ref="files.row.Path"
style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]"
>
<el-button
circle
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
:disabled="
files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
"
@click.native.prevent="previewFile(files.row)"
/>
<img
v-show="false"
crossorigin="anonymous"
:src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image"
/>
</viewer>
</template>
</el-table-column>
@@ -59,13 +109,32 @@
</template>
</el-table-column>
<!--后处理文件数-->
<el-table-column prop="UploadedFileCount" :label="$t('upload:nonedicom:table:uploadFileCount')">
<el-table-column
prop="UploadedFileCount"
:label="$t('upload:nonedicom:table:uploadFileCount')"
>
<template slot-scope="scope">
<el-popover v-if="scope.row.UploadedFileCount" trigger="click" placement="bottom">
<el-table :data="scope.row.UploadedFileList" height="300" size="small">
<el-popover
v-if="scope.row.UploadedFileCount"
trigger="click"
placement="bottom"
>
<el-table
:data="scope.row.UploadedFileList"
height="300"
size="small"
>
<!-- 文件名称 -->
<el-table-column prop="FileName" :label="$t('trials:audit:table:nonDicomsFileName')" width="200" />
<el-table-column prop="FileSize" :label="$t('trials:audit:table:nonDicomsFileSize')" width="100">
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column
prop="FileSize"
:label="$t('trials:audit:table:nonDicomsFileSize')"
width="100"
>
<template slot-scope="scope">
<span>{{
scope.row.FileSize && scope.row.FileSize > 0
@@ -77,13 +146,27 @@
<el-table-column :label="$t('common:action:action')" width="120">
<template slot-scope="files">
<!-- 预览 -->
<viewer :ref="files.row.Path" style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]">
<el-button circle icon="el-icon-view" :title="$t('upload:nonedicom:button:preview')" :disabled="files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
" @click.native.prevent="previewFile(files.row)" />
<img v-show="false" crossorigin="anonymous" :src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image" />
<viewer
:ref="files.row.Path"
style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]"
>
<el-button
circle
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
:disabled="
files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
"
@click.native.prevent="previewFile(files.row)"
/>
<img
v-show="false"
crossorigin="anonymous"
:src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image"
/>
</viewer>
</template>
</el-table-column>
@@ -97,34 +180,75 @@
<span v-else>{{ scope.row.UploadedFileCount }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')" fixed="right" width="180">
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="180"
>
<template slot-scope="scope">
<!--预览--->
<el-button circle :disabled="scope.row.UploadedFileCount <= 0" icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')" @click.stop="handlePreviewNoneDicomFiles(scope.row)" />
<el-button
circle
:disabled="scope.row.UploadedFileCount <= 0"
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
@click.stop="handlePreviewNoneDicomFiles(scope.row)"
/>
<!--上传--->
<el-button circle icon="el-icon-upload2" :title="$t('upload:nonedicom:button:upload')"
@click.native.prevent="handleUpload(scope.row)" />
<el-button
circle
icon="el-icon-upload2"
:title="$t('upload:nonedicom:button:upload')"
@click.native.prevent="handleUpload(scope.row)"
/>
<!--删除--->
<el-button :disabled="scope.row.UploadedFileCount <= 0 ||
scope.row.ReadingTaskState === 2
" circle icon="el-icon-delete" :title="$t('upload:nonedicom:button:delete')"
@click.stop="remove(scope.row)" />
<el-button
:disabled="
scope.row.UploadedFileCount <= 0 ||
scope.row.ReadingTaskState === 2
"
circle
icon="el-icon-delete"
:title="$t('upload:nonedicom:button:delete')"
@click.stop="remove(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<!-- 预览单个图像 -->
<el-dialog v-if="imgObj.visible" :visible.sync="imgObj.visible" :title="$t('upload:nonedicom: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" />
<el-dialog
v-if="imgObj.visible"
:visible.sync="imgObj.visible"
:title="$t('upload:nonedicom: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>
<!-- 上传非dicom文件 -->
<el-dialog v-if="uploadVisible" :visible.sync="uploadVisible" :close-on-click-modal="false"
:title="$t('trials:uploadNonDicoms:dialogTitle:upload')" width="800px" append-to-body
custom-class="base-dialog-wrapper" @close="resetFileDiaolg">
<el-dialog
v-if="uploadVisible"
:visible.sync="uploadVisible"
:close-on-click-modal="false"
:title="$t('trials:uploadNonDicoms:dialogTitle:upload')"
width="800px"
append-to-body
custom-class="base-dialog-wrapper"
@close="resetFileDiaolg"
>
<!-- 多文件上传 -->
<form id="inputForm" ref="uploadForm">
<el-divider content-position="left">{{
@@ -132,15 +256,33 @@
}}</el-divider>
<div class="form-group">
<div class="upload" style="margin-right: 10px">
<input multiple="multiple" webkitdirectory="" directory accept="*/*" type="file" name="uploadFolder"
class="select-file" title="" @change="beginScanFiles($event)" v-if="!btnLoading" />
<input
multiple="multiple"
webkitdirectory=""
directory
accept="*/*"
type="file"
name="uploadFolder"
class="select-file"
title=""
@change="beginScanFiles($event)"
v-if="!btnLoading"
/>
<div class="btn-select">
{{ $t('trials:uploadNonDicoms:button:selectFolder') }}
</div>
</div>
<div class="upload">
<input class="select-file" multiple="" :accept="faccept.join(',')" type="file" name="uploadFile" title=""
@change="beginScanFiles($event)" v-if="!btnLoading" />
<input
class="select-file"
multiple=""
:accept="faccept.join(',')"
type="file"
name="uploadFile"
title=""
@change="beginScanFiles($event)"
v-if="!btnLoading"
/>
<div class="btn-select">
{{ $t('trials:uploadNonDicoms:button:select') }}
</div>
@@ -151,46 +293,82 @@
</div>
</form>
<!-- 文件列表 -->
<el-table ref="filesTable" :data="fileList" class="dicomFiles-table" height="300"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="(row, index) => row.status !== 2 && !btnLoading" />
<el-table
ref="filesTable"
:data="fileList"
class="dicomFiles-table"
height="300"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
:selectable="(row, index) => row.status !== 2 && !btnLoading"
/>
<el-table-column type="index" width="50" />
<!-- 文件名称 -->
<el-table-column prop="name" :label="$t('trials:uploadNonDicoms:table:fileName')" min-width="100" />
<el-table-column
prop="name"
:label="$t('trials:uploadNonDicoms:table:fileName')"
min-width="100"
/>
<!-- 文件大小 -->
<el-table-column prop="size" :label="$t('trials:uploadNonDicoms:table:fileSize')">
<el-table-column
prop="size"
:label="$t('trials:uploadNonDicoms:table:fileSize')"
>
<template slot-scope="scope">
<span>{{
scope.row.size && scope.row.size > 0
? `${(scope.row.size / 1024 / 1024).toFixed(3)}MB`
: '0MB'
: ''
}}</span>
</template>
</el-table-column>
<!-- 文件类型 -->
<el-table-column prop="type" :label="$t('trials:uploadNonDicoms:table:fileType')" />
<el-table-column
prop="type"
:label="$t('trials:uploadNonDicoms:table:fileType')"
/>
<!-- 上传状态 -->
<el-table-column prop="status" :label="$t('trials:uploadNonDicoms:table:uploadStatus')" min-width="100">
<el-table-column
prop="status"
:label="$t('trials:uploadNonDicoms:table:uploadStatus')"
min-width="100"
>
<template slot-scope="scope">
<el-tag :type="['warning', 'info', 'success', 'danger'][scope.row.status]"
v-if="scope.row.status || scope.row.status === 0">{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
<el-tag
:type="['warning', 'info', 'success', 'danger'][scope.row.status]"
v-if="scope.row.status || scope.row.status === 0"
>{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('trials:uploadNonDicoms:table:failedFileCount')" min-width="150"
show-overflow-tooltip>
<el-table-column
:label="$t('trials:uploadNonDicoms:table:failedFileCount')"
min-width="150"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-progress color="#409eff" :percentage="scope.row.size && scope.row.size > 0 ? ((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
1
: ((scope.row.uploadFileSize * 100) / 1).toFixed(2) *
1
" />
<el-progress
color="#409eff"
:percentage="
((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
1
"
/>
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<el-button size="mini" icon="el-icon-delete" circle :disabled="btnLoading"
:title="$t('trials:crcUpload:action:delete')" @click="handleRemoveFile(scope.row)" />
<el-button
size="mini"
icon="el-icon-delete"
circle
:disabled="btnLoading"
:title="$t('trials:crcUpload:action:delete')"
@click="handleRemoveFile(scope.row)"
/>
</template>
</el-table-column>
</el-table>
@@ -198,8 +376,13 @@
<span style="margin-right: 10px">{{
$store.state.trials.uploadTip
}}</span>
<el-button size="small" type="primary" :disabled="selectArr.length == 0" :loading="btnLoading"
@click="beginUpload">
<el-button
size="small"
type="primary"
:disabled="selectArr.length == 0"
:loading="btnLoading"
@click="beginUpload"
>
{{ $t('trials:uploadNonDicoms:action:upload') }}
</el-button>
</div>
@@ -405,7 +588,7 @@ export default {
)
}
})
.catch(() => { })
.catch(() => {})
},
resetUploadForm() {
this.$nextTick(() => {
@@ -531,10 +714,11 @@ export default {
if (!this.uploadVisible) return
let file = this.fileList.filter((item) => item.id === arr[index].id)[0]
file.status = 1
let path = `/${this.$route.query.trialId}/TaskImage/${this.currentRow.SubjectId
}/${this.currentRow.VisitTaskId}/${this.$guid()}${file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
let path = `/${this.$route.query.trialId}/TaskImage/${
this.currentRow.SubjectId
}/${this.currentRow.VisitTaskId}/${this.$guid()}${file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
file.curPath = path
const fileData = await this.fileToBlob(file.file)
let res = await this.fileToOss(path, fileData, file)
@@ -588,7 +772,7 @@ export default {
(percentage, checkpoint, lastPer) => {
item.uploadFileSize += checkpoint.size * (percentage - lastPer)
if (item.uploadFileSize > file.fileSize) {
item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1
item.uploadFileSize = file.fileSize
}
}
)
@@ -685,7 +869,6 @@ export default {
.top {
margin: 10px 0;
}
.upload {
display: inline-block;
height: 30px;
@@ -700,7 +883,6 @@ export default {
background: #428bca;
border-color: #428bca;
color: #fff;
.select-file {
height: 30px;
width: 90px;
@@ -711,7 +893,6 @@ export default {
opacity: 0;
font-size: 0;
}
.btn-select {
//给显示在页面上的按钮写样式
width: 90px;
@@ -727,12 +908,10 @@ export default {
pointer-events: none; //pointer-events:none用来控制该标签的点击穿透事件
}
}
.tip {
display: flex;
align-items: flex-start;
margin-top: 5px;
i {
margin: 3px 5px 0 0;
}
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 26 KiB

-7
View File
@@ -54,8 +54,6 @@ import upload from '@/components/element-ui/upload'
Vue.use(upload)
import Preview from '@/components/Preview/index'
Vue.use(Preview)
import Onlyoffice from '@/components/Preview_onlyoffice/index'
Vue.use(Onlyoffice)
import MFA from '@/components/MFA/index'
Vue.use(MFA)
import FB from '@/components/feedBack/index'
@@ -310,11 +308,6 @@ async function VueInit() {
text = text.replace(test, item.TrialName)
})
}
let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo'))
if(CompanyInfo&&CompanyInfo.SystemShortName){
let test = new RegExp('IRC', 'ig')
text = text.replace(test, CompanyInfo.SystemShortName)
}
// return i18n.t(key)
return text;
}
-6
View File
@@ -68,12 +68,6 @@ body .el-table th.gutter {
}
}
.text-ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.el-loading-mask {
background-color: rgba(255, 255, 255, 0.5);
}
+137 -10
View File
@@ -39,6 +39,108 @@ function getNumberValues(dataSet, tag, minimumLength) {
return values;
}
function getLutDescriptor(dataSet, tag) {
if (!dataSet.elements[tag] || dataSet.elements[tag].length !== 6) {
return;
}
return [
dataSet.uint16(tag, 0),
dataSet.uint16(tag, 1),
dataSet.uint16(tag, 2),
];
}
function getLutData(lutDataSet, tag, lutDescriptor) {
const lut = [];
const lutData = lutDataSet.elements[tag];
for (let i = 0; i < lutDescriptor[0]; i++) {
// Output range is always unsigned
if (lutDescriptor[2] === 16) {
lut[i] = lutDataSet.uint16(tag, i);
} else {
lut[i] = lutDataSet.byteArray[i + lutData.dataOffset];
}
}
return lut;
}
function populateSmallestLargestPixelValues(dataSet, imagePixelModule) {
const pixelRepresentation = dataSet.uint16('x00280103');
if (pixelRepresentation === 0) {
imagePixelModule.smallestPixelValue = dataSet.uint16('x00280106');
imagePixelModule.largestPixelValue = dataSet.uint16('x00280107');
} else {
imagePixelModule.smallestPixelValue = dataSet.int16('x00280106');
imagePixelModule.largestPixelValue = dataSet.int16('x00280107');
}
imagePixelModule.largestPixelValue = imagePixelModule.largestPixelValue === 0 ? undefined : imagePixelModule.largestPixelValue;
}
function populatePaletteColorLut(dataSet, imagePixelModule) {
imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281101'
);
imagePixelModule.greenPaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281102'
);
imagePixelModule.bluePaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281103'
);
// The first Palette Color Lookup Table Descriptor value is the number of entries in the lookup table.
// When the number of table entries is equal to 2ˆ16 then this value shall be 0.
// See http://dicom.nema.org/MEDICAL/DICOM/current/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.5
if (imagePixelModule.redPaletteColorLookupTableDescriptor[0] === 0) {
imagePixelModule.redPaletteColorLookupTableDescriptor[0] = 65536;
imagePixelModule.greenPaletteColorLookupTableDescriptor[0] = 65536;
imagePixelModule.bluePaletteColorLookupTableDescriptor[0] = 65536;
}
// The third Palette Color Lookup Table Descriptor value specifies the number of bits for each entry in the Lookup Table Data.
// It shall take the value of 8 or 16.
// The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1.
// The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors.
//
// Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits;
// this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry.
// The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16.
const numLutEntries =
imagePixelModule.redPaletteColorLookupTableDescriptor[0];
const lutData = dataSet.elements.x00281201;
const lutBitsAllocated = lutData.length === numLutEntries ? 8 : 16;
// If the descriptors do not appear to have the correct values, correct them
if (
imagePixelModule.redPaletteColorLookupTableDescriptor[2] !==
lutBitsAllocated
) {
imagePixelModule.redPaletteColorLookupTableDescriptor[2] = lutBitsAllocated;
imagePixelModule.greenPaletteColorLookupTableDescriptor[2] =
lutBitsAllocated;
imagePixelModule.bluePaletteColorLookupTableDescriptor[2] =
lutBitsAllocated;
}
imagePixelModule.redPaletteColorLookupTableData = getLutData(
dataSet,
'x00281201',
imagePixelModule.redPaletteColorLookupTableDescriptor
);
imagePixelModule.greenPaletteColorLookupTableData = getLutData(
dataSet,
'x00281202',
imagePixelModule.greenPaletteColorLookupTableDescriptor
);
imagePixelModule.bluePaletteColorLookupTableData = getLutData(
dataSet,
'x00281203',
imagePixelModule.bluePaletteColorLookupTableDescriptor
);
}
function metaDataProvider(type, imageId) {
const parsedImageId = parseImageId(imageId);
const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(parsedImageId.url);
@@ -100,7 +202,7 @@ function metaDataProvider(type, imageId) {
};
}
if (type === 'imagePixelModule') {
return {
const imagePixelModule = {
samplesPerPixel: dataSet.uint16('x00280002'),
photometricInterpretation: dataSet.string('x00280004'),
rows: dataSet.uint16('x00280010'),
@@ -110,16 +212,41 @@ function metaDataProvider(type, imageId) {
highBit: dataSet.uint16('x00280102'),
pixelRepresentation: dataSet.uint16('x00280103'),
planarConfiguration: dataSet.uint16('x00280006'),
pixelAspectRatio: dataSet.uint16('x00280034'),
smallestPixelValue: null,
largestPixelValue: null,
redPaletteColorLookupTableDescriptor: dataSet.string('x00281101'),
greenPaletteColorLookupTableDescriptor: dataSet.string('x00281102'),
bluePaletteColorLookupTableDescriptor: dataSet.string('x00281103'),
redPaletteColorLookupTableData: dataSet.string('x00281201'),
greenPaletteColorLookupTableData: dataSet.string('x00281202'),
bluePaletteColorLookupTableData: dataSet.string('x00281203')
pixelAspectRatio: dataSet.string('x00280034'),
};
populateSmallestLargestPixelValues(dataSet, imagePixelModule);
if (
imagePixelModule.photometricInterpretation === 'PALETTE COLOR' &&
dataSet.elements.x00281101
) {
populatePaletteColorLut(dataSet, imagePixelModule);
}
return imagePixelModule;
}
// if (type === 'imagePixelModule') {
// return {
// samplesPerPixel: dataSet.uint16('x00280002'),
// photometricInterpretation: dataSet.string('x00280004'),
// rows: dataSet.uint16('x00280010'),
// columns: dataSet.uint16('x00280011'),
// bitsAllocated: dataSet.uint16('x00280100'),
// bitsStored: dataSet.uint16('x00280101'),
// highBit: dataSet.uint16('x00280102'),
// pixelRepresentation: dataSet.uint16('x00280103'),
// planarConfiguration: dataSet.uint16('x00280006'),
// pixelAspectRatio: dataSet.uint16('x00280034'),
// smallestPixelValue: null,
// largestPixelValue: null,
// // smallestPixelValue: dataSet.uint16('x00280106'),
// // largestPixelValue: dataSet.uint16('x00280107'),
// redPaletteColorLookupTableDescriptor: dataSet.string('x00281101'),
// greenPaletteColorLookupTableDescriptor: dataSet.string('x00281102'),
// bluePaletteColorLookupTableDescriptor: dataSet.string('x00281103'),
// redPaletteColorLookupTableData: dataSet.string('x00281201'),
// greenPaletteColorLookupTableData: dataSet.string('x00281202'),
// bluePaletteColorLookupTableData: dataSet.string('x00281203')
// }
// }
}
export default metaDataProvider;
-66
View File
@@ -1,66 +0,0 @@
let TYPES = ['word', 'cell', 'slide', 'pdf']
let DOCUMENTTYPE = {
'.doc': TYPES[0],
'.docm': TYPES[0],
'.docx': TYPES[0],
'.dot': TYPES[0],
'.dotm': TYPES[0],
'.dotx': TYPES[0],
'.epub': TYPES[0],
'.fb2': TYPES[0],
'.fodt': TYPES[0],
'.htm': TYPES[0],
'.html': TYPES[0],
'.mht': TYPES[0],
'.mhtml': TYPES[0],
'.odt': TYPES[0],
'.ott': TYPES[0],
'.pages': TYPES[0],
'.rtf': TYPES[0],
'.stw': TYPES[0],
'.sxw': TYPES[0],
'.txt': TYPES[0],
'.wps': TYPES[0],
'.wpt': TYPES[0],
'.xml': TYPES[0],
'.csv': TYPES[1],
'.et': TYPES[1],
'.ett': TYPES[1],
'.fods': TYPES[1],
'.numbers': TYPES[1],
'.ods': TYPES[1],
'.ots': TYPES[1],
'.sxc': TYPES[1],
'.xls': TYPES[1],
'.xlsb': TYPES[1],
'.xlsm': TYPES[1],
'.xlsx': TYPES[1],
'.xlt': TYPES[1],
'.xltm': TYPES[1],
'.xltx': TYPES[1],
'.xml': TYPES[1],
'.dps': TYPES[2],
'.dpt': TYPES[2],
'.fodp': TYPES[2],
'.key': TYPES[2],
'.odp': TYPES[2],
'.otp': TYPES[2],
'.pot': TYPES[2],
'.potm': TYPES[2],
'.potx': TYPES[2],
'.pps': TYPES[2],
'.ppsm': TYPES[2],
'.ppsx': TYPES[2],
'.ppt': TYPES[2],
'.pptm': TYPES[2],
'.pptx': TYPES[2],
'.sxi': TYPES[2],
'.djvu': TYPES[3],
'.docxf': TYPES[3],
'.oform': TYPES[3],
'.oxps': TYPES[3],
'.pdf': TYPES[3],
'.xps': TYPES[3]
}
export default DOCUMENTTYPE
-2
View File
@@ -21,8 +21,6 @@ service.interceptors.request.use(
async config => {
path = router && router.app && router.app._route && router.app._route.path
config.headers['Content-Type'] = 'application/json;charset=UTF-8'
// config.baseURL = process.env.NODE_ENV === 'prod' ? "https://api.irc.extimaging.com" : '/api'
config.headers['Self-Referer'] = window.location.href
var language = zzSessionStorage.getItem('lang')
config.headers['Accept-Language'] = language === 'en' ? 'en-US,en;q=0.5' : 'zh-CN,zh;q=0.9'
config.headers['TimeZoneId'] = moment.tz.guess()
@@ -1,45 +1,100 @@
<template>
<el-form ref="sysAttachmentFrom" v-loading="loading" :model="form" label-width="190px" size="small" :rules="rules"
class="upload-temporary-file">
<el-form
ref="sysAttachmentFrom"
v-loading="loading"
:model="form"
label-width="190px"
size="small"
:rules="rules"
class="upload-temporary-file"
>
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:signature:form:FileTypeId')" prop="FileTypeId">
<el-select v-model="form.FileTypeId" style="width: 100%" size="small" filterable>
<el-option v-for="item of dictionaryList.Sys_Document" :key="item.Id" :label="item.Value" :value="item.Id" />
<el-form-item
:label="$t('dictionary:signature:form:FileTypeId')"
prop="FileTypeId"
>
<el-select
v-model="form.FileTypeId"
style="width: 100%"
size="small"
filterable
>
<el-option
v-for="item of dictionaryList.Sys_Document"
:key="item.Id"
:label="item.Value"
:value="item.Id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:File')">
<div class="upload-container">
<el-upload class="upload-demo" action accept=".pdf" :before-upload="beforeUpload"
:http-request="handleUploadFile" :on-preview="handlePreview" :on-remove="handleRemoveFile"
:show-file-list="true" :file-list="fileList" :limit="1" :on-exceed="handleExceed"
:disabled="form.Type === ''">
<el-button size="small" type="primary" :disabled="form.FileTypeId === ''" :loading="btnLoading">{{
$t('common:button:check') }}</el-button>
<el-upload
class="upload-demo"
action
accept=".pdf"
:before-upload="beforeUpload"
:http-request="handleUploadFile"
:on-preview="handlePreview"
:on-remove="handleRemoveFile"
:show-file-list="true"
:file-list="fileList"
:limit="1"
:on-exceed="handleExceed"
:disabled="form.Type === ''"
>
<el-button
size="small"
type="primary"
:disabled="form.FileTypeId === ''"
:loading="btnLoading"
>{{ $t('common:button:check') }}</el-button
>
<span slot="tip" style="margin-left: 10px" class="el-upload__tip">
({{ $t('trials:signature:label:mustBepdf') }})
</span>
</el-upload>
</div>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:NeedConfirmedUserTypeIdList')"
prop="NeedConfirmedUserTypeIdList">
<el-select v-model="form.NeedConfirmedUserTypeIdList" style="width: 100%" multiple>
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName" :value="item.Id" />
<el-form-item
:label="$t('dictionary:signature:form:NeedConfirmedUserTypeIdList')"
prop="NeedConfirmedUserTypeIdList"
>
<el-select
v-model="form.NeedConfirmedUserTypeIdList"
style="width: 100%"
multiple
>
<el-option
v-for="item of userTypeOptions"
:key="item.Id"
:label="item.UserTypeShortName"
:value="item.Id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:DocUserSignType')" prop="DocUserSignType">
<el-switch v-model="form.DocUserSignType" :active-value="1" :inactive-value="0">
<el-form-item
:label="$t('dictionary:signature:form:DocUserSignType')"
prop="DocUserSignType"
>
<el-switch
v-model="form.DocUserSignType"
:active-value="1"
:inactive-value="0"
>
</el-switch>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:SignViewMinimumMinutes')" prop="SignViewMinimumMinutes">
<el-input-number v-model="form.SignViewMinimumMinutes" controls-position="right" :min="1" :max="50" />
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:CurrentStaffTrainDays')" prop="CurrentStaffTrainDays">
<el-input-number v-model="form.CurrentStaffTrainDays" controls-position="right" :min="0" :max="1000" />
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:NewStaffTrainDays')" prop="NewStaffTrainDays">
<el-input-number v-model="form.NewStaffTrainDays" controls-position="right" :min="0" :max="1000" />
<el-form-item
:label="$t('dictionary:signature:form:SignViewMinimumMinutes')"
prop="SignViewMinimumMinutes"
>
<el-input-number
v-model="form.SignViewMinimumMinutes"
controls-position="right"
:min="1"
:max="50"
/>
</el-form-item>
<!-- <el-form-item v-if="form.Id !== ''" label="是否废除: ">
<el-radio-group v-model="form.IsDeleted">
@@ -50,8 +105,14 @@
</div>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
<el-form-item style="text-align: right">
<el-button size="small" type="primary" :disabled="form.FileTypeId === '' || form.Name === ''"
:loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save') }}</el-button>
<el-button
size="small"
type="primary"
:disabled="form.FileTypeId === '' || form.Name === ''"
:loading="saveBtnLoading"
@click="handleSave"
>{{ $t('common:button:save') }}</el-button
>
</el-form-item>
</div>
</el-form>
@@ -77,12 +138,9 @@ export default {
FileTypeId: '',
Name: '',
Path: '',
IsPublish: false,
IsDeleted: true,
IsDeleted: false,
SignViewMinimumMinutes: null,
DocUserSignType: 0,
CurrentStaffTrainDays: 1,
NewStaffTrainDays: 14,
},
rules: {
FileTypeId: [
@@ -138,11 +196,8 @@ export default {
this.form.Name = this.data.Name
this.form.Path = this.data.Path
this.form.IsDeleted = this.data.IsDeleted
this.form.IsPublish = this.data.IsPublish
this.form.SignViewMinimumMinutes = this.data.SignViewMinimumMinutes
this.form.DocUserSignType = this.data.DocUserSignType
this.form.CurrentStaffTrainDays = this.data.CurrentStaffTrainDays
this.form.NewStaffTrainDays = this.data.NewStaffTrainDays
}
this.loading = false
},
@@ -152,7 +207,7 @@ export default {
.then((res) => {
this.dictionaryList = { ...res.Result }
})
.catch(() => { })
.catch(() => {})
},
// 获取用户类型下拉数据
getUserType() {
@@ -250,16 +305,13 @@ export default {
width: 80px;
height: 40px;
}
.upload-container .el-input--small {
margin-bottom: 5px;
}
.upload-container .el-icon-circle-check {
color: #428bca;
font-size: 13px;
}
.account_item_clear {
.el-tag__close {
display: none !important;
@@ -1,223 +0,0 @@
<template>
<el-form ref="attachmentFrom" v-loading="loading" :model="form" label-width="190px" size="small" :rules="rules"
class="upload-temporary-file">
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:signature:form:FileName')" prop="Name">
<el-input v-model="form.Name" clearable></el-input>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:OffLine')" prop="OffLine">
<el-switch v-model="form.OffLine" :active-value="true" :inactive-value="false"
:active-text="$fd('YesOrNo', true)" :inactive-text="$fd('YesOrNo', false)">
</el-switch>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:File')">
<div class="upload-container">
<el-upload class="upload-demo" action :accept="this.accept.join(',')" :before-upload="beforeUpload"
:http-request="handleUploadFile" :on-preview="handlePreview" :on-remove="handleRemoveFile"
:show-file-list="true" :file-list="fileList" :limit="1" :on-exceed="handleExceed">
<el-button size="small" type="primary" :loading="btnLoading">{{ $t('common:button:check')
}}</el-button>
<span slot="tip" style="margin-left: 10px" class="el-upload__tip">
({{ $t('trials:signature:label:type').replace("xxx", this.accept.join(", ")) }})
</span>
</el-upload>
</div>
</el-form-item>
</div>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
<el-form-item style="text-align: right">
<el-button size="small" type="primary" :disabled="form.FileTypeId === '' || form.Name === ''"
:loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save') }}</el-button>
</el-form-item>
</div>
</el-form>
</template>
<script>
import { addOrUpdateSystemDocumentAttachment } from '@/api/dictionary'
export default {
props: {
data: {
type: Object,
default() {
return {}
},
},
SystemDocumentId: {
type: String,
default: ''
}
},
data() {
return {
form: {
Id: '',
Name: null,
FileFormat: null,
FileName: null,
FilePath: null,
FileSize: null,
OffLine: false,
SystemDocumentId: null,
},
rules: {
Name: [
{
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: ['change'],
},
],
},
fileList: [],
btnLoading: false,
saveBtnLoading: false,
loading: false,
accept: ['.jpg',
'.jpeg',
'.png',
'.pdf',
'.ppt',
'.pptx',
'.doc',
'.docx',
'.xls',
'.xlsx']
}
},
mounted() {
this.initForm()
},
methods: {
async initForm() {
this.loading = true
if (this.data && this.data.Id) {
Object.keys(this.form).forEach(key => {
this.form[key] = this.data[key]
})
this.fileList = [
{
name: this.data.FileName,
url: this.data.FilePath,
path: this.data.FilePath,
},
]
}
this.loading = false
},
beforeUpload(file) {
// 检测文件类型是否符合要求
if (this.checkFileSuffix(file.name)) {
this.fileList = []
return true
} else {
this.$alert(this.$t('trials:signature:label:type').replace("xxx", this.accept.join(", ")))
return false
}
},
async handleUploadFile(param) {
this.loading = true
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(
`/System/DocumentToSign/${param.file.name}${new Date().getTime()}`,
file
)
this.fileList.push({
name: param.file.name,
path: this.$getObjectName(res.url),
url: this.$getObjectName(res.url),
})
this.form.Name = param.file.name
this.form.FileName = param.file.name
this.form.FilePath = this.$getObjectName(res.url)
this.form.FileSize = param.file.size
this.form.FileFormat = param.file.name
.substring(param.file.name.lastIndexOf('.'))
.toLocaleLowerCase().split('.')[1]
this.loading = false
},
handleSave() {
this.$refs.attachmentFrom.validate((valid) => {
if (!valid) return false
if (!this.form.FilePath)
return this.$alert(this.$t('trials:signature:message:selectFile'))
this.saveBtnLoading = true
if (this.SystemDocumentId) this.form.SystemDocumentId = this.SystemDocumentId
addOrUpdateSystemDocumentAttachment(this.form)
.then((res) => {
this.saveBtnLoading = false
this.$emit('closeDialog')
this.$emit('getList')
this.$message.success(this.$t('common:message:updatedSuccessfully'))
})
.catch(() => {
this.saveBtnLoading = false
})
})
},
handleRemoveFile() {
this.fileList = []
this.form.FilePath = ''
this.form.FileSize = ''
this.form.FileFormat = ''
this.form.FileName = ''
},
handlePreview(file) {
if (file.fullPath) {
window.open(file.fullPath, '_blank')
}
},
handleExceed(files, fileList) {
this.$message.warning(this.$t('upload:rule:maxFile1'))
},
checkFileSuffix(fileName) {
var typeArr = [
'jpg',
'jpeg',
'png',
'pdf',
'ppt',
'pptx',
'doc',
'docx',
'xls',
'xlsx',
]
var extendName = fileName
.substring(fileName.lastIndexOf('.') + 1)
.toLocaleLowerCase()
if (typeArr.indexOf(extendName) !== -1) {
return true
} else {
return false
}
},
},
}
</script>
<style lang="scss">
.upload-temporary-file {
.upload-container .el-upload--text {
border: none;
width: 80px;
height: 40px;
}
.upload-container .el-input--small {
margin-bottom: 5px;
}
.upload-container .el-icon-circle-check {
color: #428bca;
font-size: 13px;
}
.account_item_clear {
.el-tag__close {
display: none !important;
}
}
}
</style>
@@ -1,258 +0,0 @@
<template>
<div v-if="config.visible">
<base-model :config="config">
<template slot="dialog-body">
<el-form ref="form" :model="rowData" label-width="80px" style="width: 80%;display: inline-block;">
<el-form-item :label="`${$t('dictionary:signature:table:Name')}: `">
<span class="name text-ellipsis" :title="rowData.Name">{{ rowData.Name }}</span>
</el-form-item>
</el-form>
<el-button size="mini" type="primary" style="float:right" @click.stop="edit({})" v-if="!isView">
{{ $t('common:button:add') }}</el-button>
<el-table :data="list" style="width: 100%" max-height="300px" v-loading="loading"
@sort-change="handleSortByColumn">
<el-table-column type="index" width="60" />
<el-table-column prop="Name" :label="$t('dictionary:signature:attachmentList:FileName')"
sortable="custom" />
<el-table-column prop="OffLine" :label="$t('dictionary:signature:attachmentList:OffLine')"
sortable="custom" v-if="!isView">
<template slot-scope="scope">
<el-switch v-model="scope.row.OffLine" @change="(val) => OffLine(scope.row, val)"
:active-value="true" :inactive-value="false" :active-text="$fd('YesOrNo', true)"
:inactive-text="$fd('YesOrNo', false)">
</el-switch>
</template>
</el-table-column>
<el-table-column prop="CreateTime" :label="$t('dictionary:signature:attachmentList:CreateTime')"
sortable="custom" />
<el-table-column :label="$t('common:action:action')" min-width="120px">
<template slot-scope="scope">
<el-button size="mini" type="text" @click.stop="preview(scope.row)">
{{ $t('common:button:preview') }}
</el-button>
<el-button size="mini" type="text" @click.stop="edit(scope.row)" v-if="!isView">
{{ $t('common:button:edit') }}
</el-button>
<!-- <el-button size="mini" type="text" @click.stop="OffLine(scope.row, true)"
:disabled="scope.row.OffLine">
{{ $t('dictionary:signature:attachmentList:OffLine') }}
</el-button> -->
<el-button size="mini" type="text" @click.stop="del(scope.row)" v-if="!isView">
{{ $t('common:button:delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增/编辑附件 -->
<el-dialog :visible.sync="visible" :close-on-click-modal="false" :append-to-body="true" :title="title"
width="800px" custom-class="base-dialog-wrapper">
<attachmentForm v-if="visible" :data="rowData" :SystemDocumentId="SystemDocumentId"
@closeDialog="closeDialog" @getList="getAllList" />
</el-dialog>
</template>
</base-model>
<viewer ref="picture_perview2" style="margin: 0 10px"
v-if="rowData.FileFormat && ['png', 'jpg', 'jpeg'].includes(rowData.FileFormat.toLowerCase())"
:images="[`${OSSclientConfig.basePath}${rowData.FilePath}`]" :options="viewerOptions">
<img v-show="false" :src="`${OSSclientConfig.basePath}${rowData.FilePath}`" alt="Image" />
</viewer>
<!-- <attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible"
v-if="perview_visible" /> -->
</div>
</template>
<script>
import BaseModel from '@/components/BaseModel'
import attachmentForm from './attachmentForm'
// import attachmentPreview from './attachmentPreview'
import { addOrUpdateSystemDocumentAttachment, getSystemDocumentAttachmentList, deleteSystemDocumentAttachment } from '@/api/dictionary'
const defaultSearchData = () => {
return {
PageIndex: 1,
PageSize: 1000,
Asc: false,
OffLine: null,
SortField: null
}
}
export default {
components: {
BaseModel,
attachmentForm,
// attachmentPreview
},
props: {
config: {
type: Object,
default: () => {
return {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
}
}
},
isView: {
type: Boolean,
default: false
},
rowData: {
type: Object,
default: () => {
return {}
}
},
SystemDocumentId: {
type: String,
default: ''
}
},
data() {
return {
searchData: defaultSearchData(),
visible: false,
title: null,
list: [],
rowData: {},
loading: false,
viewerOptions: {
toolbar: {
zoomIn: true,
zoomOut: true,
reset: true,
prev: false,
next: false,
rotateLeft: true,
rotateRight: true,
flipHorizontal: true,
flipVertical: true,
}
},
// perview_visible: false
}
},
watch: {
SystemDocumentId: {
handler() {
this.getList()
},
immediate: true,
}
},
methods: {
closeDialog() {
this.visible = false
},
getAllList() {
this.getList()
this.$emit("getList")
},
async del(row) {
try {
let confirm = await this.$confirm(this.$t("dictionary:signature:attachmentList:message:del"))
if (!confirm) return false
this.loading = true
let res = await deleteSystemDocumentAttachment(row.Id)
this.loading = false
if (res.IsSuccess) {
this.getAllList()
}
} catch (err) {
console.log(err)
this.loading = false
}
},
edit(row) {
this.title = this.$t('dictionary:signature:attachmentForm:title:update')
if (!row.Id) {
this.title = this.$t('dictionary:signature:attachmentForm:title:add')
}
this.rowData = Object.assign({}, row)
this.visible = true
},
async getList() {
try {
if (!this.SystemDocumentId) return false
this.loading = true
this.searchData.SystemDocumentId = this.SystemDocumentId
if (this.isView) {
this.searchData.OffLine = false
}
let res = await getSystemDocumentAttachmentList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result.CurrentPageData
}
} catch (err) {
this.loading = false
console.log(err)
}
},
async OffLine(row, val) {
try {
let data = Object.assign({}, row)
data.OffLine = val
this.loading = true
let res = await addOrUpdateSystemDocumentAttachment(data)
this.loading = false
if (res.IsSuccess) {
this.$t('dictionary:signature:attachmentList:updateSuccessfully')
this.getList()
}
} catch (err) {
this.loading = false
row.OffLine = !row.OffLine
console.log(err)
}
},
preview(data) {
// return this.perview_visible = true
this.rowData = Object.assign({}, data)
if (['.ppt',
'.pptx',
'.doc',
'.docx',
'.xls',
'.xlsx'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$onlyOffice({
path: data.FilePath,
type: data.FileFormat,
title: data.Name
})
}
if (['.jpg',
'.jpeg',
'.png'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$nextTick(() => {
this.$refs['picture_perview2'].$viewer.show()
})
}
if (['.pdf'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$preview({
path: data.Path || data.FilePath,
type: 'pdf',
title: data.Name,
})
}
},
// 排序
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
}
}
</script>
<style lang="scss" scoped>
.name {
display: block;
width: 90%;
}
</style>
@@ -1,312 +0,0 @@
<template>
<el-dialog :visible.sync="visible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper" :before-close="handleClose">
<div v-loading="loading" class="img-container" v-if="visible">
<el-card class="box-card left">
<div class="title">
{{ $t('dictionary:signature:fileList') }}
</div>
<div class="left-content">
<!-- 检查层级 -->
<div id="imgList" style="height: 100%; overflow: hidden">
<template v-for="(item, index) in list">
<div :id="`img${item.Id}`" :key="item.Id" :class="{
'is-boxActive': item.Id === rowData.Id,
}" class="img-box" @click="selected(item)">
<div class="file-image">
<el-image v-if="
[
'jpeg',
'jpg',
'png',
].includes(item.FileFormat)
" style="width: 100%; height: 100%"
:src="`${OSSclientConfig.basePath}${item.FilePath}?x-oss-process=image/resize,w_50,h_50/format,png`"
fit="contain" crossorigin="anonymous" />
<el-image v-else style="width: 100%; height: 100%" :src="getsrc(item.FileFormat)"
fit="contain" crossorigin="anonymous" />
</div>
<div v-if="item.Name.length < 15" class="img-text">
{{ `${index + 1}. ${item.Name}` }}
</div>
<el-tooltip v-else :content="item.Name" placement="bottom">
<div class="img-text">
{{ `${index + 1}. ${item.Name}` }}
</div>
</el-tooltip>
</div>
</template>
</div>
</div>
</el-card>
<!-- 预览图像 -->
<el-card class="box-card right">
<div style="width: 100%; height: 100%" v-if="[
'jpeg',
'jpg',
'png',
].includes(rowData.FileFormat)">
<imageViewer :rowData="rowData" />
</div>
<div style="width: 100%; height: 100%" v-else>
<PreviewFile v-if='rowData.FilePath' :file-path="rowData.FilePath" :file-type="rowData.FileFormat"
:title="rowData.Name" />
</div>
</el-card>
<!-- <el-card class="box-card" style="width:300px;height:100%;padding: 10px;margin-left:10px;">
<CheckForm />
</el-card> -->
</div>
</el-dialog>
</template>
<script>
import pdf from '@/assets/file_icon/pdf.png'
import zip from '@/assets/file_icon/zip.png'
import doc from '@/assets/file_icon/doc.png'
import docx from '@/assets/file_icon/docx.png'
import ppt from '@/assets/file_icon/ppt.png'
import pptx from '@/assets/file_icon/pptx.png'
import xls from '@/assets/file_icon/xls.png'
import xlsx from '@/assets/file_icon/xlsx.png'
import PreviewFile from '@/components/PreviewFile'
import imageViewer from './image-viewer'
import { getSystemDocumentAttachmentList } from '@/api/dictionary'
const defaultSearchData = () => {
return {
PageIndex: 1,
PageSize: 1000,
Asc: false,
OffLine: null,
SortField: null
}
}
export default {
name: 'Notice',
components: {
PreviewFile,
imageViewer
},
props: {
SystemDocumentId: {
type: String,
default: ''
},
visible: {
type: Boolean,
default: false
},
isView: {
type: Boolean,
default: false
}
},
data() {
return {
pdf,
zip,
doc,
docx,
ppt,
pptx,
xls,
xlsx,
rowData: {},
list: [],
searchData: defaultSearchData(),
title: this.$t('dictionary:signature:fileList')
}
},
watch: {
SystemDocumentId: {
handler() {
this.getList()
},
immediate: true,
}
},
methods: {
getsrc(type) {
return this[type.toLowerCase()]
},
selected(row) {
this.rowData = row
},
handleClose() {
this.$emit("update:visible", false)
},
async getList() {
try {
if (!this.SystemDocumentId) return false
this.loading = true
this.searchData.SystemDocumentId = this.SystemDocumentId
if (this.isView) {
this.searchData.OffLine = false
}
let res = await getSystemDocumentAttachmentList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result.CurrentPageData
this.rowData = this.list[0] || {}
}
} catch (err) {
this.loading = false
console.log(err)
}
},
},
}
</script>
<style lang="scss" scoped>
.img-container {
position: relative;
width: 100%;
height: 100%;
padding: 10px;
display: flex;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
::v-deep .el-card__body {
padding: 0px;
}
}
.study-desc {
padding: 10px 5px;
line-height: 20px;
background-color: #d5d5d5;
font-weight: 500;
}
.left {
width: 220px;
height: 100%;
::v-deep .el-card__body {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.title {
height: 40px;
line-height: 40px;
border: 1ppx solid;
border: 1px solid #ebe7e7;
padding-left: 10px;
background-color: #4e4e4e;
color: #ffffff;
}
.left-content {
flex: 1;
overflow-y: auto;
}
// ::v-deep .el-tabs{
// height: 100%;
// }
// ::v-deep .el-tabs__header{
// height: 40px;
// }
// ::v-deep .el-tabs__content{
// flex: 1;
// overflow-y: auto;
// padding: 0;
// }
.img-box {
// position: relative;
display: inline-block;
box-sizing: border-box;
border-bottom: 2px solid #f3f3f3;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: flex-start;
padding: 5px 10px;
cursor: pointer;
// margin-bottom: 5px;
padding-left: 5px;
}
.img-text {
display: inline-block;
width: calc(100% - 60px);
margin-left: 5px;
height: 50px;
line-height: 50px;
overflow: hidden;
text-overflow: ellipsis;
/* 用省略号表示溢出的文本 */
white-space: nowrap;
}
.img-box:nth-last-child(1) {
margin-bottom: 0px;
}
.is-boxActive {
// border-color: #409eff;
color: #409eff;
}
.is-boxActiv:after {
opacity: 0;
}
}
.right {
flex: 1;
height: 100%;
margin-left: 10px;
::v-deep .el-card__body {
height: 100%;
width: 100%;
}
}
.switchBox {
width: 100%;
margin: 5px 0;
color: #4e4e4e;
.item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 5px;
}
}
.file-image {
width: 50px;
height: 50px;
}
::v-deep .el-collapse-item__header {
background-color: #d5d5d5;
}
::v-deep .el-collapse-item__header {
min-height: 48px;
height: auto;
}
::v-deep .el-collapse-item__content {
padding-bottom: 0;
}
</style>
@@ -1,381 +0,0 @@
/* eslint-disable no-unused-vars */
<template>
<div style="width: 100%; height: 100%">
<transition name="viewer-fade">
<div ref="image-viewer__wrapper" tabindex="-1" class="image-viewer__wrapper" :style="{ 'z-index': 5 }">
<!-- Arrow -->
<!-- 工具栏 -->
<div class="image-viewer__btn image-viewer__actions">
<div class="image-viewer__actions__inner">
<i class="el-icon-zoom-out" @click="handleActions('zoomOut')" />
<i class="el-icon-zoom-in" @click="handleActions('zoomIn')" />
<i class="el-image-viewer__actions__divider" />
<i class="el-icon-c-scale-to-original" @click="toggleMode" />
<i class="el-image-viewer__actions__divider" />
<i class="el-icon-refresh-left" @click="handleActions('anticlocelise')" />
<i class="el-icon-refresh-right" @click="handleActions('clocelise')" />
</div>
</div>
<!-- 图片 -->
<div id="image-viewer__canvas" class="image-viewer__canvas">
<img crossorigin="anonymous" :src="`${OSSclientConfig.basePath}${rowData.FilePath}`
" :style="imgStyle" style="max-width: 100%; max-height: 100%" @load="handleImgLoad" @error="handleImgError"
@mousedown="handleMouseDown" />
</div>
</div>
</transition>
</div>
</template>
<script>
import { on, off } from 'element-ui/src/utils/dom'
import { rafThrottle, isFirefox } from 'element-ui/src/utils/util'
const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
export default {
name: 'ImageViewer',
props: {
onSwitch: {
type: Function,
default: () => { },
},
onClose: {
type: Function,
default: () => { },
},
rowData:{
type: Object,
default: () => {
return {}
},
}
},
data() {
return {
loading: false,
transform: {
scale: 1,
deg: 0,
offsetX: 0,
offsetY: 0,
enableTransition: false,
},
}
},
computed: {
imgStyle() {
const { scale, deg, offsetX, offsetY, enableTransition } = this.transform
const style = {
transform: `scale(${scale}) rotate(${deg}deg)`,
transition: enableTransition ? 'transform .3s' : '',
'margin-left': `${offsetX}px`,
'margin-top': `${offsetY}px`,
}
return style
},
},
mounted() {
document.getElementById('image-viewer__canvas').onmousewheel = (event) => {
if (event.deltaY > 0) {
// 缩小
this.handleActions('zoomOut', {
zoomRate: 0.015,
enableTransition: false,
})
} else {
// 放大
this.handleActions('zoomIn', {
zoomRate: 0.015,
enableTransition: false,
})
}
return false
}
this.deviceSupportInstall()
},
methods: {
hide() {
this.deviceSupportUninstall()
this.onClose()
},
deviceSupportInstall() {
this._keyDownHandler = (e) => {
e.stopPropagation()
const keyCode = e.keyCode
switch (keyCode) {
// ESC
case 27:
this.hide()
break
// SPACE
case 32:
this.toggleMode()
break
// LEFT_ARROW
case 37:
this.prev()
break
// UP_ARROW
case 38:
this.handleActions('zoomIn')
break
// RIGHT_ARROW
case 39:
this.next()
break
// DOWN_ARROW
case 40:
this.handleActions('zoomOut')
break
}
}
this._mouseWheelHandler = rafThrottle((e) => {
const delta = e.wheelDelta ? e.wheelDelta : -e.detail
if (delta > 0) {
this.handleActions('zoomIn', {
zoomRate: 0.015,
enableTransition: false,
})
} else {
this.handleActions('zoomOut', {
zoomRate: 0.015,
enableTransition: false,
})
}
})
on(document, 'keydown', this._keyDownHandler)
on(document, mousewheelEventName, null)
// on(document, mousewheelEventName, this._mouseWheelHandler)
},
deviceSupportUninstall() {
off(document, 'keydown', this._keyDownHandler)
off(document, mousewheelEventName, this._mouseWheelHandler)
this._keyDownHandler = null
this._mouseWheelHandler = null
},
handleImgLoad(e) {
this.loading = false
},
handleImgError(e) {
this.loading = false
e.target.alt = '加载失败'
},
handleMouseDown(e) {
if (this.loading || e.button !== 0) return
const { offsetX, offsetY } = this.transform
const startX = e.pageX
const startY = e.pageY
this._dragHandler = rafThrottle((ev) => {
this.transform.offsetX = offsetX + ev.pageX - startX
this.transform.offsetY = offsetY + ev.pageY - startY
})
on(document, 'mousemove', this._dragHandler)
on(document, 'mouseup', (ev) => {
off(document, 'mousemove', this._dragHandler)
})
e.preventDefault()
},
reset() {
this.transform = {
scale: 1,
deg: 0,
offsetX: 0,
offsetY: 0,
enableTransition: false,
}
},
toggleMode() {
if (this.loading) return
this.reset()
},
handleActions(action, options = {}) {
if (this.loading) return
const { zoomRate, rotateDeg, enableTransition } = {
zoomRate: 0.2,
rotateDeg: 90,
enableTransition: true,
...options,
}
const { transform } = this
switch (action) {
case 'zoomOut':
if (transform.scale > 0.2) {
transform.scale = parseFloat(
(transform.scale - zoomRate).toFixed(3)
)
}
break
case 'zoomIn':
if (transform.scale < 5) {
transform.scale = parseFloat(
(transform.scale + zoomRate).toFixed(3)
)
}
break
case 'clocelise':
transform.deg += rotateDeg
break
case 'anticlocelise':
transform.deg -= rotateDeg
break
}
transform.enableTransition = enableTransition
},
},
}
</script>
<style lang="scss" scoped>
.image-viewer__wrapper {
position: relative;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
.image-viewer__btn {
position: absolute;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
opacity: 0.8;
cursor: pointer;
box-sizing: border-box;
user-select: none;
}
.image-viewer__close {
display: none;
top: 40px;
right: 40px;
width: 40px;
height: 40px;
font-size: 40px;
}
.image-viewer_desc {
position: absolute;
top: 40px;
left: 40px;
font-size: 15px;
padding: 5px;
height: 30px;
width: 70px;
line-height: 20px;
text-align: center;
color: #fff;
background-color: #606266;
border-color: #fff;
z-index: 1;
border-radius: 17px;
// border-radius: 2%;
}
.image-viewer__canvas {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.image-viewer__actions {
left: 50%;
bottom: 30px;
transform: translateX(-50%);
width: 282px;
height: 44px;
padding: 0 23px;
background-color: #606266;
border-color: #fff;
border-radius: 22px;
}
.image-viewer__actions__inner {
width: 100%;
height: 100%;
text-align: justify;
cursor: default;
font-size: 23px;
color: #fff;
display: flex;
align-items: center;
justify-content: space-around;
}
.image-viewer__next,
.image-viewer__prev {
top: 50%;
width: 44px;
height: 44px;
font-size: 24px;
color: #fff;
background-color: #606266;
border-color: #fff;
}
.image-viewer__prev {
transform: translateY(-50%);
left: 40px;
}
.image-viewer__next {
transform: translateY(-50%);
right: 40px;
text-indent: 2px;
}
.image-viewer__mask {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0.5;
// background:#000
}
.viewer-fade-enter-active {
animation: viewer-fade-in 0.3s;
}
.viewer-fade-leave-active {
animation: viewer-fade-out 0.3s;
}
@keyframes viewer-fade-in {
0% {
transform: translate3d(0, -20px, 0);
opacity: 0;
}
100% {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}
@keyframes viewer-fade-out {
0% {
transform: translate3d(0, 0, 0);
opacity: 1;
}
100% {
transform: translate3d(0, -20px, 0);
opacity: 0;
}
}
</style>
@@ -1,103 +1,80 @@
<template>
<BaseContainer>
<template slot="title-container">
<el-row v-if="isSystem" style="width: 100%;">
<el-col :span="12">
<h3>{{ TITLE }}</h3>
</el-col>
<el-col :span="12" style="text-align:right;">
<h3>
<Pagination class="page" :total="total" :page.sync="searchData.pageIndex" :limit.sync="searchData.pageSize"
layout="total, sizes, prev, pager, next" :background="false" style="display: inline-block;"
@pagination="getList" />
<el-button icon="el-icon-refresh-left" size="small" circle :title="$t('common:button:reset')"
@click="handleReset" />
</h3>
</el-col>
</el-row>
</template>
<template slot="search-container">
<el-form :inline="true" size="small">
<el-form-item :label="$t('dictionary:signature:search:FileTypeId')">
<el-select v-model="searchData.FileTypeId" style="width: 150px" clearable>
<el-option v-for="item of $d.Sys_Document" :key="item.id" :label="item.label" :value="item.id" />
<el-select v-model="searchData.FileTypeId" style="width: 150px">
<el-option
v-for="item of dict.type.Sys_Document"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:search:Name')">
<el-input v-model="searchData.Name" style="width: 130px" clearable />
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:NeedConfirmedUserTypes')">
<el-select v-model="searchData.UserTypeId" style="width: 150px" clearable>
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName"
:value="item.Id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:IsDeleted')">
<el-select v-model="searchData.IsDeleted" style="width: 150px" clearable>
<el-option v-for="item of $d.TrainingStatus" :key="item.id" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:DocUserSignType')">
<el-select v-model="searchData.DocUserSignType" style="width: 150px" clearable>
<el-option v-for="item of $d.ReadingYesOrNo" :key="item.id" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:createTime')">
<el-date-picker v-model="timeList" @change="changeTimeList" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" type="datetimerange">
</el-date-picker>
</el-form-item>
<el-form-item>
<!-- 查询 -->
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
{{ $t('common:button:reset') }}
</el-button>
<el-button type="primary" size="small" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
<el-button type="primary" size="small" :disabled="multipleSelection.length <= 0"
@click="publishSystemDocument(multipleSelection)">
{{ $t('dictionary:signature:button:publish') }}
</el-button>
<el-button type="primary" size="small" :disabled="multipleSelection.length <= 0"
@click="handleRepeal(multipleSelection)">
{{ $t('common:button:revoke') }}
</el-button>
</el-form-item>
</el-form>
<el-button
type="primary"
style="margin-left: auto; margin-bottom: 10px"
size="small"
@click="handleAdd"
>
{{ $t('common:button:new') }}
</el-button>
</template>
<template slot="main-container">
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" stripe height="100"
@sort-change="handleSortByColumn" @selection-change="handleSelectionChange">
<!-- <el-table-column type="index" width="40" /> -->
<el-table-column type="selection" width="55" :selectable="handleSelectable">
</el-table-column>
<el-table-column prop="FileType" :label="$t('dictionary:signature:table:FileType')" show-overflow-tooltip
sortable="custom" min-width="120px" />
<el-table-column prop="Name" :label="$t('dictionary:signature:table:Name')" show-overflow-tooltip
sortable="custom" min-width="120px" />
<el-table-column prop="AttachmentCount" :label="$t('dictionary:signature:table:AttachmentCount')"
show-overflow-tooltip sortable="custom" min-width="150px">
<template slot-scope="scope">
<el-button type="text" @click.stop="openAttachment(scope.row, true)">
{{ scope.row.AttachmentCount }}
<i class="el-icon-upload2" />
</el-button>
</template>
</el-table-column>
<el-table-column prop="SignViewMinimumMinutes" :label="$t('dictionary:signature:table:SignViewMinimumMinutes')"
show-overflow-tooltip sortable="custom" min-width="200px" />
<el-table-column prop="CurrentStaffTrainDays" :label="$t('dictionary:signature:table:CurrentStaffTrainDays')"
show-overflow-tooltip sortable="custom" min-width="200px" />
<el-table-column prop="NewStaffTrainDays" :label="$t('dictionary:signature:table:NewStaffTrainDays')"
show-overflow-tooltip sortable="custom" min-width="200px" />
<el-table-column prop="NeedConfirmedUserTypes" :label="$t('dictionary:signature:table:NeedConfirmedUserTypes')"
show-overflow-tooltip>
<el-table
v-adaptive="{ bottomOffset: 60 }"
v-loading="loading"
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="40" />
<el-table-column
prop="FileType"
:label="$t('dictionary:signature:table:FileType')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="Name"
:label="$t('dictionary:signature:table:Name')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="SignViewMinimumMinutes"
:label="$t('dictionary:signature:table:SignViewMinimumMinutes')"
show-overflow-tooltip
sortable="custom"
min-width="110"
/>
<el-table-column
prop="NeedConfirmedUserTypes"
:label="$t('dictionary:signature:table:NeedConfirmedUserTypes')"
show-overflow-tooltip
>
<template slot-scope="scope">
{{
scope.row.NeedConfirmedUserTypes
@@ -106,8 +83,12 @@
}}
</template>
</el-table-column>
<el-table-column prop="IsDeleted" :label="$t('dictionary:signature:table:IsDeleted')" show-overflow-tooltip
sortable="custom" min-width="120px">
<el-table-column
prop="IsDeleted"
:label="$t('dictionary:signature:table:IsDeleted')"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
$fd('TrainingStatus', scope.row.IsDeleted)
@@ -117,89 +98,103 @@
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="IsPublish" :label="$t('dictionary:signature:table:IsPublish')" show-overflow-tooltip
sortable="custom" min-width="120px">
<template slot-scope="scope">
<el-tag :type="scope.row.IsPublish ? 'primary' : 'danger'">{{
$fd('AttachmentPublishStatus', scope.row.IsPublish)
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="DocUserSignType" :label="$t('dictionary:signature:table:DocUserSignType')"
show-overflow-tooltip sortable="custom" min-width="150px">
<el-table-column
prop="DocUserSignType"
:label="$t('dictionary:signature:table:DocUserSignType')"
show-overflow-tooltip
sortable="custom"
min-width="90"
>
<template slot-scope="scope">
{{ $fd('ReadingYesOrNo', Number(scope.row.DocUserSignType)) }}
</template>
</el-table-column>
<el-table-column prop="CreateTime" :label="$t('dictionary:signature:table:CreateTime')" show-overflow-tooltip
sortable="custom" min-width="180px" />
<el-table-column
prop="CreateTime"
:label="$t('dictionary:signature:table:CreateTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column :label="$t('common:action:action')" min-width="240px" fixed="right">
<el-table-column :label="$t('common:action:action')" min-width="120">
<template slot-scope="scope">
<el-button circle icon="el-icon-view" @click="handlePreview(scope.row)"
:title="$t('common:button:preview')">
<el-button type="text" @click="handlePreview(scope.row)">
{{ $t('common:button:preview') }}
</el-button>
<el-button circle icon="el-icon-edit-outline" :title="$t('common:button:edit')"
@click="handleEdit(scope.row)">
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('common:button:edit') }}
</el-button>
<el-button :disabled="scope.row.IsPublish" circle icon="el-icon-position"
:title="$t('dictionary:signature:button:publish')" @click="publishSystemDocument([scope.row])">
<el-button
:disabled="scope.row.IsDeleted"
type="text"
@click="handleRepeal(scope.row)"
>
{{ $t('common:button:revoke') }}
</el-button>
<el-button :disabled="scope.row.IsDeleted" circle icon="el-icon-close" :title="$t('common:button:revoke')"
@click="handleRepeal([scope.row])">
</el-button>
<el-button circle icon="el-icon-delete" :title="$t('common:button:delete')"
@click="handleDelete(scope.row)">
<el-button type="text" @click="handleDelete(scope.row)">
{{ $t('common:button:delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" v-if="!isSystem" />
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<!-- 新增/编辑 -->
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title"
width="600px" custom-class="base-dialog-wrapper">
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
<el-dialog
v-if="editVisible"
:visible.sync="editVisible"
:close-on-click-modal="false"
:title="title"
width="600px"
custom-class="base-dialog-wrapper"
>
<TemplateForm
:data="currentRow"
@closeDialog="closeDialog"
@getList="getList"
/>
</el-dialog>
<!--附件列表-->
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
@getList="getList" />
<!-- 预览文件 -->
<attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible" :isView="true"
v-if="perview_visible" />
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="$t('common:button:preview')"
:fullscreen="true" append-to-body custom-class="base-dialog-wrapper">
<span style="position: fixed; left: 16px; top: 45px;cursor: pointer;font-size: 18px;color:#409EFF"
@click.stop="openAttachment(currentRow)" v-if="currentRow.AttachmentCount">{{
$t('trials:signRecords:table:AttachmentCount') }} ({{
currentRow.AttachmentCount }})</span>
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<PreviewFile v-if="previewVisible" :file-path="currentPath" :file-type="currentType" />
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:title="$t('common:button:preview')"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<div
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<PreviewFile
v-if="previewVisible"
:file-path="currentPath"
:file-type="currentType"
/>
</div>
</el-dialog>
</template>
</BaseContainer>
</template>
<script>
import { getSystemDocumentList, deleteSystemDocument, publishSystemDocument, outLineSystemDocument, getSystemDocumentAttachmentList } from '@/api/dictionary'
import { userAbandonDoc, getTrialUserTypeList } from '@/api/trials'
import { getSystemDocumentList, deleteSystemDocument } from '@/api/dictionary'
import { userAbandonDoc } from '@/api/trials'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import TemplateForm from './TemplateForm'
import attachmentList from './attachmentList'
import PreviewFile from '@/components/PreviewFile/index'
import attachmentPreview from './attachmentPreview'
const searchDataDefault = () => {
return {
FileTypeId: '',
BeginCreateTime: null,
EndCreateTime: null,
IsDeleted: null,
DocUserSignType: null,
UserTypeId: null,
Name: '',
PageIndex: 1,
PageSize: 20,
@@ -207,18 +202,8 @@ const searchDataDefault = () => {
}
export default {
name: 'SignatureTemplate',
components: { BaseContainer, Pagination, TemplateForm, PreviewFile, attachmentList, attachmentPreview },
components: { BaseContainer, Pagination, TemplateForm, PreviewFile },
dicts: ['Sys_Document'],
props: {
isSystem: {
type: Boolean,
default: false
},
TITLE: {
type: String,
default: ''
}
},
data() {
return {
searchData: searchDataDefault(),
@@ -231,82 +216,12 @@ export default {
previewVisible: false,
title: '',
loading: false,
userTypeOptions: [],
timeList: [],
attachment_Visible: false,
SystemDocumentId: null,
config: {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
},
multipleSelection: [],
perview_visible: false
}
},
mounted() {
this.getList()
this.getUserType()
},
methods: {
handleSelectable(row) {
return !row.IsDeleted || !row.IsPublish
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 发布
async publishSystemDocument(list) {
try {
let confirm = await this.$confirm(this.$t('dictionary:signature:confirm:publishFile'), {
type: 'warning',
distinguishCancelAndClose: true,
})
if (!confirm) return false
let arr = list.filter(item => !item.IsPublish)
if (arr.length <= 0) return this.getList()
let data = {
ids: arr.map(item => item.Id)
}
this.loading = true
let res = await publishSystemDocument(data)
this.loading = false
if (res.IsSuccess) {
this.getList()
}
} catch (err) {
this.loading = false
console.log(err)
}
},
openAttachment(row, isList = false) {
this.SystemDocumentId = row.Id
this.currentRow = { ...row }
if (!isList) {
this.perview_visible = true
} else {
this.config.visible = true
}
},
changeTimeList() {
if (this.timeList) {
this.searchData.BeginCreateTime = this.timeList[0]
this.searchData.EndCreateTime = this.timeList[1]
} else {
this.searchData.BeginCreateTime = null
this.searchData.EndCreateTime = null
}
},
// 获取用户类型下拉数据
getUserType() {
getTrialUserTypeList()
.then((res) => {
this.userTypeOptions = res.Result
})
.catch(() => {
this.loading = false
})
},
// 获取系统文件数据
getList() {
this.loading = true
@@ -336,23 +251,12 @@ export default {
this.editVisible = true
},
// 预览
async handlePreview(row) {
handlePreview(row) {
const { Name, FullFilePath } = row
this.currentPath = FullFilePath
this.currentType = row.Name
? Name.substring(Name.lastIndexOf('.') + 1).toLocaleLowerCase()
: ''
let searchData = {
OffLine: false,
PageIndex: 1,
PageSize: 1000,
Asc: false,
SortField: null,
SystemDocumentId: row.Id
}
this.currentRow = Object.assign({}, row)
let res = await getSystemDocumentAttachmentList(searchData)
this.currentRow.AttachmentCount = res.Result.CurrentPageData.length
this.previewVisible = true
},
// 编辑
@@ -368,13 +272,8 @@ export default {
distinguishCancelAndClose: true,
})
.then(() => {
let arr = row.filter(item => !item.IsDeleted)
if (arr.length <= 0) return this.getList()
let data = {
Ids: arr.map(item => item.Id)
}
this.loading = true
outLineSystemDocument(data)
userAbandonDoc(row.Id, true)
.then((res) => {
this.loading = false
if (res.IsSuccess) {
@@ -388,7 +287,7 @@ export default {
this.loading = false
})
})
.catch(() => { })
.catch(() => {})
},
// 删除
handleDelete(row) {
@@ -418,7 +317,6 @@ export default {
// 关闭弹窗
closeDialog() {
this.editVisible = false
this.attachment_Visible = false
},
// 重置
handleReset() {
@@ -4,160 +4,319 @@
<el-form :inline="true" class="base-search-form">
<!-- 是否需要回执 -->
<el-form-item :label="$t('trials:emailManageCfg:title:isReturnRequired')" v-if="!systemLevel">
<el-select v-model="searchData.IsReturnRequired" clearable style="width: 100px">
<el-option v-for="item of $d.YesOrNo" :value="item.value" :label="item.label" :key="item.id" />
<el-select
v-model="searchData.IsReturnRequired"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.YesOrNo"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<!-- 是否加急 -->
<el-form-item :label="$t('dictionary:email:label:IsUrgent')" v-if="!systemLevel">
<el-select v-model="searchData.IsUrgent" clearable style="width: 100px">
<el-option v-for="item of $d.YesOrNo" :value="item.value" :label="item.label" :key="item.id" />
<el-select
v-model="searchData.IsUrgent"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.YesOrNo"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<!-- 是否启用 -->
<el-form-item :label="$t('trials:emailManageCfg:table:IsEnable')" v-if="!systemLevel">
<el-select v-model="searchData.IsEnable" clearable style="width: 100px">
<el-option v-for="item of $d.YesOrNo" :value="item.value" :label="item.label" :key="item.id" />
<el-select
v-model="searchData.IsEnable"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.YesOrNo"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:auditRecord:table:criterion')" v-if="isDistinguishCriteria && !systemLevel">
<el-select v-model="searchData.CriterionTypeEnum" clearable style="width: 100px">
<el-option v-for="item of $d.CriterionType" :value="item.value" :label="item.label" :key="item.id" />
<el-form-item
:label="$t('trials:auditRecord:table:criterion')"
v-if="isDistinguishCriteria && !systemLevel"
>
<el-select
v-model="searchData.CriterionTypeEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.CriterionType"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:emailManageCfg:form:BusinessModule')">
<el-select v-model="searchData.BusinessModuleEnum" clearable style="width: 100px">
<el-option v-for="item of $d.BusinessModule" :value="item.value" :label="item.label" :key="item.id" />
<el-select
v-model="searchData.BusinessModuleEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.BusinessModule"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:emailManageCfg:form:BusinessScenario')">
<el-select v-model="searchData.BusinessScenarioEnum" clearable style="width: 100px">
<el-option v-for="item of $d.Email_BusinessScenario" :value="item.value" :label="item.label"
:key="item.id" />
<el-form-item
:label="$t('trials:emailManageCfg:form:BusinessScenario')"
>
<el-select
v-model="searchData.BusinessScenarioEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.Email_BusinessScenario"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:emailManageCfg:form:ToUserType')">
<el-select v-model="searchData.ToUserType" clearable style="width: 100px">
<el-option v-for="item of UserTypeList" :value="item.value" :label="item.label" :key="item.id" />
<el-select
v-model="searchData.ToUserType"
clearable
style="width: 100px"
>
<el-option
v-for="item of UserTypeList"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:emailManageCfg:form:EmailUrgent')" v-if="systemLevel === 1">
<el-select v-model="searchData.EmailUrgentEnum" clearable style="width: 100px">
<el-option v-for="item of $d.EmailUrgent" :value="item.value" :label="item.label" :key="item.id" />
<el-form-item
:label="$t('trials:emailManageCfg:form:EmailUrgent')"
v-if="systemLevel === 1"
>
<el-select
v-model="searchData.EmailUrgentEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.EmailUrgent"
:value="item.value"
:label="item.label"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
<!-- <el-button
</el-form>
<span style="margin-left: auto">
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
<!-- <el-button
type="primary"
size="mini"
>
场景配置
</el-button> -->
<el-button type="primary" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
</el-form-item>
</el-form>
<el-button type="primary" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
</span>
</div>
<!-- 受试者列表 -->
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" :data="list" stripe height="100" style="width: 100%"
@sort-change="handleSortByColumn">
<el-table
v-loading="loading"
v-adaptive="{ bottomOffset: 45 }"
:data="list"
stripe
height="100"
style="width: 100%"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="40" />
<!-- Code -->
<el-table-column prop="Code" :label="$t('trials:emailManageCfg:title:code')" sortable="custom"
show-overflow-tooltip min-width="100" />
<el-table-column v-if="isDistinguishCriteria" prop="TrialReadingCriterionId"
:label="$t('trials:reviewTrack:table:criterionName')" show-overflow-tooltip sortable="custom" min-width="120">
<el-table-column
prop="Code"
:label="$t('trials:emailManageCfg:title:code')"
sortable="custom"
show-overflow-tooltip
min-width="100"
/>
<el-table-column
v-if="isDistinguishCriteria"
prop="TrialReadingCriterionId"
:label="$t('trials:reviewTrack:table:criterionName')"
show-overflow-tooltip
sortable="custom"
min-width="120"
>
<template slot-scope="scope">
{{ $fd('CriterionType', scope.row.CriterionTypeEnum) }}
</template>
</el-table-column>
<!-- 邮件主题中文 -->
<el-table-column prop="EmailTopicCN" :label="$t('trials:emailManageCfg:table:EmailTopicCN')" sortable="custom"
show-overflow-tooltip min-width="160" />
<el-table-column
prop="EmailTopicCN"
:label="$t('trials:emailManageCfg:table:EmailTopicCN')"
sortable="custom"
show-overflow-tooltip
min-width="160"
/>
<!-- 邮件主题英文 -->
<el-table-column prop="EmailTopic" :label="$t('trials:emailManageCfg:table:EmailTopic')" sortable="custom"
show-overflow-tooltip min-width="160" />
<el-table-column
prop="EmailTopic"
:label="$t('trials:emailManageCfg:table:EmailTopic')"
sortable="custom"
show-overflow-tooltip
min-width="160"
/>
<!-- 业务层级 -->
<el-table-column prop="BusinessLevelEnum" :label="$t('dictionary:email:label:businessLevel')" sortable="custom"
show-overflow-tooltip min-width="150">
<el-table-column
prop="BusinessLevelEnum"
:label="$t('dictionary:email:label:businessLevel')"
sortable="custom"
show-overflow-tooltip
min-width="150"
>
<template slot-scope="scope">
{{ $fd('BusinessLevel', scope.row.BusinessLevelEnum) }}
</template>
</el-table-column>
<!-- 业务模块 -->
<el-table-column prop="BusinessModuleEnum" :label="$t('dictionary:email:label:businessModule')" sortable="custom"
show-overflow-tooltip min-width="160">
<el-table-column
prop="BusinessModuleEnum"
:label="$t('dictionary:email:label:businessModule')"
sortable="custom"
show-overflow-tooltip
min-width="160"
>
<template slot-scope="scope">
{{ $fd('BusinessModule', scope.row.BusinessModuleEnum) }}
</template>
</el-table-column>
<!-- 业务场景 -->
<el-table-column prop="BusinessScenarioEnum" :label="$t('trials:emailManageCfg:table:BusinessScenarioEnum')"
sortable="custom" show-overflow-tooltip min-width="130">
<el-table-column
prop="BusinessScenarioEnum"
:label="$t('trials:emailManageCfg:table:BusinessScenarioEnum')"
sortable="custom"
show-overflow-tooltip
min-width="130"
>
<template slot-scope="scope">
{{ $fd('Email_BusinessScenario', scope.row.BusinessScenarioEnum) }}
</template>
</el-table-column>
<!-- 收件人v-if="systemLevel !== 1" -->
<el-table-column prop="ToUserTypeList" :label="$t('trials:emailManageCfg:title:toUserTypeList')"
show-overflow-tooltip min-width="100">
<el-table-column
prop="ToUserTypeList"
:label="$t('trials:emailManageCfg:title:toUserTypeList')"
show-overflow-tooltip
min-width="100"
>
<template slot-scope="scope">
{{
scope.row.ToUserTypeList.length > 0
? scope.row.ToUserTypeList.map((v) => $fd('UserType', v)).join(
'、'
)
'、'
)
: ''
}}
</template>
</el-table-column>
<!-- 抄送人v-if="!systemLevel" -->
<el-table-column prop="CopyUserTypeList" :label="$t('trials:emailManageCfg:title:copyUserTypeList')"
show-overflow-tooltip min-width="100">
<el-table-column
prop="CopyUserTypeList"
:label="$t('trials:emailManageCfg:title:copyUserTypeList')"
show-overflow-tooltip
min-width="100"
>
<template slot-scope="scope">
{{
scope.row.CopyUserTypeList.length > 0
? scope.row.CopyUserTypeList.map((v) => $fd('UserType', v)).join(
'、'
)
'、'
)
: ''
}}
</template>
</el-table-column>
<!-- 加急状态 -->
<el-table-column prop="EmailUrgentEnum" :label="$t('dictionary:email:label:IsUrgent')" sortable="custom"
show-overflow-tooltip min-width="110">
<el-table-column
prop="EmailUrgentEnum"
:label="$t('dictionary:email:label:IsUrgent')"
sortable="custom"
show-overflow-tooltip
min-width="110"
>
<template slot-scope="scope">
{{ $fd('EmailUrgent', scope.row.EmailUrgentEnum) }}
</template>
</el-table-column>
<!-- 发送周期和时间 -->
<el-table-column prop="EmailCron" :label="$t('trials:emailManageCfg:table:EmailCron')" sortable="custom"
show-overflow-tooltip min-width="180" />
<el-table-column
prop="EmailCron"
:label="$t('trials:emailManageCfg:table:EmailCron')"
sortable="custom"
show-overflow-tooltip
min-width="180"
/>
<!-- 附件 -->
<el-table-column prop="FileName" :label="$t('trials:emailManageCfg:title:fileName')" show-overflow-tooltip
min-width="100" v-if="!systemLevel">
<el-table-column
prop="FileName"
:label="$t('trials:emailManageCfg:title:fileName')"
show-overflow-tooltip
min-width="100"
v-if="!systemLevel"
>
<template slot-scope="scope">
<el-button v-if="scope.row.FilePath" type="text" @click="handlePreview(scope.row.FilePath)">
<el-button
v-if="scope.row.FilePath"
type="text"
@click="handlePreview(scope.row.FilePath)"
>
{{ scope.row.FileName }}
</el-button>
</template>
</el-table-column>
<!-- 是否需要回执 -->
<el-table-column prop="IsReturnRequired" :label="$t('trials:emailManageCfg:title:isReturnRequired')"
show-overflow-tooltip sortable="custom" min-width="160" v-if="!systemLevel">
<el-table-column
prop="IsReturnRequired"
:label="$t('trials:emailManageCfg:title:isReturnRequired')"
show-overflow-tooltip
sortable="custom"
min-width="160"
v-if="!systemLevel"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsReturnRequired" type="danger">
{{ $fd('YesOrNo', scope.row.IsReturnRequired) }}
@@ -168,8 +327,14 @@
</template>
</el-table-column>
<!-- 是否自动发送 -->
<el-table-column prop="IsAutoSend" :label="$t('trials:emailManageCfg:title:isAutoSend')" show-overflow-tooltip
sortable="custom" min-width="160" v-if="!systemLevel">
<el-table-column
prop="IsAutoSend"
:label="$t('trials:emailManageCfg:title:isAutoSend')"
show-overflow-tooltip
sortable="custom"
min-width="160"
v-if="!systemLevel"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsAutoSend" type="danger">
{{ $fd('YesOrNo', scope.row.IsAutoSend) }}
@@ -179,8 +344,14 @@
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="IsEnable" :label="$t('trials:emailManageCfg:table:IsEnable')" show-overflow-tooltip
sortable="custom" min-width="160" v-if="!systemLevel">
<el-table-column
prop="IsEnable"
:label="$t('trials:emailManageCfg:table:IsEnable')"
show-overflow-tooltip
sortable="custom"
min-width="160"
v-if="!systemLevel"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsEnable" type="danger">
{{ $fd('YesOrNo', scope.row.IsEnable) }}
@@ -191,12 +362,22 @@
</template>
</el-table-column>
<!-- 更新时间 -->
<el-table-column prop="UpdateTime" :label="$t('trials:emailManageCfg:title:updateTime')" show-overflow-tooltip
sortable="custom" min-width="160" />
<el-table-column
prop="UpdateTime"
:label="$t('trials:emailManageCfg:title:updateTime')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<!-- 创建时间 -->
<el-table-column prop="CreateTime" :label="$t('trials:emailManageCfg:title:createTime')" show-overflow-tooltip
sortable="custom" min-width="160" />
<el-table-column :label="$t('common:action:action')" min-width="180" fixed="right">
<el-table-column
prop="CreateTime"
:label="$t('trials:emailManageCfg:title:createTime')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column label="Action" min-width="180" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('common:button:edit') }}
@@ -205,38 +386,77 @@
<el-button type="text" @click="handleDelete(scope.row)">
{{ $t('common:button:delete') }}
</el-button>
<el-button type="text" @click="
preview(scope.row.EmailHtmlContentCN, scope.row.EmailHtmlContent)
">{{ $t('common:button:preview') }}</el-button>
<el-button
type="text"
@click="
preview(scope.row.EmailHtmlContentCN, scope.row.EmailHtmlContent)
"
>{{ $t('common:button:preview') }}</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<!-- 搜索框 -->
<!-- 修改受试者状态 -->
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title" width="700px"
fullscreen custom-class="base-dialog-wrapper">
<EmailForm :data="rowData" :system-level="systemLevel" :isDistinguishCriteria="isDistinguishCriteria"
@closeDialog="closeDialog" @getList="getList" @PreviewHTML="preview" />
<el-dialog
v-if="editVisible"
:visible.sync="editVisible"
:close-on-click-modal="false"
:title="title"
width="700px"
fullscreen
custom-class="base-dialog-wrapper"
>
<EmailForm
:data="rowData"
:system-level="systemLevel"
:isDistinguishCriteria="isDistinguishCriteria"
@closeDialog="closeDialog"
@getList="getList"
@PreviewHTML="preview"
/>
</el-dialog>
<!-- 修改受试者状态 -->
<el-dialog v-if="attachmentVisible" :visible.sync="attachmentVisible" :close-on-click-modal="false"
:title="$t('trials:emailManageCfg:title:fileName')" width="80%" custom-class="base-dialog-wrapper" append-to-body>
<AttachmentList :business-scenario-enum="rowData.BusinessScenarioEnum"
:is-distinguish-criteria="rowData.IsDistinguishCriteria" @getList="getList" />
<el-dialog
v-if="attachmentVisible"
:visible.sync="attachmentVisible"
:close-on-click-modal="false"
:title="$t('trials:emailManageCfg:title:fileName')"
width="80%"
custom-class="base-dialog-wrapper"
append-to-body
>
<AttachmentList
:business-scenario-enum="rowData.BusinessScenarioEnum"
:is-distinguish-criteria="rowData.IsDistinguishCriteria"
@getList="getList"
/>
</el-dialog>
<!-- 预览模板 -->
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :close-on-click-modal="false"
:title="$t('common:button:preview')" fullscreen custom-class="base-dialog-wrapper">
<div style="
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:close-on-click-modal="false"
:title="$t('common:button:preview')"
fullscreen
custom-class="base-dialog-wrapper"
>
<div
style="
display: flex;
align-items: flex-start;
justify-content: space-around;
flex-wrap: wrap;
">
"
>
<div style="min-width: 50%">
<!-- 邮件内容模版CN -->
<h3>{{ $t('dictionary:email:title:title1') }}</h3>
@@ -410,8 +630,3 @@ export default {
},
}
</script>
<style lang="scss" scoped>
.box-body .search .base-search-form .el-form-item {
margin-bottom: 10px;
}
</style>
+63 -27
View File
@@ -1,41 +1,85 @@
<template>
<base-model :config="config">
<div slot="dialog-body">
<el-form ref="fileForm" :model="form" label-width="100px" size="small" :rules="rules">
<el-form
ref="fileForm"
:model="form"
label-width="100px"
size="small"
:rules="rules"
>
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:file:form:name')" prop="Name">
<el-input v-model="form.Name" />
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:nameCN')" prop="NameCN">
<el-form-item
:label="$t('dictionary:file:form:nameCN')"
prop="NameCN"
>
<el-input v-model="form.NameCN" />
</el-form-item>
<el-form-item :label="$t('dictionary:browser:form:ArchiveTypeEnum')" prop="ArchiveTypeEnum">
<el-select v-model="form.ArchiveTypeEnum" clearable placeholder="" style="width: 100%">
<el-option v-for="item in $d.ArchiveType" :key="item.id" :label="item.label" :value="item.value">
<el-form-item
:label="$t('dictionary:browser:form:ArchiveTypeEnum')"
prop="ArchiveTypeEnum"
>
<el-select
v-model="form.ArchiveTypeEnum"
clearable
placeholder=""
style="width: 100%"
>
<el-option
v-for="item in $d.ArchiveType"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:browser:form:SubIdentificationEnum')" prop="SubIdentificationEnum">
<el-select style="width: 100%" v-model="form.SubIdentificationEnum" clearable placeholder="">
<el-option v-for="item in $d.SubIdentification" :key="item.id" :label="item.label" :value="item.value">
<el-form-item
:label="$t('dictionary:browser:form:SubIdentificationEnum')"
prop="SubIdentificationEnum"
>
<el-select
style="width: 100%"
v-model="form.SubIdentificationEnum"
clearable
placeholder=""
>
<el-option
v-for="item in $d.SubIdentification"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:browser:form:SysTemplateTypeEnum')" prop="SysTemplateTypeEnum">
<el-select style="width: 100%" v-model="form.SysTemplateTypeEnum" clearable placeholder="">
<el-option v-for="item in $d.SysTemplateType" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:ShowOrder')" prop="ShowOrder">
<el-input-number v-model="form.ShowOrder" :step="1" step-strictly></el-input-number>
<el-form-item
:label="$t('dictionary:file:form:ShowOrder')"
prop="ShowOrder"
>
<el-input-number
v-model="form.ShowOrder"
:step="1"
step-strictly
></el-input-number>
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:IsEnable')">
<el-switch v-model="form.IsEnable" :active-value="true" :inactive-value="false">
<el-switch
v-model="form.IsEnable"
:active-value="true"
:inactive-value="false"
>
</el-switch>
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:IsConfirmRecord')">
<el-switch v-model="form.IsConfirmRecord" :active-value="true" :inactive-value="false">
<el-switch
v-model="form.IsConfirmRecord"
:active-value="true"
:inactive-value="false"
>
</el-switch>
</el-form-item>
</div>
@@ -51,7 +95,7 @@
</div>
</base-model>
</template>
<script>
<script>
import baseModel from '@/components/BaseModel'
import { addOrUpdateSysFileType } from '@/api/dictionary'
export default {
@@ -82,7 +126,6 @@ export default {
NameCN: null,
SubIdentificationEnum: null,
ShowOrder: 0,
SysTemplateTypeEnum: null
},
rules: {
Name: [
@@ -106,13 +149,6 @@ export default {
trigger: ['blur', 'change'],
},
],
SysTemplateTypeEnum: [
{
required: true,
message: this.$t('common:ruleMessage:select'),
trigger: ['blur', 'change'],
},
],
ArchiveTypeEnum: [
{
required: true,
+149 -52
View File
@@ -11,41 +11,85 @@
<el-input v-model="searchData.NameCN" style="width: 100px" />
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:archiveTypeEnum')">
<el-select v-model="searchData.ArchiveTypeEnum" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.ArchiveType" :key="item.id" :label="item.label" :value="item.value">
<el-select
v-model="searchData.ArchiveTypeEnum"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.ArchiveType"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:subIdentificationEnum')">
<el-select v-model="searchData.SubIdentificationEnum" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.SubIdentification" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:SysTemplateTypeEnum')">
<el-select v-model="searchData.SysTemplateTypeEnum" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.SysTemplateType" :key="item.id" :label="item.label" :value="item.value">
<el-form-item
:label="$t('dictionary:file:search:subIdentificationEnum')"
>
<el-select
v-model="searchData.SubIdentificationEnum"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.SubIdentification"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:isEnable')">
<el-select v-model="searchData.IsEnable" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value">
<el-select
v-model="searchData.IsEnable"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.YesOrNo"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:isConfirmRecord')">
<el-select v-model="searchData.IsConfirmRecord" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value">
<el-select
v-model="searchData.IsConfirmRecord"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.YesOrNo"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
<el-button
type="primary"
icon="el-icon-search"
@click="handleSearch"
>
{{ $t('common:button:search') }}
</el-button>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
@@ -57,60 +101,106 @@
</span>
</div>
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" :data="list" stripe height="100"
style="width: 100%" @sort-change="handleSortByColumn">
<el-table
v-loading="loading"
v-adaptive="{ bottomOffset: 45 }"
:data="list"
stripe
height="100"
style="width: 100%"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="40" />
<el-table-column prop="Name" :label="$t('dictionary:file:table:Name')" sortable="custom" show-overflow-tooltip
min-width="150px" />
<el-table-column prop="NameCN" :label="$t('dictionary:file:table:NameCN')" show-overflow-tooltip
sortable="custom" min-width="150px" />
<el-table-column prop="ArchiveTypeEnum" :label="$t('dictionary:file:table:archiveTypeEnum')"
show-overflow-tooltip sortable="custom" min-width="120px">
<el-table-column
prop="Name"
:label="$t('dictionary:file:table:Name')"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column
prop="NameCN"
:label="$t('dictionary:file:table:NameCN')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="ArchiveTypeEnum"
:label="$t('dictionary:file:table:archiveTypeEnum')"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('ArchiveType', scope.row.ArchiveTypeEnum) }}
</template>
</el-table-column>
<el-table-column prop="SubIdentificationEnum" :label="$t('dictionary:file:table:subIdentificationEnum')"
show-overflow-tooltip sortable="custom" min-width="120px">
<el-table-column
prop="SubIdentificationEnum"
:label="$t('dictionary:file:table:subIdentificationEnum')"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('SubIdentification', scope.row.SubIdentificationEnum) }}
</template>
</el-table-column>
<el-table-column prop="SysTemplateTypeEnum" :label="$t('dictionary:file:table:SysTemplateTypeEnum')"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
{{ $fd('SysTemplateType', scope.row.SysTemplateTypeEnum) }}
</template>
</el-table-column>
<el-table-column prop="ShowOrder" :label="$t('dictionary:file:table:ShowOrder')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('dictionary:file:table:IsEnable')" prop="IsEnable" show-overflow-tooltip
sortable="custom" min-width="120px">
<el-table-column
prop="ShowOrder"
:label="$t('dictionary:file:table:ShowOrder')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
:label="$t('dictionary:file:table:IsEnable')"
prop="IsEnable"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<el-tag :type="!scope.row.IsEnable ? 'info' : ''">
{{ $fd('YesOrNo', scope.row.IsEnable) }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('dictionary:file:table:isConfirmRecord')" prop="IsConfirmRecord"
show-overflow-tooltip sortable="custom" min-width="150px">
<el-table-column
:label="$t('dictionary:file:table:isConfirmRecord')"
prop="IsConfirmRecord"
show-overflow-tooltip
sortable="custom"
width="200"
>
<template slot-scope="scope">
<el-tag :type="!scope.row.IsEnable ? 'info' : ''">
{{ $fd('YesOrNo', scope.row.IsConfirmRecord) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="CreateTime" :label="$t('dictionary:file:table:createTime')" show-overflow-tooltip
sortable="custom" min-width="180px" />
<el-table-column prop="UpdateTime" :label="$t('dictionary:file:table:updateTime')" show-overflow-tooltip
sortable="custom" min-width="180px" />
<el-table-column :label="$t('dictionary:file:table:action')" width="200" fixed="right">
<el-table-column
prop="CreateTime"
:label="$t('dictionary:file:table:createTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="UpdateTime"
:label="$t('dictionary:file:table:updateTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
:label="$t('dictionary:file:table:action')"
width="200"
fixed="right"
>
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('dictionary:file:button:edit') }}
</el-button>
<el-button type="text" @click="handleDelete(scope.row)" v-if="hasPermi(['dictionary:template:file:del'])">
<el-button
type="text"
@click="handleDelete(scope.row)"
v-if="hasPermi(['dictionary:template:file:del'])"
>
{{ $t('dictionary:file:button:delete') }}
</el-button>
</template>
@@ -118,9 +208,20 @@
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<File-form :config="config" :data="rowData" v-if="config.visible" @close="close" @getList="getList" />
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<File-form
:config="config"
:data="rowData"
v-if="config.visible"
@close="close"
@getList="getList"
/>
</box-content>
</BoxContent>
</template>
@@ -137,7 +238,6 @@ const searchDataDefault = () => {
Name: null,
NameCN: null,
SubIdentificationEnum: null,
SysTemplateTypeEnum: null,
PageIndex: 1,
PageSize: 20,
asc: false,
@@ -244,7 +344,4 @@ export default {
}
</script>
<style lang="scss" scoped>
.box-body .search .base-search-form .el-form-item {
margin-bottom: 10px;
}
</style>
+67 -24
View File
@@ -9,36 +9,71 @@
<!-- Reset Password -->
<div class="box-wrapper" v-if="active === 0">
<el-form ref="resetForm" v-loading="formLoading" :model="form" label-width="130px" :rules="rules"
class="demo-ruleForm" size="small">
<el-form
ref="resetForm"
v-loading="formLoading"
:model="form"
label-width="130px"
:rules="rules"
class="demo-ruleForm"
size="small"
>
<!-- 邮箱 -->
<el-form-item :label="$t('passwordReset:form:email')" prop="EmailOrPhone">
<el-form-item
:label="$t('passwordReset:form:email')"
prop="EmailOrPhone"
>
<el-col :span="18">
<el-input v-model="form.EmailOrPhone" autocomplete="off" @change="handleEmailChange" />
<el-input
v-model="form.EmailOrPhone"
autocomplete="off"
@change="handleEmailChange"
/>
</el-col>
</el-form-item>
<!-- 验证码 -->
<el-form-item :label="$t('trials:researchForm:form:verifyCode')" required>
<el-form-item
:label="$t('trials:researchForm:form:verifyCode')"
required
>
<el-col :span="18">
<el-form-item prop="VerificationCode">
<el-input v-model="form.VerificationCode" autocomplete="off" />
</el-form-item>
</el-col>
<el-col :span="6" style="text-align: right">
<el-button size="small" type="primary" style="width: 80%" :disabled="sendDisabled"
@click="handleSendCode">{{ sendTitle }}</el-button>
<el-button
size="small"
type="primary"
style="width: 80%"
:disabled="sendDisabled"
@click="handleSendCode"
>{{ sendTitle }}</el-button
>
</el-col>
</el-form-item>
</el-form>
<!-- 校验 -->
<el-button size="small" type="primary" style="width: 50%; margin: auto; display: block"
:disabled="form.VerificationCode === '' || form.EmailOrPhone === ''" @click="verifyCode">
<el-button
size="small"
type="primary"
style="width: 50%; margin: auto; display: block"
:disabled="form.VerificationCode === '' || form.EmailOrPhone === ''"
@click="verifyCode"
>
{{ $t('passwordReset:button:verify') }}
</el-button>
</div>
<div class="box-wrapper" v-show="active === 1">
<el-form ref="resetForm2" v-loading="formLoading" :model="form"
:label-width="$i18n.locale === 'en' ? '180px' : '100px'" :rules="rules2" class="demo-ruleForm" size="small">
<el-form
ref="resetForm2"
v-loading="formLoading"
:model="form"
:label-width="$i18n.locale === 'en' ? '180px' : '100px'"
:rules="rules2"
class="demo-ruleForm"
size="small"
>
<!-- 用户名 -->
<el-form-item :label="$t('passwordReset:form:userName')" prop="UserId">
<el-input v-model="form.UserName" disabled />
@@ -70,17 +105,27 @@
<el-input v-model="form.UserType" disabled />
</el-form-item> -->
<!-- 新密码 -->
<el-form-item class="my_new_pwd" :label="$t('passwordReset:form:password')" prop="NewPwd"
style="position: relative">
<el-form-item
class="my_new_pwd"
:label="$t('passwordReset:form:password')"
prop="NewPwd"
style="position: relative"
>
<el-input v-model="form.NewPwd" show-password autocomplete="off" />
<span style="position: absolute; right: -30px">
<el-tooltip :content="$t('passwordReset:form:passwordCentent')" placement="top">
<el-tooltip
:content="$t('passwordReset:form:passwordCentent')"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
</span>
</el-form-item>
<!-- 确认密码 -->
<el-form-item :label="$t('passwordReset:form:confirmPassword')" prop="CheckPass">
<el-form-item
:label="$t('passwordReset:form:confirmPassword')"
prop="CheckPass"
>
<el-input v-model="form.CheckPass" show-password autocomplete="off" />
</el-form-item>
</el-form>
@@ -90,7 +135,12 @@
{{ $t('passwordReset:button:cancel') }}
</el-button>
<!-- 提交 -->
<el-button size="small" type="primary" @click="onSubmit" style="width: 46%">
<el-button
size="small"
type="primary"
@click="onSubmit"
style="width: 46%"
>
{{ $t('passwordReset:button:submit') }}
</el-button>
</div>
@@ -338,14 +388,10 @@ export default {
}
},
onCancel() {
// this.$refs['resetForm'].resetFields()
this.$refs['resetForm'].resetFields()
Object.keys(this.form).forEach((key) => {
this.form[key] = ''
})
this.sendDisabled = false
this.sendTitle = this.$t('passwordReset:button:send')
countdown = 60
clearTimeout(timer)
this.active = 0
},
goBack() {
@@ -358,14 +404,12 @@ export default {
.reset-wrapper {
padding: 20px;
}
.reset-wrapper .el-page-header {
line-height: 50px;
border: 1px solid #ebeef5;
border-radius: 4px;
background-color: #fff;
}
.reset-wrapper .box-wrapper {
width: 700px;
margin: 20px auto;
@@ -381,7 +425,6 @@ export default {
.is-error.my_new_pwd {
margin-bottom: 45px;
}
.flexBox {
display: flex;
justify-content: center;
+159 -82
View File
@@ -2,76 +2,152 @@
<div class="log">
<div ref="leftContainer" class="left">
<el-form :inline="true">
<el-form-item :label="$t('system:loginLog:label:OptType')" prop="OptType">
<el-select v-model="searchData.OptTypeList" clearable style="width: 200px" multiple :collapse-tags="true">
<el-option v-for="item of $d.UserOptType" :key="'UserOptType' + item.label" :value="item.value"
:label="item.label" />
<el-form-item
:label="$t('system:loginLog:label:OptType')"
prop="OptType"
>
<el-select
v-model="searchData.OptType"
clearable
style="width: 120px"
>
<el-option
v-for="item of $d.UserOptType"
:key="'UserOptType' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item label="IP" prop="IP">
<el-input v-model="searchData.IP" size="small" clearable style="width: 120px" />
<el-input
v-model="searchData.IP"
size="small"
clearable
style="width: 120px"
/>
</el-form-item>
<el-form-item :label="$t('system:loginLog:label:LoginFaildName')" prop="LoginFaildName">
<el-input v-model="searchData.LoginFaildName" size="small" clearable style="width: 120px" />
<el-form-item
:label="$t('system:loginLog:label:LoginFaildName')"
prop="LoginFaildName"
>
<el-input
v-model="searchData.LoginFaildName"
size="small"
clearable
style="width: 120px"
/>
</el-form-item>
<el-form-item :label="$t('system:loginLog:table:LoginUserName')" prop="LoginFaildName">
<el-input v-model="searchData.LoginUserName" size="small" clearable style="width: 120px" />
<el-form-item
:label="$t('system:loginLog:table:LoginUserName')"
prop="LoginFaildName"
>
<el-input
v-model="searchData.LoginUserName"
size="small"
clearable
style="width: 120px"
/>
</el-form-item>
<!-- <el-form-item :label="$t('system:loginLog:table:LoginUserType')" prop="LoginUserTypeEnum">
<el-select v-model="searchData.LoginUserTypeEnum" clearable style="width: 120px">
<el-option v-for="item of $d.UserType" :key="'UserType' + item.label" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item> -->
<el-form-item :label="$t('system:loginLog:label:IsLoginUncommonly')" prop="IsLoginUncommonly ">
<el-select v-model="searchData.IsLoginUncommonly" clearable style="width: 120px">
<el-option v-for="item of $d.YesOrNo" :key="item.id" :value="item.value" :label="item.label" />
<el-form-item
:label="$t('system:loginLog:table:LoginUserType')"
prop="LoginUserTypeEnum"
>
<el-select
v-model="searchData.LoginUserTypeEnum"
clearable
style="width: 120px"
>
<el-option
v-for="item of $d.UserType"
:key="'UserType' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('system:loginLog:label:CreateTime')">
<el-date-picker v-model="datetimerange" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" @change="handleDatetimeChange" style="width: 380px" />
<el-date-picker
v-model="datetimerange"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
@change="handleDatetimeChange"
style="width: 380px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="getList">
{{ $t('common:button:search') }}
</el-button>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" height="100" :data="list" class="table"
@sort-change="handleSortByColumn">
<el-table
v-loading="loading"
v-adaptive="{ bottomOffset: 45 }"
height="100"
:data="list"
class="table"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="50">
<template slot-scope="scope">
<span style="
<span
style="
display: flex;
align-items: center;
justify-content: flex-end;
">
<el-tooltip class="item" effect="dark" :content="$t('system:loginLog:label:IsLoginUncommonly')"
placement="top" style="margin-right: 3px" v-if="scope.row.IsIgnoreUncommonly">
<i v-if="scope.row.IsLoginUncommonly" class="el-icon-warning icon-i icon-success"></i>
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="$t('system:loginLog:label:IsLoginUncommonly')"
placement="top" style="margin-right: 3px" v-else-if="scope.row.IsLoginUncommonly">
<i v-if="scope.row.IsLoginUncommonly" class="el-icon-warning icon-i"
@click.stop="setIsIgnoreUncommonly(scope.row)"></i>
"
>
<el-tooltip
class="item"
effect="dark"
:content="$t('system:loginLog:label:IsLoginUncommonly')"
placement="top"
style="margin-right: 3px"
v-if="scope.row.IsLoginUncommonly"
>
<i
v-if="scope.row.IsLoginUncommonly"
class="el-icon-warning icon-i"
></i>
</el-tooltip>
<span>{{ scope.$index + 1 }}</span>
</span>
</template>
</el-table-column>
<el-table-column :label="$t('system:loginLog:table:OptType')" prop="OptType" min-width="150"
show-overflow-tooltip sortable="custom">
<el-table-column
:label="$t('system:loginLog:table:OptType')"
prop="OptType"
min-width="150"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('UserOptType', scope.row.OptType) }}
</template>
</el-table-column>
<el-table-column label="IP" prop="IP" min-width="150" sortable="custom" show-overflow-tooltip />
<el-table-column :label="$t('trials:loginLog:table:IPRegion')" prop="IPRegion" min-width="120"
show-overflow-tooltip sortable="custom" />
<el-table-column
label="IP"
prop="IP"
min-width="150"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column
:label="$t('trials:loginLog:table:IPRegion')"
prop="IPRegion"
min-width="120"
show-overflow-tooltip
sortable="custom"
/>
<!-- <el-table-column
:label="$t('system:loginLog:table:LoginFaildName')"
prop="LoginFaildName"
@@ -79,10 +155,20 @@
show-overflow-tooltip
sortable="custom"
/> -->
<el-table-column :label="$t('system:loginLog:table:LoginUserName')" prop="ActionUserName" min-width="140"
show-overflow-tooltip sortable="custom" />
<el-table-column :label="$t('system:loginLog:table:Aetionlserlype')" prop="ActionUserType" min-width="100"
show-overflow-tooltip sortable="custom" />
<el-table-column
:label="$t('system:loginLog:table:LoginUserName')"
prop="ActionUserName"
min-width="140"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
:label="$t('system:loginLog:table:Aetionlserlype')"
prop="ActionUserType"
min-width="100"
show-overflow-tooltip
sortable="custom"
/>
<!-- <el-table-column
:label="$t('system:loginLog:table:LoginUserType')"
prop="LoginUserTypeEnum"
@@ -94,8 +180,13 @@
{{ $fd("UserType", scope.row.LoginUserTypeEnum) }}
</template>
</el-table-column> -->
<el-table-column :label="$t('system:loginLog:table:OptUserName')" prop="TargetIdentityUserName" min-width="200"
sortable="custom" show-overflow-tooltip />
<el-table-column
:label="$t('system:loginLog:table:OptUserName')"
prop="TargetIdentityUserName"
min-width="200"
sortable="custom"
show-overflow-tooltip
/>
<!-- <el-table-column
:label="$t('system:loginLog:table:OptUserType')"
prop="OptUserTypeEnum"
@@ -107,36 +198,51 @@
{{ $fd("UserType", scope.row.OptUserTypeEnum) }}
</template>
</el-table-column> -->
<el-table-column :label="$t('system:loginLog:table:detail')" min-width="120" show-overflow-tooltip>
<el-table-column
:label="$t('system:loginLog:table:detail')"
min-width="120"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-button v-if="scope.row.JsonObj" type="text" @click="handleOpenDialog(scope.row)">
<el-button
v-if="scope.row.JsonObj"
type="text"
@click="handleOpenDialog(scope.row)"
>
<span>{{ $t('system:loginLog:message:detail') }}</span>
</el-button>
</template>
</el-table-column>
<el-table-column :label="$t('system:loginLog:table:CreateTime')" prop="CreateTime" min-width="180"
sortable="custom" show-overflow-tooltip />
<el-table-column
:label="$t('system:loginLog:table:CreateTime')"
prop="CreateTime"
min-width="180"
sortable="custom"
show-overflow-tooltip
/>
</el-table>
<div class="pagination" style="text-align: right; margin-top: 5px">
<pagination :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<pagination
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
</div>
</div>
<detail :config="config" :JsonObj="JsonObj" />
</div>
</template>
<script>
import { getUserLogList, setIsIgnoreUncommonly } from '@/api/user'
import { getUserLogList } from '@/api/user'
import Pagination from '@/components/Pagination'
import detail from './detail.vue'
import moment from 'moment'
const searchDataDefault = () => {
return {
OptType: null,
OptTypeList: [],
Ip: '',
LoginFaildName: '',
IsLoginUncommonly: null,
LoginUserName: '',
LoginUserTypeEnum: null,
BeginDate: '',
@@ -170,26 +276,6 @@ export default {
this.getList()
},
methods: {
// 忽略异地登录
async setIsIgnoreUncommonly(row) {
try {
let confirm = await this.$confirm(this.$t("system:loginLog:confirmMessage:setIsIgnoreUncommonly"))
if (!confirm) return false
let data = {
IsIgnoreUncommonly: true,
Id: row.Id
}
this.loading = true
let res = await setIsIgnoreUncommonly(data)
this.loading = false
if (res.IsSuccess) {
this.getList()
}
} catch (err) {
this.loading = false
console.log(err)
}
},
handleOpenDialog(row) {
if (!row.JsonObj)
return this.$message.warning(this.$t('system:loginLog:message:noJSON'))
@@ -248,37 +334,28 @@ export default {
display: flex;
padding: 10px;
border-radius: 5px;
.left {
display: flex;
flex-direction: column;
width: 0;
flex-grow: 4;
// border-right: 1px solid #ccc;
.filter-container {
display: flex;
align-items: center;
margin: 5px;
}
.data-table {
flex: 1;
padding: 5px 0px;
}
.pagination-container {
text-align: right;
}
}
.icon-i {
color: #f56c6c;
cursor: pointer;
}
.icon-success {
color: #67C23A
}
}
</style>
+559 -181
View File
@@ -9,28 +9,64 @@
</el-form-item>
<!-- 研究方案号 -->
<el-form-item :label="$t('trials:trials-list:table:researchNumber')">
<el-input v-model="searchData.ResearchProgramNo" style="width: 100px" clearable />
<el-input
v-model="searchData.ResearchProgramNo"
style="width: 100px"
clearable
/>
</el-form-item>
<!-- 试验名称 -->
<el-form-item :label="$t('trials:trials-list:table:experimentName')">
<el-input v-model="searchData.ExperimentName" style="width: 100px" clearable />
<el-input
v-model="searchData.ExperimentName"
style="width: 100px"
clearable
/>
</el-form-item>
<!-- Sponsor -->
<el-form-item :label="$t('trials:trials-list:table:sponsor')">
<el-select v-model="searchData.SponsorId" style="width: 150px" clearable>
<el-option v-for="item in sponsorList" :key="item.Id" :label="item.SponsorName" :value="item.Id" />
<el-select
v-model="searchData.SponsorId"
style="width: 150px"
clearable
>
<el-option
v-for="item in sponsorList"
:key="item.Id"
:label="item.SponsorName"
:value="item.Id"
/>
</el-select>
</el-form-item>
<!-- 阅片标准 -->
<el-form-item v-if="hasPermi(['role:ir'])" :label="$t('trials:trials-list:table:IR_ReadingCriterionList')">
<el-select v-model="searchData.CriterionType" style="width: 150px" clearable>
<el-option v-for="item in $d.CriterionType" :key="item.id" :label="item.label" :value="item.value" />
<el-form-item
v-if="hasPermi(['role:ir'])"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
>
<el-select
v-model="searchData.CriterionType"
style="width: 150px"
clearable
>
<el-option
v-for="item in $d.CriterionType"
:key="item.id"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<!-- 联系人 -->
<el-form-item v-if="hasPermi(['role:ir'])" :label="$t('trials:trials-list:table:IR_PMEmailList')">
<el-input v-model="searchData.PM_EMail" style="width: 100px" clearable />
<el-form-item
v-if="hasPermi(['role:ir'])"
:label="$t('trials:trials-list:table:IR_PMEmailList')"
>
<el-input
v-model="searchData.PM_EMail"
style="width: 100px"
clearable
/>
</el-form-item>
<el-form-item>
<!-- <el-button type="text" @click="isShow = !isShow">More</el-button> -->
@@ -39,19 +75,33 @@
{{ $t('common:button:search') }}
</el-button>
<!-- Reset -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
{{ $t('common:button:reset') }}
</el-button>
<!-- Export -->
<el-button v-hasPermi="['trials:trials-list:export']" type="primary" icon="el-icon-download"
:loading="exportLoading" @click="handleExportTrial">
<el-button
v-hasPermi="['trials:trials-list:export']"
type="primary"
icon="el-icon-download"
:loading="exportLoading"
@click="handleExportTrial"
>
{{ $t('common:button:export') }}
</el-button>
</el-form-item>
</el-form>
<span style="margin-left: auto">
<!-- New -->
<el-button v-hasPermi="['trials:trials-list:new']" icon="el-icon-plus" type="primary" @click="handleNew">
<el-button
v-hasPermi="['trials:trials-list:new']"
icon="el-icon-plus"
type="primary"
@click="handleNew"
>
{{ $t('common:button:new') }}
</el-button>
</span>
@@ -62,88 +112,190 @@
<div style="padding: 10px">
<el-form label-width="140px">
<el-form-item label="Trial ID">
<el-input v-model="searchData.Code" placeholder="Trial ID" style="width: 100%" clearable />
<el-input
v-model="searchData.Code"
placeholder="Trial ID"
style="width: 100%"
clearable
/>
</el-form-item>
<el-form-item label="Indication">
<el-input v-model="searchData.Indication" placeholder="Indication" style="width: 100%" clearable />
<el-input
v-model="searchData.Indication"
placeholder="Indication"
style="width: 100%"
clearable
/>
</el-form-item>
<el-form-item label="Assessment Criteria">
<el-select v-model="searchData.CriterionIds" placeholder="Assessment Criteria" style="width: 100%" clearable
multiple>
<el-select
v-model="searchData.CriterionIds"
placeholder="Assessment Criteria"
style="width: 100%"
clearable
multiple
>
<!-- <el-option
v-for="(key,value) of dictionaryList.ReadingStandard"
:key="key"
:label="key"
:value="value"
/> -->
<el-option v-for="item of dict.type.ReadingStandard" :key="item.value" :label="item.label"
:value="item.value" />
<el-option
v-for="item of dict.type.ReadingStandard"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="Sponsor">
<el-select v-model="searchData.SponsorId" placeholder="Sponsor" style="width: 100%" clearable>
<el-option v-for="item in sponsorList" :key="item.Id" :label="item.SponsorName" :value="item.Id" />
<el-select
v-model="searchData.SponsorId"
placeholder="Sponsor"
style="width: 100%"
clearable
>
<el-option
v-for="item in sponsorList"
:key="item.Id"
:label="item.SponsorName"
:value="item.Id"
/>
</el-select>
</el-form-item>
<el-form-item label="CRO">
<el-select v-model="searchData.CROId" placeholder="CRO" style="width: 100%" clearable>
<el-option v-for="item of croList" :key="item.Id" :label="item.CROName" :value="item.Id" />
<el-select
v-model="searchData.CROId"
placeholder="CRO"
style="width: 100%"
clearable
>
<el-option
v-for="item of croList"
:key="item.Id"
:label="item.CROName"
:value="item.Id"
/>
</el-select>
</el-form-item>
<el-form-item label="Phase">
<el-select v-model="searchData.Phase" placeholder="Phase" style="width: 100%" clearable>
<el-option v-for="item in phaseOptions" :key="item.value" :label="item.value" :value="item.value" />
<el-select
v-model="searchData.Phase"
placeholder="Phase"
style="width: 100%"
clearable
>
<el-option
v-for="item in phaseOptions"
:key="item.value"
:label="item.value"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="ReviewType">
<el-select v-model="searchData.ReviewTypeIds" placeholder="ReviewType" style="width: 100%" clearable
multiple>
<el-select
v-model="searchData.ReviewTypeIds"
placeholder="ReviewType"
style="width: 100%"
clearable
multiple
>
<!-- <el-option
v-for="(key,value) of dictionaryList.ReviewType"
:key="key"
:label="key"
:value="value"
/> -->
<el-option v-for="item of dict.type.ReviewType" :key="item.value" :label="item.label"
:value="item.value" />
<el-option
v-for="item of dict.type.ReviewType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="Modality">
<el-select v-model="searchData.ModalityIds" multiple placeholder="Modality" style="width: 100%" clearable>
<el-select
v-model="searchData.ModalityIds"
multiple
placeholder="Modality"
style="width: 100%"
clearable
>
<!-- <el-option
v-for="(key,value) of dictionaryList.ReadingType"
:key="key"
:label="key"
:value="value"
/> -->
<el-option v-for="item of dict.type.ReadingType" :key="item.value" :label="item.label"
:value="item.value" />
<el-option
v-for="item of dict.type.ReadingType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="Expedited: ">
<el-select v-model="searchData.Expedited" value-key="value" clearable style="width: 100%">
<el-option v-for="item in expeditedOption" :key="item.value" :label="item.label" :value="item.value" />
<el-select
v-model="searchData.Expedited"
value-key="value"
clearable
style="width: 100%"
>
<el-option
v-for="item in expeditedOption"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="BeginDate: ">
<el-date-picker v-model="searchData.BeginDate" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date"
:picker-options="beginPickerOption" :clearable="false" style="width: 100%" />
<el-date-picker
v-model="searchData.BeginDate"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
type="date"
:picker-options="beginPickerOption"
:clearable="false"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="EndDate: ">
<el-date-picker v-model="searchData.EndDate" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date"
:picker-options="endpickerOption" :clearable="false" style="width: 100%" />
<el-date-picker
v-model="searchData.EndDate"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
type="date"
:picker-options="endpickerOption"
:clearable="false"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="Attended Reviewer Type:">
<el-select v-model="searchData.AttendedReviewerType" placeholder="Attended Reviewer Type"
style="width: 100%" clearable>
<el-option v-for="item of $d.AttendedReviewerType" :key="item.value" :label="item.label"
:value="item.value" />
<el-select
v-model="searchData.AttendedReviewerType"
placeholder="Attended Reviewer Type"
style="width: 100%"
clearable
>
<el-option
v-for="item of $d.AttendedReviewerType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSelectSearch">Search</el-button>
<el-button type="primary" @click="handleSelectSearch"
>Search</el-button
>
<el-button type="primary" @click="handleReset">Reset</el-button>
<el-button type="primary" @click="isShow = false">Back</el-button>
</el-form-item>
@@ -153,89 +305,219 @@
<!-- 项目列表 -->
<template slot="main-container">
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="listLoading" :data="list" stripe height="100"
@selection-change="handleSelectChange" @sort-change="handleSortChange" @row-click="rowClick">
<el-table
v-adaptive="{ bottomOffset: 60 }"
v-loading="listLoading"
:data="list"
stripe
height="100"
@selection-change="handleSelectChange"
@sort-change="handleSortChange"
@row-click="rowClick"
>
<el-table-column type="selection" align="left" width="45" />
<el-table-column type="index" width="40" align="left" />
<el-table-column prop="TrialCode" :label="$t('trials:trials-list:table:trialId')" show-overflow-tooltip
sortable="custom" width="120" />
<el-table-column prop="ResearchProgramNo" :label="$t('trials:trials-list:table:researchNumber')"
show-overflow-tooltip sortable="custom" min-width="160" />
<el-table-column
prop="TrialCode"
:label="$t('trials:trials-list:table:trialId')"
show-overflow-tooltip
sortable="custom"
width="120"
/>
<el-table-column
prop="ResearchProgramNo"
:label="$t('trials:trials-list:table:researchNumber')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column prop="ExperimentName" :label="$t('trials:trials-list:table:experimentName')"
show-overflow-tooltip sortable="custom" min-width="240" />
<el-table-column prop="Sponsor" :label="$t('trials:trials-list:table:sponsor')" show-overflow-tooltip
sortable="custom" min-width="120" />
<el-table-column prop="TrialStatusStr" :label="$t('trials:trials-list:table:status')" show-overflow-tooltip
sortable="custom" min-width="120">
<el-table-column
prop="ExperimentName"
:label="$t('trials:trials-list:table:experimentName')"
show-overflow-tooltip
sortable="custom"
min-width="240"
/>
<el-table-column
prop="Sponsor"
:label="$t('trials:trials-list:table:sponsor')"
show-overflow-tooltip
sortable="custom"
min-width="120"
/>
<el-table-column
prop="TrialStatusStr"
:label="$t('trials:trials-list:table:status')"
show-overflow-tooltip
sortable="custom"
min-width="120"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.TrialStatusStr === 'Initializing'" type="info">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag v-if="scope.row.TrialStatusStr === 'Ongoing'" type="primary">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag v-if="scope.row.TrialStatusStr === 'Completed'" type="warning">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag v-if="scope.row.TrialStatusStr === 'Stopped'" type="danger">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag
v-if="scope.row.TrialStatusStr === 'Initializing'"
type="info"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag
v-if="scope.row.TrialStatusStr === 'Ongoing'"
type="primary"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag
v-if="scope.row.TrialStatusStr === 'Completed'"
type="warning"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag
v-if="scope.row.TrialStatusStr === 'Stopped'"
type="danger"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
</template>
</el-table-column>
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="ExpetiedTaskCount"
:label="$t('trials:trials-list:table:ExpetiedTaskCount')" show-overflow-tooltip sortable="custom"
min-width="120" />
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="ReReadingApprovalCount"
:label="$t('trials:trials-list:table:ReReadingApprovalCount')" show-overflow-tooltip sortable="custom"
min-width="180" />
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="PendingReconciliationCount"
:label="$t('trials:trials-list:table:PendingReconciliationCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="PendingResponseCount"
:label="$t('trials:trials-list:table:PendingResponseCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:crc', 'role:cra'])" prop="CRC_UrgentCount"
:label="$t('trials:trials-list:table:CRC_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:crc', 'role:cra'])" prop="CRC_QCQuestionCount"
:label="$t('trials:trials-list:table:CRC_QCQuestionCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:crc', 'role:cra'])" prop="CRC_CheckQuestionCount"
:label="$t('trials:trials-list:table:CRC_CheckQuestionCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_ReadingCriterionList"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')" show-overflow-tooltip min-width="160">
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="ExpetiedTaskCount"
:label="$t('trials:trials-list:table:ExpetiedTaskCount')"
show-overflow-tooltip
sortable="custom"
min-width="120"
/>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="ReReadingApprovalCount"
:label="$t('trials:trials-list:table:ReReadingApprovalCount')"
show-overflow-tooltip
sortable="custom"
min-width="180"
/>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="PendingReconciliationCount"
:label="$t('trials:trials-list:table:PendingReconciliationCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="PendingResponseCount"
:label="$t('trials:trials-list:table:PendingResponseCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:crc', 'role:cra'])"
prop="CRC_UrgentCount"
:label="$t('trials:trials-list:table:CRC_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:crc', 'role:cra'])"
prop="CRC_QCQuestionCount"
:label="$t('trials:trials-list:table:CRC_QCQuestionCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:crc', 'role:cra'])"
prop="CRC_CheckQuestionCount"
:label="$t('trials:trials-list:table:CRC_CheckQuestionCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_ReadingCriterionList"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
show-overflow-tooltip
min-width="160"
>
<template slot-scope="scope">
{{ scope.row.IR_ReadingCriterionList.join(', ') }}
</template>
</el-table-column>
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_UrgentCount"
:label="$t('trials:trials-list:table:IR_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_UnReadCount"
:label="$t('trials:trials-list:table:IR_UnReadCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_TotalReadCount"
:label="$t('trials:trials-list:table:IR_TotalReadCount')" show-overflow-tooltip sortable="custom"
min-width="170" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_PMEmailList"
:label="$t('trials:trials-list:table:IR_PMEmailList')" show-overflow-tooltip min-width="170">
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_UrgentCount"
:label="$t('trials:trials-list:table:IR_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_UnReadCount"
:label="$t('trials:trials-list:table:IR_UnReadCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_TotalReadCount"
:label="$t('trials:trials-list:table:IR_TotalReadCount')"
show-overflow-tooltip
sortable="custom"
min-width="170"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_PMEmailList"
:label="$t('trials:trials-list:table:IR_PMEmailList')"
show-overflow-tooltip
min-width="170"
>
<template slot-scope="scope">
{{ scope.row.IR_PMEmailList.join(', ') }}
</template>
</el-table-column>
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_UrgentCount"
:label="$t('trials:trials-list:table:IQC_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_ToBeClaimedCount"
:label="$t('trials:trials-list:table:IQC_ToBeClaimedCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_AuditToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_AuditToBeDealedCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_QuestionToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_QuestionToBeDealedCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:mim'])" prop="MIM_UrgentCount"
:label="$t('trials:trials-list:table:MIM_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_UrgentCount"
:label="$t('trials:trials-list:table:IQC_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_ToBeClaimedCount"
:label="$t('trials:trials-list:table:IQC_ToBeClaimedCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_AuditToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_AuditToBeDealedCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_QuestionToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_QuestionToBeDealedCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_UrgentCount"
:label="$t('trials:trials-list:table:MIM_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<!-- <el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_UrgentCount"
@@ -244,63 +526,127 @@
sortable="custom"
min-width="160"
/> -->
<el-table-column v-if="hasPermi(['role:mim'])" prop="MIM_PendingReviewCount"
:label="$t('trials:trials-list:table:MIM_PendingReviewCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:mim'])" prop="MIM_PendingResponseCount"
:label="$t('trials:trials-list:table:MIM_PendingResponseCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:spm', 'role:cpm'])" prop="SPM_ReReadingApprovalCount"
:label="$t('trials:trials-list:table:SPM_ReReadingApprovalCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:spm', 'role:cpm'])" prop="SPM_ReviewerSelectApprovalCount" :label="$t('trials:trials-list:table:SPM_ReviewerSelectApprovalCount')
" show-overflow-tooltip sortable="custom" min-width="160" />
<el-table-column prop="CreateTime" :label="$t('trials:trials-list:table:createDate')" show-overflow-tooltip
sortable="custom" width="180" />
<el-table-column :label="$t('common:action:action')" width="260" align="left" fixed="right">
<el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_PendingReviewCount"
:label="$t('trials:trials-list:table:MIM_PendingReviewCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_PendingResponseCount"
:label="$t('trials:trials-list:table:MIM_PendingResponseCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:spm', 'role:cpm'])"
prop="SPM_ReReadingApprovalCount"
:label="$t('trials:trials-list:table:SPM_ReReadingApprovalCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:spm', 'role:cpm'])"
prop="SPM_ReviewerSelectApprovalCount"
:label="
$t('trials:trials-list:table:SPM_ReviewerSelectApprovalCount')
"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
prop="CreateTime"
:label="$t('trials:trials-list:table:createDate')"
show-overflow-tooltip
sortable="custom"
width="180"
/>
<el-table-column
:label="$t('common:action:action')"
width="260"
align="left"
fixed="right"
>
<template slot-scope="scope">
<!-- 详情 -->
<el-button v-hasPermi="['trials:trials-list:panel']" circle icon="el-icon-info" :disabled="(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm']) ||
hasPermi(['role:op']) ||
hasPermi(['role:dev']) ||
hasPermi(['role:admin'])
))
" :title="$t('trials:trials-list:action:panel')" @click.stop="handleDetail(scope.row)" />
<el-button
v-hasPermi="['trials:trials-list:panel']"
circle
icon="el-icon-info"
:disabled="
(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm'])
))
"
:title="$t('trials:trials-list:action:panel')"
@click.stop="handleDetail(scope.row)"
/>
<!-- 编辑项目基本信息 -->
<el-button v-hasPermi="['trials:trials-list:edit']" circle icon="el-icon-edit-outline"
:disabled="scope.row.IsDeleted" :title="$t('trials:trials-list:action:edit')"
@click.stop="handleEdit(scope.row)" />
<el-button
v-hasPermi="['trials:trials-list:edit']"
circle
icon="el-icon-edit-outline"
:disabled="scope.row.IsDeleted"
:title="$t('trials:trials-list:action:edit')"
@click.stop="handleEdit(scope.row)"
/>
<!-- 修改项目状态 -->
<el-button v-hasPermi="['trials:trials-list:status']" circle icon="el-icon-edit"
:disabled="scope.row.IsDeleted" :title="$t('trials:trials-list:action:status')"
@click.stop="handleStatus(scope.row)" />
<el-button
v-hasPermi="['trials:trials-list:status']"
circle
icon="el-icon-edit"
:disabled="scope.row.IsDeleted"
:title="$t('trials:trials-list:action:status')"
@click.stop="handleStatus(scope.row)"
/>
<!--项目文档-->
<el-button v-hasPermi="[
'trials:trials-panel:trial-summary:trial-document:inspect',
'trials:trials-panel:trial-summary:trial-document:manage',
]" circle icon="el-icon-folder-opened" :disabled="(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm'])
))
" :title="$t('trials:trials-list:action:trialDocument')" @click.stop="toTrialDocument(scope.row)" />
<el-button
v-hasPermi="[
'trials:trials-panel:trial-summary:trial-document:inspect',
'trials:trials-panel:trial-summary:trial-document:manage',
]"
circle
icon="el-icon-folder-opened"
:disabled="
(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm'])
))
"
:title="$t('trials:trials-list:action:trialDocument')"
@click.stop="toTrialDocument(scope.row)"
/>
<!-- 废除项目 -->
<el-button v-hasPermi="['trials:trials-list:abolish']" circle icon="el-icon-delete" :disabled="scope.row.IsDeleted ||
scope.row.TrialStatusStr !== 'Initializing'
" :title="$t('trials:trials-list:action:abolition')" @click.stop="handleAbandon(scope.row)" />
<el-button
v-hasPermi="['trials:trials-list:abolish']"
circle
icon="el-icon-delete"
:disabled="
scope.row.IsDeleted ||
scope.row.TrialStatusStr !== 'Initializing'
"
:title="$t('trials:trials-list:action:abolition')"
@click.stop="handleAbandon(scope.row)"
/>
<!-- 代办详情-->
<!-- <el-button-->
<!-- v-hasPermi="['trials:trials-list:abolish']"-->
@@ -315,26 +661,61 @@
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
</template>
<!-- 新增/编辑项目 -->
<el-dialog v-if="dialogVisible" :visible.sync="dialogVisible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper">
<TrialForm :trial-id="currentId" @getList="getList" @closeDialog="closeDialog" />
<el-dialog
v-if="dialogVisible"
:visible.sync="dialogVisible"
:title="title"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<TrialForm
:trial-id="currentId"
@getList="getList"
@closeDialog="closeDialog"
/>
</el-dialog>
<!-- 修改项目状态 -->
<el-dialog v-if="statusVisible" :visible.sync="statusVisible" :close-on-click-modal="false"
:title="$t('trials:trials-list:dialogTitle:changeStatus')" width="700px" custom-class="base-dialog-wrapper"
append-to-body>
<TrialStatusForm :data="currentRow" @closeDialog="closeStatusDialog" @getList="getList" />
<el-dialog
v-if="statusVisible"
:visible.sync="statusVisible"
:close-on-click-modal="false"
:title="$t('trials:trials-list:dialogTitle:changeStatus')"
width="700px"
custom-class="base-dialog-wrapper"
append-to-body
>
<TrialStatusForm
:data="currentRow"
@closeDialog="closeStatusDialog"
@getList="getList"
/>
</el-dialog>
<el-dialog v-if="doneDialogVisible" :visible.sync="doneDialogVisible" :title="doneTitle" :fullscreen="true"
append-to-body custom-class="base-dialog-wrapper">
<DoneList :trial-id="currentId" @getList="getList" @closeDialog="doneDialogVisible = false" />
<el-dialog
v-if="doneDialogVisible"
:visible.sync="doneDialogVisible"
:title="doneTitle"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<DoneList
:trial-id="currentId"
@getList="getList"
@closeDialog="doneDialogVisible = false"
/>
</el-dialog>
</BaseContainer>
</template>
@@ -516,7 +897,7 @@ export default {
this.$confirm(res.ErrorMessage, {
type: 'warning',
showCancelButton: false,
callback: (action) => { },
callback: (action) => {},
})
}
})
@@ -541,7 +922,7 @@ export default {
this.currentRow = { ...row }
this.abandonTrial()
})
.catch(() => { })
.catch(() => {})
},
// 废除项目
abandonTrial() {
@@ -573,10 +954,7 @@ export default {
!(
this.hasPermi(['role:qa']) ||
this.hasPermi(['role:ea']) ||
this.hasPermi(['role:pm']) ||
hasPermi(['role:op']) ||
hasPermi(['role:dev']) ||
hasPermi(['role:admin'])
this.hasPermi(['role:pm'])
)
) {
return
@@ -4,108 +4,158 @@
<div class="title" v-if="isDoc">
{{ TITLE }}
</div>
<el-row v-if="isSystem" style="width: 100%;">
<el-col :span="12">
<h3>{{ TITLE }}</h3>
</el-col>
<el-col :span="12" style="text-align:right;">
<h3>
<Pagination class="page" :total="total" :page.sync="searchData.pageIndex" :limit.sync="searchData.pageSize"
layout="total, sizes, prev, pager, next" :background="false" style="display: inline-block;"
@pagination="getList" />
<el-button icon="el-icon-refresh-left" size="small" circle :title="$t('common:button:reset')"
@click="handleReset" />
</h3>
</el-col>
</el-row>
</template>
<!-- 搜索框 -->
<template slot="search-container">
<el-form :inline="true">
<!-- 文件类型 -->
<el-form-item :label="$t('trials:signRecords:table:fileType')">
<el-select v-model="searchData.FileTypeId" clearable style="width: 150px">
<template v-if="isSystem">
<el-option v-for="item of typeOptions" :key="item.id" :label="item.label" :value="item.id" />
</template>
<template v-else>
<el-option v-for="item of typeOptions" :key="item.FileTypeId" :label="item.FileType"
:value="item.FileTypeId" />
</template>
<el-select
v-model="searchData.FileTypeId"
clearable
style="width: 150px"
>
<el-option
v-for="item of typeOptions"
:key="item.FileTypeId"
:label="item.FileType"
:value="item.FileTypeId"
/>
</el-select>
</el-form-item>
<!-- 文件名称 -->
<el-form-item :label="$t('trials:signRecords:table:fileName')">
<el-input v-model="searchData.Name" clearable style="width: 120px" />
<el-input v-model="searchData.Name" style="width: 120px" />
</el-form-item>
<!-- 签署人 -->
<el-form-item :label="$t('trials:signRecords:table:user')" v-if="!isDoc">
<el-select v-model="searchData.UserId" clearable filterable style="width: 140px">
<el-option v-for="item of userOptions" :key="item.ConfirmUserId" :label="item.FullName"
:value="item.ConfirmUserId">
<span style="float: left">{{ item.RealName || item.FullName }}</span>
<span style="
<el-form-item
:label="$t('trials:signRecords:table:user')"
v-if="!isDoc"
>
<el-select
v-model="searchData.UserId"
clearable
filterable
style="width: 140px"
>
<el-option
v-for="item of userOptions"
:key="item.UserId"
:label="item.RealName"
:value="item.UserId"
>
<span style="float: left">{{ item.RealName }}</span>
<span
style="
float: right;
color: #8492a6;
font-size: 13px;
margin-left: 5px;
">
"
>
{{ item.UserName }}
</span>
</el-option>
</el-select>
</el-form-item>
<!-- 用户名 -->
<el-form-item :label="$t('trials:signRecords:table:userName')" v-if="isSystem">
<el-input v-model="searchData.userName" clearable style="width: 120px" />
</el-form-item>
<!-- 用户类型 -->
<el-form-item :label="$t('trials:signRecords:table:userType')" v-if="!isDoc">
<el-select v-model="searchData.UserTypeId" clearable filterable style="width: 120px">
<el-option v-for="item of userTypeOptions" v-show="item.UserTypeEnum !== 26 && item.UserTypeEnum !== 27"
:key="item.Id" :label="item.UserTypeShortName" :value="item.Id">
<el-form-item
:label="$t('trials:signRecords:table:userType')"
v-if="!isDoc"
>
<el-select
v-model="searchData.UserTypeId"
clearable
filterable
style="width: 120px"
>
<el-option
v-for="item of userTypeOptions"
v-show="item.UserTypeEnum !== 26 && item.UserTypeEnum !== 27"
:key="item.Id"
:label="item.UserTypeShortName"
:value="item.Id"
>
<span>{{ item.UserType }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:signRecords:table:isSign')" v-if="!isDoc || !viewStatus">
<el-select v-model="searchData.IsConfirmed" clearable style="width: 120px">
<el-option v-for="i of $d.TrainingStatusEnum" :key="'IsConfirmed' + i.label" :value="i.value"
:label="i.label" />
<el-form-item
:label="$t('trials:signRecords:table:isSign')"
v-if="!isDoc || !viewStatus"
>
<el-select
v-model="searchData.IsConfirmed"
clearable
style="width: 120px"
>
<el-option
v-for="i of $d.TrainingStatusEnum"
:key="'IsConfirmed' + i.label"
:value="i.value"
:label="i.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
">
<el-select v-model="searchData.IsDeleted" clearable style="width: 120px">
<el-option v-for="i of $d.TrainingStatus" :key="'IsDeleted' + i.label" :value="i.value" :label="i.label" />
<el-form-item
:label="
isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
"
>
<el-select
v-model="searchData.IsDeleted"
clearable
style="width: 120px"
>
<el-option
v-for="i of $d.TrainingStatus"
:key="'IsDeleted' + i.label"
:value="i.value"
:label="i.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:signRecords:table:username')" v-if="isDoc">
<el-form-item
:label="$t('trials:signRecords:table:username')"
v-if="isDoc"
>
<el-input v-model="searchData.UserName" style="width: 120px" />
</el-form-item>
<el-form-item :label="$t('trials:signRecords:table:confirmTime')" v-if="isDoc || isSystem">
<el-date-picker v-model="timeList" @change="changeTimeList" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" type="datetimerange">
<el-form-item
:label="$t('trials:signRecords:table:confirmTime')"
v-if="isDoc"
>
<el-date-picker
v-model="timeList"
@change="changeTimeList"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
type="datetimerange"
>
</el-date-picker>
</el-form-item>
<el-form-item :label="$t('trials:signRecords:table:uploadTime')" v-if="isSystem">
<el-date-picker v-model="timeListC" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss"
type="datetimerange" :default-time="['00:00:00', '23:59:59']" @change="changeTimeListC" />
</el-form-item>
<el-form-item>
<!-- 查询 -->
<el-button icon="el-icon-search" type="primary" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button icon="el-icon-refresh-left" type="primary" @click="handleReset">
<el-button
icon="el-icon-refresh-left"
type="primary"
@click="handleReset"
>
{{ $t('common:button:reset') }}
</el-button>
<!-- 导出 -->
<el-button type="primary" icon="el-icon-download" :loading="exportLoading" @click="handleExport"
v-if="!isSystem || !hasPermi(['role:ea'])">
<el-button
type="primary"
icon="el-icon-download"
:loading="exportLoading"
@click="handleExport"
>
{{ $t('common:button:export') }}
</el-button>
</el-form-item>
@@ -114,25 +164,39 @@
<template slot="main-container">
<!-- 系统文件列表 -->
<el-table ref="AttachmentsManagement" v-loading="loading" v-adaptive="{ bottomOffset: 60 }" :data="list" stripe
height="100" @sort-change="handleSortByColumn">
<el-table
ref="AttachmentsManagement"
v-loading="loading"
v-adaptive="{ bottomOffset: 60 }"
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="40" />
<!-- 文件类型 -->
<el-table-column prop="FileType" :label="$t('trials:signRecords:table:fileType')" show-overflow-tooltip
sortable="custom" width="160" />
<el-table-column
prop="FileType"
:label="$t('trials:signRecords:table:fileType')"
show-overflow-tooltip
sortable="custom"
width="160"
/>
<!-- 文件名称 -->
<el-table-column prop="Name" :label="$t('trials:signRecords:table:fileName')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('trials:signRecords:table:AttachmentCount')" prop="AttachmentCount"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-button type="text" @click.stop="openAttachment(scope.row, true)">{{ scope.row.AttachmentCount
}}</el-button>
</template>
</el-table-column>
<el-table-column
prop="Name"
:label="$t('trials:signRecords:table:fileName')"
show-overflow-tooltip
sortable="custom"
/>
<!-- 文件级别 -->
<el-table-column prop="IsSystemDoc" :label="$t('trials:signRecords:table:fileLevel')" show-overflow-tooltip
width="160" sortable="custom" v-if="!isSystem">
<el-table-column
prop="IsSystemDoc"
:label="$t('trials:signRecords:table:fileLevel')"
show-overflow-tooltip
width="160"
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsSystemDoc" type="primary">{{
$fd('IsSystemDoc', scope.row.IsSystemDoc)
@@ -143,10 +207,16 @@
</template>
</el-table-column>
<!-- 是否废除 -->
<el-table-column prop="IsDeleted" :label="isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
" show-overflow-tooltip sortable="custom">
<el-table-column
prop="IsDeleted"
:label="
isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
$fd('TrainingStatus', scope.row.IsDeleted)
@@ -157,11 +227,20 @@
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column prop="CreateTime" :label="$t('trials:signRecords:table:uploadTime')" show-overflow-tooltip
width="160" sortable="custom" />
<el-table-column
prop="CreateTime"
:label="$t('trials:signRecords:table:uploadTime')"
show-overflow-tooltip
width="160"
sortable="custom"
/>
<!-- 是否签署 -->
<el-table-column prop="ConfirmTime" :label="$t('trials:signRecords:table:isSign')" show-overflow-tooltip
sortable="custom">
<el-table-column
prop="ConfirmTime"
:label="$t('trials:signRecords:table:isSign')"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsConfirmed" type="primary">{{
$fd('TrainingStatusEnum', scope.row.IsConfirmed)
@@ -172,55 +251,86 @@
</template>
</el-table-column>
<!-- 签署人 -->
<el-table-column prop="RealName" :label="$t('trials:signRecords:table:user')" show-overflow-tooltip
sortable="custom" v-if="!isDoc || !viewStatus" />
<el-table-column
prop="RealName"
:label="$t('trials:signRecords:table:user')"
show-overflow-tooltip
sortable="custom"
v-if="!isDoc || !viewStatus"
/>
<!-- 用户名 -->
<el-table-column prop="UserName" :label="$t('trials:signRecords:table:userName')" show-overflow-tooltip
sortable="custom" />
<el-table-column
prop="UserName"
:label="$t('trials:signRecords:table:userName')"
show-overflow-tooltip
sortable="custom"
/>
<!-- 用户类型 -->
<el-table-column prop="UserConfirmedUserTypeList" :label="$t('trials:signRecords:table:userType')"
show-overflow-tooltip>
<el-table-column
prop="UserConfirmedUserTypeList"
:label="$t('trials:signRecords:table:userType')"
show-overflow-tooltip
>
<template slot-scope="scope">
<span>{{
Array.isArray(scope.row.UserConfirmedUserTypeList) &&
scope.row.UserConfirmedUserTypeList.length > 0
scope.row.UserConfirmedUserTypeList.length > 0
? scope.row.UserConfirmedUserTypeList.join(', ')
: ''
}}</span>
</template>
</el-table-column>
<!-- 签署时间 -->
<el-table-column prop="ConfirmTime" :label="$t('trials:signRecords:table:confirmTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column
prop="ConfirmTime"
:label="$t('trials:signRecords:table:confirmTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button circle :title="$t('trials:signRecords:action:preview')" icon="el-icon-view"
@click="handlePreview(scope.row)" />
<el-button
circle
:title="$t('trials:signRecords:action:preview')"
icon="el-icon-view"
@click="handlePreview(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" v-if="!isSystem" />
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
</template>
<!-- 预览文件 -->
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="$t('trials:signRecords:action:preview')"
:fullscreen="true" append-to-body custom-class="base-dialog-wrapper">
<span style="position: fixed; left: 16px; top: 45px;cursor: pointer;font-size: 18px;color:#409EFF"
@click.stop="openAttachment(currentRow)" v-if="currentRow.AttachmentCount">{{
$t('trials:signRecords:table:AttachmentCount') }} ({{
currentRow.AttachmentCount }})</span>
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<PreviewFile v-if="previewVisible" :file-path="currentPath" :file-type="currentType" @getList="getList" />
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:title="$t('trials:signRecords:action:preview')"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<div
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<PreviewFile
v-if="previewVisible"
:file-path="currentPath"
:file-type="currentType"
@getList="getList"
/>
</div>
</el-dialog>
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
:isView="true" @getList="getList" />
<attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible" :isView="true"
v-if="perview_visible" />
</BaseContainer>
</template>
<script>
@@ -229,23 +339,16 @@ import {
getTrialUserSelect,
getTrialUserTypeList,
getTrialDocAndSystemDocType,
getSysDocumentConfirmList,
getSysDocSignUserList
} from '@/api/trials'
import { pMTrainingRecordList_Export, getSysDocumentConfirmList_Export } from '@/api/export'
import { pMTrainingRecordList_Export } from '@/api/export'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import PreviewFile from '@/components/PreviewFile/index'
import attachmentPreview from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentPreview'
import attachmentList from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentList'
const searchDataDefault = () => {
return {
UserName: null,
StartConfirmTime: null,
EndConfirmTime: null,
EndCreateTime: null,
BeginCreateTime: null,
userName: null,
FileTypeId: '',
Name: '',
UserId: '',
@@ -258,7 +361,7 @@ const searchDataDefault = () => {
}
export default {
name: 'AttachmentsManagement',
components: { BaseContainer, Pagination, PreviewFile, attachmentPreview, attachmentList },
components: { BaseContainer, Pagination, PreviewFile },
props: {
isDoc: {
type: Boolean,
@@ -272,10 +375,6 @@ export default {
type: Boolean,
default: false,
},
isSystem: {
type: Boolean,
default: false,
}
},
data() {
return {
@@ -294,14 +393,6 @@ export default {
trialId: this.$route.query.trialId,
exportLoading: false,
timeList: [],
timeListC: [],
SystemDocumentId: null,
perview_visible: null,
config: {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
},
}
},
mounted() {
@@ -310,16 +401,6 @@ export default {
this.getUserType()
},
methods: {
openAttachment(row, isList = false) {
if (!row.AttachmentCount) return false
this.SystemDocumentId = row.Id
this.currentRow = { ...row }
if (!isList) {
this.perview_visible = true
} else {
this.config.visible = true
}
},
changeTimeList() {
if (this.timeList) {
this.searchData.StartConfirmTime = this.timeList[0]
@@ -329,26 +410,8 @@ export default {
this.searchData.EndConfirmTime = null
}
},
changeTimeListC() {
if (this.timeListC) {
this.searchData.BeginCreateTime = this.timeListC[0]
this.searchData.EndCreateTime = this.timeListC[1]
} else {
this.searchData.BeginCreateTime = null
this.searchData.EndCreateTime = null
}
},
handleExport() {
this.exportLoading = true
if (this.isSystem) {
return getSysDocumentConfirmList_Export(this.searchData)
.then(() => {
this.exportLoading = false
})
.catch((err) => {
this.exportLoading = false
})
}
pMTrainingRecordList_Export(this.searchData)
.then(() => {
this.exportLoading = false
@@ -369,52 +432,29 @@ export default {
this.searchData.UserTypeId = IR.Id
}
}
if (this.isSystem) {
getSysDocumentConfirmList(this.searchData)
.then(async (res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
})
.catch(() => {
this.loading = false
})
} else {
this.searchData.TrialId = this.trialId
getDocumentConfirmList(this.searchData)
.then(async (res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
})
.catch(() => {
this.loading = false
})
}
this.searchData.TrialId = this.trialId
getDocumentConfirmList(this.searchData)
.then(async (res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
console.log(this.total)
})
.catch(() => {
this.loading = false
})
},
// 获取文件类型下拉数据
getTypeOptions() {
if (this.isSystem) {
this.typeOptions = this.$d.Sys_Document
} else {
getTrialDocAndSystemDocType(this.trialId).then((res) => {
this.typeOptions = res.Result
})
}
getTrialDocAndSystemDocType(this.trialId).then((res) => {
this.typeOptions = res.Result
})
},
// 获取当前项目下参与者信息
getUserSelect() {
if (this.isSystem) {
getSysDocSignUserList().then((res) => {
this.userOptions = res.Result
})
} else {
getTrialUserSelect(this.trialId).then((res) => {
this.userOptions = res.Result
})
}
getTrialUserSelect(this.trialId).then((res) => {
this.userOptions = res.Result
})
},
// 获取用户类型下拉数据
getUserType() {
@@ -441,7 +481,6 @@ export default {
handleReset() {
this.searchData = searchDataDefault()
this.timeList = []
this.timeListC = []
this.getList()
this.$nextTick(() => {
this.$refs.AttachmentsManagement.clearSort()
@@ -5,9 +5,17 @@
<el-form :inline="true">
<!-- 文件类型 -->
<el-form-item :label="$t('trials:self-attachment:table:fileType')">
<el-select v-model="searchData.FileTypeId" clearable style="width:150px;">
<el-option v-for="item of typeOptions" :key="item.FileTypeId" :label="item.FileType"
:value="item.FileTypeId" />
<el-select
v-model="searchData.FileTypeId"
clearable
style="width:150px;"
>
<el-option
v-for="item of typeOptions"
:key="item.FileTypeId"
:label="item.FileType"
:value="item.FileTypeId"
/>
</el-select>
</el-form-item>
<!-- 文件名称 -->
@@ -18,7 +26,7 @@
<el-form-item :label="$t('trials:self-attachment:table:isSign')">
<el-select v-model="searchData.IsSign" clearable style="width:120px;">
<template v-for="item of $d.TrainingStatusEnum">
<el-option v-if="item.raw.ValueCN !== '无'" :label="item.label" :value="item.value" :key="item.id" />
<el-option v-if="item.raw.ValueCN !== '无'" :label="item.label" :value="item.value" :key="item.id"/>
</template>
</el-select>
</el-form-item>
@@ -36,71 +44,104 @@
</template>
<template slot="main-container">
<!-- 系统文件列表 -->
<el-table ref="TrialAttachments" v-loading="loading" v-adaptive="{ bottomOffset: 60 }" :data="list" stripe
height="100" @sort-change="handleSortByColumn">
<el-table
ref="TrialAttachments"
v-loading="loading"
v-adaptive="{bottomOffset:60}"
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table-column type="selection" width="50" />
<el-table-column type="index" width="40" />
<!-- 文件类型 -->
<el-table-column prop="FileType" :label="$t('trials:self-attachment:table:fileType')" show-overflow-tooltip
sortable="custom" />
<el-table-column
prop="FileType"
:label="$t('trials:self-attachment:table:fileType')"
show-overflow-tooltip
sortable="custom"
/>
<!-- 文件名称 -->
<el-table-column prop="Name" :label="$t('trials:self-attachment:table:fileName')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('trials:self-attachment:table:AttachmentCount')" prop="AttachmentCount"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-button type="text" @click.stop="openAttachment(scope.row, true)">{{ scope.row.AttachmentCount
}}</el-button>
</template>
</el-table-column>
<el-table-column
prop="Name"
:label="$t('trials:self-attachment:table:fileName')"
show-overflow-tooltip
sortable="custom"
/>
<!-- 是否废除 -->
<el-table-column prop="IsDeleted" :label="$t('trials:self-attachment:table:isDeleted')" show-overflow-tooltip
sortable="custom">
<el-table-column
prop="IsDeleted"
:label="$t('trials:self-attachment:table:isDeleted')"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{ $fd('TrainingStatus', scope.row.IsDeleted) }}</el-tag>
<el-tag v-else type="primary">{{ $fd('TrainingStatus', scope.row.IsDeleted) }}</el-tag>
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column prop="CreateTime" :label="$t('trials:self-attachment:table:uploadTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column
prop="CreateTime"
:label="$t('trials:self-attachment:table:uploadTime')"
show-overflow-tooltip
sortable="custom"
/>
<!-- 是否签署 -->
<el-table-column prop="ConfirmTime" :label="$t('trials:self-attachment:table:isSign')" show-overflow-tooltip
sortable="custom">
<el-table-column
prop="ConfirmTime"
:label="$t('trials:self-attachment:table:isSign')"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.IsConfirmed" type="primary">{{ $fd('TrainingStatusEnum', scope.row.IsConfirmed)
}}</el-tag>
<el-tag v-if="scope.row.IsConfirmed" type="primary">{{ $fd('TrainingStatusEnum', scope.row.IsConfirmed) }}</el-tag>
<el-tag v-else type="danger">{{ $fd('TrainingStatusEnum', scope.row.IsConfirmed) }}</el-tag>
</template>
</el-table-column>
<!-- 签署时间 -->
<el-table-column prop="ConfirmTime" :label="$t('trials:self-attachment:table:signTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column
prop="ConfirmTime"
:label="$t('trials:self-attachment:table:signTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button icon="el-icon-view" circle :title="$t('trials:self-attachment:action:preview')"
@click="handlePreview(scope.row)" />
<el-button
icon="el-icon-view"
circle
:title="$t('trials:self-attachment:action:preview')"
@click="handlePreview(scope.row)"
/>
<!-- 签署 -->
<el-button icon="el-icon-edit-outline" circle :disabled="!!scope.row.ConfirmTime"
:title="$t('trials:self-attachment:action:sign')" @click="handleSign(scope.row)" />
<el-button
icon="el-icon-edit-outline"
circle
:disabled="!!scope.row.ConfirmTime"
:title="$t('trials:self-attachment:action:sign')"
@click="handleSign(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
</template>
<!-- 预览文件 -->
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper">
<span style="position: fixed; left: 16px; top: 45px;cursor: pointer;font-size: 18px;color:#409EFF"
@click.stop="openAttachment(currentRow)" v-if="currentRow.AttachmentCount">{{
$t('trials:self-attachment:table:AttachmentCount') }} ({{
currentRow.AttachmentCount }})</span>
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:title="title"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<span v-if="!currentIsConfirm" style="position: fixed;right: 75px;top: 14px;">
<span style="color:red;margin-right:10px;">
<!-- 请仔细阅读文件并签名确认 -->
@@ -108,8 +149,13 @@
<span v-show="duration < currentMinMinutes * 60">{{ `(${currentMinMinutes * 60 - duration}s)` }}</span>
</span>
<!-- 签署 -->
<el-button size="small" type="primary" :disabled="timer !== null || duration === 0" :loading="btnLoading"
@click="handleConfirm">
<el-button
size="small"
type="primary"
:disabled="timer !== null || duration === 0"
:loading="btnLoading"
@click="handleConfirm"
>
{{ $t('common:button:sign') }}
<!-- {{ duration >= currentMinMinutes * 60?'确认':`确认(${currentMinMinutes * 60 - duration}s)` }} -->
</el-button>
@@ -121,19 +167,19 @@
</el-dialog>
<!-- 签名弹框 -->
<el-dialog v-if="signVisible" :visible.sync="signVisible" :close-on-click-modal="false" width="600px"
append-to-body>
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
append-to-body
>
<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>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${ currentUser })` }}</span>
</div>
<SignForm :is-system-doc="currentRow.IsSystemDoc" :document-id="currentRow.Id" :file-name="fileName"
:trial-id="trialId" @closeDialog="closeSignDialog" />
<SignForm :is-system-doc="currentRow.IsSystemDoc" :document-id="currentRow.Id" :file-name="fileName" :trial-id="trialId" @closeDialog="closeSignDialog" />
</el-dialog>
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
:isView="true" @getList="getList" />
<attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible" :isView="true"
v-if="perview_visible" />
</BaseContainer>
</template>
<script>
@@ -143,8 +189,6 @@ import Pagination from '@/components/Pagination'
import PreviewFile from '@/components/PreviewFile/index'
import SignForm from './components/SignForm'
import store from '@/store'
import attachmentPreview from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentPreview'
import attachmentList from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentList'
const searchDataDefault = () => {
return {
FileTypeId: '',
@@ -158,7 +202,7 @@ const searchDataDefault = () => {
}
export default {
name: 'TrialAttachments',
components: { BaseContainer, Pagination, PreviewFile, SignForm, attachmentPreview, attachmentList },
components: { BaseContainer, Pagination, PreviewFile, SignForm },
data() {
return {
searchData: searchDataDefault(),
@@ -179,14 +223,7 @@ export default {
fileName: '',
currentUser: zzSessionStorage.getItem('userName'),
typeOptions: [],
trialId: this.$route.query.trialId,
SystemDocumentId: null,
perview_visible: null,
config: {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
},
trialId: this.$route.query.trialId
}
},
mounted() {
@@ -203,16 +240,6 @@ export default {
}
},
methods: {
openAttachment(row, isList = false) {
if (!row.AttachmentCount) return false
this.SystemDocumentId = row.Id
this.currentRow = { ...row }
if (!isList) {
this.perview_visible = true
} else {
this.config.visible = true
}
},
// 获取系统文件数据
getList() {
this.loading = true
@@ -309,8 +336,8 @@ export default {
// 文档签署已完成,是否关闭弹窗?
this.$confirm(this.$t('trials:self-attachment:message:closeDocument')).then(() => {
this.previewVisible = false
}).catch(() => { })
}).catch(()=>{})
} else {
this.handleSign(res.Result)
}
@@ -729,7 +729,7 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${
@@ -766,7 +766,7 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${
@@ -801,7 +801,7 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${
@@ -277,7 +277,7 @@ export default {
}
}
</script>
<style lang="scss" scoped>
<style lang="scss">
.preview-wrapper{
display: flex;
flex-direction: row !important;
@@ -1406,7 +1406,7 @@ export default {
)
var token = getToken()
var path = ''
if (row.ReadingTool === 0 || row.ReadingTool === 2) {
if (row.ReadingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${row.TrialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${row.TrialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
File diff suppressed because it is too large Load Diff
@@ -203,6 +203,7 @@ export default {
console.log(toolsUtilities)
this.subjectCode = this.$route.query.subjectCode
var element = document.getElementById(`viewport${this.index}`)
element.addEventListener(VOLUME_NEW_IMAGE, this.handleVolumeNewImage)
element.addEventListener(Enums.Events.CAMERA_MODIFIED, this.handleCameraModified)
element.addEventListener(Enums.Events.VOI_MODIFIED, this.handleVOIModified)
@@ -248,10 +249,8 @@ export default {
this.getOrientationMarker()
this.sliderBoxHeight = imageIndex * 100 / (this.seriesInfo.imageMaxLength - 1)
}
let properties = viewport.getProperties()
if (this.index === 3) {
properties = viewport.getProperties(`cornerstoneStreamingImageVolume:PT_VOLUME_ID`)
}
var properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
@@ -325,12 +324,7 @@ export default {
viewport = renderingEngine.getViewport(this.viewportId)
if (!viewport) return
let properties = viewport.getProperties()
if (this.index === 3) {
// const volumeId = viewport.getVolumeId()
const volumeId = `cornerstoneStreamingImageVolume:PT_VOLUME_ID`
properties = viewport.getProperties(volumeId)
}
var properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(
@@ -568,21 +562,12 @@ export default {
ctx.fillRect(0, 0, rectWidth, rectHeight)
},
setWwWc() {
let properties = viewport.getProperties()
if (this.index === 3) {
properties = viewport.getProperties(`cornerstoneStreamingImageVolume:PT_VOLUME_ID`)
}
var properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
// console.log(lower, upper)
// const windowWidth = upper - lower
// const windowCenter = (upper + lower) / 2
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(
lower,
upper
)
const windowWidth = upper - lower
const windowCenter = (upper + lower) / 2
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
this.$emit('upperRangeChange', Math.round(windowWidth))
}
},
async getScreenshots() {
@@ -4,8 +4,7 @@ import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunc
import { utilities } from '@cornerstonejs/core'
const { getColormap } = utilities.colormap
function setPetColorMapTransferFunctionForVolumeActor(
volumeInfo,
isPT = false
volumeInfo
) {
const { volumeActor, preset } = volumeInfo
const mapper = volumeActor.getMapper()
@@ -23,14 +22,8 @@ function setPetColorMapTransferFunctionForVolumeActor(
// Create scalar opacity function
const ofun = vtkPiecewiseFunction.newInstance()
if (isPT) {
ofun.addPoint(0, 0.0)
ofun.addPoint(0.1, 1.0)
} else {
ofun.addPoint(0, 0.0)
ofun.addPoint(0.1, 0.9)
}
ofun.addPoint(0, 0.0)
ofun.addPoint(0.1, 0.9)
ofun.addPoint(5, 1.0)
volumeActor.getProperty().setScalarOpacity(0, ofun)
@@ -456,7 +456,7 @@ export default {
deep: true,
immediate: true,
handler(v, oldv) {
// console.log(v)
console.log(v)
}
}
},
@@ -1,10 +1,7 @@
<template>
<div ref="container" style="width:100%;height:100%" class="dicom-container">
<!-- 访视阅片 -->
<div v-if="readingCategory=== 1 && (CriterionType === 7 || ((CriterionType === 1 || CriterionType === 0) && readingVersionEnum === 1)) " class="reading-wrapper">
<VisitReview :reading-tool="readingTool" />
</div>
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
<div v-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeave">
<!-- 阅片 -->
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
@@ -32,7 +29,7 @@
</el-tab-pane>
</el-tabs>
</div>
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType === 0" class="reading-wrapper">
<div v-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType === 0" class="reading-wrapper">
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeaveCustomize">
<!-- 阅片 -->
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
@@ -174,7 +171,6 @@
</template>
<script>
import { getNextTask, readClinicalData, verifyDefaultQuestionBeAnswer } from '@/api/trials'
import VisitReview from './../dicoms3D/components/VisitReview'
import ReadPage from './components/ReadPage'
import CustomizeReadPage from './customize/CustomizeReadPage'
import ReportPage from './components/ReportPage'
@@ -191,7 +187,6 @@ import requestPoolManager from '@/utils/request-pool'
export default {
name: 'Reading',
components: {
VisitReview,
ReadPage,
ReportPage,
GlobalReview,
@@ -222,7 +217,7 @@ export default {
isReadingTaskViewInOrder: null,
firstTaskReadingCategory: null,
criterionType: null,
readingTool: 0,
readingTool: null,
dialogVisible: false,
TrialReadingCriterionId: null,
isNewSubject: null,
@@ -234,8 +229,7 @@ export default {
isFullscreen: false,
tipVisible: false,
closeCDVisible: false,
cdVisitTaskId: '',
readingVersionEnum: null
cdVisitTaskId: ''
}
},
mounted() {
@@ -272,7 +266,7 @@ export default {
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
// this.isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
// this.criterionType = this.$router.currentRoute.query.criterionType
this.readingTool = this.$router.currentRoute.query.readingTool ? Number(this.$router.currentRoute.query.readingTool) : 0
// this.readingTool = this.$router.currentRoute.query.readingTool
this.TrialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
// this.isNewSubject = this.$router.currentRoute.query.isNewSubject
@@ -347,7 +341,6 @@ export default {
localStorage.setItem('IsExistUnprocessedFeedback', res.Result.IsExistUnprocessedFeedback)
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
this.readingCategory = res.Result.ReadingCategory
this.readingVersionEnum = res.Result.ReadingVersionEnum
this.questionFormChangeState = false
this.questionFormChangeNum = 0
if (this.isExistsClinicalData && this.isNeedReadClinicalData && !this.isReadClinicalData) {
@@ -596,10 +589,6 @@ export default {
position: relative;
}
}
::v-deep .el-radio__input.is-disabled.is-checked .el-radio__inner {
background-color: #428bca;
border-color: #428bca;
}
.full-dialog-container{
::v-deep.is-fullscreen .el-dialog__body{
@@ -1,276 +0,0 @@
<template>
<el-form ref="fusionForm" :model="fusionForm" label-width="120px" label-position="left">
<!-- 任务名称 -->
<el-form-item :label="$t('trials:lugano:fusionDialog:label:taskBlindName')" prop="taskBlindName">
<el-select v-model="fusionForm.visitTaskId" clearable @change="handleTaskIdChange" disabled>
<el-option v-for="item in taskList" :key="item.VisitTaskId" :label="item.TaskBlindName"
:value="item.VisitTaskId" />
</el-select>
</el-form-item>
<!-- 检查 -->
<el-form-item :label="$t('trials:lugano:fusionDialog:label:study')" prop="studyId" :rules="[
{ required: true, message: $t('common:ruleMessage:select'), trigger: 'blur' }
]">
<el-select v-model="fusionForm.studyId" clearable @change="handleStudyIdChange">
<el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode" :value="item.StudyId" />
</el-select>
</el-form-item>
<!-- 融合图像 -->
<label style="color: #dfdfdf;line-height: 36px;vertical-align: middle;font-size: 14px;">{{
$t('trials:lugano:fusionDialog:label:fusionImages') }}</label>
<div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom:10px;"
class="series-table">
<div style="border: 1px solid #5e5e5e;border-radius: 5px;padding: 0 10px;">
<!-- CT/MRI序列 -->
<h3 style="color:#ddd">{{ $t('trials:lugano:fusionDialog:label:ctSeries') }}</h3>
<el-table ref="ctSeries" :data="ctSeries" :show-header="false" style="width: 380px" size="mini" height="300"
:default-sort="{ prop: 'instanceCount', order: 'descending' }" @selection-change="handleCTSelectionChange"
@select="handleCTSelect">
<el-table-column type="selection" width="30" />
<el-table-column label="" width="100">
<template slot-scope="scope">
<el-image style="width: 60px; height: 60px"
:src="`${OSSclientConfig.basePath}${scope.row.ImageResizePath}`" fit="fit" crossorigin="anonymous" />
</template>
</el-table-column>
<el-table-column label="" min-width="50" show-overflow-tooltip>
<template slot-scope="scope">
<div>#{{ scope.row.SeriesNumber }} </div>
<div>{{ scope.row.Modality }}: {{ scope.row.InstanceCount }} images T: {{
parseFloat(scope.row.SliceThickness).toFixed(digitPlaces) }}</div>
<div>{{ scope.row.Description }}</div>
</template>
</el-table-column>
</el-table>
</div>
<div style="border: 1px solid #5e5e5e;border-radius: 5px;padding: 0 10px;">
<!-- PET序列 -->
<h3 style="color:#ddd">{{ $t('trials:lugano:fusionDialog:label:ptSeries') }}</h3>
<el-table ref="petSeries" :data="petSeries" :show-header="false" style="width: 380px" size="mini" height="300"
@selection-change="handlePTSelectionChange" @select="handlePTSelect">
<el-table-column type="selection" width="30" />
<el-table-column label="" width="100">
<template slot-scope="scope">
<el-image style="width: 60px; height: 60px"
:src="`${OSSclientConfig.basePath}${scope.row.ImageResizePath}`" fit="fit" crossorigin="anonymous" />
</template>
</el-table-column>
<el-table-column label="" min-width="50" show-overflow-tooltip>
<template slot-scope="scope">
<div>#{{ scope.row.SeriesNumber }} </div>
<div>{{ scope.row.Modality }}: {{ scope.row.InstanceCount }} images T: {{
parseFloat(scope.row.SliceThickness).toFixed(digitPlaces) }}</div>
<div>{{ scope.row.Description }}</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-form-item style="text-align:right;">
<!-- 取消 -->
<el-button size="mini" @click="handleCancel">{{ $t('common:button:cancel') }}</el-button>
<!-- 确认 -->
<el-button type="primary" size="mini" @click="handleSubmitFusionSeries">
{{ $t('common:button:confirm') }}</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: 'FusionForm',
props: {
taskList: {
type: Array,
default: () => {
return []
}
},
activeTaskIndex: {
type: Number,
default: 0
}
},
data() {
return {
fusionForm: {
visitTaskId: '',
studyId: '',
taskBlindName: '',
isBaseLineTask: null,
ctSeriesInfo: {},
petSeriesInfo: {},
defaultStudyId: '',
defaultCTSeriesId: '',
defaultPTSeriesId: ''
},
studyList: [],
ctSeries: [],
petSeries: [],
petctWindow: null,
digitPlaces: 2
}
},
mounted() {
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.initForm()
},
methods: {
initForm() {
if (this.taskList.length === 0) return
this.getStudyList(this.taskList[this.activeTaskIndex])
this.handleStudyIdChange(this.studyList[0].StudyId)
if (this.studyList.length > 0) {
this.fusionForm.studyId = this.studyList[0].StudyId
this.handleStudyIdChange(this.studyList[0].StudyId)
} else {
this.fusionForm.studyId = ''
this.ctSeries = []
this.petSeries = []
}
this.fusionForm.visitTaskId = this.taskList[this.activeTaskIndex].VisitTaskId
this.fusionForm.readingTaskState = this.taskList[this.activeTaskIndex].ReadingTaskState
this.fusionForm.taskBlindName = this.taskList[this.activeTaskIndex].TaskBlindName
this.fusionForm.subjectCode = this.taskList[this.activeTaskIndex].SubjectCode
this.fusionForm.isBaseLineTask = this.taskList[this.activeTaskIndex].IsBaseLineTask
this.fusionForm.isCurrentTask = this.taskList[this.activeTaskIndex].IsCurrentTask
},
getStudyList(obj) {
if (obj) {
var studyList = obj.StudyList || []
studyList = studyList.filter(i => !i.IsCriticalSequence && i.Modalities.indexOf('CT') !== -1 && i.Modalities.indexOf('PT') !== -1)
if (studyList.length === 0) return
this.studyList = studyList
}
},
handleSubmitFusionSeries() {
this.$refs['fusionForm'].validate((valid) => {
if (!valid) return
if (Object.keys(this.fusionForm.ctSeriesInfo).length === 0 || Object.keys(this.fusionForm.petSeriesInfo).length === 0) {
// ''
this.$confirm(this.$t('trials:lugano:fusionDialog:message:checkSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
showCancelButton: false,
type: 'warning'
}).then(() => { }).catch(() => { })
return
}
var count = Math.abs(this.fusionForm.ctSeriesInfo.InstanceCount - this.fusionForm.petSeriesInfo.InstanceCount)
if (count > 10) {
// ', ?'
this.$confirm(this.$t('trials:lugano:fusionDialog:message:validSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
type: 'warning'
}).then(() => {
this.fusion()
}).catch(() => { })
} else {
this.fusion()
}
})
},
fusion() {
this.$emit('fusion', { ct: this.fusionForm.ctSeriesInfo, pt: this.fusionForm.petSeriesInfo })
},
handleCancel() {
this.$emit('close')
},
handleTaskIdChange(v) {
var idx = this.taskList.findIndex(i => i.VisitTaskId === v)
this.studyList = idx > -1 ? this.getStudyList(this.taskList[idx]) : []
this.fusionForm.taskBlindName = idx > -1 ? this.taskList[idx].TaskBlindName : ''
this.fusionForm.isBaseLineTask = idx > -1 ? this.taskList[idx].IsBaseLineTask : null
this.studyList = idx > -1 ? this.taskList[idx].StudyList : null
this.fusionForm.studyId = ''
this.fusionForm.defaultStudyId = idx > -1 ? this.taskList[idx].StudyId : ''
this.fusionForm.defaultCTSeriesId = idx > -1 ? this.taskList[idx].CTSeriesId : ''
this.fusionForm.defaultPTSeriesId = idx > -1 ? this.taskList[idx].PTSeriesId : ''
this.ctSeries = []
this.petSeries = []
},
handleStudyIdChange(v) {
var i = this.studyList.findIndex(i => i.StudyId === v)
if (i === -1) {
this.ctSeries = []
this.petSeries = []
} else {
var seriesList = this.studyList[i].SeriesList
var series = seriesList.filter(series => series.Modality === 'CT')
this.ctSeries = series.sort((a, b) => b.instanceCount - a.instanceCount)
series = seriesList.filter(series => series.Modality === 'PT')
this.petSeries = series.sort((a, b) => b.instanceCount - a.instanceCount)
}
},
handleCTSelectionChange(rows) {
if (rows.length > 0) {
this.fusionForm.ctSeriesInfo = Object.assign({}, rows[0])
} else {
this.fusionForm.ctSeriesInfo = {}
}
},
handleCTSelect(selection) {
if (selection.length > 1) {
const del_row = selection.shift()
this.$refs.ctSeries.toggleRowSelection(del_row, false)
}
},
handlePTSelectionChange(rows) {
if (rows.length > 0) {
this.fusionForm.petSeriesInfo = Object.assign({}, rows[0])
} else {
this.fusionForm.petSeriesInfo = {}
}
},
handlePTSelect(selection) {
if (selection.length > 1) {
const del_row = selection.shift()
this.$refs.petSeries.toggleRowSelection(del_row, false)
}
}
}
}
</script>
<style lang="scss" scoped>
.series-table {
::v-deep.el-table {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
::v-deep.el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
border-bottom: 1px solid #dfdfdf;
}
.el-table--border::after,
.el-table--group::after,
.el-table::before {
background-color: #1e1e1e;
}
::v-deep.el-table__header-wrapper {
th {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
}
::v-deep.el-table__body-wrapper {
tr {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
tr:hover>td {
background-color: #1e1e1e !important;
}
}
::v-deep.el-table__empty-block {
background-color: #1e1e1e !important;
}
}
</style>
@@ -1,970 +0,0 @@
<template>
<div ref="viewport-fusion" class="viewport-wrapper" @mouseup="sliderMouseup" @mousemove="sliderMousemove"
@mouseleave="sliderMouseleave" :style="{ color: series.Modality === 'PT' || isMip ? '#666' : '#ddd' }">
<div v-if="series && taskInfo" class="left-top-text">
<div v-if="taskInfo.IsExistsClinicalData && !isMip && !isFusion" class="cd-info"
:title="$t('trials:reading:button:clinicalData')">
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
@click.stop="viewCD(series.TaskInfo.VisitTaskId)" />
</div>
<h2 v-if="taskInfo.IsReadingShowSubjectInfo && series.TaskInfo" class="subject-info">
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
</h2>
<div v-if="!isMip && !isFusion">Series: #{{ series.SeriesNumber }}</div>
<div v-if="series.Stack && !isMip">Image: #{{ `${series.SliceIndex + 1}/${series.Stack.length}` }}</div>
<div v-if="!isMip && !isFusion">{{ series.Modality }}</div>
</div>
<!-- <div v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && series.TaskInfo && !isMip && !isFusion"
class="top-center-tool">
<div class="toggle-visit-container">
<div class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
@dblclick.stop="preventDefault($event)">
<i class="el-icon-caret-left" />
</div>
<div class="arrow_text">
{{ series.TaskInfo.TaskBlindName }}
</div>
<div class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
@dblclick.stop="preventDefault($event)">
<i class="el-icon-caret-right" />
</div>
</div>
</div> -->
<div v-if="series && !isMip && !isFusion" class="right-top-text">
<div>{{ series.Description }}</div>
</div>
<div v-if="series" class="left-bottom-text">
<div v-show="mousePosition.index.length > 0 && !isMip">
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}, {{ mousePosition.index[2] }}
</div>
<div
v-if="(series.Modality === 'CT' || series.Modality === 'DR' || series.Modality === 'CR') && mousePosition.value && !isMip && !isFusion">
HU: {{ mousePosition.value }}
</div>
<div v-else-if="(series.Modality === 'PT' && mousePosition.value) && !isMip && !isFusion">
SUVbw(g/ml): {{ digitPlaces === -1 ? mousePosition.value.toFixed(3) : mousePosition.value.toFixed(digitPlaces)
}}
</div>
<div v-else-if="mousePosition.value && !isMip && !isFusion">
Density: {{ mousePosition.value }}
</div>
<div v-show="imageInfo.size && !isMip && !isFusion">
W*H: {{ imageInfo.size }}
</div>
</div>
<div v-if="series && !isMip" class="right-bottom-text">
<div v-show="imageInfo.location && !isFusion">Location: {{ `${Number(imageInfo.location).toFixed(digitPlaces)} mm`
}}</div>
<div v-show="series.SliceThickness && !isFusion">Slice Thickness: {{
`${Number(series.SliceThickness).toFixed(digitPlaces)} mm`
}}</div>
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
</div>
<div class="orientation-top" v-if="!isMip">
{{ markers.top }}
</div>
<div class="orientation-right" v-if="!isMip">
{{ markers.right }}
</div>
<div class="orientation-bottom" v-if="!isMip">
{{ markers.bottom }}
</div>
<div class="orientation-left" v-if="!isMip">
{{ markers.left }}
</div>
<div v-if="isFusion" class="color_bar">
<canvas :id="`colorBar_Canvas_${viewportId}`" />
<!-- <div id="colorBar_Canvas" /> -->
</div>
<div v-if="isMip" id="rotateBar" ref="rotateBar" class="rotate_slider_box" @click.stop="clickRotate($event)">
<div id="rotateSlider" :style="{ left: rotateBarLeft + 'px' }" class="box" @click.stop.prevent="() => { return }"
@mousedown.stop="rotateBarMousedown($event)" />
</div>
<div ref="sliderBox" class="right-slider-box" @click.stop="clickSlider($event)" v-show="!isMip">
<div :style="{ top: sliderInfo.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
@mousedown.stop="sliderMousedown($event)" />
</div>
</div>
</template>
<script>
// import * as cornerstonejs from '@cornerstonejs/core'
import {
// RenderingEngine,
Enums,
// imageLoader,
metaData,
getRenderingEngine,
volumeLoader,
// eventTarget,
utilities as csUtils,
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { utilities as cstUtils } from '@cornerstonejs/tools';
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import setPetTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetTransferFunctionForVolumeActor'
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
const {
ToolGroupManager,
MIPJumpToClickTool,
VolumeRotateTool,
Enums: csToolsEnums,
} = cornerstoneTools
const { BlendModes, OrientationAxis } = Enums;
const { MouseBindings } = csToolsEnums
const { getColormap, getColormapNames } = csUtils.colormap;
const { ViewportColorbar } = cstUtils.voi.colorbar;
const { ColorbarRangeTextPosition } = cstUtils.voi.colorbar.Enums;
import { vec3, mat4 } from 'gl-matrix'
export default {
name: 'ImageViewport',
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
viewportIndex: {
type: Number,
required: true
},
},
data() {
return {
element: '',
series: {},
ctSeries: {},
petSeries: {},
isFusion: false,
isMip: false,
taskInfo: null,
sliderInfo: {
oldB: null,
oldM: null,
isMove: false,
height: 0
},
mousePosition: {
index: [],
value: null,
modalityUnit: '',
world: []
},
imageInfo: {
zoom: null,
size: null,
location: null,
sliceThickness: null,
wwwc: null
},
digitPlaces: 2,
orientationMarkers: [],
originalMarkers: [],
markers: { top: '', right: '', bottom: '', left: '' },
playClipState: false,
wwwcIdx: 2,
presetName: '',
volumeId: null,
defaultWindowLevel: {},
Colorbar: null,
rotateAngle: 0,
rotateBarLeft: 0,
rotateBarInfo: {
initX: null,
initLeft: null,
isMove: false
},
ptVolumeId: null,
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
this.initViewport()
})
},
methods: {
initViewport() {
this.element = this.$refs['viewport-fusion']
const resizeObserver = new ResizeObserver(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
if (renderingEngine) {
renderingEngine.resize(true, false)
}
})
this.element.oncontextmenu = (e) => e.preventDefault()
// resizeObserver.observe(this.element)
this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage)
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
this.element.addEventListener(cornerstoneTools.Enums.Events.MOUSE_WHEEL, this.handletoolsMouseWheel)
this.element.addEventListener('mouseleave', () => {
this.mousePosition.index = []
this.mousePosition.value = null
})
document.addEventListener('mouseup', () => {
this.sliderMouseup()
if (this.isMip) {
this.rotateBarMouseup()
}
})
document.addEventListener('mousemove', (e) => {
this.sliderMousemove(e)
if (this.isMip) {
this.rotateBarMousemove(e)
}
})
// console.log(cornerstoneTools)
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
},
stackNewImage(e) {
const { detail } = e
this.series.SliceIndex = detail.imageIndex
this.sliderInfo.height = detail.imageIndex * 100 / detail.numberOfSlices
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
let imageId = viewport.getCurrentImageId()
if (imageId) {
const imagePlaneModule = metaData.get('imagePlaneModule', imageId)
this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}`
this.imageInfo.location = imagePlaneModule.sliceLocation
this.getOrientationMarker()
// this.$emit('renderAnnotations', this.series)
let properties = viewport.getProperties()
if (this.isFusion) {
properties = viewport.getProperties(this.ptVolumeId)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const windowWidth = upper - lower
const windowCenter = (upper + lower) / 2
this.defaultWindowLevel.windowWidth = windowWidth
this.defaultWindowLevel.windowCenter = windowCenter
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
// const toolGroupId = `viewport-${this.viewportIndex}`
// const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
// toolGroup.setToolEnabled('ScaleOverlay')
}
},
setFullScreen(index) {
setTimeout(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
csUtils.jumpToSlice(viewport.element, { imageIndex: index })
viewport.render()
})
},
voiModified(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let properties = viewport.getProperties()
if (this.isFusion) {
properties = viewport.getProperties(this.volumeId)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
this.$emit('upperRangeChange', Math.round(windowWidth))
}
},
getOrientationMarker() {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const { viewUp, viewPlaneNormal } = viewport.getCamera()
const viewRight = vec3.create()
vec3.cross(viewRight, viewUp, viewPlaneNormal)
const columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]]
const rowCosines = viewRight
const rowString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(rowCosines)
const columnString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(columnCosines)
const oppositeRowString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(rowString)
const oppositeColumnString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(columnString)
this.markers.top = oppositeColumnString
this.markers.right = rowString
this.markers.bottom = columnString
this.markers.left = oppositeRowString
this.orientationMarkers = [oppositeColumnString, rowString, columnString, oppositeRowString]
if (this.originalMarkers.length === 0) {
this.originalMarkers = [...this.orientationMarkers]
}
},
setMarkers() {
const markers = [...this.orientationMarkers]
for (const key in this.markers) {
const v = markers.shift(0)
this.markers[key] = v
}
},
resetOrientationMarkers() {
if (this.originalMarkers.length > 0) {
this.orientationMarkers = [...this.originalMarkers]
this.setMarkers()
}
},
rotateOrientationMarkers(type) {
if (this.orientationMarkers.length > 0) {
if (type === 1) {
this.resetOrientationMarkers()
return
}
const markers = [...this.orientationMarkers]
if (type === 2) {
//
this.orientationMarkers[0] = markers[2]
this.orientationMarkers[2] = markers[0]
} else if (type === 3) {
//
this.orientationMarkers[1] = markers[3]
this.orientationMarkers[3] = markers[1]
} else if (type === 4) {
// 90
this.orientationMarkers = markers.slice(1, 4).concat(markers[0])
} else if (type === 5) {
// 90
this.orientationMarkers = [markers[3]].concat(markers.slice(0, 3))
}
this.setMarkers()
}
},
toggleClipPlay(isPlay, framesPerSecond) {
this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: false })
} else {
cornerstoneTools.utilities.cine.stopClip(viewport.element)
}
},
scrollPage(type) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const numImages = viewport.getImageIds().length
let newImageIdIndex = null
if (type === 0) {
newImageIdIndex = 0
} else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) {
newImageIdIndex = numImages - 1
}
// viewport.setImageIdIndex(newImageIdIndex)
csUtils.jumpToSlice(viewport.element, { imageIndex: newImageIdIndex })
cornerstoneTools.utilities.cine.stopClip(viewport.element)
},
setZoom(ratio) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
if (ratio > 0) {
viewport.setZoom(zoom * 1.05)
} else {
viewport.setZoom(zoom / 1.05)
}
viewport.render()
},
resize(forceFitToWindow) {
console.log('resize: ', forceFitToWindow)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (!forceFitToWindow) {
viewport.setZoom(0.5)
viewport.render()
} else {
viewport.setZoom(1)
viewport.render()
}
},
voiChange(v) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const voiRange = { lower: 0, upper: v }
const viewport = renderingEngine.getViewport(this.viewportId)
if (!viewport) return
let volumeId = this.isFusion ? this.ptVolumeId : this.volumeId
const viewportsContainingVolumeUID = csUtils.getViewportsWithVolumeId(
volumeId,
viewport.renderingEngineId
)
viewport.setProperties({ voiRange }, volumeId)
viewportsContainingVolumeUID.forEach((vp) => {
vp.render()
// this.$refs[vp.id].voiModified()
this.voiModified()
})
},
renderColorBar(presetName) {
var colorMap = null
this.Colorbar = null
if (presetName === 'hsv') {
colorMap = vtkColorMaps.getPresetByName(presetName)
} else {
colorMap = getColormap(presetName)
}
if (!colorMap) return false
// let colormaps = getColormapNames().map(name => getColormap(name))
// console.log(colormaps)
// const canvas = document.getElementById('colorBar_Canvas')
// this.Colorbar = new ViewportColorbar({
// id: this.volumeId,
// element: this.element,
// container: canvas,
// colormaps,
// activeColormapName: presetName,
// ticks: {
// position: ColorbarRangeTextPosition.Left,
// style: {
// font: '12px Arial',
// color: '#fff',
// maxNumTicks: 8,
// tickSize: 5,
// tickWidth: 1,
// labelMargin: 3,
// },
// },
// });
const rgbPoints = colorMap.RGBPoints
const canvas = document.getElementById(`colorBar_Canvas_${this.viewportId}`)
if (!canvas) return false
const ctx = canvas.getContext('2d')
const canvasWidth = 160
const canvasHeight = 5
const rectWidth = 160
const rectHeight = canvasHeight
canvas.width = canvasWidth
canvas.height = canvasHeight
const gradient = ctx.createLinearGradient(0, 0, rectWidth, 0)
for (let i = 0; i < rgbPoints.length; i += 4) {
let position = 0
if (rgbPoints[0] === -1) {
position = (rgbPoints[i] + 1) / 2
} else {
position = rgbPoints[i]
}
const color = `rgb(${parseInt(rgbPoints[i + 1] * 255)}, ${parseInt(rgbPoints[i + 2] * 255)}, ${parseInt(rgbPoints[i + 3] * 255)})`
gradient.addColorStop(position, color)
}
ctx.fillStyle = gradient
ctx.fillRect(0, 0, rectWidth, rectHeight)
},
setPreset(presetName) {
this.presetName = presetName
},
setColorMap(presetName) {
if (this.Colorbar) {
this.Colorbar.activeColormapName = presetName;
}
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
viewport.setProperties({ colormap: { name: presetName } }, this.volumeId)
viewport.render()
},
async prefetchMetadataInformation(imageIdsToPrefetch) {
let taskPromises = []
for (let i = 0; i < imageIdsToPrefetch.length; i++) {
taskPromises.push(cornerstoneDICOMImageLoader.wadouri.loadImage(imageIdsToPrefetch[i]).promise)
if (taskPromises.length >= 6 || i === imageIdsToPrefetch.length - 1) {
await Promise.all(taskPromises)
taskPromises = []
}
}
},
async createImageIdsAndCacheMetaData(obj) {
await createImageIdsAndCacheMetaData({
modality: obj.Modality,
imageIds: obj.ImageIds
})
},
async setSeriesInfo(obj, option = {}) {
try {
let { data, volumeId } = obj
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description) {
data.SliceIndex = this.series.SliceIndex
}
this.ptVolumeId = null
this.series = {}
let { isFusion, isMip, colorMap } = option
this.isFusion = isFusion;
this.isMip = isMip;
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (this.isFusion) {
this.$nextTick(() => {
this.renderColorBar(this.presetName)
})
let { ct, data, ctVolumeId, ptVolumeId, fusionVolumeId } = obj
this.series = { ...data }
this.ctSeries = { ...ct }
this.petSeries = { ...data }
// const maxCount = Math.max(this.ctSeries.ImageIds.length, this.petSeries.ImageIds.length)
// this.$set(this.ctSeries, 'imageMaxLength', maxCount)
// this.$set(this.petSeries, 'imageMaxLength', maxCount)
// await this.createImageIdsAndCacheMetaData(this.ctSeries)
// await this.createImageIdsAndCacheMetaData(this.petSeries)
this.volumeId = ptVolumeId
this.ptVolumeId = fusionVolumeId
await viewport
.setVolumes([
{
volumeId: this.ptVolumeId, callback: (r) => {
setPetColorMapTransferFunctionForVolumeActor(r)
console.log("融合pet渲染成功");
}
},
{
volumeId: ctVolumeId, callback: (r) => {
setCtTransferFunctionForVolumeActor(r)
console.log("融合ct渲染成功")
}
},
{
volumeId: this.volumeId, callback: (r) => {
setPetColorMapTransferFunctionForVolumeActor(r)
console.log("融合pet渲染成功");
}
},
]).then(res => {
if (colorMap) {
this.setColorMap(this.presetName)
}
})
} else {
this.series = { ...data }
this.volumeId = volumeId
if (this.isMip) {
let { volume } = obj
const ptVolumeDimensions = volume.dimensions;
const slabThickness = Math.sqrt(
ptVolumeDimensions[0] * ptVolumeDimensions[0] +
ptVolumeDimensions[1] * ptVolumeDimensions[1] +
ptVolumeDimensions[2] * ptVolumeDimensions[2]
);
viewport
.setVolumes([{
volumeId: this.volumeId,
callback: (r) => {
setPetColorMapTransferFunctionForVolumeActor(r)
console.log("mip渲染成功")
},
slabThickness,
blendMode: BlendModes.MAXIMUM_INTENSITY_BLEND,
defaultOptions: {
orientation: OrientationAxis.CORONAL
}
}]).then(res => {
if (colorMap) {
this.setColorMap(this.presetName)
}
})
} else {
viewport
.setVolumes([{
volumeId: this.volumeId, callback: (r) => {
if (this.series.Modality === 'PT') {
setPetColorMapTransferFunctionForVolumeActor(r, true)
} else {
setCtTransferFunctionForVolumeActor(r)
}
console.log("渲染成功")
}
}]).then(res => {
if (colorMap) {
this.setColorMap(this.presetName)
}
})
}
}
viewport.render()
} catch (e) {
console.log(e)
}
},
cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail
const worldPoint = currentPoints.world
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const imageData = viewport.getImageData()
if (!imageData) return
const index = imageData.imageData.worldToIndex(worldPoint)
index[0] = Math.floor(index[0])
index[1] = Math.floor(index[1])
index[2] = Math.floor(index[2])
this.mousePosition.index = index
},
toggleTask(evt, visitTaskNum, i) {
this.$emit('activeViewport', this.viewportIndex)
const num = visitTaskNum + i
if (num >= 0 && num <= this.taskInfo.VisitNum) {
this.$emit('toggleTaskByViewport', { series: this.series, visitTaskNum: num })
}
evt.stopImmediatePropagation()
evt.stopPropagation()
evt.preventDefault()
},
viewCD(taskId) {
this.$emit('previewCD', taskId)
},
setWwwcIdx(idx) {
this.wwwcIdx = idx
},
clickSlider(e) {
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
this.sliderInfo.height = height
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseup(e) {
this.sliderInfo.isMove = false
},
sliderMousedown(e) {
const boxHeight = this.$refs['sliderBox'].clientHeight
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
this.sliderInfo.oldM = e.clientY
this.sliderInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
sliderMousemove(e) {
if (!this.sliderInfo.isMove) return
const delta = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
const boxHeight = this.$refs['sliderBox'].clientHeight
if (delta < 0) return
if (delta > boxHeight) return
const height = delta * 100 / boxHeight
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
this.sliderInfo.height = height
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseleave(e) {
if (!this.sliderInfo.isMove) return
this.sliderInfo.isMove = false
},
handletoolsMouseWheel(e) {
const { viewportId, wheel } = e.detail
if (this.isMip) {
const container = document.getElementById('rotateBar')
const slider = document.getElementById('rotateSlider')
const containerWidth = container.offsetWidth
const sliderWidth = slider.offsetWidth
const maxX = containerWidth - sliderWidth
const { direction } = wheel
var x = Math.trunc(30 * ((containerWidth - sliderWidth) / 360))
if (direction > 0 && (this.rotateBarLeft + x) > maxX) {
this.rotateBarLeft = x - (containerWidth - sliderWidth - this.rotateBarLeft)
} else if (direction < 0 && (this.rotateBarLeft < x)) {
this.rotateBarLeft = containerWidth - (x - this.rotateBarLeft + sliderWidth)
} else {
this.rotateBarLeft = x * direction + this.rotateBarLeft
}
}
},
rotateBarMouseup(e) {
this.rotateBarInfo.isMove = false
},
rotateBarMousemove(e) {
//
if (!this.rotateBarInfo.isMove) return
const container = document.getElementById('rotateBar')
const slider = document.getElementById('rotateSlider')
const containerWidth = container.offsetWidth
const sliderWidth = slider.offsetWidth
let x = Math.trunc(e.clientX - this.rotateBarInfo.initX + this.rotateBarInfo.initLeft)
if (x < 0) x = 0
if (x > containerWidth - sliderWidth) x = containerWidth - sliderWidth
const deltaX = x - this.rotateBarLeft
const angle = Math.sin((deltaX * (360 / (containerWidth - sliderWidth))) * Math.PI / 180)
this.rotate(angle)
this.rotateBarLeft = x
},
rotateBarMousedown(e) {
this.rotateBarInfo.initLeft = e.srcElement.offsetLeft
this.rotateBarInfo.initX = e.clientX
this.rotateBarInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
rotate(angle) {
let renderingEngine = getRenderingEngine(this.renderingEngineId)
let viewport = renderingEngine.getViewport(this.viewportId)
const camera = viewport.getCamera()
const { viewUp, position, focalPoint } = camera
const [cx, cy, cz] = focalPoint
const [ax, ay, az] = [0, 0, 1]
const newPosition = [0, 0, 0]
const newFocalPoint = [0, 0, 0]
const newViewUp = [0, 0, 0]
const transform = mat4.identity(new Float32Array(16))
mat4.translate(transform, transform, [cx, cy, cz])
mat4.rotate(transform, transform, angle, [ax, ay, az])
mat4.translate(transform, transform, [-cx, -cy, -cz])
vec3.transformMat4(newPosition, position, transform)
vec3.transformMat4(newFocalPoint, focalPoint, transform)
mat4.identity(transform)
mat4.rotate(transform, transform, angle, [ax, ay, az])
vec3.transformMat4(newViewUp, viewUp, transform)
viewport.setCamera({
position: newPosition,
viewUp: newViewUp,
focalPoint: newFocalPoint
})
viewport.render()
},
clickRotate(e) {
// console.log('clickRotate')
const container = document.getElementById('rotateBar')
const containerWidth = container.offsetWidth
const slider = document.getElementById('rotateSlider')
const sliderWidth = slider.offsetWidth
const x = Math.trunc(e.offsetX)
const deltaX = x - this.rotateBarLeft
const angle = Math.sin((deltaX * (360 / (containerWidth - sliderWidth))) * Math.PI / 180)
this.rotate(angle)
this.rotateBarLeft = x
},
preventDefault(e) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
}
}
}
</script>
<style lang="scss" scoped>
.viewport-wrapper {
width: 100%;
height: 100%;
position: relative;
.left-top-text {
position: absolute;
left: 5px;
top: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
.cd-info {
// color: #ddd;
font-size: 18px;
}
.subject-info {
color: #f44336;
padding: 5px 0px;
margin: 0;
}
}
.top-center-tool {
position: absolute;
left: 50%;
top: 5px;
transform: translateX(-50%);
z-index: 1;
.toggle-visit-container {
display: flex;
}
.arrw_icon {
width: 20px;
height: 20px;
background-color: #3f3f3f;
text-align: center;
line-height: 20px;
border-radius: 10%;
}
.arrow_text {
height: 20px;
line-height: 20px;
background-color: #00000057;
color: #fff;
padding: 0 10px;
font-size: 14px;
}
}
.right-top-text {
position: absolute;
right: 5px;
top: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.left-bottom-text {
position: absolute;
left: 5px;
bottom: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-bottom-text {
position: absolute;
right: 5px;
bottom: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-slider-box {
position: absolute;
right: 1px;
height: calc(100% - 140px);
transform: translateY(-50%);
top: calc(50% - 30px);
width: 10px;
background: #333;
z-index: 1;
cursor: pointer;
}
.right-slider-box:after {
content: '';
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
background: #333;
}
.slider {
height: 20px;
width: 100%;
position: absolute;
top: 0;
z-index: 10;
background: #9e9e9e;
cursor: move
}
.orientation-top {
position: absolute;
left: 50%;
top: 30px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-bottom {
position: absolute;
left: 50%;
bottom: 15px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-left {
position: absolute;
top: 50%;
left: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
.orientation-right {
position: absolute;
top: 50%;
right: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
}
.color_bar {
position: absolute;
transform: rotate(-90deg);
transform-origin: right;
left: -150px;
top: 30%;
z-index: 1;
}
.rotate_slider_box {
position: absolute;
width: 380px;
height: 10px;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
background: #333;
z-index: 10;
cursor: pointer;
.box {
z-index: 10;
background: #9e9e9e;
height: 100%;
width: 20px;
position: absolute;
top: 0;
cursor: move
}
}
</style>
File diff suppressed because it is too large Load Diff
@@ -1,325 +0,0 @@
<template>
<div>
<div
v-if="!!question.GroupName && question.Type==='group'"
>
<h4 style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?question.GroupEnName:question.GroupName }}
</h4>
</div>
<template v-else>
<el-form-item
v-if="(question.ShowQuestion===1 && question.ParentTriggerValueList.includes(String(questionForm[question.ParentId]))) || question.ShowQuestion===0 "
:label="`${question.QuestionName}`"
:prop="question.Id"
:rules="[
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (questionForm[question.RelevanceId] === question.RelevanceValue))) && question.Type!=='group' && question.Type!=='summary',
message: ['radio', 'select', 'checkbox'].includes(question.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']},
]"
:class="[question.Type==='group' ? 'mb' : (question.Type==='upload' || question.QuestionName.length > 15) ?'uploadWrapper' : '']"
>
<!-- 输入框 -->
<el-input
v-if="question.Type==='input'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
/>
<!-- 多行文本输入框 -->
<el-input
v-else-if="question.Type==='textarea'"
v-model="questionForm[question.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
maxlength="500"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
/>
<!-- 下拉框 -->
<el-select
v-else-if="question.Type==='select'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2 || ((question.TableQuestionType === 2 || question.QuestionGenre === 2) && !!question.DictionaryCode)"
clearable
@change="((val)=>{formItemChange(val, question)})"
>
<template v-if="question.TableQuestionType === 1">
<el-option
v-for="item in organList"
:key="item.Id"
:label="item[question.DataTableColumn]"
:value="item[question.DataTableColumn]"
/>
</template>
<template v-else-if="question.TableQuestionType === 3 || question.QuestionGenre === 3">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:label="item.label"
/>
</template>
<template v-else-if="(question.TableQuestionType === 2 || question.QuestionGenre === 2) && question.DictionaryCode">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<!-- 单选 -->
<el-radio-group
v-else-if="question.Type==='radio'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
>
<template v-if="question.DictionaryCode">
<el-radio
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:label="String(item.value)"
>
{{ item.label }}
</el-radio>
</template>
<template v-else-if="question.TypeValue">
<el-radio
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</template>
</el-radio-group>
<!-- 复选框 -->
<el-checkbox-group
v-else-if="question.Type==='checkbox'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
>
<el-checkbox
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-checkbox>
</el-checkbox-group>
<!-- 数值 -->
<template v-else-if="question.Type==='number'">
<el-input-number
v-if="question.ValueType === 0"
v-model="questionForm[question.Id]"
:precision="0"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 3"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 1 || question.ValueType === 2"
v-model="questionForm[question.Id]"
:precision="digitPlaces"
:disabled="readingTaskState >= 2"
/>
</template>
<el-input
v-else-if="question.Type==='calculation'"
v-model="questionForm[question.Id]"
disabled
>
<template v-if="question.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(question.Unit)) }}
</template>
</el-input>
<!-- 上传图像 -->
<el-upload
v-else-if="question.Type==='upload'"
action
:accept="accept"
:limit="question.ImageCount"
:on-preview="handlePictureCardPreview"
:before-upload="handleBeforeUpload"
:http-request="uploadScreenshot"
list-type="picture-card"
:on-remove="handleRemove"
:file-list="fileList"
:class="{disabled:fileList.length >= question.ImageCount}"
:disabled="readingTaskState >= 2"
>
<i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}">
<img
class="el-upload-list__item-thumbnail"
:src="OSSclientConfig.basePath + file.url"
alt=""
>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
v-if="readingTaskState < 2"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete" />
</span>
</span>
</div>
</el-upload>
<el-dialog
v-if="question.Type==='upload'"
append-to-body
:visible.sync="imgVisible"
width="600px"
>
<el-image :src="imageUrl" width="100%">
<div slot="placeholder" class="image-slot">
加载中<span class="dot">...</span>
</div>
</el-image>
</el-dialog>
</el-form-item>
</template>
<question-form-item
v-for="(item) in question.Childrens"
:key="item.Id"
:question="item"
:question-form="questionForm"
:reading-task-state="readingTaskState"
:visitTaskId="visitTaskId"
@resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData"
/>
</div>
</template>
<script>
// import { uploadReadingAnswerImage } from '@/api/trials'
import { mapGetters } from 'vuex'
export default {
name: 'QuestionFormItem',
props: {
questionForm: {
type: Object,
default() {
return {}
}
},
question: {
type: Object,
default() {
return {}
}
},
readingTaskState: {
type: Number,
required: true
},
visitTaskId: {
type: String,
default: ''
}
},
data() {
return {
fileList: [],
accept: '.png,.jpg,.jpeg',
imgVisible: false,
imageUrl: '',
urls: [],
digitPlaces: 2
}
},
computed: {
...mapGetters(['language'])
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v) {
// console.log(v)
}
}
},
mounted() {
let digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
},
methods: {
formItemChange(v, question) {
console.log('formItemChange')
if (question.Childrens.length > 0) {
this.resetChild(question.Childrens)
} else {
this.$emit('setFormItemData', { key: question.Id, val: v })
}
},
resetChild(obj) {
obj.forEach(i => {
this.$emit('resetFormItemData', i.Id)
if (i.Childrens && i.Childrens.length > 0) {
this.resetChild(i.Childrens)
}
})
},
resetFormItemData(v) {
this.$emit('resetFormItemData', v)
},
setFormItemData(obj) {
this.$emit('setFormItemData', obj)
},
}
}
</script>
<style lang="scss" scoped>
.mb{
margin-bottom: 0px;
}
.disabled{
::v-deep .el-upload--picture-card {
display: none;
}
}
.uploadWrapper{
display: flex;
flex-direction: column !important;
align-items: flex-start;
}
::v-deep .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-input-group__append, .el-input-group__prepend{
padding: 0 10px;
}
::v-deep .el-form-item__content {
width: 100%;
}
::v-deep .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
// ::v-deep .el-radio__input.is-disabled.is-checked .el-radio__inner {
// background-color: #428bca;
// border-color: #428bca;
// }
</style>
@@ -1,357 +0,0 @@
<template>
<div class="table-question-form">
<div style="display: flex;justify-content: space-between;">
<h3 v-if="qsForm.LesionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ qsForm.LesionName }}
</h3>
<!-- 关闭 -->
<div>
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="close" />
</div>
</div>
<el-form-item
:label="$t('trials:reading:title:lesionType')"
prop="LesionType"
:rules="[
{ required:true,message: $t('common:ruleMessage:select'), trigger: ['blur']},
]"
>
<!-- 下拉框 -->
<el-select
v-model="qsForm.LesionType"
filterable
:disabled="!isCurrentTask || readingTaskState>=2 || !isBaseLineTask"
@change="((val)=>{lesionTypeChange(val)})"
>
<el-option
v-for="item of $d.LesionType"
v-show="!(isBaseLineTask && item.value === 2)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<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 && (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']},
]"
>
<!-- 输入框 -->
<template v-if="qs.Type==='input' || qs.Type==='number'">
<el-input
v-if="qs.Type==='input' || qs.Type==='number'"
v-model="qsForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 || qs.QuestionMark === 0 || qs.QuestionMark === 1 || qs.QuestionMark === 2 || qs.QuestionMark === 5 || (qs.QuestionMark === 6 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))|| (qs.QuestionMark === 8 && (isCurrentTaskAdd === 'False' || !!answer.SplitOrMergeLesionName) && lesionType !== 2) || (qs.QuestionMark === 10 && (isCurrentTaskAdd === 'False' || !!answer.SplitOrMergeLesionName))"
@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>
</template>
<!-- 多行文本输入框 -->
<el-input
v-if="qs.Type==='textarea'"
v-model="qsForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<!-- 下拉框 -->
<el-select
v-if="qs.Type==='select'"
v-model="qsForm[qs.Id]"
filterable
:placeholder="qs.QuestionMark === 8 ? $t('common:placeholder:selectorsearch') : qs.QuestionMark === 2 ? '' : $t('common:placeholder:select')"
:disabled="!isCurrentTask || readingTaskState>=2 || qs.QuestionMark === 0 || qs.QuestionMark === 1 || qs.QuestionMark === 2 || qs.QuestionMark === 5 || (qs.QuestionMark === 6 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))|| (qs.QuestionMark === 8 && (isCurrentTaskAdd === 'False'|| !!answer.SplitOrMergeLesionName)) || (qs.QuestionMark === 10 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))"
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.QuestionMark === 8" #prefix>
<span style="padding-left: 5px;">
<i class="el-icon-search" />
</span>
</template>
<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 && qs.QuestionMark === 7 && isBaseLineTask">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="(lesionType === 0 && item.value ===0) || (lesionType === 1 && (item.value ===0))"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark === 7 && !isBaseLineTask">
<el-option-group
:label="!isNaN(parseFloat(answer.LastTaskState)) ? `${$t('trials:dicomReading:tip:lastVisitStatus')} ${$fd(qs.DictionaryCode,parseFloat(answer.LastTaskState))}` : ''"
>
<!-- 首次分裂的病灶只能选择存在 -->
<template v-if="answer.IsFristAdd=== 'True' && answer.SplitOrMergeType === '0'">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="item.value === 0"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<!-- 首次添加的新病灶不能为无法评估和消失 -->
<template v-else-if="isCurrentTaskAdd=== 'True' && lesionType === 2">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="item.value === 0 || item.value === 1"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="item of filterState($d[qs.DictionaryCode])"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
</el-option-group>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark !== 7">
<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-if="qs.Type==='radio'"
v-model="qsForm[qs.id]"
:disabled="!isCurrentTask || readingTaskState>=2"
>
<el-radio
v-for="val in qs.options.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</el-radio-group>
</el-form-item>
</div>
</template>
<script>
export default {
name: 'TableQuestionFormItem',
props: {
tableInfo: {
type: Object,
default() {
return {}
}
},
answer: {
type: Object,
default() {
return {}
}
},
questionForm: {
type: Object,
default() {
return {}
}
},
organs: {
type: Array,
default() {
return []
}
},
readingTaskState: {
type: Number,
required: true
},
isBaseLineTask: {
type: Boolean,
required: true
},
isCurrentTask: {
type: Boolean,
required: true
}
},
data() {
return {
isCurrentTaskAdd: null,
lesionType: null,
questions: [],
organList: [],
qsForm: {}
}
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v) {
if (v.MeasureData) {
const { markTool } = v.MeasureData
if (markTool === 'Bidirectional') {
this.getOrganList(1)
} else if (markTool === 'Length') {
this.getOrganList(0)
} else {
this.getOrganList()
}
} else {
this.getOrganList()
}
for (const key in v) {
this.$set(this.qsForm, key, v[key])
}
this.isCurrentTaskAdd = v.IsCurrentTaskAdd
}
},
tableInfo: {
deep: true,
immediate: true,
handler(v) {
if (v) {
this.lesionType = v.LesionType
this.questions = v.TableQuestions.Questions
}
}
}
},
methods: {
lesionTypeChange(v) {
this.$emit('lesionTypeChange', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex, newLesionType: v })
},
formItemChange(v, qs) {
const updateArr = []
if (qs.QuestionMark === 8 && qs.RelationQuestions.length > 0) {
//
const index = this.organList.findIndex(item => item[qs.DataTableColumn] === v)
if (index > -1) {
const selected = this.organList[index]
qs.RelationQuestions.map(q => {
const val = selected[q.DataTableColumn]
updateArr.push({ questionId: q.Id, val: val, questionMark: q.QuestionMark })
})
updateArr.push({ questionId: 'OrganInfoId', val: selected.OrganInfoId })
updateArr.push({ questionId: 'IsCanEditPosition', val: selected.IsCanEditPosition })
} else {
qs.RelationQuestions.map(q => {
updateArr.push({ questionId: q.Id, val: '', questionMark: q.QuestionMark })
})
}
}
this.$emit('update', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex, questionMark: qs.QuestionMark, questionId: qs.Id, val: v, updateArr })
},
getOrganList(isLymphNodes = null) {
const idx = this.organs.findIndex(i => i.LesionType === this.questionForm.LesionType)
if (idx > -1) {
const arr = this.organs[idx].OrganList
if (!isNaN(parseInt(isLymphNodes))) {
this.organList = arr.filter((item) => item.IsLymphNodes === parseInt(isLymphNodes))
} else {
this.organList = arr
}
}
},
filterState(arr) {
if (!this.isBaseLineTask) {
const isLymphLesion = this.questionForm.IsLymphNodes
const lesionLength = this.questionForm.LesionLength
const lesionShort = this.questionForm.LesionShort
const bLesionL = !isNaN(parseFloat(this.questionForm.BaseLineMajorAxis)) ? parseFloat(this.questionForm.BaseLineMajorAxis) : 0
const bLesionS = !isNaN(parseFloat(this.questionForm.BaseLineShortAxis)) ? parseFloat(this.questionForm.BaseLineShortAxis) : 0
if (this.lesionType === 1 && isLymphLesion === 1 && this.questionForm.MeasureData && this.questionForm.MeasureData.markTool === 'Bidirectional' && lesionShort < bLesionS) {
arr = arr.filter(i => i.value !== 1)
} else if (this.lesionType === 1 && isLymphLesion === 1 && this.questionForm.MeasureData && this.questionForm.MeasureData.markTool === 'Bidirectional' && lesionShort >= 10 && lesionShort > bLesionS) {
arr = arr.filter(i => i.value === 0 || i.value === 1)
} else if (this.lesionType === 1 && isLymphLesion === 0 && this.questionForm.MeasureData && (this.questionForm.MeasureData.markTool === 'Length' || this.questionForm.MeasureData.markTool === 'Bidirectional') && lesionLength < bLesionL) {
arr = arr.filter(i => i.value !== 1)
}
return arr
} else {
return arr
}
},
close() {
this.$emit('close', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex })
}
}
}
</script>
<style lang="scss" scoped>
.table-question-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;
}
.el-form-item__content
.el-select{
width: 100%;
}
.input-width1{
width: calc(100% - 60px)!important;
}
.input-width2{
width: 100% !important;
}
}
</style>
@@ -1,914 +0,0 @@
<template>
<div class="report-wrapper">
<el-card v-loading="loading" shadow="never">
<div slot="header" class="clearfix report-header">
<!-- 电子影像病例报告表eICRF -->
<h3 style="margin:0;padding:0;">{{ $t('trials:readingReport:title:eicrf') }}</h3>
<div style="margin-left:auto">
<el-switch
v-model="isShowDetail"
:active-text="$t('trials:readingReport:title:expandDetails')"
:inactive-text="$t('trials:readingReport:title:collapseDetails')"
style="margin-right:5px;"
@change="handleShowDetail"
/>
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="skipTask"
>
<!-- 跳过 -->
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="getReportInfo(false)"
>
<!-- 刷新 -->
{{ $t('trials:readingReport:button:refresh') }}
</el-button>
<el-button
v-if="readingTaskState<2 && criterionType !== 10"
type="primary"
size="small"
@click="handleSave(true)"
>
<!-- 保存 -->
{{ $t('common:button:save') }}
</el-button>
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="beforeLeave"
>
<!-- 提交 -->
{{ $t('common:button:submit') }}
</el-button>
</div>
</div>
<div ref="tableWrapper" style="height:100%;overflow-y: auto;">
<el-table
v-if="height"
ref="reportList"
:data="taskQuestions"
row-key="Id"
border
:expand-row-keys="expandedRows"
:height="height"
:tree-props="{children: 'Childrens', hasChildren: 'hasChildren'}"
size="mini"
>
<el-table-column
prop=""
label=""
show-overflow-tooltip
width="350px"
>
<template slot-scope="scope">
<span v-if="scope.row.QuestionName" :style="{color: ((scope.row.isLymphNodes === 1 && scope.row.QuestionMark === 1) || (scope.row.isLymphNodes === 0 && scope.row.QuestionMark === 0)) && (scope.row.LesionType === 0 || scope.row.LesionType === 5) ? '#f66' : '#fff'}">{{ scope.row.QuestionName }}</span>
<span
v-else
style="font-weight: bold;font-size: 16px;color: #f44336;"
>
{{ language==='en'?scope.row.GroupEnName:scope.row.GroupName }}
</span>
</template>
</el-table-column>
<el-table-column
v-for="task in visitTaskList"
:key="task.VisitTaskId"
prop="date"
show-overflow-tooltip
width="150px"
>
<template slot="header">
<div v-if="task.IsCurrentTask">
<div>
{{ task.BlindName }}
</div>
</div>
<div v-else>
<div>
{{ task.BlindName }}
<el-button type="text" size="small" @click="previewDicoms(task)">
<span class="el-icon-view" />
</el-button>
</div>
</div>
</template>
<template slot-scope="scope">
<span :style="{color: ((scope.row.isLymphNodes === 1 && scope.row.QuestionMark === 1) || (scope.row.isLymphNodes === 0 && scope.row.QuestionMark === 0)) && (scope.row.LesionType === 0 || scope.row.LesionType === 5) || (scope.row.QuestionMark === 12) || scope.row.HighlightAnswerList.includes(`${scope.row.Answers[task.VisitTaskId]}`) ? '#f66' : '#fff'}">
<template v-if="task.VisitTaskId === visitTaskId && readingTaskState < 2 && [13,14,15,42].includes(scope.row.QuestionType)">
<!-- 是否存在疾病基线时可修改 -->
<template v-if="task.IsBaseLine && scope.row.QuestionType=== 15">
<el-select
v-if="scope.row.Type==='select' && scope.row.DictionaryCode"
v-model="currentExistDisease"
size="mini"
@change="handleExistDiseaseChange"
>
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</el-select>
</template>
<!-- 整体肿瘤评估非基线可修改 -->
<template v-else-if="!task.IsBaseLine && (scope.row.QuestionType=== 13 || scope.row.QuestionType=== 42)">
<el-select
v-if="scope.row.Type==='select' && scope.row.DictionaryCode"
v-model="currentEvaluateResult"
size="mini"
@change="handleEvaluateResultChange"
>
<template v-if="criterionType === 1 && tLesionCount">
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
v-show="(!task.IsBaseLine && item.value > -1) && (task.CrterionDictionaryGroup.indexOf(item.raw.CrterionDictionaryGroup) > -1) && (item.value !== 1 && item.value !== 3)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else-if="criterionType === 1 && ntLesionCount">
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
v-show="(!task.IsBaseLine && item.value > -1) && (task.CrterionDictionaryGroup.indexOf(item.raw.CrterionDictionaryGroup) > -1) && (item.value !== 1)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
v-show="(!task.IsBaseLine && item.value > -1) && (task.CrterionDictionaryGroup.indexOf(item.raw.CrterionDictionaryGroup) > -1)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
</el-select>
</template>
<!-- <template v-else-if="task.IsBaseLine && scope.row.QuestionType=== 13">
{{ $fd(scope.row.DictionaryCode, currentEvaluateResult) }}
</template> -->
<!-- 访视点备注是否存在疾病与系统不一致或者整体肿瘤评估与系统不一致时必填 -->
<!-- tumorEvaluate && task.VisitTaskId === visitTaskId && scope.row.QuestionType=== 14 && (currentEvaluateResult !== tumorEvaluate || currentExistDisease !== isExistDisease) -->
<template v-else-if="task.VisitTaskId === visitTaskId && scope.row.QuestionType=== 14 ">
<!-- v-if="tumorEvaluate && (currentEvaluateResult !== tumorEvaluate || currentExistDisease !== isExistDisease)" -->
<template>
<!-- 输入框 -->
<el-input
v-if="scope.row.Type==='input'"
v-model="currentTaskReason"
size="mini"
@change="evaluateReasonChange"
/>
<el-input
v-else-if="scope.row.Type==='textarea'"
v-model="currentTaskReason"
:autosize="{ minRows: 2, maxRows: 4}"
size="mini"
maxlength="500"
@change="evaluateReasonChange"
/>
<!-- 系统评估结果为xxx,与当前调整的结果不一致请填写调整原因 -->
<p v-if="currentEvaluateResult !== tumorEvaluate" style="width: 140px;padding:0 2px;white-space: normal;word-break: break-all;word-wrap: break-word;" v-html="getWarningText()" />
<p v-else-if="currentExistDisease !== isExistDisease" style="width: 140px;padding:0 2px;white-space: normal;word-break: break-all;word-wrap: break-word;">{{ $t('trials:readingReport:title:sysEvaluationRes') }}<span style="color:red">{{ $fd('ExistDisease',isExistDisease) }}</span>{{ $t('trials:readingReport:message:msg1') }}
</p>
</template>
<!-- <template v-else>
<span>{{ currentTaskReason }}</span>
</template> -->
</template>
<template v-else-if="scope.row.DictionaryCode">
{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}
</template>
<template v-else>
{{ scope.row.Answers[task.VisitTaskId] }}
</template>
</template>
<template v-else-if="scope.row.QuestionType=== 15">
<el-tooltip v-if="getAnswerInfo(scope.row.Answer,task.VisitTaskId,'IsGlobalChange')" :content="`${$t('trials:reading:warnning:msg55')}${$fd(scope.row.DictionaryCode, getAnswerInfo(scope.row.Answer,task.VisitTaskId,'GlobalChangeAnswer'))}`" placement="top" effect="light">
<span style="color:red;"> {{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</el-tooltip>
<span v-else>{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</template>
<template v-else-if="scope.row.QuestionType=== 13 || scope.row.QuestionType=== 42">
<el-tooltip v-if="getAnswerInfo(scope.row.Answer,task.VisitTaskId,'IsGlobalChange')" :content="`${$t('trials:reading:warnning:msg55')}${$fd(scope.row.DictionaryCode, getAnswerInfo(scope.row.Answer,task.VisitTaskId,'GlobalChangeAnswer'))}`" placement="top" effect="light">
<span style="color:red;"> {{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</el-tooltip>
<span v-else>{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</template>
<template v-else-if="scope.row.QuestionType=== 22">
{{ scope.row.Answers[task.VisitTaskId] === '-1' ? $t('trials:readingReport:title:unknow') : scope.row.Answers[task.VisitTaskId] }}
</template>
<template v-else-if="scope.row.DictionaryCode">
{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}
</template>
<template v-else-if="criterionType === 10">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]}` }}
</template>
<template v-else-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ `${scope.row.Answers[task.VisitTaskId]}` }}
<span v-if="scope.row.Answers[task.VisitTaskId] !== 'NA' && !isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))">{{ `${$fd('ValueUnit',scope.row.Unit)}` }}</span>
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]}%` }}
</template>
<template v-else-if="scope.row.Answers && scope.row.Answers.hasOwnProperty(task.VisitTaskId)">
{{ scope.row.Answers[task.VisitTaskId] }}
</template>
</span>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 附加评估 -->
<el-dialog
v-if="additionalAssessmentsDig.visible"
:visible.sync="additionalAssessmentsDig.visible"
:close-on-click-modal="false"
:title="additionalAssessmentsDig.title"
width="600px"
>
<additional-assessment
:questions="assessmentQuestions"
:visit-task-id="visitTaskId"
@close="additionalAssessmentsDig.visible = false"
@sign="sign"
/>
</el-dialog>
<!-- 签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
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" @closeDialog="closeSignDialog" />
</el-dialog>
</div>
</template>
<script>
import { getReadingReportEvaluation, changeDicomReadingQuestionAnswer, submitDicomVisitTask, verifyVisitTaskQuestions, getTaskAdditionalQuestion } from '@/api/trials'
import { setSkipReadingCache } from '@/api/reading'
import { getAutoCutNextTask } from '@/api/user'
import const_ from '@/const/sign-code'
import SignForm from '@/views/trials/components/newSignForm'
import { getToken } from '@/utils/auth'
// import store from '@/store'
import { mapGetters } from 'vuex'
import { changeURLStatic } from '@/utils/history.js'
import AdditionalAssessment from '@/views/trials/trials-panel/reading/dicoms/components/AdditionalAssessment'
export default {
name: 'ReportPage',
components: { SignForm, AdditionalAssessment },
data() {
return {
currentUser: zzSessionStorage.getItem('userName'),
signVisible: false,
signCode: null,
visitTaskList: [],
taskQuestions: [],
loading: false,
answers: [],
readingTaskState: 2,
tumorEvaluate: null,
currentEvaluateResult: null,
isExistDisease: null,
currentExistDisease: null,
currentTaskReason: '',
answerArr: [],
questions: [],
isShowDetail: false,
criterionType: 0,
height: 0,
additionalAssessmentsDig: { visible: false, title: this.$t('trials:trials-panel:setting:reading-unit:TrialCriterionAdditionalAssessmentTypeList') },
assessmentQuestions: [],
tLesionCount: null,
ntLesionCount: null,
openWindow: null,
expandedRows: [],
taskInfo: {},
visitTaskId: '',
isBaselineTask: false
}
},
computed: {
...mapGetters(['language'])
},
watch: {
taskQuestions() {
this.$nextTick(() => {
this.getTableHeight()
this.$refs.reportList && this.$refs.reportList.doLayout()
this.setScrollTop()
})
}
},
created() { this.getTableHeight() },
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.criterionType = this.taskInfo.CriterionType
this.visitTaskId = this.taskInfo.VisitTaskId
this.isBaselineTask = this.taskInfo.IsBaseLine
window.addEventListener('resize', () => {
this.handleResize()
this.setScrollTop()
})
this.getReportInfo()
},
beforeDestroy() {
if (this.openWindow) {
this.openWindow.close()
}
},
methods: {
myConfirm(msg) {
return new Promise(resolve => {
this.$confirm(msg, {
type: 'warning',
showCancelButton: true
}).then(() => {
resolve(true)
}).catch(() => {
resolve(false)
})
})
},
async beforeLeave() {
this.handleConfirm()
},
getAnswerInfo(answerArr, visitTaskId, prop) {
var i = answerArr.findIndex(i => i.VisitTaskId === visitTaskId)
if (i === -1) return ''
var val = answerArr[i][prop]
return isNaN(parseInt(val)) ? val : parseInt(val)
},
getTableHeight() {
this.height = window.innerHeight - 170
},
async getReportInfo(IsCalculate) {
this.loading = true
try {
var params = {
visitTaskId: this.visitTaskId,
trialId: this.$router.currentRoute.query.trialId,
IsCalculate: IsCalculate !== false
}
const res = await getReadingReportEvaluation(params)
if (res.IsSuccess) {
this.readingTaskState = res.Result.ReadingTaskState
this.tumorEvaluate = res.Result.CalculateResult && res.Result.CalculateResult.TumorEvaluate ? parseInt(res.Result.CalculateResult.TumorEvaluate) : null
this.isExistDisease = res.Result.CalculateResult && res.Result.CalculateResult.IsExistDisease ? parseInt(res.Result.CalculateResult.IsExistDisease) : null
this.answerArr = []
this.questions = res.Result.TaskQuestions.concat()
this.visitTaskList = res.Result.VisitTaskList
var taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null, null)
this.taskQuestions = []
taskQuestions.forEach(item => {
this.$set(this.taskQuestions, this.taskQuestions.length, item)
})
const tLesion = res.Result.LesionCountList.find(i => i.LesionType === 0)
this.tLesionCount = tLesion ? tLesion.Count : 0
const ntLesion = res.Result.LesionCountList.find(i => i.LesionType === 1)
this.ntLesionCount = ntLesion ? ntLesion.Count : 0
this.setScrollTop()
}
this.loading = false
} catch (e) {
this.loading = false
console.log(e)
}
},
setScrollTop(a) {
setTimeout(() => {
this.$nextTick(() => {
if (this.$refs.reportList) {
this.getTableHeight()
this.$refs.reportList.bodyWrapper.scrollTop = this.$refs.reportList.bodyWrapper.scrollHeight
}
})
}, 50)
},
getQuestions(questions, isNTFilterLength, lesionType, isLymphNodes) {
const arr = []
if (questions.length !== 0) {
questions.forEach((item) => {
if (this.criterionType === 21) {
if (!this.isShowDetail) {
if (!item.RowId) {
this.expandedRows.push(item.Id)
}
} else {
this.expandedRows.push(item.Id)
}
} else {
this.expandedRows.push(item.Id)
}
//
//
//
lesionType = item.LesionType
var filterArr = [7]
// 0 5
// 12678irecisit
// 0123ID4567810
// 11051106
if ((item.LesionType === 1 || item.LesionType === 2 || item.LesionType === 6 || item.LesionType === 7 || item.LesionType === 8) && isNTFilterLength) {
filterArr = [0, 1, 3, 4, 5, 6, 2, 8, 10, 7, 1105]
} else {
filterArr = [3, 4, 5, 6, 2, 8, 10, 7, 1106, 1105]
}
if ((lesionType === 0 || lesionType === 5) && isLymphNodes === 0 && !this.isShowDetail && (this.criterionType === 1 || this.criterionType === 3 || this.criterionType === 7 || this.criterionType === 17)) {
filterArr.push(1)
}
if (isLymphNodes === 0) {
filterArr.push(1)
}
if (!(filterArr.includes(item.QuestionMark))) {
const obj = item
obj.Answers = {}
if (item.RowIndex > 0) {
try {
var idx = item.Childrens.findIndex(i => i.QuestionMark === 8)
var idxLoc = item.Childrens.findIndex(i => i.QuestionMark === 10)
var state = item.Childrens.findIndex(i => i.QuestionMark === 7)
if (idx > -1) {
if (item.Childrens[idx].Answer.length > 0) {
var k = item.Childrens[idx].Answer.findIndex(v => v.Answer !== '')
var part = ''
if (obj.IsCanEditPosition) {
part = `${item.Childrens[idx].Answer[k].Answer}--${item.Childrens[idxLoc].Answer[k].Answer}`
} else {
part = `${item.Childrens[idx].Answer[k].Answer}`
}
if (item.SplitOrMergeLesionName && k > -1) {
// obj.QuestionName = `${obj.QuestionName} --${part} (Split from ${item.SplitOrMergeLesionName})`
obj.QuestionName = `${obj.QuestionName} --${part}`
var Answers = {}
if (state >= 0) {
this.visitTaskList.forEach(v => {
const o = item.Childrens[state].Answer.find(v1 => {
return v1.VisitTaskId === v.VisitTaskId
})
if (o) {
Answers[o.VisitTaskId] = this.$fd(item.Childrens[state].DictionaryCode, parseInt(o.Answer))
}
})
}
this.$set(obj, 'Answers', Answers)
// obj.QuestionName = `${obj.QuestionName} `
} else if (!item.SplitOrMergeLesionName && k > -1) {
obj.QuestionName = `${obj.QuestionName}--${part}`
const Answers = {}
if (state >= 0) {
this.visitTaskList.forEach(v => {
const o = item.Childrens[state].Answer.find(v1 => {
return v1.VisitTaskId === v.VisitTaskId
})
if (o) {
Answers[o.VisitTaskId] = this.$fd(item.Childrens[state].DictionaryCode, parseInt(o.Answer))
}
})
}
this.$set(obj, 'Answers', Answers)
// obj.QuestionName = `${obj.QuestionName} `
} else {
obj.QuestionName = `${obj.QuestionName} `
}
if (item.ReportMark) {
obj.QuestionName = `${obj.QuestionName} (${item.ReportMark})`
}
if (this.criterionType === 1 || this.criterionType === 3 || this.criterionType === 7 || this.criterionType === 17) {
var idxLymphNode = item.Childrens.findIndex(i => i.QuestionMark === 2)
if (idxLymphNode > -1) {
isLymphNodes = item.Childrens[idxLymphNode].Answer[k].Answer ? parseInt(item.Childrens[idxLymphNode].Answer[k].Answer) : null
item.Childrens.forEach(v => {
this.$set(v, 'isLymphNodes', isLymphNodes)
})
}
}
}
}
if (this.criterionType === 21) {
var liverSegmentIdx = item.Childrens.findIndex(i => i.QuestionMark === 1106)
if (liverSegmentIdx > -1) {
if (item.Childrens[liverSegmentIdx].Answer.length > 0) {
const v = item.Childrens[liverSegmentIdx].Answer[0].Answer
obj.QuestionName = this.$fd(item.Childrens[liverSegmentIdx].DictionaryCode, parseInt(v))
const Answers = {}
const mean = item.Childrens.findIndex(i => i.QuestionMark === 1104)
if (mean > -1) {
this.visitTaskList.forEach(v => {
const o = item.Childrens[mean].Answer.find(v1 => {
return v1.VisitTaskId === v.VisitTaskId
})
if (o) {
Answers[o.VisitTaskId] = isNaN(parseFloat(o.Answer)) ? o.Answer : `${o.Answer}%`
}
})
}
this.$set(obj, 'Answers', Answers)
}
}
}
} catch (e) {
console.log(e)
}
}
item.Answer.forEach(i => {
if (item.DictionaryCode) {
obj.Answers[i.VisitTaskId] = i.Answer ? parseInt(i.Answer) : null
} else {
obj.Answers[i.VisitTaskId] = i.Answer
}
})
if (item.QuestionType === 15) {
this.currentExistDisease = obj.Answers[this.visitTaskId]
this.answerArr.push({ id: item.QuestionId, answer: obj.Answers[this.visitTaskId], questionType: 15 })
}
if (item.QuestionType === 13 || item.QuestionType === 42) {
this.currentEvaluateResult = obj.Answers[this.visitTaskId]
this.answerArr.push({ id: item.QuestionId, answer: obj.Answers[this.visitTaskId], questionType: item.QuestionType })
}
if (item.QuestionType === 14) {
this.currentTaskReason = obj.Answers[this.visitTaskId]
this.answerArr.push({ id: item.QuestionId, answer: obj.Answers[this.visitTaskId], questionType: 14 })
}
if (item.Childrens.length >= 1) {
obj.Childrens = this.getQuestions(item.Childrens, isNTFilterLength, lesionType, isLymphNodes)
}
arr.push(obj)
}
})
}
return arr
},
handleShowDetail(val) {
this.getReportInfo()
// this.taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null)
},
handleExistDiseaseChange(val) {
// this.currentExistDisease = parseInt(val)
if (val === this.isExistDisease && this.tumorEvaluate === this.currentEvaluateResult) {
this.currentTaskReason = ''
this.evaluateReasonChange('')
}
this.currentTaskReason = ''
this.evaluateReasonChange('')
var idx = this.answerArr.findIndex(i => i.questionType === 15)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
handleEvaluateResultChange(val) {
// this.currentEvaluateResult = parseInt(val)
if (val === this.tumorEvaluate && this.isExistDisease === this.currentExistDisease) {
this.currentTaskReason = ''
this.evaluateReasonChange('')
}
this.currentTaskReason = ''
this.evaluateReasonChange('')
var idx = this.answerArr.findIndex(i => i.questionType === 13 || i.questionType === 42)
if (idx > -1) {
this.answerArr[idx].answer = val
}
this.setScrollTop()
},
evaluateReasonChange(val) {
var idx = this.answerArr.findIndex(i => i.questionType === 14)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
async handleConfirm() {
this.loading = true
try {
await this.handleSave(false)
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
var i = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
var isBaseline = this.visitTaskList[i].IsBaseLine
if (isBaseline) {
const res = await getTaskAdditionalQuestion({ visitTaskId: this.visitTaskId })
this.assessmentQuestions = res.Result
if (this.assessmentQuestions.length > 0) {
//
this.additionalAssessmentsDig.visible = true
} else {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
}
} else {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
}
this.loading = false
} catch (e) {
this.loading = false
}
},
sign() {
this.additionalAssessmentsDig.visible = false
this.$nextTick(() => {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
})
},
handleResize() {
this.$nextTick(() => {
this.$refs.reportList && this.$refs.reportList.doLayout()
})
},
//
closeSignDialog(isSign, signInfo) {
if (isSign) {
this.signConfirm(signInfo)
} else {
this.signVisible = false
}
},
//
async signConfirm(signInfo) {
this.loading = true
try {
var params = {
data: {
visitTaskId: this.visitTaskId
},
signInfo: signInfo
}
const res = await submitDicomVisitTask(params)
if (res.IsSuccess) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
if (this.$refs['signForm']) {
this.$refs['signForm'].btnLoading = false
}
this.signVisible = false
// window.location.reload()
window.opener.postMessage('refreshTaskList', window.location)
//
this.readingTaskState = 2
this.$emit('setReadingTaskState', 2)
const res = await getAutoCutNextTask()
var isAutoTask = res.Result.AutoCutNextTask
if (isAutoTask) {
window.location.reload()
} else {
// ''
this.$confirm(this.$t('trials:readingReport:message:msg4'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
window.location.reload()
})
.catch(action => {
changeURLStatic('visitTaskId', this.visitTaskId)
})
}
window.opener.postMessage('refreshTaskList', window.location)
}
this.loading = false
} catch (e) {
this.loading = false
if (this.$refs['signForm'] && this.$refs['signForm'].btnLoading) {
this.$refs['signForm'].btnLoading = false
}
}
},
previewDicoms(task) {
if (this.openWindow) {
this.openWindow.close()
}
var token = getToken()
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
// var subjectCode = this.$router.currentRoute.query.subjectCode
var subjectCode = localStorage.getItem('subjectCode')
var subjectId = this.$router.currentRoute.query.subjectId
var trialId = this.$router.currentRoute.query.trialId
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var criterionType = this.$router.currentRoute.query.criterionType
var readingTool = this.$router.currentRoute.query.readingTool
var path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${task.VisitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
const routeData = this.$router.resolve({ path })
this.openWindow = window.open(routeData.href, '_blank')
},
handleSave(isPrompt) {
return new Promise(async(resolve, reject) => {
var isBeill
var evaluateResult = ''
var evaluateAjustReason = ''
this.answers = []
var isExistEvaluateResult = false
this.answerArr.map(item => {
if (item.questionType === 13 || item.questionType === 42) {
evaluateResult = item.answer
isExistEvaluateResult = true
}
if (item.questionType === 14) {
evaluateAjustReason = item.answer
}
if (item.questionType === 15) {
isBeill = item.answer
}
this.answers.push({ id: item.id, answer: item.answer })
})
console.log(this.currentExistDisease, this.isExistDisease, evaluateAjustReason, isBeill)
if (this.currentExistDisease !== this.isExistDisease && !evaluateAjustReason) {
this.$confirm(this.$t('trials:readingReport:message:msg2'), {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
resolve()
return
}
if (isExistEvaluateResult && (evaluateResult === null && !this.isBaselineTask)) {
//
this.$confirm(this.$t('trials:readingReport:message:msg2'), {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
resolve()
return
}
if (isExistEvaluateResult && (evaluateResult !== this.tumorEvaluate) && !evaluateAjustReason) {
//
this.$confirm(this.$t('trials:readingReport:message:msg3'), {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
resolve()
return
}
this.loading = true
try {
var params = {
visitTaskId: this.visitTaskId,
answers: this.answers
}
const res = await changeDicomReadingQuestionAnswer(params)
if (res.IsSuccess && isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.loading = false
resolve()
} catch (e) {
this.loading = false
reject()
}
})
},
getWarningText() {
var sysRes = ''
var curRes = ''
if (this.CriterionType === 2) {
sysRes = this.$fd('ImagingOverallAssessment_Lugano', this.tumorEvaluate)
curRes = this.$fd('ImagingOverallAssessment_Lugano', this.currentEvaluateResult)
} else {
sysRes = this.$fd('OverallAssessment', this.tumorEvaluate)
curRes = this.$fd('OverallAssessment', this.currentEvaluateResult)
}
if (!curRes) {
return ''
}
const msg = this.$t('trials:readingReport:message:msg9').replace('xxx', '<font color="red">' + sysRes + '</font>').replace('yyy', '<font color="red">' + curRes + '</font>')
return msg
},
async skipTask() {
try {
//
const confirm = await this.$confirm(
this.$t('trials:readingReport:message:skipConfirm'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.loading = true
const res = await setSkipReadingCache({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
window.location.reload()
}
} catch (e) {
this.loading = false
console.log(e)
}
}
}
}
</script>
<style lang="scss" scoped>
.report-wrapper{
height: 100%;
padding: 10px 0px;
// background-color: #fff;
background-color: #000;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
.report-header{
display: flex;
}
.el-card{
display:flex;flex-direction: column;height: 100%;
background-color: #000;
color: #ffffff;
border:none;
::v-deep .el-card__body{
flex: 1;
}
}
// ::v-deep .el-table__cell{
// background-color: #000;
// color: #ffffff;
// }
// ::v-deep .el-table{
// background-color: #000;
// color: #ffffff;
// }
// ::v-deep .el-table__cell{
// background-color: #000;
// color: #ffffff;
// }
::v-deep .el-table, .el-table__expanded-cell {
background-color: #000;
color: #fff;
border-color:#444444;
}
::v-deep .el-table th, .el-table tr {
background-color: #000;
color: #fff;
border-color:#444444;
}
::v-deep .el-table__body tr > td{
background-color:#000 !important;
color: #fff;
border-color:#444444;
}
::v-deep .el-table__body tr:hover > td{
background-color:#858282 !important;
color: #fff;
border-color:#444444;
}
::v-deep .el-table--border th.gutter:last-of-type{
border: none;
}
::v-deep .el-card__header{
border: none;
padding: 10px;
}
}
::v-deep .el-switch__label{
color:#fff;
}
::v-deep .el-switch__label.is-active{
color: #428bca;
}
.colorOfRed{
color: #f66;
}
</style>
@@ -1,333 +0,0 @@
<template>
<div v-loading="loading" class="study-wrapper">
<div class="study-info">
<div
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
:title="taskInfo.SubjectCode"
>
{{ taskInfo.SubjectCode }}
</div>
<div
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
:title="visitTaskInfo.TaskBlindName"
>
{{ visitTaskInfo.TaskBlindName }}
</div>
</div>
<div class="ps">
<el-collapse v-model="activeNames">
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`">
<template slot="title">
<div
v-if="!study.IsCriticalSequence"
class="dicom-desc"
>
<template v-if="taskInfo && taskInfo.IsShowStudyName">
<div style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
<span v-if="study.StudyName" :title="study.StudyName" style="margin-left: 5px;">{{ study.StudyName }}</span>
<span v-else :title="study.Modalities" style="margin-left: 5px;">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
</div>
<div v-if="study.StudyName" style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
</div>
</template>
<template v-else-if="taskInfo && !taskInfo.IsShowStudyName">
<div style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
</div>
</template>
</div>
<div v-else>
<!-- 关键序列 -->
{{ $t('trials:reading:title:keySeries') }}
</div>
</template>
<div class="dicom-list-container">
<div
v-for="(series, i) in study.SeriesList"
:key="series.Id"
style="position:relative;margin-top:1px;"
@click="activeSeries(series, i, index)"
>
<div
:class="{'series-active': index === activeStudyIndex && i === activeSeriesIndex}"
class="series-wrapper"
>
<div class="series-image">
<el-image
style="width: 100%;height: 100%;"
:src="`${OSSclientConfig.basePath}${series.ImageResizePath}`"
fit="fill"
crossorigin="anonymous"
/>
</div>
<div class="series-text">
<div v-if="series.IsExistMutiFrames && series.InstanceCount > 1"
style="position: absolute;right: 0;top: 0;">
<el-popover
placement="right"
trigger="hover"
popper-class="instance_frame_wrapper"
>
<div class="frame_list">
<div
v-for="(instance, idx) in series.InstanceInfoList"
:key="instance.Id"
class="frame_content"
:style="{'margin-bottom':idx<series.InstanceInfoList.length-1? '5px':'0px'}"
@click.stop="showMultiFrames(index,series, i, instance)"
>
<div>
<div>{{ instance.InstanceNumber }}</div>
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
</el-popover>
</div>
<div v-if="!study.IsCriticalSequence" class="text-desc" :title="series.SeriesNumber">
#{{ series.SeriesNumber }}
</div>
<div v-if="series.Description" class="text-desc" :title="series.Description">
{{ series.Description }}
</div>
<div v-if="series.SliceThickness && !study.IsCriticalSequence" class="text-desc">
T: {{ parseFloat(series.SliceThickness).toFixed(digitPlaces) }}
</div>
<div class="text-desc">
<span v-show="series.LoadedImageCount < series.InstanceCount">
{{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image
</span>
<span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{ series.InstanceCount }} image</span>
</div>
<div style="line-height: 12px;">
<i v-show="series.IsBeMark || markedSeriesIds.includes(series.Id)" class="el-icon-star-on" style="font-size: 12px;color: #ff5722;" />
</div>
</div>
</div>
<div v-if="series.LoadedImageCount > 0 && series.LoadedImageCount < series.InstanceCount" style="width: 100%;">
<el-progress
:percentage="parseInt((series.LoadedImageProgress / series.InstanceCount).toFixed(2))"
/>
</div>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
</template>
<script>
export default {
name: 'StudyList',
props: {
visitTaskInfo: {
type: Object,
default() {
return {}
}
},
markedSeriesIds: {
type: Array,
default() {
return []
}
}
},
data() {
return {
loading: false,
activeNames: [],
activeStudyIndex: -1,
activeSeriesIndex: -1,
taskInfo: null,
studyList: [],
annotations: [],
digitPlaces: 2
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.studyList = this.visitTaskInfo.StudyList
this.annotations = this.visitTaskInfo.Annotations
if (this.studyList.length === 0) return
this.$nextTick(() => {
this.activeStudy(this.studyList[0].StudyId)
})
},
methods: {
activeSeries(series, seriesIndex, studyIndex) {
this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex
this.$emit('activeSeries', series)
},
activeStudy(id) {
if (this.activeNames.indexOf(id) > -1) return
this.activeNames.push(id)
},
setSeriesActive(studyIndex, seriesIndex) {
this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex
const studyId = this.studyList[studyIndex].StudyId
if (!studyId) return
this.activeStudy(studyId)
},
showMultiFrames(studyIndex, series, seriesIndex, instance) {
let obj = Object.assign({}, series)
this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex
let taskId = this.visitTaskInfo.VisitTaskId
const nFrames = instance.NumberOfFrames || 0
let imageIds = []
const stack = []
if (nFrames === 0) {
//
stack.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
} else {
//
for (let i = 0; i < nFrames; i++) {
const newImageId = `wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}&frame=${i + 1}`
stack.push(newImageId)
}
}
imageIds.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
obj.Stack = stack
obj.ImageIds = imageIds
obj.SliceIndex = 0
this.$emit('showMultiFrame', obj)
},
getPreviousOrNextSeries(type, series) {
const seriseList = this.studyList.map(s => s.SeriesList).flat()
const i = seriseList.findIndex(i => i.Id === series.Id && i.StudyId === series.StudyId)
if (i === -1) return
let newIndex = null
if (type === -1) {
newIndex = i === 0 ? i : i - 1
} else {
newIndex = i >= seriseList.length - 1 ? i : i + 1
}
const studyIndex = seriseList[newIndex].StudyIndex
const seriesIndex = seriseList[newIndex].SeriesIndex
this.setSeriesActive(studyIndex, seriesIndex)
this.activeSeries(seriseList[newIndex], seriesIndex, studyIndex)
}
}
}
</script>
<style lang="scss" scoped>
.study-wrapper{
width:100%;
height: 100%;
overflow-y: hidden;
overflow-x: hidden;
display: flex;
flex-direction: column;
.study-info {
font-size: 16px;
font-weight: bold;
color: #ddd;
padding: 5px 0px;
margin: 0;
text-align: center;
background-color: #4c4c4c;
height: 50px;
}
.dicom-desc{
font-weight: bold;
font-size: 13px;
text-align: left;
color: #d0d0d0;
padding: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ps {
flex: 1;
overflow-anchor: none;
touch-action: auto;
overflow-y: auto;
}
.series-active {
background-color: #607d8b!important;
border: 1px solid #607d8b!important;
}
::v-deep.el-progress__text{
color: #ccc;
font-size: 12px;
}
.dicom-list-container{
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
.series-wrapper {
width: 100%;
padding: 5px;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
background-color: #3a3a3a;
.el-progress__text{
display: none;
}
.el-progress-bar{
padding-right:0px;
}
.series-image {
width: 50px;
height: 50px;
}
.series-text {
flex: 1;
padding-left: 5px;
color: #ddd;
position: relative;
.text-desc {
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
line-height: 16px;
}
}
}
}
::v-deep.el-collapse{
border: none;
.el-collapse-item{
background-color: #000!important;
color: #ddd;
}
.el-collapse-item__content{
padding-bottom:0px;
background-color: #000!important;
}
.el-collapse-item__header{
background-color: #000!important;
color: #ddd;
border-bottom-color:#5a5a5a;
padding-left: 5px;
// height: 50px;
line-height: 20px;
}
}
::v-deep .el-progress-bar__inner{
transition: width 0s ease;
}
}
</style>
@@ -1,670 +0,0 @@
<template>
<div
ref="viewport"
class="viewport-wrapper"
@mouseup="sliderMouseup"
@mousemove="sliderMousemove"
@mouseleave="sliderMouseleave"
>
<div v-if="series && taskInfo" class="left-top-text">
<div
v-if="taskInfo.IsExistsClinicalData"
class="cd-info"
:title="$t('trials:reading:button:clinicalData')"
>
<svg-icon
style="cursor: pointer;"
icon-class="documentation"
class="svg-icon"
@click.stop="viewCD(series.TaskInfo.VisitTaskId)"
/>
</div>
<h2
v-if="taskInfo.IsReadingShowSubjectInfo"
class="subject-info"
>
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
</h2>
<div>Series: #{{ series.SeriesNumber }}</div>
<div v-if="series.Stack">Image: #{{ `${series.SliceIndex + 1}/${series.Stack.length}` }}</div>
<div>{{ series.Modality }}</div>
</div>
<div
v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1"
class="top-center-tool"
>
<div class="toggle-visit-container">
<div
class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum !== 0 ? '#fff': '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
@dblclick.stop="preventDefault($event)"
>
<i class="el-icon-caret-left" />
</div>
<div class="arrow_text">
{{ series.TaskInfo.TaskBlindName }}
</div>
<div
class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff': '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
@dblclick.stop="preventDefault($event)"
>
<i class="el-icon-caret-right" />
</div>
</div>
</div>
<div v-if="series" class="right-top-text">
<div>{{ series.Description }}</div>
</div>
<div v-if="series" class="left-bottom-text">
<div v-show="mousePosition.index.length > 0">
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}
</div>
<div v-if="(series.Modality === 'CT' || series.Modality === 'DR' || series.Modality === 'CR') && mousePosition.value">
HU: {{ mousePosition.value }}
</div>
<div v-else-if="(series.Modality === 'PT' && mousePosition.value)">
{{mousePosition.modalityUnit}}: {{ digitPlaces === -1 ?mousePosition.value.toFixed(3) :mousePosition.value.toFixed(digitPlaces) }}
</div>
<div v-else-if="mousePosition.value">
Density: {{ mousePosition.value }}
</div>
<div v-show="imageInfo.size">
W*H: {{ imageInfo.size }}
</div>
<div v-show="imageInfo.zoom">
Zoom: {{ imageInfo.zoom }}
</div>
</div>
<div v-if="series" class="right-bottom-text">
<div v-show="imageInfo.location">Location: {{ `${Number(imageInfo.location).toFixed(digitPlaces)} mm` }}</div>
<div v-show="series.SliceThickness">Slice Thickness: {{ `${Number(series.SliceThickness).toFixed(digitPlaces)} mm` }}</div>
<div v-show="imageInfo.wwwc ">WW/WL: {{ imageInfo.wwwc }}</div>
</div>
<div class="orientation-top">
{{ markers.top }}
</div>
<div class="orientation-right">
{{ markers.right }}
</div>
<div class="orientation-bottom">
{{ markers.bottom }}
</div>
<div class="orientation-left">
{{ markers.left }}
</div>
<div ref="sliderBox" class="right-slider-box" @click.stop="clickSlider($event)">
<div :style="{top: sliderInfo.height + '%'}" class="slider" @click.stop.prevent="() => {return}" @mousedown.stop="sliderMousedown($event)" />
</div>
</div>
</template>
<script>
// import * as cornerstonejs from '@cornerstonejs/core'
import {
// RenderingEngine,
// Enums,
// imageLoader,
metaData,
getRenderingEngine,
// eventTarget,
utilities as csUtils
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import {
utilities as csToolsUtils
} from '@cornerstonejs/tools'
import { getPTImageIdInstanceMetadata } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/getPTImageIdInstanceMetadata'
import ptScalingMetaDataProvider from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/ptScalingMetaDataProvider'
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv'
import { vec3 } from 'gl-matrix'
export default {
name: 'ImageViewport',
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
viewportIndex: {
type: Number,
required: true
}
},
data() {
return {
element: '',
series: null,
taskInfo: null,
sliderInfo: {
oldB: null,
oldM: null,
isMove: false,
height: 0
},
mousePosition: {
index: [],
value: null,
modalityUnit: '',
world: []
},
imageInfo: {
zoom: null,
size: null,
location: null,
sliceThickness: null,
wwwc: null
},
digitPlaces: 2,
orientationMarkers: [],
originalMarkers: [],
markers: { top: '', right: '', bottom: '', left: '' },
playClipState: false,
wwwcIdx: 2
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
this.initViewport()
})
},
methods: {
initViewport() {
this.element = this.$refs['viewport']
const resizeObserver = new ResizeObserver(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
if (renderingEngine) {
renderingEngine.resize(true, false)
}
})
this.element.oncontextmenu = (e) => e.preventDefault()
resizeObserver.observe(this.element)
this.element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
// this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
// this.element.addEventListener('CORNERSTONE_CAMERA_MODIFIED', this.cameraModified)
this.element.addEventListener('CORNERSTONE_IMAGE_RENDERED', this.imageRendered)
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
this.element.addEventListener('mouseleave', () => {
this.mousePosition.index = []
this.mousePosition.value = null
})
// console.log(cornerstoneTools)
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
},
stackNewImage(e) {
const { detail } = e
this.series.SliceIndex = detail.imageIdIndex
this.sliderInfo.height = detail.imageIdIndex * 100 / (this.series.Stack.length - 1)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
this.imageInfo.size = `${detail.image.columns}*${detail.image.rows}`
const imagePlaneModule = metaData.get('imagePlaneModule', detail.imageId)
this.imageInfo.location = imagePlaneModule.sliceLocation
// this.imageInfo.wwwc = `${Math.round(detail.image.windowWidth)}/${Math.round(detail.image.windowCenter)}`
this.getOrientationMarker()
this.$emit('renderAnnotations', this.series)
// const toolGroupId = `viewport-${this.viewportIndex}`
// const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
// toolGroup.setToolEnabled('ScaleOverlay')
},
imageRendered(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
},
cameraModified(e) {
console.log(e)
},
voiModified(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
},
getOrientationMarker() {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const { viewUp, viewPlaneNormal } = viewport.getCamera()
const viewRight = vec3.create()
vec3.cross(viewRight, viewUp, viewPlaneNormal)
const columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]]
const rowCosines = viewRight
const rowString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(rowCosines)
const columnString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(columnCosines)
const oppositeRowString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(rowString)
const oppositeColumnString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(columnString)
this.markers.top = oppositeColumnString
this.markers.right = rowString
this.markers.bottom = columnString
this.markers.left = oppositeRowString
this.orientationMarkers = [oppositeColumnString, rowString, columnString, oppositeRowString]
if (this.originalMarkers.length === 0) {
this.originalMarkers = [...this.orientationMarkers]
}
},
setMarkers() {
const markers = [...this.orientationMarkers]
for (const key in this.markers) {
const v = markers.shift(0)
this.markers[key] = v
}
},
resetOrientationMarkers() {
if (this.originalMarkers.length > 0) {
this.orientationMarkers = [...this.originalMarkers]
this.setMarkers()
}
},
rotateOrientationMarkers(type) {
if (this.orientationMarkers.length > 0) {
if (type === 1) {
this.resetOrientationMarkers()
return
}
const markers = [...this.orientationMarkers]
if (type === 2) {
//
this.orientationMarkers[0] = markers[2]
this.orientationMarkers[2] = markers[0]
} else if (type === 3) {
//
this.orientationMarkers[1] = markers[3]
this.orientationMarkers[3] = markers[1]
} else if (type === 4) {
// 90
this.orientationMarkers = markers.slice(1, 4).concat(markers[0])
} else if (type === 5) {
// 90
this.orientationMarkers = [markers[3]].concat(markers.slice(0, 3))
}
this.setMarkers()
}
},
toggleClipPlay(isPlay, framesPerSecond) {
this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: false })
} else {
cornerstoneTools.utilities.cine.stopClip(viewport.element)
}
},
scrollPage(type) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const numImages = viewport.getImageIds().length
let newImageIdIndex = null
if (type === 0) {
newImageIdIndex = 0
} else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) {
newImageIdIndex = numImages - 1
}
// viewport.setImageIdIndex(newImageIdIndex)
csUtils.jumpToSlice(viewport.element, { imageIndex: newImageIdIndex })
cornerstoneTools.utilities.cine.stopClip(viewport.element)
},
setZoom(ratio) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
if (ratio > 0) {
viewport.setZoom(zoom * 1.05)
} else {
viewport.setZoom(zoom / 1.05)
}
viewport.render()
},
resize(forceFitToWindow) {
console.log('resize: ', forceFitToWindow)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (!forceFitToWindow) {
viewport.setZoom(0.5)
viewport.render()
} else {
viewport.setZoom(1)
viewport.render()
}
},
async prefetchMetadataInformation(imageIdsToPrefetch, modality) {
let taskPromises = []
for (let i = 0; i < imageIdsToPrefetch.length; i++) {
taskPromises.push(cornerstoneDICOMImageLoader.wadouri.loadImage(imageIdsToPrefetch[i]).promise)
if (taskPromises.length >= 6 || i === imageIdsToPrefetch.length - 1) {
let res = await Promise.all(taskPromises)
if (modality === 'PT') {
this.cachePTMetadata(res)
}
taskPromises = []
}
}
},
cachePTMetadata(images) {
images.map(i=>{
const instanceMetadata = getPTImageIdInstanceMetadata(i.imageId)
if (typeof instanceMetadata.CorrectedImage === 'string') {
instanceMetadata.CorrectedImage = instanceMetadata.CorrectedImage.split('\\')
}
if (instanceMetadata) {
const suvScalingFactors = calculateSUVScalingFactors([instanceMetadata])
ptScalingMetaDataProvider.addInstance(i.imageId, suvScalingFactors[0])
}
})
},
async setSeriesInfo(obj, isLocate = false) {
try {
if (this.series && obj.Id === this.series.Id && obj.Description === this.series.Description && !isLocate) {
obj.SliceIndex = this.series.SliceIndex
}
// if (isLocate && obj.SliceIndex === this.series.SliceIndex) return
if (this.series?.Stack && obj.Stack[obj.SliceIndex] === this.series.Stack[this.series.SliceIndex]) return
this.series = { ...obj }
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const image = await cornerstoneDICOMImageLoader.wadouri.loadImage(obj.ImageIds[obj.SliceIndex]).promise
if (obj.Modality === 'PT') {
this.cachePTMetadata([image])
}
this.prefetchMetadataInformation(obj.ImageIds, obj.Modality)
await viewport.setStack(this.series.Stack, obj.SliceIndex)
viewport.render()
} catch (e) {
console.log(e)
}
},
cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail
const worldPoint = currentPoints.world
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let referencedImageId = viewport.getCurrentImageId()
const data = viewport.getImageData()
if (!data) return
const { dimensions, imageData, metadata, voxelManager } = data
const index = imageData.worldToIndex(worldPoint)
index[0] = Math.floor(index[0])
index[1] = Math.floor(index[1])
index[2] = Math.floor(index[2])
this.mousePosition.index = index
const modality = metadata.Modality
let ijk = csUtils.transformWorldToIndex(imageData, worldPoint)
ijk = vec3.round(ijk, ijk);
if (csUtils.indexWithinDimensions(ijk, dimensions)) {
this.isHandleOutsideImage = false
let value = voxelManager.getAtIJKPoint(ijk)
ijk[2] = viewport.getCurrentImageIdIndex()
let modalityUnit
if (modality === 'US') {
const calibratedResults = csToolsUtils.getCalibratedProbeUnitsAndValue(image, [ijk])
const hasEnhancedRegionValues = calibratedResults.values.every(
(value) => value !== null
)
value = (hasEnhancedRegionValues ? calibratedResults.values : value)
modalityUnit = hasEnhancedRegionValues
? calibratedResults.units
: 'raw';
} else {
const scalingModule = referencedImageId && metaData.get('scalingModule', referencedImageId)
const isSuvScaled = typeof scalingModule?.suvbw === 'number'
const pixelUnitsOptions = {
isPreScaled: csToolsUtils.viewport.isViewportPreScaled(viewport, referencedImageId),
isSuvScaled: isSuvScaled,
}
modalityUnit = csToolsUtils.getPixelValueUnits(
modality,
referencedImageId,
pixelUnitsOptions
);
}
this.mousePosition.value = value
this.mousePosition.modalityUnit = modalityUnit
}
},
toggleTask(evt, visitTaskNum, i) {
this.$emit('activeViewport', this.viewportIndex)
const num = visitTaskNum + i
if (num >= 0 && num <= this.taskInfo.VisitNum) {
this.$emit('toggleTaskByViewport', { series: this.series, visitTaskNum: num })
}
evt.stopImmediatePropagation()
evt.stopPropagation()
evt.preventDefault()
},
viewCD(taskId) {
this.$emit('previewCD', taskId)
},
setWwwcIdx(idx) {
this.wwwcIdx = idx
},
clickSlider(e) {
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
this.sliderInfo.height = height
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseup(e) {
this.sliderInfo.isMove = false
},
sliderMousedown(e) {
const boxHeight = this.$refs['sliderBox'].clientHeight
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
this.sliderInfo.oldM = e.clientY
this.sliderInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
sliderMousemove(e) {
if (!this.sliderInfo.isMove) return
const delta = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
const boxHeight = this.$refs['sliderBox'].clientHeight
if (delta < 0) return
if (delta > boxHeight) return
const height = delta * 100 / boxHeight
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
this.sliderInfo.height = height
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseleave(e) {
if (!this.sliderInfo.isMove) return
this.sliderInfo.isMove = false
},
preventDefault(e) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
}
}
}
</script>
<style lang="scss" scoped>
.viewport-wrapper {
width:100%;
height:100%;
position: relative;
.left-top-text {
position: absolute;
left: 5px;
top: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
.cd-info {
color: #ddd;
font-size: 18px;
}
.subject-info {
color:#f44336;
padding: 5px 0px;
margin: 0;
}
}
.top-center-tool {
position: absolute;
left:50%;
top: 5px;
transform: translateX(-50%);
z-index: 1;
.toggle-visit-container {
display: flex;
}
.arrw_icon{
width: 20px;
height: 20px;
background-color: #3f3f3f;
text-align: center;
line-height: 20px;
border-radius: 10%;
}
.arrow_text{
height: 20px;
line-height: 20px;
background-color: #00000057;
color: #fff;
padding:0 10px;
font-size: 14px;
}
}
.right-top-text {
position: absolute;
right: 5px;
top: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
}
.left-bottom-text {
position: absolute;
left: 5px;
bottom: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-bottom-text {
position: absolute;
right: 5px;
bottom: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-slider-box {
position: absolute;
right: 1px;
height: calc(100% - 140px);
transform: translateY(-50%);
top: calc(50% - 30px);
width: 10px;
background: #333;
z-index: 1;
cursor: pointer;
}
.right-slider-box:after{
content: '';
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
background: #333;
}
.slider {
height: 20px;
width: 100%;
position: absolute;
top: 0;
z-index:10;
background: #9e9e9e;
cursor: move
}
.orientation-top {
position: absolute;
left: 50%;
top: 30px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-bottom {
position: absolute;
left: 50%;
bottom: 15px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-left {
position: absolute;
top: 50%;
left: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
.orientation-right {
position: absolute;
top: 50%;
right: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
}
</style>
@@ -1,101 +0,0 @@
<template>
<div class="visit-review-container">
<el-tabs v-model="activeName">
<!-- 阅片 -->
<el-tab-pane v-if="taskInfo" :label="$t('trials:reading:tabTitle:review')" name="read">
<read-page ref="readPage" :reading-tool="readingTool" />
</el-tab-pane>
<!-- 报告 -->
<el-tab-pane
v-if="taskInfo && !taskInfo.IseCRFShowInDicomReading"
:label="$t('trials:reading:tabTitle:report')"
name="report"
>
<report-page
v-if="activeName === 'report' && taskInfo.CriterionType !== 0"
@setReadingTaskState="setReadingTaskState"
/>
<customize-report-page
v-if="activeName === 'report' && taskInfo.CriterionType === 0"
@setReadingTaskState="setReadingTaskState"
/>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import ReadPage from './ReadPage'
import ReportPage from './ReportPage'
import CustomizeReportPage from './customize/ReportPage'
export default {
name: 'VisitReview',
components: {
ReadPage,
ReportPage,
CustomizeReportPage
},
props: {
readingTool: {
type: Number,
default: 0
}
},
data() {
return {
activeName: 'read',
taskInfo: null
}
},
mounted() {
console.log(this.readingTool)
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
},
methods: {
setReadingTaskState(state) {
this.$refs['readPage'].setReadingTaskState(state)
}
}
}
</script>
<style lang="scss" scoped>
.visit-review-container {
height: 100%;
display: flex;
flex-direction: column;
background-color: #000;
padding: 5px;
::v-deep .el-tabs {
height: 100%;
display: flex;
flex-direction: column;
.el-tabs__item {
color: #fff;
}
.el-tabs__item.is-active {
color: #428bca;
}
.el-tabs__item:hover {
color: #428bca;
}
.el-tabs__header {
height: 50px;
margin: 0px;
}
.el-tabs__content {
flex: 1;
margin: 0px;
}
.el-tab-pane {
height: 100%;
}
}
}
</style>
@@ -1,325 +0,0 @@
<template>
<div class="colorMap">
<div class="item" effect="dark" :title="$t('trials:lugano:button:colormap')">
<div class="colorBar"
style="display:flex;justify-content: flex-start;align-items: center;position: relative;"
@mouseleave="isSlideMoving = false">
<div class="tool-wrapper" style="margin-right:0px" @click.stop="showColorBarPanel($event)"
@mouseleave="handleColorBarMouseout">
<div>
<div class="dropdown">
<div id="colorBar" class="icon" style="display: flex;align-items: center;width:266px">
<canvas id="colorBarCanvas" />
</div>
<!-- 伪彩 -->
<div class="text">{{ $t('trials:lugano:button:colormap') }}</div>
<div class="dropdown-content" style="width:266px">
<ul>
<li v-for="(colorMap, index) in colorMaps" :key="colorMap"
style="display: flex;align-items: center;margin-bottom:5px;padding:0 5px;justify-content: space-between;"
:class="{ activeLi: rgbPresetName === colorMap }"
@click="setColorMap(colorMap)">
<canvas :id="`colorBarCanvas${index}`" />
<span style="margin-left:5px;font-size: 10px;">{{ colorMap
}}</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<div style="margin-left:-1px;border: 1px solid #424242;">
<el-input v-model="range" size="mini" style="width:120px" maxlength="3"
oninput="if(value){value=value.replace(/[^\d]/g,'')} if(value<=0){value=''}"
@change="upperRangeChange">
<template slot="append">g/ml</template>
</el-input>
</div>
<div id="slider" style="position: absolute;left: 6px;top:5px;cursor: pointer;">
<div id="sliderBox" class="slider" style="height: 17px;width: 10px;background-color: #909399;" />
<div id="slider-position" style="color:#ddd;font-size: 12px;">0</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {
utilities as csUtils,
} from '@cornerstonejs/core'
import colormaps from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/colormaps'
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
const { registerColormap, getColormapNames, getColormap } = csUtils.colormap
export default {
name: "colorMap",
data() {
return {
colorMaps: [],
rgbPresetName: 'siemens',
range: 40,
upper: 6,
}
},
mounted() {
colormaps.forEach(colormap => {
registerColormap(colormap)
})
this.colorMaps = getColormapNames()
this.colorMaps.unshift('hsv')
this.$nextTick(() => {
this.renderColorMaps()
this.upperRangeChange(this.range)
this.initSlider()
})
},
methods: {
renderColorMaps() {
this.createColorBar(this.rgbPresetName, 'colorBarCanvas', 256, 15)
this.colorMaps.forEach((e, index) => {
this.createColorBar(e, `colorBarCanvas${index}`, 180, 15)
})
},
voiChange(v) {
this.$emit('voiChange', v)
},
initSlider() {
var slider = document.getElementById('slider')
var sliderBox = document.getElementById('sliderBox')
var container = document.getElementById('colorBarCanvas')
slider.addEventListener('mousedown', () => {
this.isSlideMoving = true
})
document.addEventListener('mousemove', (e) => {
if (this.isSlideMoving) {
var containerWidth = container.clientWidth
var sliderWidth = sliderBox.clientWidth
var maxLeft = containerWidth - sliderWidth
var left = e.clientX - container.getBoundingClientRect().left
var position = null
position = left
if (left < 0) {
left = 6
position = 0
} else if (left > maxLeft) {
left = maxLeft + 6
position = maxLeft
}
slider.style.left = left + 'px'
var positionValue = document.getElementById('slider-position')
var upper = this.range
position = parseInt((position / maxLeft) * upper)
positionValue.textContent = position
this.upper = position
this.voiChange(position)
}
})
document.addEventListener('mouseup', () => {
this.isSlideMoving = false
})
},
upperRangeChange(v) {
if (v === 0 || v < this.upper) {
return
}
var sliderBox = document.getElementById('sliderBox')
var container = document.getElementById('colorBarCanvas')
var containerWidth = container.clientWidth
var sliderWidth = sliderBox.clientWidth
var maxLeft = containerWidth - sliderWidth
var left = (this.upper / this.range) * maxLeft
if (left < 0) {
left = 6
} else if (left >= maxLeft) {
left = maxLeft + 6
}
var slider = document.getElementById('slider')
slider.style.left = left + 'px'
var positionValue = document.getElementById('slider-position')
positionValue.textContent = this.upper
},
createColorBar(rgbPresetName, elId, width, height) {
var colorMap = null
if (rgbPresetName === 'hsv') {
colorMap = vtkColorMaps.getPresetByName(rgbPresetName)
} else {
colorMap = getColormap(rgbPresetName)
}
const rgbPoints = colorMap.RGBPoints
const canvas = document.getElementById(elId)
const ctx = canvas.getContext('2d')
const canvasWidth = width
const canvasHeight = height
const rectWidth = width
const rectHeight = canvasHeight
canvas.width = canvasWidth
canvas.height = canvasHeight
const gradient = ctx.createLinearGradient(0, 0, rectWidth, 0)
for (let i = 0; i < rgbPoints.length; i += 4) {
let position = 0
if (rgbPoints[0] === -1) {
position = (rgbPoints[i] + 1) / 2
} else {
position = rgbPoints[i]
}
const color = `rgb(${parseInt(rgbPoints[i + 1] * 255)}, ${parseInt(rgbPoints[i + 2] * 255)}, ${parseInt(rgbPoints[i + 3] * 255)})`
gradient.addColorStop(position, color)
}
ctx.fillStyle = gradient
ctx.fillRect(0, 0, rectWidth, rectHeight)
},
async setColorMap(rgbPresetName) {
this.rgbPresetName = rgbPresetName
this.createColorBar(this.rgbPresetName, 'colorBarCanvas', 256, 15)
this.$emit("setColorMap", rgbPresetName)
},
showColorBarPanel(e) {
e.currentTarget.firstChild.firstChild.lastChild.style.display = 'block'
},
handleColorBarMouseout(e) {
e.currentTarget.firstChild.firstChild.lastChild.style.display = 'none'
},
init() {
this.createColorBar(this.rgbPresetName, 'colorBarCanvas', 256, 15)
this.$emit("setColorMap", this.rgbPresetName)
}
}
}
</script>
<style lang="scss" scoped>
.activeLi {
background-color: #919295;
}
.tool-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-right: 30px;
.icon {
padding: 5px;
border: 1px solid #404040;
cursor: pointer;
text-align: center;
.svg-icon {
font-size: 25px;
color: #ddd;
}
}
.text {
position: relative;
font-size: 12px;
margin-top: 5px;
color: #d0d0d0;
display: none;
}
}
.dropdown {
position: relative;
display: inline-block;
.icon-content {
display: flex;
align-items: center;
border: 1px solid #404040;
}
.text {
text-align: center;
}
.tool-icon {
padding: 5px;
cursor: pointer;
text-align: center;
.svg-icon {
font-size: 20px;
color: #ddd;
}
}
.arrow-icon {
cursor: pointer;
padding: 7px 2px 7px 0px;
}
.arrow-icon:hover {
background-color: #607d8b;
}
.icon-content-d:hover {
background-color: #607d8b;
}
.tool-icon-d {
padding: 5px;
.svg-icon {
font-size: 20px;
color: #ddd;
}
}
}
.dropdown-content {
display: none;
position: absolute;
background-color: #383838;
color: #fff;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 9999;
font-size: 12px;
ul {
list-style: none;
margin: 0;
padding: 0;
text-align: center;
li {
a {
display: block;
padding: 5px;
}
}
}
ul li:hover {
background-color: #727272;
cursor: pointer;
}
}
.item {
box-sizing: border-box;
position: relative;
border: 1px solid rgba(255, 255, 255, 0.21);
position: relative;
&_active {
// border: 2px solid #ffeb3b;fff
border: 1px dashed rgb(250, 250, 0);
}
}
.colorBar {
::v-deep .el-input--mini .el-input__inner {
height: 25px;
line-height: 25px;
border: none;
background-color: transparent;
color: #ddd;
}
}
</style>
@@ -1,438 +0,0 @@
<template>
<div v-loading="loading" class="questionList-wrapper">
<div class="container">
<div class="basic-info">
<h3 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo">
<span v-if="visitInfo.SubjectCode">{{ visitInfo.SubjectCode }} </span>
<span style="margin-left:5px;">{{ visitInfo.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="resetForm"
/>
</el-tooltip>
</div>
</div>
<el-form
v-if="taskInfo && rerender"
ref="questions"
size="small"
:model="questionForm"
class="ecrf-form"
>
<template v-if="rerender">
<QuestionFormItem
v-for="question of questions"
:key="question.Id"
:visit-task-id="visitTaskId"
:question="question"
:question-form="questionForm"
:reading-task-state="readingTaskState"
:criterion-id="criterionId"
:calculation-list="calculationList"
:is-baseline="isBaseLineTask"
@resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData"
/>
</template>
<el-form-item v-if="readingTaskState < 2">
<div style="text-align:center;">
<el-button v-if="taskInfo && taskInfo.IseCRFShowInDicomReading" type="primary" @click="skipTask">
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button type="primary" @click="handleSave">
{{ $t('common:button:save') }}
</el-button>
<el-button v-if="taskInfo && taskInfo.IseCRFShowInDicomReading" type="primary" @click="handleSubmit">
{{ $t('common:button:submit') }}
</el-button>
</div>
</el-form-item>
</el-form>
</div>
<!-- 签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
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" @closeDialog="closeSignDialog" />
</el-dialog>
</div>
</template>
<script>
import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, getQuestionCalculateRelation } from '@/api/trials'
import { setSkipReadingCache, resetReadingTask } from '@/api/reading'
import const_ from '@/const/sign-code'
import QuestionFormItem from '@/views/trials/trials-panel/reading/dicoms/customize/CustomizeQuestionFormItem'
import SignForm from '@/views/trials/components/newSignForm'
export default {
name: 'EcrfList',
components: {
QuestionFormItem,
SignForm
},
props: {
visitInfo: {
type: Object,
required: true
},
readingTaskState: {
type: Number,
required: true
},
},
data() {
return {
trialId: '',
criterionId: '',
visitTaskId: '',
loading: false,
questions: [],
questionForm: {},
publicQuestions: [],
signVisible: false,
signCode: null,
currentUser: zzSessionStorage.getItem('userName'),
activeName: 0,
classArr: [],
calculationList: [],
taskInfo: null,
isBaseLineTask: false,
rerender: true
}
},
mounted() {
this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionType = this.taskInfo.CriterionType
this.getQuestionCalculateRelation()
this.getQuestions()
},
methods: {
async getQuestions() {
this.loading = true
try {
const param = {
visitTaskId: this.visitTaskId
}
const res = await getCustomTableQuestionAnswer(param)
if (res.IsSuccess) {
// this.readingTaskState = res.OtherInfo.ReadingTaskState
res.Result.SinglePage.map((v) => {
if (v.Type === 'group' && v.Childrens.length === 0) return
if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary' && v.Type !== 'table' && v.Type !== 'basicTable' && v.Type !== 'number') {
this.$set(this.questionForm, v.Id, v.Answer)
}
if (v.Type === 'table' || v.Type === 'basicTable') {
this.$set(this.questionForm, v.Id, v.TableQuestions.Answers)
}
if (v.Type === 'class') {
this.classArr.push({ triggerId: v.ClassifyQuestionId, classId: v.Id, classifyAlgorithms: v.ClassifyAlgorithms, classifyType: v.ClassifyType })
}
if (v.Type === 'number') {
this.$set(this.questionForm, v.Id, v.Answer === '' ? '' : parseFloat(v.Answer).toFixed(this.digitPlaces))
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
}
})
this.questions = res.Result.SinglePage
this.loading = false
}
} catch (e) {
console.log(e)
this.loading = false
}
},
setChild(obj) {
obj.forEach(i => {
if (i.Type !== 'group' && i.Type !== 'summary' && i.Id && i.Type !== 'table' && i.Type !== 'basicTable') {
this.$set(this.questionForm, i.Id, i.Answer)
}
if (i.Type === 'table' || i.Type === 'basicTable') {
i.TableQuestions.Questions.forEach(o => {
if (o.Type === 'number') {
i.TableQuestions.Answers.forEach((ite, index) => {
this.$set(i.TableQuestions.Answers[index], o.Id, i.TableQuestions.Answers[index][o.Id] ? parseFloat(i.TableQuestions.Answers[index][o.Id]).toFixed(this.digitPlaces) : null)
})
}
})
this.$set(this.questionForm, i.Id, i.TableQuestions.Answers)
}
if (i.Type === 'class') {
this.classArr.push({ triggerId: i.ClassifyQuestionId, classId: i.Id, classifyAlgorithms: i.ClassifyAlgorithms, classifyType: i.ClassifyType })
}
if (i.Type === 'number') {
this.$set(this.questionForm, i.Id, i.Answer === '' ? '' : parseFloat(i.Answer).toFixed(this.digitPlaces))
}
if (i.Childrens && i.Childrens.length > 0) {
this.setChild(i.Childrens)
}
})
},
async getQuestionCalculateRelation() {
try {
const res = await getQuestionCalculateRelation({ TrialReadingCriterionId: this.criterionId })
this.calculationList = res.Result
} catch (e) {
console.log(e)
}
},
async handleSave(isMsg) {
const valid = await this.$refs['questions'].validate()
if (!valid) return
this.loading = true
try {
var answers = []
for (const k in this.questionForm) {
if (this.questionForm[k] instanceof Array) {} else {
answers.push({ id: k, answer: this.questionForm[k] })
}
}
var params = {
visitTaskId: this.visitTaskId,
answers: answers
}
const res = await changeDicomReadingQuestionAnswer(params)
if (res.IsSuccess) {
if (isMsg) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.loading = false
}
} catch (e) {
this.loading = false
}
},
async handleSubmit() {
const valid = await this.$refs['questions'].validate()
if (!valid) return
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
},
//
closeSignDialog(isSign, signInfo) {
if (isSign) {
this.signConfirm(signInfo)
} else {
this.signVisible = false
}
},
//
async signConfirm(signInfo) {
this.loading = true
var answers = []
for (const k in this.questionForm) {
answers.push({ readingQuestionTrialId: k, answer: this.questionForm[k] })
}
var params = {
data: {
trialId: this.trialId,
visitTaskId: this.visitTaskId,
readingQuestionCriterionTrialId: this.criterionId,
answerList: answers
},
signInfo: signInfo
}
try {
const res = await submitVisitTaskQuestionsInDto(params)
this.loading = false
if (res.IsSuccess) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.isEdit = false
this.$refs['signForm'].btnLoading = false
this.signVisible = false
this.$emit('setReadingTaskState', 2)
window.opener.postMessage('refreshTaskList', window.location)
const confirm = await this.$confirm(
this.$t('trials:noneDicoms:message:msg1'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
window.location.reload()
}
} catch (e) {
this.loading = false
this.$refs['signForm'].btnLoading = false
}
},
async skipTask() {
try {
//
const confirm = await this.$confirm(
this.$t('trials:readingReport:message:skipConfirm'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.loading = true
const res = await setSkipReadingCache({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
window.location.reload()
}
} catch (e) {
this.loading = false
console.log(e)
}
},
resetFormItemData(v) {
this.questionForm[v] = null
},
setFormItemData(obj) {
this.$set(this.questionForm, obj.key, JSON.parse(JSON.stringify(obj.val)))
this.classArr.map(i => {
if (i.triggerId === obj.key) {
let answer = null
const list = JSON.parse(i.classifyAlgorithms)
if (i.classifyType === 0) {
const o = list.find(v => {
return (
parseFloat(obj.val) >= parseFloat(v.gt) &&
parseFloat(obj.val) < parseFloat(v.lt)
)
})
answer = o ? o.label : null
} else if (i.classifyType === 1) {
const o = list.find(v => {
return v.val.includes(obj.val)
})
answer = o ? o.label : null
}
this.$set(this.questionForm, i.classId, answer)
}
})
},
async resetForm() {
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 })
if (res.IsSuccess) {
this.rerender = false
await this.getQuestionCalculateRelation()
await this.getQuestions()
this.$emit('resetAnnotations', this.visitTaskId)
this.$nextTick(()=>{
this.rerender = true
})
}
loading.close()
} catch (e) {
loading.close()
console.log(e)
}
},
}
}
</script>
<style lang="scss" scoped>
.questionList-wrapper{
height: 100%;
overflow-y: auto;
.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;
}
}
.ecrf-form{
::v-deep .el-form-item__label{
color: #ddd;
}
}
::v-deep .el-table,
.el-table__expanded-cell {
background-color: #000;
color: #fff;
border-color: #444444;
}
::v-deep .el-table th,
.el-table tr {
background-color: #000;
color: #fff;
border-color: #444444;
}
::v-deep .el-table__body tr > td {
background-color: #000 !important;
color: #fff;
border-color: #444444;
}
::v-deep .el-table__body tr:hover > td {
background-color: #858282 !important;
color: #fff;
border-color: #444444;
}
::v-deep .el-table--border th.gutter:last-of-type {
border: none;
}
::v-deep .el-dialog{
background: #1e1e1e;
border: 1px solid #ddd;
color: #ddd;
.el-dialog__title{
color:#fff;
}
.el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
.el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
.el-form-item__label{
color: #dfdfdf
}
}
}
}
// .ecrf-list-container{
// min-height:400px;
// color: #ddd;
// }
</style>
@@ -1,855 +0,0 @@
<template>
<div class="report-wrapper">
<el-card v-loading="loading" shadow="never" style="display:flex;flex-direction: column;">
<div slot="header" class="clearfix report-header">
<h3 style="margin:0;padding:0;">{{ $t('trials:readingReport:title:eicrf') }}</h3>
<div style="margin-left:auto">
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="skipTask"
>
<!-- 跳过 -->
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button v-if="readingTaskState<2" type="primary" size="small" @click="getReportInfo">{{ $t('trials:readingReport:button:refresh') }}</el-button>
<el-button v-if="readingTaskState<2" type="primary" size="small" @click="handleSave(true)">{{ $t('common:button:save') }}</el-button>
<el-button v-if="readingTaskState<2" type="primary" size="small" @click="handleConfirm">{{ $t('common:button:submit') }}</el-button>
</div>
</div>
<div style="flex: 1">
<el-table
v-if="taskQuestions.length > 0"
ref="reportList"
v-adaptive="{bottomOffset:0}"
:data="taskQuestions"
row-key="Id"
border
default-expand-all
height="100"
:tree-props="{children: 'Childrens', hasChildren: 'hasChildren'}"
size="mini"
>
<el-table-column
prop=""
label=""
show-overflow-tooltip
width="350px"
>
<template slot-scope="scope">
<span v-if="scope.row.QuestionName">{{ scope.row.BlindName ? scope.row.QuestionName : scope.row.QuestionName }}</span>
<span
v-else
style="font-weight: bold;font-size: 16px;color: #f44336;"
>
{{ scope.row.GroupName }}
</span>
</template>
</el-table-column>
<el-table-column
v-for="task in visitTaskList"
:key="task.VisitTaskId"
prop="date"
show-overflow-tooltip
width="200px"
>
<template slot="header">
<div v-if="task.IsCurrentTask">
{{ task.BlindName }}
</div>
<div v-else>
<div>
{{ task.BlindName }}
<el-button type="text" size="small" @click="previewDicoms(task)">
<span class="el-icon-view" />
</el-button>
</div>
</div>
</template>
<template slot-scope="scope">
<template v-if="readingTaskState<2 && task.VisitTaskId === visitTaskId && (scope.row.Type==='input' || scope.row.Type==='number' || scope.row.Type==='select' || scope.row.Type==='textarea' || scope.row.Type==='radio')">
<!-- 输入框 -->
<div>
<template v-if="!((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)" />
<el-input
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type==='input' || scope.row.Type==='textarea') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
size="mini"
/>
<span v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type==='input' || scope.row.Type==='textarea')">
{{ questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId] }}
</span>
<el-input
v-else-if="(scope.row.Type==='input' || scope.row.Type==='textarea') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId]"
size="mini"
/>
<span v-else-if="scope.row.Type==='input' || scope.row.Type==='textarea'">
{{ questionForm[scope.row.QuestionId] }}
</span>
<el-select
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type==='select' || scope.row.Type==='radio') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
size="mini"
clearable
>
<template>
<el-option
v-for="val in scope.row.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<span v-else-if="questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type==='select'">
{{ questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId] }}
</span>
<el-select
v-else-if="(scope.row.Type==='select' || scope.row.Type==='radio') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId]"
size="mini"
clearable
>
<template>
<el-option
v-for="val in scope.row.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<span v-else-if="scope.row.Type==='select' || scope.row.Type==='radio'">
{{ questionForm[scope.row.QuestionId] }}
</span>
<el-input
v-else-if="scope.row.DataSource !== 1 && questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type==='number' && (scope.row.xfIndex || scope.row.xfIndex === 0) && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
:disabled="scope.row.DataSource === 1"
size="mini"
@blur="limitBlur(questionForm[scope.row.QuestionId][scope.row.xfIndex], scope.row.TableQuestionId, scope.row.ValueType)"
@focus="() => {questionId = scope.row.QuestionId}"
>
<template v-if="scope.row.Unit !== 0" slot="append">{{ scope.row.Unit !== 4 ? $fd('ValueUnit', scope.row.Unit) : scope.row.CustomUnit }}</template>
<template v-else-if="scope.row.ValueType === 2" slot="append">%</template>
</el-input>
<span v-else-if="questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type==='number' && (scope.row.xfIndex || scope.row.xfIndex === 0)">
<template v-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]))? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]:`${questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]} ${scope.row.Unit !== 4 ? $fd('ValueUnit',scope.row.Unit) : scope.row.CustomUnit}` }}
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId])) ? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]:`${questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]} %` }}
</template>
<template v-else>
{{ isNaN(parseInt(questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId])) ? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]:`${questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]}` }}
</template>
</span>
<el-input
v-else-if="scope.row.DataSource !== 1 && scope.row.Type==='number' && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId]"
:disabled="scope.row.DataSource === 1"
size="mini"
@blur="limitBlur(questionForm, scope.row.QuestionId, scope.row.ValueType)"
@focus="() => {questionId = scope.row.QuestionId}"
>
<template v-if="scope.row.Unit !== 0" slot="append">{{ scope.row.Unit !== 4 ? $fd('ValueUnit', scope.row.Unit) : scope.row.CustomUnit }}</template>
<template v-else-if="scope.row.ValueType === 2" slot="append">%</template>
</el-input>
<span v-else-if="scope.row.Type==='number'">
<template v-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId]))? questionForm[scope.row.QuestionId]:`${questionForm[scope.row.QuestionId]} ${scope.row.Unit !== 4 ? $fd('ValueUnit',scope.row.Unit) : scope.row.CustomUnit}` }}
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId])) ? questionForm[scope.row.QuestionId]:`${questionForm[scope.row.QuestionId]} %` }}
</template>
<template v-else>
{{ isNaN(parseInt(questionForm[scope.row.QuestionId])) ? questionForm[scope.row.QuestionId] : questionForm[scope.row.QuestionId] }}
</template>
</span>
</div>
</template>
<template v-else-if="scope.row.Type==='upload' && scope.row.Answers[task.VisitTaskId]">
<span v-for="(url,index) in scope.row.Answers[task.VisitTaskId].split('|')" :key="url" style="margin-left: 5px;">
<el-button v-if="scope.row.Answers[task.VisitTaskId]" type="text" @click="preview(url)">
{{ `${$t('trials:noneDicom:title:attachment')}${index + 1}` }}
</el-button>
</span>
</template>
<template v-else-if="scope.row.DictionaryCode">
{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}
</template>
<template v-else-if="criterionType === 10">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]}` }}
</template>
<template v-else-if="!((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)" />
<template v-else-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]} ${scope.row.Unit !== 4 ? $fd('ValueUnit',scope.row.Unit) : scope.row.CustomUnit}` }}
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId])) ? scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]} %` }}
</template>
<template v-else-if="scope.row.Answers && scope.row.Answers.hasOwnProperty(task.VisitTaskId)">
{{ scope.row.Answers[task.VisitTaskId] }}
</template>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
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" @closeDialog="closeSignDialog" />
</el-dialog>
<!-- 预览文件 -->
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:title="$t('common:button:preview')"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<div
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<PreviewFile
v-if="previewVisible"
:file-path="currentPath"
:file-type="currentType"
/>
</div>
</el-dialog>
</div>
</template>
<script>
import { changeCalculationAnswer, getReadingReportEvaluation, submitDicomVisitTask, verifyVisitTaskQuestions, getQuestionCalculateRelation } from '@/api/trials'
import { setSkipReadingCache } from '@/api/reading'
import { getAutoCutNextTask } from '@/api/user'
import const_ from '@/const/sign-code'
import SignForm from '@/views/trials/components/newSignForm'
import PreviewFile from '@/components/PreviewFile/index'
import { getToken } from '@/utils/auth'
import store from '@/store'
export default {
name: 'CustomizeReportPage',
components: { SignForm, PreviewFile },
data() {
return {
trialId: '',
visitTaskId: '',
subjectId: '',
readingTool: 1,
criterionType: null,
isReadingTaskViewInOrder: false,
currentUser: zzSessionStorage.getItem('userName'),
signVisible: false,
signCode: null,
visitTaskList: [],
taskQuestions: [],
loading: false,
answers: [],
readingTaskState: 2,
answerArr: [],
questions: [],
CalculationList: [],
TrialReadingCriterionId: null,
tableAnswers: {},
questionForm: {},
questionId: null,
taskInfo: null,
previewVisible: false,
currentPath: '',
currentType: ''
}
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v, oldv) {
try {
if (!v[this.questionId] || !oldv[this.questionId]) return
} catch (e) {
}
this.formItemNumberChange(this.questionId, false)
}
}
},
async mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.trialId = this.$route.query.trialId
this.visitTaskId = this.taskInfo.VisitTaskId
this.subjectId = this.taskInfo.SubjectId
this.criterionType = this.taskInfo.CriterionType
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.TrialReadingCriterionId = this.taskInfo.TrialReadingCriterionId
window.addEventListener('resize', () => {
this.handleResize()
})
await this.getQuestionCalculateRelation()
this.getReportInfo()
},
methods: {
limitBlur(questionForm, id, valueType) {
const value = questionForm[id]
if (valueType === 0) {
this.$set(questionForm, id, parseInt(value))
} else if (valueType === 3) {
this.$set(questionForm, id, parseFloat(value))
} else {
this.$set(questionForm, id, parseFloat(value).toFixed(this.digitPlaces))
}
},
setImageUrl(qid, index, tqid, url, RowId) {
if (index || index === 0) {
//
this.$set(this.questionForm[qid][index], tqid, url)
this.$set(this.questionForm[qid][index], tqid + '_RowId', RowId)
// this.questionForm[qid][index][tqid] = url
} else {
//
this.questionForm[qid] = url
}
},
getTagterAnswers(list, questionId) {
list.forEach(v => {
if (v.QuestionId === questionId) {
return Object.assign({}, v.Answers)
} else if (v.Childrens.length > 0) {
return this.getTagterAnswers(v.Childrens, questionId)
}
})
},
formItemNumberChange(questionId, isTable) {
if (isTable) {
this.CalculationList.forEach((v, i) => {
var find = v.CalculateQuestionList.filter(o => {
return o.QuestionId === questionId
})
// findnumber
if (find) {
var num = this.logic(v)
if (num !== false) {
this.$set(this.questionForm, v.QuestionId, num)
// this.$emit('setFormItemData', { key: v.QuestionId, val: num })
}
}
})
} else {
this.CalculationList.forEach(v => {
var find = v.CalculateQuestionList.filter(o => {
return o.TableQuestionId === questionId
})
// findnumber
if (find) {
var num = this.logic(v)
if (num !== false) {
this.$set(this.questionForm, v.QuestionId, num)
// this.$emit('setFormItemData', { key: v.QuestionId, val: num })
}
}
})
}
// this.$emit('formItemNumberChange')
},
getTableAnswers(QuestionId, list) {
var arr = []
window.xfList = list
list.forEach((v, i) => {
var obj = {}
v.Childrens.forEach((o) => {
this.$set(o, 'xfIndex', i)
obj[o.TableQuestionId + '_RowId'] = o.RowId
obj[o.TableQuestionId] = o.Answers[this.visitTaskId]
})
arr.push(obj)
})
return arr
},
InitVisitTaskQuestionForm() {
this.taskQuestions.map((v, i) => {
if (v.Type === 'group' && v.Childrens.length === 0 && v.Type !== 'table' && v.Type !== 'basicTable') return
if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary' && v.Type !== 'table' && v.Type !== 'basicTable' && v.Type !== 'number') {
this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId])
}
if (v.Type === 'table' || v.Type === 'basicTable') {
var tableAnswers = this.getTableAnswers(v.QuestionId, v.Childrens, i)
this.$set(this.questionForm, v.QuestionId, tableAnswers)
// this.$set(v, 'xfIndex', i)
}
if (v.Type === 'number') {
let val = null
if (v.ValueType === 0) {
val = parseInt(v.Answers[this.visitTaskId])
} else if (v.ValueType === 3) {
val = v.Answers[this.visitTaskId]
} else {
val = v.Answers[this.visitTaskId] === '' ? null : v.Answers[this.visitTaskId]
}
this.$set(this.questionForm, v.QuestionId, val)
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
}
})
this.formItemNumberChange(this.questionId, false)
},
setChild(obj) {
obj.forEach((i, index) => {
if (i.Type !== 'group' && i.Type !== 'summary' && i.Id && i.Type !== 'table' && i.Type !== 'basicTable') {
this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId])
}
if (i.Type === 'table' || i.Type === 'basicTable') {
var tableAnswers = this.getTableAnswers(i.QuestionId, i.Childrens, index)
this.$set(this.questionForm, i.QuestionId, tableAnswers)
}
if (i.Type === 'number') {
let val = null
if (i.ValueType === 0) {
val = parseInt(i.Answers[this.visitTaskId])
} else if (i.ValueType === 3) {
val = i.Answers[this.visitTaskId]
} else {
val = i.Answers[this.visitTaskId] === '' ? null : i.Answers[this.visitTaskId]
}
this.$set(this.questionForm, i.QuestionId, val)
}
if (i.Childrens && i.Childrens.length > 0 && i.Type !== 'table' && i.Type !== 'basicTable') {
this.setChild(i.Childrens)
}
})
},
getQuestionCalculateRelation() {
return new Promise(resolve => {
getQuestionCalculateRelation({
TrialReadingCriterionId: this.TrialReadingCriterionId
}).then(res => {
this.CalculationList = res.Result
resolve()
})
})
},
logic(rules, num = 0) {
try {
if (rules.CalculateQuestionList.length === 0) {
return false
}
rules.CalculateQuestionList.forEach((o, i) => {
if (i === 0) {
if (rules.CustomCalculateMark > 4) {
switch (rules.CustomCalculateMark) {
case 5:
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = parseFloat(q[o.TableQuestionId])
} else {
num *= parseFloat(q[o.TableQuestionId])
}
})
break
case 6:
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = isNaN(parseFloat(q[o.TableQuestionId])) ? null : parseFloat(q[o.TableQuestionId])
} else {
num += isNaN(parseFloat(q[o.TableQuestionId])) ? null : parseFloat(q[o.TableQuestionId])
}
})
break
case 7:
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = parseFloat(q[o.TableQuestionId])
} else {
num += parseFloat(q[o.TableQuestionId])
}
})
num = this.questionForm[o.QuestionId].length === 0 ? 0 : num / this.questionForm[o.QuestionId].length
break
case 8:
const arr = []
this.questionForm[o.QuestionId].forEach(q => {
arr.push(q[o.TableQuestionId])
})
num = arr.length === 0 ? 0 : Math.max(...arr)
break
case 9:
const arr1 = []
this.questionForm[o.QuestionId].forEach(q => {
arr1.push(q[o.TableQuestionId])
})
num = arr1.length === 0 ? 0 : Math.min(...arr1)
break
}
} else {
num = parseFloat(this.questionForm[o.TableQuestionId])
}
} else {
switch (rules.CustomCalculateMark) {
case 1:
num += parseFloat(this.questionForm[o.TableQuestionId])
break
case 2:
num -= parseFloat(this.questionForm[o.TableQuestionId])
break
case 3:
num *= parseFloat(this.questionForm[o.TableQuestionId])
break
case 4:
num /= parseFloat(this.questionForm[o.TableQuestionId])
// num /= parseFloat(this.questionForm[o.TableQuestionId])
break
}
}
})
} catch (e) {
console.log(e)
}
if (rules.ValueType === 2) {
num = num * 100
}
return isNaN(num) ? '' : isFinite(num) ? num.toFixed(this.digitPlaces) : '∞'
},
getReportInfo() {
this.loading = true
var params = {
visitTaskId: this.visitTaskId,
trialId: this.trialId
}
this.taskQuestions = []
getReadingReportEvaluation(params).then(res => {
this.readingTaskState = res.Result.ReadingTaskState
this.answerArr = []
this.questions = res.Result.TaskQuestions.concat()
var taskQuestions = this.getQuestions(res.Result.TaskQuestions)
taskQuestions.forEach(item => {
this.$set(this.taskQuestions, this.taskQuestions.length, item)
})
this.visitTaskList = res.Result.VisitTaskList
this.InitVisitTaskQuestionForm()
this.handleResize()
this.loading = false
}).catch(() => { this.loading = false })
},
getQuestions(questions) {
const arr = []
if (questions.length !== 0) {
questions.forEach((item) => {
const obj = item
this.$set(obj, 'Answers', {})
item.Answer.forEach(i => {
if (item.DictionaryCode) {
this.$set(obj.Answers, i.VisitTaskId, i.Answer ? parseInt(i.Answer) : null)
// obj.Answers[i.VisitTaskId] = i.Answer ? parseInt(i.Answer) : null
} else {
if (item.Type === 'number') {
let val = null
if (item.ValueType === 0) {
val = parseInt(i.Answer)
} else if (item.ValueType === 3) {
val = i.Answer
} else {
val = isNaN(parseFloat(i.Answer)) ? i.Answer : parseFloat(i.Answer).toFixed(this.digitPlaces)
}
this.$set(obj.Answers, i.VisitTaskId, val)
} else {
this.$set(obj.Answers, i.VisitTaskId, i.Answer)
}
// obj.Answers[i.VisitTaskId] = i.Answer
}
})
if (item.Childrens.length >= 1) {
obj.Childrens = this.getQuestions(item.Childrens)
}
arr.push(obj)
})
}
return arr
},
handleShowDetail(val) {
this.getReportInfo()
// this.taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null)
},
async handleConfirm() {
await this.handleSave(false)
await this.verifyVisitTaskQuestions()
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
},
verifyVisitTaskQuestions() {
return new Promise((resolve, reject) => {
this.loading = true
verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId }).then(res => {
this.loading = false
resolve()
}).catch(() => {
this.loading = false
reject()
})
})
},
handleResize() {
this.$nextTick(() => {
this.$refs.reportList ? this.$refs.reportList.doLayout() : ''
})
},
//
closeSignDialog(isSign, signInfo) {
if (isSign) {
this.signConfirm(signInfo)
} else {
this.signVisible = false
}
},
//
async signConfirm(signInfo) {
this.loading = true
try {
var params = {
data: {
visitTaskId: this.visitTaskId
},
signInfo: signInfo
}
const res = await submitDicomVisitTask(params)
if (res.IsSuccess) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
if (this.$refs['signForm']) {
this.$refs['signForm'].btnLoading = false
}
this.signVisible = false
//
this.readingTaskState = 2
this.$emit('setReadingTaskState', 2)
window.opener.postMessage('refreshTaskList', window.location)
const res = await getAutoCutNextTask()
const isAutoTask = res.Result.AutoCutNextTask
if (isAutoTask) {
window.location.reload()
} else {
// ''
this.$confirm(this.$t('trials:readingReport:message:msg4'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
window.location.reload()
})
.catch(action => {
// changeURLStatic('visitTaskId', this.visitTaskId)
})
}
}
this.loading = false
} catch (e) {
console.log(e)
this.loading = false
if (this.$refs['signForm'] && this.$refs['signForm'].btnLoading) {
this.$refs['signForm'].btnLoading = false
}
}
},
previewDicoms(task) {
if (this.openWindow) {
this.openWindow.close()
}
var token = getToken()
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
// var subjectCode = this.$router.currentRoute.query.subjectCode
var subjectCode = localStorage.getItem('subjectCode')
var subjectId = this.$router.currentRoute.query.subjectId
var trialId = this.$router.currentRoute.query.trialId
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var criterionType = this.$router.currentRoute.query.criterionType
var readingTool = this.$router.currentRoute.query.readingTool
var path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${task.VisitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
const routeData = this.$router.resolve({ path })
this.openWindow = window.open(routeData.href, '_blank')
},
handleSave(isPrompt) {
return new Promise((resolve, reject) => {
this.loading = true
var answers = []
var tableQuestionAnswer = []
for (const k in this.questionForm) {
if (this.questionForm[k] instanceof Array) {
this.questionForm[k].forEach((v, i) => {
Object.keys(v).forEach(o => {
if (o.indexOf('_RowId') === -1) {
tableQuestionAnswer.push({
questionId: k,
answer: v[o],
tableQuestionId: o,
rowId: v[o + '_RowId']
})
}
})
})
// tableQuestionAnswer.push({})
} else {
answers.push({ questionId: k, answer: this.questionForm[k] })
}
}
var params = {
visitTaskId: this.visitTaskId,
questionAnswer: answers,
tableQuestionAnswer: tableQuestionAnswer
}
changeCalculationAnswer(params).then(res => {
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
// DicomEvent.$emit('refreshQuestionAnswer')
this.loading = false
resolve()
}).catch(() => {
this.loading = false
reject()
})
})
},
async skipTask() {
try {
//
const confirm = await this.$confirm(
this.$t('trials:readingReport:message:skipConfirm'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.loading = true
const res = await setSkipReadingCache({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
window.location.reload()
}
} catch (e) {
this.loading = false
console.log(e)
}
},
//
preview(path) {
this.currentPath = path
const arr = path.split('.')
this.currentType = arr[arr.length - 1]
this.previewVisible = true
}
}
}
</script>
<style lang="scss" scoped>
.report-wrapper{
height: 100%;
// background-color: #fff;
background-color: #000;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
// background: #d0d0d0;
}
.report-header{
display: flex;
}
.el-card{
background-color: #000;
color: #ffffff;
border:none;
}
::v-deep .el-table--border th.gutter:last-of-type{
border: none;
}
::v-deep .el-table, .el-table__expanded-cell {
background-color: #000;
color: #fff;
border-color:#444444;
}
::v-deep .el-table th, .el-table tr {
background-color: #000;
color: #fff;
border-color:#444444;
}
::v-deep .el-table__body tr > td{
background-color:#000 !important;
color: #fff;
border-color:#444444;
}
::v-deep .el-table__body tr:hover > td{
background-color:#858282 !important;
color: #fff;
border-color:#444444;
}
::v-deep .el-table--border th.gutter:last-of-type{
border: none;
}
::v-deep .el-card__header{
border: none;
padding: 10px;
}
::v-deep .el-upload-list--picture-card .el-upload-list__item{
width: 30px;
height: 30px;
}
::v-deep .el-upload--picture-card{
width: 30px;
height: 30px;
line-height: 40px;
}
::v-deep .el-dialog{
background: #1e1e1e;
border: 1px solid #ddd;
color: #ddd;
.el-dialog__title{
color:#fff;
}
.el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
.el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
.el-form-item__label{
color: #dfdfdf
}
}
}
::v-deep .el-switch__label{
color:#fff;
}
::v-deep .el-switch__label.is-active{
color: #428bca;
}
.uploadWrapper{
display: flex;
flex-direction: column;
align-items: flex-start;
}
</style>
@@ -1,324 +0,0 @@
<template>
<div>
<div
v-if="!!question.GroupName && question.Type==='group'"
>
<h4 style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?question.GroupEnName:question.GroupName }}
</h4>
</div>
<template v-else>
<el-form-item
v-if="(question.ShowQuestion===1 && question.ParentTriggerValueList.includes(String(questionForm[question.ParentId]))) || question.ShowQuestion===0 "
:label="`${question.QuestionName}`"
:prop="question.Id"
:rules="[
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (questionForm[question.RelevanceId] === question.RelevanceValue))) && question.Type!=='group' && question.Type!=='summary',
message: ['radio', 'select', 'checkbox'].includes(question.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']},
]"
:class="[question.Type==='group' ? 'mb' : (question.Type==='upload' || question.QuestionName.length > 15) ?'uploadWrapper' : '']"
>
<!-- 输入框 -->
<el-input
v-if="question.Type==='input'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
/>
<!-- 多行文本输入框 -->
<el-input
v-else-if="question.Type==='textarea'"
v-model="questionForm[question.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
maxlength="500"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
/>
<!-- 下拉框 -->
<el-select
v-else-if="question.Type==='select'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2 || ((question.TableQuestionType === 2 || question.QuestionGenre === 2) && !!question.DictionaryCode)"
clearable
@change="((val)=>{formItemChange(val, question)})"
>
<template v-if="question.TableQuestionType === 1">
<el-option
v-for="item in organList"
:key="item.Id"
:label="item[question.DataTableColumn]"
:value="item[question.DataTableColumn]"
/>
</template>
<template v-else-if="question.TableQuestionType === 3 || question.QuestionGenre === 3">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:label="item.label"
/>
</template>
<template v-else-if="(question.TableQuestionType === 2 || question.QuestionGenre === 2) && question.DictionaryCode">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<!-- 单选 -->
<el-radio-group
v-else-if="question.Type==='radio'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
>
<template v-if="question.DictionaryCode">
<el-radio
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:label="String(item.value)"
>
{{ item.label }}
</el-radio>
</template>
<template v-else-if="question.TypeValue">
<el-radio
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</template>
</el-radio-group>
<!-- 复选框 -->
<el-checkbox-group
v-else-if="question.Type==='checkbox'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
>
<el-checkbox
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-checkbox>
</el-checkbox-group>
<!-- 数值 -->
<template v-else-if="question.Type==='number'">
<el-input-number
v-if="question.ValueType === 0"
v-model="questionForm[question.Id]"
:precision="0"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 3"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 1 || question.ValueType === 2"
v-model="questionForm[question.Id]"
:precision="digitPlaces"
:disabled="readingTaskState >= 2"
/>
</template>
<el-input
v-else-if="question.Type==='calculation'"
v-model="questionForm[question.Id]"
disabled
>
<template v-if="question.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(question.Unit)) }}
</template>
</el-input>
<!-- 上传图像 -->
<el-upload
v-else-if="question.Type==='upload'"
action
:accept="accept"
:limit="question.ImageCount"
:on-preview="handlePictureCardPreview"
:before-upload="handleBeforeUpload"
:http-request="uploadScreenshot"
list-type="picture-card"
:on-remove="handleRemove"
:file-list="fileList"
:class="{disabled:fileList.length >= question.ImageCount}"
:disabled="readingTaskState >= 2"
>
<i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}">
<img
class="el-upload-list__item-thumbnail"
:src="OSSclientConfig.basePath + file.url"
alt=""
>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
v-if="readingTaskState < 2"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete" />
</span>
</span>
</div>
</el-upload>
<el-dialog
v-if="question.Type==='upload'"
append-to-body
:visible.sync="imgVisible"
width="600px"
>
<el-image :src="imageUrl" width="100%">
<div slot="placeholder" class="image-slot">
加载中<span class="dot">...</span>
</div>
</el-image>
</el-dialog>
</el-form-item>
</template>
<question-form-item
v-for="(item) in question.Childrens"
:key="item.Id"
:question="item"
:question-form="questionForm"
:reading-task-state="readingTaskState"
:visitTaskId="visitTaskId"
@resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData"
/>
</div>
</template>
<script>
// import { uploadReadingAnswerImage } from '@/api/trials'
import { mapGetters } from 'vuex'
export default {
name: 'QuestionFormItem',
props: {
questionForm: {
type: Object,
default() {
return {}
}
},
question: {
type: Object,
default() {
return {}
}
},
readingTaskState: {
type: Number,
required: true
},
visitTaskId: {
type: String,
default: ''
}
},
data() {
return {
fileList: [],
accept: '.png,.jpg,.jpeg',
imgVisible: false,
imageUrl: '',
urls: [],
digitPlaces: 2
}
},
computed: {
...mapGetters(['language'])
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v) {
// console.log(v)
}
}
},
mounted() {
let digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
},
methods: {
formItemChange(v, question) {
if (question.Childrens.length > 0) {
this.resetChild(question.Childrens)
} else {
this.$emit('setFormItemData', { key: question.Id, val: v })
}
},
resetChild(obj) {
obj.forEach(i => {
this.$emit('resetFormItemData', i.Id)
if (i.Childrens && i.Childrens.length > 0) {
this.resetChild(i.Childrens)
}
})
},
resetFormItemData(v) {
this.$emit('resetFormItemData', v)
},
setFormItemData(obj) {
this.$emit('setFormItemData', obj)
},
}
}
</script>
<style lang="scss" scoped>
.mb{
margin-bottom: 0px;
}
.disabled{
::v-deep .el-upload--picture-card {
display: none;
}
}
.uploadWrapper{
display: flex;
flex-direction: column !important;
align-items: flex-start;
}
::v-deep .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-input-group__append, .el-input-group__prepend{
padding: 0 10px;
}
::v-deep .el-form-item__content {
width: 100%;
}
::v-deep .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
// ::v-deep .el-radio__input.is-disabled.is-checked .el-radio__inner {
// background-color: #428bca;
// border-color: #428bca;
// }
</style>
@@ -1,365 +0,0 @@
<template>
<div class="table-question-form">
<div style="display: flex;justify-content: space-between;">
<h3 v-if="qsForm.LesionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ qsForm.LesionName }}
</h3>
<!-- 关闭 -->
<div>
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="close" />
</div>
</div>
<el-form-item
:label="$t('trials:reading:title:lesionType')"
prop="LesionType"
:rules="[
{ required:true,message: $t('common:ruleMessage:select'), trigger: ['blur']},
]"
>
<!-- 下拉框 -->
<el-select
v-model="qsForm.LesionType"
filterable
:disabled="!isCurrentTask || readingTaskState>=2 || !isBaseLineTask"
@change="((val)=>{lesionTypeChange(val)})"
>
<el-option
v-for="item of $d.LesionType"
v-show="!(isBaseLineTask && item.value === 2)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<!-- 靶病灶非靶病灶的器官为肝脏/Liver时,需要选择典型肝内病灶该值默认为否如果选择是对于靶病灶需要提示按照独立影像评估章程的相关规则对于典型肝内靶病灶请测量肿瘤活性部分最长径提示方式为在长径属性上显示浮框或者增加
-->
<el-form-item
v-for="qs in questions"
v-show="qs.ShowQuestion!==2"
:key="qs.Id"
:prop="qs.Id"
:rules="[
{ required: (qs.IsRequired === 0 || (qs.IsRequired ===1 && qs.RelevanceId && (questionForm[qs.RelevanceId] === qs.RelevanceValue)) || (qs.QuestionMark === 6 && questionForm.IsCanEditPosition === true) || (questionForm.IsCanEditPosition && qs.QuestionMark === 10) || (qs.QuestionMark === 21 && (questionForm.LesionOrgan === '肝脏' || questionForm.LesionOrgan === 'Liver') && (lesionType === 0 || lesionType === 1 || lesionType === 2))) && qs.Type!=='group' && qs.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(qs.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<span slot="label" style="display:inline-block;" >
<el-tooltip v-if="qs.QuestionMark === 0 && (questionForm.LesionOrgan === '肝脏' || questionForm.LesionOrgan === 'Liver') && (lesionType === 0 || lesionType === 1 || lesionType === 2) && questionForm.IntrahepaticLesion" effect="dark" :content="$t('trials:mRecist:warnning:msg1')" placement="bottom">
<i class='el-icon-warning' />
</el-tooltip>
{{ qs.QuestionName }}
</span>
<!-- 输入框 -->
<template v-if="qs.Type==='input' || qs.Type==='number'">
<el-input
v-if="qs.Type==='input' || qs.Type==='number'"
v-model="qsForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 || qs.QuestionMark === 0 || qs.QuestionMark === 1 || qs.QuestionMark === 2 || qs.QuestionMark === 5 || (qs.QuestionMark === 6 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))|| (qs.QuestionMark === 8 && (isCurrentTaskAdd === 'False' || !!answer.SplitOrMergeLesionName) && lesionType !== 2) || (qs.QuestionMark === 10 && (isCurrentTaskAdd === 'False' || !!answer.SplitOrMergeLesionName))"
@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>
</template>
<!-- 多行文本输入框 -->
<el-input
v-if="qs.Type==='textarea'"
v-model="qsForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<!-- 下拉框 -->
<el-select
v-if="qs.Type==='select'"
v-model="qsForm[qs.Id]"
filterable
:placeholder="qs.QuestionMark === 8 ? $t('common:placeholder:selectorsearch') : qs.QuestionMark === 2 ? '' : $t('common:placeholder:select')"
:disabled="!isCurrentTask || readingTaskState>=2 || qs.QuestionMark === 0 || qs.QuestionMark === 1 || qs.QuestionMark === 2 || qs.QuestionMark === 5 || (qs.QuestionMark === 6 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))|| (qs.QuestionMark === 8 && (isCurrentTaskAdd === 'False'|| !!answer.SplitOrMergeLesionName)) || (qs.QuestionMark === 10 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName)) || (qs.QuestionMark === 21 && (isCurrentTaskAdd === 'False'|| !!answer.SplitOrMergeLesionName)) || (questionForm.LesionOrgan && questionForm.LesionOrgan !== '肝脏' && questionForm.LesionOrgan !== 'Liver' && qs.QuestionMark === 21)"
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.QuestionMark === 8" #prefix>
<span style="padding-left: 5px;">
<i class="el-icon-search" />
</span>
</template>
<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 && qs.QuestionMark === 7 && isBaseLineTask">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="(lesionType === 0 && item.value ===0) || (lesionType === 1 && (item.value ===0))"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark === 7 && !isBaseLineTask">
<el-option-group
:label="!isNaN(parseFloat(answer.LastTaskState)) ? `${$t('trials:dicomReading:tip:lastVisitStatus')} ${$fd(qs.DictionaryCode,parseFloat(answer.LastTaskState))}` : ''"
>
<!-- 首次分裂的病灶只能选择存在 -->
<template v-if="answer.IsFristAdd=== 'True' && answer.SplitOrMergeType === '0'">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="item.value === 0"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<!-- 首次添加的新病灶不能为无法评估和消失 -->
<template v-else-if="isCurrentTaskAdd=== 'True' && lesionType === 2">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="item.value === 0 || item.value === 1"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="item of filterState($d[qs.DictionaryCode])"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
</el-option-group>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark !== 7">
<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-if="qs.Type==='radio'"
v-model="qsForm[qs.id]"
:disabled="!isCurrentTask || readingTaskState>=2"
>
<el-radio
v-for="val in qs.options.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</el-radio-group>
</el-form-item>
</div>
</template>
<script>
export default {
name: 'TableQuestionFormItem',
props: {
tableInfo: {
type: Object,
default() {
return {}
}
},
answer: {
type: Object,
default() {
return {}
}
},
questionForm: {
type: Object,
default() {
return {}
}
},
organs: {
type: Array,
default() {
return []
}
},
readingTaskState: {
type: Number,
required: true
},
isBaseLineTask: {
type: Boolean,
required: true
},
isCurrentTask: {
type: Boolean,
required: true
}
},
data() {
return {
isCurrentTaskAdd: null,
lesionType: null,
questions: [],
organList: [],
qsForm: {}
}
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v) {
if (v.MeasureData) {
const { markTool } = v.MeasureData
if (markTool === 'Bidirectional') {
this.getOrganList(1)
} else if (markTool === 'Length') {
this.getOrganList(0)
} else {
this.getOrganList()
}
} else {
this.getOrganList()
}
for (const key in v) {
this.$set(this.qsForm, key, v[key])
}
this.isCurrentTaskAdd = v.IsCurrentTaskAdd
}
},
tableInfo: {
deep: true,
immediate: true,
handler(v) {
if (v) {
this.lesionType = v.LesionType
this.questions = v.TableQuestions.Questions
}
}
}
},
methods: {
lesionTypeChange(v) {
this.$emit('lesionTypeChange', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex, newLesionType: v })
},
formItemChange(v, qs) {
const updateArr = []
if (qs.QuestionMark === 8 && qs.RelationQuestions.length > 0) {
//
const index = this.organList.findIndex(item => item[qs.DataTableColumn] === v)
if (index > -1) {
const selected = this.organList[index]
qs.RelationQuestions.map(q => {
const val = selected[q.DataTableColumn]
updateArr.push({ questionId: q.Id, val: val, questionMark: q.QuestionMark })
})
updateArr.push({ questionId: 'OrganInfoId', val: selected.OrganInfoId })
updateArr.push({ questionId: 'IsCanEditPosition', val: selected.IsCanEditPosition })
} else {
qs.RelationQuestions.map(q => {
updateArr.push({ questionId: q.Id, val: '', questionMark: q.QuestionMark })
})
}
}
this.$emit('update', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex, questionMark: qs.QuestionMark, questionId: qs.Id, val: v, updateArr })
},
getOrganList(isLymphNodes = null) {
const idx = this.organs.findIndex(i => i.LesionType === this.questionForm.LesionType)
if (idx > -1) {
const arr = this.organs[idx].OrganList
if (!isNaN(parseInt(isLymphNodes))) {
this.organList = arr.filter((item) => item.IsLymphNodes === parseInt(isLymphNodes))
} else {
this.organList = arr
}
}
},
filterState(arr) {
if (!this.isBaseLineTask) {
const isLymphLesion = this.questionForm.IsLymphNodes
const lesionLength = this.questionForm.LesionLength
const lesionShort = this.questionForm.LesionShort
const bLesionL = !isNaN(parseFloat(this.questionForm.BaseLineMajorAxis)) ? parseFloat(this.questionForm.BaseLineMajorAxis) : 0
const bLesionS = !isNaN(parseFloat(this.questionForm.BaseLineShortAxis)) ? parseFloat(this.questionForm.BaseLineShortAxis) : 0
if (this.lesionType === 1 && isLymphLesion === 1 && this.questionForm.MeasureData && this.questionForm.MeasureData.markTool === 'Bidirectional' && lesionShort < bLesionS) {
arr = arr.filter(i => i.value !== 1)
} else if (this.lesionType === 1 && isLymphLesion === 1 && this.questionForm.MeasureData && this.questionForm.MeasureData.markTool === 'Bidirectional' && lesionShort >= 10 && lesionShort > bLesionS) {
arr = arr.filter(i => i.value === 0 || i.value === 1)
} else if (this.lesionType === 1 && isLymphLesion === 0 && this.questionForm.MeasureData && (this.questionForm.MeasureData.markTool === 'Length' || this.questionForm.MeasureData.markTool === 'Bidirectional') && lesionLength < bLesionL) {
arr = arr.filter(i => i.value !== 1)
}
return arr
} else {
return arr
}
},
close() {
this.$emit('close', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex })
}
}
}
</script>
<style lang="scss" scoped>
.table-question-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;
}
.el-form-item__content
.el-select{
width: 100%;
}
.input-width1{
width: calc(100% - 60px)!important;
}
.input-width2{
width: 100% !important;
}
}
</style>
@@ -1,283 +0,0 @@
const config = {
'standards': [
{
'type': 1,
'name': 'RECIST 1.1',
'tools': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '长短径测量工具',
'icon': 'bidirection',
'toolName': 'Bidirectional',
'i18nKey': 'trials:reading:button:bidirectional',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'type': 2,
'name': 'Lugano 2014',
'tools': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '长短径测量工具',
'icon': 'bidirection',
'toolName': 'Bidirectional',
'i18nKey': 'trials:reading:button:bidirectional',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'type': 3,
'name': 'iRECIST',
'tools': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '长短径测量工具',
'icon': 'bidirection',
'toolName': 'Bidirectional',
'i18nKey': 'trials:reading:button:bidirectional',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'type': 7,
'name': 'mRECIST HCC',
'tools': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '长短径测量工具',
'icon': 'bidirection',
'toolName': 'Bidirectional',
'i18nKey': 'trials:reading:button:bidirectional',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'type': 10,
'name': 'PCWG3',
'tools': [
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'type': 17,
'name': 'PCWG3',
'tools': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'type': 19,
'name': 'IVUS定量评估',
'tools': []
},
{
'type': 20,
'name': 'OCT定量评估',
'tools': []
},
{
'type': 21,
'name': 'MRI-PDFF',
'tools': [
{
'name': '圆形测量',
'icon': 'oval',
'toolName': 'Probe',
'i18nKey': 'trials:reading:button:circle',
'isDisabled': false,
'disabledReason': ''
}
]
}
],
'customizeStandards': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '长短径测量工具',
'icon': 'bidirection',
'toolName': 'Bidirectional',
'i18nKey': 'trials:reading:button:bidirectional',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '椭圆工具',
'icon': 'oval',
'toolName': 'CircleROI',
'i18nKey': 'trials:reading:button:Circle',
'isDisabled': false,
'disabledReason': ''
}
]
}
const getTools = (criterionType) => {
const standard = config.standards.find(s => s.type === criterionType)
return standard?.tools || []
}
const getCustomizeStandardsTools = (toolNames) => {
const filteredTools = config.customizeStandards.filter(item => toolNames.includes(item.toolName))
return filteredTools || []
}
export { config, getTools, getCustomizeStandardsTools }
@@ -1,305 +0,0 @@
import {
VolumeViewport,
utilities as csUtils,
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
const {
utilities,
annotation,
drawing
} = cornerstoneTools
const { getAnnotations } = annotation.state
const { isAnnotationVisible } = annotation.visibility
const { isAnnotationLocked } = annotation.locking
const drawHandlesSvg = drawing.drawHandles
const drawRectSvg = drawing.drawRectByCoordinates
const drawLinkedTextBoxSvg = drawing.drawLinkedTextBox
const { getTextBoxCoordsCanvas } = utilities.drawing
/**
* RectangleROIAnnotation let you draw annotations that measures the statistics
* such as area, max, mean and stdDev of a Rectangular region of interest.
* You can use RectangleROIAnnotation in all perpendicular views (axial, sagittal, coronal).
* Note: annotation tools in cornerstone3DTools exists in the exact location
* in the physical 3d space, as a result, by default, all annotations that are
* drawing in the same frameOfReference will get shared between viewports that
* are in the same frameOfReference. RectangleROI tool's text box lines are dynamically
* generated based on the viewport's underlying Modality. For instance, if
* the viewport is displaying CT, the text box will shown the statistics in Hounsfield units,
* and if the viewport is displaying PET, the text box will show the statistics in
* SUV units.
*
* The resulting annotation's data (statistics) and metadata (the
* state of the viewport while drawing was happening) will get added to the
* ToolState manager and can be accessed from the ToolState by calling getAnnotations
* or similar methods.
*
* ```js
* cornerstoneTools.addTool(RectangleROITool)
*
* const toolGroup = ToolGroupManager.createToolGroup('toolGroupId')
*
* toolGroup.addTool(RectangleROITool.toolName)
*
* toolGroup.addViewport('viewportId', 'renderingEngineId')
*
* toolGroup.setToolActive(RectangleROITool.toolName, {
* bindings: [
* {
* mouseButton: MouseBindings.Primary, // Left Click
* },
* ],
* })
* ```
*
* Read more in the Docs section of the website.
*/
class RectangleROITool extends cornerstoneTools.RectangleROITool {
constructor(
toolProps,
defaultToolProps
) {
super(toolProps, defaultToolProps);
}
/**
* it is used to draw the rectangleROI annotation in each
* request animation frame. It calculates the updated cached statistics if
* data is invalidated and cache it.
*
* @param enabledElement - The Cornerstone's enabledElement.
* @param svgDrawingHelper - The svgDrawingHelper providing the context for drawing.
*/
renderAnnotation = (
enabledElement,
svgDrawingHelper
) => {
let renderStatus = false;
const { viewport } = enabledElement;
const { element } = viewport;
let annotations = getAnnotations(this.getToolName(), element);
if (!annotations?.length) {
return renderStatus;
}
annotations = this.filterInteractableAnnotationsForElement(
element,
annotations
);
if (!annotations?.length) {
return renderStatus;
}
const targetId = this.getTargetId(viewport);
const renderingEngine = viewport.getRenderingEngine();
const styleSpecifier = {
toolGroupId: this.toolGroupId,
toolName: this.getToolName(),
viewportId: enabledElement.viewport.id,
};
for (let i = 0; i < annotations.length; i++) {
const annotation = annotations[i];
const { annotationUID, data } = annotation;
const { points, activeHandleIndex } = data.handles;
const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
styleSpecifier.annotationUID = annotationUID;
const { color, lineWidth, lineDash } = this.getAnnotationStyle({
annotation,
styleSpecifier,
});
const { viewPlaneNormal, viewUp } = viewport.getCamera();
// If cachedStats does not exist, or the unit is missing (as part of import/hydration etc.),
// force to recalculate the stats from the points
if (
!data.cachedStats[targetId] ||
data.cachedStats[targetId].areaUnit == null
) {
data.cachedStats[targetId] = {
Modality: null,
area: null,
max: null,
mean: null,
stdDev: null,
areaUnit: null,
};
this._calculateCachedStats(
annotation,
viewPlaneNormal,
viewUp,
renderingEngine,
enabledElement
);
} else if (annotation.invalidated) {
this._throttledCalculateCachedStats(
annotation,
viewPlaneNormal,
viewUp,
renderingEngine,
enabledElement
);
// If the invalidated data is as a result of volumeViewport manipulation
// of the tools, we need to invalidate the related stackViewports data if
// they are not at the referencedImageId, so that
// when scrolling to the related slice in which the tool were manipulated
// we re-render the correct tool position. This is due to stackViewport
// which doesn't have the full volume at each time, and we are only working
// on one slice at a time.
if (viewport instanceof VolumeViewport) {
const { referencedImageId } = annotation.metadata;
// invalidate all the relevant stackViewports if they are not
// at the referencedImageId
for (const targetId in data.cachedStats) {
if (targetId.startsWith('imageId')) {
const viewports = renderingEngine.getStackViewports();
const invalidatedStack = viewports.find((vp) => {
// The stack viewport that contains the imageId but is not
// showing it currently
const referencedImageURI =
csUtils.imageIdToURI(referencedImageId);
const hasImageURI = vp.hasImageURI(referencedImageURI);
const currentImageURI = csUtils.imageIdToURI(
vp.getCurrentImageId()
);
return hasImageURI && currentImageURI !== referencedImageURI;
});
if (invalidatedStack) {
delete data.cachedStats[targetId];
}
}
}
}
}
// If rendering engine has been destroyed while rendering
if (!viewport.getRenderingEngine()) {
console.warn('Rendering Engine has been destroyed');
return renderStatus;
}
let activeHandleCanvasCoords;
if (!isAnnotationVisible(annotationUID)) {
continue;
}
if (
!isAnnotationLocked(annotationUID) &&
!this.editData &&
activeHandleIndex !== null && activeHandleIndex !== undefined
) {
// Not locked or creating and hovering over handle, so render handle.
activeHandleCanvasCoords = [canvasCoordinates[activeHandleIndex]];
}
if (activeHandleCanvasCoords) {
const handleGroupUID = '0';
drawHandlesSvg(
svgDrawingHelper,
annotationUID,
handleGroupUID,
activeHandleCanvasCoords,
{
color,
}
);
}
const dataId = `${annotationUID}-rect`;
const rectangleUID = '0';
drawRectSvg(
svgDrawingHelper,
annotationUID,
rectangleUID,
canvasCoordinates,
{
color,
lineDash,
lineWidth,
},
dataId
);
renderStatus = true;
const options = this.getLinkedTextBoxStyle(styleSpecifier, annotation);
if (!options.visibility) {
data.handles.textBox = {
hasMoved: false,
worldPosition: [0, 0, 0],
worldBoundingBox: {
topLeft: [0, 0, 0],
topRight: [0, 0, 0],
bottomLeft: [0, 0, 0],
bottomRight: [0, 0, 0],
},
};
continue;
}
const textLines = this.configuration.getTextLines(data, targetId);
if (!textLines || textLines.length === 0) {
continue;
}
if (!data.handles.textBox.hasMoved) {
const canvasTextBoxCoords = getTextBoxCoordsCanvas(canvasCoordinates);
data.handles.textBox.worldPosition =
viewport.canvasToWorld(canvasTextBoxCoords);
}
const textBoxPosition = viewport.worldToCanvas(
data.handles.textBox.worldPosition
);
const textBoxUID = '1';
const boundingBox = drawLinkedTextBoxSvg(
svgDrawingHelper,
annotationUID,
textBoxUID,
textLines,
textBoxPosition,
canvasCoordinates,
{},
options
);
const { x: left, y: top, width, height } = boundingBox;
data.handles.textBox.worldBoundingBox = {
topLeft: viewport.canvasToWorld([left, top]),
topRight: viewport.canvasToWorld([left + width, top]),
bottomLeft: viewport.canvasToWorld([left, top + height]),
bottomRight: viewport.canvasToWorld([left + width, top + height]),
};
}
return renderStatus;
};
}
export default RectangleROITool;
@@ -1,113 +0,0 @@
<template>
<div v-loading="loading" class="reading-viewer-container">
<!-- 访视阅片 -->
<visit-review
v-if="taskInfo && taskInfo.ReadingCategory=== 1"
/>
<!-- 临床数据 -->
<el-dialog
:visible.sync="clinicalDataVisible"
:custom-class="isClinicalDataFullscreen?'full-dialog-container':'dialog-container'"
:show-close="false"
:close-on-click-modal="false"
:fullscreen="isClinicalDataFullscreen"
>
<span slot="title" class="dialog-footer">
<!-- 当前阅片任务存在临床数据请查看若已查看请点击确认 -->
<span v-if="!closeCDVisible">{{ $t('trials:reading:dagTitle:msg1') }}</span>
<div style="position: absolute;right: 20px;top: 10px;">
<svg-icon :icon-class="isClinicalDataFullscreen?'exit-fullscreen':'fullscreen'" style="cursor: pointer;font-size: 20px;" @click="isClinicalDataFullscreen=!isClinicalDataFullscreen" />
<svg-icon v-if="closeCDVisible" icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;" @click="clinicalDataVisible = false" />
</div>
</span>
<div style="height: 100%;margin:0;display: flex;flex-direction: column;">
<clinical-data
v-if="clinicalDataVisible"
style="flex: 1"
:trial-id="trialId"
:subject-id="taskInfo.SubjectId"
:visit-task-id="cdVisitTaskId"
:is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
/>
<div v-if="!closeCDVisible" style="text-align:right">
<el-button type="primary" @click="handleConfirmCD">{{ $t('trials:reading:button:confirm') }}</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import VisitReview from './components/VisitReview'
import ClinicalData from '@/views/trials/trials-panel/reading/clinical-data'
export default {
name:'Dicoms3d',
components: { VisitReview,ClinicalData },
data() {
return {
taskInfo: null,
trialId: '',
loading: false,
clinicalDataVisible: false,
isClinicalDataFullscreen: false,
closeCDVisible: false,
cdVisitTaskId: ''
}
},
mounted() {
this.trialId = this.$route.query.trialId
this.getTaskInfo()
},
methods: {
async getTaskInfo() {
this.loading = true
try {
const params = {
subjectId: this.$route.query.subjectId,
trialId: this.$route.query.trialId,
subjectCode: this.$route.query.subjectCode,
visitTaskId: this.$route.query.visitTaskId,
trialReadingCriterionId: this.$route.query.TrialReadingCriterionId
}
const res = await getNextTask(params)
this.taskInfo = res.Result
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces))
this.loading = false
this.$nextTick(() => {
if (this.taskInfo.IsExistsClinicalData && this.taskInfo.IsNeedReadClinicalData && !this.taskInfo.IsReadClinicalData) {
this.isClinicalDataFullscreen = false
this.clinicalDataVisible = true
this.cdVisitTaskId = this.taskInfo.VisitTaskId
}
})
} catch (e) {
console.log(e)
this.loading = false
}
},
}
}
</script>
<style lang="scss" scoped>
.reading-viewer-container {
width: 100%;
height: 100%;
// ::v-deep .dialog-container{
// margin-top: 50px !important;
// width:75%;
// height:80%;
// }
// ::v-deep .el-dialog__body{
// padding: 10px;
// height: calc(100% - 70px);
// }
// .el-dialog__header{
// position: relative;
// }
// .full-dialog-container{
// ::v-deep .is-fullscreen .el-dialog__body{
// height: calc(100% - 70px);
// }
// }
}
</style>
@@ -302,7 +302,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -317,9 +317,8 @@ export default {
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
@@ -348,23 +347,22 @@ export default {
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
console.log(isPrompt)
this.$message.success(this.$t('common:message:savedSuccessfully'))
try {
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
console.log(isPrompt)
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve()
} catch (e) {
this.loading = false
reject()
}
this.$emit('getGlInfo')
resolve(true)
} else {
reject(false)
reject()
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
},
@@ -358,7 +358,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -373,9 +373,9 @@ export default {
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
@@ -404,24 +404,22 @@ export default {
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
try {
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
console.log(isPrompt)
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve()
} catch (e) {
this.loading = false
reject()
}
this.$emit('getGlInfo')
resolve(true)
} else {
resolve(false)
reject()
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
},
getBeforeAnswer(qsId, row) {
@@ -362,7 +362,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -377,9 +377,8 @@ export default {
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
@@ -408,23 +407,22 @@ export default {
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
try {
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
console.log(isPrompt)
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve()
} catch (e) {
this.loading = false
reject()
}
this.$emit('getGlInfo')
resolve(true)
} else {
resolve(false)
reject()
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
},
@@ -1,481 +0,0 @@
<template>
<el-form v-if="globalForm.taskList.length > 0" ref="globalRuleForm" :model="globalForm" class="global-form">
<el-table
v-loading="loading"
:data="globalForm.taskList"
>
<!-- 访视名称 -->
<el-table-column
prop="BlindName"
:label="$t('trials:globalReview:table:visitName')"
show-overflow-tooltip
width="150"
/>
<!-- 评估结果 -->
<el-table-column
:label="$t('trials:globalReview:table:evaluationRes')"
align="center"
prop=""
>
<template>
<el-table-column
v-for="(qs,index) in globalInfo.evaluationQsList"
:key="index"
prop=""
:label="qs"
show-overflow-tooltip
width="150"
>
<!-- <template slot-scope="scope">
<div v-if="scope.row.BeforeQuestionList.length>index && scope.row.BeforeQuestionList[index].Answer" :style="{color: scope.row.BeforeQuestionList[index].IsGlobalAnswer ? '#f66' : null}">
<span v-if="scope.row.BeforeQuestionList[index].DictionaryCode">
{{ $fd(scope.row.BeforeQuestionList[index].DictionaryCode,parseInt(scope.row.BeforeQuestionList[index].Answer)) }}
</span>
<span v-else>{{ scope.row.BeforeQuestionList[index].Answer }}</span>
</div>
</template> -->
<template slot-scope="scope">
<template v-if="(scope.row.IsBaseLine && (scope.row.BeforeQuestionList[index].GlobalReadingShowType ===1 || scope.row.BeforeQuestionList[index].GlobalReadingShowType ===5)) || (!scope.row.IsBaseLine && (scope.row.BeforeQuestionList[index].GlobalReadingShowType ===2 || scope.row.BeforeQuestionList[index].GlobalReadingShowType ===6)) || (scope.row.BeforeQuestionList[index].GlobalReadingShowType ===0 || scope.row.BeforeQuestionList[index].GlobalReadingShowType ===4)">
<div v-if="scope.row.BeforeQuestionList.length>index && scope.row.BeforeQuestionList[index].Answer" :style="{color: scope.row.BeforeQuestionList[index].IsGlobalAnswer ? '#f66' : null}">
<span v-if="scope.row.BeforeQuestionList[index].DictionaryCode">
{{ $fd(scope.row.BeforeQuestionList[index].DictionaryCode,parseInt(scope.row.BeforeQuestionList[index].Answer)) }}
</span>
<span v-else>{{ scope.row.BeforeQuestionList[index].Answer }}</span>
</div>
</template>
</template>
</el-table-column>
</template>
</el-table-column>
<!-- 是否同意访视结果 -->
<el-table-column
prop=""
:label="$t('trials:globalReview:table:isAgreeEvaluationRes')"
show-overflow-tooltip
width="170"
>
<template slot-scope="scope">
<el-form-item
v-if="readingTaskState<2"
:prop="`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`"
label=""
:rules="[
{ required: true,message: $t('common:ruleMessage:select'), trigger: ['change','blur']},
]"
class="form-item"
>
<el-radio-group
v-model="globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]"
@change="handleAgreeOrNotChange(scope.$index,scope.row.AgreeOrNot[0].GlobalAnswerType)"
>
<el-radio
v-for="item of $d.ReadingYesOrNo"
:key="'AgreeOrNot' + item.value"
:label="String(item.value)"
>
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-tag v-else-if="scope.row.AgreeOrNot.length > 0 && parseInt(scope.row.AgreeOrNot[0].Answer) === 1" type="primary">
{{ $fd('ReadingYesOrNo',parseInt(scope.row.AgreeOrNot[0].Answer)) }}
</el-tag>
<el-tag v-else-if="scope.row.AgreeOrNot.length > 0 && parseInt(scope.row.AgreeOrNot[0].Answer) === 0" type="danger"> {{ $fd('ReadingYesOrNo',parseInt(scope.row.AgreeOrNot[0].Answer)) }}</el-tag>
<span v-else />
</template>
</el-table-column>
<!-- 调整后结果 -->
<el-table-column
:label="$t('trials:globalReview:table:adjustedRes')"
align="center"
prop=""
>
<template>
<el-table-column
v-for="(qs,index) in globalInfo.adjustedQsList"
v-if="qs.isShow"
:key="index"
prop=""
:label="qs.questionName"
show-overflow-tooltip
:min-width="index === 3 ? '200' : '200'"
>
<template slot-scope="scope">
<div v-if="readingTaskState<2 && (scope.row.AfterQuestionList[index].GlobalReadingShowType === 0 || (scope.row.IsBaseLine && scope.row.AfterQuestionList[index].GlobalReadingShowType === 1) || (!scope.row.IsBaseLine && scope.row.AfterQuestionList[index].GlobalReadingShowType === 2))">
<!-- <span v-if="(scope.row.IsBaseLine && scope.row.AfterQuestionList[index].LimitEdit === 2) || (!scope.row.IsBaseLine && scope.row.AfterQuestionList[index].LimitEdit === 1)">
{{ $fd(scope.row.AfterQuestionList[index].DictionaryCode, parseInt(scope.row.AfterQuestionList[index].VisitAnswer)) }}
</span> -->
<el-form-item
style="margin-bottom: 0;"
:prop="`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:scope.row.AfterQuestionList[index].GlobalAnswerType}`"
label=""
:rules="[
{ required:parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) === 0,message: $t('common:ruleMessage:specify'), trigger: ['change','blur']},
]"
>
<label v-if="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) === 0" />
<!-- 裁判问题 -->
<template v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 0 ">
<el-tooltip v-if="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`], scope.row.AfterQuestionList[index])" class="item" effect="dark" :content="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`], scope.row.AfterQuestionList[index])" placement="top-start">
<el-select
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0"
>
<template v-if="scope.row.AfterQuestionList[index].TypeValue">
<el-option
v-for="val in scope.row.AfterQuestionList[index].TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode && scope.row.AfterQuestionList[index].QuestionType === 13">
<el-option
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value!==-1"
:key="item.id"
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode">
<el-option
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
:label="item.label"
/>
</template>
</el-select>
</el-tooltip>
<el-select
v-else
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0"
>
<template v-if="scope.row.AfterQuestionList[index].TypeValue">
<el-option
v-for="val in scope.row.AfterQuestionList[index].TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode && scope.row.AfterQuestionList[index].QuestionType === 13">
<template v-if="getLesionCount(scope.row.LesionCountList,0)">
<el-option
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value!==-1 && item.value !== 1 && item.value !== 3"
:key="item.id"
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template>
<template v-else-if="getLesionCount(scope.row.LesionCountList,1)">
<el-option
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value!==-1 && item.value !== 1 && item.value !== 6"
:key="item.id"
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template>
<template v-else>
<el-option
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value === 1 || item.value === 2 || item.value === 4"
:key="item.id"
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template>
</template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode">
<el-option
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value !== 6"
:key="item.id"
:value="String(item.value)"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
:label="item.label"
/>
</template>
</el-select>
</template>
<!-- 评估更新类型 GlobalAnswerType:3 -->
<template v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 3">
<el-tooltip v-if="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`], scope.row.AfterQuestionList[index], scope.row.AfterQuestionList[index].GlobalAnswerType)" class="item" effect="dark" :content="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`], scope.row.AfterQuestionList[index], scope.row.AfterQuestionList[index].GlobalAnswerType)" placement="top-start">
<el-select
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`]"
style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0"
>
<el-option
v-for="val in globalInfo.assessTypeList"
v-show="(scope.row.IsBaseLine && val.IsBaseLineUse) || (!scope.row.IsBaseLine && val.IsFollowVisitUse)"
:key="val.Code"
:label="language === 'en'?val.Value:val.ValueCN"
:value="val.Code"
/>
</el-select>
</el-tooltip>
<el-select
v-else
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`]"
style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0"
>
<el-option
v-for="val in globalInfo.assessTypeList"
v-show="(scope.row.IsBaseLine && val.IsBaseLineUse) || (!scope.row.IsBaseLine && val.IsFollowVisitUse)"
:key="val.Code"
:label="language === 'en'?val.Value:val.ValueCN"
:value="val.Code"
/>
</el-select>
</template>
<el-input
v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 1"
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
type="textarea"
maxlength="100"
show-word-limit
style="width:90%;"
:autosize="{ minRows: 2 }"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0"
/>
</el-form-item>
</div>
<div v-else>
<span v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 3">
{{ getAssessType(scope.row.AfterQuestionList[index].Answer) }}
</span>
<span v-else-if="scope.row.AfterQuestionList[index].DictionaryCode">
{{ $fd(scope.row.AfterQuestionList[index].DictionaryCode,parseInt(scope.row.AfterQuestionList[index].Answer)) }}
</span>
<span v-else>{{ scope.row.AfterQuestionList[index].Answer }}</span>
</div>
</template>
</el-table-column>
</template>
</el-table-column>
<el-table-column
:label="$t('common:action:action')"
width="100"
>
<template slot-scope="scope">
<el-button
circle
:title="$t('trials:globalReview:table:view')"
icon="el-icon-view"
@click="handleView(scope.row)"
/>
</template>
</el-table-column>
</el-table>
</el-form>
</template>
<script>
import { getToken } from '@/utils/auth'
import { batchSubmitGlobalReadingInfo } from '@/api/trials'
import { mapGetters } from 'vuex'
export default {
props: {
globalInfo: {
type: Object,
default() {
return {}
}
},
globalForm: {
type: Object,
default() {
return {}
}
},
readingTaskState: {
type: Number,
required: true
}
},
data() {
return {
loading: false,
assessTypes: []
}
},
computed: {
...mapGetters(['language'])
},
mounted() {
this.assessTypes = this.globalInfo.assessTypeList.filter(i => i.IsBaseLineUse === this.isBaseline)
},
methods: {
getText(val, row, type) {
if (type === 3) {
var o = this.globalInfo.assessTypeList.find(v => {
return parseInt(v.Code) === parseInt(val)
})
if (!o) {
return ''
}
return this.language === 'en' ? o.Value : o.ValueCN
} else if (row.TypeValue) {
return val
} else if (row.DictionaryCode) {
return this.$fd(row.DictionaryCode, parseInt(val))
}
},
handleView(row) {
var token = getToken()
var visitTaskId = row.VisitTaskId
var criterionType = this.$router.currentRoute.query.criterionType
var readingTool = this.$router.currentRoute.query.readingTool
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
}
const routeData = this.$router.resolve({ path })
var newWindow = window.open(routeData.href, '_blank')
this.$emit('setOpenWindow', newWindow)
},
getLesionCount(lesionList, lesionType) {
const lesion = lesionList.find(i => i.LesionType === lesionType)
return lesion ? lesion.Count : 0
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
var answerList = []
item.AfterQuestionList.map(i => {
var obj = {}
if (i.QuestionId) {
obj.questionId = i.QuestionId
obj.globalAnswerType = i.GlobalAnswerType
obj.answer = this.globalForm[ `${index}${i.QuestionId}`]
} else {
obj.questionId = ''
obj.globalAnswerType = i.GlobalAnswerType
obj.answer = this.globalForm[ `${index}${i.GlobalAnswerType}`]
}
answerList.push(obj)
})
answerList.push({ questionId: '', globalAnswerType: item.AgreeOrNot[0].GlobalAnswerType,
answer: this.globalForm[ `${index}${item.AgreeOrNot[0].GlobalAnswerType}`] })
visitTaskAnswerList.push({ visitTaskId: item.VisitTaskId, answerList: answerList })
})
var params = {
globalTaskId: this.globalInfo.visitTaskId,
subjectId: this.globalInfo.subjectId,
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve(true)
} else {
resolve(false)
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
},
getBeforeAnswer(qsId, row) {
var i = row.BeforeQuestionList.findIndex(item => item.QuestionName === qsId)
if (i > -1 && row.BeforeQuestionList[i].Answer) {
var answer = ''
if (row.BeforeQuestionList[i].DictionaryCode) {
answer = row.BeforeQuestionList[i].Answer
} else {
answer = row.BeforeQuestionList[i].Answer
}
return answer
} else {
return ''
}
},
handleAgreeOrNotChange(index, globalAnswerType) {
var agreeOrNot = parseInt(this.globalForm[`${index}${globalAnswerType}`])
if (agreeOrNot === 1) {
var qsList = this.globalForm.taskList[index].AfterQuestionList
qsList.map(v => {
if (v.QuestionId) {
this.globalForm[`${index}${v.QuestionId}`] = ''
} else if (v.GlobalAnswerType !== globalAnswerType) {
this.globalForm[`${index}${v.GlobalAnswerType}`] = ''
}
})
}
console.log(this.globalForm)
},
getAssessType(v) {
console.log(this.language)
var i = this.globalInfo.assessTypeList.findIndex(i => String(i.Code) === String(v))
if (i > -1) {
return this.language === 'en' ? this.globalInfo.assessTypeList[i].Value : this.globalInfo.assessTypeList[i].ValueCN
} else {
return ''
}
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-form-item label:before {
content: '*';
color: #F56C6C;
margin-right: 4px;
}
::v-deep .el-textarea .el-input__count{
background: rgba(0,0,0,0);
line-height: normal;
}
::v-deep .el-form-item{
margin-bottom: 0px;
}
.global-form{
::v-deep .el-form-item__content{
padding-bottom: 10px;
}
::v-deep .form-item .el-form-item__error{
top: 60%;
}
}
</style>
@@ -220,9 +220,8 @@ export default {
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
@@ -248,24 +247,21 @@ export default {
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
try {
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve()
} catch (e) {
this.loading = false
reject()
}
this.$emit('getGlInfo')
resolve(true)
} else {
resolve(false)
reject()
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
}
}
@@ -355,7 +355,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -369,10 +369,9 @@ export default {
return lesion ? lesion.Count : 0
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
return new Promise(async(resolve, reject) => {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
@@ -401,24 +400,22 @@ export default {
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
try {
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
console.log(isPrompt)
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve()
} catch (e) {
this.loading = false
reject()
}
this.$emit('getGlInfo')
resolve(true)
} else {
resolve(false)
reject()
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
},
getBeforeAnswer(qsId, row) {
@@ -349,7 +349,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -364,9 +364,8 @@ export default {
},
handleSave(isPrompt = true) {
return new Promise(async (resolve, reject) => {
try {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
let valid = await this.$refs['globalRuleForm'].validate()
if (valid) {
this.loading = true
var visitTaskAnswerList = []
this.globalForm.taskList.forEach((item, index) => {
@@ -395,23 +394,22 @@ export default {
trialId: this.globalInfo.trialId,
visitTaskAnswerList
}
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
try {
await batchSubmitGlobalReadingInfo(params)
this.loading = false
if (isPrompt) {
console.log(isPrompt)
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.$emit('getGlInfo')
resolve()
} catch (e) {
this.loading = false
reject()
}
this.$emit('getGlInfo')
resolve(true)
} else {
resolve(false)
reject()
}
} catch(e) {
console.log(e)
this.loading = false
resolve(false)
}
})
},
@@ -41,7 +41,7 @@
{{ $t('trials:globalReview:button:submit') }}
</el-button>
</div>
<customize-table
<CustomizeTable
v-if="CriterionType === 0 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
@@ -50,7 +50,7 @@
@getGlInfo="getGlInfo"
@setOpenWindow="setOpenWindow"
/>
<recist-table
<RecistTable
v-if="CriterionType === 1 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
@@ -59,7 +59,7 @@
@getGlInfo="getGlInfo"
@setOpenWindow="setOpenWindow"
/>
<lugano-table
<LuganoTable
v-if="CriterionType === 2 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
@@ -69,7 +69,7 @@
@handleView="handleView"
@setOpenWindow="setOpenWindow"
/>
<pcwg3-table
<PCWG3Table
v-if="CriterionType === 10 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
@@ -79,7 +79,7 @@
@handleView="handleView"
@setOpenWindow="setOpenWindow"
/>
<irecist-table
<IRecistTable
v-if="CriterionType === 3 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
@@ -88,7 +88,7 @@
@getGlInfo="getGlInfo"
@setOpenWindow="setOpenWindow"
/>
<recistbm-table
<RecistBMTable
v-if="CriterionType === 17 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
@@ -97,16 +97,7 @@
@getGlInfo="getGlInfo"
@setOpenWindow="setOpenWindow"
/>
<mrecist-table
v-if="CriterionType === 7 && Object.keys(globalInfo).length !== 0"
ref="globalTbl"
:global-info="globalInfo"
:global-form="globalInfo.globalForm"
:reading-task-state="readingTaskState"
@getGlInfo="getGlInfo"
@setOpenWindow="setOpenWindow"
/>
</el-card>
<el-card v-if="isReadingShowPreviousResults" :body-style="{ padding: '10px' }" shadow="never">
@@ -173,17 +164,16 @@ import const_ from '@/const/sign-code'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import CustomizeTable from './components/CustomizeTable'
import RecistTable from './components/RecistTable'
import pcwg3Table from './components/PCWG3Table'
import irecistTable from './components/IRecistTable'
import recistbmTable from './components/RecistBMTable'
import luganoTable from './components/LuganoTable'
import mrecistTable from './components/MRecistTable.vue'
import PCWG3Table from './components/PCWG3Table'
import IRecistTable from './components/IRecistTable'
import RecistBMTable from './components/RecistBMTable'
import LuganoTable from './components/LuganoTable'
import SignForm from '@/views/trials/components/newSignForm'
import { changeURLStatic } from '@/utils/history.js'
import store from '@/store'
export default {
name: 'GlobalReview',
components: { CustomizeTable, RecistTable, pcwg3Table, irecistTable, recistbmTable,luganoTable,mrecistTable, SignForm },
components: { CustomizeTable, RecistTable, PCWG3Table, IRecistTable, RecistBMTable,LuganoTable, SignForm },
props: {
trialId: {
type: String,
@@ -394,13 +384,10 @@ export default {
.catch(() => {})
} else {
//
let res = await this.$refs['globalTbl'].handleSave(false)
if (res) {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
}
await this.$refs['globalTbl'].handleSave(false)
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
}
},
//
@@ -471,7 +458,7 @@ export default {
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -328,7 +328,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId;
var path = "";
if (readingTool === 0 || readingTool === 2) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${
this.rowData.SubjectCode
}&subjectId=${
@@ -355,7 +355,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId;
var path = "";
if (readingTool === 0 || readingTool === 2) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${
this.rowData.SubjectCode
}&subjectId=${this.rowData.SubjectId}&visitTaskId=${
@@ -320,7 +320,7 @@ export default {
var isReadingTaskViewInOrder = this.rowData.IsReadingTaskViewInOrder
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
@@ -201,7 +201,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
@@ -178,7 +178,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
@@ -787,7 +787,7 @@ export default {
var trialReadingCriterionId = row.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
@@ -550,7 +550,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0 || readingTool === 2 ) {
if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@@ -1112,7 +1112,7 @@ export default {
lookReadingResults(row) {
var token = getToken()
var path
if (row.ReadingTool === 0 || row.ReadingTool === 2) {
if (row.ReadingTool === 0) {
path = `/readingDicoms?trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
@@ -521,7 +521,7 @@ export default {
window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId)
var token = getToken()
var path = ''
if (row.ReadingTool === 0 || row.ReadingTool === 2 ) {
if (row.ReadingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
@@ -32,7 +32,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var criterionType = this.$router.currentRoute.query.criterionType
var path = ''
if (this.readingTool === 0 || this.readingTool === 2 ) {
if (this.readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${this.readingTool}&TokenKey=${this.token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${this.readingTool}&TokenKey=${this.token}`
@@ -436,7 +436,7 @@ export default {
)
var token = getToken()
var path = ''
if (this.readingTool === 0 || this.readingTool === 2) {
if (this.readingTool === 0) {
if (this.criterionType === 0 && this.trialId === '08dd28b3-6843-fc05-0242-ac1301000000') {
path = `/fusion?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&studyId=62b3dfc4-1e04-4180-910d-fe595f398361&ctseriesId=1bd24f53-d419-32e5-92d4-2b04640aaa65&ptseriesId=2b7b128d-8c3f-8357-ad14-e38f3acbbdff&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&TokenKey=${token}&lang=${this.$i18n.locale}`
} else {
@@ -468,7 +468,7 @@ export default {
)
var token = getToken()
var path = ''
if (this.readingTool === 0 || this.readingTool === 2 ) {
if (this.readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&isReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&isReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&TokenKey=${token}`
@@ -614,7 +614,7 @@ export default {
}
var token = getToken()
var path
if (row.ReadingTool === 0 || row.ReadingTool === 2) {
if (row.ReadingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
@@ -601,29 +601,10 @@
</el-dialog>
<!-- 退回影响任务列表/已影响任务列表 -->
<el-dialog v-if="ReReadingOrBackVisible" :title="opentype === 'read'
? $t('trials:reviewTrack:action:back')
? $t('trials:reviewTrack:dialog:backImpactList')
: $t('trials:reviewTrack:dialog:impactList')
" :visible.sync="ReReadingOrBackVisible" width="1460px" append-to-body :close-on-click-modal="false"
custom-class="base-dialog-wrapper">
<el-form ref="backReasonForm" :rules="rules" :model="backforReasonForm" class="demo-ruleForm" size="small"
label-width="180px">
<!-- 申请原因 -->
<el-divider content-position="left">
{{ $t('trials:reviewTrack:applyReread:title:backReason') }}
</el-divider>
<!-- 申请原因 -->
<el-form-item :label="$t('trials:reviewTrack:applyReread:title:backReason')" prop="pmBackReason" :rules="[
{ required: true, message: $t('common:ruleMessage:specify') },
]">
<el-input v-model="backforReasonForm.pmBackReason" style="width: 400px" type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }" :placeholder="$t('common:ruleMessage:specify')" maxlength="500"
show-word-limit />
</el-form-item>
</el-form>
<!-- 影响的任务列表 -->
<el-divider content-position="left">{{
$t('trials:reviewTrack:dialog:backImpactList')
}}</el-divider>
<div class="base-dialog-body">
<el-table v-loading="loading" :data="InfluenceTaskList" stripe height="100" style="min-height: 400px">
<!-- 任务编号 -->
@@ -752,8 +733,7 @@
</div>
<div slot="footer" class="dialog-footer" v-if="opentype === 'read'">
<!-- 取消 -->
<el-button :disabled="btnLoading" size="small" type="primary"
@click="ReReadingOrBackVisible = false, backforReasonForm = { pmBackReason: null }">
<el-button :disabled="btnLoading" size="small" type="primary" @click="ReReadingOrBackVisible = false">
{{ $t('common:button:cancel') }}
</el-button>
<!-- 确定 -->
@@ -948,9 +928,6 @@ export default {
Type: null,
RequestReReadingReason: null,
},
backforReasonForm: {
pmBackReason: null
},
rules: {
Type: [
{
@@ -966,13 +943,6 @@ export default {
trigger: 'blur',
},
],
pmBackReason: [
{
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: 'blur',
},
],
},
RefereeAllocationVisible: false,
trialId: this.$route.query.trialId,
@@ -1105,16 +1075,10 @@ export default {
this.loading = false
})
},
async PMSetTaskBack() {
try {
let validate = await this.$refs.backReasonForm.validate()
console.log(validate, 'validate')
if (!validate) return false
// let data = Object.assign({}, this.backReasonForm)
this.loading = true
let res = await PMSetTaskBack(this.trialId, this.rowData.Id, this.backforReasonForm.pmBackReason)
this.loading = false
if (res.IsSuccess) {
PMSetTaskBack() {
this.loading = true
PMSetTaskBack(this.trialId, this.rowData.Id)
.then((res) => {
this.loading = false
this.ReReadingOrBackVisible = false
this.getList()
@@ -1122,25 +1086,10 @@ export default {
this.$message.success(
this.$t('trials:reviewTrack:message:returnedSuccessfully')
)
}
} catch (err) {
this.loading = false
console.log(err)
}
// this.loading = true
// PMSetTaskBack(this.trialId, this.rowData.Id)
// .then((res) => {
// this.loading = false
// this.ReReadingOrBackVisible = false
// this.getList()
// // '退'
// this.$message.success(
// this.$t('trials:reviewTrack:message:returnedSuccessfully')
// )
// })
// .catch(() => {
// this.loading = false
// })
})
.catch(() => {
this.loading = false
})
},
openReReadingOrBackList(row) {
this.loading = true
@@ -1150,9 +1099,6 @@ export default {
.then((res) => {
this.InfluenceTaskList = res.Result
this.ReReadingOtherInfo = res.OtherInfo
this.backforReasonForm = {
pmBackReason: null
}
this.ReReadingOrBackVisible = true
this.loading = false
})
@@ -1167,7 +1113,7 @@ export default {
}
var token = getToken()
var path
if (row.ReadingTool === 0 || row.ReadingTool === 2) {
if (row.ReadingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
@@ -390,7 +390,7 @@ export default {
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.readingTaskState = this.taskInfo.ReadingTaskState
if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
if (this.taskInfo.VisitNum > 0 && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
this.rows = 1
this.cols = 2
this.activeCanvasIndex = 1
@@ -200,8 +200,7 @@ export default {
this.$refs[res.Result[idx].VisitTaskId][0].setInitActiveFile()
})
}
if (this.taskInfo.IsReadingTaskViewInOrder === 1 && res.Result.length > 1) {
//
if (this.taskInfo.IsReadingTaskViewInOrder !== 0 && res.Result.length > 1) {
const i = this.visitTaskList.findIndex(i => i.IsBaseLineTask)
if (i > -1) {
await this.getReadingImageFile(res.Result[i].VisitTaskId, i)
@@ -216,14 +215,6 @@ export default {
}
}
}
if (this.taskInfo.IsReadingTaskViewInOrder === 2) {
//
const studyList = this.visitTaskList[idx].StudyList
if (studyList.length > 0) {
const fileInfo = studyList[0].NoneDicomStudyFileList[0]
this.relatedStudyInfo = { fileInfo, visitTaskInfo: this.visitTaskList[idx], fileList: studyList[0].NoneDicomStudyFileList, fileIndex: 0, studyId: studyList[0].Id }
}
}
this.loading = false
} catch (e) {
console.log(e)
@@ -295,8 +286,8 @@ export default {
async toggleTaskByViewer(visitTaskNum) {
const i = this.visitTaskList.findIndex(v => v.VisitTaskNum === visitTaskNum)
if (i === -1) return
const visitTaskId = this.visitTaskList[i].VisitTaskId
this.setActiveTaskVisitId(visitTaskId, true)
const visistTaskId = this.visitTaskList[i].VisitTaskId
this.setActiveTaskVisitId(visistTaskId, true)
},
// 访
async setActiveTaskVisitId(id, isInitActiveFile = false) {
@@ -16,8 +16,7 @@
<!-- 级别: -->
<el-form-item :label="$t('trials:qcCfg:table:level')">
<el-select v-model="searchData.IsDefeaultViewParent" style="width:120px;">
<el-option v-for="item of $d.IsDefeaultViewParentLevel" :key="item.id" :value="item.value"
:label="item.label" />
<el-option v-for="item of $d.IsDefeaultViewParentLevel" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</el-form-item>
<el-form-item>
@@ -26,50 +25,87 @@
</el-form-item>
</el-form>
<span style="margin-left:auto">
<el-button type="primary" size="mini" :disabled="selectArr.length <= 0" @click="handleSubmit">
<el-button type="primary" size="mini" :disabled="selectArr.length<=0" @click="handleSubmit">
{{ $t('common:button:submit') }}
</el-button>
</span>
</div>
<el-table ref="qsList" :data="list" stripe size="small" height="400" @selection-change="handleSelectChange"
@select="handleselect" @select-all="handleselectAll">
<el-table
ref="qsList"
:data="list"
stripe
size="small"
height="400"
@selection-change="handleSelectChange"
@select="handleselect"
>
<el-table-column type="selection" align="left" width="45" :selectable="handleSelectTable" />
<!-- 序号 -->
<el-table-column prop="ShowOrder" :label="$t('trials:qcCfg:table:order')" width="60" />
<el-table-column
prop="ShowOrder"
:label="$t('trials:qcCfg:table:order')"
width="60"
/>
<!-- 审核问题 -->
<el-table-column prop="QuestionName" :label="$t('trials:qcCfg:table:questionName')" show-overflow-tooltip />
<el-table-column
prop="QuestionName"
:label="$t('trials:qcCfg:table:questionName')"
show-overflow-tooltip
/>
<!-- 类型 -->
<el-table-column prop="Type" :label="$t('trials:qcCfg:table:type')" show-overflow-tooltip>
<el-table-column
prop="Type"
:label="$t('trials:qcCfg:table:type')"
show-overflow-tooltip
>
<template slot-scope="scope">
{{ $fd('QcType', scope.row.Type) }}
</template>
</el-table-column>
<!-- 选项 -->
<el-table-column prop="TypeValue" :label="$t('trials:qcCfg:table:typeValue')" show-overflow-tooltip
min-width="110" />
<el-table-column
prop="TypeValue"
:label="$t('trials:qcCfg:table:typeValue')"
show-overflow-tooltip
min-width="110"
/>
<!-- 父问题 -->
<el-table-column prop="ParentShowOrder" :label="$t('trials:qcCfg:table:parentQs')" show-overflow-tooltip
width="120" />
<el-table-column
prop="ParentShowOrder"
:label="$t('trials:qcCfg:table:parentQs')"
show-overflow-tooltip
width="120"
/>
<!-- 父问题触发值 -->
<el-table-column prop="ParentTriggerValue" :label="$t('trials:qcCfg:table:parentTriggerValue')"
show-overflow-tooltip />
<el-table-column
prop="ParentTriggerValue"
:label="$t('trials:qcCfg:table:parentTriggerValue')"
show-overflow-tooltip
/>
<!-- 是否必填 -->
<el-table-column prop="IsRequired" :label="$t('trials:qcCfg:table:isRequired')" min-width="90">
<el-table-column
prop="IsRequired"
:label="$t('trials:qcCfg:table:isRequired')"
min-width="90"
>
<template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsRequired) }}
</template>
</el-table-column>
<!-- 启用状态 -->
<el-table-column prop="IsEnable" :label="$t('trials:qcCfg:table:isEnable')" min-width="120">
<el-table-column
prop="IsEnable"
:label="$t('trials:qcCfg:table:isEnable')"
min-width="120"
>
<template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsEnable) }}
</template>
</el-table-column>
</el-table>
<Pagination style="margin-top: 10px" class="page" :total="total" :page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize" @pagination="getList" />
<Pagination style="margin-top: 10px" class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
</box-content>
</template>
<script>
@@ -108,7 +144,7 @@ export default {
computed: {
...mapGetters(['language'])
},
created() {
created(){
this.trialId = this.$route.query.trialId;
this.getList();
},
@@ -129,13 +165,7 @@ export default {
}).catch(() => { this.loading = false })
},
handleSelectChange(val) {
// this.selectArr = val
},
handleselectAll(selection) {
this.selectArr = []
if (selection.length > 0) {
this.selectArr = this.list
}
this.selectArr = val
},
handleselect(selection, row) {
const selected = selection.length && selection.indexOf(row) !== -1
@@ -145,22 +175,6 @@ export default {
arr.map(item => {
this.$refs.qsList.toggleRowSelection(item, selected)
})
let list = [...selection, ...arr]
if (selected) {
list.forEach(item => {
if (!this.selectArr.find(d => d.Id === item.Id)) {
this.selectArr.push(item)
}
})
} else {
list = [row, ...arr]
list.forEach(item => {
let index = this.selectArr.indexOf(d => d.Id === item.Id)
if (!~index) {
this.selectArr.splice(index, 1)
}
})
}
},
handleSubmit() {
this.loading = true

Some files were not shown because too many files have changed in this diff Show More