115 Commits

Author SHA1 Message Date
wangxiaoshuang 474c0dca70 医学审核问题配置查询条件可清除
continuous-integration/drone/push Build encountered an error
2025-08-13 14:35:29 +08:00
wangxiaoshuang a7806d07bb 自定义标准(旧)报告数值问题默认值修改
continuous-integration/drone/push Build is passing
2025-08-12 17:55:37 +08:00
wangxiaoshuang f6e87596ee 1
continuous-integration/drone/push Build is passing
2025-08-12 17:18:55 +08:00
wangxiaoshuang d1448d4cc6 质控下载工具
continuous-integration/drone/push Build is passing
2025-08-12 14:44:52 +08:00
wangxiaoshuang bf985bcbc8 添加工具文件上传
continuous-integration/drone/push Build is passing
2025-08-12 14:26:22 +08:00
wangxiaoshuang 70db0d9258 简历部分信息修改
continuous-integration/drone/push Build is passing
2025-08-12 09:47:45 +08:00
wangxiaoshuang 8f1ab432b2 自定义表格问题数值下拉框自动计算修改
continuous-integration/drone/push Build is passing
2025-08-12 09:20:53 +08:00
wangxiaoshuang 3f0573eeb3 简历日期添加修改
continuous-integration/drone/push Build is passing
2025-08-11 16:59:53 +08:00
wangxiaoshuang 2ed051e25b 下载文件转换
continuous-integration/drone/push Build is passing
2025-08-11 16:06:48 +08:00
wangxiaoshuang dde53103f9 自定义提示信息修改
continuous-integration/drone/push Build is passing
2025-08-11 15:50:37 +08:00
wangxiaoshuang 042a5fe59b 表单必填项校验修改
continuous-integration/drone/push Build is passing
2025-08-11 15:37:09 +08:00
wangxiaoshuang 8dda50f78e 影像汇总dicom下载路径修改
continuous-integration/drone/push Build is passing
2025-08-11 13:46:40 +08:00
wangxiaoshuang 7c06c94177 1
continuous-integration/drone/push Build is passing
2025-08-08 17:34:56 +08:00
wangxiaoshuang 42652cd9ee 后处理下载处理
continuous-integration/drone/push Build is passing
2025-08-08 17:30:20 +08:00
wangxiaoshuang 2370c25ed7 质控下载修改
continuous-integration/drone/push Build is passing
2025-08-08 17:08:26 +08:00
wangxiaoshuang cdefe6d640 1
continuous-integration/drone/push Build is passing
2025-08-08 14:11:35 +08:00
wangxiaoshuang 9ef348efbf 1
continuous-integration/drone/push Build is passing
2025-08-07 17:42:39 +08:00
wangxiaoshuang 06e876619f 影像汇总新增阅片影像大小字段、导出阅片影像功能
continuous-integration/drone/push Build is passing
2025-08-07 15:51:56 +08:00
wangxiaoshuang 3334e24c66 上传影像添加字段
continuous-integration/drone/push Build is passing
2025-08-07 15:24:34 +08:00
wangxiaoshuang 9b3e169ef2 阅片单元外层问题添加配置排除访视显示
continuous-integration/drone/push Build is passing
2025-08-07 13:53:49 +08:00
wangxiaoshuang fa30c68153 阅片页面提交时自动保存
continuous-integration/drone/push Build is passing
2025-08-06 15:33:21 +08:00
wangxiaoshuang e08f094435 质控下载影像按钮不与复核状态相关联
continuous-integration/drone/push Build is passing
2025-08-06 15:05:17 +08:00
wangxiaoshuang d047df807e 1
continuous-integration/drone/push Build is passing
2025-08-06 14:18:33 +08:00
wangxiaoshuang 2c5e33903d 邮箱校验规则默认值问题
continuous-integration/drone/push Build is passing
2025-08-06 13:52:14 +08:00
wangxiaoshuang b024252f98 1
continuous-integration/drone/push Build is passing
2025-08-06 10:18:23 +08:00
wangxiaoshuang c1be3bbf4d 稽查修改
continuous-integration/drone/push Build is passing
2025-08-06 09:54:50 +08:00
wangxiaoshuang f2b07131aa 部分页面增加排序
continuous-integration/drone/push Build is passing
2025-08-05 17:17:15 +08:00
wangxiaoshuang 6c71803a11 影像指控添加导出质控问题功能
continuous-integration/drone/push Build is passing
2025-08-05 14:07:10 +08:00
wangxiaoshuang 91078abd15 影像统计小于等于0时默认赋值为0
continuous-integration/drone/push Build is passing
2025-08-05 10:34:00 +08:00
wangxiaoshuang 04f8a938c3 阅片报告预览其他访视时切换关闭问题
continuous-integration/drone/push Build is passing
2025-08-04 17:53:45 +08:00
wangxiaoshuang 2c85013008 部分问题修复
continuous-integration/drone/push Build is passing
2025-08-04 17:39:51 +08:00
wangxiaoshuang 9d839e46cd 标记保存名称未填写校验
continuous-integration/drone/push Build is passing
2025-08-04 15:10:14 +08:00
wangxiaoshuang 509f8f02b6 已阅片后阅片页面可添加临时标记
continuous-integration/drone/push Build is passing
2025-08-04 14:51:34 +08:00
wangxiaoshuang 9cc1962b3b 1
continuous-integration/drone/push Build is passing
2025-08-04 14:01:47 +08:00
wangxiaoshuang 774ab78a7c CDISC导出配置修改
continuous-integration/drone/push Build is running
2025-08-04 14:00:30 +08:00
wangxiaoshuang 16794dfe1d 医学审核问题导表
continuous-integration/drone/push Build is passing
2025-08-04 13:49:49 +08:00
wangxiaoshuang 1c69ed08cd 1
continuous-integration/drone/push Build is passing
2025-08-04 13:37:01 +08:00
wangxiaoshuang 833324e1ac 全局替换IRC规则修改
continuous-integration/drone/push Build is passing
2025-08-04 13:14:42 +08:00
wangxiaoshuang f36a00cf81 部分问题修复
continuous-integration/drone/push Build is passing
2025-08-04 11:46:52 +08:00
wangxiaoshuang 233bcbb1d0 培训文件限制只能上传pdf
continuous-integration/drone/push Build is passing
2025-08-01 17:02:55 +08:00
wangxiaoshuang b644098203 阅片导入接口修改
continuous-integration/drone/push Build is passing
2025-08-01 16:57:02 +08:00
wangxiaoshuang 424a59c4d9 质控质疑提交后刷新外部列表
continuous-integration/drone/push Build is passing
2025-08-01 16:20:36 +08:00
wangxiaoshuang a3e3db3d5b 复核任务自动跳转下一个任务功能开启
continuous-integration/drone/push Build is passing
2025-08-01 11:31:52 +08:00
wangxiaoshuang a803ee2c00 1
continuous-integration/drone/push Build is passing
2025-07-31 16:16:43 +08:00
wangxiaoshuang 5a8ec13c2f 在影像质控完成后,可以更正影像检查的基本信息,并且需要签名
continuous-integration/drone/push Build is passing
2025-07-31 16:09:44 +08:00
wangxiaoshuang d911d55129 【一致性分析】ir申请重阅一致性分析任务后,pm在重阅跟踪看到该任务的受试者编号为原始编号而不是虚拟编号
continuous-integration/drone/push Build is passing
2025-07-31 14:46:04 +08:00
wangxiaoshuang ebedae85e7 稽查附件展示
continuous-integration/drone/push Build is passing
2025-07-31 14:33:44 +08:00
wangxiaoshuang d54dfae99f 1
continuous-integration/drone/push Build is passing
2025-07-31 09:31:41 +08:00
wangxiaoshuang 00396f3c9d 问题测量时点击取消清除标记
continuous-integration/drone/push Build is passing
2025-07-30 16:02:55 +08:00
wangxiaoshuang 2138bd3345 自定义标记名称保存提示信息位置更改
continuous-integration/drone/push Build is passing
2025-07-30 15:59:45 +08:00
wangxiaoshuang 0416b1bca8 1
continuous-integration/drone/push Build is passing
2025-07-30 15:37:09 +08:00
wangxiaoshuang 6dd579e910 复核质控去除重传功能
continuous-integration/drone/push Build is passing
2025-07-30 14:26:15 +08:00
wangxiaoshuang 98dc6beba5 自定义外层问题上传报错
continuous-integration/drone/push Build is passing
2025-07-30 13:56:38 +08:00
wangxiaoshuang f7a62b2016 自定义dicom增加自由曲线工具
continuous-integration/drone/push Build is passing
2025-07-30 11:48:58 +08:00
wangxiaoshuang eb50f24204 画标记增加提示语
continuous-integration/drone/push Build is passing
2025-07-30 11:45:02 +08:00
wangxiaoshuang 3c4cce70c5 用户列表增加用户参与项目的统计数字
continuous-integration/drone/push Build is passing
2025-07-30 11:28:34 +08:00
wangxiaoshuang a566c1a0b8 重传审批新增导出功能
continuous-integration/drone/push Build is passing
2025-07-30 11:24:17 +08:00
wangxiaoshuang 3bdd567f1e Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-07-30 09:20:13 +08:00
wangxiaoshuang cbbbb227ea 1
continuous-integration/drone/push Build encountered an error
2025-07-29 17:33:18 +08:00
wangxiaoshuang 91dc08493b 项目邮件配置开放系统标准修改
continuous-integration/drone/push Build is passing
2025-07-29 14:52:00 +08:00
wangxiaoshuang bacdbd9fa1 1
continuous-integration/drone/push Build is passing
2025-07-29 14:42:45 +08:00
wangxiaoshuang 3d096f397f DICOM影像上传过程中,对于匿名字段,只有文件存在时才需要匿名,如果文件本身不存在需要匿名DICOM元素,则不需要做匿名字段
continuous-integration/drone/push Build is running
2025-07-29 14:40:43 +08:00
wangxiaoshuang 4f7a308cf1 项目邮件配置查询参数变更
continuous-integration/drone/push Build is passing
2025-07-29 12:10:15 +08:00
wangxiaoshuang bb3e3e52a5 阅片相关文件上传路径修改
continuous-integration/drone/push Build is passing
2025-07-29 11:54:22 +08:00
wangxiaoshuang f918004dda 影像上传终止状态显示位置修改
continuous-integration/drone/push Build is passing
2025-07-29 11:40:05 +08:00
wangxiaoshuang fd683d74f9 对于通过DICOM AE推送的影像支持按检查查看
continuous-integration/drone/push Build is passing
2025-07-28 14:31:50 +08:00
wangxiaoshuang d7838051e8 质控通过刷新页面
continuous-integration/drone/push Build is passing
2025-07-25 16:18:34 +08:00
wangxiaoshuang b727d6b068 1
continuous-integration/drone/push Build is passing
2025-07-25 16:04:20 +08:00
wangxiaoshuang 3b14944671 邮箱校验修改
continuous-integration/drone/push Build is passing
2025-07-25 15:55:23 +08:00
wangxiaoshuang 2b820a114b 稽查增加配置‘是否修改前展示’
continuous-integration/drone/push Build is passing
2025-07-25 15:27:27 +08:00
wangxiaoshuang 3f69434251 1
continuous-integration/drone/push Build is passing
2025-07-25 15:04:10 +08:00
wangxiaoshuang ee545589af 邮箱校验修改
continuous-integration/drone/push Build is passing
2025-07-25 14:57:18 +08:00
wangxiaoshuang feed991971 非dicom上传下载
continuous-integration/drone/push Build is passing
2025-07-25 14:52:59 +08:00
wangxiaoshuang a56b536e95 数组图片稽查校验修改
continuous-integration/drone/push Build is passing
2025-07-25 14:42:03 +08:00
wangxiaoshuang eaf856a755 【后处理上传】当阅片单元配置关闭报告页时,在阅片页的提交按钮没有校验后处理上传
continuous-integration/drone/push Build is passing
2025-07-25 11:17:40 +08:00
wangxiaoshuang 8f497ed363 Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-07-25 10:18:14 +08:00
wangxiaoshuang c33c2d6a09 【非dicom工具】更多中的工具画出的标记应该为临时标记
continuous-integration/drone/push Build is passing
2025-07-25 10:05:49 +08:00
wangxiaoshuang cc788b9833 1
continuous-integration/drone/push Build encountered an error
2025-07-24 17:48:00 +08:00
wangxiaoshuang 0aaf2f3edb tableQuestionId为空时增加判断
continuous-integration/drone/push Build encountered an error
2025-07-24 16:41:00 +08:00
wangxiaoshuang 2a80893932 1
continuous-integration/drone/push Build is passing
2025-07-24 15:58:45 +08:00
wangxiaoshuang 6a0859aaab 影像质控的自动任务需要增加开关和任务分组
continuous-integration/drone/push Build is passing
2025-07-24 15:44:55 +08:00
wangxiaoshuang 690b29c5c5 影像查看工具中,增加受试者、访视信息
continuous-integration/drone/push Build is passing
2025-07-24 15:20:13 +08:00
wangxiaoshuang 0d3cb15806 1
continuous-integration/drone/push Build is passing
2025-07-24 11:28:54 +08:00
wangxiaoshuang 4b32c290e7 复核通过时验证是否有历史质疑
continuous-integration/drone/push Build is passing
2025-07-24 09:52:20 +08:00
wangxiaoshuang 390df569c9 邮箱校验规则从后端获取
continuous-integration/drone/push Build is passing
2025-07-24 09:45:36 +08:00
wangxiaoshuang 05c6e9727f 稽查配置children上下移动
continuous-integration/drone/push Build is passing
2025-07-23 18:04:24 +08:00
wangxiaoshuang 87eac9f478 Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-07-23 17:47:05 +08:00
wangxiaoshuang ef489552ea 1
continuous-integration/drone/push Build encountered an error
2025-07-23 17:41:18 +08:00
wangxiaoshuang dd80abed02 1
continuous-integration/drone/push Build is running
2025-07-23 14:31:22 +08:00
wangxiaoshuang 6ce18843ee 稽查展示新增数组图片分类
continuous-integration/drone/push Build is running
2025-07-23 14:30:13 +08:00
wangxiaoshuang fb48b59587 稽查配置新增数组图片
continuous-integration/drone/push Build is passing
2025-07-23 14:20:10 +08:00
wangxiaoshuang ed2b75d331 稽查阅片结果token获取 2025-07-23 14:19:40 +08:00
wangxiaoshuang 0c040719b0 复核按钮添加置灰条件
continuous-integration/drone/push Build encountered an error
2025-07-23 13:48:45 +08:00
wangxiaoshuang 5dc5213202 标记问题移除绑定标记后标记变更可以保存
continuous-integration/drone/push Build is passing
2025-07-22 17:40:02 +08:00
wangxiaoshuang bdfef06b5f 复核图标变更
continuous-integration/drone/push Build encountered an error
2025-07-22 17:20:19 +08:00
wangxiaoshuang 1d009c8e18 非DICOM工具的测量工具,能否也是和DICOM的测量工具一样,选择了哪些才展示那些
continuous-integration/drone/push Build is passing
2025-07-22 16:21:12 +08:00
wangxiaoshuang c03e85ff22 复核时也可以指派
continuous-integration/drone/push Build encountered an error
2025-07-22 15:36:35 +08:00
wangxiaoshuang 0a752ed92f 非dicom阅片工具配置
continuous-integration/drone/push Build is passing
2025-07-22 14:00:54 +08:00
wangxiaoshuang eab207fc35 阅片页面表格内层问题,部分问题无法使用(截图、附件修改)
continuous-integration/drone/push Build is passing
2025-07-22 11:53:28 +08:00
wangxiaoshuang 5ef755249c 用户账号邮箱格式验证
continuous-integration/drone/push Build is passing
2025-07-21 18:00:16 +08:00
wangxiaoshuang 8da7b81235 标记问题不是数值NE的也能保存
continuous-integration/drone/push Build is passing
2025-07-21 17:40:43 +08:00
wangxiaoshuang 276d8adac0 非dicom画标记问题
continuous-integration/drone/push Build is passing
2025-07-21 17:28:28 +08:00
wangxiaoshuang 12da4c5d9f 1
continuous-integration/drone/push Build is passing
2025-07-21 17:03:00 +08:00
wangxiaoshuang 850d64f0aa tab切换问题
continuous-integration/drone/push Build is passing
2025-07-21 16:59:17 +08:00
wangxiaoshuang 541d44b4f2 标记问题不是数值NE的也能保存
continuous-integration/drone/push Build is passing
2025-07-21 16:44:45 +08:00
wangxiaoshuang a1137c0a5b 数值问题配置为可选择,数值输入框在未绑定标记时需要可手动输入保存
continuous-integration/drone/push Build is passing
2025-07-21 15:34:51 +08:00
wangxiaoshuang e2e20a24fd forrest表单问题
continuous-integration/drone/push Build is passing
2025-07-21 15:18:32 +08:00
wangxiaoshuang 2f1fcfa81d mp4文件图标更换
continuous-integration/drone/push Build is passing
2025-07-21 14:57:03 +08:00
wangxiaoshuang ba4a5c0d1d 数值问题没有绑定标记,数值输入框的提示必填,下方保存按钮无法保存
continuous-integration/drone/push Build is passing
2025-07-21 14:18:38 +08:00
wangxiaoshuang face77f949 标记删除问题
continuous-integration/drone/push Build is passing
2025-07-21 14:14:09 +08:00
wangxiaoshuang de80b75c0b 输入框与按钮的间距需要调整增加
continuous-integration/drone/push Build is passing
2025-07-21 14:09:35 +08:00
wangxiaoshuang f050df725e 圆形测量area小数位取2位
continuous-integration/drone/push Build is running
2025-07-21 14:07:01 +08:00
wangxiaoshuang 290210c27e 数值问题测量后,提示输入标记名称,点击弹窗外部弹窗会被关闭,此时标记无名称仍可以被绑定
continuous-integration/drone/push Build is running
2025-07-21 14:04:40 +08:00
wangxiaoshuang be2651501d 质控页面中检查的影像为0,检查列表没有渲染。点击DICOM影像时,会出现
continuous-integration/drone/push Build is passing
2025-07-21 13:52:08 +08:00
wangxiaoshuang 2df6c37fd0 RECIST1.1标准,在基线时,矩形工具应该是可用的
continuous-integration/drone/push Build is passing
2025-07-21 10:49:02 +08:00
109 changed files with 3485 additions and 2819 deletions
+8
View File
@@ -11,6 +11,14 @@
<meta http-equiv="Cache-control" content="no-store,no-cache,must-revalidate">
<meta http-equiv="Cache" content="no-cache">
<title><%= webpackConfig.name %></title>
<style>
.customPromptTip {
position: absolute;
left: 0;
bottom: -100px;
z-index: 99999;
}
</style>
<% if (eval(process.env.VUE_APP_LOGIN_FOR_PERMISSION)) { %>
<script>
window.zzSessionStorage = {
+7 -1
View File
@@ -281,7 +281,13 @@ export function getCommonDocumentList(param) {
data: param
})
}
export function getCommonDocument(param) {
return request({
url: `/CommonDocument/getCommonDocument`,
method: 'get',
params: param
})
}
export function addOrUpdateCommonDocument(param) {
return request({
url: `/CommonDocument/addOrUpdateCommonDocument`,
+27
View File
@@ -203,6 +203,15 @@ export function qCVisitList_Export(data) {
data
})
}
// 导出影像指控问题和答案
export function GetTrialQCQuestionAnserList_Export(data) {
return requestDownload({
url: `/ExcelExport/GetTrialQCQuestionAnserList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出下载记录
export function getTrialDownloadList_Export(data) {
return requestDownload({
@@ -273,3 +282,21 @@ export function GetEmailNoticeConfigList_Export(data) {
data
})
}
// 导出重传审批
export function GetImageBackList_Export(data) {
return requestDownload({
url: `/ExcelExport/GetImageBackList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出医学审核配置
export function GetReadingMedicineSystemQuestionList_Export(data) {
return requestDownload({
url: `/ExcelExport/GetReadingMedicineSystemQuestionList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
+11 -3
View File
@@ -45,10 +45,11 @@ export function saveImageLabelList(param) {
})
}
export function getStudyInfo(studyId) {
export function getStudyInfo(studyId, params) {
return request({
url: `/Study/item/${studyId}`,
method: 'get'
method: 'get',
params
})
}
export function getSeriesList(url) {
@@ -285,4 +286,11 @@ export function deleteSingleTableQuestionMark(param, type) {
})
}
// 阅片导入
export function readingImport(param) {
return request({
url: `/ReadingCalculate/readingImport`,
method: 'post',
data: param
})
}
+24
View File
@@ -4204,4 +4204,28 @@ export function getExportSubjectVisitImageList(data) {
method: 'post',
data
})
}
// 影像质控-更正dicom
export function updateDicomStudyInfo(data) {
return request({
url: `/Inspection/QCOperation/UpdateDicomStudyInfo`,
method: 'post',
data
})
}
// 影像质控-更正非dicom
export function updateNoneDicomStudy(data) {
return request({
url: `/Inspection/NoneDicomStudy/UpdateNoneDicomStudy`,
method: 'post',
data
})
}
// 阅片单元-获取访视计划
export function getVisitStage(data) {
return request({
url: `/VisitPlan/getVisitStage`,
method: 'post',
data
})
}
+5 -11
View File
@@ -1,15 +1,7 @@
<template>
<div
id="canvas"
ref="canvas"
v-loading="loading"
:element-loading-text="NSTip"
element-loading-background="rgba(0, 0, 0, 0.8)"
style="width:100%;height:100%;position:relative;"
class="cornerstone-element"
@contextmenu.prevent="onContextmenu"
@mouseup="sliderMouseup"
>
<div id="canvas" ref="canvas" v-loading="loading" :element-loading-text="NSTip"
element-loading-background="rgba(0, 0, 0, 0.8)" style="width:100%;height:100%;position:relative;"
class="cornerstone-element" @contextmenu.prevent="onContextmenu" @mouseup="sliderMouseup">
<div v-show="dicomInfo.series" class="info-series">
<div>Series #{{ dicomInfo.series }}</div>
<div>Image #{{ dicomInfo.frame }}</div>
@@ -47,6 +39,8 @@
</div>
<div class="info-subject">
<div v-if="series.subjectCode">{{ series.subjectCode }}</div>
<div v-if="series.visitName">{{ series.visitName }}</div>
<div>{{ stack.description }}</div>
<!-- <div>{{ dicomInfo.hospital }}</div> -->
<!-- <div v-show="dicomInfo.pid">{{ dicomInfo.pid }}</div> -->
@@ -24,8 +24,7 @@
</div>
<!--上传列表@selection-change="handleSelectionChange" @sort-change="handleSortByColumn"-->
<el-table ref="dicomFilesTable" v-adaptive="{ bottomOffset: 85 }" height="100" :data="list" :loading="loading"
class="dicomFiles-table"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
class="dicomFiles-table" :default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
<!-- <el-table-column
type="selection"
width="55"
@@ -298,24 +297,47 @@ export default {
if (data.StudyList && data.StudyList.length > 0) {
let StudyList = data.StudyList
StudyList.forEach((study) => {
if (study.StudyDIRPath) {
let obj = {
name: `${data.SubjectCode}/${data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${study.StudyCode
}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
if (this.IsReadingTaskViewInOrder === 0) {
obj = {
name: `${data.TaskBlindName}/${this.$fd(
'IsDicom',
true
)}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
}
files.push(obj)
}
if (study.SeriesList.length > 0) {
study.SeriesList.forEach((series) => {
if (series.InstancePathList.length > 0) {
series.InstancePathList.forEach((instance) => {
if (series.InstanceList.length > 0) {
series.InstanceList.forEach((instance) => {
let fileName = instance.Path.split('/').pop()
if (instance.FileName) {
fileName = instance.FileName
}
let obj = {
name: `${data.SubjectCode}/${data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${study.StudyCode
}/${fileName}`,
}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
}
if (this.IsReadingTaskViewInOrder === 0) {
obj = {
name: `${data.TaskBlindName}/${this.$fd(
'IsDicom',
true
)}/${fileName}`,
)}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
}
}
files.push(obj)
@@ -731,6 +731,8 @@ export default {
fileList: [],
dicomInfo: {
studyId: data.string('x00200010'),
DicomStudyDate: data.string('x00080020'),
DicomStudyTime: data.string('x00080030'),
studyUid: studyUid,
patientId: data.string('x00100020'),
patientName: patientNameStr,
@@ -841,6 +843,8 @@ export default {
)
seriesItem = {
seriesUid: seriesUid,
DicomSeriesDate: data.string('x00080021'),
DicomSeriesTime: data.string('x00080031'),
seriesNumber: data.intString('x00200011') || 1,
modality: data.string('x00080060') || '',
description: seriesDescriptionStr,
@@ -880,6 +884,10 @@ export default {
}
instanceItem = {
instanceUid: instanceUid,
SOPClassUID: data.string('x00080016'),
TransferSytaxUID: data.string('x00020010'),
MediaStorageSOPInstanceUID: instanceUid,
MediaStorageSOPClassUID: data.string('x00080016'),
instanceNumber: data.intString('x00200013') || 1,
frameCount: data.intString('x00280008') || 1,
instanceTime: instanceTime,
@@ -1088,6 +1096,8 @@ export default {
acquisitionNumber: dicomInfo.acquisitionNumber,
triggerTime: dicomInfo.triggerTime,
bodyPartExamined: '',
DicomStudyDate: dicomInfo.DicomStudyDate,
DicomStudyTime: dicomInfo.DicomStudyTime,
seriesList: [],
},
}
@@ -1112,6 +1122,10 @@ export default {
instanceList.push({
studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime,
@@ -1193,6 +1207,10 @@ export default {
studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid,
sopInstanceUid: o.instanceUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime,
imageRows: o.imageRows,
@@ -1238,6 +1256,8 @@ export default {
seriesInstanceUid: v.seriesUid,
seriesNumber: v.seriesNumber,
seriesTime: v.seriesTime,
DicomSeriesDate: v.DicomSeriesDate,
DicomSeriesTime: v.DicomSeriesTime,
sliceThickness: v.sliceThickness,
imagePositionPatient: v.imagePositionPatient,
imageOrientationPatient: v.imageOrientationPatient,
@@ -206,7 +206,6 @@ export default {
default: true,
},
isUpload: {
required: true,
type: Boolean,
default: false,
},
+1 -1
View File
@@ -32,7 +32,7 @@ export default {
ResetImageQualityControlQuestion: 112, // 重置影像质控问题
CreateReviewTask: 113, // 生成复核任务
ReviewImageQualityControlQuestion: 219, // 复核质控问题
CorrectImageExaminationInformation: 220, // 更正影像检查信息
},
};
</script>
+16 -1
View File
@@ -202,6 +202,7 @@ async function VueInit() {
// 获取版本信息
let PublishInfo = await getCurrentPublishInfo();
Vue.prototype.$version = PublishInfo.Result;
Vue.prototype.$companyInfo = PublishInfo.OtherInfo;
// 获取检查部位
Vue.prototype.$getBodyPart = (id) => {
return new Promise(async (resolve, reject) => {
@@ -275,6 +276,20 @@ async function VueInit() {
}
return companyName;
}
Vue.prototype.$reg = () => {
if (localStorage.getItem('CompanyInfo')) {
let { EmailRegexStr } = JSON.parse(localStorage.getItem('CompanyInfo'))
if (EmailRegexStr) {
return { EmailRegexStr }
}
} else if (Vue.prototype.$companyInfo) {
let { EmailRegexStr } = Vue.prototype.$companyInfo
if (EmailRegexStr) {
return { EmailRegexStr }
}
}
return { EmailRegexStr: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$' };
}
Vue.prototype.$updateDictionary = function () {
Vue.prototype.$d = function (code) {
var dictInfo = res.Result
@@ -316,7 +331,7 @@ async function VueInit() {
})
}
let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo'))
if (CompanyInfo && CompanyInfo.SystemShortName) {
if (CompanyInfo && CompanyInfo.SystemShortName && text.toUpperCase() !== "CIRCLE") {
let test = new RegExp('IRC', 'ig')
text = text.replace(test, CompanyInfo.SystemShortName)
}
+5 -3
View File
@@ -15,6 +15,7 @@ export const anonymization = function (file, config) {
let dataset = dcmjs.data.DicomMessage.readFile(buffer)
for (var i = 0; i < AnonymizeFixedList.length; i++) {
let AnonymizeFixed = AnonymizeFixedList[i]
if (!dataset.dict.hasOwnProperty(`${AnonymizeFixed.Group + AnonymizeFixed.Element}`)) continue
if (dataset.dict[AnonymizeFixed.Group + AnonymizeFixed.Element]) {
dataset.dict[AnonymizeFixed.Group + AnonymizeFixed.Element].Value[0] = AnonymizeFixed.ReplaceValue
} else {
@@ -28,6 +29,7 @@ export const anonymization = function (file, config) {
}
for (var i = 0; i < AnonymizeNotFixedList.length; i++) {
let AnonymizeNotFixed = AnonymizeNotFixedList[i]
// if (!dataset.dict.hasOwnProperty(`${AnonymizeNotFixed.Group + AnonymizeNotFixed.Element}`)) continue
if (AnonymizeNotFixed.Group + AnonymizeNotFixed.Element === '00100020') {
console.log(`${DicomStoreInfo.TrialCode}_${DicomStoreInfo.SubjectCode}`)
if (dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element]) {
@@ -42,7 +44,7 @@ export const anonymization = function (file, config) {
}
} else {
if (dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element]) {
dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element].Value[0] = DicomStoreInfo[AnonymizeNotFixed.ReplaceValue] ? DicomStoreInfo[AnonymizeNotFixed.ReplaceValue].toString() : ''
dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element].Value[0] = DicomStoreInfo[AnonymizeNotFixed.ReplaceValue] || Number(DicomStoreInfo[AnonymizeNotFixed.ReplaceValue]) === 0 ? DicomStoreInfo[AnonymizeNotFixed.ReplaceValue].toString() : ''
} else {
dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element] = {
vr: AnonymizeNotFixed.ValueRepresentation,
@@ -53,9 +55,9 @@ export const anonymization = function (file, config) {
}
}
}
// console.log(dataset)
try {
let newDicomFile = dataset.write()
let newDicomFile = dataset.write() // fragmentMultiframe 原始数据是否进行分割
const bufferArray = new Uint8Array(newDicomFile)
const blob = new Blob([bufferArray], { type: 'application/octet-stream' })
resolve({ blob, pixelDataElement })
+23 -1
View File
@@ -1,6 +1,7 @@
import streamSaver from "streamsaver";
import "streamsaver/examples/zip-stream.js";
import store from '@/store'
import dcmjs from './dcmUpload/dcmjs'
streamSaver.mitm = `${window.location.origin}/mitm.html?version=2.0.0`
// 下载文件并压缩
function zipFiles(zipName, files) {
@@ -19,7 +20,10 @@ function zipFiles(zipName, files) {
if (fileInfo.done) {//迭代终止
ctrl.close();
} else {
let { name, url } = fileInfo.value;
let { name, url, IsEncapsulated = false } = fileInfo.value;
if (IsEncapsulated) {
url = await downloadFileToUrl(url)
}
// url = decodeUtf8(url); // 待定,可能做过特殊处理
return fetch(url).then(res => {
ctrl.enqueue({
@@ -99,6 +103,24 @@ function decodeUtf8(bytes) {
str2.pop();
return str2.join("/") + '/' + name;
}
// 下载文件进行修改并输出本地url
function downloadFileToUrl(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
const arraybuffer = xhr.response;
let dataset = dcmjs.data.DicomMessage.readFile(arraybuffer)
let newDicomFile = dataset.write({ fragmentMultiframe: false }) // fragmentMultiframe 原始数据是否进行分割
const bufferArray = new Uint8Array(newDicomFile)
const blob = new Blob([bufferArray], { type: 'application/octet-stream' })
const href = URL.createObjectURL(blob)
resolve(href)
};
xhr.send();
})
}
export async function downLoadFile(file, name, type = 'file') {
if (type === 'zip') return await zipFiles(name, file);
return await updateFile(file, name)
+2 -1
View File
@@ -179,7 +179,8 @@ export default {
trigger: 'blur',
},
{
type: 'email',
// type: 'email',
pattern: new RegExp(this.$reg().EmailRegexStr),
message: 'Please input the correct email address',
trigger: ['blur'],
},
+31 -8
View File
@@ -194,7 +194,8 @@ export default {
currentLoadIns: [],
isFromCRCUpload: false,
isReading: null,
activeSeriesId: null
activeSeriesId: null,
isPacs: false
}
},
created: function () {
@@ -211,6 +212,9 @@ export default {
if (this.$router.currentRoute.query.isReading) {
this.isReading = this.$router.currentRoute.query.isReading
}
if (this.$router.currentRoute.query.isPacs) {
this.isPacs = Boolean(this.$router.currentRoute.query.isPacs)
}
this.studyId = this.$router.currentRoute.query.studyId
this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload
if (this.type === 'Series') {
@@ -241,7 +245,11 @@ export default {
},
methods: {
async loadStudy() {
const data = await getStudyInfo(this.studyId)
let params = {}
if (this.isPacs) {
params.IsPacs = true
}
const data = await getStudyInfo(this.studyId, params)
if (data.IsSuccess) {
if (data.Result) {
this.studyCode = data.Result.StudyCode
@@ -250,6 +258,11 @@ export default {
this.description = data.Result.Description
}
let isReading = !!this.isReading ? `?IsReading=true` : ''
if (isReading && this.isPacs) {
isReading += `&IsPacs=true`
} else if (!isReading && this.isPacs) {
isReading = `?IsPacs=true`
}
const url = `/series/list/${this.studyId}${isReading}`
this.getSeriesList(url)
}
@@ -300,7 +313,9 @@ export default {
loadStatus: false,
imageloadedArr: [],
isExistMutiFrames: item.IsExistMutiFrames,
isShowPopper: false
isShowPopper: false,
subjectCode: item.SubjectCode,
visitName: item.VisitName
})
})
this.seriesList = seriesList
@@ -360,7 +375,9 @@ export default {
loadStatus: false,
imageloadedArr: [],
isExistMutiFrames: item.IsExistMutiFrames,
isShowPopper: false
isShowPopper: false,
subjectCode: item.SubjectCode,
visitName: item.VisitName
})
})
this.seriesList = seriesList
@@ -430,7 +447,9 @@ export default {
loadStatus: false,
imageloadedArr: [],
isExistMutiFrames: isExistMutiFrames,
isShowPopper: false
isShowPopper: false,
subjectCode: res.OtherInfo.SubjectCode,
visitName: res.OtherInfo.VisitName
})
this.seriesList = seriesList
if (this.seriesList.length > 0) {
@@ -516,7 +535,9 @@ export default {
isReading: series.isReading,
isDeleted: series.isDeleted,
previewImageUrl: series.previewImageUrl,
instanceCount: series.instanceCount
instanceCount: series.instanceCount,
subjectCode: series.SubjectCode,
visitName: series.VisitName
}
this.$refs.dicomViewer.loadImageStack(seriesInfo)
if (!series.loadStatus) {
@@ -582,7 +603,9 @@ export default {
keySeries: seriesInfo.KeySeries,
loadStatus: false,
imageloadedArr: [],
isShowPopper: false
isShowPopper: false,
subjectCode: seriesInfo.SubjectCode,
visitName: seriesInfo.VisitName
})
this.seriesList = seriesList
if (this.seriesList.length > 0) {
@@ -861,7 +884,7 @@ export default {
let file = this.seriesList[seriesIndex].instanceInfoList.find(item => item.ImageId === imageId)
if (file && this.activeSeriesId === this.seriesList[seriesIndex].seriesId) {
getNetWorkSpeed()
setNetWorkSpeedSize(percentComplete, e.detail.total, imageId)
setNetWorkSpeedSize(percentComplete, e.detail.total, imageId)
}
if (prefetchInstanceCount >= instanceCount * 100) {
this.seriesList[seriesIndex].prefetchInstanceCount = instanceCount * 100
+9 -3
View File
@@ -417,7 +417,9 @@ export default {
loadStatus: false,
imageloadedArr: [],
isExistMutiFrames: series.IsExistMutiFrames,
isShowPopper: false
isShowPopper: false,
subjectCode: series.SubjectCode,
visitName: series.VisitName
})
})
data.SeriesList = seriesList
@@ -518,7 +520,9 @@ export default {
isReading: series.isReading,
isDeleted: series.isDeleted,
previewImageUrl: series.previewImageUrl,
instanceCount: series.instanceCount
instanceCount: series.instanceCount,
subjectCode: series.SubjectCode,
visitName: series.VisitName
}
this.$refs.dicomViewer.loadImageStack(seriesInfo)
if (!series.loadStatus) {
@@ -792,7 +796,9 @@ export default {
loadStatus: false,
imageloadedArr: [],
isExistMutiFrames: item.IsExistMutiFrames,
isShowPopper: false
isShowPopper: false,
subjectCode: item.SubjectCode,
visitName: item.VisitName
})
})
// scope.relationStudyList[index].seriesCount = seriesList.length
@@ -70,7 +70,7 @@ 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 mp4 from '@/assets/file_icon/xlsx.png'
import mp4 from '@/assets/file_icon/mp4.png'
import PreviewFile from '@/components/PreviewFile'
import imageViewer from './image-viewer'
import { getSystemDocumentAttachmentList } from '@/api/dictionary'
@@ -0,0 +1,269 @@
<template>
<el-form ref="sysTemplateFrom" v-loading="loading" :model="form" label-width="140px" size="small" :rules="rules"
class="upload-temporary-file">
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:attachment:label:code')" prop="Code">
<el-input v-model="form.Code" />
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:businessScenario')" prop="BusinessScenarioEnum">
<el-select v-model="form.BusinessScenarioEnum" style="width: 100%" size="small" filterable>
<el-option v-for="item of $d.Common_File_BusinessScenario" :key="item.id" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:file')">
<div class="upload-container">
<el-upload class="upload-demo" action accept="" :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.FileTypeEnum && form.FileTypeEnum !== 0)">
<el-button size="small" type="primary" :disabled="(!form.FileTypeEnum && form.FileTypeEnum !== 0)"
:loading="btnLoading">Select</el-button>
<!-- <span slot="tip" style="margin-left: 10px" class="el-upload__tip">
(must be in xlsx/xls/doc/docx format)
</span> -->
</el-upload>
</div>
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:name')" prop="Name">
<el-input v-model="form.Name" />
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:export:form:nameCN')" prop="NameCN">
<el-input v-model="form.NameCN" />
</el-form-item>
<el-form-item v-if="form.Id !== ''" :label="$t('dictionary:attachment:label:isDeleted')">
<el-radio-group v-model="form.IsDeleted">
<el-radio v-for="item of $d.YesOrNo" :label="item.value" :key="item.id">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:description')">
<el-input v-model="form.Description" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" />
</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.FileTypeEnum && form.FileTypeEnum !== 0)"
:loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save') }}</el-button>
</el-form-item>
</div>
</el-form>
</template>
<script>
import {
addOrUpdateCommonDocument,
uploadCommonDoc,
Upload,
} from '@/api/dictionary'
import { getBasicDataSelects } from '@/api/dictionary/dictionary'
export default {
name: 'TemplateForm',
props: {
data: {
type: Object,
default() {
return {}
},
},
},
data() {
return {
form: {
Id: '',
Code: '',
FileTypeEnum: 0,
BusinessScenarioEnum: null,
Name: '',
NameCN: '',
Path: '',
Description: '',
IsDeleted: false,
},
rules: {
Code: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
Name: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
NameCN: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
BusinessScenarioEnum: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
},
fileList: [],
btnLoading: false,
saveBtnLoading: false,
loading: false,
dictionaryList: {},
}
},
mounted() {
this.initForm()
},
methods: {
async initForm() {
await this.getDicData()
if (Object.keys(this.data).length > 0) {
if (this.data.Path) {
this.fileList = [
{
name: this.data.Name,
path: this.data.Path,
url: this.data.Path,
type: this.data.Type,
},
]
}
for (const k in this.form) {
if (this.data.hasOwnProperty(k)) {
this.form[k] = this.data[k]
}
}
}
},
//
getDicData() {
this.loading = true
getBasicDataSelects(['Common_File_ModuleType', 'Common_File_Type'])
.then((res) => {
this.dictionaryList = { ...res.Result }
this.loading = false
})
.catch(() => {
this.loading = false
})
},
beforeUpload(file) {
//
if (this.checkFileSuffix(file.name)) {
this.fileList = []
return true
} else {
this.$alert(this.$t('dictionary:attachment:export:alert:formatFile'))
return false
}
},
async handleUploadFile(param) {
this.loading = true
this.form.FileName = param.file.name
let extendName = param.file.name
.substring(param.file.name.lastIndexOf('.'))
.toLocaleLowerCase()
let file = await this.fileToBlob(param.file)
let res = await this.OSSclient.put(`/System/Tools/${this.$guid()}${extendName}`, file)
this.form.Path = this.$getObjectName(res.url)
this.form.NameCN = param.file.name
this.fileList.push({
name: param.file.name,
path: this.form.Path,
fullPath: this.form.Path,
url: this.form.Path,
})
this.loading = false
this.btnLoading = false
// Upload(formData, 1).then((res) => {
// this.fileList.push({
// name: param.file.name,
// path: res.Result.FilePath,
// fullPath: res.Result.FullFilePath,
// url: res.Result.FilePath,
// })
// })
},
fileToBlob(file) {
// FileReader
const reader = new FileReader()
return new Promise((resolve) => {
// FileReader load
reader.addEventListener('load', (e) => {
let blob
if (typeof e.target.result === 'object') {
blob = new Blob([e.target.result])
} else {
blob = e.target.result
}
resolve(blob)
})
// FileReader ArrayBuffer File
reader.readAsArrayBuffer(file)
})
},
handleSave() {
this.$refs.sysTemplateFrom.validate((valid) => {
if (!valid) return
if (!this.form.Name) {
this.$alert(this.$t('dictionary:attachment:message:msg1'))
return
}
this.saveBtnLoading = true
addOrUpdateCommonDocument(this.form)
.then((res) => {
this.saveBtnLoading = false
this.$emit('closeDialog')
this.$emit('getList')
this.$message.success(this.$t('common:message:savedSuccessfully'))
})
.catch(() => {
this.saveBtnLoading = false
})
})
},
handleRemoveFile() {
this.fileList = []
this.form.Path = ''
this.form.NameCN = ''
this.form.Name = ''
},
handlePreview(file) {
if (file.fullPath) {
window.open(file.fullPath, '_blank')
}
},
handleExceed(files, fileList) {
this.$message.warning(this.$t('upload:rule:maxFile1'))
},
checkFileSuffix(fileName) {
return true
var typeArr = ['xls', 'xlsx', 'doc', 'docx']
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>
@@ -0,0 +1,238 @@
<template>
<BaseContainer>
<template slot="search-container">
<el-form :inline="true" size="small">
<!-- 业务场景 -->
<el-form-item :label="$t('dictionary:attachment:label:businessScenario')">
<el-select v-model="searchData.BusinessScenarioEnum" style="width: 150px">
<el-option v-for="item of $d.Common_File_BusinessScenario" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<!-- 文件名称 -->
<el-form-item :label="$t('dictionary:attachment:label:name')">
<el-input v-model="searchData.Name" style="width: 130px" clearable />
</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">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
<el-button type="primary" style="float: right" size="small" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
</el-form>
</template>
<template slot="main-container">
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" stripe height="100"
@sort-change="handleSortChange">
<el-table-column type="index" width="40" />
<el-table-column prop="Code" :label="$t('dictionary:attachment:label:code')" show-overflow-tooltip
sortable="custom" />
<!-- 业务场景 -->
<el-table-column prop="BusinessScenarioEnum" :label="$t('dictionary:attachment:label:businessScenario')"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
{{
$fd(
'Common_File_BusinessScenario',
scope.row.BusinessScenarioEnum
)
}}
</template>
</el-table-column>
<!-- 文件名称 -->
<el-table-column prop="Name" :label="$t('dictionary:attachment:label:name')" show-overflow-tooltip
sortable="custom" />
<el-table-column prop="NameCN" :label="$t('dictionary:attachment:upload:table:nameCN')" show-overflow-tooltip
sortable="custom" />
<!-- 描述 -->
<el-table-column prop="Description" :label="$t('dictionary:attachment:label:description')"
show-overflow-tooltip />
<!-- 是否废除 -->
<el-table-column prop="IsDeleted" :label="$t('dictionary:attachment:label:isDeleted')" show-overflow-tooltip
sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
$fd('YesOrNo', scope.row.IsDeleted)
}}</el-tag>
<el-tag v-else type="primary">{{
$fd('YesOrNo', scope.row.IsDeleted)
}}</el-tag>
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column prop="UpdateTime" :label="$t('dictionary:attachment:label:updateTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('common:action:action')" width="300">
<template slot-scope="scope">
<!-- <el-button type="text" @click="PreviewFile(scope.row)">
{{ $t('common:button:preview') }}
</el-button> -->
<el-button type="text" @click="handleDownload(scope.row)">
{{ $t('common:button:download') }}
</el-button>
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('common:button:edit') }}
</el-button>
<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" />
<!-- 新增/编辑 -->
<el-dialog v-if="editDialog.visible" :visible.sync="editDialog.visible" :close-on-click-modal="false"
:title="editDialog.title" width="600px" custom-class="base-dialog-wrapper">
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
</el-dialog>
</template>
</BaseContainer>
</template>
<script>
import {
getCommonDocumentList,
DownloadCommonDoc,
deleteCommonDocument,
} from '@/api/dictionary'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import TemplateForm from './TemplateForm'
import { downLoadFile } from '@/utils/stream.js'
const FileTypeEnum = 0
const searchDataDefault = () => {
return {
FileTypeEnum: FileTypeEnum,
BusinessScenarioEnum: null,
Name: '',
PageIndex: 1,
PageSize: 20,
}
}
export default {
name: 'ToolsTemplate',
components: { BaseContainer, Pagination, TemplateForm },
data() {
return {
searchData: searchDataDefault(),
list: [],
total: 0,
currentRow: {},
editDialog: { title: '', visible: false },
loading: false,
}
},
mounted() {
this.getList()
},
computed: {
isEN() {
return this.$i18n.locale !== 'zh'
},
},
methods: {
handleDelete(row) {
//
this.$confirm(this.$t('dictionary:attachment:message:msg1')).then(() => {
deleteCommonDocument(row.Id).then(() => {
this.$message.success(this.$t('common:message:deletedSuccessfully'))
this.getList()
})
}).catch(() => { })
},
PreviewFile(row) {
let basePath = window.location.origin
if (window.location.protocol !== 'https:') {
basePath = 'https://irc.test.extimaging.com'
}
let data = {
name: row.NameCN,
path: basePath + row.Path,
}
this.$emit('PreviewFile', data)
},
getList() {
this.loading = true
getCommonDocumentList(this.searchData)
.then((res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
})
.catch(() => {
this.loading = false
})
},
//
handleAdd() {
this.editDialog.title = this.$t('common:button:new')
this.currentRow = { FileTypeEnum: FileTypeEnum }
this.editDialog.visible = true
},
//
async handleDownload(row) {
try {
this.loading = true
let fileName = this.isEN ? row.Name : row.NameCN;
let type = fileName
.substring(fileName.lastIndexOf('.'))
.toLocaleLowerCase()
if (!type) {
let extendName = row.Path
.substring(row.Path.lastIndexOf('.'))
.toLocaleLowerCase()
fileName += extendName
}
let res = await downLoadFile(this.OSSclientConfig.basePath + row.Path, fileName)
this.loading = false
} catch (err) {
this.loading = false
}
},
//
handleEdit(row) {
this.editDialog.title = this.$t('common:button:edit')
this.currentRow = { ...row }
this.editDialog.visible = true
},
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
handleReset() {
this.searchData = searchDataDefault()
this.getList()
},
closeDialog() {
this.editDialog.visible = false
},
//
handleSortChange(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>
::v-deep .search {
display: block;
}
</style>
+16 -42
View File
@@ -1,52 +1,22 @@
<template>
<div class="attachment-wrapper">
<el-tabs v-model="activeTab" @tab-click="clickTab">
<el-tab-pane
v-for="item in $d.Common_File_Type"
:key="item.value"
:label="item.label"
:name="String(item.value)"
>
<UploadTemplate
v-if="activeTab === '1' && item.value == activeTab"
@PreviewFile="PreviewFile"
/>
<ExportTemplate
v-if="activeTab === '2' && item.value == activeTab"
@PreviewFile="PreviewFile"
/>
<el-tab-pane v-for="item in $d.Common_File_Type" :key="item.value" :label="item.label" :name="String(item.value)">
<UploadTemplate v-if="activeTab === '1' && item.value == activeTab" @PreviewFile="PreviewFile" />
<ExportTemplate v-if="activeTab === '2' && item.value == activeTab" @PreviewFile="PreviewFile" />
<EmailTemplate v-if="activeTab === '3' && item.value == activeTab" />
<CommonTemplate v-if="activeTab === '4' && item.value == activeTab" />
<SignatureTemplate
v-if="activeTab === '5' && item.value == activeTab"
/>
<SignatureTemplate v-if="activeTab === '5' && item.value == activeTab" />
<ToolsTemplate v-if="activeTab === '0' && item.value == activeTab" />
</el-tab-pane>
</el-tabs>
<!-- 预览 -->
<el-dialog
v-if="Preview.visible"
:visible.sync="Preview.visible"
:close-on-click-modal="false"
:fullscreen="true"
:title="Preview.title"
width="600px"
custom-class="base-dialog-wrapper"
>
<vue-office-docx
v-if="docxTypes.includes(Preview.type)"
:src="Preview.path"
style="height: calc(100vh - 70px)"
@rendered="renderedHandler"
@error="errorHandler"
/>
<vue-office-excel
v-else-if="excelTypes.includes(Preview.type)"
:src="Preview.path"
:options="options"
style="height: calc(100vh - 70px)"
@rendered="renderedHandler"
@error="errorHandler"
/>
<el-dialog v-if="Preview.visible" :visible.sync="Preview.visible" :close-on-click-modal="false" :fullscreen="true"
:title="Preview.title" width="600px" custom-class="base-dialog-wrapper">
<vue-office-docx v-if="docxTypes.includes(Preview.type)" :src="Preview.path" style="height: calc(100vh - 70px)"
@rendered="renderedHandler" @error="errorHandler" />
<vue-office-excel v-else-if="excelTypes.includes(Preview.type)" :src="Preview.path" :options="options"
style="height: calc(100vh - 70px)" @rendered="renderedHandler" @error="errorHandler" />
<PreviewFile v-else :file-path="Preview.path" :file-type="Preview.type" />
</el-dialog>
</div>
@@ -57,6 +27,7 @@ import ExportTemplate from './components/ExportTemplate'
import EmailTemplate from './components/EmailTemplate'
import CommonTemplate from './components/CommonTemplate'
import SignatureTemplate from './components/SignatureTemplate'
import ToolsTemplate from './components/ToolsTemplate'
import VueOfficeDocx from '@vue-office/docx'
import '@vue-office/docx/lib/index.css'
import VueOfficeExcel from '@vue-office/excel'
@@ -73,6 +44,7 @@ export default {
VueOfficeDocx,
VueOfficeExcel,
PreviewFile,
ToolsTemplate
},
data() {
return {
@@ -142,16 +114,18 @@ export default {
display: flex;
flex-direction: column;
}
.el-tabs__header {
height: 40px;
margin-bottom: 5px;
}
.el-tabs__content {
flex: 1;
.el-tab-pane {
height: 100%;
}
}
}
</style>
File diff suppressed because it is too large Load Diff
@@ -43,6 +43,7 @@
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="60" />
<!-- Group -->
@@ -50,6 +51,7 @@
prop="Group"
:label="$t('template:anonymization:label:group')"
show-overflow-tooltip
sortable="custom"
/>
<!-- Element -->
<el-table-column
@@ -57,24 +59,28 @@
:label="$t('template:anonymization:label:element')"
show-overflow-tooltip
min-width="110"
sortable="custom"
/>
<!-- Tag Description -->
<el-table-column
prop="TagDescription"
:label="$t('template:anonymization:label:tagDescription')"
min-width="110"
sortable="custom"
/>
<!-- Tag DescriptionCN -->
<el-table-column
prop="TagDescriptionCN"
:label="$t('template:anonymization:label:tagDescriptionCN')"
min-width="110"
sortable="custom"
/>
<!-- Value Representation -->
<el-table-column
prop="ValueRepresentation"
:label="$t('template:anonymization:label:valueRepresentation')"
min-width="110"
sortable="custom"
/>
<!-- Is Fixed -->
<el-table-column :label="$t('template:anonymization:label:isFixed')" width="100">
@@ -92,6 +98,7 @@
prop="ReplaceValue"
:label="$t('template:anonymization:label:valueReplace')"
min-width="110"
sortable="custom"
/>
<!-- Is Enable -->
<el-table-column :label="$t('template:anonymization:label:isEnable')" width="100" fixed="right">
@@ -139,7 +146,9 @@ const searchDataDefault = () => {
IsAdd: false,
TagDescriptionCN: '',
PageIndex: 1,
PageSize: 500
PageSize: 500,
Asc: false,
SortField: ''
}
}
export default {
@@ -159,6 +168,17 @@ export default {
this.getList()
},
methods: {
//
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()
},
switchChange(event, item) {
this.loading = true
addOrUpdateSystemAnonymization(item).then(res => {
@@ -43,6 +43,7 @@
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="60" />
<!-- Group -->
@@ -50,6 +51,7 @@
prop="Group"
:label="$t('template:anonymization:label:group')"
show-overflow-tooltip
sortable="custom"
/>
<!-- Element -->
<el-table-column
@@ -57,24 +59,28 @@
:label="$t('template:anonymization:label:element')"
show-overflow-tooltip
min-width="110"
sortable="custom"
/>
<!-- Tag Description -->
<el-table-column
prop="TagDescription"
:label="$t('template:anonymization:label:tagDescription')"
min-width="110"
sortable="custom"
/>
<!-- Tag DescriptionCN -->
<el-table-column
prop="TagDescriptionCN"
:label="$t('template:anonymization:label:tagDescriptionCN')"
min-width="110"
sortable="custom"
/>
<!-- Value Representation -->
<el-table-column
prop="ValueRepresentation"
:label="$t('template:anonymization:label:valueRepresentation')"
min-width="110"
sortable="custom"
/>
<!-- Is Fixed -->
<el-table-column :label="$t('template:anonymization:label:isFixed')" width="100">
@@ -92,6 +98,7 @@
prop="ReplaceValue"
:label="$t('template:anonymization:label:valueReplace')"
min-width="110"
sortable="custom"
/>
<!-- Is Enable -->
<el-table-column :label="$t('template:anonymization:label:isEnable')" width="100" fixed="right">
@@ -138,7 +145,9 @@ const searchDataDefault = () => {
TagDescriptionCN: '',
IsAdd: true,
PageIndex: 1,
PageSize: 500
PageSize: 500,
Asc: false,
SortField: ''
}
}
export default {
@@ -158,6 +167,17 @@ export default {
this.getList()
},
methods: {
//
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()
},
switchChange(event, item) {
this.loading = true
addOrUpdateSystemAnonymization(item).then(res => {
@@ -30,13 +30,13 @@
<el-form-item
:label="$t('trials:auditRecord:table:criterion')"
>
<el-select v-model="searchData.CriterionTypeEnum">
<el-select v-model="searchData.CriterionTypeEnum" clearable>
<el-option v-for="item of $d.CriterionType" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</el-form-item>
<!-- 是否通用 -->
<el-form-item :label="$t('dictionary:medicalAudit:label:IsGeneral')">
<el-select v-model="searchData.IsGeneral">
<el-select v-model="searchData.IsGeneral" clearable>
<el-option v-for="item of $d.YesOrNo" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</el-form-item>
@@ -51,6 +51,9 @@
>
{{ $t('common:button:reset') }}
</el-button>
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
</el-form-item>
</el-form>
<span style="margin-left:auto">
@@ -66,6 +69,7 @@
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<!-- 序号 -->
<el-table-column
@@ -79,6 +83,7 @@
:label="$t('trials:MIMqcCfg:table:questionName')"
show-overflow-tooltip
min-width="140"
sortable="custom"
/>
<!-- 审核问题 -->
<el-table-column
@@ -86,6 +91,7 @@
:label="$t('common:title:languageType')"
show-overflow-tooltip
min-width="160"
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('LanguageType', scope.row.LanguageType) }}
@@ -97,6 +103,7 @@
:label="$t('trials:qcCfg:table:type')"
show-overflow-tooltip
min-width="140"
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('QcType', scope.row.Type) }}
@@ -108,6 +115,7 @@
:label="$t('trials:qcCfg:table:typeValue')"
show-overflow-tooltip
min-width="140"
sortable="custom"
/>
<!-- 任务类型 -->
<el-table-column
@@ -115,6 +123,7 @@
:label="$t('trials:medicalFeedbackCfg:title:taskType')"
show-overflow-tooltip
min-width="140"
sortable="custom"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.ReadingCategory === 1" type="primary">
@@ -136,6 +145,7 @@
:label="$t('trials:auditRecord:table:criterion')"
min-width="160"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<div>
@@ -148,6 +158,7 @@
:label="$t('dictionary:medicalAudit:label:IsGeneral')"
min-width="120"
show-overflow-tooltip
sortable="custom"
>
<template slot-scope="scope">
<div>
@@ -161,6 +172,7 @@
:label="$t('trials:qcCfg:table:parentQs')"
show-overflow-tooltip
min-width="140"
sortable="custom"
/>
<!-- 父问题触发值 -->
<el-table-column
@@ -168,12 +180,14 @@
:label="$t('trials:qcCfg:table:parentTriggerValue')"
show-overflow-tooltip
min-width="160"
sortable="custom"
/>
<!-- 是否必填 -->
<el-table-column
prop="IsRequired"
:label="$t('trials:qcCfg:table:isRequired')"
min-width="120"
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsRequired) }}
@@ -184,6 +198,7 @@
prop="IsEnable"
:label="$t('trials:qcCfg:table:isEnable')"
min-width="120"
sortable="custom"
>
<template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsEnable) }}
@@ -215,7 +230,7 @@
</template>
<script>
import { getReadingMedicineSystemQuestionList, deleteReadingMedicineSystemQuestion } from '@/api/dictionary'
import { GetReadingMedicineSystemQuestionList_Export } from '@/api/export'
import BoxContent from '@/components/BoxContent'
import Pagination from '@/components/Pagination'
import MedicalAuditForm from './MedicalAuditForm'
@@ -228,7 +243,9 @@ const searchDataDefault = () => {
LanguageType: null,
Type: '',
CriterionTypeEnum: null,
IsGeneral: null
IsGeneral: null,
Asc: false,
SortField: ''
}
}
export default {
@@ -248,6 +265,20 @@ export default {
this.getList()
},
methods: {
async handleExport() {
await GetReadingMedicineSystemQuestionList_Export(this.searchData)
},
//
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()
},
//
getList() {
this.loading = true
+8
View File
@@ -164,6 +164,14 @@ export default {
},
},
],
Email: [
{
// type: 'email',
pattern: new RegExp(this.$reg().EmailRegexStr),
message: this.$t('rules:email'),
trigger: 'blur,change',
},
]
},
userId: null,
loading: false,
+3
View File
@@ -125,6 +125,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.EmailOrPhone && reg.test(this.form.EmailOrPhone)) {
this.sendDisabled = false
callback()
@@ -172,6 +172,13 @@ export default {
],
Phone: [
{ required: true, validator: checkPhone, trigger: 'blur' }
],
Email: [
{
pattern: new RegExp(this.$reg().EmailRegexStr),
message: 'Please input the correct email address',
trigger: 'blur,change',
}
]
},
siteOptions: [],
@@ -117,6 +117,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.Email && reg.test(this.form.Email)) {
this.sendDisabled = false
callback()
@@ -136,6 +136,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.Email && reg.test(this.form.Email)) {
this.sendDisabled = false
callback()
+6
View File
@@ -158,6 +158,9 @@ export default {
callback(new Error(this.$t('trials:researchForm:formRule:specify')))
} else {
var reg = /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.EmailOrPhone && reg.test(this.form.EmailOrPhone)) {
callback()
} else {
@@ -170,6 +173,9 @@ export default {
callback(new Error(this.$t('trials:researchForm:formRule:specify')))
} else {
var reg = /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.ReplaceUserEmailOrPhone && reg.test(this.form.ReplaceUserEmailOrPhone)) {
callback()
} else {
+8 -1
View File
@@ -49,7 +49,7 @@
<el-input v-model="form.Phone" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
</el-form-item>
<!-- 联系邮箱 -->
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')">
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')" prop="Email">
<el-input v-model="form.Email" disabled />
</el-form-item>
@@ -183,6 +183,13 @@ export default {
],
Phone: [
{ required: true, validator: checkPhone, trigger: 'blur' }
],
Email: [
{
pattern: new RegExp(this.$reg().EmailRegexStr),
message: 'Please input the correct email address',
trigger: 'blur,change',
}
]
},
siteOptions: [],
@@ -108,6 +108,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.Email && reg.test(this.form.Email)) {
this.sendDisabled = false
callback()
@@ -139,6 +139,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.Email && reg.test(this.form.Email)) {
this.sendDisabled = false
callback()
+6
View File
@@ -131,6 +131,9 @@ export default {
callback(new Error(this.$t('trials:researchForm:formRule:specify')))
} else {
var reg = /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.EmailOrPhone && reg.test(this.form.EmailOrPhone)) {
// this.sendDisabled = false
callback()
@@ -145,6 +148,9 @@ export default {
callback(new Error(this.$t('trials:researchForm:formRule:specify')))
} else {
var reg = /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.ReplaceUserEmailOrPhone && reg.test(this.form.ReplaceUserEmailOrPhone)) {
callback()
} else {
@@ -110,6 +110,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.EmailOrPhone && reg.test(this.form.EmailOrPhone)) {
this.sendDisabled = false
callback()
@@ -125,6 +128,9 @@ export default {
} else {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (
this.form.ReplaceUserEmailOrPhone &&
reg.test(this.form.ReplaceUserEmailOrPhone)
+2 -1
View File
@@ -285,7 +285,8 @@ export default {
trigger: 'blur',
},
{
type: 'email',
// type: 'email',
pattern: new RegExp(this.$reg().EmailRegexStr),
message: 'Please input the correct email address',
trigger: 'blur,change',
},
@@ -254,7 +254,7 @@
<el-date-picker
v-model="form.StartTime"
type="year"
value-format="yyyy-MM-DD"
value-format="yyyy"
>
</el-date-picker>
</el-form-item>
@@ -265,7 +265,7 @@
<el-date-picker
v-model="form.EndTime"
type="year"
value-format="yyyy-MM-DD"
value-format="yyyy"
>
</el-date-picker>
</el-form-item>
@@ -904,12 +904,23 @@ export default {
try {
if (key === 'clinicalTrials') {
let validate = await this.$refs.clinicalTrialsFrom.validate()
console.log(validate, 'validate')
if (!validate) return false
this.form.DoctorId = this.reviewerId
if (this.trialId) {
this.form.TrialId = this.trialId
}
if (this.form.StartTime) {
let arr = this.form.StartTime.split("-")
if (arr.length <= 1) {
this.form.StartTime = `${this.form.StartTime}-01-01`
}
}
if (this.form.EndTime) {
let arr = this.form.EndTime.split("-")
if (arr.length <= 1) {
this.form.EndTime = `${this.form.EndTime}-12-31`
}
}
this.loading = true
let res = await addOrUpdateTrialExperience(this.form)
this.loading = false
@@ -38,7 +38,11 @@
<span v-if="isEN">{{ DATA.DepartmentOther }}</span>
<span v-else>{{ DATA.DepartmentOtherCN }}</span>
</span>
<span class="el-icon-user" v-if="DATA.Rank || DATA.RankCN">
<span class="el-icon-user" v-if="DATA.RankOther || DATA.RankOtherCN">
<span v-if="isEN">{{ DATA.RankOther }}</span>
<span v-else>{{ DATA.RankOtherCN }}</span>
</span>
<span class="el-icon-user" v-else-if="DATA.Rank || DATA.RankCN">
<span v-if="isEN">{{ DATA.Rank }}</span>
<span v-else>{{ DATA.RankCN }}</span>
</span>
@@ -327,7 +331,13 @@
:label="$t('curriculumVitae:info:form:physician')"
prop="RankId"
>
<el-select v-model="form.RankId" clearable placeholder="">
<el-select v-model="form.RankId" clearable placeholder="" @change="()=>{
if($fd('Rank', form.RankId, 'id') !==
$t('curriculumVitae:selectLabel:Other')){
form.RankOther = null
form.RankOtherCN = null
}
}">
<el-option
v-for="item in $d.Rank"
:key="item.id"
@@ -548,7 +558,8 @@ export default {
trigger: 'blur',
},
{
type: 'email',
// type: 'email',
pattern: new RegExp(this.$reg().EmailRegexStr),
message: this.$t('rules:email'),
trigger: 'blur,change',
},
@@ -72,7 +72,11 @@
reviewerData.EmploymentView.DepartmentOtherCN
}}</span>
</span>
<span class="el-icon-user"
<span class="el-icon-user" v-if="reviewerData.EmploymentView.RankOther || reviewerData.EmploymentView.RankOtherCN">
<span v-if="isEN">{{ reviewerData.EmploymentView.RankOther }}</span>
<span v-else>{{ reviewerData.EmploymentView.RankOtherCN }}</span>
</span>
<span class="el-icon-user" v-else
><span v-if="isEN">{{ reviewerData.EmploymentView.Rank }}</span>
<span v-else>{{ reviewerData.EmploymentView.RankCN }}</span></span
>
@@ -417,7 +421,12 @@
v-if="true"
>
<template slot-scope="scope">
<span>{{ $fd('Indication', scope.row.IndicationEnum) }}</span>
<span v-if="scope.row.EvaluationContent">
{{ scope.row.EvaluationContent }}
</span>
<span v-else>
{{ $fd('Indication', scope.row.IndicationEnum) }}
</span>
</template>
</el-table-column>
<el-table-column
+3
View File
@@ -530,6 +530,9 @@ export default {
emailList.forEach((item) => {
var pattern =
/^([A-Za-z0-9_\-\.\u4e00-\u9fa5])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/
if (this.$reg().EmailRegexStr) {
pattern = new RegExp(this.$reg().EmailRegexStr)
}
if (!pattern.test(item)) {
isError = true
}
@@ -439,7 +439,8 @@ export default {
trigger: 'blur',
},
{
type: 'email',
// type: 'email',
pattern: new RegExp(this.$reg().EmailRegexStr),
message: 'Please input the correct email address',
trigger: ['blur'],
},
+7
View File
@@ -219,6 +219,13 @@ export default {
sortable: 'custom',
showOverflowTooltip: true,
},
{
prop: 'JoinedTrialCount',
label: this.$t('system:userlist:table:JoinedTrialCount'),
minWidth: 150,
sortable: 'custom',
showOverflowTooltip: true,
},
{
prop: 'LastLoginTime',
label: this.$t('system:userlist:table:LastLoginTime'),
+4 -1
View File
@@ -289,7 +289,10 @@ export default {
},
handleEmailChange() {
var reg =
/^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.userForm.EMail && reg.test(this.userForm.EMail)) {
this.sendDisabled = false
} else {
@@ -535,7 +535,8 @@ export default {
trigger: 'blur',
},
{
type: 'email',
// type: 'email',
pattern: new RegExp(this.$reg().EmailRegexStr),
message: this.$t('rules:email'),
trigger: 'blur,change',
},
@@ -610,6 +611,9 @@ export default {
emailList.forEach((item) => {
var pattern =
/^([A-Za-z0-9_\-\.\u4e00-\u9fa5])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/
if (this.$reg().EmailRegexStr) {
pattern = new RegExp(this.$reg().EmailRegexStr)
}
if (!pattern.test(item)) {
isError = true
}
@@ -842,7 +842,7 @@ export default {
var trialId = this.$route.query.trialId
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(
`/${trialId}/Read/${this.subjectId}/visit/${param.file.name}`,
`/${trialId}/Read/${this.subjectId}/${this.visitTaskId}/${param.file.name}`,
file
)
console.log(res)
@@ -721,7 +721,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -739,7 +739,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -872,7 +872,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -37,7 +37,7 @@
<div class="add-icon" @click.prevent="downloadTpl">
<i class="el-icon-download" />
</div>
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType)">
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType, item.QuestionName)">
<i class="el-icon-upload2" />
</div>
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
@@ -174,7 +174,7 @@
<!-- 导入 -->
<el-dialog v-if="upload.visible" :visible.sync="upload.visible" :close-on-click-modal="false"
:title="upload.title" width="500px">
<UploadExcel :visit-task-id="visitTaskId" @close="uploadDlgClose" />
<UploadExcel :visit-task-id="visitTaskId" :TableName="upload.TableName" @close="uploadDlgClose" />
</el-dialog>
</div>
</div>
@@ -233,7 +233,7 @@ export default {
formChanged: false,
digitPlaces: 2,
addOrEdit: { visible: false, title: '' },
upload: { visible: false, title: '' },
upload: { visible: false, title: '', TableName: '' },
qsList: [],
answersList: [],
qsForm: {},
@@ -668,7 +668,8 @@ export default {
console.log(e)
}
},
uploadTpl(lesionType) {
uploadTpl(lesionType, TableName) {
this.upload.TableName = TableName
this.upload.title = `导入( ${this.$fd('LesionType', lesionType)} `
this.upload.visible = true
},
@@ -33,12 +33,16 @@
</el-form>
</template>
<script>
import { uploadIVUSTemplate } from '@/api/reading'
import { readingImport } from '@/api/reading'
export default {
props: {
visitTaskId: {
type: String,
required: true
},
TableName: {
type: String,
default: ''
}
},
data() {
@@ -63,7 +67,9 @@ export default {
var data = new FormData()
data.append('file', param.file)
data.append('visitTaskId', this.visitTaskId)
await uploadIVUSTemplate(data)
data.append('readingImportType', 0)
data.append('TableName', this.TableName)
await readingImport(data)
this.$emit('close')
this.$message.success('导入成功!')
loading.close()
@@ -1073,7 +1073,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -715,7 +715,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -276,7 +276,7 @@ export default {
window.opener.postMessage(data, window.location)
},
async receiveMsg(event) {
console.log('nonedicoms', event.data.type)
// console.log('nonedicoms', event.data.type)
if (event.data.type === 'isCanActiveNoneDicomTool') {
if (event.data.data.isCanActiveTool) {
// this.model = 'ArrowAnnotate'
@@ -304,8 +304,12 @@ export default {
// this.canvasData.splice(i, 1)
// }
// }
var idx = this.canvasData.findIndex(item => item.data.uuid === event.data.data.data.uuid)
this.canvasData.splice(idx, 1)
if (!event.data.data) {
this.canvasData = []
} else {
var idx = this.canvasData.findIndex(item => item.data.uuid === event.data.data.data.uuid)
this.canvasData.splice(idx, 1)
}
ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height) //
await ctx.drawImage(
this.currentImg,
@@ -512,6 +516,11 @@ export default {
this.canvasData.push(this.currentDrawData) //
}
}
//
if (this.model) {
var data = { type: 'setMeasurement', data: this.currentDrawData }
window.opener.postMessage(data, window.location)
}
this.isMouseDown = false //
this.model = ''
this.lesionName = ''
@@ -519,9 +528,6 @@ export default {
x: e.offsetX, //
y: e.offsetY
}
//
var data = { type: 'setMeasurement', data: this.currentDrawData }
window.opener.postMessage(data, window.location)
},
//
@@ -37,7 +37,7 @@
<div class="add-icon" @click.prevent="downloadTpl(item.LesionType)">
<i class="el-icon-download" />
</div>
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType)">
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType, item.QuestionName)">
<i class="el-icon-upload2" />
</div>
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
@@ -169,7 +169,7 @@
<!-- 导入 -->
<el-dialog v-if="upload.visible" :visible.sync="upload.visible" :close-on-click-modal="false"
:title="upload.title" width="500px">
<UploadExcel :visit-task-id="visitTaskId" :lesion-type="upload.lesionType" @close="uploadDlgClose" />
<UploadExcel :visit-task-id="visitTaskId" :lesion-type="upload.lesionType" :TableName="upload.TableName" @close="uploadDlgClose" />
</el-dialog>
</div>
</div>
@@ -228,7 +228,7 @@ export default {
formChanged: false,
digitPlaces: 2,
addOrEdit: { visible: false, title: '', lesionType: null },
upload: { visible: false, title: '', lesionType: null },
upload: { visible: false, title: '', lesionType: null, TableName: '', },
qsList: [],
answersList: [],
qsForm: {},
@@ -669,8 +669,9 @@ export default {
console.log(e)
}
},
uploadTpl(lesionType) {
uploadTpl(lesionType, TableName) {
this.upload.lesionType = lesionType
this.upload.TableName = TableName
this.upload.title = `导入( ${this.$fd('LesionType', lesionType)} `
this.upload.visible = true
},
@@ -33,7 +33,7 @@
</el-form>
</template>
<script>
import { uploadOCTFCTTemplate, uploadOCTLipidAngleTemplate } from '@/api/reading'
import { readingImport } from '@/api/reading'
export default {
props: {
visitTaskId: {
@@ -43,6 +43,10 @@ export default {
lesionType: {
type: Number,
required: true
},
TableName: {
type: String,
default: ''
}
},
data() {
@@ -67,10 +71,13 @@ export default {
var data = new FormData()
data.append('file', param.file)
data.append('visitTaskId', this.visitTaskId)
data.append('TableName', this.TableName)
if (this.lesionType === 112) {
await uploadOCTFCTTemplate(data)
data.append('readingImportType', 1)
await readingImport(data)
} else {
await uploadOCTLipidAngleTemplate(data)
data.append('readingImportType', 2)
await readingImport(data)
}
this.$emit('close')
this.$message.success('导入成功!')
@@ -590,7 +590,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -452,7 +452,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -801,7 +801,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -727,7 +727,7 @@ export default {
file = this.convertBase64ToBlob(file)
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -91,7 +91,7 @@
</div>
</template>
<script>
import { submitDicomVisitTask } from '@/api/trials'
import { submitDicomVisitTask, verifyVisitTaskQuestions } from '@/api/trials'
import { getCustomTag, submitCustomTag, resetReadingTask } from '@/api/reading'
import { setSkipReadingCache } from '@/api/reading'
import DicomEvent from './../components/DicomEvent'
@@ -358,6 +358,7 @@ export default {
async handleConfirm() {
var res = await this.$refs['QuestionsPreview'].handleSave(false)
if (res) {
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
@@ -353,7 +353,7 @@ export default {
validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify')));
callback();
} else {
if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -261,7 +261,7 @@ export default {
validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify')));
callback();
} else {
if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -483,7 +483,7 @@ export default {
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${param.file.name}`, file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${param.file.name}`, file)
console.log(res)
this.fileList.push({ name: param.file.name, path: this.$getObjectName(res.url), url: this.$getObjectName(res.url) })
this.urls.push(this.$getObjectName(res.url))
@@ -85,7 +85,7 @@
</template>
</el-select>
<span
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type === 'select' || scope.row.Type === 'radio'">
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type === 'select' || scope.row.Type === 'radio')">
{{ questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId] }}
</span>
<el-select
@@ -407,7 +407,8 @@ export default {
// this.$set(v, 'xfIndex', i)
}
if (v.Type === 'number') {
this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : v.Answers[this.visitTaskId])
// this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : v.Answers[this.visitTaskId])
this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId])
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
@@ -425,7 +426,8 @@ export default {
this.$set(this.questionForm, i.QuestionId, tableAnswers)
}
if (i.Type === 'number') {
this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : i.Answers[this.visitTaskId])
// this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : i.Answers[this.visitTaskId])
this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId])
}
if (i.Childrens && i.Childrens.length > 0 && i.Type !== 'table' && i.Type !== 'basicTable') {
this.setChild(i.Childrens)
@@ -120,7 +120,7 @@ name: "CustomizeReportPageUpload",
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${param.file.name}`, file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${param.file.name}`, file)
console.log(res)
this.fileList.push({ name: param.file.name, path: this.$getObjectName(res.url), url: this.$getObjectName(res.url)})
this.urls.push(this.$getObjectName(res.url))
@@ -346,6 +346,7 @@ export default {
localStorage.setItem('digitPlaces', res.Result.DigitPlaces)
localStorage.setItem('IsExistUnprocessedFeedback', res.Result.IsExistUnprocessedFeedback)
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
sessionStorage.setItem('taskInfo', JSON.stringify(res.Result))
this.readingCategory = res.Result.ReadingCategory
this.readingVersionEnum = res.Result.ReadingVersionEnum
this.questionFormChangeState = false
@@ -190,7 +190,7 @@ export default {
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
@@ -280,11 +280,11 @@
>
<svg-icon icon-class="refresh" class="svg-icon" />
</div>
<!-- 更多 -->
<!-- 更多 :class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" -->
<div
v-if="criterionType === 0"
:title="$t('trials:reading:button:more')"
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']"
:class="['tool-item']"
@click.stop="showPanel($event)"
@mouseleave="toolMouseout"
>
@@ -297,7 +297,8 @@
<i class="el-icon-arrow-down" style="color:#fff;" />
</div>
<div class="dropdown-content">
<ul v-if="readingTaskState < 2" style="width:100px;">
<!--v-if="readingTaskState < 2"-->
<ul style="width:100px;">
<li v-for="i in customizeStandards" :key="i.toolName" style="text-align:left;">
<a href="#" @click.prevent="setMoreToolActive(i.toolName)">
<svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" />
@@ -786,7 +787,7 @@ export default {
// resetAnnotation: false , // 使
saveCustomAnnotationTimer: null,
//
//
downloadImageVisible: false,
uploadImageVisible: false,
uploadSubjectId: null,
@@ -873,7 +874,7 @@ export default {
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isReadingTaskViewInOrder = this.taskInfo.IsReadingTaskViewInOrder
this.criterionType = this.taskInfo.CriterionType
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -882,6 +883,7 @@ export default {
this.tools = getCustomizeStandardsTools(this.taskInfo.ReadingToolList)
const toolNames = this.tools.map(i => i.toolName)
this.customizeStandards = config.customizeStandards.filter(item => !toolNames.includes(item.toolName))
console.log(this.customizeStandards,'this.customizeStandards')
} else {
this.tools = getTools(this.criterionType)
}
@@ -899,7 +901,7 @@ export default {
this.initLoader()
this.getWwcTpl()
})
this.getTrialCriterion()
DicomEvent.$on('isCanActiveNoneDicomTool', data => {
this.open.postMessage({ type: 'isCanActiveNoneDicomTool', data: data }, window.location)
})
@@ -1363,10 +1365,12 @@ export default {
const isCriticalSequence = this.visitTaskList[taskIndex].StudyList[studyIndex].IsCriticalSequence
const keyImages = this.visitTaskList[taskIndex].KeyImages
const series = this.visitTaskList[taskIndex].StudyList[studyIndex].SeriesList[seriesIndex]
let file = series.find(item => item.ImageId === imageId)
if (file) {
getNetWorkSpeed()
setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId)
if (series && series.length > 0) {
let file = series.find(item => item.ImageId === imageId)
if (file) {
getNetWorkSpeed()
setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId)
}
}
if (percentComplete === 100) {
workSpeedclose()
@@ -1508,14 +1512,32 @@ export default {
this.setToolsPassive()
},
annotationRemovedListener(e) {
if (this.readingTaskState === 2) return
const { annotation } = e.detail
if (!annotation) return
if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) {
const index = this.markedSeriesIds.indexOf(annotation.seriesId)
if (index !== -1) {
this.markedSeriesIds.splice(index, 1)
try{
if (!annotation) return
if (this. readingTaskState === 2 && !annotation.data.label) return false
if (this.readingTaskState === 2) {
const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg
}
if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) {
const index = this.markedSeriesIds.indexOf(annotation.seriesId)
if (index !== -1) {
this.markedSeriesIds.splice(index, 1)
}
} else {
const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg
}
} catch (e) {
cornerstoneTools.annotation.state.addAnnotation(annotation)
const renderingEngine = getRenderingEngine(renderingEngineId)
for (let i = 0; i < this.cells.length; i++) {
const viewportId = `${this.viewportKey}-${i}`
const viewport = renderingEngine.getViewport(viewportId)
viewport.render()
}
console.log(e)
}
},
async customAnnotationCompletedListener(e) {
@@ -1557,6 +1579,10 @@ export default {
}
this.saveCustomAnnotationTimer = setTimeout(()=>{this.saveCustomAnnotation(annotation)},500)
}
} else {
// if (this.isNumber(operateStateEnum)) {
// this.removeAnnotation(annotation)
// }
}
}
@@ -1631,6 +1657,7 @@ export default {
try {
// if ( this.resetAnnotation && this.isFusion ) return false
if (!annotation) return false
if (this.readingTaskState === 2 && !annotation.data.label) return false
if (this.readingTaskState === 2) {
const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg
@@ -1657,13 +1684,13 @@ export default {
annotation.data.label +
'?'
)
let res = null
if (annotation.markId) {
res = await deleteCustomTag(annotation.markId)
let res = await deleteCustomTag(annotation.markId)
if (!res.IsSuccess) throw ''
}else if (annotation.id) {
res = await deleteCustomTag(annotation.id)
let res = await deleteCustomTag(annotation.id)
if (!res.IsSuccess) throw ''
}
if (!res.isSuccess) return false
}
const index = this.markedSeriesIds.indexOf(annotation.seriesId)
if (index !== -1) {
@@ -1946,7 +1973,7 @@ export default {
if (area) {
const areaLine = isEmptyArea
? `Area: Oblique not supported`
: `Area: ${parseFloat(area)} ${areaUnit}`
: `Area: ${parseFloat(area).toFixed(2)} ${areaUnit}`
textLines.push(areaLine)
}
@@ -2034,7 +2061,7 @@ export default {
},
//
setAnnotateToolActive(toolName) {
if (this.readingTaskState === 2) return
// if (this.readingTaskState === 2) return
const toolObj = this.tools.find(i => i.toolName === toolName)
if (!toolObj || toolObj.isDisabled) return
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
@@ -2087,7 +2114,7 @@ export default {
}
},
setMoreToolActive(toolName) {
if (this.readingTaskState === 2) return
// if (this.readingTaskState === 2) return
this.setToolsPassive()
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
@@ -2124,7 +2151,10 @@ export default {
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
const isCurrentTask = series.TaskInfo.IsCurrentTask
const readingTaskState = this.readingTaskState
if (!isCurrentTask || readingTaskState >= 2) {
if (isCurrentTask && readingTaskState >= 2) {
this.tools[i].isDisabled = false
e.target.style.cursor = 'pointer'
} else if (!isCurrentTask || readingTaskState >= 2) {
this.tools[i].isDisabled = true
e.target.style.cursor = 'not-allowed'
if (this.activeTool) {
@@ -2941,9 +2971,25 @@ export default {
try {
const that = this
//
const { value } = await this.$prompt(this.$t('trials:noneDicom:message:msg1'), '', {
let message = this.$t('trials:noneDicom:message:msg1')
// if (isShowCancelButton) {
// message = `<div><p>${this.$t('trials:noneDicom:message:msg1')}</p><p style='font-size:12px' class='customPromptTip'>${this.$t('trials:noneDicom:message:saveTip')}</p></div>`
// }
const { value } = await this.$prompt( message, '', {
showClose: false,
showCancelButton: isShowCancelButton,
cancelButtonText: isShowCancelButton ? this.$t('trials:reading:button:temporarySave') : this.$t('common:button:cancel'),
confirmButtonText: isShowCancelButton ? this.$t('trials:reading:button:enduringSave') : this.$t('trials:reading:button:relevancy'),
// showCancelButton: isShowCancelButton,
// dangerouslyUseHTMLString: isShowCancelButton,
inputValidator: (res) => {
if (!res) {
return isShowCancelButton ? this.$t('trials:noneDicom:message:saveTip') : this.$t('trials:noneDicom:message:saveTipByRelevancy')
}
},
inputErrorMessage: this.$t('trials:noneDicom:message:saveTip'),
showCancelButton: true,
closeOnClickModal: false,
closeOnPressEscape: false,
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
const value = instance.inputValue
@@ -2960,7 +3006,8 @@ export default {
}
})
return value
} catch {
} catch(err) {
console.log(err)
return null
}
},
@@ -3199,9 +3246,9 @@ export default {
try {
file = this.convertBase64ToBlob(file)
const trialId = this.$route.query.trialId
const taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const subjectId = taskInfo.SubjectId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -235,7 +235,7 @@ export default {
mounted() {
this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionType = this.taskInfo.CriterionType
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -1325,7 +1325,7 @@ export default {
file = this.convertBase64ToBlob(file)
const trialId = this.$route.query.trialId
const subjectId = this.taskInfo.SubjectId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -1489,6 +1489,7 @@ export default {
this.getOuterQuestions()
this.getTableQuestions()
this.$emit('resetAnnotations', this.visitTaskId)
DicomEvent.$emit('removeNoneDicomMeasureData', null)
}
loading.close()
} catch (e) {
@@ -1745,9 +1746,9 @@ export default {
if (this.activeName) {
return this.checkToolCanActive(toolName)
} else {
if (this.isBaseLineTask && (toolName === 'Bidirectional' || toolName === 'Length' || toolName === 'RectangleRoi')) {
if (this.isBaseLineTask && (toolName === 'Bidirectional' || toolName === 'Length' || toolName === 'RectangleRoi' || toolName === 'RectangleROI')) {
return { isCanActiveTool: true, reason: '' }
} else if (!this.isBaseLineTask && (toolName === 'ArrowAnnotate' || toolName === 'Bidirectional' || toolName === 'Length' || toolName === 'RectangleRoi')) {
} else if (!this.isBaseLineTask && (toolName === 'ArrowAnnotate' || toolName === 'Bidirectional' || toolName === 'Length' || toolName === 'RectangleRoi' || toolName === 'RectangleROI')) {
return { isCanActiveTool: true, reason: '' }
} else if (this.isBaseLineTask && toolName === 'ArrowAnnotate') {
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg54') }
@@ -1770,10 +1771,10 @@ export default {
} else if (innerForm.LesionType === 0 && isLymphNodes === 0 && toolName !== 'Length') {
// '使'
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg7') }
} else if (innerForm.LesionType === 1 && isLymphNodes === 1 && toolName !== 'Bidirectional' && toolName !== 'RectangleRoi') {
} else if (innerForm.LesionType === 1 && isLymphNodes === 1 && toolName !== 'Bidirectional' && toolName !== 'RectangleRoi' && toolName !== 'RectangleROI') {
// '使'
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg8') }
} else if (innerForm.LesionType === 1 && isLymphNodes === 0 && toolName !== 'Length' && toolName !== 'RectangleRoi') {
} else if (innerForm.LesionType === 1 && isLymphNodes === 0 && toolName !== 'Length' && toolName !== 'RectangleRoi' && toolName !== 'RectangleROI') {
// '使'
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg9') }
} else if (toolName === 'ArrowAnnotate') {
@@ -1788,10 +1789,10 @@ export default {
} else if (innerForm.LesionType === 0 && isLymphNodes === 0 && toolName !== 'Length' && toolName !== 'ArrowAnnotate') {
// 使
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg11') }
} else if (innerForm.LesionType === 1 && isLymphNodes === 1 && toolName !== 'Bidirectional' && toolName !== 'ArrowAnnotate' && toolName !== 'RectangleRoi') {
} else if (innerForm.LesionType === 1 && isLymphNodes === 1 && toolName !== 'Bidirectional' && toolName !== 'ArrowAnnotate' && toolName !== 'RectangleRoi' && toolName !== 'RectangleROI') {
// 使
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg52') }
} else if (innerForm.LesionType === 1 && isLymphNodes === 0 && toolName !== 'Length' && toolName !== 'ArrowAnnotate' && toolName !== 'RectangleRoi') {
} else if (innerForm.LesionType === 1 && isLymphNodes === 0 && toolName !== 'Length' && toolName !== 'ArrowAnnotate' && toolName !== 'RectangleRoi' && toolName !== 'RectangleROI') {
// 使
return { isCanActiveTool: false, reason: this.$t('trials:reading:warnning:msg53') }
} else if (innerForm.LesionType === 2 && isLymphNodes === 1 && toolName !== 'Bidirectional' && toolName !== 'ArrowAnnotate') {
@@ -327,7 +327,7 @@ export default {
},
created() { this.getTableHeight() },
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.criterionType = this.taskInfo.CriterionType
this.visitTaskId = this.taskInfo.VisitTaskId
this.isBaselineTask = this.taskInfo.IsBaseLine
@@ -367,7 +367,7 @@ export default {
getTableHeight() {
this.height = window.innerHeight - 170
},
async getReportInfo(IsCalculate) {
async getReportInfo(IsCalculate = true) {
this.loading = true
try {
var params = {
@@ -153,7 +153,7 @@ export default {
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.studyList = this.visitTaskInfo.StudyList
@@ -174,7 +174,7 @@ export default {
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
@@ -1,6 +1,6 @@
<template>
<div class="visit-review-container">
<el-tabs v-model="activeName">
<el-tabs v-model="activeName" @tab-click="handleClick">
<!-- 阅片 -->
<el-tab-pane v-if="taskInfo" :label="$t('trials:reading:tabTitle:review')" name="read">
<read-page ref="readPage" :reading-tool="readingTool" />
@@ -12,11 +12,13 @@
name="report"
>
<report-page
v-if="activeName === 'report' && taskInfo.CriterionType !== 0"
v-if="taskInfo.CriterionType !== 0"
ref="reportPage"
@setReadingTaskState="setReadingTaskState"
/>
<customize-report-page
v-if="activeName === 'report' && taskInfo.CriterionType === 0"
v-if="taskInfo.CriterionType === 0"
ref="reportPage"
@setReadingTaskState="setReadingTaskState"
/>
</el-tab-pane>
@@ -47,12 +49,16 @@ export default {
}
},
mounted() {
console.log(this.readingTool)
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
},
methods: {
setReadingTaskState(state) {
this.$refs['readPage'].setReadingTaskState(state)
},
handleClick(tab) {
if (tab.name === 'report') {
this.$refs['reportPage'].getReportInfo()
}
}
}
}
@@ -21,7 +21,7 @@
<el-table-column :prop="item.Id" :label="item.QuestionName" :key="item.Id"
v-for="item of question.TableQuestions.Questions" show-overflow-tooltip :render-header="renderHeader">
<template slot-scope="scope">
<span v-if="item.Type === 'upload'">
<span v-if="item.Type === 'upload' || item.Type === 'screenshot'">
{{ scope.row[item.Id] === '' ? '' : scope.row[item.Id] ? scope.row[item.Id].split('|').length : '' }}
</span>
<span v-else-if="item.Type === 'number'">
@@ -82,7 +82,8 @@
validator: question.Type === 'number' && !question.TypeValue ? validatorNumberInput : (rule, value, callback) => { callback() },
trigger: ['blur', 'change']
}
]" :class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' ? 'uploadWrapper' : '']">
]"
:class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' || question.Type === 'screenshot' ? 'uploadWrapper' : '']">
<!-- 输入框 -->
<el-input v-if="question.Type === 'input'" v-model="questionForm[question.Id]"
:disabled="question.TableQuestionType === 2 || readingTaskState === 2" />
@@ -161,12 +162,13 @@
</el-select>
<template v-if="question.Type === 'number' && (question.ImageMarkEnum === 1 || question.ImageMarkEnum === 2)">
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;">
<el-input type="number" @change="(val) => { formItemNumberChange(val, question) }"
<el-input type="text" @change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
v-model="questionForm[question.Id]"
:title="questionsMarkStatus[question.Id] ? questionsMarkStatus[question.Id].OrderMarkName : ''"
:title="questionsMarkStatus[question.Id] ? questionsMarkStatus[question.Id].OrderMarkName : question.Remark"
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1"
style="width: 150px;">
style="width: 150px;margin-right: 5px;">
<template v-if="question.Unit !== 0" slot="append">
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
</template>
@@ -236,18 +238,18 @@
</el-input>
</template>
<!-- 上传图像 -->
<el-upload v-if="question.Type === 'upload'" :disabled="readingTaskState === 2" action
:accept="question.FileType" :limit="question.ImageCount === 0 ? 100 : question.ImageCount"
:on-preview="handlePictureCardPreview"
:before-upload="(file) => { return handleBeforeUpload(file, question.FileType) }"
<el-upload v-if="question.Type === 'upload' || question.Type === 'screenshot'"
:disabled="readingTaskState === 2" action :accept="question.FileType"
:limit="question.ImageCount === 0 ? 100 : question.ImageCount" :on-preview="handlePictureCardPreview"
:before-upload="(file) => { return handleBeforeUpload(file, question.FileType, question.Type) }"
:http-request="uploadScreenshot" :on-remove="handleRemove" :file-list="fileList"
:class="{ disabled: question.ImageCount === 0 ? false : fileList.length >= question.ImageCount }">
<el-button slot="default" class="el-icon-plus" v-if="readingTaskState < 2">
{{ this.$t('common:button:upload') }}
</el-button>
</el-upload>
<viewer v-if="question.Type === 'upload' && imgVisible" :ref="imageUrl" style="margin:0 10px;"
:images="[imageUrl]">
<viewer v-if="(question.Type === 'upload' || question.Type === 'screenshot') && imgVisible" :ref="imageUrl"
style="margin:0 10px;" :images="[imageUrl]">
<img v-show="false" crossorigin="anonymous" :src="imageUrl" alt="Image">
</viewer>
</el-form-item>
@@ -274,24 +276,28 @@
</base-model> -->
<!-- 预览文件 -->
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="$t('common:button:preview')"
<!-- <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>
</el-dialog> -->
</div>
</template>
<script>
import { deleteReadingRowAnswer, getQuestionCalculateRelation, submitTableQuestion, deleteCustomTag } from '@/api/trials'
import QuestionTableFormItem from './QuestionTableFormItem'
import BaseModel from '@/components/BaseModel'
import PreviewFile from '@/components/PreviewFile/index'
// import PreviewFile from '@/components/PreviewFile/index'
import { mapGetters } from 'vuex'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
export default {
name: 'QuestionFormItem',
components: { QuestionTableFormItem, BaseModel, PreviewFile },
components: {
QuestionTableFormItem,
BaseModel,
// PreviewFile
},
props: {
isBaseline: {
type: Boolean,
@@ -354,9 +360,9 @@ export default {
digitPlaces: 2,
CalculationTabelList: [],
classArr: [],
previewVisible: false,
currentPath: '',
currentType: '',
// previewVisible: false,
// currentPath: '',
// currentType: '',
markTableQuestions: [],
parentQsId: ''
}
@@ -440,12 +446,14 @@ export default {
// }
// }
// }, 300)
if (this.question.Type === 'upload') {
if (this.question.Type === 'upload' || this.question.Type === 'screenshot') {
if (this.questionForm[this.question.Id]) {
this.urls = this.questionForm[this.question.Id].split('|')
this.fileList = []
this.urls.map((url, index) => {
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${index + 1}`, url: `${url}` })
var index = url.lastIndexOf('.')
var suffix = url.substring(index + 1, url.length)
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${index + 1}(${suffix})`, url: `${url}` })
})
}
}
@@ -486,7 +494,7 @@ export default {
validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify')));
callback();
} else {
if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -509,7 +517,7 @@ export default {
}
},
handleMarkedQsBlur(value, a, b, question) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
this.$set(a, b, !isNaN(parseFloat(value)) ? parseFloat(value).toFixed(this.digitPlaces) : value)
this.$emit('operateImageMarker', { operateStateEnum: 6, question })
},
async deleteTableCol(row, index) {
@@ -1104,6 +1112,7 @@ export default {
// },
async operateImageMarker(obj) {
// if (obj.question.IsTableQuestion && this.question.Id !== obj.question.ParentQsId) return
if (obj.operateStateEnum === 5 && this.questionForm[obj.question.Id] && isNaN(parseFloat(this.questionForm[obj.question.Id])) && this.questionForm[obj.question.Id] !== 'NE') return false
if (obj.operateStateEnum === 4) {
//
this.$set(this.questionForm, obj.question.Id, null)
@@ -1246,13 +1255,22 @@ export default {
text: 'Loading',
spinner: 'el-icon-loading'
})
var fileName = param.file.name
let file = await this.fileToBlob(param.file)
let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file)
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}`, url: this.$getObjectName(res.url) })
this.urls.push(this.$getObjectName(res.url))
this.$emit("setFormItemData", { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question })
this.$set(this.QuestionsForm, this.question.Id, this.urls.length > 0 ? this.urls.join('|') : '')
try {
var fileName = param.file.name
var index = fileName.lastIndexOf('.')
var suffix = fileName.substring(index + 1, fileName.length)
let file = await this.fileToBlob(param.file)
// let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file)
const taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const subjectId = taskInfo.SubjectId
let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}`, file)
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}(${suffix})`, url: this.$getObjectName(res.url) })
this.urls.push(this.$getObjectName(res.url))
this.$emit("setFormItemData", { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question })
this.$set(this.QuestionsForm, this.question.Id, this.urls.length > 0 ? this.urls.join('|') : '')
} catch (err) {
console.log(err)
}
loading.close()
// uploadReadingAnswerImage(this.$route.query.trialId, this.visitTaskId, formData).then(res => {
// if (res.IsSuccess) {
@@ -1265,7 +1283,10 @@ export default {
// loading.close()
// })
},
handleBeforeUpload(file, accept) {
handleBeforeUpload(file, accept, type) {
if (type === 'screenshot') {
accept = '.png,.jpeg,.jpg'
}
//
if (this.checkFileSuffix(file.name, accept) || accept === '-1') {
return true
@@ -1288,11 +1309,27 @@ export default {
handlePictureCardPreview(file) {
var suffix = file.url.substring(file.url.lastIndexOf(".") + 1)
suffix = suffix ? suffix.toLowerCase() : ''
if (suffix === 'doc' || suffix === 'docx' || suffix === 'pdf') {
if (['ppt',
'pptx',
'doc',
'docx',
'xls',
'xlsx'].includes(suffix)) {
// window.open(this.OSSclientConfig.basePath + file.url,'_blank')
this.currentPath = file.url
this.currentType = suffix
this.previewVisible = true
this.$onlyOffice({
path: file.url,
type: suffix,
title: file.name
})
// this.currentPath = file.url
// this.currentType = suffix
// this.previewVisible = true
} else if (['pdf'].includes(suffix)) {
this.$preview({
path: file.url,
type: 'pdf',
title: file.name,
})
} else {
this.imageUrl = this.OSSclientConfig.basePath + file.url
this.imgVisible = true
@@ -55,7 +55,7 @@
<script>
import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, getQuestionCalculateRelation, saveTaskQuestion } from '@/api/trials'
import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, verifyVisitTaskQuestions, getQuestionCalculateRelation, saveTaskQuestion } from '@/api/trials'
import { setSkipReadingCache, resetReadingTask, saveTableQuestionMark } from '@/api/reading'
import const_ from '@/const/sign-code'
import QuestionFormItem from './QuestionFormItem'
@@ -114,7 +114,7 @@ export default {
window.addEventListener('message', this.receiveMsg)
this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionId = this.taskInfo.TrialReadingCriterionId
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -242,6 +242,8 @@ export default {
async handleSubmit() {
const valid = await this.$refs['questions'].validate()
if (!valid) return
await this.handleSave(false)
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
@@ -605,7 +607,9 @@ export default {
}
markInfo[0].PicturePath = picturePath
}
markInfo[0].MarkId = annotation ? annotation.annotationUID : null
if (markInfo && markInfo.length > 0) {
markInfo[0].MarkId = annotation ? annotation.annotationUID : null
}
await saveTaskQuestion(-10, {
visitTaskId: this.visitTaskId,
answers,
@@ -614,8 +618,9 @@ export default {
this.$set(this.questionsMarkStatus, obj.question.Id, {
isMarked: !!this.questionMarkInfoList[index]?.MeasureData,
isSaved: true,
OrderMarkName: this.questionMarkInfoList[index].OrderMarkName
OrderMarkName: index > -1 ? this.questionMarkInfoList[index].OrderMarkName : ''
})
this.resetOperateState()
if (annotation) {
for (let i = 0; i < this.questionMarkInfoList.length; i++) {
const item = this.questionMarkInfoList[i]
@@ -987,7 +992,7 @@ export default {
const trialId = this.$route.query.trialId
const taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const subjectId = taskInfo.SubjectId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -11,7 +11,8 @@
validator: question.Type === 'number' && !question.TypeValue ? validatorNumberInput : (rule, value, callback) => { callback() },
trigger: ['blur', 'change']
}
]" :class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' ? 'uploadWrapper' : '']">
]"
:class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' || question.Type === 'screenshot' ? 'uploadWrapper' : '']">
<!-- 输入框 -->
<el-input v-if="question.Type === 'input'" v-model="questionForm[question.Id]"
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False')" />
@@ -80,12 +81,13 @@
<!-- 数值 -->
<template v-if="question.Type === 'number' && (question.ImageMarkEnum === 1 || question.ImageMarkEnum === 2)">
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;">
<el-input type="number" @change="(val) => { formItemNumberChange(val, question) }"
<el-input type="text" @change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
v-model="questionForm[question.Id]"
:title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : ''"
:title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : question.Remark"
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1"
style="width: 150px;">
style="width: 150px;margin-right: 5px;">
<template v-if="question.Unit !== 0" slot="append">
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
</template>
@@ -156,41 +158,20 @@
</el-input>
</template>
<!-- 上传图像 -->
<el-upload v-if="question.Type === 'upload'" action :accept="question.FileType"
:limit="question.ImageCount === 0 ? 100 : question.ImageCount" :on-preview="handlePictureCardPreview"
:before-upload="handleBeforeUpload" :http-request="uploadScreenshot" list-type="picture-card"
:on-remove="handleRemove" :file-list="fileList"
<el-upload v-if="question.Type === 'upload' || question.Type === 'screenshot'" :disabled="readingTaskState === 2"
action :accept="question.FileType" :limit="question.ImageCount === 0 ? 100 : question.ImageCount"
:on-preview="handlePictureCardPreview"
:before-upload="(file) => { return handleBeforeUpload(file, question.FileType, question.Type) }"
:http-request="uploadScreenshot" :on-remove="handleRemove" :file-list="fileList"
:class="{ disabled: question.ImageCount === 0 ? false : fileList.length >= question.ImageCount }">
<i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}">
<viewer :ref="file.url" :images="[imageUrl]" style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
">
<img class="el-upload-list__item-thumbnail" :src="OSSclientConfig.basePath + file.url"
crossOrigin="anonymous" alt="" style="max-width: 100%; max-height: 100%" />
<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>
</viewer>
</div>
<el-button slot="default" class="el-icon-plus" v-if="readingTaskState < 2">
{{ this.$t('common:button:upload') }}
</el-button>
</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">
{{ $t('trials:readingUnit:qsList:message:loading') }}<span class="dot">...</span>
</div>
</el-image>
</el-dialog>
<viewer v-if="(question.Type === 'upload' || question.Type === 'screenshot') && imgVisible" :ref="imageUrl"
style="margin:0 10px;" :images="[imageUrl]">
<img v-show="false" crossorigin="anonymous" :src="imageUrl" alt="Image">
</viewer>
</el-form-item>
</div>
</template>
@@ -297,12 +278,14 @@ export default {
mounted() {
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
if (this.question.Type === 'upload') {
if (this.question.Type === 'upload' || this.question.Type === 'screenshot') {
if (this.questionForm[this.question.Id]) {
this.urls = this.questionForm[this.question.Id].split('|')
this.fileList = []
this.urls.map(url => {
this.fileList.push({ name: '', url: `${url}` })
this.urls.map((url, index) => {
var index = url.lastIndexOf('.')
var suffix = url.substring(index + 1, url.length)
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${index + 1}(${suffix})`, url: `${url}` })
})
}
}
@@ -325,7 +308,7 @@ export default {
validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify')));
callback();
} else {
if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -361,6 +344,7 @@ export default {
} else {
this.$emit('setFormItemData', { key: question.Id, val: v, question: question })
}
this.$emit('formItemTableNumberChange', v, question)
},
handleBlur(value, a, b) {
if (!value) return false
@@ -369,7 +353,7 @@ export default {
}
},
handleMarkedQsBlur(value, a, b, question) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
this.$set(a, b, !isNaN(parseFloat(value)) ? parseFloat(value).toFixed(this.digitPlaces) : value)
question.IsTableQuestion = true
// this.$emit('operateImageMarker', {operateStateEnum: 6, question})
},
@@ -535,6 +519,7 @@ export default {
obj.question.IsTableQuestion = true
obj.question.RowId = this.rowId
obj.question.ParentQsId = this.parentQsId
if (obj.operateStateEnum === 7 && this.questionForm[obj.question.Id] && isNaN(parseFloat(this.questionForm[obj.question.Id])) && this.questionForm[obj.question.Id] !== 'NE') return false
if (obj.operateStateEnum === 7) {
//
// if (!obj.question.RowId) {
@@ -573,32 +558,36 @@ export default {
text: 'Loading',
spinner: 'el-icon-loading'
})
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
var fileName = param.file.name
var index = fileName.lastIndexOf('.')
var suffix = fileName.substring(index + 1, fileName.length)
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${param.file.name}`, file)
this.fileList.push({ name: param.file.name, path: this.$getObjectName(res.url), url: this.$getObjectName(res.url) })
// let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file)
const taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const subjectId = taskInfo.SubjectId
let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}`, file)
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}(${suffix})`, url: this.$getObjectName(res.url) })
this.urls.push(this.$getObjectName(res.url))
this.$emit('setFormItemData', { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question })
loading.close()
},
handleBeforeUpload(file) {
handleBeforeUpload(file, accept, type) {
if (type === 'screenshot') {
accept = '.png,.jpeg,.jpg'
}
//
if (this.checkFileSuffix(file.name)) {
// this.fileList = []
if (this.checkFileSuffix(file.name, accept) || accept === '-1') {
return true
} else {
let msg = this.$t(
"trials:readingUnit:qsList:message:imageFormat"
).replace("xxx", this.question.FileType)
const msg = this.$t('trials:adReview:title:msg4').replace('xxx', accept)
this.$alert(msg)
return false
}
},
checkFileSuffix(fileName) {
checkFileSuffix(fileName, accept) {
var index = fileName.lastIndexOf('.')
var suffix = fileName.substring(index + 1, fileName.length)
if (this.question.FileType.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1) {
if (accept.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1) {
return false
} else {
return true
@@ -608,21 +597,46 @@ export default {
handlePictureCardPreview(file) {
var suffix = file.url.substring(file.url.lastIndexOf(".") + 1)
suffix = suffix ? suffix.toLowerCase() : ''
if (suffix === 'doc' || suffix === 'docx' || suffix === 'pdf') {
window.open(this.OSSclientConfig.basePath + file.url, '_blank')
if (['ppt',
'pptx',
'doc',
'docx',
'xls',
'xlsx'].includes(suffix)) {
// window.open(this.OSSclientConfig.basePath + file.url,'_blank')
this.$onlyOffice({
path: file.url,
type: suffix,
title: file.name
})
// this.currentPath = file.url
// this.currentType = suffix
// this.previewVisible = true
} else if (['pdf'].includes(suffix)) {
this.$preview({
path: file.url,
type: 'pdf',
title: file.name,
})
} else {
this.imageUrl = this.OSSclientConfig.basePath + file.url
// this.imgVisible = true
this.$refs[file.url].$viewer.show()
this.imgVisible = true
this.$nextTick(() => {
this.$refs[this.imageUrl].$viewer.show()
})
}
},
//
handleRemove(file, fileList) {
this.imageUrl = ''
this.fileList.splice(this.fileList.findIndex(f => f.url === file.url), 1)
this.urls.splice(this.fileList.findIndex(f => f === file.url), 1)
this.$emit('setFormItemData', { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question })
if (file && file.status === "success") {
this.imageUrl = ''
this.fileList.splice(this.fileList.findIndex(f => f.url === file.url), 1)
this.fileList.forEach((i, index) => {
i.name = `${this.$t('trials:emailManageCfg:title:fileName')}${index + 1}`
})
this.urls.splice(this.fileList.findIndex(f => f === file.url), 1)
this.$emit('setFormItemData', { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question })
}
}
}
}
@@ -275,7 +275,7 @@ export default {
}
},
async mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.trialId = this.$route.query.trialId
this.visitTaskId = this.taskInfo.VisitTaskId
this.subjectId = this.taskInfo.SubjectId
@@ -263,7 +263,7 @@ export default {
}
},
mounted() {
let digitPlaces = Number(localStorage.getItem('digitPlaces'))
let digitPlaces = Number(sessionStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
},
methods: {
@@ -276,7 +276,7 @@ export default {
mounted() {
this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionType = this.taskInfo.CriterionType
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -1428,7 +1428,7 @@ export default {
file = this.convertBase64ToBlob(file)
const trialId = this.$route.query.trialId
const subjectId = this.taskInfo.SubjectId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result }
} catch (e) {
console.log(e)
@@ -292,8 +292,82 @@ const config = {
'i18nKey': 'trials:reading:button:CobbAngle',
'isDisabled': false,
'disabledReason': ''
}
]
},
{
'name': '自由曲线',
'icon': 'polygon',
'toolName': 'PlanarFreehandROI',
'props': ['radius', 'area', 'mean', 'max', 'stdDev'],
'i18nKey': 'trials:reading:button:planarFreehandROI',
'isDisabled': false,
'disabledReason': ''
},
],
'customizeStandardsNoneDicom': [
{
'name': '直径测量工具',
'icon': 'length',
'toolName': 'Length',
'props': ['length'],
'i18nKey': 'trials:reading:button:length',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '矩形工具',
'icon': 'rectangle',
'toolName': 'RectangleROI',
'props': ['area', 'mean', 'max', 'stdDev'],
'i18nKey': 'trials:reading:button:rectangle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '箭头工具',
'icon': 'arrow',
'toolName': 'ArrowAnnotate',
'props': [],
'i18nKey': 'trials:reading:button:arrowAnnotate',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '圆形工具',
'icon': 'oval',
'toolName': 'CircleROI',
'props': ['radius', 'area', 'mean', 'max', 'stdDev'],
'i18nKey': 'trials:reading:button:Circle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '椭圆工具',
'icon': 'elliptical',
'toolName': 'EllipticalROI',
'props': ['radius', 'area', 'mean', 'max', 'stdDev'],
'i18nKey': 'trials:reading:button:Elliptical',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '角度工具',
'icon': 'angle',
'toolName': 'Angle',
'props': ['angle'],
'i18nKey': 'trials:reading:button:Angle',
'isDisabled': false,
'disabledReason': ''
},
{
'name': '自由曲线',
'icon': 'polygon',
'toolName': 'PlanarFreehandROI',
'props': [],
'i18nKey': 'trials:reading:button:planarFreehandROI',
'isDisabled': false,
'disabledReason': ''
},
],
}
const getTools = (criterionType) => {
const standard = config.standards.find(s => s.type === criterionType)
@@ -303,4 +377,8 @@ const getCustomizeStandardsTools = (toolNames) => {
const filteredTools = config.customizeStandards.filter(item => toolNames.includes(item.toolName))
return filteredTools || []
}
export { config, getTools, getCustomizeStandardsTools }
const getCustomizeStandardsNoneDicomTools = (toolNames) => {
const filteredTools = config.customizeStandardsNoneDicom.filter(item => toolNames.includes(item.toolName))
return filteredTools || []
}
export { config, getTools, getCustomizeStandardsTools, getCustomizeStandardsNoneDicomTools }
@@ -70,6 +70,7 @@ export default {
}
const res = await getNextTask(params)
this.taskInfo = res.Result
sessionStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces))
this.loading = false
@@ -318,7 +318,7 @@
:disabled="!scope.row.IsHaveQuestion || scope.row.IsInvalid"
circle
:title="$t('trials:medicalFeedback:table:view')"
icon="el-icon-edit-outline"
icon="el-icon-view"
@click="handleReadMecialAudit(scope.row)"
/>
<!-- 回复:disabled="!scope.row.IsHaveQuestion || scope.row.IsInvalid" -->
@@ -285,6 +285,7 @@ export default {
async handleSubmit() {
const valid = await this.$refs['questions'].validate()
if (!valid) return
await this.handleSave()
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
@@ -119,7 +119,7 @@ name: "UploadFile",
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${param.file.name}`, file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${param.file.name}`, file)
console.log(res)
this.fileList.push({ name: param.file.name, path: this.$getObjectName(res.url), url: this.$getObjectName(res.url)})
this.urls.push(this.$getObjectName(res.url))
@@ -1,59 +1,39 @@
<template>
<div v-loading="loading" class="reading-viewer-container">
<!-- 访视阅片 -->
<visit-review v-if="taskInfo && taskInfo.ReadingCategory=== 1" />
<visit-review v-if="taskInfo && taskInfo.ReadingCategory === 1" />
<!-- 全局阅片 -->
<global-review
v-else-if="taskInfo && taskInfo.ReadingCategory=== 2"
:trial-id="trialId"
:subject-id="taskInfo.SubjectId"
:visit-task-id="taskInfo.VisitTaskId"
:reading-category="taskInfo.ReadingCategory"
:subject-code="taskInfo.SubjectCode"
:task-blind-name="taskInfo.TaskBlindName"
:is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
<global-review v-else-if="taskInfo && taskInfo.ReadingCategory === 2" :trial-id="trialId"
:subject-id="taskInfo.SubjectId" :visit-task-id="taskInfo.VisitTaskId"
:reading-category="taskInfo.ReadingCategory" :subject-code="taskInfo.SubjectCode"
:task-blind-name="taskInfo.TaskBlindName" :is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
:is-reading-show-previous-results="taskInfo.IsReadingShowPreviousResults"
:is-exists-clinical-data="taskInfo.IsExistsClinicalData"
/>
:is-exists-clinical-data="taskInfo.IsExistsClinicalData" />
<!-- 裁判阅片 -->
<ad-review
v-else-if="taskInfo && taskInfo.ReadingCategory=== 4"
:trial-id="trialId"
:subject-id="taskInfo.SubjectId"
:visit-task-id="taskInfo.VisitTaskId"
:reading-category="taskInfo.ReadingCategory"
:subject-code="taskInfo.SubjectCode"
:task-blind-name="taskInfo.TaskBlindName"
:is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
<ad-review v-else-if="taskInfo && taskInfo.ReadingCategory === 4" :trial-id="trialId"
:subject-id="taskInfo.SubjectId" :visit-task-id="taskInfo.VisitTaskId"
:reading-category="taskInfo.ReadingCategory" :subject-code="taskInfo.SubjectCode"
:task-blind-name="taskInfo.TaskBlindName" :is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
:is-reading-show-previous-results="taskInfo.IsReadingShowPreviousResults"
:is-exists-clinical-data="taskInfo.IsExistsClinicalData"
/>
:is-exists-clinical-data="taskInfo.IsExistsClinicalData" />
<!-- 肿瘤学阅片 -->
<!-- <oncology-review v-else-if="taskInfo && taskInfo.ReadingCategory=== 5" /> -->
<el-dialog
:visible.sync="clinicalDataVisible"
:custom-class="isClinicalDataFullscreen?'full-dialog-container':'dialog-container'"
:show-close="false"
:close-on-click-modal="false"
:fullscreen="isClinicalDataFullscreen"
>
<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" />
<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"
/>
<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>
@@ -65,6 +45,7 @@
<script>
import { getNextTask, readClinicalData } from '@/api/trials'
import store from '@/store'
import { changeURLStatic } from '@/utils/history.js'
import VisitReview from '@/views/trials/trials-panel/reading/visit-review'
import GlobalReview from '@/views/trials/trials-panel/reading/global-review'
import AdReview from '@/views/trials/trials-panel/reading/ad-review'
@@ -92,6 +73,10 @@ export default {
},
mounted() {
this.trialId = this.$route.query.trialId
if (this.$router.currentRoute.query.TokenKey) {
store.dispatch('user/setToken', this.$router.currentRoute.query.TokenKey)
changeURLStatic('TokenKey', '')
}
this.getTaskInfo()
},
methods: {
@@ -108,6 +93,7 @@ export default {
const res = await getNextTask(params)
this.taskInfo = res.Result
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
sessionStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces))
this.loading = false
this.$nextTick(() => {
@@ -142,20 +128,24 @@ export default {
.reading-viewer-container {
width: 100%;
height: 100%;
::v-deep .dialog-container{
::v-deep .dialog-container {
margin-top: 50px !important;
width:75%;
height:80%;
width: 75%;
height: 80%;
}
::v-deep .el-dialog__body{
padding: 10px;
height: calc(100% - 70px);
}
.el-dialog__header{
::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{
.full-dialog-container {
::v-deep .is-fullscreen .el-dialog__body {
height: calc(100% - 70px);
}
}
@@ -130,18 +130,9 @@
<el-table-column prop="OriginalReReadingTask.SubjectCode" :label="$t('trials:rereadTrack:table:subjectCode')"
min-width="120" sortable="custom" show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="
scope.row.OriginalReReadingTask.MedicalNo &&
scope.row.OriginalReReadingTask.MedicalNo !==
scope.row.OriginalReReadingTask.SubjectCode
">
{{
`${scope.row.OriginalReReadingTask.SubjectCode}/${scope.row.OriginalReReadingTask.MedicalNo}`
}}
<span>
{{ getSubjectCode(scope.row.OriginalReReadingTask) }}
</span>
<span v-else>{{
scope.row.OriginalReReadingTask.SubjectCode
}}</span>
</template>
</el-table-column>
<!-- 任务名称 -->
@@ -385,7 +376,8 @@
</el-input>
</el-form-item>
<el-form-item :label="$t('trials:reviewTrack:dialog:backImpactList')" />
<el-table v-loading="loading" :data="InfluenceTaskList" stripe height="100" style="min-height:200px;max-height: 300px">
<el-table v-loading="loading" :data="InfluenceTaskList" stripe height="100"
style="min-height:200px;max-height: 300px">
<!-- 任务编号 -->
<el-table-column prop="TaskCode" :label="$t('trials:reviewTrack:table:taskCode')" min-width="100"
show-overflow-tooltip />
@@ -873,6 +865,16 @@ export default {
this.getTrialCriterionList()
},
methods: {
getSubjectCode(obj) {
let str = obj.SubjectCode
if (obj.MedicalNo && obj.MedicalNo !== obj.SubjectCode) {
str += `/${obj.MedicalNo}`
}
if (obj.BlindSubjectCode && obj.BlindSubjectCode !== obj.SubjectCode) {
str += `/${obj.BlindSubjectCode}`
}
return str
},
async auditImageBack() {
try {
console.log(this.form)
@@ -45,7 +45,7 @@
<el-input
v-model="scope.row.CDISCCode"
size="mini"
:disabled="scope.row.HasChildren || (scope.row.IsTableQuestion && exportInfo.CriterionType !== 0)"
:disabled="scope.row.HasChildren || (scope.row.IsTableQuestion && exportInfo.CriterionType !== 0 && exportInfo.CriterionGroup !== 0)"
v-show="!scope.row.IsGroup || !scope.row.HasChildren"
>
</el-input>
@@ -152,7 +152,7 @@ export default {
} else if ((this.exportInfo.CriterionGroup === 0 || this.exportInfo.CriterionType === 0 ) && item.Code === 1 && (row.HasChildren || row.IsTableQuestion)) {
// (1)
return true
} else if (item.Code === 8 && (row.HasChildren || (row.IsTableQuestion && this.exportInfo.CriterionType !== 0))) {
} else if ( item.Code === 8 && (row.HasChildren || (row.IsTableQuestion && this.exportInfo.CriterionType !== 0 && this.exportInfo.CriterionGroup !== 0) )) {
// else if (item.Code === 8 && (row.HasChildren || row.IsTableQuestion))
// CDISC
return true
@@ -340,7 +340,7 @@
<el-table-column fixed="right" :label="$t('common:action:action')" width="220">
<template slot-scope="scope">
<!-- 查看阅片结果 -->
<el-button :disabled="scope.row.ReadingTaskState !== 2 && scope.row.IsSubjectQuit" icon="el-icon-view"
<el-button :disabled="scope.row.ReadingTaskState !== 2" icon="el-icon-view"
circle :title="$t('trials:reviewTrack:action:viewResults')" @click="lookReadingResults(scope.row)" />
<!-- 申请重阅 -->
<el-button :disabled="scope.row.ReadingCategory !== 1 ||
@@ -120,7 +120,7 @@ name: "CustomizeReportPageUpload",
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${param.file.name}`, file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${param.file.name}`, file)
console.log(res)
this.fileList.push({ name: param.file.name, path: this.$getObjectName(res.url), url: this.$getObjectName(res.url)})
this.urls.push(this.$getObjectName(res.url))
@@ -1,36 +1,17 @@
<template>
<div v-loading="loading" class="ecrf-list-container">
<el-form
v-if="taskInfo"
ref="questions"
size="small"
:model="questionForm"
class="ecrf-form"
>
<!-- <FormItem
v-for="question of questions"
:key="question.Id"
:question="question"
:question-form="questionForm"
:reading-task-state="readingTaskState"
:visit-task-id="visitTaskId"
:calculation-list="calculationList"
@setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData"
/> -->
<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="isBaseline"
@resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData"
/>
<el-form v-if="taskInfo" ref="questions" size="small" :model="questionForm" class="ecrf-form">
<template v-if="taskInfo.CriterionType === 16">
<FormItem v-for="question of questions" :key="question.Id" :question="question" :question-form="questionForm"
:reading-task-state="readingTaskState" :visit-task-id="visitTaskId" :calculation-list="calculationList"
@setFormItemData="setFormItemData" @resetFormItemData="resetFormItemData" />
</template>
<template v-else>
<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="isBaseline"
@resetFormItemData="resetFormItemData" @setFormItemData="setFormItemData" />
</template>
<el-form-item v-if="readingTaskState < 2">
<div style="text-align:center;">
@@ -48,16 +29,11 @@
</el-form>
<!-- 签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
custom-class="base-dialog-wrapper"
>
<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>
<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>
@@ -67,19 +43,20 @@
<script>
import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, getQuestionCalculateRelation } from '@/api/trials'
import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, getQuestionCalculateRelation, verifyVisitTaskQuestions } from '@/api/trials'
import { setSkipReadingCache } from '@/api/reading'
import const_ from '@/const/sign-code'
import store from '@/store'
import { mapGetters } from 'vuex'
// import FormItem from './FormItem'
import FormItem from './FormItem'
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
SignForm,
FormItem
},
props: {
visitTaskInfo: {
@@ -216,7 +193,7 @@ export default {
try {
var answers = []
for (const k in this.questionForm) {
if (this.questionForm[k] instanceof Array) {} else {
if (this.questionForm[k] instanceof Array) { } else {
answers.push({ id: k, answer: this.questionForm[k] })
}
}
@@ -238,6 +215,8 @@ export default {
async handleSubmit() {
const valid = await this.$refs['questions'].validate()
if (!valid) return
await this.handleSave(false)
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
@@ -329,7 +308,7 @@ export default {
const o = list.find(v => {
return (
parseFloat(obj.val) >= parseFloat(v.gt) &&
parseFloat(obj.val) < parseFloat(v.lt)
parseFloat(obj.val) < parseFloat(v.lt)
)
})
answer = o ? o.label : null
@@ -347,15 +326,17 @@ export default {
}
</script>
<style lang="scss" scoped>
.ecrf-list-container{
min-height:400px;
.ecrf-list-container {
min-height: 400px;
color: #ddd;
.ecrf-form{
::v-deep .el-form-item__label{
.ecrf-form {
::v-deep .el-form-item__label {
color: #ddd;
}
}
::v-deep .el-table,
.el-table__expanded-cell {
background-color: #000;
@@ -369,35 +350,43 @@ export default {
color: #fff;
border-color: #444444;
}
::v-deep .el-table__body tr > td {
::v-deep .el-table__body tr>td {
background-color: #000 !important;
color: #fff;
border-color: #444444;
}
::v-deep .el-table__body tr:hover > td {
::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{
::v-deep .el-dialog {
background: #1e1e1e;
border: 1px solid #ddd;
color: #ddd;
.el-dialog__title{
color:#fff;
.el-dialog__title {
color: #fff;
}
.el-input .el-input__inner{
.el-input .el-input__inner {
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
.el-input.is-disabled .el-input__inner{
.el-input.is-disabled .el-input__inner {
background-color: #646464a1;
}
.el-form-item__label{
.el-form-item__label {
color: #dfdfdf
}
}
@@ -31,48 +31,12 @@
:title="$t('trials:reading:button:rotate')" @click.prevent="setToolActive('PlanarRotate')">
<svg-icon icon-class="rotate" class="svg-icon" />
</div>
<!--直线工具-->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Length' ? 'tool-item-active' : '']"
:title="$t('trials:nondicom-show:length')" @click.prevent="setAnnotateToolActive('Length')">
<svg-icon icon-class="length" class="svg-icon" />
</div>
<!-- 箭头工具 -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'ArrowAnnotate' ? 'tool-item-active' : '']"
:title="$t('trials:reading:button:arrowAnnotate')" @click.prevent="setAnnotateToolActive('ArrowAnnotate')">
<svg-icon icon-class="arrow" class="svg-icon" />
</div>
<!-- 角度工具 -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Angle' ? 'tool-item-active' : '']"
:title="$t('trials:dicom-show:Angle')" @click.prevent="setAnnotateToolActive('Angle')">
<svg-icon icon-class="cobb" class="svg-icon" />
</div>
<!-- 矩形工具 -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'RectangleROI' ? 'tool-item-active' : '']"
:title="$t('trials:dicom-show:RectangleRoi')" @click.prevent="setAnnotateToolActive('RectangleROI')">
<svg-icon icon-class="rectangle" class="svg-icon" />
</div>
<!-- 圆形工具 -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'CircleROI' ? 'tool-item-active' : '']"
:title="$t('trials:dicom-show:CircleROI')" @click.prevent="setAnnotateToolActive('CircleROI')">
<svg-icon icon-class="oval" class="svg-icon" />
</div>
<!-- 椭圆工具 -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'EllipticalROI' ? 'tool-item-active' : '']"
:title="$t('trials:dicom-show:EllipticalROI')" @click.prevent="setAnnotateToolActive('EllipticalROI')">
<svg-icon icon-class="elliptical" class="svg-icon" />
</div>
<!-- 自由曲线 -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'PlanarFreehandROI' ? 'tool-item-active' : '']"
:title="$t('trials:reading:button:planarFreehandROI')"
@click.prevent="setAnnotateToolActive('PlanarFreehandROI')">
<svg-icon icon-class="polygon" class="svg-icon" />
<div v-for="tool in tools" :key="tool.toolName"
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']"
:style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }"
:title="tool.disabledReason ? tool.disabledReason : $t(`${tool.i18nKey}`)"
@click.prevent="setAnnotateToolActive(tool.toolName)">
<svg-icon :icon-class="tool.icon" class="svg-icon" />
</div>
<!-- <div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'SplineROITool' ? 'tool-item-active' : '']"
@@ -81,9 +45,8 @@
>
<svg-icon icon-class="polygon" class="svg-icon" />
</div> -->
<div
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Eraser' ? 'tool-item-active' : '']"
<!--readingTaskState === 2 ? 'tool-disabled' : '',-->
<div :class="['tool-item', activeTool === 'Eraser' ? 'tool-item-active' : '']"
:title="$t('trials:dicom-show:Eraser')" @click.prevent="setAnnotateToolActive('Eraser')">
<svg-icon icon-class="clear" class="svg-icon" />
</div>
@@ -105,6 +68,50 @@
<div class="tool-item" :title="$t('trials:reading:button:reset')" @click.prevent="resetViewport">
<svg-icon icon-class="refresh" class="svg-icon" />
</div>
<!-- 更多:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" -->
<div v-if="criterionType === 0" :title="$t('trials:reading:button:more')" :class="['tool-item']"
@click.stop="showPanel($event)" @mouseleave="toolMouseout">
<div class="dropdown">
<div class="icon" data-tool="more">
<svg-icon icon-class="more" class="svg-icon" />
<i class="el-icon-arrow-down" style="color:#fff;" />
</div>
<div class="dropdown-content">
<!--v-if="readingTaskState < 2"-->
<ul style="width:100px;">
<li v-for="i in customizeStandardsNoneDicom" :key="i.toolName" style="text-align:left;">
<a href="#" @click.prevent="setAnnotateToolActive(i.toolName)">
<svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" />
{{ $t(i.i18nKey) }}
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="tool-item" :title="$t('trials:reading:button:upload')"
v-if="trialCriterion.ImageUploadEnum > 0 && readingTaskState < 2" v-hasPermi="['role:ir']">
<div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('upload')">
<i class="el-icon-upload2 svg-icon" />
</div>
</div>
</div>
<div v-if="trialCriterion.ImageDownloadEnum > 0" v-hasPermi="[
'role:ir',
'role:mim',
'role:mc',
'role:pm',
'role:apm',
'role:ea',
'role:qa',
]" class="tool-item" :title="$t('trials:reading:button:download')">
<div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('download')">
<i class="el-icon-download svg-icon" />
</div>
</div>
</div>
</div>
<div>
@@ -217,10 +224,16 @@
:close-on-click-modal="false" :title="personalConfigDialog.title" width="600px">
<Others />
</el-dialog>
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
<download-dicom-and-nonedicom v-if="downloadImageVisible" :subject-id="uploadSubjectId"
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :task-id="taskId"
:visible.sync="downloadImageVisible" />
</div>
</template>
<script>
import { addNoneDicomMark, deleteTrialFileType } from '@/api/trials'
import { addNoneDicomMark, deleteTrialFileType, getCriterionReadingInfo } from '@/api/trials'
import {
RenderingEngine,
Enums,
@@ -242,6 +255,9 @@ import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others
const { ViewportType } = Enums
const renderingEngineId = 'myRenderingEngine'
import LengthscaleTool from "../tools/LengthscaleTool"
import { getCustomizeStandardsNoneDicomTools, config } from '@/views/trials/trials-panel/reading/dicoms3D/components/toolConfig'
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
const {
ToolGroupManager,
Enums: csToolsEnums,
@@ -263,7 +279,11 @@ const {
const { MouseBindings, Events: toolsEvents } = csToolsEnums
export default {
name: 'ImageViewer',
components: { Others },
components: {
Others,
downloadDicomAndNonedicom,
uploadDicomAndNonedicom,
},
props: {
relatedStudyInfo: {
type: Object,
@@ -306,7 +326,23 @@ export default {
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
{ pattern: /^\d+$/, message: this.$t('trials:noneDicom:message:msg3'), trigger: ['blur', 'change'] }
]
}
},
customizeStandardsNoneDicom: [],
tools: [],
criterionType: null,
//
downloadImageVisible: false,
uploadImageVisible: false,
uploadSubjectId: null,
uploadSubjectCode: null,
uploadTrialCriterion: {},
uploadStatus: 'upload',
taskId: '',
isReadingTaskViewInOrder: null,
trialCriterion: {}
}
},
computed: {
@@ -358,6 +394,14 @@ export default {
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.readingTaskState = this.taskInfo.ReadingTaskState
this.criterionType = this.taskInfo.CriterionType
if (this.criterionType === 0) {
this.tools = getCustomizeStandardsNoneDicomTools(this.taskInfo.ReadingToolList)
const toolNames = this.tools.map(i => i.toolName)
this.customizeStandardsNoneDicom = config.customizeStandardsNoneDicom.filter(item => !toolNames.includes(item.toolName))
} else {
this.tools = config.customizeStandardsNoneDicom
}
if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
this.rows = 1
this.cols = 2
@@ -382,11 +426,36 @@ export default {
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.initLoader()
window.addEventListener('message', this.handleIframeMessage)
this.getTrialCriterion()
},
beforeDestroy() {
window.removeEventListener('message', this.handleIframeMessage)
},
methods: {
getTrialCriterion() {
getCriterionReadingInfo({
TrialId: this.$route.query.trialId,
TrialReadingCriterionId: this.$route.query.TrialReadingCriterionId
})
.then((res) => {
this.trialCriterion = res.Result
})
.catch(() => { })
},
openUploadImage(status) {
this.taskId = this.taskInfo.VisitTaskId
this.uploadSubjectCode = localStorage.getItem("subjectCode")
this.uploadSubjectId = localStorage.getItem("subjectId")
this.uploadTrialCriterion = this.trialCriterion
this.uploadStatus = status
this[`${status}ImageVisible`] = true
},
showPanel(e) {
e.currentTarget.firstChild.lastChild.style.display = 'block'
},
toolMouseout(e) {
e.currentTarget.firstChild.lastChild.style.display = 'none'
},
//
async initLoader() {
registerWebImageLoader(imageLoader)
@@ -784,7 +853,8 @@ export default {
},
//
setAnnotateToolActive(toolName) {
if (this.readingTaskState === 2) return
// if (this.readingTaskState === 2) return
if (this.readingTaskState === 2 && toolName === 'Lengthscale') return
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
if (i === -1) return
if (this.viewportInfos[i].taskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
@@ -851,25 +921,41 @@ export default {
)
},
async annotationRemovedListener(e) {
if (this.readingTaskState === 2) return
const { annotation } = e.detail
if (!annotation) return
if (annotation.annotationId) {
await deleteTrialFileType(annotation.annotationId)
} else {
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
}
const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
viewport.render()
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
const imageId = annotation.metadata.referencedImageId
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
const fileList = this.viewportInfos[i].fileList
const fileIndex = fileList.findIndex(f => f.Path === path)
if (annotation.metadata.toolName === 'Lengthscale') {
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null })
try {
if (!annotation) return
if (this.readingTaskState === 2 && !annotation.annotationId) {
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
return false
}
if (this.readingTaskState === 2) {
const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg
}
if (annotation.annotationId) {
await deleteTrialFileType(annotation.annotationId)
} else {
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
}
const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
viewport.render()
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
const imageId = annotation.metadata.referencedImageId
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
const fileList = this.viewportInfos[i].fileList
const fileIndex = fileList.findIndex(f => f.Path === path)
if (annotation.metadata.toolName === 'Lengthscale') {
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null })
}
} catch (e) {
cornerstoneTools.annotation.state.addAnnotation(annotation)
const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
viewport.render()
console.log(e)
}
},
async annotationModifiedListener(e) {
console.log('Modified')
@@ -896,6 +982,7 @@ export default {
}
this.setToolsPassive()
}
if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
const params = {
id: annotation.annotationId,
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
@@ -938,7 +1025,7 @@ export default {
this.setToolsPassive()
return
}
if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
const params = {
id: '',
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
@@ -973,6 +1060,7 @@ export default {
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
return
}
if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
const params = {
id: '',
visitTaskId: this.form.annotationObj.visitTaskId,
@@ -1310,6 +1398,43 @@ export default {
cursor: default !important;
}
.dropdown {
position: relative;
display: inline-block;
.text {
text-align: center;
}
}
.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 a:hover {
background-color: #727272;
}
}
.none-dicom-viewer {
display: flex;
flex-direction: column;
@@ -12,7 +12,7 @@
<!-- 文件 -->
<el-form-item :label="$t('trials:attachment:form:file')">
<div class="upload-container">
<el-upload class="upload-demo" action accept=".pdf,.mp4" :before-upload="beforeUpload"
<el-upload class="upload-demo" action accept=".pdf" :before-upload="beforeUpload"
:http-request="handleUploadFile" :on-remove="handleRemoveFile" :show-file-list="true" :file-list="fileList"
:limit="1" :on-exceed="handleExceed" :disabled="form.FileTypeId === ''">
<el-button size="small" type="primary" :disabled="form.FileTypeId === '' || saveBtnLoading"
@@ -218,7 +218,7 @@ export default {
},
// pdf
checkFileSuffix(fileName) {
var typeArr = ['pdf', 'mp4']
var typeArr = ['pdf']
var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase()
if (typeArr.indexOf(extendName) !== -1) {
return true
@@ -93,9 +93,12 @@
<el-col :span="24">
<el-form-item :label="$t('trials:emailManageCfg:table:CriterionTypeEnum')"
v-if="form.CriterionTypeList && form.CriterionTypeList.length > 0" prop="CriterionTypeList">
<el-select disabled v-model="form.CriterionTypeList" clearable class="mr" multiple>
<el-option v-for="item of $d.CriterionType" :key="`CriterionType${item.label}`" :label="item.label"
:value="item.value" />
<el-select v-model="form.CriterionTypeList" clearable class="mr" multiple>
<template v-for="item of $d.CriterionType">
<el-option :key="`CriterionType${item.label}`" :label="item.label" :value="item.value"
v-if="form.SysCriterionTypeList.includes(item.value)" />
</template>
</el-select>
</el-form-item>
</el-col>
@@ -196,6 +199,7 @@ export default {
IsAutoSend: true,
CriterionTypeEnum: null,
CriterionTypeList: [],
SysCriterionTypeList: [],
FromEmail: '',
FromName: '',
AuthorizationCode: '',
@@ -11,9 +11,9 @@
</el-form-item>
<el-form-item v-if="isDistinguishCriteria" style="margin-bottom: 10px"
:label="$t('trials:reviewTrack:table:criterionName')">
<el-select v-model="searchData.TrialReadingCriterionId" clearable style="width: 120px">
<el-select v-model="searchData.CriterionTypeEnum" clearable style="width: 120px">
<el-option v-for="item of trialCriterionList"
:key="'TrialReadingCriterionId' + item.TrialReadingCriterionId" :value="item.TrialReadingCriterionId"
:key="'TrialReadingCriterionId' + item.TrialReadingCriterionId" :value="item.CriterionType"
:label="item.TrialReadingCriterionName" />
</el-select>
</el-form-item>
@@ -143,6 +143,7 @@ export default {
},]
},
NODE_ENV: process.env.NODE_ENV,
VUE_APP_OSS_PATH: process.env.VUE_APP_OSS_PATH,
}
},
// watch: {
@@ -151,10 +152,20 @@ export default {
// }
// },
created() {
if(this.NODE_ENV === 'production'){
if(this.VUE_APP_OSS_PATH === '/uat/dist'){
this.form= {
EmailFromEmail: 'uat@extimaging.com',
EmailFromName: 'Uat IRC Imaging System',
EmailAuthorizationCode: 'SHzyyl2021',
EmailSMTPServerAddress: 'smtp.qiye.aliyun.com',
EmailSMTPServerPort: 465,
IsConfigureEmail: true
};
}
if(this.VUE_APP_OSS_PATH === '/test/dist'){
this.form= {
EmailFromEmail: 'test@extimaging.com',
EmailFromName: 'Test_IRC',
EmailFromName: 'Test IRC Imaging System',
EmailAuthorizationCode: 'SHzyyl2021',
EmailSMTPServerAddress: 'smtp.qiye.aliyun.com',
EmailSMTPServerPort: 465,
@@ -114,6 +114,9 @@ export default {
callback(new Error(this.$t('common:ruleMessage:specify')))
} else {
var reg = /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
if (this.$reg().EmailRegexStr) {
reg = new RegExp(this.$reg().EmailRegexStr)
}
if (this.form.Email && reg.test(this.form.Email)) {
this.sendDisabled = false
callback()
File diff suppressed because it is too large Load Diff
@@ -1,350 +1,182 @@
<template>
<div class="reading-rule-config-form">
<!-- 配置信息表单 -->
<el-form
ref="readingRulesForm"
v-loading="loading"
:model="form"
style="width: 800px"
:rules="rules"
label-width="340px"
size="small"
>
<el-form ref="readingRulesForm" v-loading="loading" :model="form" style="width: 800px" :rules="rules"
label-width="340px" size="small">
<!-- 阅片平台 -->
<el-form-item
:label="$t('trials:processCfg:form:imagePlatform')"
prop="ImagePlatform"
>
<el-radio-group
v-model="form.ImagePlatform"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-form-item :label="$t('trials:processCfg:form:imagePlatform')" prop="ImagePlatform">
<el-radio-group v-model="form.ImagePlatform" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<template v-if="isUSA">
<el-radio
v-for="item of $d.ImagePlatformUSA"
:key="item.id"
:label="item.value"
>
<el-radio v-for="item of $d.ImagePlatformUSA" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</template>
<template v-else>
<el-radio
v-for="item of $d.ImagePlatform"
:key="item.id"
:label="item.value"
>
<el-radio v-for="item of $d.ImagePlatform" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</template>
</el-radio-group>
</el-form-item>
<!-- 阅片工具 -->
<el-form-item
v-if="form.ImagePlatform === 3"
:label="$t('trials:readingUnit:readingRules:title:readingTool')"
prop="ReadingTool"
>
<el-radio-group
v-model="form.ReadingTool"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.ReadingTool"
:key="item.id"
:label="item.value"
>
<el-form-item v-if="form.ImagePlatform === 3" :label="$t('trials:readingUnit:readingRules:title:readingTool')"
prop="ReadingTool">
<el-radio-group v-model="form.ReadingTool" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])" @input="handleReadingToolInput">
<el-radio v-for="item of $d.ReadingTool" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 测量工具 -->
<el-form-item
v-if="CriterionType === 0 && (form.ReadingTool === 0 || form.ReadingTool === 2 ) && form.ReadingVersionEnum === 1"
:label="$t('trials:readingUnit:readingRules:title:measureTool')"
>
<el-checkbox-group
v-model="form.ReadingToolList"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-checkbox
v-for="tool in tools"
:key="tool.toolName"
:label="tool.toolName"
name="ReadingToolList"
>
v-if="CriterionType === 0 && (form.ReadingTool === 0 || form.ReadingTool === 1 || form.ReadingTool === 2) && form.ReadingVersionEnum === 1"
:label="$t('trials:readingUnit:readingRules:title:measureTool')">
<el-checkbox-group v-model="form.ReadingToolList" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-checkbox v-for="tool in tools" :key="tool.toolName" :label="tool.toolName" name="ReadingToolList">
{{ $t(`${tool.i18nKey}`) }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<!--检查类型筛选-->
<el-form-item
:label="$t('trials:processCfg:form:IsImageFilter')"
prop="IsImageFilter"
>
<el-radio-group
v-model="form.IsImageFilter"
@input="IsImageFilterChange"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
:label="item.value"
v-for="item in $d.YesOrNoModality"
:key="item.id"
>
<el-form-item :label="$t('trials:processCfg:form:IsImageFilter')" prop="IsImageFilter">
<el-radio-group v-model="form.IsImageFilter" @input="IsImageFilterChange" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio :label="item.value" v-for="item in $d.YesOrNoModality" :key="item.id">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 影像模态 -->
<el-form-item
:label="$t('trials:readingUnit:readingRules:title:CriterionModalitys')"
prop="CriterionModalitys"
style="position: relative"
v-if="form.IsImageFilter"
>
<el-checkbox-group
v-model="CriterionModalitys"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-form-item :label="$t('trials:readingUnit:readingRules:title:CriterionModalitys')" prop="CriterionModalitys"
style="position: relative" v-if="form.IsImageFilter">
<el-checkbox-group v-model="CriterionModalitys" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-checkbox v-for="item in modalityList" :label="item" :key="item">{{
item
}}</el-checkbox>
</el-checkbox-group>
<el-button
v-if="
!isConfirm &&
hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
size="mini"
style="position: absolute; top: 0; right: -40px"
@click.stop="handleCheckAllChange"
type="success"
>{{
<el-button v-if="
!isConfirm &&
hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" size="mini" style="position: absolute; top: 0; right: -40px" @click.stop="handleCheckAllChange"
type="success">{{
CriterionModalitys.length === modalityList.length
? $t(
'trials:readingUnit:readingRules:title:CriterionModalitysCancel'
)
'trials:readingUnit:readingRules:title:CriterionModalitysCancel'
)
: $t(
'trials:readingUnit:readingRules:title:CriterionModalitysAll'
)
}}</el-button
>
'trials:readingUnit:readingRules:title:CriterionModalitysAll'
)
}}</el-button>
</el-form-item>
<el-form-item
:label="$t('trials:consistencyAnalysis:table:isUrgent')"
prop="DigitPlaces"
>
<el-radio-group
v-model="form.IsUrgent"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="item.id"
:label="item.value"
>
<el-form-item :label="$t('trials:consistencyAnalysis:table:isUrgent')" prop="DigitPlaces">
<el-radio-group v-model="form.IsUrgent" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.YesOrNo" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 存在附加评估 -->
<el-form-item
:label="$t('trials:processCfg:form:IsAdditionalAssessment')"
prop="IsAdditionalAssessment"
v-if="CriterionType === 1"
>
<el-radio-group
v-model="form.IsAdditionalAssessment"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`IsAdditionalAssessment${item.value}`"
:label="item.value"
>
<el-form-item :label="$t('trials:processCfg:form:IsAdditionalAssessment')" prop="IsAdditionalAssessment"
v-if="CriterionType === 1">
<el-radio-group v-model="form.IsAdditionalAssessment" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.YesOrNo" :key="`IsAdditionalAssessment${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 阅片任务生成方式 -->
<el-form-item
:label="$t('trials:processCfg:form:IsAutoCreate')"
prop="IsAutoCreate"
>
<el-radio-group
v-model="form.IsAutoCreate"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.YesOrNoAuto"
:key="`IsAutoCreate${item.value}`"
:label="item.value"
>
<el-form-item :label="$t('trials:processCfg:form:IsAutoCreate')" prop="IsAutoCreate">
<el-radio-group v-model="form.IsAutoCreate" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.YesOrNoAuto" :key="`IsAutoCreate${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!--阅片模式-->
<el-form-item
:label="$t('trials:processCfg:form:readingType')"
prop="ReadingType"
>
<el-radio-group
v-model="form.ReadingType"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
@change="
<el-form-item :label="$t('trials:processCfg:form:readingType')" prop="ReadingType">
<el-radio-group v-model="form.ReadingType" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" @change="
() => {
form.IsArbitrationReading = false
}
"
>
<el-radio
v-for="item of $d.ReadingMethod"
:key="item.id"
:label="item.value"
>
">
<el-radio v-for="item of $d.ReadingMethod" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!--仲裁阅片-->
<el-form-item
:label="$t('trials:processCfg:form:ad')"
prop="IsArbitrationReading"
>
<el-radio-group
v-model="form.IsArbitrationReading"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
form.ReadingType !== 2
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`IsArbitrationReading${item.value}`"
:label="item.value"
>
<el-form-item :label="$t('trials:processCfg:form:ad')" prop="IsArbitrationReading">
<el-radio-group v-model="form.IsArbitrationReading" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
form.ReadingType !== 2
">
<el-radio v-for="item of $d.YesOrNo" :key="`IsArbitrationReading${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 是否阅片期 -->
<el-form-item
:label="$t('trials:readingUnit:readingRules:title:isReadingPeriod')"
prop="IsReadingPeriod"
>
<el-radio-group
v-model="form.IsReadingPeriod"
:disabled="
isConfirm ||
IsMustGlobalReading ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
@change="
<el-form-item :label="$t('trials:readingUnit:readingRules:title:isReadingPeriod')" prop="IsReadingPeriod">
<el-radio-group v-model="form.IsReadingPeriod" :disabled="isConfirm ||
IsMustGlobalReading ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" @change="
(v) => {
if (!v) {
form.IsGlobalReading = v
form.IsOncologyReading = v
}
}
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`IsReadingPeriod${item.value}`"
:label="item.value"
>
">
<el-radio v-for="item of $d.YesOrNo" :key="`IsReadingPeriod${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="$t('trials:processCfg:form:global')"
prop="IsGlobalReading"
>
<el-radio-group
v-model="form.IsGlobalReading"
:disabled="
!form.IsReadingPeriod ||
IsMustGlobalReading ||
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`IsGlobalReading${item.value}`"
:label="item.value"
>
<el-form-item :label="$t('trials:processCfg:form:global')" prop="IsGlobalReading">
<el-radio-group v-model="form.IsGlobalReading" :disabled="!form.IsReadingPeriod ||
IsMustGlobalReading ||
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.YesOrNo" :key="`IsGlobalReading${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="$t('trials:processCfg:form:clinical')"
prop="IsOncologyReading"
>
<el-radio-group
v-model="form.IsOncologyReading"
:disabled="
!form.IsReadingPeriod ||
!form.IsSystemSetOncology ||
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`IsOncologyReading${item.value}`"
:label="item.value"
>
<el-form-item :label="$t('trials:processCfg:form:clinical')" prop="IsOncologyReading">
<el-radio-group v-model="form.IsOncologyReading" :disabled="!form.IsReadingPeriod ||
!form.IsSystemSetOncology ||
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.YesOrNo" :key="`IsOncologyReading${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 任务展示方式 -->
<el-form-item
:label="
$t('trials:readingUnit:readingRules:title:readingTaskViewInOrder')
"
prop="IsReadingTaskViewInOrder"
>
<el-radio-group
v-model="form.IsReadingTaskViewInOrder"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
@change="
<el-form-item :label="$t('trials:readingUnit:readingRules:title:readingTaskViewInOrder')
" prop="IsReadingTaskViewInOrder">
<el-radio-group v-model="form.IsReadingTaskViewInOrder" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" @change="
(v) => {
form.ImageDownloadEnum = 0
form.ImageUploadEnum = 0
@@ -357,254 +189,143 @@
form.ReadingTaskViewEnum = 2
}
}
"
>
<el-radio
v-for="item of $d.IsReadingTaskViewInOrder"
:key="'IsReadingTaskViewInOrder' + item.value"
:label="item.value"
>
">
<el-radio v-for="item of $d.IsReadingTaskViewInOrder" :key="'IsReadingTaskViewInOrder' + item.value"
:label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 任务组织级别 -->
<el-form-item
:label="$t('trials:readingUnit:readingRules:title:readingTaskViewEnum')"
prop="ReadingTaskViewEnum"
>
<el-radio-group
v-model="form.ReadingTaskViewEnum"
:disabled="
isConfirm ||
!!!isReadingTaskViewInOrder ||
!!isReadingTaskViewInOrder ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.ReadingTaskViewEnum"
:key="item.id"
:label="item.value"
>
<el-form-item :label="$t('trials:readingUnit:readingRules:title:readingTaskViewEnum')" prop="ReadingTaskViewEnum">
<el-radio-group v-model="form.ReadingTaskViewEnum" :disabled="isConfirm ||
!!!isReadingTaskViewInOrder ||
!!isReadingTaskViewInOrder ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.ReadingTaskViewEnum" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!--支持影像下载v-if="CriterionType === 0"-->
<el-form-item
:label="$t('trials:processCfg:form:ImageDownloadEnum')"
prop="ImageDownloadEnum"
>
<el-radio-group
v-model="form.ImageDownloadEnum"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.ImageDownloadEnum"
:key="item.id"
:label="item.value"
:disabled="
(form.IsReadingTaskViewInOrder === 1 ||
form.IsReadingTaskViewInOrder === 0) &&
item.value === 1
"
>
<el-form-item :label="$t('trials:processCfg:form:ImageDownloadEnum')" prop="ImageDownloadEnum">
<el-radio-group v-model="form.ImageDownloadEnum" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.ImageDownloadEnum" :key="item.id" :label="item.value" :disabled="(form.IsReadingTaskViewInOrder === 1 ||
form.IsReadingTaskViewInOrder === 0) &&
item.value === 1
">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!--支持上传DICOM影像-->
<el-form-item
:label="$t('trials:processCfg:form:ImageUploadEnum')"
prop="ImageUploadEnum"
>
<el-radio-group
v-model="form.ImageUploadEnum"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.ImageUploadEnum"
:key="item.id"
:label="item.value"
:disabled="
(form.IsReadingTaskViewInOrder === 1 ||
form.IsReadingTaskViewInOrder === 0) &&
item.value === 1
"
>
<el-form-item :label="$t('trials:processCfg:form:ImageUploadEnum')" prop="ImageUploadEnum">
<el-radio-group v-model="form.ImageUploadEnum" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.ImageUploadEnum" :key="item.id" :label="item.value" :disabled="(form.IsReadingTaskViewInOrder === 1 ||
form.IsReadingTaskViewInOrder === 0) &&
item.value === 1
">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- IR阅片页面是否显示受试者信息 -->
<el-form-item
:label="
$t('trials:readingUnit:readingRules:title:isReadingShowSubjectInfo')
"
prop="IsReadingShowSubjectInfo"
>
<el-radio-group
v-model="form.IsReadingShowSubjectInfo"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
!!form.IsReadingTaskViewInOrder
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="'IsReadingShowSubjectInfo' + item.value"
:label="item.value"
>
<el-form-item :label="$t('trials:readingUnit:readingRules:title:isReadingShowSubjectInfo')
" prop="IsReadingShowSubjectInfo">
<el-radio-group v-model="form.IsReadingShowSubjectInfo" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
!!form.IsReadingTaskViewInOrder
">
<el-radio v-for="item of $d.YesOrNo" :key="'IsReadingShowSubjectInfo' + item.value" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- IR阅片页面是否可以查看既往任务结果 -->
<el-form-item
:label="
$t(
'trials:readingUnit:readingRules:title:isReadingShowPreviousResults'
)
"
prop="IsReadingShowPreviousResults"
>
<el-radio-group
v-model="form.IsReadingShowPreviousResults"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
!!form.IsReadingTaskViewInOrder
"
@change="
<el-form-item :label="$t(
'trials:readingUnit:readingRules:title:isReadingShowPreviousResults'
)
" prop="IsReadingShowPreviousResults">
<el-radio-group v-model="form.IsReadingShowPreviousResults" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
!!form.IsReadingTaskViewInOrder
" @change="
(v) => {
if (!v) {
form.IseCRFShowInDicomReading = true
}
}
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="'IsReadingShowPreviousResults' + item.value"
:label="item.value"
>
">
<el-radio v-for="item of $d.YesOrNo" :key="'IsReadingShowPreviousResults' + item.value" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- eCRF是否显示在影像阅片页面 -->
<el-form-item
:label="
$t('trials:readingUnit:readingRules:title:isECRFShowInDicomReading')
"
prop="IseCRFShowInDicomReading"
>
<el-radio-group
v-model="form.IseCRFShowInDicomReading"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
!form.IsReadingShowPreviousResults
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="item.label"
:label="item.value"
>
<el-form-item :label="$t('trials:readingUnit:readingRules:title:isECRFShowInDicomReading')
" prop="IseCRFShowInDicomReading">
<el-radio-group v-model="form.IseCRFShowInDicomReading" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
!form.IsReadingShowPreviousResults
">
<el-radio v-for="item of $d.YesOrNo" :key="item.label" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 修约小数位数 -->
<el-form-item
:label="$t('trials:processCfg:form:digitPlaces')"
prop="DigitPlaces"
>
<el-radio-group
v-model="form.DigitPlaces"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-radio
v-for="item of $d.DigitPlaces"
:key="item.id"
:label="item.value"
>
<el-form-item :label="$t('trials:processCfg:form:digitPlaces')" prop="DigitPlaces">
<el-radio-group v-model="form.DigitPlaces" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-radio v-for="item of $d.DigitPlaces" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="
$t(
'trials:trials-panel:setting:reading-unit:TrialCriterionAdditionalAssessmentTypeList'
)
"
v-if="
<el-form-item :label="$t(
'trials:trials-panel:setting:reading-unit:TrialCriterionAdditionalAssessmentTypeList'
)
" v-if="
form.IsAdditionalAssessment &&
form.TrialCriterionAdditionalAssessmentTypeList &&
form.TrialCriterionAdditionalAssessmentTypeList.length > 0
"
>
">
</el-form-item>
<template v-for="item of form.TrialCriterionAdditionalAssessmentTypeList">
<el-form-item
:key="item.Id"
:prop="`AdditionalAssessmentType${item.Id}`"
:rules="[
{
required: true,
message: $t('common:ruleMessage:select'),
trigger: ['blur'],
},
]"
:label="
$fd('AdditionalAssessmentType', item.AdditionalAssessmentType)
"
v-if="
<el-form-item :key="item.Id" :prop="`AdditionalAssessmentType${item.Id}`" :rules="[
{
required: true,
message: $t('common:ruleMessage:select'),
trigger: ['blur'],
},
]" :label="$fd('AdditionalAssessmentType', item.AdditionalAssessmentType)
" v-if="
form.IsAdditionalAssessment &&
form.TrialCriterionAdditionalAssessmentTypeList
"
>
<el-radio-group
v-model="item.IsSelected"
:disabled="
isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
@change="
">
<el-radio-group v-model="item.IsSelected" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" @change="
(v) => {
$set(form, 'AdditionalAssessmentType' + item.Id, v)
}
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`AdditionalAssessmentType${item.value}`"
:label="item.value"
>
">
<el-radio v-for="item of $d.YesOrNo" :key="`AdditionalAssessmentType${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</template>
<el-form-item
v-if="
!isConfirm &&
hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
"
>
<el-form-item v-if="
!isConfirm &&
hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<!-- 保存 -->
<el-button type="primary" @click="handleSave(true)">
{{ $t('common:button:save') }}
@@ -839,7 +560,7 @@ export default {
if (this.CriterionType === 0) {
this.tools = [...config.customizeStandards]
}
this.initPage()
},
computed: {
@@ -856,6 +577,17 @@ export default {
},
},
methods: {
//
handleReadingToolInput(val) {
this.form.ReadingToolList = []
if (this.CriterionType !== 0) return this.tools = []
if (val === 0 || val === 2) {
this.tools = [...config.customizeStandards]
}
if (val === 1) {
this.tools = [...config.customizeStandardsNoneDicom]
}
},
//
IsImageFilterChange(data) {
if (data) {
@@ -893,6 +625,14 @@ export default {
this.form[k] = res.Result[k]
}
}
if (this.CriterionType === 0) {
if (this.form.ReadingTool === 0 || this.form.ReadingTool === 2) {
this.tools = [...config.customizeStandards]
}
if (this.form.ReadingTool === 1) {
this.tools = [...config.customizeStandardsNoneDicom]
}
}
this.CriterionModalitys = this.form.CriterionModalitys
? this.form.CriterionModalitys.split('|')
: []
@@ -918,7 +658,7 @@ export default {
this.$emit('setOncologyReading', res.Result.IsOncologyReading)
this.$emit('setDigitPlaces', res.Result.DigitPlaces)
this.$emit('setReadingTools', res.Result.ReadingToolList)
if (res.Result.ReadingType === 1) {
this.$emit('setArbitrationReading', false)
}
@@ -109,6 +109,25 @@
<el-input-number v-model="form.ChangeDefalutDays" controls-position="right" :min="0"
:disabled="form.IsTrialBasicLogicConfirmed && !isEdit" />
</el-form-item>
<!-- 自动跳转下一个任务 -->
<el-form-item :label="$t('trials:logincCfg:form:IsIQCAutoNextTask')" prop="IsIQCAutoNextTask" v-if="showMore">
<el-radio-group v-model="form.IsIQCAutoNextTask" :disabled="form.IsTrialBasicLogicConfirmed && !isEdit"
@input="handleIsIQCAutoNextTaskChange">
<el-radio v-for="item of $d.YesOrNo" :key="`IsIQCAutoNextTask${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 自动任务是否区分类型 -->
<el-form-item :label="$t('trials:logincCfg:form:IsIQCAutoTaskDistinguishType')"
prop="IsIQCAutoTaskDistinguishType" v-if="form.IsIQCAutoNextTask && showMore">
<el-radio-group v-model="form.IsIQCAutoTaskDistinguishType"
:disabled="form.IsTrialBasicLogicConfirmed && !isEdit">
<el-radio v-for="item of $d.YesOrNo" :key="`IsIQCAutoTaskDistinguishType${item.value}`" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<div :class="{ showMore: true, isCheck: showMore }" @click.stop="showMore = !showMore">
<i class="el-icon-arrow-down"></i>
@@ -507,7 +526,9 @@ export default {
TrialObjectNameList: [],
TrialObjectNameConfigStr: '',
StudyUseModalityList: [],
StudyUseStudyNameList: []
StudyUseStudyNameList: [],
IsIQCAutoNextTask: false,
IsIQCAutoTaskDistinguishType: false
// ClinicalDataSetNames: [],
// ClinicalDataTrialSetIds: [],
// ClinicalDataSetNamesStr: ''
@@ -714,6 +735,9 @@ export default {
},
},
methods: {
handleIsIQCAutoNextTaskChange(val) {
if (!val) this.form.IsIQCAutoTaskDistinguishType = false
},
selectableStudyName(row) {
let select = this.trialStudyNameList.filter((item) => item.IsChoose)
return (!this.form.StudyUseStudyNameList.includes(row.Name) && !this.form.StudyUseStudyNameList.includes(row.EnName)) || (!select.includes(row) && (this.form.StudyUseStudyNameList.includes(row.EnName) || this.form.StudyUseStudyNameList.includes(row.Name)))
@@ -1234,6 +1258,16 @@ export default {
NewVal: this.form.ChangeDefalutDays,
OldVal: this.initialForm.ChangeDefalutDays,
},
{
Name: this.$t('trials:logincCfg:form:IsIQCAutoNextTask'),
NewVal: this.$fd('YesOrNo', this.form.IsIQCAutoNextTask),
OldVal: this.$fd('YesOrNo', this.initialForm.IsIQCAutoNextTask),
},
{
Name: this.$t('trials:logincCfg:form:IsIQCAutoTaskDistinguishType'),
NewVal: this.$fd('YesOrNo', this.form.IsIQCAutoTaskDistinguishType),
OldVal: this.$fd('YesOrNo', this.initialForm.IsIQCAutoTaskDistinguishType),
},
// {
// Name: '',
// NewVal: this.form.ClinicalDataSetNames.join(', '),
@@ -230,7 +230,7 @@
{{ $t('trials:auditRecord:title:viewDetail') }}
</a>
<viewer
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.oldValue && scope.row.oldValue !== '--'"
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage') && scope.row.oldValue && scope.row.oldValue !== '--'"
:ref="`${scope.row.oldValue instanceof Array ? scope.row.oldValue[0] : scope.row.oldValue}_modelCfg`"
:images="imagesList">
<!-- 查看图片 -->
@@ -238,13 +238,17 @@
$t('trials:auditRecord:title:viewImage') }}{{ scope.row.oldValue
instanceof Array ? `(${scope.row.oldValue.length})` : '' }}</span>
<template v-for="item of scope.row.oldValue">
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item"
v-show="false" crossorigin="anonymous" alt="">
<img v-if="scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage'" :key="item"
:src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
</template>
<img v-if="scope.row.DataType === 'Image'" :src="OSSclientConfig.basePath + scope.row.oldValue"
v-show="false" crossorigin="anonymous" alt="">
</viewer>
<div v-else-if="scope.row.DataType === 'Dialog'" v-html="scope.row.oldValue"></div>
<el-button v-else-if="isFile(scope.row.oldValue)" type="text" size="small"
@click.stop="download(scope.row.oldValue)">
{{ $t('common:button:download') }}
</el-button>
<span v-else>
{{ scope.row.oldValue }}
</span>
@@ -268,7 +272,7 @@
{{ $t('trials:auditRecord:title:viewDetail') }}
</a>
<viewer
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.newValue && scope.row.newValue !== '--'"
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage') && scope.row.newValue && scope.row.newValue !== '--'"
:ref="`${scope.row.newValue instanceof Array ? scope.row.newValue[0] : scope.row.newValue}_modelcfg`"
:images="imagesList">
<!-- 查看图片 -->
@@ -276,14 +280,18 @@
$t('trials:auditRecord:title:viewImage') }}{{ scope.row.newValue
instanceof Array ? `(${scope.row.newValue.length})` : '' }}</span>
<template v-for="item of scope.row.newValue">
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item"
v-show="false" crossorigin="anonymous" alt="">
<img v-if="scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage'" :key="item"
:src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
</template>
<img v-if="scope.row.DataType === 'Image'" :src="OSSclientConfig.basePath + scope.row.newValue"
v-show="false" crossorigin="anonymous" alt="">
<!-- <img :src="scope.row.newValue" v-show="false" crossorigin="anonymous" alt="">-->
</viewer>
<div v-else-if="scope.row.DataType === 'Dialog'" v-html="scope.row.newValue"></div>
<el-button v-else-if="isFile(scope.row.newValue)" type="text" size="small"
@click.stop="download(scope.row.newValue)">
{{ $t('common:button:download') }}
</el-button>
<span v-else>{{ scope.row.newValue }}</span>
</span>
</template>
@@ -476,7 +484,7 @@
{{ $t('trials:auditRecord:title:viewDetail') }}
</a>
<viewer
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.oldValue && scope.row.oldValue !== '--'"
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage') && scope.row.oldValue && scope.row.oldValue !== '--'"
:ref="scope.row.oldValue instanceof Array ? scope.row.oldValue[0] : scope.row.oldValue"
:images="imagesList">
<!-- 查看图片 -->
@@ -484,8 +492,8 @@
$t('trials:auditRecord:title:viewImage') }}{{ scope.row.oldValue
instanceof Array ? `(${scope.row.oldValue.length})` : '' }}</span>
<template v-for="item of scope.row.oldValue">
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item"
v-show="false" crossorigin="anonymous" alt="">
<img v-if="scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage'" :key="item"
:src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
</template>
<img v-if="scope.row.DataType === 'Image'" :src="OSSclientConfig.basePath + scope.row.oldValue"
v-show="false" crossorigin="anonymous" alt="">
@@ -519,7 +527,7 @@
{{ $t('trials:auditRecord:title:viewDetail') }}
</a>
<viewer
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.newValue && scope.row.newValue !== '--'"
v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage') && scope.row.newValue && scope.row.newValue !== '--'"
:ref="scope.row.newValue instanceof Array ? scope.row.newValue[0] : scope.row.newValue"
:images="imagesList">
<!-- 查看图片 -->
@@ -527,8 +535,8 @@
$t('trials:auditRecord:title:viewImage') }}{{ scope.row.newValue
instanceof Array ? `(${scope.row.newValue.length})` : '' }}</span>
<template v-for="item of scope.row.newValue">
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item"
v-show="false" crossorigin="anonymous" alt="">
<img v-if="scope.row.DataType === 'ImageList' || scope.row.DataType === 'ArrayImage'" :key="item"
:src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
</template>
<img v-if="scope.row.DataType === 'Image'" :src="OSSclientConfig.basePath + scope.row.newValue"
v-show="false" crossorigin="anonymous" alt="">
@@ -630,6 +638,7 @@ import Pagination from '@/components/Pagination'
import BaseContainer from '@/components/BaseContainer'
import BaseModel from '@/components/BaseModel'
import { getToken } from '@/utils/auth'
import { downLoadFile } from '@/utils/stream.js'
const searchDataDefault = () => {
return {
SortField: 'CreateTime',
@@ -711,6 +720,22 @@ export default {
this.getModuleTypeList()
},
methods: {
isFile(str) {
return str && Object.prototype.toString.call(str) === "[object String]" && !!~str.indexOf('❄❅❆❇❈❉❊')
},
async download(str) {
str = str.replace("❄❅❆❇❈❉❊", '')
let urls = str.split("|")
let name = `${Date.now()}.zip`, files = []
urls.forEach(url => {
let obj = {
url: this.OSSclientConfig.basePath + url,
name: url.split("/")[url.split("/").length - 1]
}
files.push(obj)
})
await downLoadFile(files, name, 'zip')
},
openImage(url, type) {
console.log(url)
@@ -863,6 +888,55 @@ export default {
}
return
}
//
if (v.DataType === 'ArrayImage') {
let objArr = [], upObjArr = []
if (obj && obj[v.Code] && obj[v.Code].length > 0) {
obj[v.Code].forEach(item => {
if (item[v.ChildDataValue]) {
objArr.push(item[v.ChildDataValue])
}
})
}
if (upObj && upObj[v.Code] && upObj[v.Code].length > 0) {
upObj[v.Code].forEach(item => {
if (item[v.ChildDataValue]) {
upObjArr.push(item[v.ChildDataValue])
}
})
}
if (obj[v.Code]) {
// obj[v.Code] = obj[v.Code].filter(s => s && s.trim())
if (row.OptType === 'Add' || row.OptType === 'Init') {
item = {
key: v.Code,
Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
newValue: objArr.length > 0 ? objArr : '--',
oldValue: ''
}
} else if (row.OptType === 'Delete') {
item = {
key: v.Code,
Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
oldValue: objArr.length > 0 ? objArr : '--',
newValue: '--'
}
} else {
item = {
key: v.Code,
Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
newValue: objArr.length > 0 ? objArr : '--',
oldValue: upObj.length > 0 ? upObj : '--',
}
}
item.DataType = v.DataType
this[auditData].push(item)
}
return
}
//
if (v.DataType === 'CombiningString') {
let arr = this.extractBraces(v.Code)
let o = null, up = null;
@@ -1089,6 +1163,7 @@ export default {
this.tableListData = body
return
}
console.log(v.IsShowParent, 'v.IsShowParent')
if (v.IsShowParent === 1) {
if (row.OptType === 'Delete') {
item = {
@@ -1106,7 +1181,7 @@ export default {
item = {
// newValue: parentRow ? (parentRow[v.Code] ? parentRow[v.Code] : '--') : '--',
newValue: parentRow ? ((parentRow[v.Code] && parentRow[v.Code] !== null && parentRow[v.Code] !== '' || parentRow[v.Code] === 0) ? parentRow[v.Code] : '--') : '--',
oldValue: parentRow ? ((parentRow[v.Code] && parentRow[v.Code] !== null && parentRow[v.Code] !== '' || parentRow[v.Code] === 0) ? parentRow[v.Code] : '--') : '--',
oldValue: parentRow ? ((parentRow[v.Code] && parentRow[v.Code] !== null && parentRow[v.Code] !== '' || parentRow[v.Code] === 0) && v.IsBeforeModifyView ? parentRow[v.Code] : '--') : '--',
// oldValue: parentRow ? (parentRow[v.Code] ? parentRow[v.Code] : '--') : '--'
}
}
@@ -1125,7 +1200,7 @@ export default {
} else {
item = {
newValue: obj ? ((obj[v.Code] && obj[v.Code] !== null && obj[v.Code] !== '' || obj[v.Code] === 0) ? obj[v.Code] : '--') : '--',
oldValue: upObj ? ((upObj[v.Code] && upObj[v.Code] !== null && upObj[v.Code] !== '' || upObj[v.Code] === 0) ? upObj[v.Code] : '--') : '--'
oldValue: upObj ? ((upObj[v.Code] && upObj[v.Code] !== null && upObj[v.Code] !== '' || upObj[v.Code] === 0) && v.IsBeforeModifyView ? upObj[v.Code] : '--') : '--'
}
}
} else {
@@ -1142,7 +1217,7 @@ export default {
} else {
item = {
newValue: row ? ((row[v.Code] && row[v.Code] !== null && row[v.Code] !== '' || row[v.Code] === 0) ? row[v.Code] : '--') : '--',
oldValue: row ? ((row[v.Code] && row[v.Code] !== null && row[v.Code] !== '' || row[v.Code] === 0) ? row[v.Code] : '--') : '--'
oldValue: row ? ((row[v.Code] && row[v.Code] !== null && row[v.Code] !== '' || row[v.Code] === 0) && v.IsBeforeModifyView ? row[v.Code] : '--') : '--'
}
}
}
@@ -33,6 +33,10 @@
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])">
{{ $t('trials:imageSummary:button:export_dicom') }}
</el-button>
<el-button type="primary" @click="handleExportImage(false, true)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])">
{{ $t('trials:imageSummary:button:export_readingDicom') }}
</el-button>
<el-button type="primary" @click="handleExportImage(true)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportKeyImage'])">
{{ $t('trials:imageSummary:button:export_image') }}
@@ -66,10 +70,10 @@
<template slot-scope="scope">
<el-tag v-if="scope.row.IsHaveDicom" type="primary">{{
$fd('IsDicom', true)
}}</el-tag>
}}</el-tag>
<el-tag v-if="scope.row.IsHaveNoneDicom" type="primary">{{
$fd('IsDicom', false)
}}</el-tag>
}}</el-tag>
</template>
</el-table-column>
<!-- 影像数量 -->
@@ -79,6 +83,10 @@
<el-table-column prop="TotalImageSizeStr" min-width="120"
:label="$t('trials:imageSummary:table:TotalImageSizeStr')" show-overflow-tooltip
sortable="custom" />
<!-- 阅片影像大小 -->
<el-table-column prop="TotalReadingImageSizeStr" min-width="120"
:label="$t('trials:imageSummary:table:TotalReadingImageSizeStr')" show-overflow-tooltip
sortable="custom" />
<!-- 最早拍片日期 -->
<el-table-column prop="EarliestScanDate" min-width="120"
:label="$t('trials:imageSummary:table:EarliestScanDate')" show-overflow-tooltip sortable="custom" />
@@ -102,7 +110,9 @@
<span>{{ $t('trials:imageSummary:remark:SubjectImageAVGSizeStr') }}</span>
<span class="size">{{ image_size.SubjectImageAVGSizeStr }} </span>,
<span>{{ $t('trials:imageSummary:remark:SubjectVisitImageAVGSizeStr') }}</span>
<span class="size">{{ image_size.SubjectVisitImageAVGSizeStr }}</span>,
<span class="size">{{ image_size.SubjectVisitImageAVGSizeStr }}</span><span>{{ `; ` }}</span>
<span>{{ $t('trials:imageSummary:remark:TotalReadingImageSizeStr') }}</span>
<span class="size">{{ image_size.TotalReadingImageSizeStr }} </span><span>{{ `; ` }}</span>
<span>{{ $t('trials:imageSummary:remark:CheckImageSize') }}</span>
<span class="size">{{ image_size.CheckImageSize }} </span>
</div>
@@ -144,6 +154,7 @@ export default {
TotalImageSizeStr: null,
SubjectImageAVGSizeStr: null,
SubjectVisitImageAVGSizeStr: null,
TotalReadingImageSizeStr: null,
CheckImageSize: null
}
}
@@ -179,11 +190,12 @@ export default {
}
},
//
async handleExportImage(IsKeyImage = false) {
async handleExportImage(IsKeyImage = false, IsExportReading = false) {
try {
let data = {
TrialId: this.$route.query.trialId,
IsKeyImage
IsKeyImage,
IsExportReading
}
data.SubjectVisitIdList = this.selectArr.map(item => item.SubjectVisitId)
if (!IsKeyImage) {
@@ -223,8 +235,9 @@ export default {
serie.InstancePathList.forEach(instance => {
let instanceArr = instance.Path.split("/")
let fileName = instanceArr[instanceArr.length - 1]
let time = study.StudyTime.split(' ')[0]
let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${study.StudyCode}_${study.StudyTime}_${serie.Modality}/${fileName}`,
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${study.StudyCode}_${time}_${serie.Modality}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
}
files.push(obj)
@@ -238,8 +251,9 @@ export default {
visit.NoneDicomStudyList.forEach(noneDicomStudy => {
if (noneDicomStudy.FileList && noneDicomStudy.FileList.length > 0) {
noneDicomStudy.FileList.forEach(file => {
let time = noneDicomStudy.ImageDate.split(' ')[0]
let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${noneDicomStudy.StudyCode}_${noneDicomStudy.ImageDate}_${noneDicomStudy.Modality}/${file.FileName}`,
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${noneDicomStudy.StudyCode}_${time}_${noneDicomStudy.Modality}/${file.FileName}`,
url: this.OSSclientConfig.basePath + file.Path,
}
files.push(obj)
@@ -287,6 +301,7 @@ export default {
this.image_size.TotalImageSizeStr = res.Result.TotalImageSizeStr;
this.image_size.SubjectImageAVGSizeStr = res.Result.SubjectImageAVGSizeStr;
this.image_size.SubjectVisitImageAVGSizeStr = res.Result.SubjectVisitImageAVGSizeStr;
this.image_size.TotalReadingImageSizeStr = res.Result.TotalReadingImageSizeStr;
}
} catch (err) {
this.loading = false
@@ -307,7 +322,7 @@ export default {
handleSelectionChange(selection) {
this.selectArr = selection
let num = this.selectArr.reduce((sum, item) => sum + item.TotalImageSize, 0)
if (num <= 0) return this.image_size.CheckImageSize = null
if (num <= 0) return this.image_size.CheckImageSize = `0MB`
this.image_size.CheckImageSize = this.$FormatSize(num)
},
// site

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