332 Commits

Author SHA1 Message Date
wangxiaoshuang 22352c57f2 受试者终止状态管理
continuous-integration/drone/push Build is passing
2025-06-25 15:46:54 +08:00
wangxiaoshuang 9fcabca64a 受试者终止状态管理
continuous-integration/drone/push Build is passing
2025-06-25 14:17:34 +08:00
wangxiaoshuang 8ed88c8e03 影像上传页基线可编辑是否失访
continuous-integration/drone/push Build is passing
2025-06-25 13:43:33 +08:00
wangxiaoshuang 43b139a2ac 项目配置临床数据预览自动计算添加小数位
continuous-integration/drone/push Build is passing
2025-06-25 10:48:17 +08:00
wangxiaoshuang f995b61c04 Merge branch 'uat'
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/dicoms/customize/CustomizeQuestionFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms/customize/CustomizeQuestionTableFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionList.vue
2025-06-25 10:33:31 +08:00
wangxiaoshuang 2c0823f027 阅片表单数值问题可输入NE
continuous-integration/drone/push Build encountered an error
2025-06-25 09:15:09 +08:00
wangxiaoshuang c1bcaa7e5d 临床数据配置添加默认值
continuous-integration/drone/push Build is passing
2025-06-24 11:19:25 +08:00
wangxiaoshuang 1ad3047689 检查部位、检查名称可选判断条件变更 2025-06-24 11:18:33 +08:00
wangxiaoshuang 6d774a255b 临床数据配置表格多选加 | 显示 2025-06-24 11:17:39 +08:00
wangxiaoshuang cf943ea328 1
continuous-integration/drone/push Build is passing
2025-06-24 10:43:45 +08:00
wangxiaoshuang 615cf94189 自定义表单数值类型输入框添加校验允许输入NE
continuous-integration/drone/push Build is running
2025-06-24 10:41:10 +08:00
wangxiaoshuang 99dd28a713 影像浏览问题修复
continuous-integration/drone/push Build is passing
2025-06-23 17:55:42 +08:00
wangxiaoshuang 6674989249 自定义结构化录入的临床数据,配置工具存在问题
continuous-integration/drone/push Build is passing
2025-06-20 18:04:34 +08:00
wangxiaoshuang 06167d4ff5 项目邮件阅片标准修改
continuous-integration/drone/push Build is passing
2025-06-20 15:27:39 +08:00
wangxiaoshuang 2a1dc4d2dd 自定义结构化录入的临床数据,配置工具存在问题
continuous-integration/drone/push Build is running
2025-06-20 13:17:21 +08:00
wangxiaoshuang 3d6cd67493 字典配置修改为可查看
continuous-integration/drone/push Build is passing
2025-06-20 11:26:20 +08:00
wangxiaoshuang c448f4cda8 上传影像预览窗宽窗位问题
continuous-integration/drone/push Build is passing
2025-06-20 11:05:27 +08:00
wangxiaoshuang 155158f954 项目配置检查名称问题解决
continuous-integration/drone/push Build is passing
2025-06-20 09:44:08 +08:00
wangxiaoshuang 44b10255dd IVUS和OCT表单修改,新增靶段
continuous-integration/drone/push Build encountered an error
2025-06-19 17:47:10 +08:00
wangxiaoshuang 551620c3c3 1
continuous-integration/drone/push Build is passing
2025-06-19 17:44:31 +08:00
wangxiaoshuang 4540f39051 切换靶段时清空备注 2025-06-19 17:42:25 +08:00
wangxiaoshuang 848bf0c8b2 自定义报告单选显示问题修改
continuous-integration/drone/push Build is passing
2025-06-19 17:24:35 +08:00
wangxiaoshuang aa1f4dae9b IVUS和OCT表单修改,新增靶段
continuous-integration/drone/push Build is passing
2025-06-19 16:53:11 +08:00
wangxiaoshuang a41359111f 字典子项增加排序
continuous-integration/drone/push Build is passing
2025-06-19 13:39:12 +08:00
wangxiaoshuang 50ae94bf08 1
continuous-integration/drone/push Build is passing
2025-06-19 13:18:07 +08:00
wangxiaoshuang 19785bd266 邮件模板编辑阅片标准改为多选
continuous-integration/drone/push Build is passing
2025-06-19 13:13:12 +08:00
wangxiaoshuang cc5a4ed2df 邮件模板编辑样式修改
continuous-integration/drone/push Build is passing
2025-06-19 11:42:53 +08:00
wangxiaoshuang 5efcbae09a 邮件模板阅片标准字段更改 2025-06-19 11:40:46 +08:00
wangxiaoshuang 6f5d48cdcd 如果上传影像都是问题影像,此时会显示数量0/0
continuous-integration/drone/push Build is passing
2025-06-19 11:28:14 +08:00
wangxiaoshuang fead8b8c8f 导出文件格式问题
continuous-integration/drone/push Build is passing
2025-06-18 14:28:08 +08:00
wangxiaoshuang 6980cd275e Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-06-18 13:48:05 +08:00
wangxiaoshuang a14aefca2c 上传影像文件统计问题
continuous-integration/drone/push Build encountered an error
2025-06-18 13:33:39 +08:00
wangxiaoshuang 334882cc68 阅片下载压缩包名称修改 2025-06-18 13:30:36 +08:00
wangxiaoshuang de250ecbf5 Merge branch 'uat'
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue
2025-06-18 09:56:39 +08:00
wangxiaoshuang d8315fbfff 阅片上传下载按钮添加
continuous-integration/drone/push Build encountered an error
2025-06-18 09:55:16 +08:00
wangxiaoshuang 1022fa2888 阅片顺序添加admin角色权限
continuous-integration/drone/push Build encountered an error
2025-06-17 16:49:15 +08:00
wangxiaoshuang a14451b82b 影像汇总导出表格
continuous-integration/drone/push Build is passing
2025-06-17 16:43:55 +08:00
wangxiaoshuang 24ff1772dd Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-06-16 17:24:31 +08:00
wangxiaoshuang 48633a1ed4 阅片顺序手动修改添加限制条件
continuous-integration/drone/push Build encountered an error
2025-06-16 17:24:14 +08:00
wangxiaoshuang 0634df6e33 Merge branch 'uat'
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/trial-summary/audit-record/index.vue
2025-06-16 16:06:54 +08:00
wangxiaoshuang 108d01f81c 阅片顺序默认排序、阅片中禁用
continuous-integration/drone/push Build encountered an error
2025-06-16 16:05:49 +08:00
caiyiling ae808679a0 1
continuous-integration/drone/push Build is passing
2025-06-13 18:02:55 +08:00
wangxiaoshuang 12e4128b7b 提交裁判阅片结果详情oldValue改为--
continuous-integration/drone/push Build encountered an error
2025-06-13 16:49:50 +08:00
caiyiling fbb23065e5 1
continuous-integration/drone/push Build is passing
2025-06-13 16:33:59 +08:00
caiyiling 0d85f138a5 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-06-13 16:07:17 +08:00
caiyiling f60d845725 自定义阅片更改 2025-06-13 16:06:54 +08:00
wangxiaoshuang f848e9a9dd Merge branch 'uat'
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/api/trials/reading.js
#	src/views/trials/trials-panel/trial-summary/audit-record/index.vue
2025-06-13 14:34:59 +08:00
wangxiaoshuang b512112d96 肿瘤学阅片查看屏蔽跳过按钮
continuous-integration/drone/push Build encountered an error
2025-06-13 14:33:55 +08:00
wangxiaoshuang a7251ce65c 阅片顺序
continuous-integration/drone/push Build encountered an error
2025-06-13 14:17:58 +08:00
wangxiaoshuang 19896b85e0 1
continuous-integration/drone/push Build is passing
2025-06-13 11:43:07 +08:00
wangxiaoshuang f94013103e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-06-13 11:17:38 +08:00
wangxiaoshuang ccdfe9d83e 阅片排序 2025-06-13 11:17:28 +08:00
caiyiling 657010202c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-06-13 10:44:35 +08:00
caiyiling 9c2c6191d2 播放工具更改 2025-06-13 10:44:12 +08:00
wangxiaoshuang 7e2ff6de1b 稽查图片不存在展示问题
continuous-integration/drone/push Build encountered an error
2025-06-12 16:23:44 +08:00
wangxiaoshuang c865608313 阅片顺序页面
continuous-integration/drone/push Build is passing
2025-06-12 16:19:08 +08:00
wangxiaoshuang 818a8add3d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2025-06-12 16:18:49 +08:00
wangxiaoshuang 53343e37d6 稽查图片不存在展示问题 2025-06-12 16:18:45 +08:00
caiyiling a3e17bbefe Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is failing
2025-06-12 15:44:23 +08:00
caiyiling 19bb1eccd8 自定义阅片表单更改 2025-06-12 15:43:59 +08:00
wangxiaoshuang e60260f68d 培训记录查看页面中角色筛选项缺少ZYBS、ZYSS角色
continuous-integration/drone/push Build is pending
2025-06-12 11:02:37 +08:00
wangxiaoshuang 2b89163419 项目文档历史记录文件名称修改方式修改
continuous-integration/drone/push Build is passing
2025-06-11 16:53:22 +08:00
wangxiaoshuang 3489d34628 影像汇总导出影像、关键图
continuous-integration/drone/push Build is passing
2025-06-11 16:34:46 +08:00
wangxiaoshuang 613d434af9 影像汇总
continuous-integration/drone/push Build is passing
2025-06-10 18:02:37 +08:00
wangxiaoshuang 123f178673 稽查图片显示问题
continuous-integration/drone/push Build is passing
2025-06-10 15:26:34 +08:00
wangxiaoshuang e8e066ab80 稽查操作名查询字段变更
continuous-integration/drone/push Build is passing
2025-06-10 09:41:55 +08:00
wangxiaoshuang 4aa5acc401 1
continuous-integration/drone/push Build is passing
2025-06-09 16:56:29 +08:00
wangxiaoshuang fa4c00230f 项目文档历史记录修改
continuous-integration/drone/push Build is passing
2025-06-09 15:58:52 +08:00
wangxiaoshuang 6ea46c076b 检查部位、检查技术、检查名称已使用禁止取消、删除
continuous-integration/drone/push Build is passing
2025-06-09 11:18:09 +08:00
caiyiling dbffc2787d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-06-06 17:25:59 +08:00
caiyiling f98ea18205 自定义标准阅片交互更改 2025-06-06 17:25:23 +08:00
wangxiaoshuang 00e53c4742 项目培训图片预览问题
continuous-integration/drone/push Build is passing
2025-06-06 16:58:38 +08:00
wangxiaoshuang 5de61dd125 项目培训发布状态默认值
continuous-integration/drone/push Build is passing
2025-06-06 16:28:07 +08:00
wangxiaoshuang ae8767c70f 配置中检查部位已在项目中使用禁止取消勾选和修改
continuous-integration/drone/push Build is passing
2025-06-06 14:34:42 +08:00
wangxiaoshuang 623a7b9858 1
continuous-integration/drone/push Build is passing
2025-06-06 14:26:45 +08:00
wangxiaoshuang ce2a0d9936 邮件管理批量编辑 2025-06-06 14:26:37 +08:00
wangxiaoshuang 18b0ec2042 pm重阅跟踪、spm重阅审批弹框列表高度修改
continuous-integration/drone/push Build is passing
2025-06-06 13:47:33 +08:00
caiyiling 8d5dfd0258 自定义阅片配置更改
continuous-integration/drone/push Build is passing
2025-06-06 11:15:31 +08:00
caiyiling 45f83322ec 1
continuous-integration/drone/push Build is passing
2025-06-05 18:32:22 +08:00
caiyiling 3d7ccafa76 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-06-05 18:03:50 +08:00
caiyiling f148c76a7f 自定义阅片更改 2025-06-05 18:03:32 +08:00
wangxiaoshuang 1ffd9e3863 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is failing
2025-06-05 16:59:56 +08:00
wangxiaoshuang 3bcf097c52 邮件管理编辑内容方式修改 2025-06-05 16:59:44 +08:00
caiyiling 1e4fd0083a 1
continuous-integration/drone/push Build is passing
2025-06-05 16:26:02 +08:00
caiyiling d504039d82 自定义标准配置更改
continuous-integration/drone/push Build is passing
2025-06-05 16:22:42 +08:00
caiyiling 0c4b3e5aed 表格问题配置更改
continuous-integration/drone/push Build is passing
2025-06-05 16:10:23 +08:00
caiyiling 262541ac08 1
continuous-integration/drone/push Build is passing
2025-06-05 16:03:06 +08:00
caiyiling dce3719c58 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2025-06-05 16:00:49 +08:00
caiyiling d05a4437d4 自定义标准配置更改及自定义阅片更改 2025-06-05 16:00:12 +08:00
wangxiaoshuang 10f2953a94 如果不能下载影像,则检查也不需要能够选择
continuous-integration/drone/push Build is passing
2025-06-05 13:12:49 +08:00
wangxiaoshuang 7a6cded333 培训材料视频禁止下载
continuous-integration/drone/push Build is passing
2025-06-05 11:38:08 +08:00
wangxiaoshuang c1f10036b0 项目文档增加附件
continuous-integration/drone/push Build is passing
2025-06-04 17:15:45 +08:00
caiyiling 8e01f3af87 Merge branch 'uat' into main
continuous-integration/drone/push Build is passing
2025-06-04 16:50:53 +08:00
caiyiling a66e15eb39 MRI-PDFF测量逻辑更改
continuous-integration/drone/push Build encountered an error
2025-06-04 16:25:48 +08:00
wangxiaoshuang 386901316d 1
continuous-integration/drone/push Build is passing
2025-06-04 15:58:30 +08:00
caiyiling 122f333c77 Merge branch 'uat' into main
continuous-integration/drone/push Build is passing
2025-06-04 13:42:00 +08:00
caiyiling 164437ea70 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-06-04 13:37:46 +08:00
caiyiling 86a8e2faeb 测量工具配置文件更改 2025-06-04 13:37:12 +08:00
caiyiling 895e3a6bed MRI-PDFF更改
continuous-integration/drone/push Build encountered an error
2025-06-04 13:35:42 +08:00
wangxiaoshuang b5b67cc5e3 稽查搜索框内容接口获取
continuous-integration/drone/push Build is passing
2025-06-04 13:34:42 +08:00
caiyiling 9dddc0c012 MRI-PDFF测量逻辑更改
continuous-integration/drone/push Build encountered an error
2025-06-04 10:53:45 +08:00
caiyiling a965f08a1e MRI-PDFF标准更改
continuous-integration/drone/push Build encountered an error
2025-06-04 09:24:41 +08:00
wangxiaoshuang d667bb4e79 审批页面优化
continuous-integration/drone/push Build is passing
2025-06-03 18:01:04 +08:00
caiyiling c7e0fab789 非Dicom工具更改
continuous-integration/drone/push Build is passing
2025-06-03 16:14:28 +08:00
caiyiling 35b16876c9 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-06-03 14:27:27 +08:00
caiyiling 549b028809 非dicom更改 2025-06-03 14:27:09 +08:00
wangxiaoshuang 330b1cf644 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-06-03 13:54:34 +08:00
wangxiaoshuang b51a8e94de 稽查轨迹的记录的操作可以在在项目配置 2025-06-03 13:54:19 +08:00
caiyiling b85853aa5e 阅片结果导出配置更改
continuous-integration/drone/push Build is passing
2025-06-03 11:32:48 +08:00
wangxiaoshuang 5386dba134 稽查新增字段是否默认
continuous-integration/drone/push Build is passing
2025-05-30 09:27:30 +08:00
caiyiling 3f63c126ff 1
continuous-integration/drone/push Build is passing
2025-05-29 17:21:25 +08:00
caiyiling f1b816fd85 自定义阅片更改
continuous-integration/drone/push Build is passing
2025-05-29 17:04:00 +08:00
caiyiling 43a221de00 自定义阅片更改
continuous-integration/drone/push Build is passing
2025-05-29 14:49:53 +08:00
caiyiling 642c708c74 Merge remote-tracking branch 'origin/uat' into main
continuous-integration/drone/push Build is passing
2025-05-29 09:58:39 +08:00
caiyiling aa8831ce54 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2025-05-29 09:57:35 +08:00
caiyiling d73970117d 自定义标准更改 2025-05-29 09:57:02 +08:00
wangxiaoshuang 9d462f69f6 人员管理中,当人员退出时,显示加入项目的时间
continuous-integration/drone/push Build is passing
2025-05-29 09:38:11 +08:00
caiyiling 9962b1a829 反色bug修复
continuous-integration/drone/push Build encountered an error
2025-05-28 18:46:53 +08:00
caiyiling 049128b90e 添加阅片完成支持添加临时标注(历史标注不允许更改)功能及阅片页面双击放大缺陷修复
continuous-integration/drone/push Build encountered an error
2025-05-28 15:44:38 +08:00
caiyiling d77c79acbd 自定义标准问题配置扩充影像标记属性
continuous-integration/drone/push Build is passing
2025-05-27 11:10:56 +08:00
caiyiling 1e300b4529 CDISC导出配置支持表格问题更改
continuous-integration/drone/push Build is passing
2025-05-27 09:06:04 +08:00
wangxiaoshuang 45e6a20988 Merge branch 'uat'
continuous-integration/drone/push Build encountered an error
# Conflicts:
#	src/utils/metaDataProvider.js
2025-05-26 12:30:44 +08:00
wangxiaoshuang 5141eb5cbd 发布配置修改
continuous-integration/drone/push Build is passing
2025-05-23 18:12:49 +08:00
wangxiaoshuang 073b06a76f 1
continuous-integration/drone/push Build is passing
2025-05-23 17:10:45 +08:00
wangxiaoshuang 20723e8d2c 1
continuous-integration/drone/push Build is passing
2025-05-23 16:25:30 +08:00
wangxiaoshuang fba00157a1 crc一致性核查回复弹窗添加取消按钮
continuous-integration/drone/push Build is passing
2025-05-23 16:06:12 +08:00
wangxiaoshuang f0e6708533 1
continuous-integration/drone/push Build is passing
2025-05-23 15:24:49 +08:00
wangxiaoshuang e770dc1078 1 2025-05-23 15:24:07 +08:00
wangxiaoshuang e15934d7ba iqc质控页面数据已退回禁用所有按钮
continuous-integration/drone/push Build is passing
2025-05-23 13:49:36 +08:00
wangxiaoshuang 4baf039d71 iqc下载非dicom文件夹名称问题
continuous-integration/drone/push Build is passing
2025-05-23 13:38:59 +08:00
wangxiaoshuang 5c4bc96a26 pm重传审批样式修改
continuous-integration/drone/push Build is passing
2025-05-23 13:27:51 +08:00
wangxiaoshuang 30f9e807b7 crc一致性核查逻辑变更
continuous-integration/drone/push Build is passing
2025-05-23 11:07:17 +08:00
wangxiaoshuang 269f9f9477 pm重传审批修改
continuous-integration/drone/push Build is passing
2025-05-23 10:11:52 +08:00
wangxiaoshuang 810c786512 1
continuous-integration/drone/push Build is passing
2025-05-22 18:04:29 +08:00
wangxiaoshuang e27705eb22 IRC国际化替换
continuous-integration/drone/push Build is passing
2025-05-22 17:49:43 +08:00
wangxiaoshuang 83bf082c43 crc一致性核查回复信息有误
continuous-integration/drone/push Build is passing
2025-05-22 16:52:50 +08:00
wangxiaoshuang 37f12b30cc 阅片跟踪影像退回添加退回原因
continuous-integration/drone/push Build is passing
2025-05-22 15:30:14 +08:00
wangxiaoshuang f045f68115 一致性核查回复修改
continuous-integration/drone/push Build is passing
2025-05-22 14:06:38 +08:00
wangxiaoshuang 64e67ad106 一致性核查回复修改
continuous-integration/drone/push Build is passing
2025-05-22 13:54:27 +08:00
wangxiaoshuang f2ee666083 重阅审批的弹框,国际化取值不正确修改
continuous-integration/drone/push Build is passing
2025-05-22 11:04:30 +08:00
caiyiling 8ece8915ff 高亮颜色更改
continuous-integration/drone/push Build is passing
2025-05-21 16:01:04 +08:00
caiyiling 8270841ca1 典型肝内病灶鼠标悬浮显示
continuous-integration/drone/push Build is passing
2025-05-21 15:21:33 +08:00
caiyiling e99c4527b9 阅片页面radio样式更改及病灶信息高亮更改
continuous-integration/drone/push Build is passing
2025-05-21 15:10:49 +08:00
caiyiling e295bff859 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-21 14:06:54 +08:00
caiyiling 7a53a75038 影像质量不正常时维护病灶默认状态 2025-05-21 14:06:06 +08:00
wangxiaoshuang d96822818c 1
continuous-integration/drone/push Build is passing
2025-05-21 14:02:23 +08:00
caiyiling 9e2255e324 阅片标准更改
continuous-integration/drone/push Build is passing
2025-05-21 10:37:12 +08:00
caiyiling dbdd18dcf6 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-21 09:49:22 +08:00
caiyiling 4ae2504278 阅片标准更改 2025-05-21 09:48:54 +08:00
wangxiaoshuang 6a0a5f4724 1
continuous-integration/drone/push Build is passing
2025-05-20 16:14:40 +08:00
wangxiaoshuang ee2e33405c 申请原因必填添加星号
continuous-integration/drone/push Build is passing
2025-05-20 11:07:41 +08:00
wangxiaoshuang 286865ba8f 影像质疑列表操作栏样式调整
continuous-integration/drone/push Build is passing
2025-05-20 09:43:02 +08:00
wangxiaoshuang 75a0f3a91a 影像退回添加申请原因、备注
continuous-integration/drone/push Build is passing
2025-05-19 17:53:54 +08:00
wangxiaoshuang 4fbcd8f8f5 项目培训新增默认字段IsPublish修改
continuous-integration/drone/push Build is passing
2025-05-19 16:05:36 +08:00
wangxiaoshuang 3c2edbffc5 1
continuous-integration/drone/push Build is passing
2025-05-19 15:39:04 +08:00
caiyiling 38fb56e09e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-19 15:19:18 +08:00
caiyiling 105537c49e 非淋巴结靶病灶保存验证更改 2025-05-19 15:18:48 +08:00
wangxiaoshuang 355f6bcf86 培训文档管理预览附件
continuous-integration/drone/push Build is passing
2025-05-19 14:48:47 +08:00
wangxiaoshuang d6e9f9ddc2 培训文档管理预览附件
continuous-integration/drone/push Build is passing
2025-05-19 14:35:17 +08:00
wangxiaoshuang 16e005e664 test环境新增onlyoffice地址配置
continuous-integration/drone/push Build is passing
2025-05-19 14:27:00 +08:00
wangxiaoshuang b92b55a45a 培训课程管理问题
continuous-integration/drone/push Build is passing
2025-05-19 14:18:59 +08:00
wangxiaoshuang 0ed070ecd7 【临床数据】新增临床数据时,选择模板同时存在中文模板和英文模板,根据语言环境只显示一个 2025-05-19 14:18:45 +08:00
caiyiling 49940ab034 lugano更改
continuous-integration/drone/push Build is passing
2025-05-19 14:15:41 +08:00
caiyiling aca5b0c721 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-19 11:28:14 +08:00
caiyiling 8ea7540581 阅片报告页更改 2025-05-19 11:27:50 +08:00
wangxiaoshuang ec6a72e143 影像质控问题配置未勾选问题提交会报错
continuous-integration/drone/push Build is passing
2025-05-15 16:44:16 +08:00
wangxiaoshuang f512c1456a 阅片结果查看跳转修改
continuous-integration/drone/push Build is passing
2025-05-15 15:39:23 +08:00
wangxiaoshuang 4aa74b5420 阅片结果查看跳转修改
continuous-integration/drone/push Build is passing
2025-05-15 15:32:24 +08:00
wangxiaoshuang 50c37824aa ir已阅查看跳转修改
continuous-integration/drone/push Build is passing
2025-05-15 15:21:47 +08:00
wangxiaoshuang 358864c6c6 onlyoffice引入方式修改
continuous-integration/drone/push Build is passing
2025-05-15 11:08:33 +08:00
wangxiaoshuang e2db9c2d51 通用培训文档修改 2025-05-15 11:08:06 +08:00
wangxiaoshuang 78fbae1c1f 通用培训记录的相关文件添加/编辑弹框需要增加标题
continuous-integration/drone/push Build is passing
2025-05-15 09:46:25 +08:00
wangxiaoshuang 26c58f14fa 稽查轨迹关联操作页面的标题需要区分
continuous-integration/drone/push Build is passing
2025-05-14 16:14:05 +08:00
caiyiling f8774224b3 视角信息更改
continuous-integration/drone/push Build is passing
2025-05-14 16:05:43 +08:00
caiyiling bc41f4b4c1 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-14 15:48:29 +08:00
caiyiling 0280dfb959 lugano更改 2025-05-14 15:48:08 +08:00
wangxiaoshuang 49aa98af9f suv融合pt图像调整
continuous-integration/drone/push Build is passing
2025-05-14 15:06:52 +08:00
wangxiaoshuang 9ce6ff25b9 1
continuous-integration/drone/push Build is passing
2025-05-14 14:23:04 +08:00
wangxiaoshuang fca8c1c9bf suv问题修复
continuous-integration/drone/push Build is passing
2025-05-14 14:12:31 +08:00
wangxiaoshuang d0ebc3e791 融合影像数存在较大差距校验
continuous-integration/drone/push Build is passing
2025-05-14 13:39:45 +08:00
caiyiling ea4f23fb16 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-14 13:18:17 +08:00
caiyiling 01d01b1126 视口信息更改 2025-05-14 13:17:56 +08:00
wangxiaoshuang 040d9309b9 影像质控问题配置未勾选问题提交会报错
continuous-integration/drone/push Build is passing
2025-05-14 13:05:00 +08:00
caiyiling 1d6656a5b8 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-05-14 11:25:22 +08:00
caiyiling 76e328dcca 阅片页面视角信息更改 2025-05-14 11:24:49 +08:00
wangxiaoshuang 9852d99a4a crc上传文件大小统计修改
continuous-integration/drone/push Build is passing
2025-05-13 15:40:30 +08:00
wangxiaoshuang 39f7ba7181 标记缓存修改
continuous-integration/drone/push Build is passing
2025-05-13 15:24:32 +08:00
wangxiaoshuang fb68892cd4 基线二维上的病灶被渲染到了随访的融合上
continuous-integration/drone/push Build is passing
2025-05-12 17:22:05 +08:00
caiyiling 1e6ec0df27 1
continuous-integration/drone/push Build is passing
2025-05-12 17:02:08 +08:00
caiyiling 4ff6416edb 矩形工具更改
continuous-integration/drone/push Build is passing
2025-05-12 16:45:48 +08:00
wangxiaoshuang b2645f6423 从随访切到基线再切到随访,测量工具会被禁用,当前访视无法标记
continuous-integration/drone/push Build is passing
2025-05-12 15:38:21 +08:00
wangxiaoshuang 122c76d9b2 suv部分问题解决
continuous-integration/drone/push Build is passing
2025-05-12 14:58:07 +08:00
wangxiaoshuang 2d155612e5 1
continuous-integration/drone/push Build is passing
2025-05-12 13:31:41 +08:00
wangxiaoshuang 329d6b1ff6 【NM自定义】三维MIP视口影像显示异常
continuous-integration/drone/push Build is passing
2025-05-12 13:22:36 +08:00
wangxiaoshuang 7006cf849e suv融合部分问题修复
continuous-integration/drone/push Build is passing
2025-05-12 13:13:36 +08:00
wangxiaoshuang 71f3519769 suv融合部分问题修复
continuous-integration/drone/push Build is passing
2025-05-09 17:54:14 +08:00
wangxiaoshuang bbf2dd16e6 【NM自定义】pet视口放大缩小,标记显示的位置产生了偏移
continuous-integration/drone/push Build is passing
2025-05-09 15:58:27 +08:00
wangxiaoshuang 520d499a0b 1
continuous-integration/drone/push Build is passing
2025-05-09 14:26:23 +08:00
wangxiaoshuang 00cfb92087 suv融合
continuous-integration/drone/push Build is passing
2025-05-09 14:20:24 +08:00
wangxiaoshuang 8eb0b96c8e 重传审批操作添加权限判断
continuous-integration/drone/push Build is passing
2025-05-09 10:05:22 +08:00
wangxiaoshuang 24b9120a0a 部分问题解决
continuous-integration/drone/push Build is passing
2025-05-08 14:47:26 +08:00
wangxiaoshuang 02fcc4a2c1 suv融合
continuous-integration/drone/push Build is passing
2025-05-08 10:36:57 +08:00
wangxiaoshuang f53412acbf 复制、粘贴快捷方式不禁用默认事件
continuous-integration/drone/push Build is passing
2025-05-07 13:39:30 +08:00
caiyiling 3948596014 阅片页面更改
continuous-integration/drone/push Build is passing
2025-05-06 09:13:59 +08:00
wangxiaoshuang e899c0814e 部分问题修复
continuous-integration/drone/push Build is passing
2025-04-30 14:51:13 +08:00
wangxiaoshuang d12b4adb68 部分问题修复
continuous-integration/drone/push Build is passing
2025-04-30 13:43:23 +08:00
wangxiaoshuang 3551a521c8 suv融合
continuous-integration/drone/push Build is passing
2025-04-29 17:51:54 +08:00
caiyiling e80d439377 阅片更改
continuous-integration/drone/push Build is passing
2025-04-28 18:32:16 +08:00
caiyiling f499557c01 1
continuous-integration/drone/push Build is passing
2025-04-28 17:37:34 +08:00
caiyiling ecaca550ab 自定义阅片工具更改
continuous-integration/drone/push Build is passing
2025-04-28 17:32:40 +08:00
caiyiling b7d7b93c4a 获取病灶截图更改
continuous-integration/drone/push Build is passing
2025-04-28 17:07:15 +08:00
caiyiling 7bf92c60ea 阅片完成后禁用“更多”操作
continuous-integration/drone/push Build is passing
2025-04-28 16:38:49 +08:00
caiyiling 36a08d1055 自定义阅片报告页更改
continuous-integration/drone/push Build is passing
2025-04-28 16:31:45 +08:00
caiyiling 5ebf9032a5 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-28 16:12:02 +08:00
caiyiling 1896c58b50 自定义阅片bug修复 2025-04-28 16:11:08 +08:00
wangxiaoshuang 9168ef3ad7 1
continuous-integration/drone/push Build is passing
2025-04-28 15:55:27 +08:00
wangxiaoshuang 4ad299e243 suv融合
continuous-integration/drone/push Build is passing
2025-04-28 15:47:07 +08:00
caiyiling 5d337b0b26 自定义阅片bug修复
continuous-integration/drone/push Build is passing
2025-04-28 14:22:35 +08:00
caiyiling ca579f8731 自定义阅片更改
continuous-integration/drone/push Build is passing
2025-04-28 10:19:37 +08:00
caiyiling 92d41dff28 1
continuous-integration/drone/push Build is passing
2025-04-27 18:00:53 +08:00
wangxiaoshuang 8d6ae3a49f suv融合
continuous-integration/drone/push Build is passing
2025-04-27 17:04:54 +08:00
caiyiling 18f23d2bba 阅片交互更改
continuous-integration/drone/push Build is passing
2025-04-25 15:27:00 +08:00
caiyiling 0a428bf954 多帧图像保存病灶更改及关键帧渲染更改
continuous-integration/drone/push Build is passing
2025-04-25 15:02:13 +08:00
caiyiling a6b5d0b196 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-25 10:53:09 +08:00
caiyiling 8bf6d5f515 自定义标准工具添加 2025-04-25 10:52:37 +08:00
wangxiaoshuang 74f3852ecc Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-25 09:39:03 +08:00
wangxiaoshuang 9408ce12e2 稽查文档删除添加二次确定 2025-04-25 09:38:08 +08:00
wangxiaoshuang 06a2361ea0 【通用培训管理】新员工培训时限默认值设为14天 2025-04-25 09:37:45 +08:00
caiyiling e3313edefd mRecist标准bug修复
continuous-integration/drone/push Build is passing
2025-04-24 16:47:08 +08:00
caiyiling 2676ff4295 阅片单元配置更改
continuous-integration/drone/push Build is passing
2025-04-24 10:34:24 +08:00
caiyiling 41b3a98594 recist1.1标准bug修复
continuous-integration/drone/push Build is passing
2025-04-23 16:59:54 +08:00
caiyiling c2aba6c3fe 自定义阅片更改
continuous-integration/drone/push Build is passing
2025-04-23 15:14:35 +08:00
caiyiling 81a5d5af17 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-23 14:10:26 +08:00
caiyiling 23ac15f978 布局更改 2025-04-23 14:10:08 +08:00
wangxiaoshuang 1ec4c25472 稽查文档通用培训记录导出
continuous-integration/drone/push Build is running
2025-04-23 14:10:06 +08:00
wangxiaoshuang ac8710b26b 稽查文档右键下载问题
continuous-integration/drone/push Build is passing
2025-04-23 11:44:05 +08:00
caiyiling 1130b55677 视口滚动图像翻页更改
continuous-integration/drone/push Build is passing
2025-04-23 09:21:32 +08:00
caiyiling fb57dfe90c 新版本阅片添加iRecist标准
continuous-integration/drone/push Build is failing
2025-04-22 17:44:50 +08:00
caiyiling 2784958ccb 多帧对齐更改
continuous-integration/drone/push Build is passing
2025-04-22 15:00:35 +08:00
caiyiling d6a3bcba30 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-22 13:43:19 +08:00
caiyiling 4ff9a7c482 多帧渲染更改 2025-04-22 13:42:58 +08:00
wangxiaoshuang 33b3818a9e 测试
continuous-integration/drone/push Build is passing
2025-04-22 10:44:48 +08:00
wangxiaoshuang 38c31af137 已发布、已下线的培训文档默认不可多选
continuous-integration/drone/push Build is passing
2025-04-21 11:28:41 +08:00
wangxiaoshuang fb671defb5 1
continuous-integration/drone/push Build is passing
2025-04-21 11:09:55 +08:00
wangxiaoshuang a25aa2482f 通用培训材料发布、下线功能修改
continuous-integration/drone/push Build is passing
2025-04-21 10:57:32 +08:00
wangxiaoshuang 4249ccd9d6 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-21 09:47:31 +08:00
wangxiaoshuang 9a88930a04 通用培训创建默认设置为失效 2025-04-21 09:47:20 +08:00
caiyiling aea6a3f8c8 病灶对齐逻辑更改
continuous-integration/drone/push Build is passing
2025-04-18 17:02:52 +08:00
caiyiling c657bb8783 标注序列图标维护
continuous-integration/drone/push Build is passing
2025-04-18 16:46:27 +08:00
caiyiling b0ae3cbd27 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-18 16:01:28 +08:00
caiyiling 10487640cd 视图工具维护 2025-04-18 16:01:00 +08:00
wangxiaoshuang 83fa937537 通用培训文档新增发布功能
continuous-integration/drone/push Build is passing
2025-04-18 14:23:29 +08:00
wangxiaoshuang dd1fb94562 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-18 09:55:17 +08:00
wangxiaoshuang 116402f865 【账号登录日志】去除用户类型查询条件 2025-04-18 09:55:06 +08:00
caiyiling 76fe08ed23 重置视口时重置窗宽窗位
continuous-integration/drone/push Build is passing
2025-04-18 09:43:21 +08:00
caiyiling 993d97e205 测量时病灶默认状态维护
continuous-integration/drone/push Build is passing
2025-04-18 09:21:47 +08:00
caiyiling 11471525af 任务切换或者单个病灶保存时前端缓存当前状态不刷新ecrf
continuous-integration/drone/push Build is passing
2025-04-17 17:36:35 +08:00
caiyiling 600abc3ce1 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-17 16:02:57 +08:00
caiyiling 9609768e5e 全局阅片更改 2025-04-17 16:02:39 +08:00
wangxiaoshuang ce565e00ff Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-17 15:14:00 +08:00
wangxiaoshuang e49fe23396 通用培训问题修复 2025-04-17 15:13:56 +08:00
caiyiling 85463ad240 典型肝内病灶提示更改
continuous-integration/drone/push Build is passing
2025-04-17 14:59:19 +08:00
caiyiling fc228622e1 病灶保存更改
continuous-integration/drone/push Build is passing
2025-04-17 14:20:00 +08:00
caiyiling 8840ddc77a 病灶清除修复
continuous-integration/drone/push Build is passing
2025-04-17 11:40:34 +08:00
caiyiling 3b31132616 mRecist表单更改
continuous-integration/drone/push Build is passing
2025-04-17 10:22:28 +08:00
caiyiling c7df59e564 1
continuous-integration/drone/push Build is passing
2025-04-17 09:29:23 +08:00
caiyiling aeef8eaacf 清除病灶信息bug修复
continuous-integration/drone/push Build is passing
2025-04-17 09:07:46 +08:00
caiyiling b0c4cfd0bf 阅片页面矩形工具补充
continuous-integration/drone/push Build is passing
2025-04-16 17:26:48 +08:00
caiyiling 38c06595aa 病灶保存bug修复
continuous-integration/drone/push Build is passing
2025-04-16 17:10:15 +08:00
caiyiling a0c5c7d304 病灶验证更改
continuous-integration/drone/push Build is passing
2025-04-16 16:43:30 +08:00
caiyiling 2323cbdd27 病灶保存成功时关闭窗口
continuous-integration/drone/push Build is passing
2025-04-16 15:57:33 +08:00
caiyiling c2f3e02ef1 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2025-04-16 15:55:44 +08:00
caiyiling b069c881f2 mRecist病灶验证更改 2025-04-16 15:55:13 +08:00
wangxiaoshuang faaaf8f28f 附件数量为0时不打开预览弹框
continuous-integration/drone/push Build is passing
2025-04-15 17:39:54 +08:00
wangxiaoshuang 1e5bd46a40 附件预览筛选是否下线
continuous-integration/drone/push Build is passing
2025-04-15 17:27:54 +08:00
wangxiaoshuang 7d2af46845 通用培训问题解决
continuous-integration/drone/push Build is passing
2025-04-15 16:29:56 +08:00
wangxiaoshuang e1c41d2327 通用培训文档优化:增加附件、培训时限
continuous-integration/drone/push Build is passing
2025-04-15 15:49:22 +08:00
wangxiaoshuang d4ae366fa6 非dicom上传去除限制
continuous-integration/drone/push Build is passing
2025-04-15 11:13:52 +08:00
wangxiaoshuang 26963b0f94 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-15 10:01:10 +08:00
wangxiaoshuang c391e3e2e7 通用培训新增附件 2025-04-15 10:00:59 +08:00
caiyiling 23feb84e30 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-14 16:46:00 +08:00
caiyiling d5ae075aa8 多帧图像渲染更改 2025-04-14 16:45:40 +08:00
wangxiaoshuang b22374db9e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-14 14:04:37 +08:00
wangxiaoshuang ba17d51f72 文档模板需要区分Elevate和Extensive的需要。 2025-04-14 14:04:28 +08:00
caiyiling 0f9963d939 箭头工具更改
continuous-integration/drone/push Build is passing
2025-04-14 13:41:42 +08:00
caiyiling ca0d406e45 recist标准更改
continuous-integration/drone/push Build is passing
2025-04-14 13:11:00 +08:00
caiyiling 8e0ad5ca9d mRecist标准更改
continuous-integration/drone/push Build is passing
2025-04-14 11:39:53 +08:00
wangxiaoshuang e0321bae72 影像预览问题解决
continuous-integration/drone/push Build encountered an error
2025-04-12 12:04:20 +08:00
wangxiaoshuang 10c1fb0bbc 重传审批添加默认查询条件
continuous-integration/drone/push Build is passing
2025-04-11 15:42:24 +08:00
wangxiaoshuang 3ab9b48842 工作台增加通用培训
continuous-integration/drone/push Build is passing
2025-04-11 15:17:05 +08:00
wangxiaoshuang 58a590bbb7 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-10 17:46:47 +08:00
wangxiaoshuang b331b43b28 表格双击、授权按钮区分 2025-04-10 17:46:35 +08:00
caiyiling 162b649c3c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-10 17:12:06 +08:00
caiyiling fcc5398bcb 阅片更改 2025-04-10 17:11:47 +08:00
wangxiaoshuang 9df1444e3d 版本记录删除与下载问题
continuous-integration/drone/push Build is passing
2025-04-10 16:23:45 +08:00
wangxiaoshuang 0f944343b3 历史版本打开有误
continuous-integration/drone/push Build is passing
2025-04-10 15:46:14 +08:00
wangxiaoshuang adeecf0b07 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-04-10 15:41:23 +08:00
wangxiaoshuang 1965abc9fd 设置忽略异地登录 2025-04-10 15:41:13 +08:00
caiyiling 1c19301f28 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-10 15:26:31 +08:00
caiyiling 42711dadb5 dicom阅片更改 2025-04-10 15:26:11 +08:00
wangxiaoshuang d9d2a2169e 表格双击、展开行事件区分
continuous-integration/drone/push Build is passing
2025-04-10 14:53:16 +08:00
wangxiaoshuang 9775ef24c8 1
continuous-integration/drone/push Build is failing
2025-04-10 14:42:10 +08:00
wangxiaoshuang 9af3cd4280 稽查文档管理问题修复
continuous-integration/drone/push Build is passing
2025-04-10 14:32:21 +08:00
wangxiaoshuang ab058d6659 稽查文档排序、新增文件夹更换接口
continuous-integration/drone/push Build is passing
2025-04-10 13:27:10 +08:00
wangxiaoshuang 0d446746e6 稽查文档管理问题修复
continuous-integration/drone/push Build is passing
2025-04-10 10:29:25 +08:00
wangxiaoshuang aaa366934b 影像退回
continuous-integration/drone/push Build is passing
2025-04-10 09:56:02 +08:00
wangxiaoshuang 7614f7a327 1
continuous-integration/drone/push Build is passing
2025-04-09 15:59:36 +08:00
wangxiaoshuang 0035ac1266 邮件管理中子页的操作列中文显示为英文,英文环境下按钮位置需要调整
continuous-integration/drone/push Build is passing
2025-04-09 13:56:49 +08:00
wangxiaoshuang 298d335a03 【忘记密码】点击上一步无法退回到上一个页面
continuous-integration/drone/push Build is passing
2025-04-09 13:50:21 +08:00
wangxiaoshuang 1bddd30709 账户日志的操作类型支持多选
continuous-integration/drone/push Build is passing
2025-04-09 13:43:47 +08:00
wangxiaoshuang 1d6ebe6388 项目切换时,需要根据项目状态过滤项目
continuous-integration/drone/push Build is passing
2025-04-09 13:37:39 +08:00
wangxiaoshuang 236a565250 工作台稽查文档
continuous-integration/drone/push Build is passing
2025-04-09 10:05:30 +08:00
wangxiaoshuang 318954b360 稽查文档管理新增文件夹
continuous-integration/drone/push Build is passing
2025-04-08 17:28:40 +08:00
wangxiaoshuang 91d31b4226 稽查文档预览
continuous-integration/drone/push Build is passing
2025-04-08 16:17:54 +08:00
wangxiaoshuang 1fb76ca72d 稽查文档预览
continuous-integration/drone/push Build is passing
2025-04-08 15:09:04 +08:00
wangxiaoshuang b76d157fca 稽查文档管理
continuous-integration/drone/push Build is passing
2025-04-07 18:00:10 +08:00
wangxiaoshuang fa71af24ad 1
continuous-integration/drone/push Build is passing
2025-04-07 10:12:32 +08:00
wangxiaoshuang a9edab9227 稽查文档管理
continuous-integration/drone/push Build is failing
2025-04-03 17:35:25 +08:00
wangxiaoshuang 1e720e399d 确认收入项,修改选项后,其他文件也改了
continuous-integration/drone/push Build encountered an error
2025-04-03 11:15:54 +08:00
wangxiaoshuang 1368397da9 项目总览—>上传记录:中心编号 查询条件,查询结果不对 2025-04-03 11:15:36 +08:00
wangxiaoshuang c8c049b5d0 DICOM影像中,存在Tag最大像素值、最小像素值等,但是和实际的数据统计结果不同 2025-04-03 11:15:22 +08:00
wangxiaoshuang 31c9db368c 稽查文档管理
continuous-integration/drone/push Build is failing
2025-04-03 10:28:59 +08:00
wangxiaoshuang 866dc923c7 中心查询条件修改trialSiteId
continuous-integration/drone/push Build is failing
2025-04-03 09:46:21 +08:00
wangxiaoshuang a6b958ce4e dicom文件maxValue tag有问题 2025-04-03 09:45:50 +08:00
wangxiaoshuang 662cc93d85 稽查文档管理
continuous-integration/drone/push Build is failing
2025-04-01 17:59:24 +08:00
caiyiling e3ad114207 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2025-04-01 16:48:50 +08:00
caiyiling 0960b480a6 阅片页面更改 2025-04-01 16:48:04 +08:00
wangxiaoshuang 9a4eb1b210 工作台稽查文档
continuous-integration/drone/push Build is passing
2025-03-28 18:01:45 +08:00
wangxiaoshuang 0567534367 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2025-03-27 13:31:59 +08:00
wangxiaoshuang 481a436169 项目文档确认收入项问题解决 2025-03-27 13:31:54 +08:00
caiyiling 4188c0110f 非dicom阅片受试者内随机初始化图像逻辑更改
continuous-integration/drone/push Build is passing
2025-03-26 15:23:29 +08:00
wangxiaoshuang 01206716ab 1
continuous-integration/drone/push Build is passing
2025-03-24 16:56:27 +08:00
195 changed files with 32982 additions and 14926 deletions
+2 -1
View File
@@ -5,7 +5,8 @@ NODE_ENV = 'development'
VUE_APP_BASE_PATH = '/'
VUE_APP_IS_TEST = false
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://onlyoffice.test.extimaging.com"
# base api
VUE_APP_BASE_API = 'http://123.56.94.154:7000'
+3
View File
@@ -5,6 +5,9 @@ NODE_ENV = 'prod'
# base public path
VUE_APP_BASE_PATH = '/'
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://office.extimaging.com"
# 是否开启登陆限制 true:是 false:否
VUE_APP_LOGIN_FOR_PERMISSION = true
+2
View File
@@ -3,6 +3,8 @@ ENV = 'production'
NODE_ENV = 'production'
# base public path
VUE_APP_BASE_PATH = '/'
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://onlyoffice.test.extimaging.com"
VUE_APP_IS_TEST = true
+3
View File
@@ -4,6 +4,9 @@ NODE_ENV = 'production'
# base public path
VUE_APP_BASE_PATH = '/'
# onlyoffice地址
VUE_APP_ONLYOFFICE_URL = "https://onlyoffice.test.extimaging.com"
# base public path
VUE_APP_BASE_PATH = '/'
+23
View File
@@ -48,6 +48,7 @@
"nprogress": "^0.2.0",
"path-to-regexp": "^0.1.10",
"pdfobject": "^2.3.0",
"prismjs": "^1.30.0",
"qrcodejs2": "^0.0.2",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.5",
@@ -62,6 +63,7 @@
"vue-count-to": "^1.0.13",
"vue-demi": "^0.14.10",
"vue-i18n": "^8.28.2",
"vue-prism-editor": "^1.3.0",
"vue-puzzle-vcode": "^1.1.10",
"vue-router": "^3.0.6",
"vue-seamless-scroll": "^1.1.23",
@@ -18044,6 +18046,15 @@
"renderkid": "^3.0.0"
}
},
"node_modules/prismjs": {
"version": "1.30.0",
"resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.30.0.tgz",
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz",
@@ -22997,6 +23008,18 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/vue-prism-editor": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/vue-prism-editor/-/vue-prism-editor-1.3.0.tgz",
"integrity": "sha512-54RfgtMGRMNr9484zKMOZs1wyLDR6EfFylzE2QrMCD9alCvXyYYcS0vX8oUHh+6pMUu6ts59uSN9cHglpU2NRQ==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"vue": "^2.6.11"
}
},
"node_modules/vue-puzzle-vcode": {
"version": "1.1.10",
"resolved": "https://registry.npmmirror.com/vue-puzzle-vcode/-/vue-puzzle-vcode-1.1.10.tgz",
+2
View File
@@ -54,6 +54,7 @@
"nprogress": "^0.2.0",
"path-to-regexp": "^0.1.10",
"pdfobject": "^2.3.0",
"prismjs": "^1.30.0",
"qrcodejs2": "^0.0.2",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.5",
@@ -68,6 +69,7 @@
"vue-count-to": "^1.0.13",
"vue-demi": "^0.14.10",
"vue-i18n": "^8.28.2",
"vue-prism-editor": "^1.3.0",
"vue-puzzle-vcode": "^1.1.10",
"vue-router": "^3.0.6",
"vue-seamless-scroll": "^1.1.23",
+2 -2
View File
@@ -252,7 +252,7 @@ export default {
}
},
handleSave() {
this.$confirm('确定修改当前页面国际化内容?')
this.$confirm(this.$t("i18n:confirm:updatei18n"))
.then(() => {
batchAddOrUpdateFrontInternationalization(this.tableData).then(
async (res) => {
@@ -270,7 +270,7 @@ export default {
i18n.mergeLocaleMessage('zh', zhMessages)
i18n.mergeLocaleMessage('en', enMessages)
this.drawer = false
this.$message.success('国际化修改成功')
this.$message.success(this.$t("i18n:message:updatei18nSuccessfully"))
if (this.il8nExternal) {
this.$EventBus.$emit('il8nUpdate')
}
+80 -4
View File
@@ -212,7 +212,20 @@ export function getSystemDocumentList(param) {
data: param
})
}
export function publishSystemDocument(param) {
return request({
url: `/SystemDocument/publishSystemDocument`,
method: 'post',
data: param
})
}
export function outLineSystemDocument(param) {
return request({
url: `/SystemDocument/outLineSystemDocument`,
method: 'post',
data: param
})
}
export function addOrUpdateSystemDocument(param) {
return request({
url: `/SystemDocument/addOrUpdateSystemDocument`,
@@ -220,6 +233,29 @@ export function addOrUpdateSystemDocument(param) {
data: param
})
}
// 新增/修改通用培训附件
export function addOrUpdateSystemDocumentAttachment(param) {
return request({
url: `/SystemDocument/addOrUpdateSystemDocumentAttachment`,
method: 'post',
data: param
})
}
// 通用培训附件列表
export function getSystemDocumentAttachmentList(param) {
return request({
url: `/SystemDocument/getSystemDocumentAttachmentList`,
method: 'post',
data: param
})
}
// 删除通用培训附件
export function deleteSystemDocumentAttachment(systemDocumentAttachmentId) {
return request({
url: `/SystemDocument/deleteSystemDocumentAttachment/${systemDocumentAttachmentId}`,
method: 'delete',
})
}
export function deleteSystemDocument(id) {
return request({
@@ -382,10 +418,11 @@ export function addOrUpdateBasicDic(param) {
})
}
export function getDictionaryChildList(id) {
export function getDictionaryChildList(data) {
return request({
url: `/Dictionary/getChildList/${id}`,
method: 'get'
url: `/Dictionary/getChildList`,
method: 'post',
data
})
}
@@ -1321,3 +1358,42 @@ export function deleteAttachment(data) {
data
})
}
// 项目文档-获取历史记录列表
export function getTrialHistoryRecordFileList(data) {
return request({
url: `/TrialHistoryRecordFile/getTrialHistoryRecordFileList`,
method: 'post',
data
})
}
// 项目文档-新增/修改历史记录
export function addOrUpdateTrialHistoryRecordFile(data) {
return request({
url: `/TrialHistoryRecordFile/addOrUpdateTrialHistoryRecordFile`,
method: 'post',
data
})
}
// 项目文档-批量新增历史记录
export function batchAddTrialHistoryRecordFile(data) {
return request({
url: `/TrialHistoryRecordFile/batchAddTrialHistoryRecordFile`,
method: 'post',
data
})
}
// 项目文档-删除历史记录
export function deleteTrialHistoryRecordFile(id) {
return request({
url: `/TrialHistoryRecordFile/deleteTrialHistoryRecordFile/${id}`,
method: 'delete',
})
}
// 邮件管理-批量修改邮件
export function batchUpdateEmail(data) {
return request({
url: `/EmailNoticeConfig/batchUpdateEmail`,
method: 'post',
data
})
}
+12 -3
View File
@@ -45,10 +45,19 @@ export function changeFrontAuditSort(param) {
})
}
export function getModuleTypeDescriptionList(param) {
export function getModuleTypeDescriptionList(params) {
return request({
url: `${param === '' ? '/FrontAuditConfig/getModuleTypeDescriptionList' : '/FrontAuditConfig/getModuleTypeDescriptionList?moduleTypeId=' + param}`,
method: 'get'
url: `/FrontAuditConfig/getModuleTypeDescriptionList`,
method: 'get',
params
})
}
export function getModuleTypeList(data) {
return request({
url: `/FrontAuditConfig/getModuleTypeList`,
method: 'post',
data
})
}
+17 -1
View File
@@ -72,7 +72,14 @@ export function getReadingTaskList_Export(param) {
data: param
})
}
export function getTrialVisitImageStatList_Export(param) {
return requestDownload({
url: '/ExcelExport/getTrialVisitImageStatList_Export',
method: 'post',
responseType: 'blob',
data: param
})
}
export function getReReadingTaskList_Export(param) {
return requestDownload({
url: '/ExcelExport/getReReadingTaskList_Export',
@@ -178,6 +185,15 @@ export function pMTrainingRecordList_Export(data) {
data
})
}
// 导出系统培训记录
export function getSysDocumentConfirmList_Export(data) {
return requestDownload({
url: `/ExcelExport/getSysDocumentConfirmList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出影像指控
export function qCVisitList_Export(data) {
return requestDownload({
+204 -1
View File
@@ -1035,7 +1035,27 @@ export function getQCVisitList(param) {
data: param
})
}
export function getImageBackList(param) {
return request({
url: `/QCList/getImageBackList`,
method: 'post',
data: param
})
}
export function getImageBackApplyUserList(params) {
return request({
url: `/QCList/getImageBackApplyUserList`,
method: 'get',
params
})
}
export function auditImageBack(params) {
return request({
url: `/QCOperation/auditImageBack`,
method: 'put',
params
})
}
export function getQCChallengeList(param) {
return request({
url: `/QCList/getQCChallengeList`,
@@ -1599,6 +1619,13 @@ export function getDocumentConfirmList(param) {
data: param
})
}
export function getSysDocumentConfirmList(param) {
return request({
url: `/TrialDocument/getSysDocumentConfirmList`,
method: 'post',
data: param
})
}
export function getTrialUserSelect(trialId) {
return request({
url: `/TrialDocument/getTrialUserSelect/${trialId}`,
@@ -1613,6 +1640,13 @@ export function getTrialDocAndSystemDocType(trialId) {
})
}
export function getSysDocSignUserList() {
return request({
url: `/TrialDocument/getSysDocSignUserList`,
method: 'get'
})
}
export function updateSubjectStatus(param) {
return request({
url: `/Subject/updateSubjectStatus`,
@@ -3308,6 +3342,13 @@ export function getReReadingApplyToBeDoneList(param) {
data: param
})
}
export function getPMImageBackToBeDoneList(param) {
return request({
url: `/PersonalWorkstation/getPMImageBackToBeDoneList`,
method: 'post',
data: param
})
}
export function deleteClinicalForm(param) {
return request({
@@ -3995,3 +4036,165 @@ export function deleteTrialFileType(id) {
})
}
// 工作台-获取稽查文档
export function getAuditDocumentData(data) {
return request({
url: `/AuditDocument/getAuditDocumentData`,
method: 'post',
data
})
}
// 工作台-新增稽查文档
export function addAuditDocument(data) {
return request({
url: `/AuditDocument/addAuditDocument`,
method: 'post',
data
})
}
// 工作台-获取当前目录层级
export function getBreadcrumbData(data) {
return request({
url: `/AuditDocument/getBreadcrumbData`,
method: 'post',
data
})
}
// 工作台-修改稽查文档
export function updateAuditDocument(data) {
return request({
url: `/AuditDocument/updateAuditDocument`,
method: 'post',
data
})
}
// 工作台-删除稽查文档
export function deleteAuditDocument(data) {
return request({
url: `/AuditDocument/deleteAuditDocument`,
method: 'post',
data
})
}
// 工作台-稽查文档获取历史版本
export function getHistoricalVersion(data) {
return request({
url: `/AuditDocument/getHistoricalVersion`,
method: 'post',
data
})
}
// 工作台-稽查文档设置当前版本
export function setCurrentVersion(data) {
return request({
url: `/AuditDocument/setCurrentVersion`,
method: 'post',
data
})
}
// 工作台-稽查文档移动
export function movieFileOrFolder(data) {
return request({
url: `/AuditDocument/movieFileOrFolder`,
method: 'post',
data
})
}
// 工作台-稽查文档复制
export function copyFileOrFolder(data) {
return request({
url: `/AuditDocument/copyFileOrFolder`,
method: 'post',
data
})
}
// 工作台-稽查文档授权
export function setIsAuthorization(data) {
return request({
url: `/AuditDocument/setIsAuthorization`,
method: 'post',
data
})
}
// 工作台-稽查文档新增文件夹
export function addFolder(data) {
return request({
url: `/AuditDocument/addFolder`,
method: 'post',
data
})
}
// 配置-项目文档发布
export function publishTrialDocument(data) {
return request({
url: `/TrialDocument/publishTrialDocument`,
method: 'post',
data
})
}
// 配置-获取项目文档附件列表
export function getTrialDocumentAttachmentList(data) {
return request({
url: `/TrialDocument/getTrialDocumentAttachmentList`,
method: 'post',
data
})
}
// 配置-新增或修改项目文档附件
export function addOrUpdateTrialDocumentAttachment(data) {
return request({
url: `/TrialDocument/addOrUpdateTrialDocumentAttachment`,
method: 'post',
data
})
}
// 配置-删除项目文档附件
export function deleteTrialDocumentAttachment(data) {
return request({
url: `/TrialDocument/deleteTrialDocumentAttachment/${data}`,
method: 'delete',
})
}
// 配置-获取稽查管理列表
export function getTrialShowInspection(data) {
return request({
url: `/Inspection/getTrialShowInspection`,
method: 'post',
data
})
}
// 配置-设置稽查管理配置
export function setTrialShowInspection(data) {
return request({
url: `/Inspection/setTrialShowInspection`,
method: 'post',
data
})
}
// 影像汇总-获取列表
export function getTrialVisitImageStatList(data) {
return request({
url: `/DownloadAndUpload/getTrialVisitImageStatList`,
method: 'post',
data
})
}
// 影像汇总-获取统计
export function getTrialVisitImageStatInfo(params) {
return request({
url: `/DownloadAndUpload/getTrialVisitImageStatInfo`,
method: 'get',
params
})
}
// 影像汇总-影像下载
export function getExportSubjectVisitImageList(data) {
return request({
url: `/DownloadAndUpload/getExportSubjectVisitImageList`,
method: 'post',
data
})
}
+12 -4
View File
@@ -346,9 +346,9 @@ export function getReReadingOrBackInfluenceTaskList(taskId, isReReading, applyId
})
}
export function PMSetTaskBack(trialId, taskId) {
export function PMSetTaskBack(trialId, taskId, pmBackReason) {
return request({
url: `/VisitTask/PMSetTaskBack/${trialId}/${taskId}`,
url: `/VisitTask/PMSetTaskBack/${trialId}/${taskId}/${pmBackReason}`,
method: 'put'
})
}
@@ -459,9 +459,9 @@ export function setMedicalReviewInvalid(params) {
})
}
export function getTrialCriterionList(trialId) {
export function getTrialCriterionList(trialId, isRandom = false) {
return request({
url: `/VisitTask/getTrialCriterionList?TrialId=${trialId}`,
url: `/VisitTask/getTrialCriterionList?TrialId=${trialId}&isRandom=${isRandom}`,
method: 'get'
})
}
@@ -480,3 +480,11 @@ export function resetReadingRestTime() {
method: 'post'
})
}
// 设置随机排序
export function setRandomTaskOrder(data) {
return request({
url: `/VisitTask/setRandomTaskOrder`,
method: 'post',
data
})
}
+8
View File
@@ -287,4 +287,12 @@ export function forwardSVDicomImage(param) {
data: param
})
}
// crc、iqc申请影像退回
export function requestImageBack(params) {
return request({
url: `/QCOperation/requestImageBack`,
method: 'put',
params
})
}
+8
View File
@@ -209,3 +209,11 @@ export function loginSelectUserRole(params) {
params,
})
}
// 忽略异地登录
export function setIsIgnoreUncommonly(data) {
return request({
url: `/User/setIsIgnoreUncommonly`,
method: 'post',
data,
})
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+27 -32
View File
@@ -1,15 +1,7 @@
<template>
<div
id="canvas"
ref="canvas"
v-loading="loading"
element-loading-text="Loading..."
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="Loading..."
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>
@@ -26,9 +18,11 @@
<div v-show="dicomInfo.location">Location {{ dicomInfo.location }}mm</div> -->
<!-- <div v-show="toolState.clipPlaying">FPS {{ dicomInfo.fps }}</div> -->
<div v-show="mousePosition.mo">
Pos: {{ mousePosition.x?mousePosition.x.toFixed(0):'' }}, {{ mousePosition.y?mousePosition.y.toFixed(0):'' }}
Pos: {{ mousePosition.x ? mousePosition.x.toFixed(0) : '' }}, {{ mousePosition.y ? mousePosition.y.toFixed(0) :
'' }}
</div>
<div v-if="(dicomInfo.modality === 'CT' || dicomInfo.modality === 'DR' || dicomInfo.modality === 'CR') && mousePosition.mo">
<div
v-if="(dicomInfo.modality === 'CT' || dicomInfo.modality === 'DR' || dicomInfo.modality === 'CR') && mousePosition.mo">
HU: {{ mousePosition.mo }}
</div>
<div v-else-if="(dicomInfo.modality === 'PT' && mousePosition.suv)">
@@ -53,8 +47,12 @@
<!-- <div v-show="dicomInfo.acc">ACC {{ dicomInfo.acc }}</div> -->
<!-- <div>{{ dicomInfo.time }}</div> -->
</div>
<div ref="sliderBox" class="my_slider_box" style="position: absolute;right: 1px;height: calc(100% - 100px);transform: translateY(-50%);top: calc(50% - 30px);width: 10px;background: #333;cursor: pointer" @click.stop="goViewer($event)">
<div :style="{top: height + '%'}" style="z-index:10;background: #9e9e9e;height: 20px;width: 100%;position: absolute;top: 0;cursor: move" @mousedown="sliderMousedown($event)" />
<div ref="sliderBox" class="my_slider_box"
style="position: absolute;right: 1px;height: calc(100% - 100px);transform: translateY(-50%);top: calc(50% - 30px);width: 10px;background: #333;cursor: pointer"
@click.stop="goViewer($event)">
<div :style="{ top: height + '%' }"
style="z-index:10;background: #9e9e9e;height: 20px;width: 100%;position: absolute;top: 0;cursor: move"
@mousedown="sliderMousedown($event)" />
</div>
<div style="position: absolute;left: 50%;top: 15px;color: #f44336;">
{{ markers.top }}
@@ -81,15 +79,8 @@
<!-- <div v-show="stack.firstImageLoading" class="load-indicator">
Loading Series #{{ stack.seriesNumber }}...
</div>-->
<el-dialog
v-if="dcmTag.visible"
:visible.sync="dcmTag.visible"
:close-on-click-modal="false"
:title="dcmTag.title"
width="1000px"
custom-class="base-dialog-wrapper"
append-to-body
>
<el-dialog v-if="dcmTag.visible" :visible.sync="dcmTag.visible" :close-on-click-modal="false" :title="dcmTag.title"
width="1000px" custom-class="base-dialog-wrapper" append-to-body>
<dicom-tags :image-id="stack.imageIds[stack.currentImageIdIndex]" @close="dcmTag.visible = false" />
</el-dialog>
</div>
@@ -263,9 +254,9 @@ export default {
)
if (!toolAlreadyAddedToElement) {
if (toolName === 'RectangleRoi') {
cornerstoneTools.addToolForElement(element, apiTool, { configuration: { showMinMax: true, showStatsText: true}})
cornerstoneTools.addToolForElement(element, apiTool, { configuration: { showMinMax: true, showStatsText: true } })
} else if (toolName === 'EllipticalRoi') {
cornerstoneTools.addToolForElement(element, apiTool, { configuration: { showMinMax: true}})
cornerstoneTools.addToolForElement(element, apiTool, { configuration: { showMinMax: true } })
} else {
cornerstoneTools.addToolForElement(element, apiTool)
}
@@ -328,7 +319,7 @@ export default {
// cornerstoneTools.addStackStateManager(this.canvas, ['stack', 'stackPrefetch', 'playClip'])
cornerstoneTools.addToolState(this.canvas, 'stack', this.stack)
// cornerstoneTools.stackPrefetch.enable(this.canvas)
cornerstone.updateImage(element, true)
cornerstone.updateImage(element, true)
// cornerstoneTools.stackPrefetch.setConfiguration({ maxImagesToPrefetch: Infinity,
// preserveExistingPool: true })
// cornerstoneTools.stackPrefetch.enable(this.canvas)
@@ -368,9 +359,8 @@ export default {
data.string('x00080030')
)
this.dicomInfo.series = data.string('x00200011')
this.dicomInfo.frame = `${this.stack.currentImageIdIndex + 1}/${
this.stack.imageIds.length
}`
this.dicomInfo.frame = `${this.stack.currentImageIdIndex + 1}/${this.stack.imageIds.length
}`
this.dicomInfo.size = `${data.uint16('x00280011')}x${data.uint16(
'x00280010'
)}`
@@ -388,6 +378,7 @@ export default {
this.stack.imageIdIndex = newImageIdIndex
this.series.imageIdIndex = newImageIdIndex
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
this.resetWwwc()
},
stackScrollCallback(e) {
const { detail } = e
@@ -678,7 +669,7 @@ export default {
cornerstoneTools.getToolState(
this.canvas,
'playClip'
).data[0].loop = false
).data[0].loop = true
},
setFps(fps) {
this.dicomInfo.fps = fps
@@ -1136,6 +1127,7 @@ export default {
font-size: 12px;
/* z-index: 1; */
}
.info-image {
position: absolute;
left: 10px;
@@ -1155,6 +1147,7 @@ export default {
font-size: 12px;
/* z-index: 1; */
}
.info-instance {
position: absolute;
right: 15px;
@@ -1187,6 +1180,7 @@ export default {
margin: 10px;
cursor: default;
}
.menu__item:hover {
color: #ff0000;
}
@@ -1206,7 +1200,8 @@ li:hover {
background-color: #e0e0e2;
color: white;
}
.my_slider_box:after{
.my_slider_box:after {
content: '';
position: absolute;
bottom: -20px;
+29 -15
View File
@@ -1,28 +1,30 @@
<template>
<div class="preview-wrapper">
<iframe
v-if="fileType.indexOf('jpg') !== -1 || fileType.indexOf('png') !== -1"
frameborder="0"
:src="filePath"
width="100%"
height="100%"
/>
<iframe v-if="fileType.indexOf('jpg') !== -1 || fileType.indexOf('png') !== -1" frameborder="0" :src="filePath"
width="100%" height="100%" />
<!-- <embed v-else-if="fileType.indexOf('pdf') !== -1" :src="filePath+'#toolbar=0'" style="width: 100%; height: 100%"> -->
<!-- <iframe v-else-if="fileType.indexOf('pdf') !== -1" :src="filePath+'#toolbar=0'" width="100%" height="100%" frameborder="0" /> -->
<iframe v-else-if="fileType.indexOf('pdf') !== -1" :src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${filePath}?userName=${currentUser}&COMPANY=${COMPANY}`" width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
<iframe v-else-if="fileType.indexOf('pdf') !== -1"
:src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${filePath}?userName=${currentUser}&COMPANY=${COMPANY}`"
width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
<!-- <pdf-->
<!-- v-else-if="fileType.indexOf('pdf') !== -1"-->
<!-- :src="`/static/pdfjs/web/viewer.html?file=${filePath}`">-->
<!-- </pdf>-->
<div v-else>
<video :src="`${OSSclientConfig.basePath}${filePath}`" style="width: 100%;height: 99%;" autoplay controls
controlsList="nodownload" v-else-if="fileType.indexOf('mp4') !== -1"></video>
<iframe v-else
:src="`/static/onlyOffice/viewer.html?url=${OSSclientConfig.basePath}${filePath}?onlyOffice_url=${onlyOffice_url}&type=${fileType}&title=${title}&documentType=${documentType}&userName=${currentUser}`"
width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
<!-- <div v-else>
{{ $t('common:message:downloadFile') }}
<el-link type="primary" @click="downLoadFile">{{ $t('common:button:download') }}</el-link>
</div>
</div> -->
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import DOCUMENTTYPE from "@/utils/onlyOffice_type.js"
export default {
name: 'PreviewFile',
computed: {
@@ -36,12 +38,22 @@ export default {
fileType: {
type: String,
required: true
}
},
title: {
type: String,
default: ''
},
},
data() {
return {
currentUser: zzSessionStorage.getItem('userName'),
COMPANY:process.env.VUE_APP_COMPANY_NAME
COMPANY: process.env.VUE_APP_COMPANY_NAME,
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL
}
},
computed: {
documentType() {
return DOCUMENTTYPE[`.${this.fileType}`]
}
},
mounted() {
@@ -62,14 +74,16 @@ export default {
}
</script>
<style lang="scss">
.preview-wrapper{
.preview-wrapper {
height: 100%;
width:100%;
width: 100%;
padding: 10px;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
+23
View File
@@ -0,0 +1,23 @@
import Vue from "vue";
import OnlyOffice from "./index.vue";
const PreviewConstructor = Vue.extend(OnlyOffice);
const onlyOffice = options => {
const { path, type, title } = options;
if (!path) throw `path is requred.but ${path}`
const id = `OnlyOffice_${new Date().getTime()}`;
const instance = new PreviewConstructor();
instance.id = id;
instance.vm = instance.$mount();
if (instance.vm.visible) return;
document.body.appendChild(instance.vm.$el);
instance.vm.open(path, type, title);
instance.vm.$on("closed", () => {
instance.vm.docEditor = null
document.body.removeChild(instance.vm.$el);
instance.vm.$destroy();
});
return instance.vm;
}
export default onlyOffice;
@@ -0,0 +1,7 @@
import OnlyOffice from "./index.vue";
import onlyOffice from "./fun";
export default Vue => {
Vue.component(OnlyOffice.name, OnlyOffice);
Vue.prototype.$onlyOffice = onlyOffice;
};
@@ -0,0 +1,46 @@
<template>
<el-dialog v-if="visible" :visible.sync="visible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper" @close="handleClose">
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<iframe v-if="visible"
:src="`/static/onlyOffice/viewer.html?url=${OSSclientConfig.basePath}${path}?onlyOffice_url=${onlyOffice_url}&type=${type}&title=${title}&documentType=${documentType}&userName=${currentUser}`"
width="100%" height="99%" frameborder="0" crossorigin="anonymous" />
</div>
</el-dialog>
</template>
<script>
import DOCUMENTTYPE from "@/utils/onlyOffice_type.js"
export default {
name: "OnlyOffice",
data() {
return {
visible: false,
path: null,
type: null,
title: null,
documentType: null,
currentUser: zzSessionStorage.getItem('userName'),
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL
};
},
methods: {
open(path, type, title) {
this.path = path;
this.type = type.toLowerCase();
this.documentType = DOCUMENTTYPE[`.${this.type}`]
this.title = title;
this.visible = true;
},
handleClose() {
this.$emit("closed");
},
},
};
</script>
<style lang="scss" scoped>
#placeholder {
width: 100%;
height: 100%;
}
</style>
+23
View File
@@ -0,0 +1,23 @@
import Vue from "vue";
import Video from "./index.vue";
const PreviewConstructor = Vue.extend(Video);
const video = options => {
const { path, type, title } = options;
if (!path) throw `path is requred.but ${path}`
const id = `OnlyOffice_${new Date().getTime()}`;
const instance = new PreviewConstructor();
instance.id = id;
instance.vm = instance.$mount();
if (instance.vm.visible) return;
document.body.appendChild(instance.vm.$el);
instance.vm.open(path, type, title);
instance.vm.$on("closed", () => {
instance.vm.docEditor = null
document.body.removeChild(instance.vm.$el);
instance.vm.$destroy();
});
return instance.vm;
}
export default video;
+7
View File
@@ -0,0 +1,7 @@
import Video from "./index.vue";
import video from "./fun";
export default Vue => {
Vue.component(Video.name, Video);
Vue.prototype.$video = video;
};
+38
View File
@@ -0,0 +1,38 @@
<template>
<el-dialog v-if="visible" :visible.sync="visible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper" @close="handleClose">
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<video :src="path" style="width: 100%;height: 99%;" autoplay controls controlsList="nodownload"></video>
</div>
</el-dialog>
</template>
<script>
export default {
name: "Video",
data() {
return {
visible: false,
path: null,
type: null,
title: null,
};
},
methods: {
open(path, type, title) {
this.path = this.OSSclientConfig.basePath + path;
this.title = title;
this.visible = true;
},
handleClose() {
this.$emit("closed");
},
},
};
</script>
<style lang="scss" scoped>
#placeholder {
width: 100%;
height: 100%;
}
</style>
@@ -1,21 +1,16 @@
<template>
<div class="criterion-form-item">
<div
v-if="!!question.QuestionName && question.ClinicalQuestionType==='group'"
style="font-weight: bold;font-size: 16px;margin: 5px 0px;margin-bottom: 10px"
>
{{ language==='en'?question.QuestionEnName:question.QuestionName }}
<div v-if="!!question.QuestionName && question.ClinicalQuestionType === 'group'"
style="font-weight: bold;font-size: 16px;margin: 5px 0px;margin-bottom: 10px">
{{ language === 'en' ? question.QuestionEnName : question.QuestionName }}
</div>
<div v-else-if="question.ClinicalQuestionType === 'summary'"
style="background:#f3f3f3;border-radius:4px;font-size: 12px;margin: 5px 0px;margin-bottom: 10px;font-size: 12px;padding: 10px">
{{ language === 'en' ? question.QuestionEnName : question.QuestionName }}
</div>
<div
v-else-if="question.ClinicalQuestionType==='summary'"
style="background:#f3f3f3;border-radius:4px;font-size: 12px;margin: 5px 0px;margin-bottom: 10px;font-size: 12px;padding: 10px"
>
{{ language==='en'?question.QuestionEnName:question.QuestionName }}
</div>
<div
v-else-if="question.ClinicalQuestionType==='table' && ((question.ClinicalQuestionShowEnum===1 && question.ParentTriggerValue === questionForm[question.ParentId].toString()) || question.ClinicalQuestionShowEnum===0)"
style="font-weight: bold;font-size: 14px;margin: 5px 0px;"
>
v-else-if="question.ClinicalQuestionType === 'table' && ((question.ClinicalQuestionShowEnum === 1 && question.ParentTriggerValue === questionForm[question.ParentId].toString()) || question.ClinicalQuestionShowEnum === 0)"
style="font-weight: bold;font-size: 14px;margin: 5px 0px;">
<div style="display: flex;justify-content: space-between;">
<span>
{{ question.QuestionName }}
@@ -25,27 +20,23 @@
{{ $t('trials:readingUnit:qsList:title:add') }}
</el-button>
</div>
<el-table
:data="questionForm[question.Id]"
>
<el-table-column
v-for="item of question.TableQuestions"
:key="item.Id"
:prop="item.Id"
:label="item.QuestionName"
min-width="100"
show-overflow-tooltip
/>
<el-table-column
:label="$t('common:action:action')"
min-width="100"
show-overflow-tooltip
>
<el-table :data="questionForm[question.Id]">
<el-table-column v-for="item of question.TableQuestions" :key="item.Id" :prop="item.Id"
:label="item.QuestionName" min-width="100" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row[item.Id] && Array.isArray(scope.row[item.Id]) ?
scope.row[item.Id].join(" | ")
: scope.row[item.Id] }}
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')" min-width="100" show-overflow-tooltip>
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openAddTableCol(question, scope.$index)">
{{ $t('common:button:edit') }}
</el-button>
<el-button type="text" size="mini" v-if="scope.row.IsCurrentTaskAdd === 'True' || !question.IsCopyLesions || IsBaseline" @click="deleteTableCol(question, scope.$index)">
<el-button type="text" size="mini"
v-if="scope.row.IsCurrentTaskAdd === 'True' || !question.IsCopyLesions || IsBaseline"
@click="deleteTableCol(question, scope.$index)">
{{ $t('common:button:delete') }}
</el-button>
</template>
@@ -54,187 +45,109 @@
</div>
<el-col v-else :span="12">
<el-form-item
v-if="(question.ClinicalQuestionShowEnum===1 && question.ParentTriggerValue === questionForm[question.ParentId].toString()) || question.ClinicalQuestionShowEnum===0"
:label="`${question.QuestionName}`"
:prop="question.Id"
:rules="[
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (question.RelevanceValue === questionForm[question.RelevanceId].toString()))) && question.ClinicalQuestionType !== 'summary' && question.ClinicalQuestionType!=='group' && question.ClinicalQuestionType!=='table',
message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']}
]"
:class="[question.Type==='group'?'mb':question.Type==='upload'?'uploadWrapper':'']"
>
v-if="(question.ClinicalQuestionShowEnum === 1 && question.ParentTriggerValue === questionForm[question.ParentId].toString()) || question.ClinicalQuestionShowEnum === 0"
:label="`${question.QuestionName}`" :prop="question.Id" :rules="[
{
required: (question.IsRequired === 0 || (question.IsRequired === 1 && question.RelevanceId && (question.RelevanceValue === questionForm[question.RelevanceId].toString()))) && question.ClinicalQuestionType !== 'summary' && question.ClinicalQuestionType !== 'group' && question.ClinicalQuestionType !== 'table',
message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
}
]" :class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' ? 'uploadWrapper' : '']">
<!-- 输入框 -->
<el-input
v-if="question.ClinicalQuestionType==='input'"
v-model="questionForm[question.Id]"
<el-input v-if="question.ClinicalQuestionType === 'input'" v-model="questionForm[question.Id]"
:disabled="question.TableQuestionType === 2"
:max-length="question.MaxAnswerLength ? question.MaxAnswerLength : 200"
/>
:max-length="question.MaxAnswerLength ? question.MaxAnswerLength : 200" />
<!-- 多行文本输入框 -->
<el-input
v-if="question.ClinicalQuestionType==='textarea'"
v-model="questionForm[question.Id]"
type="textarea"
:max-length="question.MaxAnswerLength ? question.MaxAnswerLength : 200"
:autosize="{ minRows: 2, maxRows: 4}"
/>
<el-input v-if="question.ClinicalQuestionType === 'textarea'" v-model="questionForm[question.Id]"
type="textarea" :max-length="question.MaxAnswerLength ? question.MaxAnswerLength : 200"
:autosize="{ minRows: 2, maxRows: 4 }" />
<!-- 下拉框 -->
<el-select
v-if="question.ClinicalQuestionType==='select'"
v-model="questionForm[question.Id]"
clearable
<el-select v-if="question.ClinicalQuestionType === 'select'" v-model="questionForm[question.Id]" clearable
:disabled="(question.TableQuestionType === 2 || question.QuestionGenre === 2) && !!question.DictionaryCode"
@change="((val)=>{formItemChange(val, question)})"
>
@change="((val) => { formItemChange(val, question) })">
<template v-if="question.TableQuestionType === 1">
<el-option
v-for="item in organList"
:key="item.Id"
:label="item[question.DataTableColumn]"
:value="item[question.DataTableColumn]"
/>
<el-option v-for="item in organList" :key="item.Id" :label="item[question.DataTableColumn]"
:value="item[question.DataTableColumn]" />
</template>
<template v-else-if="question.TableQuestionType === 3 || question.QuestionGenre === 3">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
<el-option v-for="item of $d[question.DictionaryCode]" :key="item.id" :value="item.value"
:label="item.label" />
</template>
<template v-else-if="(question.TableQuestionType === 2 || question.QuestionGenre === 2) && question.DictionaryCode">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
<template
v-else-if="(question.TableQuestionType === 2 || question.QuestionGenre === 2) && question.DictionaryCode">
<el-option v-for="item of $d[question.DictionaryCode]" :key="item.id" :value="item.value"
:label="item.label" />
</template>
<template v-else>
<el-option
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
:value="val.trim()"
/>
<el-option v-for="val in question.TypeValue.split('|')" :key="val" :label="val" :value="val.trim()" />
</template>
</el-select>
<!-- 日期 -->
<el-date-picker v-if="question.ClinicalQuestionType === 'time'" v-model="questionForm[question.Id]"
style="width: 200px" align="right" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" />
<!-- 单选 -->
<el-date-picker
v-if="question.ClinicalQuestionType === 'time'"
v-model="questionForm[question.Id]"
style="width: 200px"
align="right"
type="date"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
/>
<!-- 单选 -->
<el-radio-group
v-if="question.ClinicalQuestionType==='radio'"
v-model="questionForm[question.Id]"
@change="((val)=>{formItemChange(val, question)})"
>
<el-radio-group v-if="question.ClinicalQuestionType === 'radio'" v-model="questionForm[question.Id]"
@change="((val) => { formItemChange(val, question) })">
<template v-if="question.DictionaryCode">
<el-radio
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:label="item.value"
>
<el-radio v-for="item of $d[question.DictionaryCode]" :key="item.id" :label="item.value">
{{ item.label }}
</el-radio>
</template>
<template v-if="question.TypeValue">
<el-radio
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
<el-radio v-for="val in question.TypeValue.split('|')" :key="val" :label="val">
{{ val }}
</el-radio>
</template>
</el-radio-group>
<!-- 复选框 -->
<el-checkbox-group
v-if="question.ClinicalQuestionType==='checkbox' && questionForm[question.Id] !== ''"
v-model="questionForm[question.Id]"
>
<el-checkbox
v-for="val of question.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
>
<el-checkbox-group v-if="question.ClinicalQuestionType === 'checkbox' && questionForm[question.Id] !== ''"
v-model="questionForm[question.Id]">
<el-checkbox v-for="val of question.TypeValue.split('|')" :key="val" :label="val" :value="val">
{{ val }}
</el-checkbox>
</el-checkbox-group>
<el-input
v-if="question.ClinicalQuestionType === 'number'"
:ref="question.Id"
v-model="questionForm[question.Id]"
type="number"
style="width: 200px"
:disabled="question.CustomCalculateMark > 0"
@input="limitInput($event, questionForm, question)"
>
<el-input v-if="question.ClinicalQuestionType === 'number'" :ref="question.Id"
v-model="questionForm[question.Id]" type="number" style="width: 200px"
:disabled="question.CustomCalculateMark > 0" @input="limitInput($event, questionForm, question)">
<template v-if="question.Unit" slot="append">{{ question.Unit }}</template>
</el-input>
<span v-if="question.CustomCalculateMark === 11 && question.ClinicalQuestionType === 'number'" v-show="questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] <= questionForm[JSON.parse(question.CalculateQuestions)[0].QuestionId]" style="margin-left: 10px">
{{ questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] }}~{{ questionForm[JSON.parse(question.CalculateQuestions)[0].QuestionId] }}
<span v-if="question.CustomCalculateMark === 11 && question.ClinicalQuestionType === 'number'"
v-show="questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] <= questionForm[JSON.parse(question.CalculateQuestions)[0].QuestionId]"
style="margin-left: 10px">
{{ questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] }}~{{
questionForm[JSON.parse(question.CalculateQuestions)[0].QuestionId] }}
</span>
<span v-if="question.CustomCalculateMark === 10 && question.ClinicalQuestionType === 'number' && questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId]" style="margin-left: 10px">
{{ questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] }}~{{ questionForm.CreateTime ? questionForm.CreateTime : parseTime(new Date(), '{y}-{m}-{d}') }}
<span
v-if="question.CustomCalculateMark === 10 && question.ClinicalQuestionType === 'number' && questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId]"
style="margin-left: 10px">
{{ questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] }}~{{ questionForm.CreateTime ?
questionForm.CreateTime : parseTime(new Date(), '{y}-{m}-{d}') }}
</span>
<!-- 生日不能大于截止日期 -->
<span v-if="question.CustomCalculateMark === 11 && question.ClinicalQuestionType === 'number'" v-show="questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] > questionForm[JSON.parse(question.CalculateQuestions)[0].QuestionId]" style="margin-left: 10px;font-size: 12px;color:#f66">
<span v-if="question.CustomCalculateMark === 11 && question.ClinicalQuestionType === 'number'"
v-show="questionForm[JSON.parse(question.CalculateQuestions)[0].TableQuestionId] > questionForm[JSON.parse(question.CalculateQuestions)[0].QuestionId]"
style="margin-left: 10px;font-size: 12px;color:#f66">
{{ $t('trials:components:clinicalDataQS:msg:birthDay') }}
</span>
</el-form-item>
</el-col>
<!-- eslint-disable vue/no-use-v-if-with-v-for -->
<!-- eslint-disable vue/valid-v-for -->
<el-col v-for="(item) in question.Childrens" :key="item.Id" v-if="question.Childrens && question.Childrens.length>0 && question.ClinicalQuestionType !== 'table'" :span="['group', 'summary', 'table'].includes(item.ClinicalQuestionType) || item.Childrens.length > 0 ? 24 : 12">
<QuestionFormItem
:key="item.Id"
:question="item"
:question-form="questionForm"
:trial-clinical-id="trialClinicalId"
@formItemNumberChange="formItemNumberChange"
@setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData"
/>
<el-col v-for="(item) in question.Childrens" :key="item.Id"
v-if="question.Childrens && question.Childrens.length > 0 && question.ClinicalQuestionType !== 'table'"
:span="['group', 'summary', 'table'].includes(item.ClinicalQuestionType) || item.Childrens.length > 0 ? 24 : 12">
<QuestionFormItem :key="item.Id" :question="item" :question-form="questionForm"
:trial-clinical-id="trialClinicalId" @formItemNumberChange="formItemNumberChange"
@setFormItemData="setFormItemData" @resetFormItemData="resetFormItemData" />
</el-col>
<el-dialog
v-if="addOrEdit.visible"
class="my_dialog"
:visible.sync="addOrEdit.visible"
:close-on-click-modal="false"
:title="addOrEdit.title"
width="400px"
append-to-body
>
<el-form
ref="tableQsForm"
v-loading="loading"
size="small"
:model="QuestionsForm"
>
<QuestionTableFormItem
v-for="(item) in QuestionsList"
:key="item.Id"
:question="item"
:question-form="QuestionsForm"
@setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData"
/>
<el-dialog v-if="addOrEdit.visible" class="my_dialog" :visible.sync="addOrEdit.visible"
:close-on-click-modal="false" :title="addOrEdit.title" width="400px" append-to-body>
<el-form ref="tableQsForm" v-loading="loading" size="small" :model="QuestionsForm">
<QuestionTableFormItem v-for="(item) in QuestionsList" :key="item.Id" :question="item"
:question-form="QuestionsForm" @setFormItemData="setFormItemData" @resetFormItemData="resetFormItemData" />
<div class="base-dialog-footer" style="text-align:right;margin-top:10px;">
<el-form-item>
<!-- 取消 -->
<el-button
size="small"
type="primary"
@click="addOrEdit.visible = false"
>
<el-button size="small" type="primary" @click="addOrEdit.visible = false">
{{ $t('common:button:cancel') }}
</el-button>
<!-- 保存 -->
@@ -282,7 +195,7 @@ export default {
},
data() {
return {
addOrEdit: { visible: false, title: '', id: null, index: 0},
addOrEdit: { visible: false, title: '', id: null, index: 0 },
fileList: [],
accept: '.png,.jpg,.jpeg',
imgVisible: false,
@@ -406,8 +319,6 @@ export default {
})
break
case 6:
console.log(this.questionForm[o.QuestionId])
console.log(this.questionForm)
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = parseFloat(q[o.TableQuestionId])
@@ -450,11 +361,16 @@ export default {
}
break
case 11:
if (parseFloat(this.getCurrentAgeByBirthDate2(this.questionForm[o.TableQuestionId], this.questionForm[o.QuestionId])) > 0) {
num = parseFloat(this.getCurrentAgeByBirthDate2(this.questionForm[o.TableQuestionId], this.questionForm[o.QuestionId]))
if (parseFloat(this.getCurrentAgeByBirthDate(this.questionForm[o.TableQuestionId])) > 0) {
num = parseFloat(this.getCurrentAgeByBirthDate(this.questionForm[o.TableQuestionId]))
} else {
num = 0
}
// if (parseFloat(this.getCurrentAgeByBirthDate2(this.questionForm[o.TableQuestionId], this.questionForm[o.QuestionId])) > 0) {
// num = parseFloat(this.getCurrentAgeByBirthDate2(this.questionForm[o.TableQuestionId], this.questionForm[o.QuestionId]))
// } else {
// num = 0
// }
break
}
} else {
@@ -494,19 +410,19 @@ export default {
} catch (e) {
console.log(e)
}
console.log(num)
if (rules.DigitPlaces) {
num = num.toFixed(rules.DigitPlaces)
}
return num
},
formItemNumberChange(questionId, isTable) {
try {
if (isTable) {
this.calculationList.forEach((v, i) => {
console.log(v, i)
var find = v.CalculateQuestionList.filter(o => {
return o.QuestionId === questionId
})
// find的自动计算值number
console.log('find', find)
if (find) {
var num = this.logic(v)
if (num !== false) {
@@ -520,7 +436,6 @@ export default {
return o.TableQuestionId === questionId
})
// find的自动计算值number
console.log('find', find)
// find的自动计算值number
if (find) {
var num = this.logic(v)
@@ -591,40 +506,47 @@ export default {
}
</script>
<style lang="scss" scoped>
.my_dialog{
.criterion-form-item{
::v-deep .el-form-item__content{
.my_dialog {
.criterion-form-item {
::v-deep .el-form-item__content {
width: auto;
}
}
}
.el-col-12 .el-col-12{
.el-col-12 .el-col-12 {
width: 100%;
}
.criterion-form-item{
.el-form-item{
.criterion-form-item {
.el-form-item {
display: flex;
flex-direction: row;
align-items: flex-start;
}
.el-input{
width:100%;
.el-input {
width: 100%;
}
.mb{
.mb {
margin-bottom: 0px;
}
.disabled{
.disabled {
::v-deep .el-upload--picture-card {
display: none;
}
}
.uploadWrapper{
.uploadWrapper {
display: flex;
flex-direction: column;
align-items: flex-start;
}
}
.clearfix:after{
.clearfix:after {
content: '';
display: table;
clear: both;
@@ -1,52 +1,30 @@
<template>
<div v-loading="loading" style="min-height: 500px;">
<el-form
v-if="isRender"
data-viewport-uid="lc"
ref="questions"
size="small"
:model="questionForm"
:disabled="openType === 'look'"
>
<el-form v-if="isRender" data-viewport-uid="lc" ref="questions" size="small" :model="questionForm"
:disabled="openType === 'look'">
<template>
<QuestionFormItem
class="father"
v-for="question of questions"
:key="question.Id"
:question="question"
:question-form="questionForm"
:trial-clinical-id="trialClinicalId"
@resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData"
/>
<QuestionFormItem class="father" v-for="question of questions" :key="question.Id" :question="question"
:question-form="questionForm" :trial-clinical-id="trialClinicalId" @resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData" />
</template>
</el-form>
<div class="base-dialog-footer" v-if="!isViewer && openType !== 'look' && [2, 3].includes(clinicalDataLevel)" style="text-align:right;margin-top:10px;">
<!-- 取消 -->
<el-button
size="small"
type="primary"
@click="close"
v-show="$route.path !== '/trials/trials-panel/visit/crc-upload'&&$route.path!=='/trials/trials-panel/visit/crc-question'"
>
{{ $t('common:button:cancel') }}
</el-button>
<!-- 保存 -->
<el-button size="small" type="primary" @click="submitClinicalForm">
{{ $t('common:button:save') }}
</el-button>
<div class="base-dialog-footer" v-if="!isViewer && openType !== 'look' && [2, 3].includes(clinicalDataLevel)"
style="text-align:right;margin-top:10px;">
<!-- 取消 -->
<el-button size="small" type="primary" @click="close"
v-show="$route.path !== '/trials/trials-panel/visit/crc-upload' && $route.path !== '/trials/trials-panel/visit/crc-question'">
{{ $t('common:button:cancel') }}
</el-button>
<!-- 保存 -->
<el-button size="small" type="primary" @click="submitClinicalForm">
{{ $t('common:button:save') }}
</el-button>
</div>
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
append-to-body
custom-class="base-dialog-wrapper"
>
<el-dialog v-if="signVisible" :visible.sync="signVisible" :close-on-click-modal="false" width="600px" append-to-body
custom-class="base-dialog-wrapper">
<div slot="title">
<span style="font-size:18px;">{{ $t('common:dialogTitle:sign') }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${ currentUser })` }}</span>
<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>
@@ -106,7 +84,7 @@ export default {
},
data: {
type: Object,
default: () => {}
default: () => { }
},
trialClinicalId: {
type: String,
@@ -166,7 +144,7 @@ export default {
let item = this.questionForm[v]
if (item instanceof Array) {
let TableQuestionAnswers = item.map(o => {
if (o instanceof Object) {
if (o instanceof Object) {
return Object.keys(o).map(x => {
return {
TableQuestionId: x,
@@ -251,7 +229,7 @@ export default {
if (item instanceof Array) {
let isCheckBox = false
let TableQuestionAnswers = item.map(o => {
if (o instanceof Object) {
if (o instanceof Object) {
return Object.keys(o).map(x => {
return {
TableQuestionId: x,
@@ -387,12 +365,12 @@ export default {
}
if (i.ClinicalQuestionType === 'table') {
this.$set(this.questionForm, i.Id, i.TableAnswer)
} else if (i.ClinicalQuestionType === 'checkbox') {
} else if (i.ClinicalQuestionType === 'checkbox') {
this.$set(this.questionForm, i.Id, i.Answer ? i.Answer.split(',') : [])
console.log(i.Answer ? i.Answer.split(',') : [])
console.log(this.questionForm)
} else if (i.ClinicalQuestionType === 'number') {
this.$set(this.questionForm, i.Id, i.Answer)
} else if (i.ClinicalQuestionType === 'number') {
this.$set(this.questionForm, i.Id, i.Answer || i.DefaultValue)
} else if (i.Childrens && i.Childrens.length > 0) {
this.setChild(i.Childrens)
}
@@ -405,7 +383,7 @@ export default {
this.questionForm[v] = 0
} else if (qs.ClinicalQuestionType === 'checkbox') {
this.questionForm[v] = []
} else{
} else {
this.questionForm[v] = ''
}
},
@@ -426,23 +404,26 @@ export default {
</script>
<style lang="scss" scoped>
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
.tabContent{
height:300px;
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
.tabContent {
height: 300px;
overflow-y: auto;
}
.father:after{
.father:after {
content: "";
display: block;
height: 0;
clear:both;
clear: both;
visibility: hidden;
}
</style>
+17 -33
View File
@@ -1,42 +1,28 @@
<template>
<div v-loading="loading">
<QuestionsForm
v-if="clinicalUploadType === 2"
:data="data"
:trial-clinical-id="trialClinicalId"
:is-viewer="isViewer"
:visit-id="visitId"
:subject-id="subjectId"
:open-type="openType"
:system-clinical-id="systemClinicalId"
:trial-id="trialId"
:reading-id="readingId"
:clinical-form-id="clinicalFormId"
:clinical-data-level="clinicalDataLevel"
@close="close"
></QuestionsForm>
<uploadClinicalData v-else :subject-visit-id="subjectVisitId" :data="data" :enum-type="0" :allow-add-or-edit="true" @getList="() => {}">
<QuestionsForm v-if="clinicalUploadType === 2" :data="data" :trial-clinical-id="trialClinicalId"
:is-viewer="isViewer" :visit-id="visitId" :subject-id="subjectId" :open-type="openType"
:system-clinical-id="systemClinicalId" :trial-id="trialId" :reading-id="readingId"
:clinical-form-id="clinicalFormId" :clinical-data-level="clinicalDataLevel" @close="close"></QuestionsForm>
<uploadClinicalData v-else :subject-visit-id="subjectVisitId" :data="data" :enum-type="0" :allow-add-or-edit="true"
@getList="() => { }">
</uploadClinicalData>
<div class="base-dialog-footer" v-if="!isViewer && openType !== 'look' && [0, 1].includes(clinicalDataLevel)" style="text-align:right;margin-top:10px;">
<div class="base-dialog-footer" v-if="!isViewer && openType !== 'look' && [0, 1].includes(clinicalDataLevel)"
style="text-align:right;margin-top:10px;">
<!-- 保存 -->
<el-button size="small" type="primary" @click="submitClinicalForm">
{{ $t('common:button:submit') }}
</el-button>
</div>
<!-- 临床数据签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
append-to-body
custom-class="base-dialog-wrapper"
>
<el-dialog v-if="signVisible" :visible.sync="signVisible" :close-on-click-modal="false" width="600px" append-to-body
custom-class="base-dialog-wrapper">
<div slot="title">
<span style="font-size:18px;">{{ $t('common:dialogTitle:sign') }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${ currentUser })` }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${currentUser})` }}</span>
</div>
<SignForm ref="signForm" :sign-code-enum="signCode" :subject-visit-id="subjectVisitId" @closeDialog="closeSignDialog" />
<SignForm ref="signForm" :sign-code-enum="signCode" :subject-visit-id="subjectVisitId"
@closeDialog="closeSignDialog" />
</el-dialog>
</div>
</template>
@@ -49,7 +35,7 @@ import uploadClinicalData from './components/uploadClinicalData'
import const_ from '@/const/sign-code'
export default {
name: "index",
name: "index",
components: { QuestionsForm, uploadClinicalData, SignForm },
methods: {
submitClinicalForm() {
@@ -83,7 +69,7 @@ name: "index",
this.close()
}).catch((res) => {
this.$refs['signForm'].btnLoading = false
})
})
},
},
data() {
@@ -148,7 +134,7 @@ name: "index",
},
data: {
type: Object,
default: () => {}
default: () => { }
},
trialClinicalId: {
type: String,
@@ -166,6 +152,4 @@ name: "index",
}
</script>
<style scoped>
</style>
<style scoped></style>
@@ -1,39 +1,19 @@
<template>
<el-dialog
:visible.sync="visible"
:fullscreen="true"
:close-on-click-modal="false"
:before-close="beforeClose"
:append-to-body="true"
v-loading="btnLoading"
class="downloadDicomAndNonedicom"
>
<el-dialog :visible.sync="visible" :fullscreen="true" :close-on-click-modal="false" :before-close="beforeClose"
:append-to-body="true" v-loading="btnLoading" class="downloadDicomAndNonedicom">
<span slot="title">{{ title }}</span>
<div class="top">
<span>{{ $t('download:top:title') }}</span>
<div class="btnBox">
<el-button
type="primary"
size="mini"
v-if="hasDicom"
@click.stop="getIRReadingDownloadStudyInfo('dicom')"
>
<el-button type="primary" size="mini" v-if="hasDicom" @click.stop="getIRReadingDownloadStudyInfo('dicom')">
{{ $t('download:button:downloadDicom') }}
</el-button>
<el-button
type="primary"
size="mini"
v-if="hasNonedicom"
@click.stop="getIRReadingDownloadStudyInfo('noneDicom')"
>
<el-button type="primary" size="mini" v-if="hasNonedicom"
@click.stop="getIRReadingDownloadStudyInfo('noneDicom')">
{{ $t('download:button:downloadNonedicom') }}
</el-button>
<el-button
type="primary"
size="mini"
v-if="hasDicom || hasNonedicom"
@click.stop="getIRReadingDownloadStudyInfo('all')"
>
<el-button type="primary" size="mini" v-if="hasDicom || hasNonedicom"
@click.stop="getIRReadingDownloadStudyInfo('all')">
{{ $t('download:button:downloadAll') }}
</el-button>
</div>
@@ -43,16 +23,9 @@
<div v-html="$t('download:tip:message')"></div>
</div>
<!--上传列表@selection-change="handleSelectionChange"-->
<el-table
ref="dicomFilesTable"
v-adaptive="{ bottomOffset: 85 }"
height="100"
:data="list"
:loading="loading"
class="dicomFiles-table"
@sort-change="handleSortByColumn"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }"
>
<el-table ref="dicomFilesTable" v-adaptive="{ bottomOffset: 85 }" height="100" :data="list" :loading="loading"
class="dicomFiles-table" @sort-change="handleSortByColumn"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
<!-- <el-table-column
type="selection"
width="55"
@@ -60,50 +33,28 @@
/> -->
<el-table-column type="index" width="40" />
<!--受试者-->
<el-table-column
:label="$t('download:table:subjectCode')"
min-width="130"
prop="SubjectCode"
show-overflow-tooltip
/>
<el-table-column :label="$t('download:table:subjectCode')" min-width="130" prop="SubjectCode"
show-overflow-tooltip />
<!--任务名称-->
<el-table-column
:label="$t('download:table:taskName')"
min-width="130"
show-overflow-tooltip
prop="TaskBlindName"
sortable="custom"
/>
<el-table-column :label="$t('download:table:taskName')" min-width="130" show-overflow-tooltip prop="TaskBlindName"
sortable="custom" />
<!--检查类型-->
<el-table-column
:label="$t('download:table:studyType')"
min-width="130"
show-overflow-tooltip
prop="IsDicom"
sortable="custom"
>
<el-table-column :label="$t('download:table:studyType')" min-width="130" show-overflow-tooltip prop="IsDicom"
sortable="custom">
<template slot-scope="scope">
<span>{{ $fd('IsDicom', scope.row.IsDicom) }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('download:table:orginalStudyListNum')"
min-width="150"
show-overflow-tooltip
>
<el-table-column :label="$t('download:table:orginalStudyListNum')" min-width="150" show-overflow-tooltip>
<template slot-scope="scope">
<el-button
v-if="
(scope.row.IsDicom &&
scope.row.DicomStudyList &&
scope.row.DicomStudyList.length >= 1) ||
(!scope.row.IsDicom &&
scope.row.NoneDicomStudyList &&
scope.row.NoneDicomStudyList.length >= 1)
"
type="text"
@click="handleOpenDialog(scope.row)"
>
<el-button v-if="
(scope.row.IsDicom &&
scope.row.DicomStudyList &&
scope.row.DicomStudyList.length >= 1) ||
(!scope.row.IsDicom &&
scope.row.NoneDicomStudyList &&
scope.row.NoneDicomStudyList.length >= 1)
" type="text" @click="handleOpenDialog(scope.row)">
<span>{{
scope.row.IsDicom
? scope.row.DicomStudyList.length
@@ -113,37 +64,19 @@
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="150"
>
<el-table-column :label="$t('common:action:action')" fixed="right" width="150">
<template slot-scope="scope">
<!--预览--->
<el-button
circle
icon="el-icon-view"
:title="$t('download:button:preview')"
@click.stop="preview(scope.row)"
/>
<el-button circle icon="el-icon-view" :title="$t('download:button:preview')"
@click.stop="preview(scope.row)" />
<!--下载--->
<el-button
circle
icon="el-icon-download"
:title="$t('download:button:download')"
@click.stop="getIRReadingDownloadStudyInfo('one', scope.row)"
/>
<el-button circle icon="el-icon-download" :title="$t('download:button:download')"
@click.stop="getIRReadingDownloadStudyInfo('one', scope.row)" />
</template>
</el-table-column>
</el-table>
<study-view
v-if="model_cfg.visible"
:model_cfg="model_cfg"
:modelList="modelList"
:bodyPart="bodyPart"
:IsDicom="IsDicom"
:visitTaskId="modelTaskId"
/>
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :modelList="modelList" :bodyPart="bodyPart"
:IsDicom="IsDicom" :visitTaskId="modelTaskId" />
</el-dialog>
</template>
<script>
@@ -358,7 +291,8 @@ export default {
name = `${list[0].SubjectCode}_${list[0].TaskBlindName}.zip`
}
if (this.IsReadingTaskViewInOrder === 0) {
name = `${list[0].TaskBlindName}.zip`
// name = `${list[0].TaskBlindName}.zip`
name = `${list[0].SubjectCode}_${list[0].TaskBlindName}.zip`
}
list.forEach((data) => {
if (data.StudyList && data.StudyList.length > 0) {
@@ -370,11 +304,9 @@ export default {
series.InstancePathList.forEach((instance) => {
let fileName = instance.Path.split('/').pop()
let obj = {
name: `${data.SubjectCode}/${
data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${
study.StudyCode
}/${fileName}`,
name: `${data.SubjectCode}/${data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${study.StudyCode
}/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
}
if (this.IsReadingTaskViewInOrder === 0) {
@@ -500,10 +432,12 @@ export default {
justify-content: space-between;
margin: 10px 0;
}
.tip {
display: flex;
align-items: flex-start;
margin-top: 5px;
i {
margin: 3px 5px 0 0;
}
@@ -4,123 +4,63 @@
<span>{{ $t('upload:dicom:title') }}</span>
<div class="tip">
<i class="el-icon-warning-outline"></i>
<div
v-html="$t(`upload:dicom:tip:message${isReadingTaskViewInOrder}`)"
></div>
<div v-html="$t(`upload:dicom:tip:message${isReadingTaskViewInOrder}`)"></div>
</div>
</div>
<!--检查列表-->
<el-table :data="list" style="width: 100%" height="300" :loading="loading">
<!--受试者-->
<el-table-column
prop="SubjectCode"
:label="$t('upload:dicom:table:subjectCode')"
/>
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" />
<!--任务名称-->
<el-table-column
prop="TaskBlindName"
:label="$t('upload:dicom:table:taskBlindName')"
/>
<el-table-column prop="TaskBlindName" :label="$t('upload:dicom:table:taskBlindName')" />
<!--原始检查数-->
<el-table-column
prop="OrginalStudyList"
:label="$t('upload:dicom:table:orginalStudyListNum')"
>
<el-table-column prop="OrginalStudyList" :label="$t('upload:dicom:table:orginalStudyListNum')">
<template slot-scope="scope">
<el-button
v-if="
scope.row.OrginalStudyList &&
scope.row.OrginalStudyList.length >= 1
"
type="text"
@click="handleOpenDialog(scope.row, 'OrginalStudyList')"
>
<el-button v-if="
scope.row.OrginalStudyList &&
scope.row.OrginalStudyList.length >= 1
" type="text" @click="handleOpenDialog(scope.row, 'OrginalStudyList')">
<span>{{ scope.row.OrginalStudyList.length }}</span>
</el-button>
<span v-else>0</span>
</template>
</el-table-column>
<!--后处理检查数-->
<el-table-column
prop="UploadStudyList"
:label="$t('upload:dicom:table:uploadStudyListNum')"
>
<el-table-column prop="UploadStudyList" :label="$t('upload:dicom:table:uploadStudyListNum')">
<template slot-scope="scope">
<el-button
v-if="
scope.row.UploadStudyList && scope.row.UploadStudyList.length >= 1
"
type="text"
@click="handleOpenDialog(scope.row, 'UploadStudyList', true)"
>
<el-button v-if="
scope.row.UploadStudyList && scope.row.UploadStudyList.length >= 1
" type="text" @click="handleOpenDialog(scope.row, 'UploadStudyList', true)">
<span>{{ scope.row.UploadStudyList.length }}</span>
</el-button>
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="180"
>
<el-table-column :label="$t('common:action:action')" fixed="right" width="180">
<template slot-scope="scope">
<div class="btnBox">
<!--上传--->
<form
id="inputForm"
:ref="`uploadForm_${scope.row.Id}`"
enctype="multipart/form-data"
>
<form id="inputForm" :ref="`uploadForm_${scope.row.Id}`" enctype="multipart/form-data">
<div class="form-group" style="margin-right: 10px">
<div
:id="`directoryInputWrapper_${scope.row.Id}`"
class="btn btn-link file-input"
>
<el-button
circle
icon="el-icon-upload2"
:disabled="btnLoading"
:loading="btnLoading"
:title="$t('upload:dicom:button:upload')"
/>
<input
:title="$t('upload:dicom:button:upload')"
type="file"
:name="`file_${scope.row.VisitTaskId}`"
:ref="`pathClear_${scope.row.VisitTaskId}`"
:disabled="btnLoading"
webkitdirectory
multiple
@change="
<div :id="`directoryInputWrapper_${scope.row.Id}`" class="btn btn-link file-input">
<el-button circle icon="el-icon-upload2" :disabled="btnLoading" :loading="btnLoading"
:title="$t('upload:dicom:button:upload')" />
<input :title="$t('upload:dicom:button:upload')" type="file" :name="`file_${scope.row.VisitTaskId}`"
:ref="`pathClear_${scope.row.VisitTaskId}`" :disabled="btnLoading" webkitdirectory multiple @change="
($event) => beginScanFiles($event, scope.row.VisitTaskId)
"
/>
" />
</div>
</div>
</form>
<!--预览--->
<el-button
circle
icon="el-icon-view"
:disabled="
!scope.row.UploadStudyList ||
scope.row.UploadStudyList.length <= 0
"
@click.stop="handleViewReadingImages(scope.row)"
:title="$t('upload:dicom:button:preview')"
/>
<el-button circle icon="el-icon-view" :disabled="!scope.row.UploadStudyList ||
scope.row.UploadStudyList.length <= 0
" @click.stop="handleViewReadingImages(scope.row)" :title="$t('upload:dicom:button:preview')" />
<!--删除--->
<el-button
circle
:disabled="
!scope.row.UploadStudyList ||
scope.row.UploadStudyList.length <= 0 ||
scope.row.ReadingTaskState === 2
"
icon="el-icon-delete"
:title="$t('upload:dicom:button:delete')"
@click.stop="remove(scope.row)"
/>
<el-button circle :disabled="!scope.row.UploadStudyList ||
scope.row.UploadStudyList.length <= 0 ||
scope.row.ReadingTaskState === 2
" icon="el-icon-delete" :title="$t('upload:dicom:button:delete')" @click.stop="remove(scope.row)" />
</div>
</template>
</el-table-column>
@@ -134,38 +74,19 @@
<form id="inputForm" ref="uploadForm" enctype="multipart/form-data">
<div class="form-group">
<div id="directoryInputWrapper" class="btn btn-link file-input">
<el-button
type="primary"
:disabled="btnLoading"
:loading="btnLoading"
size="mini"
>
<el-button type="primary" :disabled="btnLoading" :loading="btnLoading" size="mini">
{{ $t('upload:dicom:button:batchUpload') }}
</el-button>
<input
type="file"
name="file"
ref="pathClear"
:disabled="btnLoading"
webkitdirectory
multiple
title=""
@change="beginScanFiles($event)"
/>
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title=""
@change="beginScanFiles($event)" />
</div>
</div>
</form>
</div>
</div>
<!--上传列表-->
<el-table
ref="dicomFilesTable"
v-adaptive="{ bottomOffset: 80 }"
height="100"
:data="uploadQueues"
class="dicomFiles-table"
@selection-change="handleSelectionChange"
>
<el-table ref="dicomFilesTable" v-adaptive="{ bottomOffset: 80 }" height="100" :data="uploadQueues"
class="dicomFiles-table" @selection-change="handleSelectionChange">
<el-table-column type="index" width="40" />
<el-table-column min-width="200" show-overflow-tooltip>
<template slot="header">
@@ -182,28 +103,21 @@
<div style="line-height: 15px">
<div>
<div>
<span v-if="scope.row.dicomInfo.accNumber"
><span style="font-weight: 500">Acc:</span>
{{ scope.row.dicomInfo.accNumber }}</span
>
<span v-if="scope.row.dicomInfo.accNumber"><span style="font-weight: 500">Acc:</span>
{{ scope.row.dicomInfo.accNumber }}</span>
<span v-else style="color: #f44336">N/A</span>
</div>
<div style="display: inline-block; margin-right: 2px">
<span v-if="scope.row.dicomInfo.modality.length > 0">
{{ scope.row.dicomInfo.modality.join('、') }},</span
>
{{ scope.row.dicomInfo.modality.join('、') }},</span>
<span v-else style="color: #f44336">N/A,</span>
</div>
<div style="display: inline-block; margin-right: 2px">
<span v-if="scope.row.seriesList.length"
>{{ scope.row.seriesList.length }} Series,</span
>
<span v-if="scope.row.seriesList.length">{{ scope.row.seriesList.length }} Series,</span>
<span v-else style="color: #f44336">N/A,</span>
</div>
<div style="display: inline-block">
<span v-if="scope.row.fileList.length"
>{{ scope.row.fileList.length }} Instances</span
>
<span v-if="scope.row.fileList.length">{{ scope.row.fileList.length }} Instances</span>
<span v-else style="color: #f44336">N/A</span>
</div>
</div>
@@ -217,8 +131,7 @@
</div>
<div style="display: inline-block">
<span v-if="scope.row.dicomInfo.description">
{{ scope.row.dicomInfo.description }}</span
>
{{ scope.row.dicomInfo.description }}</span>
<span v-else style="color: #f44336">N/A</span>
</div>
</div>
@@ -242,16 +155,12 @@
<template slot-scope="scope">
<div style="line-height: 15px">
<div>
<span v-if="scope.row.dicomInfo.patientId"
><span style="font-weight: 500">PID: </span
>{{ scope.row.dicomInfo.patientId }}</span
>
<span v-if="scope.row.dicomInfo.patientId"><span style="font-weight: 500">PID: </span>{{
scope.row.dicomInfo.patientId }}</span>
<span v-else style="color: #f44336">N/A</span>
</div>
<div>
<span
:class="[scope.row.dicomInfo.patientName ? '' : 'colorOfRed']"
>
<span :class="[scope.row.dicomInfo.patientName ? '' : 'colorOfRed']">
{{
scope.row.dicomInfo.patientName
? scope.row.dicomInfo.patientName
@@ -260,9 +169,7 @@
</span>
</div>
<div>
<span
:class="[scope.row.dicomInfo.patientSex ? '' : 'colorOfRed']"
>
<span :class="[scope.row.dicomInfo.patientSex ? '' : 'colorOfRed']">
{{
scope.row.dicomInfo.patientSex
? scope.row.dicomInfo.patientSex
@@ -270,9 +177,7 @@
}},
</span>
<span
:class="[scope.row.dicomInfo.patientAge ? '' : 'colorOfRed']"
>
<span :class="[scope.row.dicomInfo.patientAge ? '' : 'colorOfRed']">
{{
scope.row.dicomInfo.patientAge
? scope.row.dicomInfo.patientAge
@@ -280,11 +185,9 @@
}},
</span>
<span
:class="[
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
]"
>
<span :class="[
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
]">
{{
scope.row.dicomInfo.patientBirthDate
? scope.row.dicomInfo.patientBirthDate
@@ -295,21 +198,14 @@
</div>
</template>
</el-table-column>
<el-table-column
:label="$t('trials:uploadDicomList:table:failedFileCount')"
min-width="150"
show-overflow-tooltip
>
<el-table-column :label="$t('trials:uploadDicomList:table:failedFileCount')" min-width="150"
show-overflow-tooltip>
<template slot-scope="scope">
<el-progress
color="#409eff"
:percentage="
(
(scope.row.dicomInfo.uploadFileSize * 100) /
scope.row.dicomInfo.fileSize
).toFixed(2) * 1
"
/>
<el-progress color="#409eff" :percentage="(
(scope.row.dicomInfo.uploadFileSize * 100) /
(scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1)
).toFixed(2) * 1
" />
<span>
{{ $t('trials:uploadDicomList:table:uploadNow')
}}{{ scope.row.dicomInfo.failedFileCount }}/{{
@@ -324,85 +220,52 @@
</template>
</el-table-column>
<el-table-column
:label="$t('trials:uploadDicomList:table:status')"
min-width="140"
show-overflow-tooltip
>
<el-table-column :label="$t('trials:uploadDicomList:table:status')" min-width="140" show-overflow-tooltip>
<template slot-scope="scope">
<span
v-if="
!scope.row.dicomInfo.failedFileCount &&
!scope.row.dicomInfo.isInit
"
>
{{ $t('trials:uploadDicomList:table:status1') }}</span
>
<span
style="color: #409eff"
v-else-if="
!scope.row.dicomInfo.failedFileCount &&
scope.row.dicomInfo.isInit &&
btnLoading
"
>{{ $t('trials:uploadDicomList:table:status2') }}</span
>
<span
style="color: #409eff"
v-else-if="
scope.row.dicomInfo.failedFileCount <
scope.row.dicomInfo.fileCount && !scope.row.uploadState.record
"
>{{ $t('trials:uploadDicomList:table:status2') }}</span
>
<span
style="color: #2cc368"
v-else-if="
scope.row.dicomInfo.failedFileCount ===
scope.row.dicomInfo.fileCount
"
>{{ $t('trials:uploadDicomList:table:status3') }}</span
>
<span
style="color: #f66"
v-else-if="
scope.row.uploadState.record &&
scope.row.uploadState.record.fileCount === 0
"
>{{ $t('trials:uploadDicomList:table:status5') }}</span
>
<span v-if="
!scope.row.dicomInfo.failedFileCount &&
!scope.row.dicomInfo.isInit
">
{{ $t('trials:uploadDicomList:table:status1') }}</span>
<span style="color: #409eff" v-else-if="
!scope.row.dicomInfo.failedFileCount &&
scope.row.dicomInfo.isInit &&
btnLoading
">{{ $t('trials:uploadDicomList:table:status2') }}</span>
<span style="color: #409eff" v-else-if="
scope.row.dicomInfo.failedFileCount <
scope.row.dicomInfo.fileCount && !scope.row.uploadState.record
">{{ $t('trials:uploadDicomList:table:status2') }}</span>
<span style="color: #2cc368" v-else-if="
scope.row.dicomInfo.failedFileCount ===
scope.row.dicomInfo.fileCount
">{{ $t('trials:uploadDicomList:table:status3') }}</span>
<span style="color: #f66" v-else-if="
scope.row.uploadState.record &&
scope.row.uploadState.record.fileCount === 0
">{{ $t('trials:uploadDicomList:table:status5') }}</span>
<span style="color: #f66" v-else>{{
$t('trials:uploadDicomList:table:Failed')
}}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('trials:uploadDicomList:table:record')"
min-width="140"
show-overflow-tooltip
>
<el-table-column :label="$t('trials:uploadDicomList:table:record')" min-width="140" show-overflow-tooltip>
<template slot-scope="scope">
<el-tooltip placement="top" v-if="scope.row.uploadState.record">
<div slot="content">
<div style="max-height: 500px; overflow-y: auto">
{{ $t('trials:uploadDicomList:table:Existed') }}:
<div v-if="scope.row.uploadState.record.Existed.length">
<div
v-for="item of scope.row.uploadState.record.Existed"
:key="item"
style="font-size: 12px; color: #baa72a"
>
<div v-for="item of scope.row.uploadState.record.Existed" :key="item"
style="font-size: 12px; color: #baa72a">
{{ item }}
</div>
</div>
<div v-else>&nbsp;</div>
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
<div v-if="scope.row.uploadState.record.Uploaded.length">
<div
v-for="item of scope.row.uploadState.record.Uploaded"
:key="item"
style="font-size: 12px; color: #24b837"
>
<div v-for="item of scope.row.uploadState.record.Uploaded" :key="item"
style="font-size: 12px; color: #24b837">
{{ item }}
</div>
</div>
@@ -410,11 +273,8 @@
<br />
{{ $t('trials:uploadDicomList:table:Failed') }}:
<div v-if="scope.row.uploadState.record.Failed.length">
<div
v-for="item of scope.row.uploadState.record.Failed"
:key="item"
style="font-size: 12px; color: #f66"
>
<div v-for="item of scope.row.uploadState.record.Failed" :key="item"
style="font-size: 12px; color: #f66">
{{ item }}
</div>
</div>
@@ -438,16 +298,8 @@
</template>
</el-table-column>
</el-table>
<study-view
v-if="model_cfg.visible"
:model_cfg="model_cfg"
:IsDicom="true"
:bodyPart="bodyPart"
:modelList="modelList"
:isUpload="openIsUpload"
:TrialModality="TrialModality"
@getList="getList"
/>
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :IsDicom="true" :bodyPart="bodyPart"
:modelList="modelList" :isUpload="openIsUpload" :TrialModality="TrialModality" @getList="getList" />
</div>
</template>
<script>
@@ -795,7 +647,7 @@ export default {
})
var validFilesCount = 0
for (var i = 0; i < checkFiles.length; ++i) {
;(function (index) {
; (function (index) {
p = p.then(function () {
if (
checkFiles[index].name.toUpperCase().indexOf('DICOMDIR') === -1
@@ -834,6 +686,7 @@ export default {
var studyUid = data.string('x0020000d')
if (!studyUid) return resolve()
var pixelDataElement = data.elements.x7fe00010
if (!pixelDataElement && modality !== 'SR') return resolve()
var studyIndex = 0
while (
studyIndex < scope.uploadQueues.length &&
@@ -936,19 +789,19 @@ export default {
) {
++instanceIndex
}
if (instanceIndex >= fileList.length) {
fileList.push({
instanceUid: instanceUid,
file: file,
})
}
scope.uploadQueues[studyIndex].dicomInfo.fileCount = fileList.length
scope.uploadQueues[studyIndex].dicomInfo.fileSize = fileList.reduce(
(prev, next) => {
return prev + next.file.size
},
0
)
// if (instanceIndex >= fileList.length) {
// fileList.push({
// instanceUid: instanceUid,
// file: file,
// })
// }
// scope.uploadQueues[studyIndex].dicomInfo.fileCount = fileList.length
// scope.uploadQueues[studyIndex].dicomInfo.fileSize = fileList.reduce(
// (prev, next) => {
// return prev + next.file.size
// },
// 0
// )
var seriesUid = data.string('x0020000e')
var seriesList = scope.uploadQueues[studyIndex].seriesList
@@ -1046,6 +899,19 @@ export default {
}
instanceList.push(instanceItem)
}
if (instanceIndex >= fileList.length) {
fileList.push({
instanceUid: instanceUid,
file: file,
})
}
scope.uploadQueues[studyIndex].dicomInfo.fileCount = fileList.length
scope.uploadQueues[studyIndex].dicomInfo.fileSize = fileList.reduce(
(prev, next) => {
return prev + next.file.size
},
0
)
resolve()
} catch (error) {
console.log(error)
@@ -1266,16 +1132,14 @@ export default {
dicomInfo.failedFileCount++
Record.FileCount++
} else {
let path = `/${params.trialId}/Image/${
params.subjectId
}/${params.subjectVisitId}/${
dicomInfo.visitTaskId
}/${scope.getGuid(
dicomInfo.studyUid +
let path = `/${params.trialId}/Image/${params.subjectId
}/${params.subjectVisitId}/${dicomInfo.visitTaskId
}/${scope.getGuid(
dicomInfo.studyUid +
v.seriesUid +
o.instanceUid +
params.trialId
)}`
)}`
if (scope.isClose) return
let res = await dcmUpload(
{
@@ -1546,16 +1410,19 @@ export default {
align-items: center;
justify-content: space-between;
}
.btnBox,
.form-group {
display: flex;
align-items: center;
}
#inputForm .file-input {
position: relative;
overflow: hidden;
display: inline-block;
}
#inputForm .file-input input[type='file'] {
position: absolute;
top: 0;
@@ -1565,10 +1432,12 @@ export default {
opacity: 0;
cursor: pointer;
}
.tip {
display: flex;
align-items: flex-start;
margin-top: 5px;
i {
margin: 3px 5px 0 0;
}
@@ -8,61 +8,25 @@
</div>
</div>
<!--检查列表-->
<el-table
:data="list"
style="width: 100%"
v-adaptive="{ bottomOffset: 60 }"
:loading="loading"
@sort-change="handleSortByColumn"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }"
>
<el-table :data="list" style="width: 100%" v-adaptive="{ bottomOffset: 60 }" :loading="loading"
@sort-change="handleSortByColumn" :default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
<!--受试者-->
<el-table-column
prop="SubjectCode"
:label="$t('upload:nonedicom:table:subject')"
/>
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')" />
<!--任务名称-->
<el-table-column
prop="TaskBlindName"
:label="$t('upload:nonedicom:table:taskName')"
sortable="custom"
/>
<el-table-column prop="TaskBlindName" :label="$t('upload:nonedicom:table:taskName')" sortable="custom" />
<!--检查类型-->
<el-table-column
prop="Modality"
:label="$t('upload:nonedicom:table:molityType')"
sortable="custom"
>
<el-table-column prop="Modality" :label="$t('upload:nonedicom:table:molityType')" sortable="custom">
</el-table-column>
<!--检查部位-->
<el-table-column
prop="BodyPart"
:label="$t('upload:nonedicom:table:bodyPart')"
sortable="custom"
/>
<el-table-column prop="BodyPart" :label="$t('upload:nonedicom:table:bodyPart')" sortable="custom" />
<!--原文件数-->
<el-table-column
prop="FileCount"
:label="$t('upload:nonedicom:table:fileCount')"
>
<el-table-column prop="FileCount" :label="$t('upload:nonedicom:table:fileCount')">
<template slot-scope="scope">
<el-popover
v-if="scope.row.FileCount"
trigger="click"
placement="bottom"
>
<el-popover v-if="scope.row.FileCount" trigger="click" placement="bottom">
<el-table :data="scope.row.FileList" height="300" size="small">
<!-- 文件名称 -->
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column
prop="FileSize"
:label="$t('trials:audit:table:nonDicomsFileSize')"
width="100"
>
<el-table-column prop="FileName" :label="$t('trials:audit:table:nonDicomsFileName')" width="200" />
<el-table-column prop="FileSize" :label="$t('trials:audit:table:nonDicomsFileSize')" width="100">
<template slot-scope="scope">
<span>{{
scope.row.FileSize && scope.row.FileSize > 0
@@ -74,27 +38,13 @@
<el-table-column :label="$t('common:action:action')" width="120">
<template slot-scope="files">
<!-- 预览 -->
<viewer
:ref="files.row.Path"
style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]"
>
<el-button
circle
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
:disabled="
files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
"
@click.native.prevent="previewFile(files.row)"
/>
<img
v-show="false"
crossorigin="anonymous"
:src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image"
/>
<viewer :ref="files.row.Path" style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]">
<el-button circle icon="el-icon-view" :title="$t('upload:nonedicom:button:preview')" :disabled="files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
" @click.native.prevent="previewFile(files.row)" />
<img v-show="false" crossorigin="anonymous" :src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image" />
</viewer>
</template>
</el-table-column>
@@ -109,32 +59,13 @@
</template>
</el-table-column>
<!--后处理文件数-->
<el-table-column
prop="UploadedFileCount"
:label="$t('upload:nonedicom:table:uploadFileCount')"
>
<el-table-column prop="UploadedFileCount" :label="$t('upload:nonedicom:table:uploadFileCount')">
<template slot-scope="scope">
<el-popover
v-if="scope.row.UploadedFileCount"
trigger="click"
placement="bottom"
>
<el-table
:data="scope.row.UploadedFileList"
height="300"
size="small"
>
<el-popover v-if="scope.row.UploadedFileCount" trigger="click" placement="bottom">
<el-table :data="scope.row.UploadedFileList" height="300" size="small">
<!-- 文件名称 -->
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column
prop="FileSize"
:label="$t('trials:audit:table:nonDicomsFileSize')"
width="100"
>
<el-table-column prop="FileName" :label="$t('trials:audit:table:nonDicomsFileName')" width="200" />
<el-table-column prop="FileSize" :label="$t('trials:audit:table:nonDicomsFileSize')" width="100">
<template slot-scope="scope">
<span>{{
scope.row.FileSize && scope.row.FileSize > 0
@@ -146,27 +77,13 @@
<el-table-column :label="$t('common:action:action')" width="120">
<template slot-scope="files">
<!-- 预览 -->
<viewer
:ref="files.row.Path"
style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]"
>
<el-button
circle
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
:disabled="
files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
"
@click.native.prevent="previewFile(files.row)"
/>
<img
v-show="false"
crossorigin="anonymous"
:src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image"
/>
<viewer :ref="files.row.Path" style="margin: 0 10px"
:images="[`${OSSclientConfig.basePath}${files.row.Path}`]">
<el-button circle icon="el-icon-view" :title="$t('upload:nonedicom:button:preview')" :disabled="files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
" @click.native.prevent="previewFile(files.row)" />
<img v-show="false" crossorigin="anonymous" :src="`${OSSclientConfig.basePath}${files.row.Path}`"
alt="Image" />
</viewer>
</template>
</el-table-column>
@@ -180,75 +97,34 @@
<span v-else>{{ scope.row.UploadedFileCount }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="180"
>
<el-table-column :label="$t('common:action:action')" fixed="right" width="180">
<template slot-scope="scope">
<!--预览--->
<el-button
circle
:disabled="scope.row.UploadedFileCount <= 0"
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
@click.stop="handlePreviewNoneDicomFiles(scope.row)"
/>
<el-button circle :disabled="scope.row.UploadedFileCount <= 0" icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')" @click.stop="handlePreviewNoneDicomFiles(scope.row)" />
<!--上传--->
<el-button
circle
icon="el-icon-upload2"
:title="$t('upload:nonedicom:button:upload')"
@click.native.prevent="handleUpload(scope.row)"
/>
<el-button circle icon="el-icon-upload2" :title="$t('upload:nonedicom:button:upload')"
@click.native.prevent="handleUpload(scope.row)" />
<!--删除--->
<el-button
:disabled="
scope.row.UploadedFileCount <= 0 ||
scope.row.ReadingTaskState === 2
"
circle
icon="el-icon-delete"
:title="$t('upload:nonedicom:button:delete')"
@click.stop="remove(scope.row)"
/>
<el-button :disabled="scope.row.UploadedFileCount <= 0 ||
scope.row.ReadingTaskState === 2
" circle icon="el-icon-delete" :title="$t('upload:nonedicom:button:delete')"
@click.stop="remove(scope.row)" />
</template>
</el-table-column>
</el-table>
<!-- 预览单个图像 -->
<el-dialog
v-if="imgObj.visible"
:visible.sync="imgObj.visible"
:title="$t('upload:nonedicom:dialogTitle:preview')"
append-to-body
width="565px"
>
<div
v-loading="imgObj.loading"
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<el-image
:src="`${OSSclientConfig.basePath}${imgObj.url}`"
crossorigin="anonymous"
fit="fit"
style="height: 500px; width: 500px"
@error="imgObj.loading = false"
@load="imgObj.loading = false"
/>
<el-dialog v-if="imgObj.visible" :visible.sync="imgObj.visible" :title="$t('upload:nonedicom:dialogTitle:preview')"
append-to-body width="565px">
<div v-loading="imgObj.loading" class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<el-image :src="`${OSSclientConfig.basePath}${imgObj.url}`" crossorigin="anonymous" fit="fit"
style="height: 500px; width: 500px" @error="imgObj.loading = false" @load="imgObj.loading = false" />
</div>
</el-dialog>
<!-- 上传非dicom文件 -->
<el-dialog
v-if="uploadVisible"
:visible.sync="uploadVisible"
:close-on-click-modal="false"
:title="$t('trials:uploadNonDicoms:dialogTitle:upload')"
width="800px"
append-to-body
custom-class="base-dialog-wrapper"
@close="resetFileDiaolg"
>
<el-dialog v-if="uploadVisible" :visible.sync="uploadVisible" :close-on-click-modal="false"
:title="$t('trials:uploadNonDicoms:dialogTitle:upload')" width="800px" append-to-body
custom-class="base-dialog-wrapper" @close="resetFileDiaolg">
<!-- 多文件上传 -->
<form id="inputForm" ref="uploadForm">
<el-divider content-position="left">{{
@@ -256,33 +132,15 @@
}}</el-divider>
<div class="form-group">
<div class="upload" style="margin-right: 10px">
<input
multiple="multiple"
webkitdirectory=""
directory
accept="*/*"
type="file"
name="uploadFolder"
class="select-file"
title=""
@change="beginScanFiles($event)"
v-if="!btnLoading"
/>
<input multiple="multiple" webkitdirectory="" directory accept="*/*" type="file" name="uploadFolder"
class="select-file" title="" @change="beginScanFiles($event)" v-if="!btnLoading" />
<div class="btn-select">
{{ $t('trials:uploadNonDicoms:button:selectFolder') }}
</div>
</div>
<div class="upload">
<input
class="select-file"
multiple=""
:accept="faccept.join(',')"
type="file"
name="uploadFile"
title=""
@change="beginScanFiles($event)"
v-if="!btnLoading"
/>
<input class="select-file" multiple="" :accept="faccept.join(',')" type="file" name="uploadFile" title=""
@change="beginScanFiles($event)" v-if="!btnLoading" />
<div class="btn-select">
{{ $t('trials:uploadNonDicoms:button:select') }}
</div>
@@ -293,82 +151,46 @@
</div>
</form>
<!-- 文件列表 -->
<el-table
ref="filesTable"
:data="fileList"
class="dicomFiles-table"
height="300"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
:selectable="(row, index) => row.status !== 2 && !btnLoading"
/>
<el-table ref="filesTable" :data="fileList" class="dicomFiles-table" height="300"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="(row, index) => row.status !== 2 && !btnLoading" />
<el-table-column type="index" width="50" />
<!-- 文件名称 -->
<el-table-column
prop="name"
:label="$t('trials:uploadNonDicoms:table:fileName')"
min-width="100"
/>
<el-table-column prop="name" :label="$t('trials:uploadNonDicoms:table:fileName')" min-width="100" />
<!-- 文件大小 -->
<el-table-column
prop="size"
:label="$t('trials:uploadNonDicoms:table:fileSize')"
>
<el-table-column prop="size" :label="$t('trials:uploadNonDicoms:table:fileSize')">
<template slot-scope="scope">
<span>{{
scope.row.size && scope.row.size > 0
? `${(scope.row.size / 1024 / 1024).toFixed(3)}MB`
: ''
: '0MB'
}}</span>
</template>
</el-table-column>
<!-- 文件类型 -->
<el-table-column
prop="type"
:label="$t('trials:uploadNonDicoms:table:fileType')"
/>
<el-table-column prop="type" :label="$t('trials:uploadNonDicoms:table:fileType')" />
<!-- 上传状态 -->
<el-table-column
prop="status"
:label="$t('trials:uploadNonDicoms:table:uploadStatus')"
min-width="100"
>
<el-table-column prop="status" :label="$t('trials:uploadNonDicoms:table:uploadStatus')" min-width="100">
<template slot-scope="scope">
<el-tag
:type="['warning', 'info', 'success', 'danger'][scope.row.status]"
v-if="scope.row.status || scope.row.status === 0"
>{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
<el-tag :type="['warning', 'info', 'success', 'danger'][scope.row.status]"
v-if="scope.row.status || scope.row.status === 0">{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
:label="$t('trials:uploadNonDicoms:table:failedFileCount')"
min-width="150"
show-overflow-tooltip
>
<el-table-column :label="$t('trials:uploadNonDicoms:table:failedFileCount')" min-width="150"
show-overflow-tooltip>
<template slot-scope="scope">
<el-progress
color="#409eff"
:percentage="
((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
1
"
/>
<el-progress color="#409eff" :percentage="scope.row.size && scope.row.size > 0 ? ((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
1
: ((scope.row.uploadFileSize * 100) / 1).toFixed(2) *
1
" />
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<el-button
size="mini"
icon="el-icon-delete"
circle
:disabled="btnLoading"
:title="$t('trials:crcUpload:action:delete')"
@click="handleRemoveFile(scope.row)"
/>
<el-button size="mini" icon="el-icon-delete" circle :disabled="btnLoading"
:title="$t('trials:crcUpload:action:delete')" @click="handleRemoveFile(scope.row)" />
</template>
</el-table-column>
</el-table>
@@ -376,13 +198,8 @@
<span style="margin-right: 10px">{{
$store.state.trials.uploadTip
}}</span>
<el-button
size="small"
type="primary"
:disabled="selectArr.length == 0"
:loading="btnLoading"
@click="beginUpload"
>
<el-button size="small" type="primary" :disabled="selectArr.length == 0" :loading="btnLoading"
@click="beginUpload">
{{ $t('trials:uploadNonDicoms:action:upload') }}
</el-button>
</div>
@@ -588,7 +405,7 @@ export default {
)
}
})
.catch(() => {})
.catch(() => { })
},
resetUploadForm() {
this.$nextTick(() => {
@@ -714,11 +531,10 @@ export default {
if (!this.uploadVisible) return
let file = this.fileList.filter((item) => item.id === arr[index].id)[0]
file.status = 1
let path = `/${this.$route.query.trialId}/TaskImage/${
this.currentRow.SubjectId
}/${this.currentRow.VisitTaskId}/${this.$guid()}${file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
let path = `/${this.$route.query.trialId}/TaskImage/${this.currentRow.SubjectId
}/${this.currentRow.VisitTaskId}/${this.$guid()}${file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
file.curPath = path
const fileData = await this.fileToBlob(file.file)
let res = await this.fileToOss(path, fileData, file)
@@ -772,7 +588,7 @@ export default {
(percentage, checkpoint, lastPer) => {
item.uploadFileSize += checkpoint.size * (percentage - lastPer)
if (item.uploadFileSize > file.fileSize) {
item.uploadFileSize = file.fileSize
item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1
}
}
)
@@ -869,6 +685,7 @@ export default {
.top {
margin: 10px 0;
}
.upload {
display: inline-block;
height: 30px;
@@ -883,6 +700,7 @@ export default {
background: #428bca;
border-color: #428bca;
color: #fff;
.select-file {
height: 30px;
width: 90px;
@@ -893,6 +711,7 @@ export default {
opacity: 0;
font-size: 0;
}
.btn-select {
//给显示在页面上的按钮写样式
width: 90px;
@@ -908,10 +727,12 @@ export default {
pointer-events: none; //pointer-events:none用来控制该标签的点击穿透事件
}
}
.tip {
display: flex;
align-items: flex-start;
margin-top: 5px;
i {
margin: 3px 5px 0 0;
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

+9
View File
@@ -54,6 +54,10 @@ import upload from '@/components/element-ui/upload'
Vue.use(upload)
import Preview from '@/components/Preview/index'
Vue.use(Preview)
import Onlyoffice from '@/components/Preview_onlyoffice/index'
Vue.use(Onlyoffice)
import Video from '@/components/Preview_video/index'
Vue.use(Video)
import MFA from '@/components/MFA/index'
Vue.use(MFA)
import FB from '@/components/feedBack/index'
@@ -308,6 +312,11 @@ async function VueInit() {
text = text.replace(test, item.TrialName)
})
}
let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo'))
if (CompanyInfo && CompanyInfo.SystemShortName) {
let test = new RegExp('IRC', 'ig')
text = text.replace(test, CompanyInfo.SystemShortName)
}
// return i18n.t(key)
return text;
}
+6
View File
@@ -61,6 +61,12 @@ export const constantRoutes = [
name: 'Resetpassword',
hidden: true
},
{
path: '/trials/trials-panel/reading/readingTracking/ReadOrder',
component: () => import('@/views/trials/trials-panel/reading/read-order/index'),
name: 'ReadOrder',
hidden: true
},
{
path: '/recompose',
component: () => import('@/views/recompose/index'),
+3 -1
View File
@@ -50,6 +50,8 @@ const getters = {
IsFirstSysDocNeedSign: state => state.user.IsFirstSysDocNeedSign,
TrialStatusStr: state => state.user.TrialStatusStr,
lastViewportTaskId: state => state.noneDicomReview.lastViewportTaskId,
currentTaskState: state => state.noneDicomReview.currentTaskState
currentTaskState: state => state.noneDicomReview.currentTaskState,
operateInfo: state => state.dicom3d.operateInfo,
deleteAnnotationIds: state => state.dicom3d.deleteAnnotationIds
}
export default getters
+3 -1
View File
@@ -13,6 +13,7 @@ import financials from './modules/financials'
import reading from './modules/reading'
import lang from './modules/lang'
import noneDicomReview from './modules/noneDicomReview'
import dicom3d from './modules/dicom3d'
Vue.use(Vuex)
const store = new Vuex.Store({
@@ -28,7 +29,8 @@ const store = new Vuex.Store({
financials,
reading,
lang,
noneDicomReview
noneDicomReview,
dicom3d
},
getters
})
+28
View File
@@ -0,0 +1,28 @@
const getDefaultState = () => {
return {
operateInfo: [],
deleteAnnotationIds: []
}
}
const state = getDefaultState
const mutations = {
}
const actions = {
setOperateInfo({ state }, arr) {
state.operateInfo = arr
},
setDeleteAnnotationIds({ state }, arr) {
state.deleteAnnotationIds = arr
},
}
export default {
namespaced: true,
state,
mutations,
actions
}
+6
View File
@@ -68,6 +68,12 @@ body .el-table th.gutter {
}
}
.text-ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.el-loading-mask {
background-color: rgba(255, 255, 255, 0.5);
}
+149
View File
@@ -39,6 +39,108 @@ function getNumberValues(dataSet, tag, minimumLength) {
return values;
}
function getLutDescriptor(dataSet, tag) {
if (!dataSet.elements[tag] || dataSet.elements[tag].length !== 6) {
return;
}
return [
dataSet.uint16(tag, 0),
dataSet.uint16(tag, 1),
dataSet.uint16(tag, 2),
];
}
function getLutData(lutDataSet, tag, lutDescriptor) {
const lut = [];
const lutData = lutDataSet.elements[tag];
for (let i = 0; i < lutDescriptor[0]; i++) {
// Output range is always unsigned
if (lutDescriptor[2] === 16) {
lut[i] = lutDataSet.uint16(tag, i);
} else {
lut[i] = lutDataSet.byteArray[i + lutData.dataOffset];
}
}
return lut;
}
function populateSmallestLargestPixelValues(dataSet, imagePixelModule) {
const pixelRepresentation = dataSet.uint16('x00280103');
if (pixelRepresentation === 0) {
imagePixelModule.smallestPixelValue = dataSet.uint16('x00280106');
imagePixelModule.largestPixelValue = dataSet.uint16('x00280107');
} else {
imagePixelModule.smallestPixelValue = dataSet.int16('x00280106');
imagePixelModule.largestPixelValue = dataSet.int16('x00280107');
}
imagePixelModule.largestPixelValue = imagePixelModule.largestPixelValue === 0 ? undefined : imagePixelModule.largestPixelValue;
}
function populatePaletteColorLut(dataSet, imagePixelModule) {
imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281101'
);
imagePixelModule.greenPaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281102'
);
imagePixelModule.bluePaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281103'
);
// The first Palette Color Lookup Table Descriptor value is the number of entries in the lookup table.
// When the number of table entries is equal to 2ˆ16 then this value shall be 0.
// See http://dicom.nema.org/MEDICAL/DICOM/current/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.5
if (imagePixelModule.redPaletteColorLookupTableDescriptor[0] === 0) {
imagePixelModule.redPaletteColorLookupTableDescriptor[0] = 65536;
imagePixelModule.greenPaletteColorLookupTableDescriptor[0] = 65536;
imagePixelModule.bluePaletteColorLookupTableDescriptor[0] = 65536;
}
// The third Palette Color Lookup Table Descriptor value specifies the number of bits for each entry in the Lookup Table Data.
// It shall take the value of 8 or 16.
// The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1.
// The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors.
//
// Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits;
// this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry.
// The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16.
const numLutEntries =
imagePixelModule.redPaletteColorLookupTableDescriptor[0];
const lutData = dataSet.elements.x00281201;
const lutBitsAllocated = lutData.length === numLutEntries ? 8 : 16;
// If the descriptors do not appear to have the correct values, correct them
if (
imagePixelModule.redPaletteColorLookupTableDescriptor[2] !==
lutBitsAllocated
) {
imagePixelModule.redPaletteColorLookupTableDescriptor[2] = lutBitsAllocated;
imagePixelModule.greenPaletteColorLookupTableDescriptor[2] =
lutBitsAllocated;
imagePixelModule.bluePaletteColorLookupTableDescriptor[2] =
lutBitsAllocated;
}
imagePixelModule.redPaletteColorLookupTableData = getLutData(
dataSet,
'x00281201',
imagePixelModule.redPaletteColorLookupTableDescriptor
);
imagePixelModule.greenPaletteColorLookupTableData = getLutData(
dataSet,
'x00281202',
imagePixelModule.greenPaletteColorLookupTableDescriptor
);
imagePixelModule.bluePaletteColorLookupTableData = getLutData(
dataSet,
'x00281203',
imagePixelModule.bluePaletteColorLookupTableDescriptor
);
}
function metaDataProvider(type, imageId) {
const parsedImageId = parseImageId(imageId);
const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(parsedImageId.url);
@@ -99,5 +201,52 @@ function metaDataProvider(type, imageId) {
columnPixelSpacing,
};
}
if (type === 'imagePixelModule') {
const imagePixelModule = {
samplesPerPixel: dataSet.uint16('x00280002'),
photometricInterpretation: dataSet.string('x00280004'),
rows: dataSet.uint16('x00280010'),
columns: dataSet.uint16('x00280011'),
bitsAllocated: dataSet.uint16('x00280100'),
bitsStored: dataSet.uint16('x00280101'),
highBit: dataSet.uint16('x00280102'),
pixelRepresentation: dataSet.uint16('x00280103'),
planarConfiguration: dataSet.uint16('x00280006'),
pixelAspectRatio: dataSet.string('x00280034'),
};
populateSmallestLargestPixelValues(dataSet, imagePixelModule);
if (
imagePixelModule.photometricInterpretation === 'PALETTE COLOR' &&
dataSet.elements.x00281101
) {
populatePaletteColorLut(dataSet, imagePixelModule);
}
return imagePixelModule;
}
// if (type === 'imagePixelModule') {
// return {
// samplesPerPixel: dataSet.uint16('x00280002'),
// photometricInterpretation: dataSet.string('x00280004'),
// rows: dataSet.uint16('x00280010'),
// columns: dataSet.uint16('x00280011'),
// bitsAllocated: dataSet.uint16('x00280100'),
// bitsStored: dataSet.uint16('x00280101'),
// highBit: dataSet.uint16('x00280102'),
// pixelRepresentation: dataSet.uint16('x00280103'),
// planarConfiguration: dataSet.uint16('x00280006'),
// pixelAspectRatio: dataSet.uint16('x00280034'),
// smallestPixelValue: null,
// largestPixelValue: null,
// // smallestPixelValue: dataSet.uint16('x00280106'),
// // largestPixelValue: dataSet.uint16('x00280107'),
// redPaletteColorLookupTableDescriptor: dataSet.string('x00281101'),
// greenPaletteColorLookupTableDescriptor: dataSet.string('x00281102'),
// bluePaletteColorLookupTableDescriptor: dataSet.string('x00281103'),
// redPaletteColorLookupTableData: dataSet.string('x00281201'),
// greenPaletteColorLookupTableData: dataSet.string('x00281202'),
// bluePaletteColorLookupTableData: dataSet.string('x00281203')
// }
// }
}
export default metaDataProvider;
+66
View File
@@ -0,0 +1,66 @@
let TYPES = ['word', 'cell', 'slide', 'pdf']
let DOCUMENTTYPE = {
'.doc': TYPES[0],
'.docm': TYPES[0],
'.docx': TYPES[0],
'.dot': TYPES[0],
'.dotm': TYPES[0],
'.dotx': TYPES[0],
'.epub': TYPES[0],
'.fb2': TYPES[0],
'.fodt': TYPES[0],
'.htm': TYPES[0],
'.html': TYPES[0],
'.mht': TYPES[0],
'.mhtml': TYPES[0],
'.odt': TYPES[0],
'.ott': TYPES[0],
'.pages': TYPES[0],
'.rtf': TYPES[0],
'.stw': TYPES[0],
'.sxw': TYPES[0],
'.txt': TYPES[0],
'.wps': TYPES[0],
'.wpt': TYPES[0],
'.xml': TYPES[0],
'.csv': TYPES[1],
'.et': TYPES[1],
'.ett': TYPES[1],
'.fods': TYPES[1],
'.numbers': TYPES[1],
'.ods': TYPES[1],
'.ots': TYPES[1],
'.sxc': TYPES[1],
'.xls': TYPES[1],
'.xlsb': TYPES[1],
'.xlsm': TYPES[1],
'.xlsx': TYPES[1],
'.xlt': TYPES[1],
'.xltm': TYPES[1],
'.xltx': TYPES[1],
'.xml': TYPES[1],
'.dps': TYPES[2],
'.dpt': TYPES[2],
'.fodp': TYPES[2],
'.key': TYPES[2],
'.odp': TYPES[2],
'.otp': TYPES[2],
'.pot': TYPES[2],
'.potm': TYPES[2],
'.potx': TYPES[2],
'.pps': TYPES[2],
'.ppsm': TYPES[2],
'.ppsx': TYPES[2],
'.ppt': TYPES[2],
'.pptm': TYPES[2],
'.pptx': TYPES[2],
'.sxi': TYPES[2],
'.djvu': TYPES[3],
'.docxf': TYPES[3],
'.oform': TYPES[3],
'.oxps': TYPES[3],
'.pdf': TYPES[3],
'.xps': TYPES[3]
}
export default DOCUMENTTYPE
+2 -1
View File
@@ -50,7 +50,8 @@ service.interceptors.response.use(
const a = document.createElement('a')
// xls类型: application/vnd.ms-excel
// xlsx类型:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
const href = URL.createObjectURL(new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' }))
// const href = URL.createObjectURL(new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' }))
const href = URL.createObjectURL(new Blob([res], { type: response.headers['content-type'] }))
a.download = fileName
a.href = href
a.click()
+2
View File
@@ -21,6 +21,8 @@ service.interceptors.request.use(
async config => {
path = router && router.app && router.app._route && router.app._route.path
config.headers['Content-Type'] = 'application/json;charset=UTF-8'
// config.baseURL = process.env.NODE_ENV === 'prod' ? "https://api.irc.extimaging.com" : '/api'
config.headers['Self-Referer'] = window.location.href
var language = zzSessionStorage.getItem('lang')
config.headers['Accept-Language'] = language === 'en' ? 'en-US,en;q=0.5' : 'zh-CN,zh;q=0.9'
config.headers['TimeZoneId'] = moment.tz.guess()
@@ -1,100 +1,45 @@
<template>
<el-form
ref="sysAttachmentFrom"
v-loading="loading"
:model="form"
label-width="190px"
size="small"
:rules="rules"
class="upload-temporary-file"
>
<el-form ref="sysAttachmentFrom" v-loading="loading" :model="form" label-width="190px" size="small" :rules="rules"
class="upload-temporary-file">
<div class="base-dialog-body">
<el-form-item
:label="$t('dictionary:signature:form:FileTypeId')"
prop="FileTypeId"
>
<el-select
v-model="form.FileTypeId"
style="width: 100%"
size="small"
filterable
>
<el-option
v-for="item of dictionaryList.Sys_Document"
:key="item.Id"
:label="item.Value"
:value="item.Id"
/>
<el-form-item :label="$t('dictionary:signature:form:FileTypeId')" prop="FileTypeId">
<el-select v-model="form.FileTypeId" style="width: 100%" size="small" filterable>
<el-option v-for="item of dictionaryList.Sys_Document" :key="item.Id" :label="item.Value" :value="item.Id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:File')">
<div class="upload-container">
<el-upload
class="upload-demo"
action
accept=".pdf"
:before-upload="beforeUpload"
:http-request="handleUploadFile"
:on-preview="handlePreview"
:on-remove="handleRemoveFile"
:show-file-list="true"
:file-list="fileList"
:limit="1"
:on-exceed="handleExceed"
:disabled="form.Type === ''"
>
<el-button
size="small"
type="primary"
:disabled="form.FileTypeId === ''"
:loading="btnLoading"
>{{ $t('common:button:check') }}</el-button
>
<el-upload class="upload-demo" action accept=".pdf,.mp4" :before-upload="beforeUpload"
:http-request="handleUploadFile" :on-preview="handlePreview" :on-remove="handleRemoveFile"
:show-file-list="true" :file-list="fileList" :limit="1" :on-exceed="handleExceed"
:disabled="form.Type === ''">
<el-button size="small" type="primary" :disabled="form.FileTypeId === ''" :loading="btnLoading">{{
$t('common:button:check') }}</el-button>
<span slot="tip" style="margin-left: 10px" class="el-upload__tip">
({{ $t('trials:signature:label:mustBepdf') }})
</span>
</el-upload>
</div>
</el-form-item>
<el-form-item
:label="$t('dictionary:signature:form:NeedConfirmedUserTypeIdList')"
prop="NeedConfirmedUserTypeIdList"
>
<el-select
v-model="form.NeedConfirmedUserTypeIdList"
style="width: 100%"
multiple
>
<el-option
v-for="item of userTypeOptions"
:key="item.Id"
:label="item.UserTypeShortName"
:value="item.Id"
/>
<el-form-item :label="$t('dictionary:signature:form:NeedConfirmedUserTypeIdList')"
prop="NeedConfirmedUserTypeIdList">
<el-select v-model="form.NeedConfirmedUserTypeIdList" style="width: 100%" multiple>
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName" :value="item.Id" />
</el-select>
</el-form-item>
<el-form-item
:label="$t('dictionary:signature:form:DocUserSignType')"
prop="DocUserSignType"
>
<el-switch
v-model="form.DocUserSignType"
:active-value="1"
:inactive-value="0"
>
<el-form-item :label="$t('dictionary:signature:form:DocUserSignType')" prop="DocUserSignType">
<el-switch v-model="form.DocUserSignType" :active-value="1" :inactive-value="0">
</el-switch>
</el-form-item>
<el-form-item
:label="$t('dictionary:signature:form:SignViewMinimumMinutes')"
prop="SignViewMinimumMinutes"
>
<el-input-number
v-model="form.SignViewMinimumMinutes"
controls-position="right"
:min="1"
:max="50"
/>
<el-form-item :label="$t('dictionary:signature:form:SignViewMinimumMinutes')" prop="SignViewMinimumMinutes">
<el-input-number v-model="form.SignViewMinimumMinutes" controls-position="right" :min="1" :max="50" />
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:CurrentStaffTrainDays')" prop="CurrentStaffTrainDays">
<el-input-number v-model="form.CurrentStaffTrainDays" controls-position="right" :min="0" :max="1000" />
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:NewStaffTrainDays')" prop="NewStaffTrainDays">
<el-input-number v-model="form.NewStaffTrainDays" controls-position="right" :min="0" :max="1000" />
</el-form-item>
<!-- <el-form-item v-if="form.Id !== ''" label="是否废除: ">
<el-radio-group v-model="form.IsDeleted">
@@ -105,14 +50,8 @@
</div>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
<el-form-item style="text-align: right">
<el-button
size="small"
type="primary"
:disabled="form.FileTypeId === '' || form.Name === ''"
:loading="saveBtnLoading"
@click="handleSave"
>{{ $t('common:button:save') }}</el-button
>
<el-button size="small" type="primary" :disabled="form.FileTypeId === '' || form.Name === ''"
:loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save') }}</el-button>
</el-form-item>
</div>
</el-form>
@@ -138,9 +77,12 @@ export default {
FileTypeId: '',
Name: '',
Path: '',
IsDeleted: false,
IsPublish: false,
IsDeleted: true,
SignViewMinimumMinutes: null,
DocUserSignType: 0,
CurrentStaffTrainDays: 1,
NewStaffTrainDays: 14,
},
rules: {
FileTypeId: [
@@ -196,8 +138,11 @@ export default {
this.form.Name = this.data.Name
this.form.Path = this.data.Path
this.form.IsDeleted = this.data.IsDeleted
this.form.IsPublish = this.data.IsPublish
this.form.SignViewMinimumMinutes = this.data.SignViewMinimumMinutes
this.form.DocUserSignType = this.data.DocUserSignType
this.form.CurrentStaffTrainDays = this.data.CurrentStaffTrainDays
this.form.NewStaffTrainDays = this.data.NewStaffTrainDays
}
this.loading = false
},
@@ -207,7 +152,7 @@ export default {
.then((res) => {
this.dictionaryList = { ...res.Result }
})
.catch(() => {})
.catch(() => { })
},
// 获取用户类型下拉数据
getUserType() {
@@ -284,7 +229,7 @@ export default {
this.$message.warning(this.$t('upload:rule:maxFile1'))
},
checkFileSuffix(fileName) {
var typeArr = ['pdf']
var typeArr = ['pdf', 'mp4']
var extendName = fileName
.substring(fileName.lastIndexOf('.') + 1)
.toLocaleLowerCase()
@@ -305,13 +250,16 @@ export default {
width: 80px;
height: 40px;
}
.upload-container .el-input--small {
margin-bottom: 5px;
}
.upload-container .el-icon-circle-check {
color: #428bca;
font-size: 13px;
}
.account_item_clear {
.el-tag__close {
display: none !important;
@@ -0,0 +1,213 @@
<template>
<el-form ref="attachmentFrom" v-loading="loading" :model="form" label-width="190px" size="small" :rules="rules"
class="upload-temporary-file">
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:signature:form:FileName')" prop="Name">
<el-input v-model="form.Name" clearable></el-input>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:OffLine')" prop="OffLine">
<el-switch v-model="form.OffLine" :active-value="true" :inactive-value="false"
:active-text="$fd('YesOrNo', true)" :inactive-text="$fd('YesOrNo', false)">
</el-switch>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:form:File')">
<div class="upload-container">
<el-upload class="upload-demo" action :accept="this.accept.join(',')" :before-upload="beforeUpload"
:http-request="handleUploadFile" :on-preview="handlePreview" :on-remove="handleRemoveFile"
:show-file-list="true" :file-list="fileList" :limit="1" :on-exceed="handleExceed">
<el-button size="small" type="primary" :loading="btnLoading">{{ $t('common:button:check')
}}</el-button>
<span slot="tip" style="margin-left: 10px" class="el-upload__tip">
({{ $t('trials:signature:label:type').replace("xxx", this.accept.join(", ")) }})
</span>
</el-upload>
</div>
</el-form-item>
</div>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
<el-form-item style="text-align: right">
<el-button size="small" type="primary" :disabled="form.FileTypeId === '' || form.Name === ''"
:loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save') }}</el-button>
</el-form-item>
</div>
</el-form>
</template>
<script>
import { addOrUpdateSystemDocumentAttachment } from '@/api/dictionary'
export default {
props: {
data: {
type: Object,
default() {
return {}
},
},
SystemDocumentId: {
type: String,
default: ''
}
},
data() {
return {
form: {
Id: '',
Name: null,
FileFormat: null,
FileName: null,
FilePath: null,
FileSize: null,
OffLine: false,
SystemDocumentId: null,
},
rules: {
Name: [
{
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: ['change'],
},
],
},
fileList: [],
btnLoading: false,
saveBtnLoading: false,
loading: false,
accept: ['.jpg',
'.jpeg',
'.png',
'.pdf',
'.ppt',
'.pptx',
'.doc',
'.docx',
'.xls',
'.xlsx',
'.mp4']
}
},
mounted() {
this.initForm()
},
methods: {
async initForm() {
this.loading = true
if (this.data && this.data.Id) {
Object.keys(this.form).forEach(key => {
this.form[key] = this.data[key]
})
this.fileList = [
{
name: this.data.FileName,
url: this.data.FilePath,
path: this.data.FilePath,
},
]
}
this.loading = false
},
beforeUpload(file) {
// 检测文件类型是否符合要求
if (this.checkFileSuffix(file.name)) {
this.fileList = []
return true
} else {
this.$alert(this.$t('trials:signature:label:type').replace("xxx", this.accept.join(", ")))
return false
}
},
async handleUploadFile(param) {
this.loading = true
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(
`/System/DocumentToSign/${param.file.name}${new Date().getTime()}`,
file
)
this.fileList.push({
name: param.file.name,
path: this.$getObjectName(res.url),
url: this.$getObjectName(res.url),
})
this.form.Name = param.file.name
this.form.FileName = param.file.name
this.form.FilePath = this.$getObjectName(res.url)
this.form.FileSize = param.file.size
this.form.FileFormat = param.file.name
.substring(param.file.name.lastIndexOf('.'))
.toLocaleLowerCase().split('.')[1]
this.loading = false
},
handleSave() {
this.$refs.attachmentFrom.validate((valid) => {
if (!valid) return false
if (!this.form.FilePath)
return this.$alert(this.$t('trials:signature:message:selectFile'))
this.saveBtnLoading = true
if (this.SystemDocumentId) this.form.SystemDocumentId = this.SystemDocumentId
addOrUpdateSystemDocumentAttachment(this.form)
.then((res) => {
this.saveBtnLoading = false
this.$emit('closeDialog')
this.$emit('getList')
this.$message.success(this.$t('common:message:updatedSuccessfully'))
})
.catch(() => {
this.saveBtnLoading = false
})
})
},
handleRemoveFile() {
this.fileList = []
this.form.FilePath = ''
this.form.FileSize = ''
this.form.FileFormat = ''
this.form.FileName = ''
},
handlePreview(file) {
if (file.fullPath) {
window.open(file.fullPath, '_blank')
}
},
handleExceed(files, fileList) {
this.$message.warning(this.$t('upload:rule:maxFile1'))
},
checkFileSuffix(fileName) {
var typeArr = this.accept.map(item => item.split('.')[1])
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,265 @@
<template>
<div v-if="config.visible">
<base-model :config="config">
<template slot="dialog-body">
<el-form ref="form" :model="rowData" label-width="80px" style="width: 80%;display: inline-block;">
<el-form-item :label="`${$t('dictionary:signature:table:Name')}: `">
<span class="name text-ellipsis" :title="rowData.Name">{{ rowData.Name }}</span>
</el-form-item>
</el-form>
<el-button size="mini" type="primary" style="float:right" @click.stop="edit({})" v-if="!isView">
{{ $t('common:button:add') }}</el-button>
<el-table :data="list" style="width: 100%" max-height="300px" v-loading="loading"
@sort-change="handleSortByColumn">
<el-table-column type="index" width="60" />
<el-table-column prop="Name" :label="$t('dictionary:signature:attachmentList:FileName')"
sortable="custom" />
<el-table-column prop="OffLine" :label="$t('dictionary:signature:attachmentList:OffLine')"
sortable="custom" v-if="!isView">
<template slot-scope="scope">
<el-switch v-model="scope.row.OffLine" @change="(val) => OffLine(scope.row, val)"
:active-value="true" :inactive-value="false" :active-text="$fd('YesOrNo', true)"
:inactive-text="$fd('YesOrNo', false)">
</el-switch>
</template>
</el-table-column>
<el-table-column prop="CreateTime" :label="$t('dictionary:signature:attachmentList:CreateTime')"
sortable="custom" />
<el-table-column :label="$t('common:action:action')" min-width="120px">
<template slot-scope="scope">
<el-button size="mini" type="text" @click.stop="preview(scope.row)">
{{ $t('common:button:preview') }}
</el-button>
<el-button size="mini" type="text" @click.stop="edit(scope.row)" v-if="!isView">
{{ $t('common:button:edit') }}
</el-button>
<!-- <el-button size="mini" type="text" @click.stop="OffLine(scope.row, true)"
:disabled="scope.row.OffLine">
{{ $t('dictionary:signature:attachmentList:OffLine') }}
</el-button> -->
<el-button size="mini" type="text" @click.stop="del(scope.row)" v-if="!isView">
{{ $t('common:button:delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增/编辑附件 -->
<el-dialog :visible.sync="visible" :close-on-click-modal="false" :append-to-body="true" :title="title"
width="800px" custom-class="base-dialog-wrapper">
<attachmentForm v-if="visible" :data="rowDATA" :SystemDocumentId="SystemDocumentId"
@closeDialog="closeDialog" @getList="getAllList" />
</el-dialog>
</template>
</base-model>
<viewer ref="picture_perview2" style="margin: 0 10px"
v-if="rowDATA.FileFormat && ['png', 'jpg', 'jpeg'].includes(rowDATA.FileFormat.toLowerCase())"
:images="[`${OSSclientConfig.basePath}${rowDATA.FilePath}`]" :options="viewerOptions">
<img v-show="false" :src="`${OSSclientConfig.basePath}${rowDATA.FilePath}`" alt="Image" />
</viewer>
<!-- <attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible"
v-if="perview_visible" /> -->
</div>
</template>
<script>
import BaseModel from '@/components/BaseModel'
import attachmentForm from './attachmentForm'
// import attachmentPreview from './attachmentPreview'
import { addOrUpdateSystemDocumentAttachment, getSystemDocumentAttachmentList, deleteSystemDocumentAttachment } from '@/api/dictionary'
const defaultSearchData = () => {
return {
PageIndex: 1,
PageSize: 1000,
Asc: false,
OffLine: null,
SortField: null
}
}
export default {
components: {
BaseModel,
attachmentForm,
// attachmentPreview
},
props: {
config: {
type: Object,
default: () => {
return {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
}
}
},
isView: {
type: Boolean,
default: false
},
rowData: {
type: Object,
default: () => {
return {}
}
},
SystemDocumentId: {
type: String,
default: ''
}
},
data() {
return {
searchData: defaultSearchData(),
visible: false,
title: null,
list: [],
rowDATA: {},
loading: false,
viewerOptions: {
toolbar: {
zoomIn: true,
zoomOut: true,
reset: true,
prev: false,
next: false,
rotateLeft: true,
rotateRight: true,
flipHorizontal: true,
flipVertical: true,
}
},
// perview_visible: false
}
},
watch: {
SystemDocumentId: {
handler() {
this.getList()
},
immediate: true,
}
},
methods: {
closeDialog() {
this.visible = false
},
getAllList() {
this.getList()
this.$emit("getList")
},
async del(row) {
try {
let confirm = await this.$confirm(this.$t("dictionary:signature:attachmentList:message:del"))
if (!confirm) return false
this.loading = true
let res = await deleteSystemDocumentAttachment(row.Id)
this.loading = false
if (res.IsSuccess) {
this.getAllList()
}
} catch (err) {
console.log(err)
this.loading = false
}
},
edit(row) {
this.title = this.$t('dictionary:signature:attachmentForm:title:update')
if (!row.Id) {
this.title = this.$t('dictionary:signature:attachmentForm:title:add')
}
this.rowDATA = Object.assign({}, row)
this.visible = true
},
async getList() {
try {
if (!this.SystemDocumentId) return false
this.loading = true
this.searchData.SystemDocumentId = this.SystemDocumentId
if (this.isView) {
this.searchData.OffLine = false
}
let res = await getSystemDocumentAttachmentList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result.CurrentPageData
}
} catch (err) {
this.loading = false
console.log(err)
}
},
async OffLine(row, val) {
try {
let data = Object.assign({}, row)
data.OffLine = val
this.loading = true
let res = await addOrUpdateSystemDocumentAttachment(data)
this.loading = false
if (res.IsSuccess) {
this.$t('dictionary:signature:attachmentList:updateSuccessfully')
this.getList()
}
} catch (err) {
this.loading = false
row.OffLine = !row.OffLine
console.log(err)
}
},
preview(data) {
// return this.perview_visible = true
this.rowDATA = Object.assign({}, data)
if (['.ppt',
'.pptx',
'.doc',
'.docx',
'.xls',
'.xlsx'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$onlyOffice({
path: data.FilePath,
type: data.FileFormat,
title: data.Name
})
}
if (['.jpg',
'.jpeg',
'.png'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$nextTick(() => {
this.$refs['picture_perview2'].$viewer.show()
})
}
if (['.pdf'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$preview({
path: data.Path || data.FilePath,
type: 'pdf',
title: data.Name,
})
}
if (['.mp4'].includes(`.${data.FileFormat.toLowerCase()}`)) {
this.$video({
path: data.Path || data.FilePath,
type: 'mp4',
title: data.Name,
})
}
},
// 排序
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
}
}
</script>
<style lang="scss" scoped>
.name {
display: block;
width: 90%;
}
</style>
@@ -0,0 +1,326 @@
<template>
<el-dialog :visible.sync="visible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper" :before-close="handleClose">
<div v-loading="loading" class="img-container" v-if="visible">
<el-card class="box-card left">
<div class="title">
{{ $t('dictionary:signature:fileList') }}
</div>
<div class="left-content">
<!-- 检查层级 -->
<div id="imgList" style="height: 100%; overflow: hidden">
<template v-for="(item, index) in list">
<div :id="`img${item.Id}`" :key="item.Id" :class="{
'is-boxActive': item.Id === rowData.Id,
}" class="img-box" @click="selected(item)">
<div class="file-image">
<el-image v-if="
[
'jpeg',
'jpg',
'png',
].includes(item.FileFormat)
" style="width: 100%; height: 100%"
:src="`${OSSclientConfig.basePath}${item.FilePath}?x-oss-process=image/resize,w_50,h_50/format,png`"
fit="contain" crossorigin="anonymous" />
<el-image v-else style="width: 100%; height: 100%" :src="getsrc(item.FileFormat)"
fit="contain" crossorigin="anonymous" />
</div>
<div v-if="item.Name.length < 15" class="img-text">
{{ `${index + 1}. ${item.Name}` }}
</div>
<el-tooltip v-else :content="item.Name" placement="bottom">
<div class="img-text">
{{ `${index + 1}. ${item.Name}` }}
</div>
</el-tooltip>
</div>
</template>
</div>
</div>
</el-card>
<!-- 预览图像 -->
<el-card class="box-card right">
<div style="width: 100%; height: 100%" v-if="[
'jpeg',
'jpg',
'png',
].includes(rowData.FileFormat)">
<imageViewer :rowData="rowData" />
</div>
<div style="width: 100%; height: 100%" v-else>
<PreviewFile v-if='rowData.FilePath' :file-path="rowData.FilePath" :file-type="rowData.FileFormat"
:title="rowData.Name" />
</div>
</el-card>
<!-- <el-card class="box-card" style="width:300px;height:100%;padding: 10px;margin-left:10px;">
<CheckForm />
</el-card> -->
</div>
</el-dialog>
</template>
<script>
import pdf from '@/assets/file_icon/pdf.png'
import zip from '@/assets/file_icon/zip.png'
import doc from '@/assets/file_icon/doc.png'
import docx from '@/assets/file_icon/docx.png'
import ppt from '@/assets/file_icon/ppt.png'
import pptx from '@/assets/file_icon/pptx.png'
import xls from '@/assets/file_icon/xls.png'
import xlsx from '@/assets/file_icon/xlsx.png'
import PreviewFile from '@/components/PreviewFile'
import imageViewer from './image-viewer'
import { getSystemDocumentAttachmentList } from '@/api/dictionary'
import { getTrialDocumentAttachmentList } from '@/api/trials'
const defaultSearchData = () => {
return {
PageIndex: 1,
PageSize: 1000,
Asc: false,
OffLine: null,
SortField: null
}
}
export default {
name: 'Notice',
components: {
PreviewFile,
imageViewer
},
props: {
SystemDocumentId: {
type: String,
default: ''
},
visible: {
type: Boolean,
default: false
},
isView: {
type: Boolean,
default: false
},
isTrial: {
type: Boolean,
default: false
}
},
data() {
return {
pdf,
zip,
doc,
docx,
ppt,
pptx,
xls,
xlsx,
rowData: {},
list: [],
searchData: defaultSearchData(),
title: this.$t('dictionary:signature:fileList')
}
},
watch: {
SystemDocumentId: {
handler() {
this.getList()
},
immediate: true,
}
},
methods: {
getsrc(type) {
return this[type.toLowerCase()]
},
selected(row) {
this.rowData = row
},
handleClose() {
this.$emit("update:visible", false)
},
async getList() {
try {
if (!this.SystemDocumentId) return false
this.loading = true
if (!this.isTrial) {
this.searchData.SystemDocumentId = this.SystemDocumentId
} else {
this.searchData.TrialDocumentId = this.SystemDocumentId
}
if (this.isView) {
this.searchData.OffLine = false
}
let res = null
if (!this.isTrial) {
res = await getSystemDocumentAttachmentList(this.searchData)
} else {
res = await getTrialDocumentAttachmentList(this.searchData)
}
this.loading = false
if (res.IsSuccess) {
this.list = res.Result.CurrentPageData
this.rowData = this.list[0] || {}
}
} catch (err) {
this.loading = false
console.log(err)
}
},
},
}
</script>
<style lang="scss" scoped>
.img-container {
position: relative;
width: 100%;
height: 100%;
padding: 10px;
display: flex;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
::v-deep .el-card__body {
padding: 0px;
}
}
.study-desc {
padding: 10px 5px;
line-height: 20px;
background-color: #d5d5d5;
font-weight: 500;
}
.left {
width: 220px;
height: 100%;
::v-deep .el-card__body {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.title {
height: 40px;
line-height: 40px;
border: 1ppx solid;
border: 1px solid #ebe7e7;
padding-left: 10px;
background-color: #4e4e4e;
color: #ffffff;
}
.left-content {
flex: 1;
overflow-y: auto;
}
// ::v-deep .el-tabs{
// height: 100%;
// }
// ::v-deep .el-tabs__header{
// height: 40px;
// }
// ::v-deep .el-tabs__content{
// flex: 1;
// overflow-y: auto;
// padding: 0;
// }
.img-box {
// position: relative;
display: inline-block;
box-sizing: border-box;
border-bottom: 2px solid #f3f3f3;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: flex-start;
padding: 5px 10px;
cursor: pointer;
// margin-bottom: 5px;
padding-left: 5px;
}
.img-text {
display: inline-block;
width: calc(100% - 60px);
margin-left: 5px;
height: 50px;
line-height: 50px;
overflow: hidden;
text-overflow: ellipsis;
/* 用省略号表示溢出的文本 */
white-space: nowrap;
}
.img-box:nth-last-child(1) {
margin-bottom: 0px;
}
.is-boxActive {
// border-color: #409eff;
color: #409eff;
}
.is-boxActiv:after {
opacity: 0;
}
}
.right {
flex: 1;
height: 100%;
margin-left: 10px;
::v-deep .el-card__body {
height: 100%;
width: 100%;
}
}
.switchBox {
width: 100%;
margin: 5px 0;
color: #4e4e4e;
.item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 5px;
}
}
.file-image {
width: 50px;
height: 50px;
}
::v-deep .el-collapse-item__header {
background-color: #d5d5d5;
}
::v-deep .el-collapse-item__header {
min-height: 48px;
height: auto;
}
::v-deep .el-collapse-item__content {
padding-bottom: 0;
}
</style>
@@ -0,0 +1,381 @@
/* eslint-disable no-unused-vars */
<template>
<div style="width: 100%; height: 100%">
<transition name="viewer-fade">
<div ref="image-viewer__wrapper" tabindex="-1" class="image-viewer__wrapper" :style="{ 'z-index': 5 }">
<!-- Arrow -->
<!-- 工具栏 -->
<div class="image-viewer__btn image-viewer__actions">
<div class="image-viewer__actions__inner">
<i class="el-icon-zoom-out" @click="handleActions('zoomOut')" />
<i class="el-icon-zoom-in" @click="handleActions('zoomIn')" />
<i class="el-image-viewer__actions__divider" />
<i class="el-icon-c-scale-to-original" @click="toggleMode" />
<i class="el-image-viewer__actions__divider" />
<i class="el-icon-refresh-left" @click="handleActions('anticlocelise')" />
<i class="el-icon-refresh-right" @click="handleActions('clocelise')" />
</div>
</div>
<!-- 图片 -->
<div id="image-viewer__canvas" class="image-viewer__canvas">
<img crossorigin="anonymous" :src="`${OSSclientConfig.basePath}${rowData.FilePath}`
" :style="imgStyle" style="max-width: 100%; max-height: 100%" @load="handleImgLoad" @error="handleImgError"
@mousedown="handleMouseDown" />
</div>
</div>
</transition>
</div>
</template>
<script>
import { on, off } from 'element-ui/src/utils/dom'
import { rafThrottle, isFirefox } from 'element-ui/src/utils/util'
const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
export default {
name: 'ImageViewer',
props: {
onSwitch: {
type: Function,
default: () => { },
},
onClose: {
type: Function,
default: () => { },
},
rowData:{
type: Object,
default: () => {
return {}
},
}
},
data() {
return {
loading: false,
transform: {
scale: 1,
deg: 0,
offsetX: 0,
offsetY: 0,
enableTransition: false,
},
}
},
computed: {
imgStyle() {
const { scale, deg, offsetX, offsetY, enableTransition } = this.transform
const style = {
transform: `scale(${scale}) rotate(${deg}deg)`,
transition: enableTransition ? 'transform .3s' : '',
'margin-left': `${offsetX}px`,
'margin-top': `${offsetY}px`,
}
return style
},
},
mounted() {
document.getElementById('image-viewer__canvas').onmousewheel = (event) => {
if (event.deltaY > 0) {
// 缩小
this.handleActions('zoomOut', {
zoomRate: 0.015,
enableTransition: false,
})
} else {
// 放大
this.handleActions('zoomIn', {
zoomRate: 0.015,
enableTransition: false,
})
}
return false
}
this.deviceSupportInstall()
},
methods: {
hide() {
this.deviceSupportUninstall()
this.onClose()
},
deviceSupportInstall() {
this._keyDownHandler = (e) => {
e.stopPropagation()
const keyCode = e.keyCode
switch (keyCode) {
// ESC
case 27:
this.hide()
break
// SPACE
case 32:
this.toggleMode()
break
// LEFT_ARROW
case 37:
this.prev()
break
// UP_ARROW
case 38:
this.handleActions('zoomIn')
break
// RIGHT_ARROW
case 39:
this.next()
break
// DOWN_ARROW
case 40:
this.handleActions('zoomOut')
break
}
}
this._mouseWheelHandler = rafThrottle((e) => {
const delta = e.wheelDelta ? e.wheelDelta : -e.detail
if (delta > 0) {
this.handleActions('zoomIn', {
zoomRate: 0.015,
enableTransition: false,
})
} else {
this.handleActions('zoomOut', {
zoomRate: 0.015,
enableTransition: false,
})
}
})
on(document, 'keydown', this._keyDownHandler)
on(document, mousewheelEventName, null)
// on(document, mousewheelEventName, this._mouseWheelHandler)
},
deviceSupportUninstall() {
off(document, 'keydown', this._keyDownHandler)
off(document, mousewheelEventName, this._mouseWheelHandler)
this._keyDownHandler = null
this._mouseWheelHandler = null
},
handleImgLoad(e) {
this.loading = false
},
handleImgError(e) {
this.loading = false
e.target.alt = '加载失败'
},
handleMouseDown(e) {
if (this.loading || e.button !== 0) return
const { offsetX, offsetY } = this.transform
const startX = e.pageX
const startY = e.pageY
this._dragHandler = rafThrottle((ev) => {
this.transform.offsetX = offsetX + ev.pageX - startX
this.transform.offsetY = offsetY + ev.pageY - startY
})
on(document, 'mousemove', this._dragHandler)
on(document, 'mouseup', (ev) => {
off(document, 'mousemove', this._dragHandler)
})
e.preventDefault()
},
reset() {
this.transform = {
scale: 1,
deg: 0,
offsetX: 0,
offsetY: 0,
enableTransition: false,
}
},
toggleMode() {
if (this.loading) return
this.reset()
},
handleActions(action, options = {}) {
if (this.loading) return
const { zoomRate, rotateDeg, enableTransition } = {
zoomRate: 0.2,
rotateDeg: 90,
enableTransition: true,
...options,
}
const { transform } = this
switch (action) {
case 'zoomOut':
if (transform.scale > 0.2) {
transform.scale = parseFloat(
(transform.scale - zoomRate).toFixed(3)
)
}
break
case 'zoomIn':
if (transform.scale < 5) {
transform.scale = parseFloat(
(transform.scale + zoomRate).toFixed(3)
)
}
break
case 'clocelise':
transform.deg += rotateDeg
break
case 'anticlocelise':
transform.deg -= rotateDeg
break
}
transform.enableTransition = enableTransition
},
},
}
</script>
<style lang="scss" scoped>
.image-viewer__wrapper {
position: relative;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
.image-viewer__btn {
position: absolute;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
opacity: 0.8;
cursor: pointer;
box-sizing: border-box;
user-select: none;
}
.image-viewer__close {
display: none;
top: 40px;
right: 40px;
width: 40px;
height: 40px;
font-size: 40px;
}
.image-viewer_desc {
position: absolute;
top: 40px;
left: 40px;
font-size: 15px;
padding: 5px;
height: 30px;
width: 70px;
line-height: 20px;
text-align: center;
color: #fff;
background-color: #606266;
border-color: #fff;
z-index: 1;
border-radius: 17px;
// border-radius: 2%;
}
.image-viewer__canvas {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.image-viewer__actions {
left: 50%;
bottom: 30px;
transform: translateX(-50%);
width: 282px;
height: 44px;
padding: 0 23px;
background-color: #606266;
border-color: #fff;
border-radius: 22px;
}
.image-viewer__actions__inner {
width: 100%;
height: 100%;
text-align: justify;
cursor: default;
font-size: 23px;
color: #fff;
display: flex;
align-items: center;
justify-content: space-around;
}
.image-viewer__next,
.image-viewer__prev {
top: 50%;
width: 44px;
height: 44px;
font-size: 24px;
color: #fff;
background-color: #606266;
border-color: #fff;
}
.image-viewer__prev {
transform: translateY(-50%);
left: 40px;
}
.image-viewer__next {
transform: translateY(-50%);
right: 40px;
text-indent: 2px;
}
.image-viewer__mask {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0.5;
// background:#000
}
.viewer-fade-enter-active {
animation: viewer-fade-in 0.3s;
}
.viewer-fade-leave-active {
animation: viewer-fade-out 0.3s;
}
@keyframes viewer-fade-in {
0% {
transform: translate3d(0, -20px, 0);
opacity: 0;
}
100% {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}
@keyframes viewer-fade-out {
0% {
transform: translate3d(0, 0, 0);
opacity: 1;
}
100% {
transform: translate3d(0, -20px, 0);
opacity: 0;
}
}
</style>
@@ -1,80 +1,103 @@
<template>
<BaseContainer>
<template slot="title-container">
<el-row v-if="isSystem" style="width: 100%;">
<el-col :span="12">
<h3>{{ TITLE }}</h3>
</el-col>
<el-col :span="12" style="text-align:right;">
<h3>
<Pagination class="page" :total="total" :page.sync="searchData.pageIndex" :limit.sync="searchData.pageSize"
layout="total, sizes, prev, pager, next" :background="false" style="display: inline-block;"
@pagination="getList" />
<el-button icon="el-icon-refresh-left" size="small" circle :title="$t('common:button:reset')"
@click="handleReset" />
</h3>
</el-col>
</el-row>
</template>
<template slot="search-container">
<el-form :inline="true" size="small">
<el-form-item :label="$t('dictionary:signature:search:FileTypeId')">
<el-select v-model="searchData.FileTypeId" style="width: 150px">
<el-option
v-for="item of dict.type.Sys_Document"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select v-model="searchData.FileTypeId" style="width: 150px" clearable>
<el-option v-for="item of $d.Sys_Document" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:search:Name')">
<el-input v-model="searchData.Name" style="width: 130px" clearable />
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:NeedConfirmedUserTypes')">
<el-select v-model="searchData.UserTypeId" style="width: 150px" clearable>
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName"
:value="item.Id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:IsDeleted')">
<el-select v-model="searchData.IsDeleted" style="width: 150px" clearable>
<el-option v-for="item of $d.TrainingStatus" :key="item.id" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:DocUserSignType')">
<el-select v-model="searchData.DocUserSignType" style="width: 150px" clearable>
<el-option v-for="item of $d.ReadingYesOrNo" :key="item.id" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:signature:table:createTime')">
<el-date-picker v-model="timeList" @change="changeTimeList" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" type="datetimerange">
</el-date-picker>
</el-form-item>
<el-form-item>
<!-- 查询 -->
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
<el-button type="primary" size="small" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
<el-button type="primary" size="small" :disabled="multipleSelection.length <= 0"
@click="publishSystemDocument(multipleSelection)">
{{ $t('dictionary:signature:button:publish') }}
</el-button>
<el-button type="primary" size="small" :disabled="multipleSelection.length <= 0"
@click="handleRepeal(multipleSelection)">
{{ $t('common:button:revoke') }}
</el-button>
</el-form-item>
</el-form>
<el-button
type="primary"
style="margin-left: auto; margin-bottom: 10px"
size="small"
@click="handleAdd"
>
{{ $t('common:button:new') }}
</el-button>
</template>
<template slot="main-container">
<el-table
v-adaptive="{ bottomOffset: 60 }"
v-loading="loading"
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="40" />
<el-table-column
prop="FileType"
:label="$t('dictionary:signature:table:FileType')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="Name"
:label="$t('dictionary:signature:table:Name')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="SignViewMinimumMinutes"
:label="$t('dictionary:signature:table:SignViewMinimumMinutes')"
show-overflow-tooltip
sortable="custom"
min-width="110"
/>
<el-table-column
prop="NeedConfirmedUserTypes"
:label="$t('dictionary:signature:table:NeedConfirmedUserTypes')"
show-overflow-tooltip
>
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" stripe height="100"
@sort-change="handleSortByColumn" @selection-change="handleSelectionChange">
<!-- <el-table-column type="index" width="40" /> -->
<el-table-column type="selection" width="55" :selectable="handleSelectable">
</el-table-column>
<el-table-column prop="FileType" :label="$t('dictionary:signature:table:FileType')" show-overflow-tooltip
sortable="custom" min-width="120px" />
<el-table-column prop="Name" :label="$t('dictionary:signature:table:Name')" show-overflow-tooltip
sortable="custom" min-width="120px" />
<el-table-column prop="AttachmentCount" :label="$t('dictionary:signature:table:AttachmentCount')"
show-overflow-tooltip sortable="custom" min-width="150px">
<template slot-scope="scope">
<el-button type="text" @click.stop="openAttachment(scope.row, true)">
{{ scope.row.AttachmentCount }}
<i class="el-icon-upload2" />
</el-button>
</template>
</el-table-column>
<el-table-column prop="SignViewMinimumMinutes" :label="$t('dictionary:signature:table:SignViewMinimumMinutes')"
show-overflow-tooltip sortable="custom" min-width="200px" />
<el-table-column prop="CurrentStaffTrainDays" :label="$t('dictionary:signature:table:CurrentStaffTrainDays')"
show-overflow-tooltip sortable="custom" min-width="200px" />
<el-table-column prop="NewStaffTrainDays" :label="$t('dictionary:signature:table:NewStaffTrainDays')"
show-overflow-tooltip sortable="custom" min-width="200px" />
<el-table-column prop="NeedConfirmedUserTypes" :label="$t('dictionary:signature:table:NeedConfirmedUserTypes')"
show-overflow-tooltip>
<template slot-scope="scope">
{{
scope.row.NeedConfirmedUserTypes
@@ -83,12 +106,8 @@
}}
</template>
</el-table-column>
<el-table-column
prop="IsDeleted"
:label="$t('dictionary:signature:table:IsDeleted')"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="IsDeleted" :label="$t('dictionary:signature:table:IsDeleted')" show-overflow-tooltip
sortable="custom" min-width="120px">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
$fd('TrainingStatus', scope.row.IsDeleted)
@@ -98,103 +117,89 @@
}}</el-tag>
</template>
</el-table-column>
<el-table-column
prop="DocUserSignType"
:label="$t('dictionary:signature:table:DocUserSignType')"
show-overflow-tooltip
sortable="custom"
min-width="90"
>
<el-table-column prop="IsPublish" :label="$t('dictionary:signature:table:IsPublish')" show-overflow-tooltip
sortable="custom" min-width="120px">
<template slot-scope="scope">
<el-tag :type="scope.row.IsPublish ? 'primary' : 'danger'">{{
$fd('AttachmentPublishStatus', scope.row.IsPublish)
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="DocUserSignType" :label="$t('dictionary:signature:table:DocUserSignType')"
show-overflow-tooltip sortable="custom" min-width="150px">
<template slot-scope="scope">
{{ $fd('ReadingYesOrNo', Number(scope.row.DocUserSignType)) }}
</template>
</el-table-column>
<el-table-column
prop="CreateTime"
:label="$t('dictionary:signature:table:CreateTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="CreateTime" :label="$t('dictionary:signature:table:CreateTime')" show-overflow-tooltip
sortable="custom" min-width="180px" />
<el-table-column :label="$t('common:action:action')" min-width="120">
<el-table-column :label="$t('common:action:action')" min-width="240px" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="handlePreview(scope.row)">
{{ $t('common:button:preview') }}
<el-button circle icon="el-icon-view" @click="handlePreview(scope.row)"
:title="$t('common:button:preview')">
</el-button>
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('common:button:edit') }}
<el-button circle icon="el-icon-edit-outline" :title="$t('common:button:edit')"
@click="handleEdit(scope.row)">
</el-button>
<el-button
:disabled="scope.row.IsDeleted"
type="text"
@click="handleRepeal(scope.row)"
>
{{ $t('common:button:revoke') }}
<el-button :disabled="scope.row.IsPublish" circle icon="el-icon-position"
:title="$t('dictionary:signature:button:publish')" @click="publishSystemDocument([scope.row])">
</el-button>
<el-button type="text" @click="handleDelete(scope.row)">
{{ $t('common:button:delete') }}
<el-button :disabled="scope.row.IsDeleted" circle icon="el-icon-close" :title="$t('common:button:revoke')"
@click="handleRepeal([scope.row])">
</el-button>
<el-button circle icon="el-icon-delete" :title="$t('common:button:delete')"
@click="handleDelete(scope.row)">
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" v-if="!isSystem" />
<!-- 新增/编辑 -->
<el-dialog
v-if="editVisible"
:visible.sync="editVisible"
:close-on-click-modal="false"
:title="title"
width="600px"
custom-class="base-dialog-wrapper"
>
<TemplateForm
:data="currentRow"
@closeDialog="closeDialog"
@getList="getList"
/>
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title"
width="600px" custom-class="base-dialog-wrapper">
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
</el-dialog>
<!--附件列表-->
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
@getList="getList" />
<!-- 预览文件 -->
<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"
/>
<attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible" :isView="true"
v-if="perview_visible" />
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="$t('common:button:preview')"
:fullscreen="true" append-to-body custom-class="base-dialog-wrapper">
<span style="position: fixed; left: 16px; top: 45px;cursor: pointer;font-size: 18px;color:#409EFF"
@click.stop="openAttachment(currentRow)" v-if="currentRow.AttachmentCount">{{
$t('trials:signRecords:table:AttachmentCount') }} ({{
currentRow.AttachmentCount }})</span>
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<PreviewFile v-if="previewVisible" :file-path="currentPath" :file-type="currentType" />
</div>
</el-dialog>
</template>
</BaseContainer>
</template>
<script>
import { getSystemDocumentList, deleteSystemDocument } from '@/api/dictionary'
import { userAbandonDoc } from '@/api/trials'
import { getSystemDocumentList, deleteSystemDocument, publishSystemDocument, outLineSystemDocument, getSystemDocumentAttachmentList } from '@/api/dictionary'
import { userAbandonDoc, getTrialUserTypeList } from '@/api/trials'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import TemplateForm from './TemplateForm'
import attachmentList from './attachmentList'
import PreviewFile from '@/components/PreviewFile/index'
import attachmentPreview from './attachmentPreview'
const searchDataDefault = () => {
return {
FileTypeId: '',
BeginCreateTime: null,
EndCreateTime: null,
IsDeleted: null,
DocUserSignType: null,
UserTypeId: null,
Name: '',
PageIndex: 1,
PageSize: 20,
@@ -202,8 +207,18 @@ const searchDataDefault = () => {
}
export default {
name: 'SignatureTemplate',
components: { BaseContainer, Pagination, TemplateForm, PreviewFile },
components: { BaseContainer, Pagination, TemplateForm, PreviewFile, attachmentList, attachmentPreview },
dicts: ['Sys_Document'],
props: {
isSystem: {
type: Boolean,
default: false
},
TITLE: {
type: String,
default: ''
}
},
data() {
return {
searchData: searchDataDefault(),
@@ -216,12 +231,82 @@ export default {
previewVisible: false,
title: '',
loading: false,
userTypeOptions: [],
timeList: [],
attachment_Visible: false,
SystemDocumentId: null,
config: {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
},
multipleSelection: [],
perview_visible: false
}
},
mounted() {
this.getList()
this.getUserType()
},
methods: {
handleSelectable(row) {
return !row.IsDeleted || !row.IsPublish
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 发布
async publishSystemDocument(list) {
try {
let confirm = await this.$confirm(this.$t('dictionary:signature:confirm:publishFile'), {
type: 'warning',
distinguishCancelAndClose: true,
})
if (!confirm) return false
let arr = list.filter(item => !item.IsPublish)
if (arr.length <= 0) return this.getList()
let data = {
ids: arr.map(item => item.Id)
}
this.loading = true
let res = await publishSystemDocument(data)
this.loading = false
if (res.IsSuccess) {
this.getList()
}
} catch (err) {
this.loading = false
console.log(err)
}
},
openAttachment(row, isList = false) {
this.SystemDocumentId = row.Id
this.currentRow = { ...row }
if (!isList) {
this.perview_visible = true
} else {
this.config.visible = true
}
},
changeTimeList() {
if (this.timeList) {
this.searchData.BeginCreateTime = this.timeList[0]
this.searchData.EndCreateTime = this.timeList[1]
} else {
this.searchData.BeginCreateTime = null
this.searchData.EndCreateTime = null
}
},
// 获取用户类型下拉数据
getUserType() {
getTrialUserTypeList()
.then((res) => {
this.userTypeOptions = res.Result
})
.catch(() => {
this.loading = false
})
},
// 获取系统文件数据
getList() {
this.loading = true
@@ -251,12 +336,23 @@ export default {
this.editVisible = true
},
// 预览
handlePreview(row) {
async handlePreview(row) {
const { Name, FullFilePath } = row
this.currentPath = FullFilePath
this.currentType = row.Name
? Name.substring(Name.lastIndexOf('.') + 1).toLocaleLowerCase()
: ''
let searchData = {
OffLine: false,
PageIndex: 1,
PageSize: 1000,
Asc: false,
SortField: null,
SystemDocumentId: row.Id
}
this.currentRow = Object.assign({}, row)
let res = await getSystemDocumentAttachmentList(searchData)
this.currentRow.AttachmentCount = res.Result.CurrentPageData.length
this.previewVisible = true
},
// 编辑
@@ -272,8 +368,13 @@ export default {
distinguishCancelAndClose: true,
})
.then(() => {
let arr = row.filter(item => !item.IsDeleted)
if (arr.length <= 0) return this.getList()
let data = {
Ids: arr.map(item => item.Id)
}
this.loading = true
userAbandonDoc(row.Id, true)
outLineSystemDocument(data)
.then((res) => {
this.loading = false
if (res.IsSuccess) {
@@ -287,7 +388,7 @@ export default {
this.loading = false
})
})
.catch(() => {})
.catch(() => { })
},
// 删除
handleDelete(row) {
@@ -317,6 +418,7 @@ export default {
// 关闭弹窗
closeDialog() {
this.editVisible = false
this.attachment_Visible = false
},
// 重置
handleReset() {
@@ -614,6 +614,18 @@
/>
</el-form-item>
</el-col>
<el-col v-show="title !== '复制'" :span="24">
<el-form-item>
<span slot="label">
是否默认
</span>
<el-switch
v-model="form.IsDefaultChoice"
:active-value="true"
:inactive-value="false"
/>
</el-form-item>
</el-col>
<!--分割线-->
<el-col v-show="title !== '复制' && form.ConfigType == 'M'" :span="24">
<el-divider content-position="left">其他信息</el-divider>
@@ -1130,6 +1142,7 @@ export default {
DescriptionCN: null,
InterfaceName: null,
IsEnable: true,
IsDefaultChoice: true,
ModuleTypeId: null,
OptTypeId: null,
ChildrenTypeId: null,
@@ -7,74 +7,28 @@
<el-button type="primary" size="mini" @click="handleAdd">新建</el-button>
</span>
</div>
<el-table
v-loading="loading"
v-adaptive="{bottomOffset:45}"
:data="list"
stripe
size="small"
height="100"
>
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" :data="list" stripe size="small" height="100"
@sort-change="handleSortByColumn">
<el-table-column type="index" width="60" />
<el-table-column
v-if="!~$route.path.indexOf('select')"
prop="Code"
label="字典键值"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
prop="ValueCN"
label="中文值"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
prop="Value"
label="英文值"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
prop="ChildGroup"
label="分组"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
prop="ShowOrder"
label="显示顺序"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
prop="Description"
label="描述"
min-width="180"
show-overflow-tooltip
/>
<el-table-column v-if="!~$route.path.indexOf('select')" prop="Code" label="字典键值" min-width="180"
show-overflow-tooltip sortable='custom' />
<el-table-column prop="ValueCN" label="中文值" min-width="180" show-overflow-tooltip sortable='custom' />
<el-table-column prop="Value" label="英文值" min-width="180" show-overflow-tooltip sortable='custom' />
<el-table-column prop="ChildGroup" label="分组" min-width="180" show-overflow-tooltip sortable='custom' />
<el-table-column prop="ShowOrder" label="显示顺序" min-width="180" show-overflow-tooltip sortable='custom' />
<el-table-column prop="Description" label="描述" min-width="180" show-overflow-tooltip sortable='custom' />
<el-table-column label="是否可用" width="100" fixed="right">
<template slot-scope="scope">
<el-switch
v-model="scope.row.IsEnable"
:active-value="true"
:inactive-value="false"
@change="(event) => {return switchChange(event, scope.row)}"
/>
<el-switch v-model="scope.row.IsEnable" :active-value="true" :inactive-value="false"
@change="(event) => { return switchChange(event, scope.row) }" />
</template>
</el-table-column>
<el-table-column label="操作" width="150" fixed="right">
<template slot-scope="scope">
<el-button
type="text"
@click="handleEdit(scope.row)"
>
<el-button type="text" @click="handleEdit(scope.row)">
编辑
</el-button>
<el-button
type="text"
@click="handleDelete(scope.row)"
>
<el-button type="text" @click="handleDelete(scope.row)">
删除
</el-button>
</template>
@@ -91,7 +45,8 @@ import DictionaryChildAddOrUpdateForm from './DictionaryChildAddOrUpdateForm'
const searchDataDefault = () => {
return {
parentId: ''
Asc: true,
SortField: 'ShowOrder',
}
}
export default {
@@ -121,6 +76,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()
},
handleChild(row) {
this.drawerChild = true
this.getDictionaryChildList(row.Id)
@@ -172,7 +138,8 @@ export default {
//
getList() {
this.loading = true
getDictionaryChildList(this.parent.Id).then(res => {
this.searchData.ParentId = this.parent.Id
getDictionaryChildList(this.searchData).then(res => {
this.loading = false
this.list = res.Result
}).catch(() => { this.loading = false })
@@ -190,6 +157,4 @@ export default {
}
</script>
<style scoped>
</style>
<style scoped></style>
@@ -5,151 +5,81 @@
</div>
<div>
<!-- 配置 -->
<el-button
size="mini"
type="primary"
:disabled="isCompleteConfig"
@click="handleAdd"
style="margin-right: 10px;"
>
<el-button size="mini" type="primary" :disabled="isCompleteConfig" @click="handleAdd"
style="margin-right: 10px;">
{{ $t('dictionary:template:criterionDictionary:button:config') }}
</el-button>
</div>
</div>
<el-table
v-loading="loading"
style="width: 100%"
:data="list"
stripe
>
<el-table v-loading="loading" style="width: 100%" :data="list" stripe>
<!-- 序号 -->
<el-table-column
prop=""
label=""
width="50"
>
<el-table-column prop="" label="" width="50">
<template slot-scope="scope">
{{scope.$index + 1}}
{{ scope.$index + 1 }}
</template>
</el-table-column>
<!-- 字典表名 -->
<el-table-column
prop="Code"
:label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip
>
<el-table-column prop="Code" :label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip>
</el-table-column>
<!-- 描述 -->
<el-table-column
prop="Description"
:label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip
>
<el-table-column prop="Description" :label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip>
</el-table-column>
<!-- 子项数量 -->
<el-table-column
prop="Count"
:label="$t('dictionary:template:criterionDictionary:table:count')"
show-overflow-tooltip
>
<el-table-column prop="Count" :label="$t('dictionary:template:criterionDictionary:table:count')"
show-overflow-tooltip>
</el-table-column>
<!-- 排序 -->
<el-table-column
prop="ShowOrder"
:label="$t('dictionary:template:criterionDictionary:table:showOrder')"
show-overflow-tooltip
>
<el-table-column prop="ShowOrder" :label="$t('dictionary:template:criterionDictionary:table:showOrder')"
show-overflow-tooltip>
</el-table-column>
<!-- 操作 -->
<el-table-column
prop="Description"
:label="$t('common:action:action')"
show-overflow-tooltip
>
<el-table-column prop="Description" :label="$t('common:action:action')" show-overflow-tooltip>
<template slot-scope="scope">
<!-- 配置 -->
<el-button :disabled="isCompleteConfig" type="text" @click="openChildren(scope.row)">
<el-button type="text" @click="openChildren(scope.row)">
{{ $t('dictionary:template:criterionDictionary:button:config') }}
</el-button>
<!-- 删除 -->
<el-button
type="text"
:disabled="isCompleteConfig"
@click="handleDelete(scope.row)"
>
<el-button type="text" :disabled="isCompleteConfig" @click="handleDelete(scope.row)">
{{ $t('common:button:delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<el-drawer
:title="drawer_cfg.title"
:append-to-body="true"
:modal-append-to-body="false"
:visible.sync="drawer_cfg.drawerChild"
direction="rtl"
size="80%"
>
<CriterionDictionaryConfig v-if="drawer_cfg.drawerChild" @getList="getList" :criterionId="criterionId" :parentCode="drawer_cfg.title"></CriterionDictionaryConfig>
<el-drawer :title="drawer_cfg.title" :append-to-body="true" :modal-append-to-body="false"
:visible.sync="drawer_cfg.drawerChild" direction="rtl" size="80%">
<CriterionDictionaryConfig v-if="drawer_cfg.drawerChild" @getList="getList" :isCompleteConfig="isCompleteConfig"
:criterionId="criterionId" :parentCode="drawer_cfg.title"></CriterionDictionaryConfig>
</el-drawer>
<el-drawer
:title="drawer_cfg2.title"
:append-to-body="true"
:modal-append-to-body="false"
:visible.sync="drawer_cfg2.drawerChild"
direction="rtl"
size="80%"
>
<el-drawer :title="drawer_cfg2.title" :append-to-body="true" :modal-append-to-body="false"
:visible.sync="drawer_cfg2.drawerChild" direction="rtl" size="80%">
<div style="text-align: right;">
<el-button
size="mini"
type="primary"
@click="handleSave"
v-loading="loading"
>
{{ $t('common:button:save')}}
<el-button size="mini" type="primary" @click="handleSave" v-loading="loading">
{{ $t('common:button:save') }}
</el-button>
</div>
<el-table
v-loading="loading"
v-adaptive="{bottomOffset:0}"
height="100"
ref="multipleTable"
style="width: 100%"
:data="dicList"
stripe
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55">
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 0 }" height="100" ref="multipleTable" style="width: 100%"
:data="dicList" stripe @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55">
</el-table-column>
<el-table-column
width="55">
<el-table-column width="55">
<template slot-scope="scope">
{{ scope.$index + 1}}
{{ scope.$index + 1 }}
</template>
</el-table-column>
<!-- 字典表名 -->
<el-table-column
prop="Code"
:label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip
>
<el-table-column prop="Code" :label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip>
</el-table-column>
<!-- 描述 -->
<el-table-column
prop="Description"
:label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip
>
<el-table-column prop="Description" :label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip>
</el-table-column>
<!-- 排序 -->
<el-table-column
prop="ShowOrder"
:label="$t('dictionary:template:criterionDictionary:table:showOrder')"
show-overflow-tooltip
>
<el-table-column prop="ShowOrder" :label="$t('dictionary:template:criterionDictionary:table:showOrder')"
show-overflow-tooltip>
</el-table-column>
</el-table>
</el-drawer>
@@ -264,7 +194,7 @@ export default {
this.loading = true
//
this.$confirm(this.$t('template:criterionDictionary:message:msg1')).then(() => {
deleteSystemCriterionDictionary({Id: row.Id}).then(res => {
deleteSystemCriterionDictionary({ Id: row.Id }).then(res => {
this.$message.success(this.$t('common:message:deletedSuccessfully'))
this.loading = false
this.getList()
@@ -277,7 +207,7 @@ export default {
</script>
<style lang="scss" scoped>
::v-deep .el-form-item__content{
::v-deep .el-form-item__content {
width: calc(100% - 110px);
}
</style>
@@ -4,134 +4,74 @@
<div>
</div>
<div>
<el-button
size="mini"
type="primary"
@click="handleAdd"
style="margin-right: 10px;"
>
<el-button size="mini" type="primary" @click="handleAdd" style="margin-right: 10px;" v-if="!isCompleteConfig">
{{ $t('dictionary:template:criterionDictionary:button:config') }}
</el-button>
</div>
</div>
<el-table
v-loading="loading"
v-adaptive="{bottomOffset:0}"
height="100"
style="width: 100%"
:data="list"
stripe
>
<el-table-column
prop=""
label=""
width="50"
>
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 0 }" height="100" style="width: 100%" :data="list" stripe>
<el-table-column prop="" label="" width="50">
<template slot-scope="scope">
{{scope.$index + 1}}
{{ scope.$index + 1 }}
</template>
</el-table-column>
<!-- 键值 -->
<el-table-column
prop="Code"
:label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip
/>
<el-table-column prop="Code" :label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip />
<!-- 中文值 -->
<el-table-column
prop="ValueCN"
:label="$t('dictionary:template:criterionDictionary:table:valueCN')"
show-overflow-tooltip
>
<el-table-column prop="ValueCN" :label="$t('dictionary:template:criterionDictionary:table:valueCN')"
show-overflow-tooltip>
</el-table-column>
<!-- 英文值 -->
<el-table-column
prop="Value"
:label="$t('dictionary:template:criterionDictionary:table:value')"
show-overflow-tooltip
>
<el-table-column prop="Value" :label="$t('dictionary:template:criterionDictionary:table:value')"
show-overflow-tooltip>
</el-table-column>
<!-- 描述 -->
<el-table-column
prop="Description"
:label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip
>
<el-table-column prop="Description" :label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip>
</el-table-column>
<!-- 分组 -->
<el-table-column
prop="Description"
:label="$t('dictionary:template:criterionDictionary:table:group')"
show-overflow-tooltip
>
<el-table-column prop="Description" :label="$t('dictionary:template:criterionDictionary:table:group')"
show-overflow-tooltip>
<template slot-scope="scope">
<div>
<el-radio-group v-model="scope.row.CrterionDictionaryGroup" @change="(v) => {crterionDictionaryGroupChange(v, scope.row)}" size="mini">
<el-radio-button v-for="item of $d.CrterionDictionaryGroup" :label="item.value" :key="item.id">{{item.label}}</el-radio-button>
<div v-if="!isCompleteConfig">
<el-radio-group v-model="scope.row.CrterionDictionaryGroup"
@change="(v) => { crterionDictionaryGroupChange(v, scope.row) }" size="mini">
<el-radio-button v-for="item of $d.CrterionDictionaryGroup" :label="item.value" :key="item.id">{{
item.label }}</el-radio-button>
</el-radio-group>
</div>
<div v-else>{{ $fd('CrterionDictionaryGroup', scope.row.CrterionDictionaryGroup) }}</div>
</template>
</el-table-column>
</el-table>
<el-dialog
v-if="config.visible"
:visible.sync="config.visible"
:close-on-click-modal="false"
:title="config.title"
width="90%"
append-to-body
>
<el-dialog v-if="config.visible" :visible.sync="config.visible" :close-on-click-modal="false" :title="config.title"
width="90%" append-to-body>
<div>
<div style="text-align: right;">
<el-button
size="mini"
type="primary"
@click="handleSave"
v-loading="loading"
>
{{ $t('common:button:save')}}
<el-button size="mini" type="primary" @click="handleSave" v-loading="loading">
{{ $t('common:button:save') }}
</el-button>
</div>
<el-table
v-loading="loading"
v-adaptive="{bottomOffset:100}"
height="100"
ref="multipleTable"
:data="$d[parentCode]"
stripe
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55">
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 100 }" height="100" ref="multipleTable"
:data="$d[parentCode]" stripe @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55">
</el-table-column>
<!-- 键值 -->
<el-table-column
prop="raw.Code"
:label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip
>
<el-table-column prop="raw.Code" :label="$t('dictionary:template:criterionDictionary:table:code')"
show-overflow-tooltip>
</el-table-column>
<!-- 中文值 -->
<el-table-column
prop="raw.ValueCN"
:label="$t('dictionary:template:criterionDictionary:table:valueCN')"
show-overflow-tooltip
>
<el-table-column prop="raw.ValueCN" :label="$t('dictionary:template:criterionDictionary:table:valueCN')"
show-overflow-tooltip>
</el-table-column>
<!-- 英文值 -->
<el-table-column
prop="raw.Value"
:label="$t('dictionary:template:criterionDictionary:table:value')"
show-overflow-tooltip
>
<el-table-column prop="raw.Value" :label="$t('dictionary:template:criterionDictionary:table:value')"
show-overflow-tooltip>
</el-table-column>
<!-- 描述 -->
<el-table-column
prop="raw.Description"
:label="$t('dictionary:template:criterionDictionary:table:description')"
show-overflow-tooltip
>
<el-table-column prop="raw.Description"
:label="$t('dictionary:template:criterionDictionary:table:description')" show-overflow-tooltip>
</el-table-column>
</el-table>
</div>
@@ -150,6 +90,10 @@ export default {
parentCode: {
type: String,
required: true
},
isCompleteConfig: {
type: Boolean,
default: false
}
},
data() {
@@ -178,7 +122,7 @@ export default {
this.loading = false
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.getList()
}).catch(() => {this.loading = false})
}).catch(() => { this.loading = false })
},
toggleSelection(rows) {
console.log(this.$refs.multipleTable)
@@ -240,7 +184,7 @@ export default {
</script>
<style lang="scss" scoped>
::v-deep .el-form-item__content{
::v-deep .el-form-item__content {
width: calc(100% - 110px);
}
</style>
@@ -1,12 +1,5 @@
<template>
<el-form
ref="emailForm"
v-loading="loading"
:model="form"
label-width="180px"
size="small"
:rules="rules"
>
<el-form ref="emailForm" v-loading="loading" :model="form" label-width="180px" size="small" :rules="rules">
<el-row>
<el-col :span="24">
<!-- Code -->
@@ -29,12 +22,7 @@
<el-col :span="12">
<!-- 邮件延时发送s数 -->
<el-form-item :label="$t('dictionary:email:label:emailDelaySeconds')" prop="EmailDelaySeconds">
<el-input
v-model.number="form.EmailDelaySeconds"
style="width: 300px"
type="number"
clearable
>
<el-input v-model.number="form.EmailDelaySeconds" style="width: 300px" type="number" clearable>
</el-input>
</el-form-item>
</el-col>
@@ -42,12 +30,8 @@
<!-- 业务层级 -->
<el-form-item :label="$t('dictionary:email:label:businessLevel')" prop="BusinessLevelEnum">
<el-select v-model="form.BusinessLevelEnum" clearable class="mr">
<el-option
v-for="item of $d.BusinessLevel"
:key="`BusinessLevel${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item of $d.BusinessLevel" :key="`BusinessLevel${item.label}`" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
@@ -55,12 +39,8 @@
<!-- 业务模块 -->
<el-form-item :label="$t('dictionary:email:label:businessModule')" prop="BusinessModuleEnum">
<el-select v-model="form.BusinessModuleEnum" clearable class="mr">
<el-option
v-for="item of $d.BusinessModule"
:key="`BusinessModule${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item of $d.BusinessModule" :key="`BusinessModule${item.label}`" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
@@ -68,80 +48,46 @@
<!-- 业务场景 -->
<el-form-item :label="$t('trials:emailManageCfg:table:BusinessScenarioEnum')" prop="BusinessScenarioEnum">
<el-select v-model="form.BusinessScenarioEnum" clearable class="mr">
<el-option
v-for="item of $d.Email_BusinessScenario"
:key="`BusinessScenarioEnum${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item of $d.Email_BusinessScenario" :key="`BusinessScenarioEnum${item.label}`"
:label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 收件人 -->
<el-form-item :label="$t('trials:emailManageCfg:title:toUserTypeList')" prop="ToUserTypeList">
<el-select
v-model="form.ToUserTypeList"
clearable
multiple
class="mr"
>
<el-option
v-for="item of $d.UserType"
:key="`ToUserTypeList${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-select v-model="form.ToUserTypeList" clearable multiple class="mr">
<el-option v-for="item of $d.UserType" :key="`ToUserTypeList${item.label}`" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 抄送人 -->
<el-form-item :label="$t('trials:emailManageCfg:title:copyUserTypeList')" prop="CopyUserTypeList">
<el-select
v-model="form.CopyUserTypeList"
clearable
multiple
class="mr"
>
<el-option
v-for="item of $d.UserType"
:key="`CopyUserTypeList${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-select v-model="form.CopyUserTypeList" clearable multiple class="mr">
<el-option v-for="item of $d.UserType" :key="`CopyUserTypeList${item.label}`" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 加急状态 -->
<el-form-item :label="$t('dictionary:email:label:IsUrgent')" prop="EmailUrgentEnum">
<el-select
v-model="form.EmailUrgentEnum"
@change="
(v) => {
v === 1 ? (form.EmailCron = null) : null
}
"
clearable
class="mr"
>
<el-option
v-for="item of $d.EmailUrgent"
:key="`EmailUrgent${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-select v-model="form.EmailUrgentEnum" @change="
(v) => {
v === 1 ? (form.EmailCron = null) : null
}
" clearable class="mr">
<el-option v-for="item of $d.EmailUrgent" :key="`EmailUrgent${item.label}`" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 发送周期和时间 -->
<el-form-item
:label="$t('trials:emailManageCfg:table:EmailCron')"
v-if="form.EmailUrgentEnum !== 1"
prop="EmailCron"
>
<el-form-item :label="$t('trials:emailManageCfg:table:EmailCron')" v-if="form.EmailUrgentEnum !== 1"
prop="EmailCron">
<el-input style="width: 300px" readonly v-model="form.EmailCron" />
<!-- 生成 cron -->
<el-button type="primary" @click="showDialog"> {{ $t('dictionary:email:button:cron') }} </el-button>
@@ -151,12 +97,8 @@
<!-- 是否需要回执 -->
<el-form-item :label="$t('trials:emailManageCfg:title:isReturnRequired')" prop="IsReturnRequired">
<el-radio-group v-model="form.IsReturnRequired">
<el-radio
v-for="item of $d.YesOrNo"
:label="item.value"
:key="`IsReturnRequired${item.value}`"
>{{ item.label }}</el-radio
>
<el-radio v-for="item of $d.YesOrNo" :label="item.value" :key="`IsReturnRequired${item.value}`">{{
item.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@@ -164,48 +106,30 @@
<!-- 是否自动发送 -->
<el-form-item :label="$t('trials:emailManageCfg:table:IsAutoSend')" prop="IsAutoSend">
<el-radio-group v-model="form.IsAutoSend">
<el-radio
v-for="item of $d.YesOrNo"
:label="item.value"
:key="`IsAutoSend${item.value}`"
>{{ item.label }}</el-radio
>
<el-radio v-for="item of $d.YesOrNo" :label="item.value" :key="`IsAutoSend${item.value}`">{{ item.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="systemLevel">
<!-- 是否区分标准 -->
<el-form-item :label="$t('dictionary:email:button:isDistinguishCriteria')" prop="IsDistinguishCriteria">
<el-radio-group
v-model="form.IsDistinguishCriteria"
@change="
() => {
form.CriterionTypeEnum = null
}
"
>
<el-radio
v-for="item of $d.YesOrNo"
:label="item.value"
:key="`IsDistinguishCriteria${item.value}`"
>{{ item.label }}</el-radio
>
<el-radio-group v-model="form.IsDistinguishCriteria" @change="
() => {
form.CriterionTypeEnum = null
}
">
<el-radio v-for="item of $d.YesOrNo" :label="item.value" :key="`IsDistinguishCriteria${item.value}`">{{
item.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
:label="$t('trials:auditRecord:table:criterion')"
v-if="form.IsDistinguishCriteria"
prop="CriterionTypeEnum"
>
<el-select v-model="form.CriterionTypeEnum" clearable class="mr">
<el-option
v-for="item of $d.CriterionType"
:key="`CriterionType${item.label}`"
:label="item.label"
:value="item.value"
/>
<el-form-item :label="$t('trials:auditRecord:table:criterion')" v-if="form.IsDistinguishCriteria"
prop="CriterionTypeList">
<el-select 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>
</el-form-item>
</el-col>
@@ -213,106 +137,65 @@
<!-- 是否启用 -->
<el-form-item :label="$t('trials:emailManageCfg:table:IsEnable')" prop="IsEnable">
<el-radio-group v-model="form.IsEnable">
<el-radio
v-for="item of $d.YesOrNo"
:label="item.value"
:key="`IsEnable${item.value}`"
>{{ item.label }}</el-radio
>
<el-radio v-for="item of $d.YesOrNo" :label="item.value" :key="`IsEnable${item.value}`">{{ item.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 附件CN -->
<el-form-item :label="$t('trials:emailManageCfg:table:fileListCN')" prop="IsEnable">
<el-upload
class="upload-demo"
action
:before-upload="beforeUploadCN"
:http-request="handleUploadFileCN"
:on-preview="handlePreviewCN"
:on-remove="handleRemoveFileCN"
:show-file-list="true"
:limit="1"
:file-list="fileListCN"
>
<el-button
size="small"
type="primary"
:disabled="fileListCN.length > 0"
>{{ $t('common:button:upload') }}</el-button
>
<el-upload class="upload-demo" action :before-upload="beforeUploadCN" :http-request="handleUploadFileCN"
:on-preview="handlePreviewCN" :on-remove="handleRemoveFileCN" :show-file-list="true" :limit="1"
:file-list="fileListCN">
<el-button size="small" type="primary" :disabled="fileListCN.length > 0">{{ $t('common:button:upload')
}}</el-button>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 附件EN -->
<el-form-item :label="$t('trials:emailManageCfg:table:fileListEN')" prop="IsEnable">
<el-upload
class="upload-demo"
action
:before-upload="beforeUploadEN"
:http-request="handleUploadFileEN"
:on-preview="handlePreviewEN"
:on-remove="handleRemoveFileEN"
:show-file-list="true"
:limit="1"
:file-list="fileListEN"
>
<el-button
size="small"
type="primary"
:disabled="fileListEN.length > 0"
>{{ $t('common:button:upload') }}</el-button
>
<el-upload class="upload-demo" action :before-upload="beforeUploadEN" :http-request="handleUploadFileEN"
:on-preview="handlePreviewEN" :on-remove="handleRemoveFileEN" :show-file-list="true" :limit="1"
:file-list="fileListEN">
<el-button size="small" type="primary" :disabled="fileListEN.length > 0">{{ $t('common:button:upload')
}}</el-button>
</el-upload>
</el-form-item>
</el-col>
</el-row>
<!-- 邮件内容模版CN -->
<el-form-item
:label="$t('dictionary:email:label:emailHtmlContentCN')"
prop="EmailHtmlContentCN"
style="position: relative"
>
<el-input
v-model="form.EmailHtmlContentCN"
type="textarea"
:autosize="{ minRows: 8, maxRows: 8 }"
/>
<el-button
:disabled="!form.EmailHtmlContentCN && form.EmailHtmlContent"
type="text"
<el-form-item :label="$t('dictionary:email:label:emailHtmlContentCN')" prop="EmailHtmlContentCN"
style="position: relative">
<div class="html_temp">
<prism-editor class="my-editor" v-model="form.EmailHtmlContentCN" :highlight="highlighter" :line-numbers="true"
style="width: 50%;max-height: 500px;"></prism-editor>
<div v-html="form.EmailHtmlContentCN" style="width: 50%;"></div>
</div>
<!-- <el-input v-model="form.EmailHtmlContentCN" type="textarea" :autosize="{ minRows: 8, maxRows: 8 }" />
<el-button :disabled="!form.EmailHtmlContentCN && form.EmailHtmlContent" type="text"
@click="PreviewHTML(form.EmailHtmlContentCN, form.EmailHtmlContent)"
style="position: absolute; left: -50px; top: 30px"
>
style="position: absolute; left: -50px; top: 30px">
{{ $t('common:button:preview') }}
</el-button>
</el-button> -->
</el-form-item>
<!-- 邮件内容模版EN -->
<el-form-item
:label="$t('dictionary:email:label:emailHtmlContent')"
prop="EmailHtmlContent"
style="position: relative"
>
<el-input
v-model="form.EmailHtmlContent"
type="textarea"
:autosize="{ minRows: 8, maxRows: 8 }"
/>
<el-button
:disabled="!form.EmailHtmlContentCN && form.EmailHtmlContent"
type="text"
<el-form-item :label="$t('dictionary:email:label:emailHtmlContent')" prop="EmailHtmlContent"
style="position: relative">
<div class="html_temp">
<prism-editor class="my-editor" v-model="form.EmailHtmlContent" :highlight="highlighter" :line-numbers="true"
style="width: 50%;max-height: 500px;"></prism-editor>
<div v-html="form.EmailHtmlContent" style="width: 50%;"></div>
</div>
<!-- <el-input v-model="form.EmailHtmlContent" type="textarea" :autosize="{ minRows: 8, maxRows: 8 }" />
<el-button :disabled="!form.EmailHtmlContentCN && form.EmailHtmlContent" type="text"
@click="PreviewHTML(form.EmailHtmlContentCN, form.EmailHtmlContent)"
style="position: absolute; left: -50px; top: 30px"
>
style="position: absolute; left: -50px; top: 30px">
{{ $t('common:button:preview') }}
</el-button>
</el-button> -->
</el-form-item>
<div
class="base-dialog-footer"
style="text-align: right; margin-top: 10px; padding-bottom: 10px"
>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px; padding-bottom: 10px">
<el-form-item style="text-align: right">
<el-button size="small" type="primary" @click="handleSave">
{{ $t('common:button:save') }}
@@ -321,12 +204,7 @@
</div>
<!-- 生成 cron -->
<el-dialog append-to-body :title="$t('dictionary:email:button:cron')" :visible.sync="showCron">
<vcrontab
:hideComponent="['year']"
@hide="showCron = false"
@fill="crontabFill"
:expression="expression"
>
<vcrontab :hideComponent="['year']" @hide="showCron = false" @fill="crontabFill" :expression="expression">
</vcrontab>
</el-dialog>
</el-form>
@@ -334,6 +212,14 @@
<script>
import { Upload, addOrUpdateEmailNoticeConfigList } from '@/api/dictionary'
import vcrontab from 'vcrontab'
import { PrismEditor } from 'vue-prism-editor';
import 'vue-prism-editor/dist/prismeditor.min.css';
import { highlight, languages } from 'prismjs/components/prism-core';
import 'prismjs/components/prism-clike';
import 'prismjs/components/prism-javascript';
import 'prismjs/themes/prism.css';
export default {
props: {
data: {
@@ -355,7 +241,7 @@ export default {
},
},
},
components: { vcrontab },
components: { vcrontab, PrismEditor },
data() {
return {
expression: '',
@@ -385,6 +271,7 @@ export default {
IsAutoSend: true,
CriterionTypeEnum: null,
EmailDelaySeconds: null,
CriterionTypeList: []
},
rules: {
Code: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }],
@@ -415,8 +302,8 @@ export default {
EmailHtmlContent: [
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] },
],
CriterionTypeEnum: [
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] },
CriterionTypeList: [
{ required: true, type: 'array', message: this.$t('common:ruleMessage:select'), trigger: ['blur'] },
],
},
scenarioOption: [],
@@ -440,6 +327,9 @@ export default {
}
},
methods: {
highlighter(code) {
return highlight(code, languages.js);
},
showDialog() {
this.expression = this.form.EmailCron // cron UI
this.showCron = true
@@ -563,3 +453,13 @@ export default {
},
}
</script>
<style lang="scss" scoped>
.html_temp {
display: flex;
.my-editor {
border: 1px solid #333;
}
}
</style>
@@ -4,319 +4,166 @@
<el-form :inline="true" class="base-search-form">
<!-- 是否需要回执 -->
<el-form-item :label="$t('trials:emailManageCfg:title:isReturnRequired')" v-if="!systemLevel">
<el-select
v-model="searchData.IsReturnRequired"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.YesOrNo"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-select v-model="searchData.IsReturnRequired" clearable style="width: 100px">
<el-option v-for="item of $d.YesOrNo" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<!-- 是否加急 -->
<el-form-item :label="$t('dictionary:email:label:IsUrgent')" v-if="!systemLevel">
<el-select
v-model="searchData.IsUrgent"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.YesOrNo"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-select v-model="searchData.IsUrgent" clearable style="width: 100px">
<el-option v-for="item of $d.YesOrNo" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<!-- 是否启用 -->
<el-form-item :label="$t('trials:emailManageCfg:table:IsEnable')" v-if="!systemLevel">
<el-select
v-model="searchData.IsEnable"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.YesOrNo"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-select v-model="searchData.IsEnable" clearable style="width: 100px">
<el-option v-for="item of $d.YesOrNo" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<el-form-item
:label="$t('trials:auditRecord:table:criterion')"
v-if="isDistinguishCriteria && !systemLevel"
>
<el-select
v-model="searchData.CriterionTypeEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.CriterionType"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-form-item :label="$t('trials:auditRecord:table:criterion')" v-if="isDistinguishCriteria && !systemLevel">
<el-select v-model="searchData.CriterionTypeEnum" clearable style="width: 100px">
<el-option v-for="item of $d.CriterionType" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:emailManageCfg:form:BusinessModule')">
<el-select
v-model="searchData.BusinessModuleEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.BusinessModule"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-select v-model="searchData.BusinessModuleEnum" clearable style="width: 100px">
<el-option v-for="item of $d.BusinessModule" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<el-form-item
:label="$t('trials:emailManageCfg:form:BusinessScenario')"
>
<el-select
v-model="searchData.BusinessScenarioEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.Email_BusinessScenario"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-form-item :label="$t('trials:emailManageCfg:form:BusinessScenario')">
<el-select v-model="searchData.BusinessScenarioEnum" clearable style="width: 100px">
<el-option v-for="item of $d.Email_BusinessScenario" :value="item.value" :label="item.label"
:key="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('trials:emailManageCfg:form:ToUserType')">
<el-select
v-model="searchData.ToUserType"
clearable
style="width: 100px"
>
<el-option
v-for="item of UserTypeList"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-select v-model="searchData.ToUserType" clearable style="width: 100px">
<el-option v-for="item of UserTypeList" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<el-form-item
:label="$t('trials:emailManageCfg:form:EmailUrgent')"
v-if="systemLevel === 1"
>
<el-select
v-model="searchData.EmailUrgentEnum"
clearable
style="width: 100px"
>
<el-option
v-for="item of $d.EmailUrgent"
:value="item.value"
:label="item.label"
:key="item.id"
/>
<el-form-item :label="$t('trials:emailManageCfg:form:EmailUrgent')" v-if="systemLevel === 1">
<el-select v-model="searchData.EmailUrgentEnum" clearable style="width: 100px">
<el-option v-for="item of $d.EmailUrgent" :value="item.value" :label="item.label" :key="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
</el-form>
<span style="margin-left: auto">
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
<!-- <el-button
<el-form-item>
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
<!-- <el-button
type="primary"
size="mini"
>
场景配置
</el-button> -->
<el-button type="primary" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
</span>
<el-button type="primary" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
<el-button type="primary" @click="openDrawer" :disabled="multipleSelection.length <= 0">
{{ $t('trials:emailManageCfg:button:batchAudit') }}
</el-button>
</el-form-item>
</el-form>
</div>
<!-- 受试者列表 -->
<el-table
v-loading="loading"
v-adaptive="{ bottomOffset: 45 }"
:data="list"
stripe
height="100"
style="width: 100%"
@sort-change="handleSortByColumn"
>
<el-table-column type="index" width="40" />
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" :data="list" stripe height="100" style="width: 100%"
@sort-change="handleSortByColumn" @selection-change="handleSelectionChange">
<!-- <el-table-column type="index" width="40" /> -->
<el-table-column type="selection" width="55">
</el-table-column>
<!-- Code -->
<el-table-column
prop="Code"
:label="$t('trials:emailManageCfg:title:code')"
sortable="custom"
show-overflow-tooltip
min-width="100"
/>
<el-table-column
v-if="isDistinguishCriteria"
prop="TrialReadingCriterionId"
:label="$t('trials:reviewTrack:table:criterionName')"
show-overflow-tooltip
sortable="custom"
min-width="120"
>
<el-table-column prop="Code" :label="$t('trials:emailManageCfg:title:code')" sortable="custom"
show-overflow-tooltip min-width="100" />
<el-table-column v-if="isDistinguishCriteria" prop="TrialReadingCriterionId"
:label="$t('trials:reviewTrack:table:criterionName')" show-overflow-tooltip sortable="custom" min-width="120">
<template slot-scope="scope">
{{ $fd('CriterionType', scope.row.CriterionTypeEnum) }}
{{scope.row.CriterionTypeList ? scope.row.CriterionTypeList.map(item => $fd('CriterionType', item)).join(', ')
: ''}}
</template>
</el-table-column>
<!-- 邮件主题中文 -->
<el-table-column
prop="EmailTopicCN"
:label="$t('trials:emailManageCfg:table:EmailTopicCN')"
sortable="custom"
show-overflow-tooltip
min-width="160"
/>
<el-table-column prop="EmailTopicCN" :label="$t('trials:emailManageCfg:table:EmailTopicCN')" sortable="custom"
show-overflow-tooltip min-width="160" />
<!-- 邮件主题英文 -->
<el-table-column
prop="EmailTopic"
:label="$t('trials:emailManageCfg:table:EmailTopic')"
sortable="custom"
show-overflow-tooltip
min-width="160"
/>
<el-table-column prop="EmailTopic" :label="$t('trials:emailManageCfg:table:EmailTopic')" sortable="custom"
show-overflow-tooltip min-width="160" />
<!-- 业务层级 -->
<el-table-column
prop="BusinessLevelEnum"
:label="$t('dictionary:email:label:businessLevel')"
sortable="custom"
show-overflow-tooltip
min-width="150"
>
<el-table-column prop="BusinessLevelEnum" :label="$t('dictionary:email:label:businessLevel')" sortable="custom"
show-overflow-tooltip min-width="150">
<template slot-scope="scope">
{{ $fd('BusinessLevel', scope.row.BusinessLevelEnum) }}
</template>
</el-table-column>
<!-- 业务模块 -->
<el-table-column
prop="BusinessModuleEnum"
:label="$t('dictionary:email:label:businessModule')"
sortable="custom"
show-overflow-tooltip
min-width="160"
>
<el-table-column prop="BusinessModuleEnum" :label="$t('dictionary:email:label:businessModule')" sortable="custom"
show-overflow-tooltip min-width="160">
<template slot-scope="scope">
{{ $fd('BusinessModule', scope.row.BusinessModuleEnum) }}
</template>
</el-table-column>
<!-- 业务场景 -->
<el-table-column
prop="BusinessScenarioEnum"
:label="$t('trials:emailManageCfg:table:BusinessScenarioEnum')"
sortable="custom"
show-overflow-tooltip
min-width="130"
>
<el-table-column prop="BusinessScenarioEnum" :label="$t('trials:emailManageCfg:table:BusinessScenarioEnum')"
sortable="custom" show-overflow-tooltip min-width="130">
<template slot-scope="scope">
{{ $fd('Email_BusinessScenario', scope.row.BusinessScenarioEnum) }}
</template>
</el-table-column>
<!-- 收件人v-if="systemLevel !== 1" -->
<el-table-column
prop="ToUserTypeList"
:label="$t('trials:emailManageCfg:title:toUserTypeList')"
show-overflow-tooltip
min-width="100"
>
<el-table-column prop="ToUserTypeList" :label="$t('trials:emailManageCfg:title:toUserTypeList')"
show-overflow-tooltip min-width="100">
<template slot-scope="scope">
{{
scope.row.ToUserTypeList.length > 0
? scope.row.ToUserTypeList.map((v) => $fd('UserType', v)).join(
'、'
)
'、'
)
: ''
}}
</template>
</el-table-column>
<!-- 抄送人v-if="!systemLevel" -->
<el-table-column
prop="CopyUserTypeList"
:label="$t('trials:emailManageCfg:title:copyUserTypeList')"
show-overflow-tooltip
min-width="100"
>
<el-table-column prop="CopyUserTypeList" :label="$t('trials:emailManageCfg:title:copyUserTypeList')"
show-overflow-tooltip min-width="100">
<template slot-scope="scope">
{{
scope.row.CopyUserTypeList.length > 0
? scope.row.CopyUserTypeList.map((v) => $fd('UserType', v)).join(
'、'
)
'、'
)
: ''
}}
</template>
</el-table-column>
<!-- 加急状态 -->
<el-table-column
prop="EmailUrgentEnum"
:label="$t('dictionary:email:label:IsUrgent')"
sortable="custom"
show-overflow-tooltip
min-width="110"
>
<el-table-column prop="EmailUrgentEnum" :label="$t('dictionary:email:label:IsUrgent')" sortable="custom"
show-overflow-tooltip min-width="110">
<template slot-scope="scope">
{{ $fd('EmailUrgent', scope.row.EmailUrgentEnum) }}
</template>
</el-table-column>
<!-- 发送周期和时间 -->
<el-table-column
prop="EmailCron"
:label="$t('trials:emailManageCfg:table:EmailCron')"
sortable="custom"
show-overflow-tooltip
min-width="180"
/>
<el-table-column prop="EmailCron" :label="$t('trials:emailManageCfg:table:EmailCron')" sortable="custom"
show-overflow-tooltip min-width="180" />
<!-- 附件 -->
<el-table-column
prop="FileName"
:label="$t('trials:emailManageCfg:title:fileName')"
show-overflow-tooltip
min-width="100"
v-if="!systemLevel"
>
<el-table-column prop="FileName" :label="$t('trials:emailManageCfg:title:fileName')" show-overflow-tooltip
min-width="100" v-if="!systemLevel">
<template slot-scope="scope">
<el-button
v-if="scope.row.FilePath"
type="text"
@click="handlePreview(scope.row.FilePath)"
>
<el-button v-if="scope.row.FilePath" type="text" @click="handlePreview(scope.row.FilePath)">
{{ scope.row.FileName }}
</el-button>
</template>
</el-table-column>
<!-- 是否需要回执 -->
<el-table-column
prop="IsReturnRequired"
:label="$t('trials:emailManageCfg:title:isReturnRequired')"
show-overflow-tooltip
sortable="custom"
min-width="160"
v-if="!systemLevel"
>
<el-table-column prop="IsReturnRequired" :label="$t('trials:emailManageCfg:title:isReturnRequired')"
show-overflow-tooltip sortable="custom" min-width="160" v-if="!systemLevel">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsReturnRequired" type="danger">
{{ $fd('YesOrNo', scope.row.IsReturnRequired) }}
@@ -327,14 +174,8 @@
</template>
</el-table-column>
<!-- 是否自动发送 -->
<el-table-column
prop="IsAutoSend"
:label="$t('trials:emailManageCfg:title:isAutoSend')"
show-overflow-tooltip
sortable="custom"
min-width="160"
v-if="!systemLevel"
>
<el-table-column prop="IsAutoSend" :label="$t('trials:emailManageCfg:title:isAutoSend')" show-overflow-tooltip
sortable="custom" min-width="160" v-if="!systemLevel">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsAutoSend" type="danger">
{{ $fd('YesOrNo', scope.row.IsAutoSend) }}
@@ -344,14 +185,8 @@
}}</el-tag>
</template>
</el-table-column>
<el-table-column
prop="IsEnable"
:label="$t('trials:emailManageCfg:table:IsEnable')"
show-overflow-tooltip
sortable="custom"
min-width="160"
v-if="!systemLevel"
>
<el-table-column prop="IsEnable" :label="$t('trials:emailManageCfg:table:IsEnable')" show-overflow-tooltip
sortable="custom" min-width="160" v-if="!systemLevel">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsEnable" type="danger">
{{ $fd('YesOrNo', scope.row.IsEnable) }}
@@ -362,22 +197,12 @@
</template>
</el-table-column>
<!-- 更新时间 -->
<el-table-column
prop="UpdateTime"
:label="$t('trials:emailManageCfg:title:updateTime')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column prop="UpdateTime" :label="$t('trials:emailManageCfg:title:updateTime')" show-overflow-tooltip
sortable="custom" min-width="160" />
<!-- 创建时间 -->
<el-table-column
prop="CreateTime"
:label="$t('trials:emailManageCfg:title:createTime')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column label="Action" min-width="180" fixed="right">
<el-table-column prop="CreateTime" :label="$t('trials:emailManageCfg:title:createTime')" show-overflow-tooltip
sortable="custom" min-width="160" />
<el-table-column :label="$t('common:action:action')" min-width="180" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('common:button:edit') }}
@@ -386,77 +211,38 @@
<el-button type="text" @click="handleDelete(scope.row)">
{{ $t('common:button:delete') }}
</el-button>
<el-button
type="text"
@click="
preview(scope.row.EmailHtmlContentCN, scope.row.EmailHtmlContent)
"
>{{ $t('common:button:preview') }}</el-button>
<el-button type="text" @click="
preview(scope.row.EmailHtmlContentCN, scope.row.EmailHtmlContent)
">{{ $t('common:button:preview') }}</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<!-- 搜索框 -->
<!-- 修改受试者状态 -->
<el-dialog
v-if="editVisible"
:visible.sync="editVisible"
:close-on-click-modal="false"
:title="title"
width="700px"
fullscreen
custom-class="base-dialog-wrapper"
>
<EmailForm
:data="rowData"
:system-level="systemLevel"
:isDistinguishCriteria="isDistinguishCriteria"
@closeDialog="closeDialog"
@getList="getList"
@PreviewHTML="preview"
/>
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title" width="700px"
fullscreen custom-class="base-dialog-wrapper">
<EmailForm :data="rowData" :system-level="systemLevel" :isDistinguishCriteria="isDistinguishCriteria"
@closeDialog="closeDialog" @getList="getList" @PreviewHTML="preview" />
</el-dialog>
<!-- 修改受试者状态 -->
<el-dialog
v-if="attachmentVisible"
:visible.sync="attachmentVisible"
:close-on-click-modal="false"
:title="$t('trials:emailManageCfg:title:fileName')"
width="80%"
custom-class="base-dialog-wrapper"
append-to-body
>
<AttachmentList
:business-scenario-enum="rowData.BusinessScenarioEnum"
:is-distinguish-criteria="rowData.IsDistinguishCriteria"
@getList="getList"
/>
<el-dialog v-if="attachmentVisible" :visible.sync="attachmentVisible" :close-on-click-modal="false"
:title="$t('trials:emailManageCfg:title:fileName')" width="80%" custom-class="base-dialog-wrapper" append-to-body>
<AttachmentList :business-scenario-enum="rowData.BusinessScenarioEnum"
:is-distinguish-criteria="rowData.IsDistinguishCriteria" @getList="getList" />
</el-dialog>
<!-- 预览模板 -->
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:close-on-click-modal="false"
:title="$t('common:button:preview')"
fullscreen
custom-class="base-dialog-wrapper"
>
<div
style="
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :close-on-click-modal="false"
:title="$t('common:button:preview')" fullscreen custom-class="base-dialog-wrapper">
<div style="
display: flex;
align-items: flex-start;
justify-content: space-around;
flex-wrap: wrap;
"
>
">
<div style="min-width: 50%">
<!-- 邮件内容模版CN -->
<h3>{{ $t('dictionary:email:title:title1') }}</h3>
@@ -469,12 +255,76 @@
</div>
</div>
</el-dialog>
<el-drawer :title="$t('trials:emailManageCfg:title:audit')" :visible.sync="drawer" direction="rtl" size="80%">
<!-- <div style="width: 800px">
<el-form label-width="100px" @submit.native.prevent size="small" :inline="true" class="demo-form-inline">
<el-form-item :label="$t('il8n:search:keyword')">
<el-input v-model="key" @input="keyChange" />
</el-form-item>
<el-form-item :label="$t('il8n:search:state')">
<el-select v-model="State" clearable filterable @change="handleStateChange">
<el-option v-for="item of $d.InternationalizationKeyState"
:key="'InternationalizationKeyState' + item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-form>
</div> -->
<el-table :data="tableData" v-adaptive="{ bottomOffset: 50 }" height="100" style="width: 100%"
@sort-change="handleSortByColumnDrawer">
<!-- Code -->
<el-table-column prop="Code" :label="$t('trials:emailManageCfg:title:code')" sortable="custom"
show-overflow-tooltip min-width="100" />
<el-table-column v-if="isDistinguishCriteria" prop="TrialReadingCriterionId"
:label="$t('trials:reviewTrack:table:criterionName')" show-overflow-tooltip sortable="custom" min-width="120">
<template slot-scope="scope">
{{ $fd('CriterionType', scope.row.CriterionTypeEnum) }}
</template>
</el-table-column>
<!-- 邮件主题中文 -->
<el-table-column prop="EmailTopicCN" :label="$t('trials:emailManageCfg:table:EmailTopicCN')" sortable="custom"
show-overflow-tooltip min-width="160">
<template slot-scope="scope">
<el-input v-model="scope.row.EmailTopicCN" @input="
(e) => {
$set(scope.row, 'EmailTopicCN', e)
}
" size="mini"></el-input>
</template>
</el-table-column>
<!-- 邮件主题英文 -->
<el-table-column prop="EmailTopic" :label="$t('trials:emailManageCfg:table:EmailTopic')" sortable="custom"
show-overflow-tooltip min-width="160">
<template slot-scope="scope">
<el-input v-model="scope.row.EmailTopic" @input="
(e) => {
$set(scope.row, 'EmailTopic', e)
}
" size="mini"></el-input>
</template>
</el-table-column>
<!-- 业务层级 -->
<el-table-column prop="BusinessLevelEnum" :label="$t('dictionary:email:label:businessLevel')" sortable="custom"
show-overflow-tooltip min-width="150">
<template slot-scope="scope">
{{ $fd('BusinessLevel', scope.row.BusinessLevelEnum) }}
</template>
</el-table-column>
</el-table>
<div style="text-align: right; padding-top: 10px; padding-right: 10px">
<el-button size="mini" @click="drawer = false">{{ $t('common:button:cancel') }}
</el-button>
<el-button size="mini" type="primary" @click="handleSave">{{
$t('common:button:save')
}}</el-button>
</div>
</el-drawer>
</box-content>
</template>
<script>
import {
getEmailNoticeConfigList,
deleteEmailNoticeConfig,
batchUpdateEmail
} from '@/api/dictionary'
import { GetEmailNoticeConfigList_Export } from '@/api/export'
import BoxContent from '@/components/BoxContent'
@@ -528,6 +378,9 @@ export default {
previewVisible: false,
previewHTML: null,
previewHTMLEN: null,
multipleSelection: [],
drawer: false,
tableData: []
}
},
computed: {
@@ -545,6 +398,50 @@ export default {
this.getList()
},
methods: {
async handleSave() {
try {
let arr = []
this.tableData.forEach(item => {
let obj = {
EmailTopic: item.EmailTopic,
EmailTopicCN: item.EmailTopicCN,
Id: item.Id
}
arr.push(obj)
})
this.drawer = false
let res = await batchUpdateEmail(arr)
if (res.IsSuccess) {
this.$message.success(this.$t('trials:emailManageCfg:message:auditSuccess'))
this.getList()
}
} catch (err) {
console.log(err)
}
},
//
handleSortByColumnDrawer(column) {
if (column.order === 'ascending') {
this.tableData.sort((a, b) =>
a[column.prop].localeCompare(b[column.prop])
)
} else {
this.tableData.sort((a, b) =>
b[column.prop].localeCompare(a[column.prop])
)
}
},
openDrawer() {
this.tableData = []
this.multipleSelection.forEach(item => {
let obj = Object.assign({}, item)
this.tableData.push(obj)
})
this.drawer = true
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
//
getList() {
this.loading = true
@@ -630,3 +527,8 @@ export default {
},
}
</script>
<style lang="scss" scoped>
.box-body .search .base-search-form .el-form-item {
margin-bottom: 10px;
}
</style>
+27 -63
View File
@@ -1,85 +1,41 @@
<template>
<base-model :config="config">
<div slot="dialog-body">
<el-form
ref="fileForm"
:model="form"
label-width="100px"
size="small"
:rules="rules"
>
<el-form ref="fileForm" :model="form" label-width="100px" size="small" :rules="rules">
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:file:form:name')" prop="Name">
<el-input v-model="form.Name" />
</el-form-item>
<el-form-item
:label="$t('dictionary:file:form:nameCN')"
prop="NameCN"
>
<el-form-item :label="$t('dictionary:file:form:nameCN')" prop="NameCN">
<el-input v-model="form.NameCN" />
</el-form-item>
<el-form-item
:label="$t('dictionary:browser:form:ArchiveTypeEnum')"
prop="ArchiveTypeEnum"
>
<el-select
v-model="form.ArchiveTypeEnum"
clearable
placeholder=""
style="width: 100%"
>
<el-option
v-for="item in $d.ArchiveType"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-form-item :label="$t('dictionary:browser:form:ArchiveTypeEnum')" prop="ArchiveTypeEnum">
<el-select v-model="form.ArchiveTypeEnum" clearable placeholder="" style="width: 100%">
<el-option v-for="item in $d.ArchiveType" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item
:label="$t('dictionary:browser:form:SubIdentificationEnum')"
prop="SubIdentificationEnum"
>
<el-select
style="width: 100%"
v-model="form.SubIdentificationEnum"
clearable
placeholder=""
>
<el-option
v-for="item in $d.SubIdentification"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-form-item :label="$t('dictionary:browser:form:SubIdentificationEnum')" prop="SubIdentificationEnum">
<el-select style="width: 100%" v-model="form.SubIdentificationEnum" clearable placeholder="">
<el-option v-for="item in $d.SubIdentification" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item
:label="$t('dictionary:file:form:ShowOrder')"
prop="ShowOrder"
>
<el-input-number
v-model="form.ShowOrder"
:step="1"
step-strictly
></el-input-number>
<el-form-item :label="$t('dictionary:browser:form:SysTemplateTypeEnum')" prop="SysTemplateTypeEnum">
<el-select style="width: 100%" v-model="form.SysTemplateTypeEnum" clearable placeholder="">
<el-option v-for="item in $d.SysTemplateType" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:ShowOrder')" prop="ShowOrder">
<el-input-number v-model="form.ShowOrder" :step="1" step-strictly></el-input-number>
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:IsEnable')">
<el-switch
v-model="form.IsEnable"
:active-value="true"
:inactive-value="false"
>
<el-switch v-model="form.IsEnable" :active-value="true" :inactive-value="false">
</el-switch>
</el-form-item>
<el-form-item :label="$t('dictionary:file:form:IsConfirmRecord')">
<el-switch
v-model="form.IsConfirmRecord"
:active-value="true"
:inactive-value="false"
>
<el-switch v-model="form.IsConfirmRecord" :active-value="true" :inactive-value="false">
</el-switch>
</el-form-item>
</div>
@@ -95,7 +51,7 @@
</div>
</base-model>
</template>
<script>
<script>
import baseModel from '@/components/BaseModel'
import { addOrUpdateSysFileType } from '@/api/dictionary'
export default {
@@ -126,6 +82,7 @@ export default {
NameCN: null,
SubIdentificationEnum: null,
ShowOrder: 0,
SysTemplateTypeEnum: null
},
rules: {
Name: [
@@ -149,6 +106,13 @@ export default {
trigger: ['blur', 'change'],
},
],
SysTemplateTypeEnum: [
{
required: true,
message: this.$t('common:ruleMessage:select'),
trigger: ['blur', 'change'],
},
],
ArchiveTypeEnum: [
{
required: true,
+52 -149
View File
@@ -11,85 +11,41 @@
<el-input v-model="searchData.NameCN" style="width: 100px" />
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:archiveTypeEnum')">
<el-select
v-model="searchData.ArchiveTypeEnum"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.ArchiveType"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-select v-model="searchData.ArchiveTypeEnum" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.ArchiveType" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item
:label="$t('dictionary:file:search:subIdentificationEnum')"
>
<el-select
v-model="searchData.SubIdentificationEnum"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.SubIdentification"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-form-item :label="$t('dictionary:file:search:subIdentificationEnum')">
<el-select v-model="searchData.SubIdentificationEnum" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.SubIdentification" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:SysTemplateTypeEnum')">
<el-select v-model="searchData.SysTemplateTypeEnum" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.SysTemplateType" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:isEnable')">
<el-select
v-model="searchData.IsEnable"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.YesOrNo"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-select v-model="searchData.IsEnable" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:file:search:isConfirmRecord')">
<el-select
v-model="searchData.IsConfirmRecord"
clearable
placeholder=""
style="width: 100px"
>
<el-option
v-for="item in $d.YesOrNo"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-select v-model="searchData.IsConfirmRecord" clearable placeholder="" style="width: 100px">
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
@click="handleSearch"
>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
@@ -101,106 +57,60 @@
</span>
</div>
<el-table
v-loading="loading"
v-adaptive="{ bottomOffset: 45 }"
:data="list"
stripe
height="100"
style="width: 100%"
@sort-change="handleSortByColumn"
>
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" :data="list" stripe height="100"
style="width: 100%" @sort-change="handleSortByColumn">
<el-table-column type="index" width="40" />
<el-table-column
prop="Name"
:label="$t('dictionary:file:table:Name')"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column
prop="NameCN"
:label="$t('dictionary:file:table:NameCN')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="ArchiveTypeEnum"
:label="$t('dictionary:file:table:archiveTypeEnum')"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="Name" :label="$t('dictionary:file:table:Name')" sortable="custom" show-overflow-tooltip
min-width="150px" />
<el-table-column prop="NameCN" :label="$t('dictionary:file:table:NameCN')" show-overflow-tooltip
sortable="custom" min-width="150px" />
<el-table-column prop="ArchiveTypeEnum" :label="$t('dictionary:file:table:archiveTypeEnum')"
show-overflow-tooltip sortable="custom" min-width="120px">
<template slot-scope="scope">
{{ $fd('ArchiveType', scope.row.ArchiveTypeEnum) }}
</template>
</el-table-column>
<el-table-column
prop="SubIdentificationEnum"
:label="$t('dictionary:file:table:subIdentificationEnum')"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="SubIdentificationEnum" :label="$t('dictionary:file:table:subIdentificationEnum')"
show-overflow-tooltip sortable="custom" min-width="120px">
<template slot-scope="scope">
{{ $fd('SubIdentification', scope.row.SubIdentificationEnum) }}
</template>
</el-table-column>
<el-table-column
prop="ShowOrder"
:label="$t('dictionary:file:table:ShowOrder')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
:label="$t('dictionary:file:table:IsEnable')"
prop="IsEnable"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="SysTemplateTypeEnum" :label="$t('dictionary:file:table:SysTemplateTypeEnum')"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
{{ $fd('SysTemplateType', scope.row.SysTemplateTypeEnum) }}
</template>
</el-table-column>
<el-table-column prop="ShowOrder" :label="$t('dictionary:file:table:ShowOrder')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('dictionary:file:table:IsEnable')" prop="IsEnable" show-overflow-tooltip
sortable="custom" min-width="120px">
<template slot-scope="scope">
<el-tag :type="!scope.row.IsEnable ? 'info' : ''">
{{ $fd('YesOrNo', scope.row.IsEnable) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
:label="$t('dictionary:file:table:isConfirmRecord')"
prop="IsConfirmRecord"
show-overflow-tooltip
sortable="custom"
width="200"
>
<el-table-column :label="$t('dictionary:file:table:isConfirmRecord')" prop="IsConfirmRecord"
show-overflow-tooltip sortable="custom" min-width="150px">
<template slot-scope="scope">
<el-tag :type="!scope.row.IsEnable ? 'info' : ''">
{{ $fd('YesOrNo', scope.row.IsConfirmRecord) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="CreateTime"
:label="$t('dictionary:file:table:createTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="UpdateTime"
:label="$t('dictionary:file:table:updateTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
:label="$t('dictionary:file:table:action')"
width="200"
fixed="right"
>
<el-table-column prop="CreateTime" :label="$t('dictionary:file:table:createTime')" show-overflow-tooltip
sortable="custom" min-width="180px" />
<el-table-column prop="UpdateTime" :label="$t('dictionary:file:table:updateTime')" show-overflow-tooltip
sortable="custom" min-width="180px" />
<el-table-column :label="$t('dictionary:file:table:action')" width="200" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('dictionary:file:button:edit') }}
</el-button>
<el-button
type="text"
@click="handleDelete(scope.row)"
v-if="hasPermi(['dictionary:template:file:del'])"
>
<el-button type="text" @click="handleDelete(scope.row)" v-if="hasPermi(['dictionary:template:file:del'])">
{{ $t('dictionary:file:button:delete') }}
</el-button>
</template>
@@ -208,20 +118,9 @@
</el-table>
<!-- 分页组件 -->
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<File-form
:config="config"
:data="rowData"
v-if="config.visible"
@close="close"
@getList="getList"
/>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<File-form :config="config" :data="rowData" v-if="config.visible" @close="close" @getList="getList" />
</box-content>
</BoxContent>
</template>
@@ -238,6 +137,7 @@ const searchDataDefault = () => {
Name: null,
NameCN: null,
SubIdentificationEnum: null,
SysTemplateTypeEnum: null,
PageIndex: 1,
PageSize: 20,
asc: false,
@@ -344,4 +244,7 @@ export default {
}
</script>
<style lang="scss" scoped>
.box-body .search .base-search-form .el-form-item {
margin-bottom: 10px;
}
</style>
+24 -67
View File
@@ -9,71 +9,36 @@
<!-- Reset Password -->
<div class="box-wrapper" v-if="active === 0">
<el-form
ref="resetForm"
v-loading="formLoading"
:model="form"
label-width="130px"
:rules="rules"
class="demo-ruleForm"
size="small"
>
<el-form ref="resetForm" v-loading="formLoading" :model="form" label-width="130px" :rules="rules"
class="demo-ruleForm" size="small">
<!-- 邮箱 -->
<el-form-item
:label="$t('passwordReset:form:email')"
prop="EmailOrPhone"
>
<el-form-item :label="$t('passwordReset:form:email')" prop="EmailOrPhone">
<el-col :span="18">
<el-input
v-model="form.EmailOrPhone"
autocomplete="off"
@change="handleEmailChange"
/>
<el-input v-model="form.EmailOrPhone" autocomplete="off" @change="handleEmailChange" />
</el-col>
</el-form-item>
<!-- 验证码 -->
<el-form-item
:label="$t('trials:researchForm:form:verifyCode')"
required
>
<el-form-item :label="$t('trials:researchForm:form:verifyCode')" required>
<el-col :span="18">
<el-form-item prop="VerificationCode">
<el-input v-model="form.VerificationCode" autocomplete="off" />
</el-form-item>
</el-col>
<el-col :span="6" style="text-align: right">
<el-button
size="small"
type="primary"
style="width: 80%"
:disabled="sendDisabled"
@click="handleSendCode"
>{{ sendTitle }}</el-button
>
<el-button size="small" type="primary" style="width: 80%" :disabled="sendDisabled"
@click="handleSendCode">{{ sendTitle }}</el-button>
</el-col>
</el-form-item>
</el-form>
<!-- 校验 -->
<el-button
size="small"
type="primary"
style="width: 50%; margin: auto; display: block"
:disabled="form.VerificationCode === '' || form.EmailOrPhone === ''"
@click="verifyCode"
>
<el-button size="small" type="primary" style="width: 50%; margin: auto; display: block"
:disabled="form.VerificationCode === '' || form.EmailOrPhone === ''" @click="verifyCode">
{{ $t('passwordReset:button:verify') }}
</el-button>
</div>
<div class="box-wrapper" v-show="active === 1">
<el-form
ref="resetForm2"
v-loading="formLoading"
:model="form"
:label-width="$i18n.locale === 'en' ? '180px' : '100px'"
:rules="rules2"
class="demo-ruleForm"
size="small"
>
<el-form ref="resetForm2" v-loading="formLoading" :model="form"
:label-width="$i18n.locale === 'en' ? '180px' : '100px'" :rules="rules2" class="demo-ruleForm" size="small">
<!-- 用户名 -->
<el-form-item :label="$t('passwordReset:form:userName')" prop="UserId">
<el-input v-model="form.UserName" disabled />
@@ -105,27 +70,17 @@
<el-input v-model="form.UserType" disabled />
</el-form-item> -->
<!-- 新密码 -->
<el-form-item
class="my_new_pwd"
:label="$t('passwordReset:form:password')"
prop="NewPwd"
style="position: relative"
>
<el-form-item class="my_new_pwd" :label="$t('passwordReset:form:password')" prop="NewPwd"
style="position: relative">
<el-input v-model="form.NewPwd" show-password autocomplete="off" />
<span style="position: absolute; right: -30px">
<el-tooltip
:content="$t('passwordReset:form:passwordCentent')"
placement="top"
>
<el-tooltip :content="$t('passwordReset:form:passwordCentent')" placement="top">
<i class="el-icon-question" />
</el-tooltip>
</span>
</el-form-item>
<!-- 确认密码 -->
<el-form-item
:label="$t('passwordReset:form:confirmPassword')"
prop="CheckPass"
>
<el-form-item :label="$t('passwordReset:form:confirmPassword')" prop="CheckPass">
<el-input v-model="form.CheckPass" show-password autocomplete="off" />
</el-form-item>
</el-form>
@@ -135,12 +90,7 @@
{{ $t('passwordReset:button:cancel') }}
</el-button>
<!-- 提交 -->
<el-button
size="small"
type="primary"
@click="onSubmit"
style="width: 46%"
>
<el-button size="small" type="primary" @click="onSubmit" style="width: 46%">
{{ $t('passwordReset:button:submit') }}
</el-button>
</div>
@@ -388,10 +338,14 @@ export default {
}
},
onCancel() {
this.$refs['resetForm'].resetFields()
// this.$refs['resetForm'].resetFields()
Object.keys(this.form).forEach((key) => {
this.form[key] = ''
})
this.sendDisabled = false
this.sendTitle = this.$t('passwordReset:button:send')
countdown = 60
clearTimeout(timer)
this.active = 0
},
goBack() {
@@ -404,12 +358,14 @@ export default {
.reset-wrapper {
padding: 20px;
}
.reset-wrapper .el-page-header {
line-height: 50px;
border: 1px solid #ebeef5;
border-radius: 4px;
background-color: #fff;
}
.reset-wrapper .box-wrapper {
width: 700px;
margin: 20px auto;
@@ -425,6 +381,7 @@ export default {
.is-error.my_new_pwd {
margin-bottom: 45px;
}
.flexBox {
display: flex;
justify-content: center;
+82 -159
View File
@@ -2,152 +2,76 @@
<div class="log">
<div ref="leftContainer" class="left">
<el-form :inline="true">
<el-form-item
:label="$t('system:loginLog:label:OptType')"
prop="OptType"
>
<el-select
v-model="searchData.OptType"
clearable
style="width: 120px"
>
<el-option
v-for="item of $d.UserOptType"
:key="'UserOptType' + item.label"
:value="item.value"
:label="item.label"
/>
<el-form-item :label="$t('system:loginLog:label:OptType')" prop="OptType">
<el-select v-model="searchData.OptTypeList" clearable style="width: 200px" multiple :collapse-tags="true">
<el-option v-for="item of $d.UserOptType" :key="'UserOptType' + item.label" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item>
<el-form-item label="IP" prop="IP">
<el-input
v-model="searchData.IP"
size="small"
clearable
style="width: 120px"
/>
<el-input v-model="searchData.IP" size="small" clearable style="width: 120px" />
</el-form-item>
<el-form-item
:label="$t('system:loginLog:label:LoginFaildName')"
prop="LoginFaildName"
>
<el-input
v-model="searchData.LoginFaildName"
size="small"
clearable
style="width: 120px"
/>
<el-form-item :label="$t('system:loginLog:label:LoginFaildName')" prop="LoginFaildName">
<el-input v-model="searchData.LoginFaildName" size="small" clearable style="width: 120px" />
</el-form-item>
<el-form-item
:label="$t('system:loginLog:table:LoginUserName')"
prop="LoginFaildName"
>
<el-input
v-model="searchData.LoginUserName"
size="small"
clearable
style="width: 120px"
/>
<el-form-item :label="$t('system:loginLog:table:LoginUserName')" prop="LoginFaildName">
<el-input v-model="searchData.LoginUserName" size="small" clearable style="width: 120px" />
</el-form-item>
<el-form-item
:label="$t('system:loginLog:table:LoginUserType')"
prop="LoginUserTypeEnum"
>
<el-select
v-model="searchData.LoginUserTypeEnum"
clearable
style="width: 120px"
>
<el-option
v-for="item of $d.UserType"
:key="'UserType' + item.label"
:value="item.value"
:label="item.label"
/>
<!-- <el-form-item :label="$t('system:loginLog:table:LoginUserType')" prop="LoginUserTypeEnum">
<el-select v-model="searchData.LoginUserTypeEnum" clearable style="width: 120px">
<el-option v-for="item of $d.UserType" :key="'UserType' + item.label" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item> -->
<el-form-item :label="$t('system:loginLog:label:IsLoginUncommonly')" prop="IsLoginUncommonly ">
<el-select v-model="searchData.IsLoginUncommonly" clearable style="width: 120px">
<el-option v-for="item of $d.YesOrNo" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</el-form-item>
<el-form-item :label="$t('system:loginLog:label:CreateTime')">
<el-date-picker
v-model="datetimerange"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
@change="handleDatetimeChange"
style="width: 380px"
/>
<el-date-picker v-model="datetimerange" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" @change="handleDatetimeChange" style="width: 380px" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="getList">
{{ $t('common:button:search') }}
</el-button>
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
v-adaptive="{ bottomOffset: 45 }"
height="100"
:data="list"
class="table"
@sort-change="handleSortByColumn"
>
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" height="100" :data="list" class="table"
@sort-change="handleSortByColumn">
<el-table-column type="index" width="50">
<template slot-scope="scope">
<span
style="
<span style="
display: flex;
align-items: center;
justify-content: flex-end;
"
>
<el-tooltip
class="item"
effect="dark"
:content="$t('system:loginLog:label:IsLoginUncommonly')"
placement="top"
style="margin-right: 3px"
v-if="scope.row.IsLoginUncommonly"
>
<i
v-if="scope.row.IsLoginUncommonly"
class="el-icon-warning icon-i"
></i>
">
<el-tooltip class="item" effect="dark" :content="$t('system:loginLog:label:IsLoginUncommonly')"
placement="top" style="margin-right: 3px" v-if="scope.row.IsIgnoreUncommonly">
<i v-if="scope.row.IsLoginUncommonly" class="el-icon-warning icon-i icon-success"></i>
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="$t('system:loginLog:label:IsLoginUncommonly')"
placement="top" style="margin-right: 3px" v-else-if="scope.row.IsLoginUncommonly">
<i v-if="scope.row.IsLoginUncommonly" class="el-icon-warning icon-i"
@click.stop="setIsIgnoreUncommonly(scope.row)"></i>
</el-tooltip>
<span>{{ scope.$index + 1 }}</span>
</span>
</template>
</el-table-column>
<el-table-column
:label="$t('system:loginLog:table:OptType')"
prop="OptType"
min-width="150"
show-overflow-tooltip
sortable="custom"
>
<el-table-column :label="$t('system:loginLog:table:OptType')" prop="OptType" min-width="150"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
{{ $fd('UserOptType', scope.row.OptType) }}
</template>
</el-table-column>
<el-table-column
label="IP"
prop="IP"
min-width="150"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column
:label="$t('trials:loginLog:table:IPRegion')"
prop="IPRegion"
min-width="120"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column label="IP" prop="IP" min-width="150" sortable="custom" show-overflow-tooltip />
<el-table-column :label="$t('trials:loginLog:table:IPRegion')" prop="IPRegion" min-width="120"
show-overflow-tooltip sortable="custom" />
<!-- <el-table-column
:label="$t('system:loginLog:table:LoginFaildName')"
prop="LoginFaildName"
@@ -155,20 +79,10 @@
show-overflow-tooltip
sortable="custom"
/> -->
<el-table-column
:label="$t('system:loginLog:table:LoginUserName')"
prop="ActionUserName"
min-width="140"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
:label="$t('system:loginLog:table:Aetionlserlype')"
prop="ActionUserType"
min-width="100"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column :label="$t('system:loginLog:table:LoginUserName')" prop="ActionUserName" min-width="140"
show-overflow-tooltip sortable="custom" />
<el-table-column :label="$t('system:loginLog:table:Aetionlserlype')" prop="ActionUserType" min-width="100"
show-overflow-tooltip sortable="custom" />
<!-- <el-table-column
:label="$t('system:loginLog:table:LoginUserType')"
prop="LoginUserTypeEnum"
@@ -180,13 +94,8 @@
{{ $fd("UserType", scope.row.LoginUserTypeEnum) }}
</template>
</el-table-column> -->
<el-table-column
:label="$t('system:loginLog:table:OptUserName')"
prop="TargetIdentityUserName"
min-width="200"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column :label="$t('system:loginLog:table:OptUserName')" prop="TargetIdentityUserName" min-width="200"
sortable="custom" show-overflow-tooltip />
<!-- <el-table-column
:label="$t('system:loginLog:table:OptUserType')"
prop="OptUserTypeEnum"
@@ -198,51 +107,36 @@
{{ $fd("UserType", scope.row.OptUserTypeEnum) }}
</template>
</el-table-column> -->
<el-table-column
:label="$t('system:loginLog:table:detail')"
min-width="120"
show-overflow-tooltip
>
<el-table-column :label="$t('system:loginLog:table:detail')" min-width="120" show-overflow-tooltip>
<template slot-scope="scope">
<el-button
v-if="scope.row.JsonObj"
type="text"
@click="handleOpenDialog(scope.row)"
>
<el-button v-if="scope.row.JsonObj" type="text" @click="handleOpenDialog(scope.row)">
<span>{{ $t('system:loginLog:message:detail') }}</span>
</el-button>
</template>
</el-table-column>
<el-table-column
:label="$t('system:loginLog:table:CreateTime')"
prop="CreateTime"
min-width="180"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column :label="$t('system:loginLog:table:CreateTime')" prop="CreateTime" min-width="180"
sortable="custom" show-overflow-tooltip />
</el-table>
<div class="pagination" style="text-align: right; margin-top: 5px">
<pagination
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<pagination :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
</div>
</div>
<detail :config="config" :JsonObj="JsonObj" />
</div>
</template>
<script>
import { getUserLogList } from '@/api/user'
import { getUserLogList, setIsIgnoreUncommonly } from '@/api/user'
import Pagination from '@/components/Pagination'
import detail from './detail.vue'
import moment from 'moment'
const searchDataDefault = () => {
return {
OptType: null,
OptTypeList: [],
Ip: '',
LoginFaildName: '',
IsLoginUncommonly: null,
LoginUserName: '',
LoginUserTypeEnum: null,
BeginDate: '',
@@ -276,6 +170,26 @@ export default {
this.getList()
},
methods: {
//
async setIsIgnoreUncommonly(row) {
try {
let confirm = await this.$confirm(this.$t("system:loginLog:confirmMessage:setIsIgnoreUncommonly"))
if (!confirm) return false
let data = {
IsIgnoreUncommonly: true,
Id: row.Id
}
this.loading = true
let res = await setIsIgnoreUncommonly(data)
this.loading = false
if (res.IsSuccess) {
this.getList()
}
} catch (err) {
this.loading = false
console.log(err)
}
},
handleOpenDialog(row) {
if (!row.JsonObj)
return this.$message.warning(this.$t('system:loginLog:message:noJSON'))
@@ -334,28 +248,37 @@ export default {
display: flex;
padding: 10px;
border-radius: 5px;
.left {
display: flex;
flex-direction: column;
width: 0;
flex-grow: 4;
// border-right: 1px solid #ccc;
.filter-container {
display: flex;
align-items: center;
margin: 5px;
}
.data-table {
flex: 1;
padding: 5px 0px;
}
.pagination-container {
text-align: right;
}
}
.icon-i {
color: #f56c6c;
cursor: pointer;
}
.icon-success {
color: #67C23A
}
}
</style>
+181 -559
View File
@@ -9,64 +9,28 @@
</el-form-item>
<!-- 研究方案号 -->
<el-form-item :label="$t('trials:trials-list:table:researchNumber')">
<el-input
v-model="searchData.ResearchProgramNo"
style="width: 100px"
clearable
/>
<el-input v-model="searchData.ResearchProgramNo" style="width: 100px" clearable />
</el-form-item>
<!-- 试验名称 -->
<el-form-item :label="$t('trials:trials-list:table:experimentName')">
<el-input
v-model="searchData.ExperimentName"
style="width: 100px"
clearable
/>
<el-input v-model="searchData.ExperimentName" style="width: 100px" clearable />
</el-form-item>
<!-- Sponsor -->
<el-form-item :label="$t('trials:trials-list:table:sponsor')">
<el-select
v-model="searchData.SponsorId"
style="width: 150px"
clearable
>
<el-option
v-for="item in sponsorList"
:key="item.Id"
:label="item.SponsorName"
:value="item.Id"
/>
<el-select v-model="searchData.SponsorId" style="width: 150px" clearable>
<el-option v-for="item in sponsorList" :key="item.Id" :label="item.SponsorName" :value="item.Id" />
</el-select>
</el-form-item>
<!-- 阅片标准 -->
<el-form-item
v-if="hasPermi(['role:ir'])"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
>
<el-select
v-model="searchData.CriterionType"
style="width: 150px"
clearable
>
<el-option
v-for="item in $d.CriterionType"
:key="item.id"
:label="item.label"
:value="item.value"
/>
<el-form-item v-if="hasPermi(['role:ir'])" :label="$t('trials:trials-list:table:IR_ReadingCriterionList')">
<el-select v-model="searchData.CriterionType" style="width: 150px" clearable>
<el-option v-for="item in $d.CriterionType" :key="item.id" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<!-- 联系人 -->
<el-form-item
v-if="hasPermi(['role:ir'])"
:label="$t('trials:trials-list:table:IR_PMEmailList')"
>
<el-input
v-model="searchData.PM_EMail"
style="width: 100px"
clearable
/>
<el-form-item v-if="hasPermi(['role:ir'])" :label="$t('trials:trials-list:table:IR_PMEmailList')">
<el-input v-model="searchData.PM_EMail" style="width: 100px" clearable />
</el-form-item>
<el-form-item>
<!-- <el-button type="text" @click="isShow = !isShow">More</el-button> -->
@@ -75,33 +39,19 @@
{{ $t('common:button:search') }}
</el-button>
<!-- Reset -->
<el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
<!-- Export -->
<el-button
v-hasPermi="['trials:trials-list:export']"
type="primary"
icon="el-icon-download"
:loading="exportLoading"
@click="handleExportTrial"
>
<el-button v-hasPermi="['trials:trials-list:export']" type="primary" icon="el-icon-download"
:loading="exportLoading" @click="handleExportTrial">
{{ $t('common:button:export') }}
</el-button>
</el-form-item>
</el-form>
<span style="margin-left: auto">
<!-- New -->
<el-button
v-hasPermi="['trials:trials-list:new']"
icon="el-icon-plus"
type="primary"
@click="handleNew"
>
<el-button v-hasPermi="['trials:trials-list:new']" icon="el-icon-plus" type="primary" @click="handleNew">
{{ $t('common:button:new') }}
</el-button>
</span>
@@ -112,190 +62,88 @@
<div style="padding: 10px">
<el-form label-width="140px">
<el-form-item label="Trial ID">
<el-input
v-model="searchData.Code"
placeholder="Trial ID"
style="width: 100%"
clearable
/>
<el-input v-model="searchData.Code" placeholder="Trial ID" style="width: 100%" clearable />
</el-form-item>
<el-form-item label="Indication">
<el-input
v-model="searchData.Indication"
placeholder="Indication"
style="width: 100%"
clearable
/>
<el-input v-model="searchData.Indication" placeholder="Indication" style="width: 100%" clearable />
</el-form-item>
<el-form-item label="Assessment Criteria">
<el-select
v-model="searchData.CriterionIds"
placeholder="Assessment Criteria"
style="width: 100%"
clearable
multiple
>
<el-select v-model="searchData.CriterionIds" placeholder="Assessment Criteria" style="width: 100%" clearable
multiple>
<!-- <el-option
v-for="(key,value) of dictionaryList.ReadingStandard"
:key="key"
:label="key"
:value="value"
/> -->
<el-option
v-for="item of dict.type.ReadingStandard"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item of dict.type.ReadingStandard" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="Sponsor">
<el-select
v-model="searchData.SponsorId"
placeholder="Sponsor"
style="width: 100%"
clearable
>
<el-option
v-for="item in sponsorList"
:key="item.Id"
:label="item.SponsorName"
:value="item.Id"
/>
<el-select v-model="searchData.SponsorId" placeholder="Sponsor" style="width: 100%" clearable>
<el-option v-for="item in sponsorList" :key="item.Id" :label="item.SponsorName" :value="item.Id" />
</el-select>
</el-form-item>
<el-form-item label="CRO">
<el-select
v-model="searchData.CROId"
placeholder="CRO"
style="width: 100%"
clearable
>
<el-option
v-for="item of croList"
:key="item.Id"
:label="item.CROName"
:value="item.Id"
/>
<el-select v-model="searchData.CROId" placeholder="CRO" style="width: 100%" clearable>
<el-option v-for="item of croList" :key="item.Id" :label="item.CROName" :value="item.Id" />
</el-select>
</el-form-item>
<el-form-item label="Phase">
<el-select
v-model="searchData.Phase"
placeholder="Phase"
style="width: 100%"
clearable
>
<el-option
v-for="item in phaseOptions"
:key="item.value"
:label="item.value"
:value="item.value"
/>
<el-select v-model="searchData.Phase" placeholder="Phase" style="width: 100%" clearable>
<el-option v-for="item in phaseOptions" :key="item.value" :label="item.value" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="ReviewType">
<el-select
v-model="searchData.ReviewTypeIds"
placeholder="ReviewType"
style="width: 100%"
clearable
multiple
>
<el-select v-model="searchData.ReviewTypeIds" placeholder="ReviewType" style="width: 100%" clearable
multiple>
<!-- <el-option
v-for="(key,value) of dictionaryList.ReviewType"
:key="key"
:label="key"
:value="value"
/> -->
<el-option
v-for="item of dict.type.ReviewType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item of dict.type.ReviewType" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="Modality">
<el-select
v-model="searchData.ModalityIds"
multiple
placeholder="Modality"
style="width: 100%"
clearable
>
<el-select v-model="searchData.ModalityIds" multiple placeholder="Modality" style="width: 100%" clearable>
<!-- <el-option
v-for="(key,value) of dictionaryList.ReadingType"
:key="key"
:label="key"
:value="value"
/> -->
<el-option
v-for="item of dict.type.ReadingType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item of dict.type.ReadingType" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="Expedited: ">
<el-select
v-model="searchData.Expedited"
value-key="value"
clearable
style="width: 100%"
>
<el-option
v-for="item in expeditedOption"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select v-model="searchData.Expedited" value-key="value" clearable style="width: 100%">
<el-option v-for="item in expeditedOption" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="BeginDate: ">
<el-date-picker
v-model="searchData.BeginDate"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
type="date"
:picker-options="beginPickerOption"
:clearable="false"
style="width: 100%"
/>
<el-date-picker v-model="searchData.BeginDate" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date"
:picker-options="beginPickerOption" :clearable="false" style="width: 100%" />
</el-form-item>
<el-form-item label="EndDate: ">
<el-date-picker
v-model="searchData.EndDate"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
type="date"
:picker-options="endpickerOption"
:clearable="false"
style="width: 100%"
/>
<el-date-picker v-model="searchData.EndDate" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date"
:picker-options="endpickerOption" :clearable="false" style="width: 100%" />
</el-form-item>
<el-form-item label="Attended Reviewer Type:">
<el-select
v-model="searchData.AttendedReviewerType"
placeholder="Attended Reviewer Type"
style="width: 100%"
clearable
>
<el-option
v-for="item of $d.AttendedReviewerType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select v-model="searchData.AttendedReviewerType" placeholder="Attended Reviewer Type"
style="width: 100%" clearable>
<el-option v-for="item of $d.AttendedReviewerType" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSelectSearch"
>Search</el-button
>
<el-button type="primary" @click="handleSelectSearch">Search</el-button>
<el-button type="primary" @click="handleReset">Reset</el-button>
<el-button type="primary" @click="isShow = false">Back</el-button>
</el-form-item>
@@ -305,219 +153,89 @@
<!-- 项目列表 -->
<template slot="main-container">
<el-table
v-adaptive="{ bottomOffset: 60 }"
v-loading="listLoading"
:data="list"
stripe
height="100"
@selection-change="handleSelectChange"
@sort-change="handleSortChange"
@row-click="rowClick"
>
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="listLoading" :data="list" stripe height="100"
@selection-change="handleSelectChange" @sort-change="handleSortChange" @row-click="rowClick">
<el-table-column type="selection" align="left" width="45" />
<el-table-column type="index" width="40" align="left" />
<el-table-column
prop="TrialCode"
:label="$t('trials:trials-list:table:trialId')"
show-overflow-tooltip
sortable="custom"
width="120"
/>
<el-table-column
prop="ResearchProgramNo"
:label="$t('trials:trials-list:table:researchNumber')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column prop="TrialCode" :label="$t('trials:trials-list:table:trialId')" show-overflow-tooltip
sortable="custom" width="120" />
<el-table-column prop="ResearchProgramNo" :label="$t('trials:trials-list:table:researchNumber')"
show-overflow-tooltip sortable="custom" min-width="160" />
<el-table-column
prop="ExperimentName"
:label="$t('trials:trials-list:table:experimentName')"
show-overflow-tooltip
sortable="custom"
min-width="240"
/>
<el-table-column
prop="Sponsor"
:label="$t('trials:trials-list:table:sponsor')"
show-overflow-tooltip
sortable="custom"
min-width="120"
/>
<el-table-column
prop="TrialStatusStr"
:label="$t('trials:trials-list:table:status')"
show-overflow-tooltip
sortable="custom"
min-width="120"
>
<el-table-column prop="ExperimentName" :label="$t('trials:trials-list:table:experimentName')"
show-overflow-tooltip sortable="custom" min-width="240" />
<el-table-column prop="Sponsor" :label="$t('trials:trials-list:table:sponsor')" show-overflow-tooltip
sortable="custom" min-width="120" />
<el-table-column prop="TrialStatusStr" :label="$t('trials:trials-list:table:status')" show-overflow-tooltip
sortable="custom" min-width="120">
<template slot-scope="scope">
<el-tag
v-if="scope.row.TrialStatusStr === 'Initializing'"
type="info"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag
v-if="scope.row.TrialStatusStr === 'Ongoing'"
type="primary"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag
v-if="scope.row.TrialStatusStr === 'Completed'"
type="warning"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag
v-if="scope.row.TrialStatusStr === 'Stopped'"
type="danger"
>{{ $fd('TrialStatusEnum', scope.row.TrialStatusStr) }}</el-tag
>
<el-tag v-if="scope.row.TrialStatusStr === 'Initializing'" type="info">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag v-if="scope.row.TrialStatusStr === 'Ongoing'" type="primary">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag v-if="scope.row.TrialStatusStr === 'Completed'" type="warning">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
<el-tag v-if="scope.row.TrialStatusStr === 'Stopped'" type="danger">{{ $fd('TrialStatusEnum',
scope.row.TrialStatusStr) }}</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="ExpetiedTaskCount"
:label="$t('trials:trials-list:table:ExpetiedTaskCount')"
show-overflow-tooltip
sortable="custom"
min-width="120"
/>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="ReReadingApprovalCount"
:label="$t('trials:trials-list:table:ReReadingApprovalCount')"
show-overflow-tooltip
sortable="custom"
min-width="180"
/>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="PendingReconciliationCount"
:label="$t('trials:trials-list:table:PendingReconciliationCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:pm', 'role:apm'])"
prop="PendingResponseCount"
:label="$t('trials:trials-list:table:PendingResponseCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:crc', 'role:cra'])"
prop="CRC_UrgentCount"
:label="$t('trials:trials-list:table:CRC_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:crc', 'role:cra'])"
prop="CRC_QCQuestionCount"
:label="$t('trials:trials-list:table:CRC_QCQuestionCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:crc', 'role:cra'])"
prop="CRC_CheckQuestionCount"
:label="$t('trials:trials-list:table:CRC_CheckQuestionCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_ReadingCriterionList"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
show-overflow-tooltip
min-width="160"
>
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="ExpetiedTaskCount"
:label="$t('trials:trials-list:table:ExpetiedTaskCount')" show-overflow-tooltip sortable="custom"
min-width="120" />
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="ReReadingApprovalCount"
:label="$t('trials:trials-list:table:ReReadingApprovalCount')" show-overflow-tooltip sortable="custom"
min-width="180" />
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="PendingReconciliationCount"
:label="$t('trials:trials-list:table:PendingReconciliationCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:pm', 'role:apm'])" prop="PendingResponseCount"
:label="$t('trials:trials-list:table:PendingResponseCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:crc', 'role:cra'])" prop="CRC_UrgentCount"
:label="$t('trials:trials-list:table:CRC_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:crc', 'role:cra'])" prop="CRC_QCQuestionCount"
:label="$t('trials:trials-list:table:CRC_QCQuestionCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:crc', 'role:cra'])" prop="CRC_CheckQuestionCount"
:label="$t('trials:trials-list:table:CRC_CheckQuestionCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_ReadingCriterionList"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')" show-overflow-tooltip min-width="160">
<template slot-scope="scope">
{{ scope.row.IR_ReadingCriterionList.join(', ') }}
</template>
</el-table-column>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_UrgentCount"
:label="$t('trials:trials-list:table:IR_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_UnReadCount"
:label="$t('trials:trials-list:table:IR_UnReadCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_TotalReadCount"
:label="$t('trials:trials-list:table:IR_TotalReadCount')"
show-overflow-tooltip
sortable="custom"
min-width="170"
/>
<el-table-column
v-if="hasPermi(['role:ir'])"
prop="IR_PMEmailList"
:label="$t('trials:trials-list:table:IR_PMEmailList')"
show-overflow-tooltip
min-width="170"
>
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_UrgentCount"
:label="$t('trials:trials-list:table:IR_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_UnReadCount"
:label="$t('trials:trials-list:table:IR_UnReadCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_TotalReadCount"
:label="$t('trials:trials-list:table:IR_TotalReadCount')" show-overflow-tooltip sortable="custom"
min-width="170" />
<el-table-column v-if="hasPermi(['role:ir'])" prop="IR_PMEmailList"
:label="$t('trials:trials-list:table:IR_PMEmailList')" show-overflow-tooltip min-width="170">
<template slot-scope="scope">
{{ scope.row.IR_PMEmailList.join(', ') }}
</template>
</el-table-column>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_UrgentCount"
:label="$t('trials:trials-list:table:IQC_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_ToBeClaimedCount"
:label="$t('trials:trials-list:table:IQC_ToBeClaimedCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_AuditToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_AuditToBeDealedCount')"
show-overflow-tooltip
sortable="custom"
min-width="140"
/>
<el-table-column
v-if="hasPermi(['role:iqc'])"
prop="IQC_QuestionToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_QuestionToBeDealedCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_UrgentCount"
:label="$t('trials:trials-list:table:MIM_UrgentCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_UrgentCount"
:label="$t('trials:trials-list:table:IQC_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_ToBeClaimedCount"
:label="$t('trials:trials-list:table:IQC_ToBeClaimedCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_AuditToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_AuditToBeDealedCount')" show-overflow-tooltip sortable="custom"
min-width="140" />
<el-table-column v-if="hasPermi(['role:iqc'])" prop="IQC_QuestionToBeDealedCount"
:label="$t('trials:trials-list:table:IQC_QuestionToBeDealedCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:mim'])" prop="MIM_UrgentCount"
:label="$t('trials:trials-list:table:MIM_UrgentCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<!-- <el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_UrgentCount"
@@ -526,127 +244,63 @@
sortable="custom"
min-width="160"
/> -->
<el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_PendingReviewCount"
:label="$t('trials:trials-list:table:MIM_PendingReviewCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:mim'])"
prop="MIM_PendingResponseCount"
:label="$t('trials:trials-list:table:MIM_PendingResponseCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:spm', 'role:cpm'])"
prop="SPM_ReReadingApprovalCount"
:label="$t('trials:trials-list:table:SPM_ReReadingApprovalCount')"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
v-if="hasPermi(['role:spm', 'role:cpm'])"
prop="SPM_ReviewerSelectApprovalCount"
:label="
$t('trials:trials-list:table:SPM_ReviewerSelectApprovalCount')
"
show-overflow-tooltip
sortable="custom"
min-width="160"
/>
<el-table-column
prop="CreateTime"
:label="$t('trials:trials-list:table:createDate')"
show-overflow-tooltip
sortable="custom"
width="180"
/>
<el-table-column
:label="$t('common:action:action')"
width="260"
align="left"
fixed="right"
>
<el-table-column v-if="hasPermi(['role:mim'])" prop="MIM_PendingReviewCount"
:label="$t('trials:trials-list:table:MIM_PendingReviewCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:mim'])" prop="MIM_PendingResponseCount"
:label="$t('trials:trials-list:table:MIM_PendingResponseCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:spm', 'role:cpm'])" prop="SPM_ReReadingApprovalCount"
:label="$t('trials:trials-list:table:SPM_ReReadingApprovalCount')" show-overflow-tooltip sortable="custom"
min-width="160" />
<el-table-column v-if="hasPermi(['role:spm', 'role:cpm'])" prop="SPM_ReviewerSelectApprovalCount" :label="$t('trials:trials-list:table:SPM_ReviewerSelectApprovalCount')
" show-overflow-tooltip sortable="custom" min-width="160" />
<el-table-column prop="CreateTime" :label="$t('trials:trials-list:table:createDate')" show-overflow-tooltip
sortable="custom" width="180" />
<el-table-column :label="$t('common:action:action')" width="260" align="left" fixed="right">
<template slot-scope="scope">
<!-- 详情 -->
<el-button
v-hasPermi="['trials:trials-list:panel']"
circle
icon="el-icon-info"
:disabled="
(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm'])
))
"
:title="$t('trials:trials-list:action:panel')"
@click.stop="handleDetail(scope.row)"
/>
<el-button v-hasPermi="['trials:trials-list:panel']" circle icon="el-icon-info" :disabled="(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm']) ||
hasPermi(['role:op']) ||
hasPermi(['role:dev']) ||
hasPermi(['role:admin'])
))
" :title="$t('trials:trials-list:action:panel')" @click.stop="handleDetail(scope.row)" />
<!-- 编辑项目基本信息 -->
<el-button
v-hasPermi="['trials:trials-list:edit']"
circle
icon="el-icon-edit-outline"
:disabled="scope.row.IsDeleted"
:title="$t('trials:trials-list:action:edit')"
@click.stop="handleEdit(scope.row)"
/>
<el-button v-hasPermi="['trials:trials-list:edit']" circle icon="el-icon-edit-outline"
:disabled="scope.row.IsDeleted" :title="$t('trials:trials-list:action:edit')"
@click.stop="handleEdit(scope.row)" />
<!-- 修改项目状态 -->
<el-button
v-hasPermi="['trials:trials-list:status']"
circle
icon="el-icon-edit"
:disabled="scope.row.IsDeleted"
:title="$t('trials:trials-list:action:status')"
@click.stop="handleStatus(scope.row)"
/>
<el-button v-hasPermi="['trials:trials-list:status']" circle icon="el-icon-edit"
:disabled="scope.row.IsDeleted" :title="$t('trials:trials-list:action:status')"
@click.stop="handleStatus(scope.row)" />
<!--项目文档-->
<el-button
v-hasPermi="[
'trials:trials-panel:trial-summary:trial-document:inspect',
'trials:trials-panel:trial-summary:trial-document:manage',
]"
circle
icon="el-icon-folder-opened"
:disabled="
(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm'])
))
"
:title="$t('trials:trials-list:action:trialDocument')"
@click.stop="toTrialDocument(scope.row)"
/>
<el-button v-hasPermi="[
'trials:trials-panel:trial-summary:trial-document:inspect',
'trials:trials-panel:trial-summary:trial-document:manage',
]" circle icon="el-icon-folder-opened" :disabled="(scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) ||
scope.row.IsDeleted ||
((scope.row.TrialStatusStr === 'Completed' ||
scope.row.TrialStatusStr === 'Stopped') &&
!(
hasPermi(['role:qa']) ||
hasPermi(['role:ea']) ||
hasPermi(['role:pm'])
))
" :title="$t('trials:trials-list:action:trialDocument')" @click.stop="toTrialDocument(scope.row)" />
<!-- 废除项目 -->
<el-button
v-hasPermi="['trials:trials-list:abolish']"
circle
icon="el-icon-delete"
:disabled="
scope.row.IsDeleted ||
scope.row.TrialStatusStr !== 'Initializing'
"
:title="$t('trials:trials-list:action:abolition')"
@click.stop="handleAbandon(scope.row)"
/>
<el-button v-hasPermi="['trials:trials-list:abolish']" circle icon="el-icon-delete" :disabled="scope.row.IsDeleted ||
scope.row.TrialStatusStr !== 'Initializing'
" :title="$t('trials:trials-list:action:abolition')" @click.stop="handleAbandon(scope.row)" />
<!-- 代办详情-->
<!-- <el-button-->
<!-- v-hasPermi="['trials:trials-list:abolish']"-->
@@ -661,61 +315,26 @@
</el-table>
<!-- 分页组件 -->
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
</template>
<!-- 新增/编辑项目 -->
<el-dialog
v-if="dialogVisible"
:visible.sync="dialogVisible"
:title="title"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<TrialForm
:trial-id="currentId"
@getList="getList"
@closeDialog="closeDialog"
/>
<el-dialog v-if="dialogVisible" :visible.sync="dialogVisible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper">
<TrialForm :trial-id="currentId" @getList="getList" @closeDialog="closeDialog" />
</el-dialog>
<!-- 修改项目状态 -->
<el-dialog
v-if="statusVisible"
:visible.sync="statusVisible"
:close-on-click-modal="false"
:title="$t('trials:trials-list:dialogTitle:changeStatus')"
width="700px"
custom-class="base-dialog-wrapper"
append-to-body
>
<TrialStatusForm
:data="currentRow"
@closeDialog="closeStatusDialog"
@getList="getList"
/>
<el-dialog v-if="statusVisible" :visible.sync="statusVisible" :close-on-click-modal="false"
:title="$t('trials:trials-list:dialogTitle:changeStatus')" width="700px" custom-class="base-dialog-wrapper"
append-to-body>
<TrialStatusForm :data="currentRow" @closeDialog="closeStatusDialog" @getList="getList" />
</el-dialog>
<el-dialog
v-if="doneDialogVisible"
:visible.sync="doneDialogVisible"
:title="doneTitle"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<DoneList
:trial-id="currentId"
@getList="getList"
@closeDialog="doneDialogVisible = false"
/>
<el-dialog v-if="doneDialogVisible" :visible.sync="doneDialogVisible" :title="doneTitle" :fullscreen="true"
append-to-body custom-class="base-dialog-wrapper">
<DoneList :trial-id="currentId" @getList="getList" @closeDialog="doneDialogVisible = false" />
</el-dialog>
</BaseContainer>
</template>
@@ -897,7 +516,7 @@ export default {
this.$confirm(res.ErrorMessage, {
type: 'warning',
showCancelButton: false,
callback: (action) => {},
callback: (action) => { },
})
}
})
@@ -922,7 +541,7 @@ export default {
this.currentRow = { ...row }
this.abandonTrial()
})
.catch(() => {})
.catch(() => { })
},
//
abandonTrial() {
@@ -954,7 +573,10 @@ export default {
!(
this.hasPermi(['role:qa']) ||
this.hasPermi(['role:ea']) ||
this.hasPermi(['role:pm'])
this.hasPermi(['role:pm']) ||
hasPermi(['role:op']) ||
hasPermi(['role:dev']) ||
hasPermi(['role:admin'])
)
) {
return
@@ -4,158 +4,109 @@
<div class="title" v-if="isDoc">
{{ TITLE }}
</div>
<el-row v-if="isSystem" style="width: 100%;">
<el-col :span="12">
<h3>{{ TITLE }}</h3>
</el-col>
<el-col :span="12" style="text-align:right;">
<h3>
<Pagination class="page" :total="total" :page.sync="searchData.pageIndex" :limit.sync="searchData.pageSize"
layout="total, sizes, prev, pager, next" :background="false" style="display: inline-block;"
@pagination="getList" />
<el-button icon="el-icon-refresh-left" size="small" circle :title="$t('common:button:reset')"
@click="handleReset" />
</h3>
</el-col>
</el-row>
</template>
<!-- 搜索框 -->
<template slot="search-container">
<el-form :inline="true">
<!-- 文件类型 -->
<el-form-item :label="$t('trials:signRecords:table:fileType')">
<el-select
v-model="searchData.FileTypeId"
clearable
style="width: 150px"
>
<el-option
v-for="item of typeOptions"
:key="item.FileTypeId"
:label="item.FileType"
:value="item.FileTypeId"
/>
<el-select v-model="searchData.FileTypeId" clearable style="width: 150px">
<template v-if="isSystem">
<el-option v-for="item of typeOptions" :key="item.id" :label="item.label" :value="item.id" />
</template>
<template v-else>
<el-option v-for="item of typeOptions" :key="item.FileTypeId" :label="item.FileType"
:value="item.FileTypeId" />
</template>
</el-select>
</el-form-item>
<!-- 文件名称 -->
<el-form-item :label="$t('trials:signRecords:table:fileName')">
<el-input v-model="searchData.Name" style="width: 120px" />
<el-input v-model="searchData.Name" clearable style="width: 120px" />
</el-form-item>
<!-- 签署人 -->
<el-form-item
:label="$t('trials:signRecords:table:user')"
v-if="!isDoc"
>
<el-select
v-model="searchData.UserId"
clearable
filterable
style="width: 140px"
>
<el-option
v-for="item of userOptions"
:key="item.UserId"
:label="item.RealName"
:value="item.UserId"
>
<span style="float: left">{{ item.RealName }}</span>
<span
style="
<el-form-item :label="$t('trials:signRecords:table:user')" v-if="!isDoc">
<el-select v-model="searchData.UserId" clearable filterable style="width: 140px">
<el-option v-for="item of userOptions" :key="item.ConfirmUserId" :label="item.FullName"
:value="item.ConfirmUserId">
<span style="float: left">{{ item.RealName || item.FullName }}</span>
<span style="
float: right;
color: #8492a6;
font-size: 13px;
margin-left: 5px;
"
>
">
{{ item.UserName }}
</span>
</el-option>
</el-select>
</el-form-item>
<!-- 用户名 -->
<el-form-item :label="$t('trials:signRecords:table:userName')" v-if="isSystem">
<el-input v-model="searchData.userName" clearable style="width: 120px" />
</el-form-item>
<!-- 用户类型 -->
<el-form-item
:label="$t('trials:signRecords:table:userType')"
v-if="!isDoc"
>
<el-select
v-model="searchData.UserTypeId"
clearable
filterable
style="width: 120px"
>
<el-option
v-for="item of userTypeOptions"
v-show="item.UserTypeEnum !== 26 && item.UserTypeEnum !== 27"
:key="item.Id"
:label="item.UserTypeShortName"
:value="item.Id"
>
<el-form-item :label="$t('trials:signRecords:table:userType')" v-if="!isDoc">
<el-select v-model="searchData.UserTypeId" clearable filterable style="width: 120px">
<el-option v-for="item of userTypeOptions"
v-show="isSystem || (item.UserTypeEnum !== 26 && item.UserTypeEnum !== 27)" :key="item.Id"
:label="item.UserTypeShortName" :value="item.Id">
<span>{{ item.UserType }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item
:label="$t('trials:signRecords:table:isSign')"
v-if="!isDoc || !viewStatus"
>
<el-select
v-model="searchData.IsConfirmed"
clearable
style="width: 120px"
>
<el-option
v-for="i of $d.TrainingStatusEnum"
:key="'IsConfirmed' + i.label"
:value="i.value"
:label="i.label"
/>
<el-form-item :label="$t('trials:signRecords:table:isSign')" v-if="!isDoc || !viewStatus">
<el-select v-model="searchData.IsConfirmed" clearable style="width: 120px">
<el-option v-for="i of $d.TrainingStatusEnum" :key="'IsConfirmed' + i.label" :value="i.value"
:label="i.label" />
</el-select>
</el-form-item>
<el-form-item
:label="
isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
"
>
<el-select
v-model="searchData.IsDeleted"
clearable
style="width: 120px"
>
<el-option
v-for="i of $d.TrainingStatus"
:key="'IsDeleted' + i.label"
:value="i.value"
:label="i.label"
/>
<el-form-item :label="isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
">
<el-select v-model="searchData.IsDeleted" clearable style="width: 120px">
<el-option v-for="i of $d.TrainingStatus" :key="'IsDeleted' + i.label" :value="i.value" :label="i.label" />
</el-select>
</el-form-item>
<el-form-item
:label="$t('trials:signRecords:table:username')"
v-if="isDoc"
>
<el-form-item :label="$t('trials:signRecords:table:username')" v-if="isDoc">
<el-input v-model="searchData.UserName" style="width: 120px" />
</el-form-item>
<el-form-item
:label="$t('trials:signRecords:table:confirmTime')"
v-if="isDoc"
>
<el-date-picker
v-model="timeList"
@change="changeTimeList"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
type="datetimerange"
>
<el-form-item :label="$t('trials:signRecords:table:confirmTime')" v-if="isDoc || isSystem">
<el-date-picker v-model="timeList" @change="changeTimeList" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" type="datetimerange">
</el-date-picker>
</el-form-item>
<el-form-item :label="$t('trials:signRecords:table:uploadTime')" v-if="isSystem">
<el-date-picker v-model="timeListC" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss"
type="datetimerange" :default-time="['00:00:00', '23:59:59']" @change="changeTimeListC" />
</el-form-item>
<el-form-item>
<!-- 查询 -->
<el-button icon="el-icon-search" type="primary" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button
icon="el-icon-refresh-left"
type="primary"
@click="handleReset"
>
<el-button icon="el-icon-refresh-left" type="primary" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
<!-- 导出 -->
<el-button
type="primary"
icon="el-icon-download"
:loading="exportLoading"
@click="handleExport"
>
<el-button type="primary" icon="el-icon-download" :loading="exportLoading" @click="handleExport"
v-if="!isSystem || !hasPermi(['role:ea'])">
{{ $t('common:button:export') }}
</el-button>
</el-form-item>
@@ -164,39 +115,25 @@
<template slot="main-container">
<!-- 系统文件列表 -->
<el-table
ref="AttachmentsManagement"
v-loading="loading"
v-adaptive="{ bottomOffset: 60 }"
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table ref="AttachmentsManagement" v-loading="loading" v-adaptive="{ bottomOffset: 60 }" :data="list" stripe
height="100" @sort-change="handleSortByColumn">
<el-table-column type="index" width="40" />
<!-- 文件类型 -->
<el-table-column
prop="FileType"
:label="$t('trials:signRecords:table:fileType')"
show-overflow-tooltip
sortable="custom"
width="160"
/>
<el-table-column prop="FileType" :label="$t('trials:signRecords:table:fileType')" show-overflow-tooltip
sortable="custom" width="160" />
<!-- 文件名称 -->
<el-table-column
prop="Name"
:label="$t('trials:signRecords:table:fileName')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="Name" :label="$t('trials:signRecords:table:fileName')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('trials:signRecords:table:AttachmentCount')" prop="AttachmentCount"
show-overflow-tooltip>
<template slot-scope="scope">
<el-button type="text" @click.stop="openAttachment(scope.row, true)">{{ scope.row.AttachmentCount
}}</el-button>
</template>
</el-table-column>
<!-- 文件级别 -->
<el-table-column
prop="IsSystemDoc"
:label="$t('trials:signRecords:table:fileLevel')"
show-overflow-tooltip
width="160"
sortable="custom"
>
<el-table-column prop="IsSystemDoc" :label="$t('trials:signRecords:table:fileLevel')" show-overflow-tooltip
width="160" sortable="custom" v-if="!isSystem">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsSystemDoc" type="primary">{{
$fd('IsSystemDoc', scope.row.IsSystemDoc)
@@ -207,16 +144,10 @@
</template>
</el-table-column>
<!-- 是否废除 -->
<el-table-column
prop="IsDeleted"
:label="
isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="IsDeleted" :label="isDoc
? $t('trials:signRecords:table:isDeletedFile')
: $t('trials:signRecords:table:isDeleted')
" show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
$fd('TrainingStatus', scope.row.IsDeleted)
@@ -227,20 +158,11 @@
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column
prop="CreateTime"
:label="$t('trials:signRecords:table:uploadTime')"
show-overflow-tooltip
width="160"
sortable="custom"
/>
<el-table-column prop="CreateTime" :label="$t('trials:signRecords:table:uploadTime')" show-overflow-tooltip
width="160" sortable="custom" />
<!-- 是否签署 -->
<el-table-column
prop="ConfirmTime"
:label="$t('trials:signRecords:table:isSign')"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="ConfirmTime" :label="$t('trials:signRecords:table:isSign')" show-overflow-tooltip
sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsConfirmed" type="primary">{{
$fd('TrainingStatusEnum', scope.row.IsConfirmed)
@@ -251,86 +173,55 @@
</template>
</el-table-column>
<!-- 签署人 -->
<el-table-column
prop="RealName"
:label="$t('trials:signRecords:table:user')"
show-overflow-tooltip
sortable="custom"
v-if="!isDoc || !viewStatus"
/>
<el-table-column prop="RealName" :label="$t('trials:signRecords:table:user')" show-overflow-tooltip
sortable="custom" v-if="!isDoc || !viewStatus" />
<!-- 用户名 -->
<el-table-column
prop="UserName"
:label="$t('trials:signRecords:table:userName')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="UserName" :label="$t('trials:signRecords:table:userName')" show-overflow-tooltip
sortable="custom" />
<!-- 用户类型 -->
<el-table-column
prop="UserConfirmedUserTypeList"
:label="$t('trials:signRecords:table:userType')"
show-overflow-tooltip
>
<el-table-column prop="UserConfirmedUserTypeList" :label="$t('trials:signRecords:table:userType')"
show-overflow-tooltip>
<template slot-scope="scope">
<span>{{
Array.isArray(scope.row.UserConfirmedUserTypeList) &&
scope.row.UserConfirmedUserTypeList.length > 0
scope.row.UserConfirmedUserTypeList.length > 0
? scope.row.UserConfirmedUserTypeList.join(', ')
: ''
}}</span>
</template>
</el-table-column>
<!-- 签署时间 -->
<el-table-column
prop="ConfirmTime"
:label="$t('trials:signRecords:table:confirmTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="ConfirmTime" :label="$t('trials:signRecords:table:confirmTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
circle
:title="$t('trials:signRecords:action:preview')"
icon="el-icon-view"
@click="handlePreview(scope.row)"
/>
<el-button circle :title="$t('trials:signRecords:action:preview')" icon="el-icon-view"
@click="handlePreview(scope.row)" />
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" v-if="!isSystem" />
</template>
<!-- 预览文件 -->
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:title="$t('trials:signRecords:action:preview')"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<div
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<PreviewFile
v-if="previewVisible"
:file-path="currentPath"
:file-type="currentType"
@getList="getList"
/>
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="$t('trials:signRecords:action:preview')"
:fullscreen="true" append-to-body custom-class="base-dialog-wrapper">
<span style="position: fixed; left: 16px; top: 45px;cursor: pointer;font-size: 18px;color:#409EFF"
@click.stop="openAttachment(currentRow)" v-if="currentRow.AttachmentCount">{{
$t('trials:signRecords:table:AttachmentCount') }} ({{
currentRow.AttachmentCount }})</span>
<div class="base-modal-body" style="border: 2px solid #ccc; padding: 10px">
<PreviewFile v-if="previewVisible" :file-path="currentPath" :file-type="currentType" @getList="getList" />
</div>
</el-dialog>
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
:isView="true" @getList="getList" />
<attachmentPreview :SystemDocumentId="SystemDocumentId" :visible.sync="perview_visible" :isView="true"
v-if="perview_visible" />
</BaseContainer>
</template>
<script>
@@ -339,16 +230,23 @@ import {
getTrialUserSelect,
getTrialUserTypeList,
getTrialDocAndSystemDocType,
getSysDocumentConfirmList,
getSysDocSignUserList
} from '@/api/trials'
import { pMTrainingRecordList_Export } from '@/api/export'
import { pMTrainingRecordList_Export, getSysDocumentConfirmList_Export } from '@/api/export'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import PreviewFile from '@/components/PreviewFile/index'
import attachmentPreview from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentPreview'
import attachmentList from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentList'
const searchDataDefault = () => {
return {
UserName: null,
StartConfirmTime: null,
EndConfirmTime: null,
EndCreateTime: null,
BeginCreateTime: null,
userName: null,
FileTypeId: '',
Name: '',
UserId: '',
@@ -361,7 +259,7 @@ const searchDataDefault = () => {
}
export default {
name: 'AttachmentsManagement',
components: { BaseContainer, Pagination, PreviewFile },
components: { BaseContainer, Pagination, PreviewFile, attachmentPreview, attachmentList },
props: {
isDoc: {
type: Boolean,
@@ -375,6 +273,10 @@ export default {
type: Boolean,
default: false,
},
isSystem: {
type: Boolean,
default: false,
}
},
data() {
return {
@@ -393,6 +295,14 @@ export default {
trialId: this.$route.query.trialId,
exportLoading: false,
timeList: [],
timeListC: [],
SystemDocumentId: null,
perview_visible: null,
config: {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
},
}
},
mounted() {
@@ -401,6 +311,16 @@ export default {
this.getUserType()
},
methods: {
openAttachment(row, isList = false) {
if (!row.AttachmentCount) return false
this.SystemDocumentId = row.Id
this.currentRow = { ...row }
if (!isList) {
this.perview_visible = true
} else {
this.config.visible = true
}
},
changeTimeList() {
if (this.timeList) {
this.searchData.StartConfirmTime = this.timeList[0]
@@ -410,8 +330,26 @@ export default {
this.searchData.EndConfirmTime = null
}
},
changeTimeListC() {
if (this.timeListC) {
this.searchData.BeginCreateTime = this.timeListC[0]
this.searchData.EndCreateTime = this.timeListC[1]
} else {
this.searchData.BeginCreateTime = null
this.searchData.EndCreateTime = null
}
},
handleExport() {
this.exportLoading = true
if (this.isSystem) {
return getSysDocumentConfirmList_Export(this.searchData)
.then(() => {
this.exportLoading = false
})
.catch((err) => {
this.exportLoading = false
})
}
pMTrainingRecordList_Export(this.searchData)
.then(() => {
this.exportLoading = false
@@ -432,29 +370,52 @@ export default {
this.searchData.UserTypeId = IR.Id
}
}
this.searchData.TrialId = this.trialId
getDocumentConfirmList(this.searchData)
.then(async (res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
console.log(this.total)
})
.catch(() => {
this.loading = false
})
if (this.isSystem) {
getSysDocumentConfirmList(this.searchData)
.then(async (res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
})
.catch(() => {
this.loading = false
})
} else {
this.searchData.TrialId = this.trialId
getDocumentConfirmList(this.searchData)
.then(async (res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
})
.catch(() => {
this.loading = false
})
}
},
//
getTypeOptions() {
getTrialDocAndSystemDocType(this.trialId).then((res) => {
this.typeOptions = res.Result
})
if (this.isSystem) {
this.typeOptions = this.$d.Sys_Document
} else {
getTrialDocAndSystemDocType(this.trialId).then((res) => {
this.typeOptions = res.Result
})
}
},
//
getUserSelect() {
getTrialUserSelect(this.trialId).then((res) => {
this.userOptions = res.Result
})
if (this.isSystem) {
getSysDocSignUserList().then((res) => {
this.userOptions = res.Result
})
} else {
getTrialUserSelect(this.trialId).then((res) => {
this.userOptions = res.Result
})
}
},
//
getUserType() {
@@ -481,6 +442,7 @@ export default {
handleReset() {
this.searchData = searchDataDefault()
this.timeList = []
this.timeListC = []
this.getList()
this.$nextTick(() => {
this.$refs.AttachmentsManagement.clearSort()
@@ -6,12 +6,8 @@
<!-- 中心编号 -->
<el-form-item :label="$t('trials:reviewAssign:readingTask:table:siteCode')">
<el-select v-model="searchData.TrialSiteId" clearable filterable style="width:120px;">
<el-option
v-for="(item,index) of siteOptions"
:key="index"
:label="item.TrialSiteCode"
:value="item.TrialSiteId"
/>
<el-option v-for="(item, index) of siteOptions" :key="index" :label="item.TrialSiteCode"
:value="item.TrialSiteId" />
</el-select>
</el-form-item>
<!-- 受试者编号 -->
@@ -20,51 +16,47 @@
</el-form-item>
<!-- 访视/阅片期名称 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:visitName')">
<el-input
v-model="searchData.TaskName"
style="width:100px;"
clearable
/>
<el-input v-model="searchData.TaskName" style="width:100px;" clearable />
</el-form-item>
<!-- 阅片人 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:reader')">
<el-select v-model="searchData.DoctorUserId" clearable style="width:120px;">
<el-option v-for="item of DoctorUserList" :key="'DoctorUserId' + item.DoctorUserId" :value="item.DoctorUserId" :label="item.UserName" />
<el-option v-for="item of DoctorUserList" :key="'DoctorUserId' + item.DoctorUserId"
:value="item.DoctorUserId" :label="item.UserName" />
</el-select>
</el-form-item>
<!-- 是否加急 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:isUrgent')">
<el-select v-model="searchData.IsUrgent" clearable style="width:120px;">
<el-option v-for="item of $d.YesOrNo" :key="'IsUrgent' + item.label" :value="item.value" :label="item.label" />
<el-option v-for="item of $d.YesOrNo" :key="'IsUrgent' + item.label" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item>
<!-- 任务状态 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:taskStatus')">
<el-select v-model="searchData.TaskState" clearable style="width:120px;">
<el-option v-for="item of $d.TaskState" :key="'TaskState' + item.label" :value="item.value" :label="item.label" />
<el-option v-for="item of $d.TaskState" :key="'TaskState' + item.label" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item>
<!-- 任务类型 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:taskType')">
<el-select v-model="searchData.ReadingCategory" clearable style="width:120px;">
<el-option v-for="item of $d.ReadingCategory" :key="'ReadingCategory' + item.label" :value="item.value" :label="item.label" />
<el-option v-for="item of $d.ReadingCategory" :key="'ReadingCategory' + item.label" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item>
<!-- 分配状态 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:assignStatus')">
<el-select v-model="searchData.TaskAllocationState" clearable style="width:120px;">
<el-option v-for="item of $d.TaskAllocationState" :key="'TaskAllocationState' + item.label" :value="item.value" :label="item.label" />
<el-option v-for="item of $d.TaskAllocationState" :key="'TaskAllocationState' + item.label"
:value="item.value" :label="item.label" />
</el-select>
</el-form-item>
<!-- 分配时间 -->
<el-form-item style="margin-bottom:10px" :label="$t('trials:reviewAssign:readingTask:table:assignTime')">
<el-date-picker
v-model="timeList"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
:default-time="['00:00:00', '23:59:59']"
@change="changeTimeList"
/>
<el-date-picker v-model="timeList" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
:default-time="['00:00:00', '23:59:59']" @change="changeTimeList" />
</el-form-item>
<el-form-item style="margin-bottom:10px">
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
@@ -77,180 +69,117 @@
</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
prop="OriginalReReadingTask.IsUrgent"
:label="$t('trials:consistencyCheck:table:isUrgent')"
show-overflow-tooltip
min-width="100"
sortable="custom"
>
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" stripe height="100"
@sort-change="handleSortChange">
<el-table-column prop="OriginalReReadingTask.IsUrgent" :label="$t('trials:consistencyCheck:table:isUrgent')"
show-overflow-tooltip min-width="100" sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.OriginalReReadingTask.IsUrgent" type="danger">{{ $fd('YesOrNo', scope.row.OriginalReReadingTask.IsUrgent) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.IsUrgent" type="danger">{{ $fd('YesOrNo',
scope.row.OriginalReReadingTask.IsUrgent) }}</el-tag>
<el-tag v-else type="primary">{{ $fd('YesOrNo', scope.row.OriginalReReadingTask.IsUrgent) }}</el-tag>
</template>
</el-table-column>
<!-- 任务编号 -->
<el-table-column
prop="OriginalReReadingTask.TaskCode"
:label="$t('trials:readTask:table:taskCode')"
min-width="100"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.TaskCode" :label="$t('trials:readTask:table:taskCode')"
min-width="100" sortable="custom" show-overflow-tooltip />
<!-- 中心编号 -->
<el-table-column
prop="OriginalReReadingTask.TrialSiteCode"
:label="$t('trials:readTask:table:siteCode')"
min-width="100"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.TrialSiteCode" :label="$t('trials:readTask:table:siteCode')"
min-width="100" sortable="custom" show-overflow-tooltip />
<!-- 受试者编号 -->
<el-table-column
prop="OriginalReReadingTask.SubjectCode"
:label="$t('trials:readTask:table:subjectCode')"
min-width="120"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.SubjectCode" :label="$t('trials:readTask:table:subjectCode')"
min-width="120" sortable="custom" show-overflow-tooltip />
<!-- 访视/阅片期名称 -->
<el-table-column
prop="OriginalReReadingTask.TaskName"
:label="$t('trials:reviewAssign:readingTask:table:visitName')"
min-width="160"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.TaskName"
:label="$t('trials:reviewAssign:readingTask:table:visitName')" min-width="160" sortable="custom"
show-overflow-tooltip />
<!-- 盲态任务标识 -->
<el-table-column
prop="OriginalReReadingTask.TaskBlindName"
:label="$t('trials:reviewAssign:readingTask:table:blindName')"
min-width="140"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.TaskBlindName"
:label="$t('trials:reviewAssign:readingTask:table:blindName')" min-width="140" sortable="custom"
show-overflow-tooltip />
<!-- 任务创建时间 -->
<el-table-column
prop="OriginalReReadingTask.CreateTime"
:label="$t('trials:reviewAssign:readingTask:table:createTime')"
min-width="140"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.CreateTime"
:label="$t('trials:reviewAssign:readingTask:table:createTime')" min-width="140" sortable="custom"
show-overflow-tooltip />
<!-- 任务状态 -->
<el-table-column
prop="OriginalReReadingTask.TaskState"
:label="$t('trials:reviewAssign:readingTask:table:taskStatus')"
min-width="100"
sortable="custom"
show-overflow-tooltip
>
<el-table-column prop="OriginalReReadingTask.TaskState"
:label="$t('trials:reviewAssign:readingTask:table:taskStatus')" min-width="100" sortable="custom"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 0" type="primary">{{ $fd('TaskState', scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 1" type="info">{{ $fd('TaskState', scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 3" type="danger">{{ $fd('TaskState', scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 4" type="warning">{{ $fd('TaskState', scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 5" type="danger">{{ $fd('TaskState', scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 0" type="primary">{{ $fd('TaskState',
scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 1" type="info">{{ $fd('TaskState',
scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 3" type="danger">{{ $fd('TaskState',
scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 4" type="warning">{{ $fd('TaskState',
scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.TaskState === 5" type="danger">{{ $fd('TaskState',
scope.row.OriginalReReadingTask.TaskState) }}</el-tag>
</template>
</el-table-column>
<!-- 任务类型 -->
<el-table-column
prop="OriginalReReadingTask.ReadingCategory"
:label="$t('trials:reviewAssign:readingTask:table:taskType')"
min-width="100"
sortable="custom"
show-overflow-tooltip
>
<el-table-column prop="OriginalReReadingTask.ReadingCategory"
:label="$t('trials:reviewAssign:readingTask:table:taskType')" min-width="100" sortable="custom"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 1" type="primary">{{ $fd('ReadingCategory', scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 2" type="info">{{ $fd('ReadingCategory', scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 4" type="danger">{{ $fd('ReadingCategory', scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 5" type="warning">{{ $fd('ReadingCategory', scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 1" type="primary">{{
$fd('ReadingCategory', scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 2" type="info">{{ $fd('ReadingCategory',
scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 4" type="danger">{{ $fd('ReadingCategory',
scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ReadingCategory === 5" type="warning">{{
$fd('ReadingCategory', scope.row.OriginalReReadingTask.ReadingCategory) }}</el-tag>
</template>
</el-table-column>
<!-- 角色 -->
<el-table-column
prop="OriginalReReadingTask.ArmEnum"
:label="$t('trials:reviewAssign:readingTask:table:role')"
min-width="80"
sortable="custom"
show-overflow-tooltip
>
<el-table-column prop="OriginalReReadingTask.ArmEnum" :label="$t('trials:reviewAssign:readingTask:table:role')"
min-width="80" sortable="custom" show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 1" type="primary">{{ $fd('ArmEnum', scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 2" type="success">{{ $fd('ArmEnum', scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 3" type="info">{{ $fd('ArmEnum', scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 4" type="danger">{{ $fd('ArmEnum', scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 5" type="warning">{{ $fd('ArmEnum', scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 1" type="primary">{{ $fd('ArmEnum',
scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 2" type="success">{{ $fd('ArmEnum',
scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 3" type="info">{{ $fd('ArmEnum',
scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 4" type="danger">{{ $fd('ArmEnum',
scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
<el-tag v-if="scope.row.OriginalReReadingTask.ArmEnum === 5" type="warning">{{ $fd('ArmEnum',
scope.row.OriginalReReadingTask.ArmEnum) }}</el-tag>
</template>
</el-table-column>
<!-- 阅片人 -->
<el-table-column
prop="OriginalReReadingTask.UserName"
:label="$t('trials:reviewAssign:readingTask:table:reader')"
min-width="100"
sortable="custom"
show-overflow-tooltip
>
<el-table-column prop="OriginalReReadingTask.UserName"
:label="$t('trials:reviewAssign:readingTask:table:reader')" min-width="100" sortable="custom"
show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OriginalReReadingTask.UserName }}({{ scope.row.OriginalReReadingTask.FullName }})
</template>
</el-table-column>
<!-- 阅片完成时间 -->
<el-table-column
prop="OriginalReReadingTask.SignTime"
:label="$t('trials:reviewTrack:table:signTime')"
min-width="180"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="OriginalReReadingTask.SignTime" :label="$t('trials:reviewTrack:table:signTime')"
min-width="180" sortable="custom" show-overflow-tooltip />
<!-- 重阅申请类型 -->
<el-table-column
prop="OriginalReReadingTask.RequestReReadingType"
:label="$t('trials:rereadTask:table:requestReReadingType')"
min-width="140"
sortable="custom"
show-overflow-tooltip
>
<el-table-column prop="OriginalReReadingTask.RequestReReadingType"
:label="$t('trials:rereadTask:table:requestReReadingType')" min-width="140" sortable="custom"
show-overflow-tooltip>
<template slot-scope="scope">
<div v-if="scope.row.RequestReReadingType">
<el-tag v-if="scope.row.RequestReReadingType === 2" type="danger">{{ $fd('RequestReReadingType', scope.row.RequestReReadingType) }}</el-tag>
<el-tag v-if="scope.row.RequestReReadingType === 2" type="danger">{{ $fd('RequestReReadingType',
scope.row.RequestReReadingType) }}</el-tag>
<el-tag v-else type="primary">{{ $fd('RequestReReadingType', scope.row.RequestReReadingType) }}</el-tag>
</div>
</template>
</el-table-column>
<!-- 申请时间 -->
<el-table-column
prop="RequestReReadingTime"
:label="$t('trials:rereadTask:table:requestReReadingTime')"
min-width="100"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="RequestReReadingTime" :label="$t('trials:rereadTask:table:requestReReadingTime')"
min-width="100" sortable="custom" show-overflow-tooltip />
<!-- 申请原因 -->
<el-table-column
prop="RequestReReadingReason"
:label="$t('trials:rereadTask:table:requestReReadingReason')"
min-width="100"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="RequestReReadingReason" :label="$t('trials:rereadTask:table:requestReReadingReason')"
min-width="100" sortable="custom" show-overflow-tooltip />
<!-- 审批结果 -->
<el-table-column
prop="AllocateTime"
:label="$t('trials:rereadTask:table:requestReReadingResultEnum')"
min-width="100"
sortable="custom"
show-overflow-tooltip
>
<el-table-column prop="AllocateTime" :label="$t('trials:rereadTask:table:requestReReadingResultEnum')"
min-width="100" sortable="custom" show-overflow-tooltip>
<template slot-scope="scope">
<div v-if="scope.row.RequestReReadingResultEnum || scope.row.RequestReReadingResultEnum === 0">
<el-tooltip v-if="scope.row.RequestReReadingResultEnum === 2" class="item" effect="dark" placement="top">
@@ -259,90 +188,217 @@
</div>
<el-tag type="danger">{{ $fd('RequestReReadingResult', scope.row.RequestReReadingResultEnum) }}</el-tag>
</el-tooltip>
<el-tag v-if="scope.row.RequestReReadingResultEnum === 1" type="primary">{{ $fd('RequestReReadingResult', scope.row.RequestReReadingResultEnum) }}</el-tag>
<el-tag v-if="scope.row.RequestReReadingResultEnum === 0" type="warning">{{ $fd('RequestReReadingResult', scope.row.RequestReReadingResultEnum) }}</el-tag>
<el-tag v-if="scope.row.RequestReReadingResultEnum === 1" type="primary">{{ $fd('RequestReReadingResult',
scope.row.RequestReReadingResultEnum) }}</el-tag>
<el-tag v-if="scope.row.RequestReReadingResultEnum === 0" type="warning">{{ $fd('RequestReReadingResult',
scope.row.RequestReReadingResultEnum) }}</el-tag>
</div>
</template>
</el-table-column>
<!-- 新任务编号 -->
<el-table-column
prop="ReReadingNewTaskCode"
:label="$t('trials:rereadTask:table:reReadingNewTaskCode')"
min-width="120"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column
v-if="hasPermi(['role:spm'])"
fixed="right"
:label="$t('common:action:action')"
width="210"
>
<el-table-column prop="ReReadingNewTaskCode" :label="$t('trials:rereadTask:table:reReadingNewTaskCode')"
min-width="120" sortable="custom" show-overflow-tooltip />
<el-table-column v-if="hasPermi(['role:spm'])" fixed="right" :label="$t('common:action:action')" width="210">
<template slot-scope="scope">
<!-- 同意 -->
<el-button
:disabled="!!scope.row.RequestReReadingResultEnum || scope.row.RequestReReadingType === 1"
icon="el-icon-check"
circle
:title="$t('trials:spmAudit:button:agree')"
@click="openReReadingOrBackList(scope.row,1)"
/>
<!-- <el-button :disabled="!!scope.row.RequestReReadingResultEnum || scope.row.RequestReReadingType === 1"
icon="el-icon-check" circle :title="$t('trials:spmAudit:button:agree')"
@click="openReReadingOrBackList(scope.row, 1)" /> -->
<!-- 拒绝 -->
<el-button
:disabled="!!scope.row.RequestReReadingResultEnum || scope.row.RequestReReadingType === 1"
icon="el-icon-close"
circle
:title="$t('trials:spmAudit:button:reject')"
@click="confirmReReading(scope.row,2, true)"
/>
<!-- <el-button :disabled="!!scope.row.RequestReReadingResultEnum || scope.row.RequestReReadingType === 1"
icon="el-icon-close" circle :title="$t('trials:spmAudit:button:reject')"
@click="confirmReReading(scope.row, 2, true)" /> -->
<el-button :disabled="!!scope.row.RequestReReadingResultEnum ||
scope.row.RequestReReadingType === 1
" icon="el-icon-edit-outline" circle :title="$t('trials:spmAudit:table:Approval')"
@click="audit(scope.row)" />
<!-- 已影响任务列表 -->
<el-button
:disabled="scope.row.RequestReReadingResultEnum !== 1"
icon="el-icon-document-copy"
circle
:title="$t('trials:spmAudit:button:influenceList')"
@click="getInfluencedTaskList(scope.row)"
/>
<el-button :disabled="scope.row.RequestReReadingResultEnum !== 1" icon="el-icon-document-copy" circle
:title="$t('trials:spmAudit:button:influenceList')" @click="getInfluencedTaskList(scope.row)" />
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<base-model v-if="config.visible" :config="config">
<template slot="dialog-body">
<el-form ref="imageBackform" :model="form" class="demo-form-inline" :rules="rules"
:label-width="isEN ? '200px' : '150px'">
<el-form-item :label="$t('trials:spmAudit:table:Matters')" prop="Matters">
<span>{{ rowData.title }}</span>
</el-form-item>
<el-form-item :label="$t('trials:spmAudit:form:ApplyReason')" prop="ApplyReason">
<span>{{ rowData.RequestReReadingReason }}</span>
</el-form-item>
<el-form-item :label="$t('trials:spmAudit:form:IsAgree')" prop="RequestReReadingResultEnum">
<el-radio-group v-model="form.RequestReReadingResultEnum">
<el-radio :label="1">{{ $t('trials:spmAudit:button:auditYes') }}</el-radio>
<el-radio :label="2">{{ $t('trials:spmAudit:button:auditNo') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('trials:spmAudit:form:ResultRemark')" v-if="form.RequestReReadingResultEnum !== 2"
key="1">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" placeholder=""
v-model="form.RequestReReadingRejectReason">
</el-input>
</el-form-item>
<el-form-item :label="$t('trials:spmAudit:form:ResultRemark')" prop="RequestReReadingRejectReason" v-else
key="2">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" placeholder=""
v-model="form.RequestReReadingRejectReason">
</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-column prop="TaskCode" :label="$t('trials:reviewTrack:table:taskCode')" min-width="100"
show-overflow-tooltip />
<!-- 中心编号 -->
<el-table-column prop="TrialSiteCode" :label="$t('trials:reviewTrack:table:siteCode')" min-width="100"
show-overflow-tooltip />
<!-- 受试者编号 -->
<el-table-column prop="SubjectCode" :label="$t('trials:reviewTrack:table:subjectCode')" min-width="120"
show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="
scope.row.BlindSubjectCode &&
scope.row.BlindSubjectCode !== scope.row.SubjectCode
">
{{ `${scope.row.SubjectCode}/${scope.row.BlindSubjectCode}` }}
</span>
<span v-else>{{ scope.row.SubjectCode }}</span>
</template>
</el-table-column>
<!-- 任务名称 -->
<el-table-column prop="VisitTaskNum" :label="$t('trials:reviewTrack:table:taskName')" min-width="120"
show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="
scope.row.TaskBlindName &&
scope.row.TaskName !== scope.row.TaskBlindName
">
{{ `${scope.row.TaskName}/${scope.row.TaskBlindName}` }}
</span>
<span v-else>{{ scope.row.TaskName }}</span>
</template>
</el-table-column>
<!-- 盲态任务标识 -->
<!-- <el-table-column
prop="TaskBlindName"
:label="$t('trials:reviewTrack:table:blindName')"
min-width="120"
show-overflow-tooltip
/> -->
<!-- 阅片标准 -->
<el-table-column prop="TrialReadingCriterionName" :label="$t('trials:reviewTrack:table:criterionName')"
min-width="100" show-overflow-tooltip />
<!-- 任务状态 -->
<el-table-column prop="TaskState" :label="$t('trials:reviewTrack:table:taskStatus')" min-width="100"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.TaskState === 0" type="primary">{{
$fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 1" type="info">{{
$fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 3" type="danger">{{
$fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 4" type="warning">{{
$fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 5" type="danger">{{
$fd('TaskState', scope.row.TaskState)
}}</el-tag>
</template>
</el-table-column>
<!-- 任务类型 -->
<el-table-column prop="ReadingCategory" min-width="100" :label="$t('trials:reviewTrack:table:taskType')"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.ReadingCategory === 1" type="primary">{{
$fd('ReadingCategory', scope.row.ReadingCategory)
}}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 2" type="info">{{
$fd('ReadingCategory', scope.row.ReadingCategory)
}}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 4" type="danger">{{
$fd('ReadingCategory', scope.row.ReadingCategory)
}}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 5" type="warning">{{
$fd('ReadingCategory', scope.row.ReadingCategory)
}}</el-tag>
</template>
</el-table-column>
<!-- 阅片状态 -->
<el-table-column prop="ReadingTaskState" :label="$t('trials:reviewTrack:table:readingStatus')"
min-width="100" show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.ReadingTaskState === 2" type="primary">{{
$fd('ReadingTaskState', scope.row.ReadingTaskState)
}}</el-tag>
<el-tag v-else type="danger">{{
$fd('ReadingTaskState', scope.row.ReadingTaskState)
}}</el-tag>
</template>
</el-table-column>
<!-- 生效后影响 -->
<el-table-column prop="OptType" :label="$t('trials:reviewTrack:applyReread:title:postEffectiveImpacts')
" min-width="100" show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.OptType === 0" type="primary">{{
$fd('ReReadingOrBackOptType', scope.row.OptType)
}}</el-tag>
<el-tag v-if="scope.row.OptType === 1" type="danger">{{
$fd('ReReadingOrBackOptType', scope.row.OptType)
}}</el-tag>
<el-tag v-if="scope.row.OptType === 2" type="warning">{{
$fd('ReReadingOrBackOptType', scope.row.OptType)
}}</el-tag>
</template>
</el-table-column>
<!-- 阅片人 -->
<el-table-column prop="UserName" :label="$t('trials:reviewTrack:table:reader')" min-width="160"
show-overflow-tooltip>
<template v-if="scope.row.DoctorUser" slot-scope="scope">
{{ scope.row.DoctorUser.UserName }}({{
scope.row.DoctorUser.FullName
}})
</template>
</el-table-column>
</el-table>
</el-form>
</template>
<template slot="dialog-footer">
<el-button type="primary" @click="auditImageBack" :loading="loading">
{{ $t('common:button:confirm') }}
</el-button>
<el-button @click="config.visible = false" :loading="loading">
{{ $t('common:button:cancel') }}
</el-button>
</template>
</base-model>
<!-- 驳回 +++-->
<el-dialog
v-if="ConfirmReReadingVisible"
:title="$t('trials:spmAudit:title:rejected')"
:visible.sync="ConfirmReReadingVisible"
width="600px"
append-to-body
:close-on-click-modal="false"
custom-class="base-dialog-wrapper"
>
<el-dialog v-if="ConfirmReReadingVisible" :title="$t('trials:spmAudit:title:rejected')"
:visible.sync="ConfirmReReadingVisible" width="600px" append-to-body :close-on-click-modal="false"
custom-class="base-dialog-wrapper">
<div style="padding:10px;border: 1px solid #e0e0e0;max-height:650px;overflow-y: auto;">
<el-form
ref="reasonForm"
:rules="rules"
:model="ConfirmReReadingForm"
class="demo-ruleForm"
size="small"
label-width="120px"
>
<el-form ref="reasonForm" :rules="rules" :model="ConfirmReReadingForm" class="demo-ruleForm" size="small"
label-width="120px">
<!-- 驳回原因 -->
<el-form-item :label="$t('trials:spmAudit:title:rejectedReason')" prop="RequestReReadingRejectReason">
<el-input
v-model="ConfirmReReadingForm.RequestReReadingRejectReason"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:placeholder="$t('common:ruleMessage:specify')"
maxlength="500"
show-word-limit
/>
<el-input v-model="ConfirmReReadingForm.RequestReReadingRejectReason" type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }" :placeholder="$t('common:ruleMessage:specify')" maxlength="500"
show-word-limit />
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<!-- 取消 -->
<el-button :disabled="btnLoading" size="small" type="primary" @click="ConfirmReReadingVisible = false;ConfirmReReadingForm = { RequestReReadingRejectReason: null }">
<el-button :disabled="btnLoading" size="small" type="primary"
@click="ConfirmReReadingVisible = false; ConfirmReReadingForm = { RequestReReadingRejectReason: null }">
{{ $t('common:button:cancel') }}
</el-button>
<!-- 保存 -->
@@ -352,137 +408,95 @@
</div>
</el-dialog>
<!-- '重阅影响任务列表' : '已影响任务列表'" +++-->
<el-dialog
v-if="ReReadingOrBackVisible"
:title="opentype === 'read' ? this.$t('trials:spmAudit:title:title1'):this.$t('trials:spmAudit:title:title2')"
:visible.sync="ReReadingOrBackVisible"
width="1460px"
append-to-body
:close-on-click-modal="false"
custom-class="base-dialog-wrapper"
>
<el-dialog v-if="ReReadingOrBackVisible"
:title="opentype === 'read' ? this.$t('trials:spmAudit:title:title1') : this.$t('trials:spmAudit:title:title2')"
:visible.sync="ReReadingOrBackVisible" width="1460px" append-to-body :close-on-click-modal="false"
custom-class="base-dialog-wrapper">
<div class="base-dialog-body">
<el-table
v-loading="loading"
:data="InfluenceTaskList"
stripe
height="100"
style="min-height: 400px;"
>
<el-table v-loading="loading" :data="InfluenceTaskList" stripe height="100" style="min-height: 400px;">
<!-- 任务编号 -->
<el-table-column
prop="TaskCode"
:label="$t('trials:readTask:table:taskCode')"
min-width="100"
show-overflow-tooltip
/>
<el-table-column prop="TaskCode" :label="$t('trials:readTask:table:taskCode')" min-width="100"
show-overflow-tooltip />
<!-- 中心编号 -->
<el-table-column
prop="TrialSiteCode"
:label="$t('trials:readTask:table:siteCode')"
min-width="100"
show-overflow-tooltip
/>
<el-table-column prop="TrialSiteCode" :label="$t('trials:readTask:table:siteCode')" min-width="100"
show-overflow-tooltip />
<!-- 受试者编号 -->
<el-table-column
prop="SubjectCode"
:label="$t('trials:readTask:table:subjectCode')"
min-width="120"
show-overflow-tooltip
/>
<el-table-column prop="SubjectCode" :label="$t('trials:readTask:table:subjectCode')" min-width="120"
show-overflow-tooltip />
<!-- 访视/阅片期名称 -->
<el-table-column
prop="VisitTaskNum"
:label="$t('trials:consistencyCheck:table:visitName')"
min-width="140"
show-overflow-tooltip
>
<el-table-column prop="VisitTaskNum" :label="$t('trials:consistencyCheck:table:visitName')" min-width="140"
show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.TaskName }}
</template>
</el-table-column>
<!-- 盲态任务标识 -->
<el-table-column
prop="TaskBlindName"
:label="$t('trials:readTask:table:blindName')"
min-width="120"
show-overflow-tooltip
/>
<el-table-column prop="TaskBlindName" :label="$t('trials:readTask:table:blindName')" min-width="120"
show-overflow-tooltip />
<!-- 阅片标准 -->
<el-table-column
prop="TrialReadingCriterionName"
:label="$t('trials:readTask:table:criterionName')"
min-width="100"
show-overflow-tooltip
/>
<el-table-column prop="TrialReadingCriterionName" :label="$t('trials:readTask:table:criterionName')"
min-width="100" show-overflow-tooltip />
<!-- 任务状态 -->
<el-table-column
prop="TaskState"
:label="$t('trials:readTask:table:taskState')"
min-width="100"
show-overflow-tooltip
>
<el-table-column prop="TaskState" :label="$t('trials:readTask:table:taskState')" min-width="100"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.TaskState === 0" type="primary">{{ $fd('TaskState', scope.row.TaskState) }}</el-tag>
<el-tag v-if="scope.row.TaskState === 1" type="info">{{ $fd('TaskState', scope.row.TaskState) }}</el-tag>
<el-tag v-if="scope.row.TaskState === 3" type="danger">{{ $fd('TaskState', scope.row.TaskState) }}</el-tag>
<el-tag v-if="scope.row.TaskState === 4" type="warning">{{ $fd('TaskState', scope.row.TaskState) }}</el-tag>
<el-tag v-if="scope.row.TaskState === 5" type="danger">{{ $fd('TaskState', scope.row.TaskState) }}</el-tag>
<el-tag v-if="scope.row.TaskState === 0" type="primary">{{ $fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 1" type="info">{{ $fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 3" type="danger">{{ $fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 4" type="warning">{{ $fd('TaskState', scope.row.TaskState)
}}</el-tag>
<el-tag v-if="scope.row.TaskState === 5" type="danger">{{ $fd('TaskState', scope.row.TaskState)
}}</el-tag>
</template>
</el-table-column>
<!-- 任务类型 -->
<el-table-column
prop="ReadingCategory"
min-width="100"
:label="$t('trials:readTask:table:readingCategory')"
show-overflow-tooltip
>
<el-table-column prop="ReadingCategory" min-width="100" :label="$t('trials:readTask:table:readingCategory')"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.ReadingCategory === 1" type="primary">{{ $fd('ReadingCategory', scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 2" type="info">{{ $fd('ReadingCategory', scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 4" type="danger">{{ $fd('ReadingCategory', scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 5" type="warning">{{ $fd('ReadingCategory', scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 1" type="primary">{{ $fd('ReadingCategory',
scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 2" type="info">{{ $fd('ReadingCategory',
scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 4" type="danger">{{ $fd('ReadingCategory',
scope.row.ReadingCategory) }}</el-tag>
<el-tag v-if="scope.row.ReadingCategory === 5" type="warning">{{ $fd('ReadingCategory',
scope.row.ReadingCategory) }}</el-tag>
</template>
</el-table-column>
<!-- 阅片状态 -->
<el-table-column
prop="ReadingTaskState"
:label="$t('trials:readTask:table:readingTaskState')"
min-width="100"
show-overflow-tooltip
>
<el-table-column prop="ReadingTaskState" :label="$t('trials:readTask:table:readingTaskState')"
min-width="100" show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.ReadingTaskState === 2" type="primary">{{ $fd('ReadingTaskState', scope.row.ReadingTaskState) }}</el-tag>
<el-tag v-if="scope.row.ReadingTaskState === 2" type="primary">{{ $fd('ReadingTaskState',
scope.row.ReadingTaskState) }}</el-tag>
<el-tag v-else type="danger">{{ $fd('ReadingTaskState', scope.row.ReadingTaskState) }}</el-tag>
</template>
</el-table-column>
<!-- 生效后影响 -->
<el-table-column
prop="OptType"
:label="$t('trials:readTask:table:optType')"
min-width="100"
show-overflow-tooltip
>
<el-table-column prop="OptType" :label="$t('trials:readTask:table:optType')" min-width="100"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag v-if="scope.row.OptType === 0" type="primary">{{ $fd('ReReadingOrBackOptType', scope.row.OptType) }}</el-tag>
<el-tag v-if="scope.row.OptType === 1" type="danger">{{ $fd('ReReadingOrBackOptType', scope.row.OptType) }}</el-tag>
<el-tag v-if="scope.row.OptType === 2" type="warning">{{ $fd('ReReadingOrBackOptType', scope.row.OptType) }}</el-tag>
<el-tag v-if="scope.row.OptType === 0" type="primary">{{ $fd('ReReadingOrBackOptType',
scope.row.OptType) }}</el-tag>
<el-tag v-if="scope.row.OptType === 1" type="danger">{{ $fd('ReReadingOrBackOptType', scope.row.OptType)
}}</el-tag>
<el-tag v-if="scope.row.OptType === 2" type="warning">{{ $fd('ReReadingOrBackOptType',
scope.row.OptType) }}</el-tag>
</template>
</el-table-column>
<!-- 阅片人 -->
<el-table-column
prop="UserName"
:label="$t('trials:readTask:table:reader')"
min-width="160"
show-overflow-tooltip
>
<el-table-column prop="UserName" :label="$t('trials:readTask:table:reader')" min-width="160"
show-overflow-tooltip>
<template v-if="scope.row.DoctorUser" slot-scope="scope">
{{ scope.row.DoctorUser.UserName }}({{ scope.row.DoctorUser.FullName }})
</template>
</el-table-column>
</el-table>
</div>
<div v-if="opentype==='read'" slot="footer" class="dialog-footer">
<div v-if="opentype === 'read'" slot="footer" class="dialog-footer">
<!-- 取消 -->
<el-button :disabled="btnLoading" size="small" type="primary" @click="ReReadingOrBackVisible = false">
{{ $t('common:button:cancel') }}
@@ -493,16 +507,11 @@
</el-button>
</div>
</el-dialog>
<el-dialog
:destroy-on-close="true"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
custom-class="base-dialog-wrapper"
>
<el-dialog :destroy-on-close="true" :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>
@@ -518,7 +527,7 @@ import { getToken } from '@/utils/auth'
import { changeURLStatic } from '@/utils/history.js'
import const_ from '@/const/sign-code'
import SignForm from '@/views/trials/components/newSignForm'
import baseModel from '@/components/BaseModel'
const searchDataDefault = () => {
return {
PageIndex: 1,
@@ -542,7 +551,7 @@ const searchDataDefault = () => {
}
export default {
name: 'TrialsNotice',
components: { BaseContainer, Pagination, SignForm },
components: { BaseContainer, Pagination, SignForm, baseModel },
data() {
return {
searchData: searchDataDefault(),
@@ -593,9 +602,40 @@ export default {
readVisible: false,
TaskOptType: null,
OtherInfo: null,
ReadingType: null
ReadingType: null,
config: {
visible: false,
title: this.$t("trials:spmAudit:confirmMessage:imageBack"),
width: '1000px',
appendToBody: true,
},
form: {
RequestReReadingResultEnum: null,
RequestReReadingRejectReason: null
},
rules: {
RequestReReadingResultEnum: [
{
required: true,
message: this.$t('common:ruleMessage:select'),
trigger: ['blur', 'change'],
},
],
RequestReReadingRejectReason: [
{
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: ['blur', 'change'],
},
]
}
}
},
computed: {
isEN() {
return this.$i18n.locale !== 'zh'
},
},
mounted() {
if (this.$route.query.SiteId) {
this.searchData.TrialSiteId = this.$route.query.SiteId
@@ -612,6 +652,39 @@ export default {
this.getDoctorUserSelectList()
},
methods: {
async auditImageBack() {
try {
console.log(this.form)
let validate = await this.$refs.imageBackform.validate()
if (!validate) return false
this.confirmSign(this.form.RequestReReadingResultEnum)
} catch (err) {
console.log(err)
}
},
async audit(row) {
try {
this.rowData = Object.assign({}, row)
this.rowData.title = `${row.ApplicantName} (${this.$fd('RequestReReadingType', row.RequestReReadingType)}) ${this.$t('trials:spmAudit:title:imageBack').replace('xxx', row.OriginalReReadingTask.SubjectCode).replace('yyy', row.OriginalReReadingTask.TaskName)}`
Object.keys(this.form).forEach(key => {
this.form[key] = null
})
this.loading = true
let res = await getReReadingOrBackInfluenceTaskList(
row.OriginalReReadingTaskId,
true,
row.Id
)
if (res.IsSuccess) {
this.InfluenceTaskList = res.Result
this.config.visible = true
this.loading = false
}
} catch (err) {
this.loading = false
console.log(err)
}
},
getInfluencedTaskList(row) {
this.loading = true
this.opentype = 'look'
@@ -663,7 +736,7 @@ export default {
return
}
if (type === 2) {
this.$refs.reasonForm.validate((valid) => {
this.$refs.imageBackform.validate((valid) => {
if (!valid) return
var params = {
data: {
@@ -675,7 +748,7 @@ export default {
NewReReadingTaskId: row.NewReReadingTaskId
}
],
RequestReReadingRejectReason: this.ConfirmReReadingForm.RequestReReadingRejectReason,
RequestReReadingRejectReason: this.form.RequestReReadingRejectReason,
TrialId: this.$route.query.trialId,
RequestReReadingResultEnum: type
},
@@ -688,7 +761,7 @@ export default {
this.btnLoading = false
this.$message.success(`${type === 1 ? this.$t('trials:spmAudit:title:title4') : this.$t('trials:spmAudit:title:title5')}`)
this.getList()
this.ConfirmReReadingVisible = false
this.config.visible = false
this.$refs['signForm'].btnLoading = false
this.signVisible = false
}).catch(() => {
@@ -720,7 +793,7 @@ export default {
this.loading = false
this.btnLoading = false
this.$message.success(`${type === 1 ? this.$t('trials:spmAudit:title:title4') : this.$t('trials:spmAudit:title:title5')}`)
this.ReReadingOrBackVisible = false
this.config.visible = false
this.$refs['signForm'].btnLoading = false
this.signVisible = false
this.getList()
@@ -787,22 +860,25 @@ export default {
}
</script>
<style lang="scss" scoped>
::v-deep .hidden-row{
::v-deep .hidden-row {
display: none;
}
::v-deep .el-dialog__body {
padding: 15px 20px;
}
::v-deep .el-tag--danger.el-tag--dark {
// background-color: #f56c6c!important;
border-color: none!important;
border-color: none !important;
// color: #fff!important;
}
::v-deep #TaskAllocationRuleList thead .el-checkbox__inner{
::v-deep #TaskAllocationRuleList thead .el-checkbox__inner {
display: none;
}
::v-deep .el-descriptions-item__label.has-colon:after{
::v-deep .el-descriptions-item__label.has-colon:after {
display: none;
}
</style>
@@ -5,17 +5,9 @@
<el-form :inline="true">
<!-- 文件类型 -->
<el-form-item :label="$t('trials:self-attachment:table:fileType')">
<el-select
v-model="searchData.FileTypeId"
clearable
style="width:150px;"
>
<el-option
v-for="item of typeOptions"
:key="item.FileTypeId"
:label="item.FileType"
:value="item.FileTypeId"
/>
<el-select v-model="searchData.FileTypeId" clearable style="width:150px;">
<el-option v-for="item of typeOptions" :key="item.FileTypeId" :label="item.FileType"
:value="item.FileTypeId" />
</el-select>
</el-form-item>
<!-- 文件名称 -->
@@ -26,7 +18,7 @@
<el-form-item :label="$t('trials:self-attachment:table:isSign')">
<el-select v-model="searchData.IsSign" clearable style="width:120px;">
<template v-for="item of $d.TrainingStatusEnum">
<el-option v-if="item.raw.ValueCN !== '无'" :label="item.label" :value="item.value" :key="item.id"/>
<el-option v-if="item.raw.ValueCN !== '无'" :label="item.label" :value="item.value" :key="item.id" />
</template>
</el-select>
</el-form-item>
@@ -44,104 +36,71 @@
</template>
<template slot="main-container">
<!-- 系统文件列表 -->
<el-table
ref="TrialAttachments"
v-loading="loading"
v-adaptive="{bottomOffset:60}"
:data="list"
stripe
height="100"
@sort-change="handleSortByColumn"
>
<el-table ref="TrialAttachments" v-loading="loading" v-adaptive="{ bottomOffset: 60 }" :data="list" stripe
height="100" @sort-change="handleSortByColumn">
<el-table-column type="selection" width="50" />
<el-table-column type="index" width="40" />
<!-- 文件类型 -->
<el-table-column
prop="FileType"
:label="$t('trials:self-attachment:table:fileType')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="FileType" :label="$t('trials:self-attachment:table:fileType')" show-overflow-tooltip
sortable="custom" />
<!-- 文件名称 -->
<el-table-column
prop="Name"
:label="$t('trials:self-attachment:table:fileName')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="Name" :label="$t('trials:self-attachment:table:fileName')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('trials:self-attachment:table:AttachmentCount')" prop="AttachmentCount"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-button type="text" @click.stop="openAttachment(scope.row, true)">{{ scope.row.AttachmentCount
}}</el-button>
</template>
</el-table-column>
<!-- 是否废除 -->
<el-table-column
prop="IsDeleted"
:label="$t('trials:self-attachment:table:isDeleted')"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="IsDeleted" :label="$t('trials:self-attachment:table:isDeleted')" show-overflow-tooltip
sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{ $fd('TrainingStatus', scope.row.IsDeleted) }}</el-tag>
<el-tag v-else type="primary">{{ $fd('TrainingStatus', scope.row.IsDeleted) }}</el-tag>
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column
prop="CreateTime"
:label="$t('trials:self-attachment:table:uploadTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="CreateTime" :label="$t('trials:self-attachment:table:uploadTime')" show-overflow-tooltip
sortable="custom" />
<!-- 是否签署 -->
<el-table-column
prop="ConfirmTime"
:label="$t('trials:self-attachment:table:isSign')"
show-overflow-tooltip
sortable="custom"
>
<el-table-column prop="ConfirmTime" :label="$t('trials:self-attachment:table:isSign')" show-overflow-tooltip
sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsConfirmed" type="primary">{{ $fd('TrainingStatusEnum', scope.row.IsConfirmed) }}</el-tag>
<el-tag v-if="scope.row.IsConfirmed" type="primary">{{ $fd('TrainingStatusEnum', scope.row.IsConfirmed)
}}</el-tag>
<el-tag v-else type="danger">{{ $fd('TrainingStatusEnum', scope.row.IsConfirmed) }}</el-tag>
</template>
</el-table-column>
<!-- 签署时间 -->
<el-table-column
prop="ConfirmTime"
:label="$t('trials:self-attachment:table:signTime')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column prop="ConfirmTime" :label="$t('trials:self-attachment:table:signTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
icon="el-icon-view"
circle
:title="$t('trials:self-attachment:action:preview')"
@click="handlePreview(scope.row)"
/>
<el-button icon="el-icon-view" circle :title="$t('trials:self-attachment:action:preview')"
@click="handlePreview(scope.row)" />
<!-- 签署 -->
<el-button
icon="el-icon-edit-outline"
circle
:disabled="!!scope.row.ConfirmTime"
:title="$t('trials:self-attachment:action:sign')"
@click="handleSign(scope.row)"
/>
<el-button icon="el-icon-edit-outline" circle :disabled="!!scope.row.ConfirmTime"
:title="$t('trials:self-attachment:action:sign')" @click="handleSign(scope.row)" />
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
</template>
<!-- 预览文件 -->
<el-dialog
v-if="previewVisible"
:visible.sync="previewVisible"
:title="title"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<el-dialog v-if="previewVisible" :visible.sync="previewVisible" :title="title" :fullscreen="true" append-to-body
custom-class="base-dialog-wrapper">
<span style="position: fixed; left: 16px; top: 45px;cursor: pointer;font-size: 18px;color:#409EFF"
@click.stop="openAttachment(currentRow)" v-if="currentRow.AttachmentCount">{{
$t('trials:self-attachment:table:AttachmentCount') }} ({{
currentRow.AttachmentCount }})</span>
<span v-if="!currentIsConfirm" style="position: fixed;right: 75px;top: 14px;">
<span style="color:red;margin-right:10px;">
<!-- 请仔细阅读文件并签名确认 -->
@@ -149,13 +108,8 @@
<span v-show="duration < currentMinMinutes * 60">{{ `(${currentMinMinutes * 60 - duration}s)` }}</span>
</span>
<!-- 签署 -->
<el-button
size="small"
type="primary"
:disabled="timer !== null || duration === 0"
:loading="btnLoading"
@click="handleConfirm"
>
<el-button size="small" type="primary" :disabled="timer !== null || duration === 0" :loading="btnLoading"
@click="handleConfirm">
{{ $t('common:button:sign') }}
<!-- {{ duration >= currentMinMinutes * 60?'确认':`确认(${currentMinMinutes * 60 - duration}s)` }} -->
</el-button>
@@ -167,19 +121,21 @@
</el-dialog>
<!-- 签名弹框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
append-to-body
>
<el-dialog v-if="signVisible" :visible.sync="signVisible" :close-on-click-modal="false" width="600px"
append-to-body>
<div slot="title">
<span style="font-size:18px;">{{ $t('common:dialogTitle:sign') }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${ currentUser })` }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${currentUser})` }}</span>
</div>
<SignForm :is-system-doc="currentRow.IsSystemDoc" :document-id="currentRow.Id" :file-name="fileName" :trial-id="trialId" @closeDialog="closeSignDialog" />
<SignForm :is-system-doc="currentRow.IsSystemDoc" :document-id="currentRow.Id" :file-name="fileName"
:trial-id="trialId" @closeDialog="closeSignDialog" />
</el-dialog>
<attachmentList2 v-if="config.visible && !currentRow.IsSystemDoc" :config="config" :rowData="currentRow"
:TrialDocumentId="TrialDocumentId" :isView="true" @getList="getList" />
<attachmentList v-if="config.visible && currentRow.IsSystemDoc" :config="config" :rowData="currentRow"
:SystemDocumentId="TrialDocumentId" :isView="true" @getList="getList" />
<attachmentPreview :SystemDocumentId="TrialDocumentId" :isTrial="!currentRow.IsSystemDoc"
:visible.sync="perview_visible" :isView="true" v-if="perview_visible" />
</BaseContainer>
</template>
<script>
@@ -189,6 +145,9 @@ import Pagination from '@/components/Pagination'
import PreviewFile from '@/components/PreviewFile/index'
import SignForm from './components/SignForm'
import store from '@/store'
import attachmentPreview from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentPreview'
import attachmentList from '@/views/dictionary/attachment/components/SignatureTemplate/attachmentList'
import attachmentList2 from '@/views/trials/trials-panel/setting/attachment/components/attachmentList'
const searchDataDefault = () => {
return {
FileTypeId: '',
@@ -202,7 +161,7 @@ const searchDataDefault = () => {
}
export default {
name: 'TrialAttachments',
components: { BaseContainer, Pagination, PreviewFile, SignForm },
components: { BaseContainer, Pagination, PreviewFile, SignForm, attachmentPreview, attachmentList, attachmentList2 },
data() {
return {
searchData: searchDataDefault(),
@@ -223,7 +182,14 @@ export default {
fileName: '',
currentUser: zzSessionStorage.getItem('userName'),
typeOptions: [],
trialId: this.$route.query.trialId
trialId: this.$route.query.trialId,
TrialDocumentId: null,
perview_visible: null,
config: {
visible: false,
title: this.$t('dictionary:signature:attachmentList:title'),
width: '800px',
},
}
},
mounted() {
@@ -240,6 +206,16 @@ export default {
}
},
methods: {
openAttachment(row, isList = false) {
if (!row.AttachmentCount) return false
this.TrialDocumentId = row.Id
this.currentRow = { ...row }
if (!isList) {
this.perview_visible = true
} else {
this.config.visible = true
}
},
//
getList() {
this.loading = true
@@ -336,8 +312,8 @@ export default {
//
this.$confirm(this.$t('trials:self-attachment:message:closeDocument')).then(() => {
this.previewVisible = false
}).catch(()=>{})
}).catch(() => { })
} else {
this.handleSign(res.Result)
}
@@ -729,7 +729,7 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0) {
if (readingTool === 0 || readingTool === 2 ) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${
@@ -766,7 +766,7 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0) {
if (readingTool === 0 || readingTool === 2 ) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${
@@ -801,7 +801,7 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId
var path = ''
if (readingTool === 0) {
if (readingTool === 0 || readingTool === 2 ) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${
@@ -277,7 +277,7 @@ export default {
}
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.preview-wrapper{
display: flex;
flex-direction: row !important;
@@ -1406,7 +1406,7 @@ export default {
)
var token = getToken()
var path = ''
if (row.ReadingTool === 0) {
if (row.ReadingTool === 0 || row.ReadingTool === 2) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${row.TrialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${row.TrialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
@@ -263,7 +263,7 @@ export default {
series: '',
ToolStateManager: null,
renderedMeasured: [],
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi'],
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe'],
measureData: [],
selectedLesion: null,
activeTool: 0, // 0:enable 1:passive 2:active
@@ -303,8 +303,8 @@ export default {
],
scrollSyncInfo: { offset: 0 },
hideMeasureArr: []
hideMeasureArr: [],
isInitWwwc: true
}
},
computed: {
@@ -565,7 +565,6 @@ export default {
e.stopPropagation()
e.preventDefault()
} else if (this.activeToolName === 'Length' || this.activeToolName === 'Bidirectional' && this.readingTaskState < 2) {
console.log(e.detail.image)
if (!e.detail.image.columnPixelSpacing || !e.detail.image.rowPixelSpacing) {
// ''
this.$confirm(this.$t('trials:reading:warnning:msg56'), '', {
@@ -578,6 +577,13 @@ export default {
e.stopPropagation()
e.preventDefault()
}
} else if (this.CriterionType === 21 && this.activeToolName === 'Probe' && this.readingTaskState < 2) {
if (!(e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME1' || e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME2')) {
this.$alert(this.$t('trials:MRIPDFF:message:message5'))
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
}
}
},
pointNearTool(e) {
@@ -607,7 +613,11 @@ export default {
if ((i.LesionType === 0 || i.LesionType === 1 || i.LesionType === 7) && i.IsFirstChangeTask) {
arr.push(i.OrderMarkName)
}
if (i.Id && this.readingTaskState >= 2) {
arr.push(i.OrderMarkName)
}
})
console.log(arr)
return arr
},
getMergeMarks(measureDatas) {
@@ -616,6 +626,9 @@ export default {
if ((i.LesionType === 0) && i.SplitOrMergeType === 1) {
arr.push(i.OrderMarkName)
}
if (i.Id && this.readingTaskState >= 2) {
arr.push(i.OrderMarkName)
}
})
return arr
},
@@ -661,7 +674,7 @@ export default {
},
sliderMousemove(e) {
if (!this.sliderInfo.isMove) return
console.log('sliderMousemove')
// console.log('sliderMousemove')
var PX = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
var boxHeight = this.$refs['sliderBox'].clientHeight
if (PX < 0) return
@@ -692,7 +705,7 @@ export default {
} else if (criterionType === 2) {
this.disabledMarks = this.getMergeMarks(this.visitTaskList[idx].MeasureData)
} else {
this.disabledMarks = []
this.disabledMarks = this.getDisabledMarks(this.visitTaskList[idx].MeasureData)
}
return true
},
@@ -785,6 +798,8 @@ export default {
} else if (toolType === 'Length') {
// toolState.data[i].length = this.calculateLenth(toolState.data[i])
}
measureData.largestPixelValue = image.imageFrame.largestPixelValue
measureData.imageId = imageId
measureData.studyId = this.stack.studyId
measureData.seriesId = this.stack.seriesId
measureData.instanceId = instanceId
@@ -901,6 +916,9 @@ export default {
}
} else if (this.activeTool === 1 && this.readingTaskState < 2) {
cornerstoneTools.setToolPassiveForElement(element, data.MeasureData.type, { mouseButtonMask: 1 })
} else if (this.readingTaskState >= 2 && this.isCurrentTask) {
// setToolPassiveForElement
cornerstoneTools.setToolEnabledForElement(element, data.MeasureData.type, { mouseButtonMask: 1 })
} else {
cornerstoneTools.setToolEnabledForElement(element, data.MeasureData.type, { mouseButtonMask: 1 })
}
@@ -919,6 +937,9 @@ export default {
}
}
})
if (this.readingTaskState >= 2 && this.activeToolName && this.isCurrentTask) {
cornerstoneTools.setToolActiveForElement(element, this.activeToolName, { mouseButtonMask: 1 })
}
},
setMeasureDataVisible() {
if (this.readingTaskState >= 2) return
@@ -986,6 +1007,7 @@ export default {
}
},
mouseClick(e) {
if (this.readingTaskState >= 2) return
const { element, currentPoints, image, viewport } = e.detail
var imageId = image.imageId
const imageInfo = this.getInstanceInfo(imageId)
@@ -1010,6 +1032,8 @@ export default {
var questionInfo = this.measureData[idx]
// const canvas = this.canvas.querySelector('canvas')
// measureData.pictureBaseStr = canvas.toDataURL('image/png', 1)
measureData.largestPixelValue = image.imageFrame.largestPixelValue
measureData.imageId = imageId
measureData.studyId = this.stack.studyId
measureData.seriesId = this.stack.seriesId
measureData.instanceId = instanceId
@@ -1035,6 +1059,7 @@ export default {
},
loadImageStack(dicomSeries) {
return new Promise(resolve => {
this.isInitWwwc = true
this.isCurrentTask = dicomSeries.isCurrentTask
this.isBaseline = dicomSeries.isBaseLineTask
this.readingTaskState = dicomSeries.readingTaskState
@@ -1073,7 +1098,8 @@ export default {
} else if (criterionType === 2) {
this.disabledMarks = this.getMergeMarks(this.visitTaskList[idx].MeasureData)
} else {
this.disabledMarks = []
// this.disabledMarks = []
this.disabledMarks = this.getDisabledMarks(this.visitTaskList[idx].MeasureData)
}
this.maxVistNum = this.visitTaskList[this.visitTaskList.length - 1].VisitTaskNum
@@ -1202,7 +1228,7 @@ export default {
this.stack.frame = this.stack.isExistMutiFrames ? parseInt(frame) : null
this.stack.instanceId = instanceId
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
// this.resetWwwc()
resolve()
})
},
@@ -1300,6 +1326,9 @@ export default {
this.scrollSyncInfo.offset = 0
}
this.renderMeasuredData(e)
if (this.isInitWwwc) {
this.resetWwwc()
}
},
getOrientationMarker(element) {
const enabledElement = cornerstone.getEnabledElement(element)
@@ -1336,6 +1365,8 @@ export default {
this.stack.frame = this.stack.isExistMutiFrames ? parseInt(frame) : null
if (e.detail.toolName === 'Length' || e.detail.toolName === 'ArrowAnnotate' || e.detail.toolName === 'RectangleRoi') {
const measureData = {}
measureData.largestPixelValue = element.image.imageFrame.largestPixelValue
measureData.imageId = imageId
measureData.studyId = this.stack.studyId
measureData.seriesId = this.stack.seriesId
measureData.instanceId = instanceId
@@ -1353,6 +1384,8 @@ export default {
cornerstoneTools.setToolPassiveForElement(this.canvas, e.detail.toolName)
} else if (e.detail.toolName === 'Bidirectional') {
const measureData = {}
measureData.largestPixelValue = element.image.imageFrame.largestPixelValue
measureData.imageId = imageId
measureData.studyId = this.stack.studyId
measureData.seriesId = this.stack.seriesId
measureData.instanceId = instanceId
@@ -1369,6 +1402,8 @@ export default {
cornerstoneTools.setToolPassiveForElement(this.canvas, e.detail.toolName)
} else if (e.detail.toolName === 'Probe') {
const measureData = {}
measureData.largestPixelValue = element.image.imageFrame.largestPixelValue
measureData.imageId = imageId
measureData.studyId = this.stack.studyId
measureData.seriesId = this.stack.seriesId
measureData.instanceId = instanceId
@@ -1478,6 +1513,8 @@ export default {
var questionInfo = this.measureData[idx]
// const canvas = this.canvas.querySelector('canvas')
// measureData.pictureBaseStr = canvas.toDataURL('image/png', 1)
measureData.largestPixelValue = element.image.imageFrame.largestPixelValue
measureData.imageId = imageId
measureData.studyId = this.stack.studyId
measureData.seriesId = this.stack.seriesId
measureData.instanceId = instanceId
@@ -1657,7 +1694,7 @@ export default {
cornerstoneTools.getToolState(
this.canvas,
'playClip'
).data[0].loop = false
).data[0].loop = true
} else {
cornerstoneTools.stopClip(this.canvas)
this.toolState.clipPlaying = false
@@ -1669,6 +1706,8 @@ export default {
},
resetWwwc() {
// console.log('resetWwwc')
this.isInitWwwc = true
this.toolState.viewportInvert = false
var viewport = cornerstone.getViewport(this.canvas)
// viewport.invert = false
@@ -1679,7 +1718,7 @@ export default {
},
setWwwc(ww, wc) {
// console.log('setWwwc', ww, wc)
this.isInitWwwc = false
var viewport = cornerstone.getViewport(this.canvas)
viewport.voi.windowWidth = ww
viewport.voi.windowCenter = wc
@@ -416,7 +416,7 @@
<dicom-canvas
v-if="canvasW"
:ref="`dicomCanvas${i-1}`"
:style="{width:canvasW,height: canvasH}"
:style="{width: fullScreenIndex === i-1 ? fullScreenWidth : canvasW,height: fullScreenIndex === i-1 ? fullScreenHeight : canvasH}"
:canvas-index="i-1"
:is-active="i-1===currentDicomCanvasIndex"
:is-scroll-sync="isScrollSync"
@@ -989,7 +989,10 @@ export default {
signVisible: false,
signCode: null,
currentUser: zzSessionStorage.getItem('userName'),
tmpData: null
tmpData: null,
fullScreenIndex: -1,
fullScreenWidth: window.innerWidth - 570 + 'px',
fullScreenHeight: window.innerHeight - 130 + 'px'
}
},
@@ -1379,22 +1382,25 @@ export default {
this.personalConfigDialog.visible = true
},
setCornerstoneStyle(i) {
if (this.layoutCol === 1 && this.layoutRow === 1) {
this.fullScreenIndex = -1
return
}
if (this.cornerstoneStyle.position) {
this.cornerstoneStyle = {}
this.setCanvasStyle()
this.fullScreenIndex = -1
} else {
this.cornerstoneStyle = {
position: 'absolute',
top: '72px',
top: '67px',
left: '0px',
right: '350px',
zIndex: 10
zIndex: 10,
}
this.canvasW = window.innerWidth - 570 + 'px'
this.canvasH = window.innerHeight - 130 + 'px'
this.fullScreenIndex = this.currentDicomCanvasIndex
}
this.$nextTick(() => {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].reloadCanvas()
for (var i = 0; i < this.maxCanvas; i++) {
this.$refs[`dicomCanvas${i}`][0].reloadCanvas()
}
@@ -1941,6 +1947,7 @@ export default {
},
//
changeLayout(name) {
this.fullScreenIndex = -1
if (this.activeTool) {
if (this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].isCurrentTask && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].readingTaskState < 2) {
this.$nextTick(() => {
@@ -2043,14 +2050,17 @@ export default {
if (i === -1) return
var isCurrentTask = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].isCurrentTask
var readingTaskState = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].readingTaskState
if (!isCurrentTask || readingTaskState >= 2) {
if (!isCurrentTask) {
this.measuredTools[i].isDisabled = true
e.target.style.cursor = 'not-allowed'
if (this.activeTool) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(toolName)
this.activeTool = ''
}
} else {
} else if (isCurrentTask && readingTaskState >= 2) {
this.measuredTools[i].isDisabled = false
e.target.style.cursor = 'pointer'
} else if (isCurrentTask && readingTaskState < 2) {
// var obj = this.$refs['measurementList'].isCanActiveTool(toolName, true)
var obj = this.$refs['measurementList'].isCanActiveTool(toolName, true)
this.measuredTools[i].disabledReason = obj.reason
@@ -2087,7 +2097,7 @@ export default {
var toolObj = this.measuredTools.find(i => i.toolName === toolName)
if (!toolObj || toolObj.isDisabled) return
var dicomSeries = this.canvasObj[this.currentDicomCanvasIndex]
if (dicomSeries.isCurrentTask && isMeasuredTool && dicomSeries.readingTaskState < 2) {
if (dicomSeries.isCurrentTask && isMeasuredTool) {
if (this.activeTool) {
this.measuredTools.forEach(item => {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
@@ -2248,13 +2258,14 @@ export default {
this.customWwc.visible = false
},
toggleInvert() {
if (this.activeTool === 'reversecolor') {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
this.activeTool = ''
} else {
this.activeTool = 'reversecolor'
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
}
// if (this.activeTool === 'reversecolor') {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
// this.activeTool = ''
// } else {
// this.activeTool = 'reversecolor'
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
// }
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
},
setImageIndexSync() {
this.isScrollSync = !this.isScrollSync
File diff suppressed because it is too large Load Diff
@@ -203,7 +203,6 @@ export default {
console.log(toolsUtilities)
this.subjectCode = this.$route.query.subjectCode
var element = document.getElementById(`viewport${this.index}`)
element.addEventListener(VOLUME_NEW_IMAGE, this.handleVolumeNewImage)
element.addEventListener(Enums.Events.CAMERA_MODIFIED, this.handleCameraModified)
element.addEventListener(Enums.Events.VOI_MODIFIED, this.handleVOIModified)
@@ -249,8 +248,10 @@ export default {
this.getOrientationMarker()
this.sliderBoxHeight = imageIndex * 100 / (this.seriesInfo.imageMaxLength - 1)
}
var properties = viewport.getProperties()
let properties = viewport.getProperties()
if (this.index === 3) {
properties = viewport.getProperties(`cornerstoneStreamingImageVolume:PT_VOLUME_ID`)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
@@ -324,7 +325,12 @@ export default {
viewport = renderingEngine.getViewport(this.viewportId)
if (!viewport) return
var properties = viewport.getProperties()
let properties = viewport.getProperties()
if (this.index === 3) {
// const volumeId = viewport.getVolumeId()
const volumeId = `cornerstoneStreamingImageVolume:PT_VOLUME_ID`
properties = viewport.getProperties(volumeId)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(
@@ -562,12 +568,21 @@ export default {
ctx.fillRect(0, 0, rectWidth, rectHeight)
},
setWwWc() {
var properties = viewport.getProperties()
let properties = viewport.getProperties()
if (this.index === 3) {
properties = viewport.getProperties(`cornerstoneStreamingImageVolume:PT_VOLUME_ID`)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const windowWidth = upper - lower
const windowCenter = (upper + lower) / 2
// console.log(lower, upper)
// const windowWidth = upper - lower
// const windowCenter = (upper + lower) / 2
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
this.$emit('upperRangeChange', Math.round(windowWidth))
}
},
async getScreenshots() {
@@ -4,7 +4,8 @@ import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunc
import { utilities } from '@cornerstonejs/core'
const { getColormap } = utilities.colormap
function setPetColorMapTransferFunctionForVolumeActor(
volumeInfo
volumeInfo,
isPT = false
) {
const { volumeActor, preset } = volumeInfo
const mapper = volumeActor.getMapper()
@@ -22,8 +23,14 @@ function setPetColorMapTransferFunctionForVolumeActor(
// Create scalar opacity function
const ofun = vtkPiecewiseFunction.newInstance()
ofun.addPoint(0, 0.0)
ofun.addPoint(0.1, 0.9)
if (isPT) {
ofun.addPoint(0, 0.0)
ofun.addPoint(0.1, 1.0)
} else {
ofun.addPoint(0, 0.0)
ofun.addPoint(0.1, 0.9)
}
ofun.addPoint(5, 1.0)
volumeActor.getProperty().setScalarOpacity(0, ofun)
@@ -8,39 +8,27 @@
<span style="margin-left:5px;">{{ taskBlindName }}</span>
</h3>
<div v-if="readingTaskState < 2">
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')" placement="bottom">
<i
class="el-icon-refresh-left"
@click="resetMeasuredData"
/>
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')"
placement="bottom">
<i class="el-icon-refresh-left" @click="resetMeasuredData" />
</el-tooltip>
</div>
</div>
<!-- 影像质量问题 -->
<div class="lesions">
<Questions
ref="ecrf"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="1"
/>
<Questions ref="ecrf" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
:group-classify="1" />
</div>
<!-- 测量问题 -->
<template v-if="questions.length > 0">
<div v-for="(qs,index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper" style="margin-bottom: 10px">
<div v-for="(qs, index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper"
style="margin-bottom: 10px">
<h4 v-if="qs.Type === 'group'" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?qs.GroupEnName:qs.GroupName }}
{{ language === 'en' ? qs.GroupEnName : qs.GroupName }}
</h4>
<div class="lesion_list">
<el-form
v-if="questions.length > 0"
:ref="`questions${index}`"
size="small"
:model="questionForm"
>
<el-form v-if="questions.length > 0" :ref="`questions${index}`" size="small" :model="questionForm">
<div class="table-wrapper">
<div v-for="item in qs.Childrens" :key="item.Id">
<div v-if="item.Type === 'basicTable'" class="flex-row" style="margin:3px 0;">
@@ -52,34 +40,25 @@
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType)">
<i class="el-icon-upload2" />
</div>
<div class="add-icon" @click.prevent="handleAddOrEdit('add',item)">
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
<i class="el-icon-plus" />
</div>
</div>
</div>
<el-table
v-if="item.Type === 'basicTable' && item.TableQuestions"
:ref="item.Id"
:data="item.TableQuestions.Answers"
>
<el-table v-if="item.Type === 'basicTable' && item.TableQuestions" :ref="item.Id"
:data="item.TableQuestions.Answers">
<!-- <el-table-column :label="$t('CustomizeQuestionFormItem:label:OrderMark')" width="60px" show-overflow-tooltip>
<template slot-scope="scope">
{{ getLesionName(item.OrderMark,scope.row.RowIndex) }}
</template>
</el-table-column> -->
</el-table-column> -->
<!-- <el-table-column
type="index"
width="40px"
/> -->
<el-table-column
v-for="q of item.TableQuestions.Questions"
:key="q.Id"
:prop="q.Id"
:label="q.QuestionName"
show-overflow-tooltip
:render-header="renderHeader"
>
<el-table-column v-for="q of item.TableQuestions.Questions" :key="q.Id" :prop="q.Id"
:label="q.QuestionName" show-overflow-tooltip :render-header="renderHeader">
<template slot-scope="scope">
<span v-if="q.Unit > 0 && !isNaN(parseFloat(scope.row[q.Id]))">
{{ `${scope.row[q.Id]} ${$fd('ValueUnit', parseInt(q.Unit))}` }}
@@ -92,14 +71,10 @@
</span>
</template>
</el-table-column>
<el-table-column
v-if="readingTaskState < 2 && item.LesionType === 102"
:label="$t('common:action:action')"
width="90px"
fixed="right"
>
<el-table-column v-if="readingTaskState < 2 && item.LesionType === 102"
:label="$t('common:action:action')" width="90px" fixed="right">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="handleAddOrEdit('edit',item, scope.$index)">
<el-button type="text" size="mini" @click="handleAddOrEdit('edit', item, scope.$index)">
{{ $t('common:button:edit') }}
</el-button>
<el-button type="text" size="mini" @click="handleDelete(item, scope.$index)">
@@ -111,41 +86,57 @@
<template v-else>
<!-- 数值 -->
<el-form-item
v-if="item.ShowQuestion!==2"
:key="item.Id"
:label="`${item.QuestionName}`"
:prop="item.Id"
:rules="[
{ required: (item.IsRequired === 0 || (item.IsRequired ===1 && item.RelevanceId && (item.RelevanceValue.includes(questionForm[item.RelevanceId])))) && item.Type!=='group' && item.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(item.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<el-form-item v-if="item.ShowQuestion !== 2" :key="item.Id" :label="`${item.QuestionName}`"
:prop="item.Id" :rules="[
{
required: (item.IsRequired === 0 || (item.IsRequired === 1 && item.RelevanceId && (item.RelevanceValue.includes(questionForm[item.RelevanceId])))) && item.Type !== 'group' && item.Type !== 'summary',
message: ['radio', 'select', 'checkbox'].includes(item.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']
},
]">
<!-- 数值类型 -->
<template v-if="item.Type==='textarea'">
<el-input
v-model="questionForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<template v-if="item.Type === 'textarea'">
<el-input v-model="questionForm[item.Id]" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
:disabled="!isCurrentTask || readingTaskState >= 2"
@change="((val) => { formItemChange(val, item) })" />
</template>
<template v-if="item.Type === 'number'">
<el-input-number v-model="questionForm[item.Id]"
:disabled="!isCurrentTask || readingTaskState >= 2" :precision="0"
@change="((val) => { formItemChange(val, item) })" />
</template>
<template v-if="item.Type === 'select'">
<el-select v-model="questionForm[item.Id]" :disabled="!isCurrentTask || readingTaskState >= 2"
@change="((val) => { formItemChange(val, item) })">
<el-option v-for="dict of $d[item.DictionaryCode]" :key="dict.id" :value="String(dict.value)"
:label="dict.label" />
</el-select>
</template>
</el-form-item>
<template v-if="item.Childrens && item.Childrens.length > 0">
<template v-for="child in item.Childrens">
<el-form-item :key="child.Id"
v-if="(child.ShowQuestion === 1 && child.ParentTriggerValueList.includes(String(questionForm[item.Id]))) || child.ShowQuestion === 0"
:label="`${child.QuestionName}`" :prop="child.Id" :rules="[
{
required: (child.IsRequired === 0 || (child.IsRequired === 1 && child.RelevanceId && (child.RelevanceValue.includes(questionForm[child.RelevanceId])))) && child.Type !== 'group' && child.Type !== 'summary',
message: ['radio', 'select', 'checkbox'].includes(child.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']
},
]">
<template v-if="child.Type === 'input'">
<el-input v-model="questionForm[child.Id]"
:disabled="!isCurrentTask || readingTaskState >= 2"
@change="((val) => { formItemChange(val, child) })" />
</template>
</el-form-item>
</template>
</template>
</template>
</div>
<div
v-if="isCurrentTask && readingTaskState<2 && qs.GroupClassify === 5"
class="base-dialog-footer"
style="text-align:right;margin-top:10px;"
>
<div v-if="isCurrentTask && readingTaskState < 2 && (qs.GroupClassify === 5 || qs.GroupClassify === 6)"
class="base-dialog-footer" style="text-align:right;margin-top:10px;">
<!-- 保存 -->
<el-button
type="primary"
size="mini"
:disabled="!formChanged"
@click="handleSave(index)"
>
<el-button type="primary" size="mini" :disabled="!formChanged" @click="handleSave(index)">
{{ $t('common:button:save') }}
</el-button>
</div>
@@ -156,51 +147,21 @@
</template>
<!-- 计算值 -->
<Questions
ref="ecrf2"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="4"
style="margin-top:20px"
/>
<Questions ref="ecrf2" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
:group-classify="4" style="margin-top:20px" />
<!-- 评估结果 -->
<Questions
ref="ecrf3"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="5"
/>
<Questions ref="ecrf3" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
:group-classify="5" />
<!-- 新增编辑弹窗 -->
<el-dialog
v-if="addOrEdit.visible"
:visible.sync="addOrEdit.visible"
:close-on-click-modal="false"
:title="addOrEdit.title"
width="500px"
>
<el-form
ref="tableQsForm"
v-loading="loading"
:model="qsForm"
size="small"
>
<QuestionTableFormItem
v-for="item in qsList"
:key="item.Id"
:question="item"
:question-form="qsForm"
:reading-task-state="readingTaskState"
@setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData"
/>
<el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false"
:title="addOrEdit.title" width="500px">
<el-form ref="tableQsForm" v-loading="loading" :model="qsForm" size="small">
<QuestionTableFormItem v-for="item in qsList" :key="item.Id" :question="item" :question-form="qsForm"
:reading-task-state="readingTaskState" @setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData" />
<el-form-item style="text-align: right">
<el-button
size="small"
@click="addOrEdit.visible = false"
>
<el-button size="small" @click="addOrEdit.visible = false">
{{ $t('common:button:cancel') }}
</el-button>
<!-- 保存 -->
@@ -211,17 +172,9 @@
</el-form>
</el-dialog>
<!-- 导入 -->
<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"
/>
<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" />
</el-dialog>
</div>
</div>
@@ -485,8 +438,22 @@ export default {
setMeasuredData(measureData) {
},
formItemChange() {
formItemChange(val, item) {
this.formChanged = true
if (item.Type === 'number') {
this.limitBlur(item.Id, item.ValueType)
}
if (question.Childrens.length > 0) {
this.resetChild(question.Childrens)
}
},
resetChild(obj) {
obj.forEach(i => {
this.resetData(i.Id)
if (i.Childrens && i.Childrens.length > 0) {
this.resetChild(i.Childrens)
}
})
},
limitBlur(qId, valueType) {
const value = this.questionForm[qId]
@@ -523,7 +490,7 @@ export default {
answers: answers
}
try {
await saveTaskQuestion(8, params)
await saveTaskQuestion(12, params)
this.$message.success(this.$t('common:message:savedSuccessfully'))
loading.close()
DicomEvent.$emit('getReportInfo', true)
@@ -578,6 +545,9 @@ export default {
},
receiveMsg(event) {
},
resetData(v) {
this.questionForm[v] = null
},
resetFormItemData(v) {
this.qsForm[v] = null
},
@@ -730,21 +700,25 @@ export default {
}
</script>
<style lang="scss" scoped>
.measurement-wrapper{
.measurement-wrapper {
height: 100%;
overflow-y: auto;
.container{
.container {
padding: 10px;
.basic-info{
.basic-info {
display: flex;
justify-content: space-between;
align-items: center;
h3{
h3 {
color: #ddd;
padding: 5px 0px;
margin: 0;
}
i{
i {
color: #fff;
font-size: 22px;
font-weight: bold;
@@ -752,14 +726,16 @@ export default {
}
}
}
.title{
.title {
padding: 5px;
font-weight: bold;
color: #ddd;
font-size: 15px;
}
.add-icon{
.add-icon {
display: inline-block;
padding: 5px;
font-weight: bold;
@@ -769,103 +745,123 @@ export default {
margin-bottom: 2px;
cursor: pointer;
}
.add-icon:hover{
.add-icon:hover {
background-color: #607d8b;
}
.flex-row{
.flex-row {
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: #424242;
}
.lesion_list{
.lesion_list {
position: relative;
::v-deep .el-form-item__label{
::v-deep .el-form-item__label {
color: #c3c3c3;
text-align: left;
}
::v-deep .el-input .el-input__inner{
::v-deep .el-input .el-input__inner {
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
::v-deep .el-textarea__inner{
::v-deep .el-textarea__inner {
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
::v-deep .el-form-item{
::v-deep .el-form-item {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
::v-deep .el-form-item__content{
::v-deep .el-form-item__content {
flex: 1;
}
::v-deep .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-select.is-disabled .el-input__inner{
::v-deep .el-input.is-disabled .el-input__inner {
background-color: #646464a1;
}
.el-form-item__content
.el-select{
::v-deep .el-select.is-disabled .el-input__inner {
background-color: #646464a1;
}
.el-form-item__content .el-select {
width: 100%;
}
}
.table-wrapper {
::-webkit-scrollbar {
width: 5px;
height: 8px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
::v-deep .el-table,
.el-table__expanded-cell {
background-color: #000;
color: #fff;
border-color: #444444;
}
::v-deep .el-table th,
.el-table tr {
background-color: #000;
color: #fff;
border-color: #444444;
}
::v-deep .el-table__body tr > td {
::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-table__fixed-right {
height: 100% !important;
}
// ::v-deep .el-table .cell {
// line-height: 20px;
// }
::v-deep .el-table__cell {
padding: 5px 0;
}
::v-deep.el-table__fixed-right-patch {
background-color: #000 !important;
border-color: #444444;
}
::v-deep.el-table__fixed-body-wrapper tr:hover > td {
::v-deep.el-table__fixed-body-wrapper tr:hover>td {
background-color: #000 !important;
}
::v-deep.el-table--scrollable-x .el-table__body-wrapper {
z-index: 2;
}
@@ -205,6 +205,7 @@
import { saveTableQuestionMark, submitTaskRowInfo, deleteTableQuestionMark, deleteSingleTableQuestionMark } from '@/api/reading'
import DicomEvent from './../DicomEvent'
import store from '@/store'
import * as cornerstone from 'cornerstone-core'
export default {
name: 'MeasurementForm',
props: {
@@ -444,7 +445,12 @@ export default {
//
measureData.data.remark = this.getLesionName(this.orderMark, this.activeQuestionMark)
}
const val = measureData.data.cachedStats.mean / 10
// const val = measureData.data.cachedStats.mean / 10
let val = parseFloat(measureData.data.cachedStats.mean)
// let imagePixelModule = cornerstone.metaData.get('imagePixelModule', measureData.imageId)
if (measureData.largestPixelValue >= 500) {
val = val / 10
}
this.$set(this.questionForm, measureData.tableQuestionId, val.toFixed(this.digitPlaces))
data = {
Id: '',
@@ -574,14 +580,26 @@ export default {
let params = {}
if (i > -1 && this.markList[i].measureData && this.markList[i].measureData.MeasureData) {
const measureData = this.markList[i].measureData.MeasureData
const tableQuestionId = this.markList[i].tableQuestionId
if (this.questionForm[tableQuestionId] > 100) {
const confirm = await this.$confirm(
this.$t('trials:MRIPDFF:message:message4'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
}
//
DicomEvent.$emit('getScreenshots', { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: measureData.OrderMarkName, lesionType: null, isMarked: !!measureData }, async val => {
params = Object.assign({}, this.markList[i].measureData)
if (val) {
const pictureObj = await this.uploadScreenshots(`${new Date().getTime()}`, val)
params.PicturePath = pictureObj.isSuccess ? this.$getObjectName(pictureObj.result.url) : ''
}
const tableQuestionId = this.markList[i].tableQuestionId
params.Answer = this.questionForm[tableQuestionId]
params.MeasureData = JSON.stringify(this.markList[i].measureData.MeasureData)
loading.close()
@@ -264,7 +264,6 @@ export default {
if (item.Type === 'table' && item.Id === obj.questionId) {
var idx = item.TableQuestions.Answers.findIndex(i => i.RowIndex === obj.rowIndex)
item.TableQuestions.Answers[idx].isMeasurable = obj.isMeasurable
console.log(obj.isMeasurable)
item.TableQuestions.Answers[idx].mean = obj.mean
item.TableQuestions.Answers[idx].saveTypeEnum = obj.saveTypeEnum
@@ -7,39 +7,28 @@
<span style="margin-left:5px;">{{ taskBlindName }}</span>
</h3>
<div v-if="readingTaskState < 2">
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')" placement="bottom">
<i
class="el-icon-refresh-left"
@click="resetMeasuredData"
/>
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')"
placement="bottom">
<i class="el-icon-refresh-left" @click="resetMeasuredData" />
</el-tooltip>
</div>
</div>
<!-- 影像质量问题 -->
<div class="lesions">
<Questions
ref="ecrf"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="1"
/>
<Questions ref="ecrf" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
:group-classify="1" />
</div>
<!-- 测量问题 -->
<template v-if="questions.length > 0">
<div v-for="(qs,index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper" style="margin-bottom: 10px">
<div v-for="(qs, index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper"
style="margin-bottom: 10px">
<h4 v-if="qs.Type === 'group'" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?qs.GroupEnName:qs.GroupName }}
{{ language === 'en' ? qs.GroupEnName : qs.GroupName }}
</h4>
<div class="lesion_list">
<el-form
v-if="questions.length > 0"
:ref="`questions${index}`"
size="small"
:model="questionForm"
>
<el-form v-if="questions.length > 0" :ref="`questions${index}`" size="small" :model="questionForm">
<div class="table-wrapper">
<div v-for="item in qs.Childrens" :key="item.Id">
<div v-if="item.Type === 'basicTable'" class="flex-row" style="margin:3px 0;">
@@ -51,35 +40,25 @@
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType)">
<i class="el-icon-upload2" />
</div>
<div class="add-icon" @click.prevent="handleAddOrEdit('add',item)">
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
<i class="el-icon-plus" />
</div>
</div>
</div>
<el-table
v-if="item.Type === 'basicTable' && item.TableQuestions"
:ref="item.Id"
:data="item.TableQuestions.Answers"
max-height="600"
>
<el-table v-if="item.Type === 'basicTable' && item.TableQuestions" :ref="item.Id"
:data="item.TableQuestions.Answers" max-height="600">
<!-- <el-table-column :label="$t('CustomizeQuestionFormItem:label:OrderMark')" width="60px" show-overflow-tooltip>
<template slot-scope="scope">
{{ getLesionName(item.OrderMark,scope.row.RowIndex) }}
</template>
</el-table-column> -->
</el-table-column> -->
<!-- <el-table-column
type="index"
width="40px"
/> -->
<el-table-column
v-for="q of item.TableQuestions.Questions"
:key="q.Id"
:prop="q.Id"
:label="q.QuestionName"
show-overflow-tooltip
:render-header="renderHeader"
>
<el-table-column v-for="q of item.TableQuestions.Questions" :key="q.Id" :prop="q.Id"
:label="q.QuestionName" show-overflow-tooltip :render-header="renderHeader">
<template slot-scope="scope">
<span v-if="q.Unit > 0 && !isNaN(parseFloat(scope.row[q.Id]))">
{{ `${scope.row[q.Id]} ${$fd('ValueUnit', parseInt(q.Unit))}` }}
@@ -92,17 +71,14 @@
</span>
</template>
</el-table-column>
<el-table-column
v-if="readingTaskState < 2"
:label="$t('common:action:action')"
width="90px"
fixed="right"
>
<el-table-column v-if="readingTaskState < 2" :label="$t('common:action:action')" width="90px"
fixed="right">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="handleAddOrEdit('edit',item, scope.$index)">
<el-button type="text" size="mini" @click="handleAddOrEdit('edit', item, scope.$index)">
{{ $t('common:button:edit') }}
</el-button>
<el-button v-if="item.LesionType === 112 || item.LesionType === 111" type="text" size="mini" @click="handleDelete(item, scope.$index)">
<el-button v-if="item.LesionType === 112 || item.LesionType === 111" type="text" size="mini"
@click="handleDelete(item, scope.$index)">
{{ $t('common:button:delete') }}
</el-button>
</template>
@@ -111,41 +87,52 @@
<template v-else>
<!-- 数值 -->
<el-form-item
v-if="item.ShowQuestion!==2"
:key="item.Id"
:label="`${item.QuestionName}`"
:prop="item.Id"
:rules="[
{ required: (item.IsRequired === 0 || (item.IsRequired ===1 && item.RelevanceId && (item.RelevanceValue.includes(questionForm[item.RelevanceId])))) && item.Type!=='group' && item.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(item.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<el-form-item v-if="item.ShowQuestion !== 2" :key="item.Id" :label="`${item.QuestionName}`"
:prop="item.Id" :rules="[
{
required: (item.IsRequired === 0 || (item.IsRequired === 1 && item.RelevanceId && (item.RelevanceValue.includes(questionForm[item.RelevanceId])))) && item.Type !== 'group' && item.Type !== 'summary',
message: ['radio', 'select', 'checkbox'].includes(item.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']
},
]">
<!-- 数值类型 -->
<template v-if="item.Type==='textarea'">
<el-input
v-model="questionForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<template v-if="item.Type === 'textarea'">
<el-input v-model="questionForm[item.Id]" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
:disabled="!isCurrentTask || readingTaskState >= 2"
@change="((val) => { formItemChange(val, item) })" />
</template>
<template v-if="item.Type === 'select'">
<el-select v-model="questionForm[item.Id]" :disabled="!isCurrentTask || readingTaskState >= 2"
@change="((val) => { formItemChange(val, item) })">
<el-option v-for="dict of $d[item.DictionaryCode]" :key="dict.id" :value="String(dict.value)"
:label="dict.label" />
</el-select>
</template>
</el-form-item>
<template v-if="item.Childrens && item.Childrens.length > 0">
<template v-for="child in item.Childrens">
<el-form-item :key="child.Id"
v-if="(child.ShowQuestion === 1 && child.ParentTriggerValueList.includes(String(questionForm[item.Id]))) || child.ShowQuestion === 0"
:label="`${child.QuestionName}`" :prop="child.Id" :rules="[
{
required: (child.IsRequired === 0 || (child.IsRequired === 1 && child.RelevanceId && (child.RelevanceValue.includes(questionForm[child.RelevanceId])))) && child.Type !== 'group' && child.Type !== 'summary',
message: ['radio', 'select', 'checkbox'].includes(child.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']
},
]">
<template v-if="child.Type === 'input'">
<el-input v-model="questionForm[child.Id]"
:disabled="!isCurrentTask || readingTaskState >= 2"
@change="((val) => { formItemChange(val, child) })" />
</template>
</el-form-item>
</template>
</template>
</template>
</div>
<div
v-if="isCurrentTask && readingTaskState<2 && qs.GroupClassify === 5"
class="base-dialog-footer"
style="text-align:right;margin-top:10px;"
>
<div v-if="isCurrentTask && readingTaskState < 2 && (qs.GroupClassify === 5 || qs.GroupClassify === 6)"
class="base-dialog-footer" style="text-align:right;margin-top:10px;">
<!-- 保存 -->
<el-button
type="primary"
size="mini"
:disabled="!formChanged"
@click="handleSave(index)"
>
<el-button type="primary" size="mini" :disabled="!formChanged" @click="handleSave(index)">
{{ $t('common:button:save') }}
</el-button>
</div>
@@ -156,50 +143,20 @@
</template>
<!-- 计算值 -->
<Questions
ref="ecrf2"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="4"
style="margin-top:20px"
/>
<Questions ref="ecrf2" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
:group-classify="4" style="margin-top:20px" />
<!-- 评估结果 -->
<Questions
ref="ecrf3"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="5"
/>
<el-dialog
v-if="addOrEdit.visible"
:visible.sync="addOrEdit.visible"
:close-on-click-modal="false"
:title="addOrEdit.title"
width="500px"
>
<el-form
ref="tableQsForm"
v-loading="loading"
:model="qsForm"
size="small"
>
<QuestionTableFormItem
v-for="item in qsList"
:key="item.Id"
:question="item"
:question-form="qsForm"
:reading-task-state="readingTaskState"
@setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData"
/>
<Questions ref="ecrf3" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
:group-classify="5" />
<el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false"
:title="addOrEdit.title" width="500px">
<el-form ref="tableQsForm" v-loading="loading" :model="qsForm" size="small">
<QuestionTableFormItem v-for="item in qsList" :key="item.Id" :question="item" :question-form="qsForm"
:reading-task-state="readingTaskState" @setFormItemData="setFormItemData"
@resetFormItemData="resetFormItemData" />
<el-form-item style="text-align: right">
<el-button
size="small"
@click="addOrEdit.visible = false"
>
<el-button size="small" @click="addOrEdit.visible = false">
{{ $t('common:button:cancel') }}
</el-button>
<!-- 保存 -->
@@ -210,18 +167,9 @@
</el-form>
</el-dialog>
<!-- 导入 -->
<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"
/>
<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" />
</el-dialog>
</div>
</div>
@@ -486,8 +434,22 @@ export default {
setMeasuredData(measureData) {
},
formItemChange() {
formItemChange(val, question) {
this.formChanged = true
if (item.Type === 'number') {
this.limitBlur(item.Id, item.ValueType)
}
if (question.Childrens.length > 0) {
this.resetChild(question.Childrens)
}
},
resetChild(obj) {
obj.forEach(i => {
this.resetData(i.Id)
if (i.Childrens && i.Childrens.length > 0) {
this.resetChild(i.Childrens)
}
})
},
limitBlur(qId, valueType) {
const value = this.questionForm[qId]
@@ -521,7 +483,7 @@ export default {
answers: answers
}
try {
await saveTaskQuestion(8, params)
await saveTaskQuestion(12, params)
this.$message.success(this.$t('common:message:savedSuccessfully'))
loading.close()
DicomEvent.$emit('getReportInfo', true)
@@ -576,6 +538,9 @@ export default {
},
receiveMsg(event) {
},
resetData(v) {
this.questionForm[v] = null
},
resetFormItemData(v) {
this.qsForm[v] = null
},
@@ -741,23 +706,26 @@ export default {
}
</script>
<style lang="scss" scoped>
.measurement-wrapper{
.measurement-wrapper {
height: 100%;
overflow-y: auto;
// overflow: hidden;
.container{
.container {
padding: 10px;
.basic-info{
.basic-info {
display: flex;
justify-content: space-between;
align-items: center;
h3{
h3 {
color: #ddd;
padding: 5px 0px;
margin: 0;
}
i{
i {
color: #fff;
font-size: 22px;
font-weight: bold;
@@ -765,14 +733,16 @@ export default {
}
}
}
.title{
.title {
padding: 5px;
font-weight: bold;
color: #ddd;
font-size: 15px;
}
.add-icon{
.add-icon {
display: inline-block;
padding: 5px;
font-weight: bold;
@@ -782,103 +752,123 @@ export default {
margin-bottom: 2px;
cursor: pointer;
}
.add-icon:hover{
.add-icon:hover {
background-color: #607d8b;
}
.flex-row{
.flex-row {
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: #424242;
}
.lesion_list{
.lesion_list {
position: relative;
::v-deep .el-form-item__label{
::v-deep .el-form-item__label {
color: #c3c3c3;
text-align: left;
}
::v-deep .el-input .el-input__inner{
::v-deep .el-input .el-input__inner {
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
::v-deep .el-textarea__inner{
::v-deep .el-textarea__inner {
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
::v-deep .el-form-item{
::v-deep .el-form-item {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
::v-deep .el-form-item__content{
::v-deep .el-form-item__content {
flex: 1;
}
::v-deep .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-select.is-disabled .el-input__inner{
::v-deep .el-input.is-disabled .el-input__inner {
background-color: #646464a1;
}
.el-form-item__content
.el-select{
::v-deep .el-select.is-disabled .el-input__inner {
background-color: #646464a1;
}
.el-form-item__content .el-select {
width: 100%;
}
}
.table-wrapper {
::-webkit-scrollbar {
width: 5px;
height: 8px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
::v-deep .el-table,
.el-table__expanded-cell {
background-color: #000;
color: #fff;
border-color: #444444;
}
::v-deep .el-table th,
.el-table tr {
background-color: #000;
color: #fff;
border-color: #444444;
}
::v-deep .el-table__body tr > td {
::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-table__fixed-right {
height: 100% !important;
}
// ::v-deep .el-table .cell {
// line-height: 20px;
// }
::v-deep .el-table__cell {
padding: 5px 0;
}
::v-deep.el-table__fixed-right-patch {
background-color: #000 !important;
border-color: #444444;
}
::v-deep.el-table__fixed-body-wrapper tr:hover > td {
::v-deep.el-table__fixed-body-wrapper tr:hover>td {
background-color: #000 !important;
}
::v-deep.el-table--scrollable-x .el-table__body-wrapper {
z-index: 2;
}
@@ -1624,7 +1624,7 @@ export default {
cornerstoneTools.getToolState(
this.canvas,
'playClip'
).data[0].loop = false
).data[0].loop = true
} else {
cornerstoneTools.stopClip(this.canvas)
this.toolState.clipPlaying = false
@@ -556,7 +556,7 @@
<dicom-canvas
v-if="canvasW"
:ref="`dicomCanvas${i - 1}`"
:style="{ width: canvasW, height: canvasH }"
:style="{width: fullScreenIndex === i-1 ? fullScreenWidth : canvasW,height: fullScreenIndex === i-1 ? fullScreenHeight : canvasH}"
:canvas-index="i - 1"
:is-active="i - 1 === currentDicomCanvasIndex"
:is-scroll-sync="isScrollSync"
@@ -895,6 +895,9 @@ export default {
uploadTrialCriterion: {},
uploadStatus: 'upload',
taskId: '',
fullScreenIndex: -1,
fullScreenWidth: window.innerWidth - 570 + 'px',
fullScreenHeight: window.innerHeight - 128 + 'px'
}
},
@@ -1314,22 +1317,25 @@ export default {
this.personalConfigDialog.visible = true
},
setCornerstoneStyle(i) {
if (this.layoutCol === 1 && this.layoutRow === 1) {
this.fullScreenIndex = -1
return
}
if (this.cornerstoneStyle.position) {
this.cornerstoneStyle = {}
this.setCanvasStyle()
this.fullScreenIndex = -1
} else {
this.cornerstoneStyle = {
position: 'absolute',
top: '72px',
top: '70px',
left: '205px',
right: '350px',
zIndex: 10,
}
this.canvasW = window.innerWidth - 570 + 'px'
this.canvasH = window.innerHeight - 130 + 'px'
this.fullScreenIndex = this.currentDicomCanvasIndex
}
this.$nextTick(() => {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].reloadCanvas()
for (var i = 0; i < this.maxCanvas; i++) {
this.$refs[`dicomCanvas${i}`][0].reloadCanvas()
}
@@ -1928,6 +1934,7 @@ export default {
},
//
changeLayout(name) {
this.fullScreenIndex = -1
if (this.activeTool) {
if (
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0]
@@ -2301,15 +2308,16 @@ export default {
this.customWwc.visible = false
},
toggleInvert() {
if (this.activeTool === 'reversecolor') {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
this.activeTool = ''
} else {
this.activeTool = 'reversecolor'
this.$refs[
`dicomCanvas${this.currentDicomCanvasIndex}`
][0].toggleInvert()
}
// if (this.activeTool === 'reversecolor') {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
// this.activeTool = ''
// } else {
// this.activeTool = 'reversecolor'
// this.$refs[
// `dicomCanvas${this.currentDicomCanvasIndex}`
// ][0].toggleInvert()
// }
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
},
setImageIndexSync() {
this.isScrollSync = !this.isScrollSync
@@ -69,6 +69,10 @@
:rules="[
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (question.RelevanceValueList.includes(isNaN(parseFloat(questionForm[question.RelevanceId])) ? questionForm[question.RelevanceId] : questionForm[question.RelevanceId].toString())))) && question.Type!=='group' && question.Type!=='summary',
message: $t('common:ruleMessage:specify'), trigger: ['blur', 'change']},
{
validator: question.Type === 'number' && !question.TypeValue ? validatorNumberInput :(rule,value,callback )=>{callback()},
trigger: ['blur', 'change']
}
]"
:class="[question.Type==='group'?'mb':question.Type==='upload'?'uploadWrapper':'']"
>
@@ -228,11 +232,12 @@
/>
</el-select>
<el-input
type="number"
type="text"
v-if="question.Type === 'number' && !question.TypeValue && question.DataSource !== 1"
@change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)"
@blur="handleBlur(questionForm[question.Id], questionForm, question.Id)"
v-model="questionForm[question.Id]"
v-model.trim="questionForm[question.Id]"
:disabled="readingTaskState === 2"
>
<!-- <template slot="append">1</template> -->
@@ -240,11 +245,12 @@
<template slot="append" v-else-if="question.ValueType === 2">%</template>
</el-input>
<el-input
type="number"
type="text"
@input="numberInput(question.Id)"
v-if="question.Type === 'number' && !question.TypeValue && question.DataSource === 1"
@blur="handleBlur(questionForm[question.Id], questionForm, question.Id)"
:disabled="question.DataSource === 1 || readingTaskState === 2"
v-model="questionForm[question.Id]"
v-model.trim="questionForm[question.Id]"
>
<!-- <template slot="append">2</template> -->
<template slot="append" v-if="question.Unit !== 0">{{question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit}}</template>
@@ -456,7 +462,7 @@ export default {
deep: true,
immediate: true,
handler(v, oldv) {
console.log(v)
// console.log(v)
}
}
},
@@ -502,6 +508,21 @@ export default {
}
},
methods: {
numberInput(id) {
this.questionForm[id] = this.questionForm[id].toUpperCase();
},
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')));
} else {
if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
}else{
callback();
}
}
},
limitInput(value, a, b) {
if (value.indexOf('.') > -1) {
if (value.split('.')[1].length >= this.digitPlaces) {
@@ -510,7 +531,10 @@ export default {
}
},
handleBlur(value, a, b) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
if (!value) return false
if(!isNaN(parseFloat(value))) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
}
},
deleteTableCol(row, index) {
this.$confirm(this.$t('trials:uploadNonDicoms:message:msg1')).then(() => {
@@ -1085,8 +1109,6 @@ export default {
flex-direction: row;
align-items: flex-start;
}
::v-deep .el-form-item__content{
}
.el-input{
width:100%;
}
@@ -7,6 +7,10 @@
:rules="[
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && !!~question.RelevanceValueList.indexOf(questionForm[question.RelevanceId]))) && question.Type!=='group' && question.Type!=='summary',
message: $t('common:ruleMessage:select'), trigger: ['blur', 'change']},
{
validator: question.Type === 'number' && !question.TypeValue ? validatorNumberInput :(rule,value,callback )=>{callback()},
trigger: ['blur', 'change']
}
]"
:class="[question.Type==='group'?'mb':question.Type==='upload'?'uploadWrapper':'']"
>
@@ -144,21 +148,23 @@
<!-- 数值 -->
<!-- :precision="2" :step="0.1" :max="10" -->
<el-input
type="number"
type="text"
v-if="question.Type === 'number' && question.DataSource !== 1"
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !IsBaseline && questionForm.IsCurrentTaskAdd === 'False')"
@change="((val)=>{formItemNumberChange(val, question)})"
@input="numberInput(question.Id)"
@blur="handleBlur(questionForm[question.Id], questionForm, question.Id)"
v-model="questionForm[question.Id]"
v-model.trim="questionForm[question.Id]"
>
<template slot="append" v-if="question.Unit !== 0">{{question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit}}</template>
</el-input>
<el-input
type="number"
type="text"
v-if="question.Type === 'number' && question.DataSource === 1"
:disabled="question.DataSource === 1"
@input="numberInput(question.Id, true )"
@blur="handleCalculationBlur(calculationValue)"
v-model="calculationValue"
v-model.trim="calculationValue"
>
<template slot="append" v-if="question.Unit !== 0">{{question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit}}</template>
</el-input>
@@ -331,7 +337,6 @@ export default {
this.fileList.push({ name: '', url: `${url}` })
})
}
console.log('11')
}
if (this.type === 'edit') return
// if (this.question.Type === 'number') {
@@ -342,6 +347,25 @@ export default {
// }
},
methods: {
numberInput(id,notId = false) {
if(notId ) {
this.calculationValue = this.calculationValue.toUpperCase();
}else {
this.questionForm[id] = this.questionForm[id].toUpperCase();
}
},
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')));
} else {
if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
}else{
callback();
}
}
},
save() {
},
openAddTableCol(row) {
@@ -382,10 +406,17 @@ export default {
}
},
handleBlur(value, a, b) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
if (!value) return false
if(!isNaN(parseFloat(value))) {
this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
}
// this.$set(a, b, parseFloat(value).toFixed(this.digitPlaces))
},
handleCalculationBlur(v) {
this.calculationValue = parseFloat(v).toFixed(this.digitPlaces)
if (!v) return false
if(!isNaN(parseFloat(v))) {
this.calculationValue = parseFloat(v).toFixed(this.digitPlaces)
}
},
limitInput(value, q) {
console.log(value)
@@ -488,7 +519,8 @@ export default {
return num.toFixed(this.digitPlaces)
},
formItemNumberChange(v, question) {
this.$emit('formItemTableNumberChange', v, question)
this.$emit('formItemTableNumberChange')
this.$emit('setFormItemData', { key: question.Id, val: v, question: question })
// this.$emit('formItemTableNumberChange', v, question)
},
resetChild(obj) {
@@ -137,7 +137,7 @@ export default {
this.classArr.push({triggerId: v.ClassifyQuestionId, classId: v.Id, classifyAlgorithms: v.ClassifyAlgorithms, classifyType: v.ClassifyType})
}
if (v.Type === 'number') {
this.$set(this.questionForm, v.Id, v.Answer === '' ? '' : parseFloat(v.Answer).toFixed(this.digitPlaces))
this.$set(this.questionForm, v.Id, isNaN(parseFloat(v.Answer)) ? v.Answer : parseFloat(v.Answer).toFixed(this.digitPlaces))
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
@@ -191,7 +191,7 @@ export default {
this.$set(this.questionForm, v.Id, v.TableQuestions.Answers)
}
if (v.Type === 'number') {
this.$set(this.questionForm, v.Id, v.Answer === '' ? '' : parseFloat(v.Answer).toFixed(this.digitPlaces))
this.$set(this.questionForm, v.Id, isNaN(parseFloat(v.Answer)) ? v.Answer : parseFloat(v.Answer).toFixed(this.digitPlaces))
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
@@ -212,7 +212,7 @@ export default {
i.TableQuestions.Questions.forEach(o => {
if (o.Type === 'number') {
i.TableQuestions.Answers.forEach((ite, index) => {
this.$set(i.TableQuestions.Answers[index], o.Id, i.TableQuestions.Answers[index][o.Id] ? parseFloat(i.TableQuestions.Answers[index][o.Id]).toFixed(this.digitPlaces) : null)
this.$set(i.TableQuestions.Answers[index], o.Id, isNaN(parseFloat(i.TableQuestions.Answers[index][o.Id])) ? i.TableQuestions.Answers[index][o.Id] : parseFloat(i.TableQuestions.Answers[index][o.Id]).toFixed(this.digitPlaces))
})
}
})
@@ -222,7 +222,7 @@ export default {
this.classArr.push({triggerId: i.ClassifyQuestionId, classId: i.Id, classifyAlgorithms: i.ClassifyAlgorithms, classifyType: i.ClassifyType})
}
if (i.Type === 'number') {
this.$set(this.questionForm, i.Id, i.Answer === '' ? '' : parseFloat(i.Answer).toFixed(this.digitPlaces))
this.$set(this.questionForm, i.Id, isNaN(parseFloat(i.Answer)) ? i.Answer : parseFloat(i.Answer).toFixed(this.digitPlaces))
}
if (i.Childrens && i.Childrens.length > 0) {
this.setChild(i.Childrens)
@@ -233,9 +233,7 @@ export default {
this.questionForm[v] = ''
},
setFormItemData(obj) {
console.log('setFormItemData', obj)
this.$set(this.questionForm, obj.key, JSON.parse(JSON.stringify(obj.val)))
console.log(this.questionForm)
this.classArr.map(i=>{
if (i.triggerId === obj.key) {
let answer = null
@@ -1,7 +1,10 @@
<template>
<div ref="container" style="width:100%;height:100%" class="dicom-container">
<!-- 访视阅片 -->
<div v-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
<div v-if="readingCategory=== 1 && (CriterionType === 7 || ((CriterionType === 1 || CriterionType === 0) && readingVersionEnum === 1)) " class="reading-wrapper">
<VisitReview :reading-tool="readingTool" />
</div>
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeave">
<!-- 阅片 -->
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
@@ -29,7 +32,7 @@
</el-tab-pane>
</el-tabs>
</div>
<div v-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType === 0" class="reading-wrapper">
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType === 0" class="reading-wrapper">
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeaveCustomize">
<!-- 阅片 -->
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
@@ -171,6 +174,7 @@
</template>
<script>
import { getNextTask, readClinicalData, verifyDefaultQuestionBeAnswer } from '@/api/trials'
import VisitReview from './../dicoms3D/components/VisitReview'
import ReadPage from './components/ReadPage'
import CustomizeReadPage from './customize/CustomizeReadPage'
import ReportPage from './components/ReportPage'
@@ -187,6 +191,7 @@ import requestPoolManager from '@/utils/request-pool'
export default {
name: 'Reading',
components: {
VisitReview,
ReadPage,
ReportPage,
GlobalReview,
@@ -217,7 +222,7 @@ export default {
isReadingTaskViewInOrder: null,
firstTaskReadingCategory: null,
criterionType: null,
readingTool: null,
readingTool: 0,
dialogVisible: false,
TrialReadingCriterionId: null,
isNewSubject: null,
@@ -229,7 +234,8 @@ export default {
isFullscreen: false,
tipVisible: false,
closeCDVisible: false,
cdVisitTaskId: ''
cdVisitTaskId: '',
readingVersionEnum: null
}
},
mounted() {
@@ -266,7 +272,7 @@ export default {
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
// this.isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
// this.criterionType = this.$router.currentRoute.query.criterionType
// this.readingTool = this.$router.currentRoute.query.readingTool
this.readingTool = this.$router.currentRoute.query.readingTool ? Number(this.$router.currentRoute.query.readingTool) : 0
this.TrialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
// this.isNewSubject = this.$router.currentRoute.query.isNewSubject
@@ -341,6 +347,7 @@ export default {
localStorage.setItem('IsExistUnprocessedFeedback', res.Result.IsExistUnprocessedFeedback)
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
this.readingCategory = res.Result.ReadingCategory
this.readingVersionEnum = res.Result.ReadingVersionEnum
this.questionFormChangeState = false
this.questionFormChangeNum = 0
if (this.isExistsClinicalData && this.isNeedReadClinicalData && !this.isReadClinicalData) {
@@ -589,6 +596,10 @@ export default {
position: relative;
}
}
::v-deep .el-radio__input.is-disabled.is-checked .el-radio__inner {
background-color: #428bca;
border-color: #428bca;
}
.full-dialog-container{
::v-deep.is-fullscreen .el-dialog__body{
@@ -0,0 +1,276 @@
<template>
<el-form ref="fusionForm" :model="fusionForm" label-width="120px" label-position="left">
<!-- 任务名称 -->
<el-form-item :label="$t('trials:lugano:fusionDialog:label:taskBlindName')" prop="taskBlindName">
<el-select v-model="fusionForm.visitTaskId" clearable @change="handleTaskIdChange" disabled>
<el-option v-for="item in taskList" :key="item.VisitTaskId" :label="item.TaskBlindName"
:value="item.VisitTaskId" />
</el-select>
</el-form-item>
<!-- 检查 -->
<el-form-item :label="$t('trials:lugano:fusionDialog:label:study')" prop="studyId" :rules="[
{ required: true, message: $t('common:ruleMessage:select'), trigger: 'blur' }
]">
<el-select v-model="fusionForm.studyId" clearable @change="handleStudyIdChange">
<el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode" :value="item.StudyId" />
</el-select>
</el-form-item>
<!-- 融合图像 -->
<label style="color: #dfdfdf;line-height: 36px;vertical-align: middle;font-size: 14px;">{{
$t('trials:lugano:fusionDialog:label:fusionImages') }}</label>
<div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom:10px;"
class="series-table">
<div style="border: 1px solid #5e5e5e;border-radius: 5px;padding: 0 10px;">
<!-- CT/MRI序列 -->
<h3 style="color:#ddd">{{ $t('trials:lugano:fusionDialog:label:ctSeries') }}</h3>
<el-table ref="ctSeries" :data="ctSeries" :show-header="false" style="width: 380px" size="mini" height="300"
:default-sort="{ prop: 'instanceCount', order: 'descending' }" @selection-change="handleCTSelectionChange"
@select="handleCTSelect">
<el-table-column type="selection" width="30" />
<el-table-column label="" width="100">
<template slot-scope="scope">
<el-image style="width: 60px; height: 60px"
:src="`${OSSclientConfig.basePath}${scope.row.ImageResizePath}`" fit="fit" crossorigin="anonymous" />
</template>
</el-table-column>
<el-table-column label="" min-width="50" show-overflow-tooltip>
<template slot-scope="scope">
<div>#{{ scope.row.SeriesNumber }} </div>
<div>{{ scope.row.Modality }}: {{ scope.row.InstanceCount }} images T: {{
parseFloat(scope.row.SliceThickness).toFixed(digitPlaces) }}</div>
<div>{{ scope.row.Description }}</div>
</template>
</el-table-column>
</el-table>
</div>
<div style="border: 1px solid #5e5e5e;border-radius: 5px;padding: 0 10px;">
<!-- PET序列 -->
<h3 style="color:#ddd">{{ $t('trials:lugano:fusionDialog:label:ptSeries') }}</h3>
<el-table ref="petSeries" :data="petSeries" :show-header="false" style="width: 380px" size="mini" height="300"
@selection-change="handlePTSelectionChange" @select="handlePTSelect">
<el-table-column type="selection" width="30" />
<el-table-column label="" width="100">
<template slot-scope="scope">
<el-image style="width: 60px; height: 60px"
:src="`${OSSclientConfig.basePath}${scope.row.ImageResizePath}`" fit="fit" crossorigin="anonymous" />
</template>
</el-table-column>
<el-table-column label="" min-width="50" show-overflow-tooltip>
<template slot-scope="scope">
<div>#{{ scope.row.SeriesNumber }} </div>
<div>{{ scope.row.Modality }}: {{ scope.row.InstanceCount }} images T: {{
parseFloat(scope.row.SliceThickness).toFixed(digitPlaces) }}</div>
<div>{{ scope.row.Description }}</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-form-item style="text-align:right;">
<!-- 取消 -->
<el-button size="mini" @click="handleCancel">{{ $t('common:button:cancel') }}</el-button>
<!-- 确认 -->
<el-button type="primary" size="mini" @click="handleSubmitFusionSeries">
{{ $t('common:button:confirm') }}</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: 'FusionForm',
props: {
taskList: {
type: Array,
default: () => {
return []
}
},
activeTaskIndex: {
type: Number,
default: 0
}
},
data() {
return {
fusionForm: {
visitTaskId: '',
studyId: '',
taskBlindName: '',
isBaseLineTask: null,
ctSeriesInfo: {},
petSeriesInfo: {},
defaultStudyId: '',
defaultCTSeriesId: '',
defaultPTSeriesId: ''
},
studyList: [],
ctSeries: [],
petSeries: [],
petctWindow: null,
digitPlaces: 2
}
},
mounted() {
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.initForm()
},
methods: {
initForm() {
if (this.taskList.length === 0) return
this.getStudyList(this.taskList[this.activeTaskIndex])
this.handleStudyIdChange(this.studyList[0].StudyId)
if (this.studyList.length > 0) {
this.fusionForm.studyId = this.studyList[0].StudyId
this.handleStudyIdChange(this.studyList[0].StudyId)
} else {
this.fusionForm.studyId = ''
this.ctSeries = []
this.petSeries = []
}
this.fusionForm.visitTaskId = this.taskList[this.activeTaskIndex].VisitTaskId
this.fusionForm.readingTaskState = this.taskList[this.activeTaskIndex].ReadingTaskState
this.fusionForm.taskBlindName = this.taskList[this.activeTaskIndex].TaskBlindName
this.fusionForm.subjectCode = this.taskList[this.activeTaskIndex].SubjectCode
this.fusionForm.isBaseLineTask = this.taskList[this.activeTaskIndex].IsBaseLineTask
this.fusionForm.isCurrentTask = this.taskList[this.activeTaskIndex].IsCurrentTask
},
getStudyList(obj) {
if (obj) {
var studyList = obj.StudyList || []
studyList = studyList.filter(i => !i.IsCriticalSequence && i.Modalities.indexOf('CT') !== -1 && i.Modalities.indexOf('PT') !== -1)
if (studyList.length === 0) return
this.studyList = studyList
}
},
handleSubmitFusionSeries() {
this.$refs['fusionForm'].validate((valid) => {
if (!valid) return
if (Object.keys(this.fusionForm.ctSeriesInfo).length === 0 || Object.keys(this.fusionForm.petSeriesInfo).length === 0) {
// ''
this.$confirm(this.$t('trials:lugano:fusionDialog:message:checkSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
showCancelButton: false,
type: 'warning'
}).then(() => { }).catch(() => { })
return
}
var count = Math.abs(this.fusionForm.ctSeriesInfo.InstanceCount - this.fusionForm.petSeriesInfo.InstanceCount)
if (count > 10) {
// ', ?'
this.$confirm(this.$t('trials:lugano:fusionDialog:message:validSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
type: 'warning'
}).then(() => {
this.fusion()
}).catch(() => { })
} else {
this.fusion()
}
})
},
fusion() {
this.$emit('fusion', { ct: this.fusionForm.ctSeriesInfo, pt: this.fusionForm.petSeriesInfo })
},
handleCancel() {
this.$emit('close')
},
handleTaskIdChange(v) {
var idx = this.taskList.findIndex(i => i.VisitTaskId === v)
this.studyList = idx > -1 ? this.getStudyList(this.taskList[idx]) : []
this.fusionForm.taskBlindName = idx > -1 ? this.taskList[idx].TaskBlindName : ''
this.fusionForm.isBaseLineTask = idx > -1 ? this.taskList[idx].IsBaseLineTask : null
this.studyList = idx > -1 ? this.taskList[idx].StudyList : null
this.fusionForm.studyId = ''
this.fusionForm.defaultStudyId = idx > -1 ? this.taskList[idx].StudyId : ''
this.fusionForm.defaultCTSeriesId = idx > -1 ? this.taskList[idx].CTSeriesId : ''
this.fusionForm.defaultPTSeriesId = idx > -1 ? this.taskList[idx].PTSeriesId : ''
this.ctSeries = []
this.petSeries = []
},
handleStudyIdChange(v) {
var i = this.studyList.findIndex(i => i.StudyId === v)
if (i === -1) {
this.ctSeries = []
this.petSeries = []
} else {
var seriesList = this.studyList[i].SeriesList
var series = seriesList.filter(series => series.Modality === 'CT')
this.ctSeries = series.sort((a, b) => b.instanceCount - a.instanceCount)
series = seriesList.filter(series => series.Modality === 'PT')
this.petSeries = series.sort((a, b) => b.instanceCount - a.instanceCount)
}
},
handleCTSelectionChange(rows) {
if (rows.length > 0) {
this.fusionForm.ctSeriesInfo = Object.assign({}, rows[0])
} else {
this.fusionForm.ctSeriesInfo = {}
}
},
handleCTSelect(selection) {
if (selection.length > 1) {
const del_row = selection.shift()
this.$refs.ctSeries.toggleRowSelection(del_row, false)
}
},
handlePTSelectionChange(rows) {
if (rows.length > 0) {
this.fusionForm.petSeriesInfo = Object.assign({}, rows[0])
} else {
this.fusionForm.petSeriesInfo = {}
}
},
handlePTSelect(selection) {
if (selection.length > 1) {
const del_row = selection.shift()
this.$refs.petSeries.toggleRowSelection(del_row, false)
}
}
}
}
</script>
<style lang="scss" scoped>
.series-table {
::v-deep.el-table {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
::v-deep.el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
border-bottom: 1px solid #dfdfdf;
}
.el-table--border::after,
.el-table--group::after,
.el-table::before {
background-color: #1e1e1e;
}
::v-deep.el-table__header-wrapper {
th {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
}
::v-deep.el-table__body-wrapper {
tr {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
tr:hover>td {
background-color: #1e1e1e !important;
}
}
::v-deep.el-table__empty-block {
background-color: #1e1e1e !important;
}
}
</style>
@@ -0,0 +1,970 @@
<template>
<div ref="viewport-fusion" class="viewport-wrapper" @mouseup="sliderMouseup" @mousemove="sliderMousemove"
@mouseleave="sliderMouseleave" :style="{ color: series.Modality === 'PT' || isMip ? '#666' : '#ddd' }">
<div v-if="series && taskInfo" class="left-top-text">
<div v-if="taskInfo.IsExistsClinicalData && !isMip && !isFusion" class="cd-info"
:title="$t('trials:reading:button:clinicalData')">
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
@click.stop="viewCD(series.TaskInfo.VisitTaskId)" />
</div>
<h2 v-if="taskInfo.IsReadingShowSubjectInfo && series.TaskInfo" class="subject-info">
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
</h2>
<div v-if="!isMip && !isFusion">Series: #{{ series.SeriesNumber }}</div>
<div v-if="series.Stack && !isMip">Image: #{{ `${series.SliceIndex + 1}/${series.Stack.length}` }}</div>
<div v-if="!isMip && !isFusion">{{ series.Modality }}</div>
</div>
<!-- <div v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && series.TaskInfo && !isMip && !isFusion"
class="top-center-tool">
<div class="toggle-visit-container">
<div class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
@dblclick.stop="preventDefault($event)">
<i class="el-icon-caret-left" />
</div>
<div class="arrow_text">
{{ series.TaskInfo.TaskBlindName }}
</div>
<div class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
@dblclick.stop="preventDefault($event)">
<i class="el-icon-caret-right" />
</div>
</div>
</div> -->
<div v-if="series && !isMip && !isFusion" class="right-top-text">
<div>{{ series.Description }}</div>
</div>
<div v-if="series" class="left-bottom-text">
<div v-show="mousePosition.index.length > 0 && !isMip">
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}, {{ mousePosition.index[2] }}
</div>
<div
v-if="(series.Modality === 'CT' || series.Modality === 'DR' || series.Modality === 'CR') && mousePosition.value && !isMip && !isFusion">
HU: {{ mousePosition.value }}
</div>
<div v-else-if="(series.Modality === 'PT' && mousePosition.value) && !isMip && !isFusion">
SUVbw(g/ml): {{ digitPlaces === -1 ? mousePosition.value.toFixed(3) : mousePosition.value.toFixed(digitPlaces)
}}
</div>
<div v-else-if="mousePosition.value && !isMip && !isFusion">
Density: {{ mousePosition.value }}
</div>
<div v-show="imageInfo.size && !isMip && !isFusion">
W*H: {{ imageInfo.size }}
</div>
</div>
<div v-if="series && !isMip" class="right-bottom-text">
<div v-show="imageInfo.location && !isFusion">Location: {{ `${Number(imageInfo.location).toFixed(digitPlaces)} mm`
}}</div>
<div v-show="series.SliceThickness && !isFusion">Slice Thickness: {{
`${Number(series.SliceThickness).toFixed(digitPlaces)} mm`
}}</div>
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
</div>
<div class="orientation-top" v-if="!isMip">
{{ markers.top }}
</div>
<div class="orientation-right" v-if="!isMip">
{{ markers.right }}
</div>
<div class="orientation-bottom" v-if="!isMip">
{{ markers.bottom }}
</div>
<div class="orientation-left" v-if="!isMip">
{{ markers.left }}
</div>
<div v-if="isFusion" class="color_bar">
<canvas :id="`colorBar_Canvas_${viewportId}`" />
<!-- <div id="colorBar_Canvas" /> -->
</div>
<div v-if="isMip" id="rotateBar" ref="rotateBar" class="rotate_slider_box" @click.stop="clickRotate($event)">
<div id="rotateSlider" :style="{ left: rotateBarLeft + 'px' }" class="box" @click.stop.prevent="() => { return }"
@mousedown.stop="rotateBarMousedown($event)" />
</div>
<div ref="sliderBox" class="right-slider-box" @click.stop="clickSlider($event)" v-show="!isMip">
<div :style="{ top: sliderInfo.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
@mousedown.stop="sliderMousedown($event)" />
</div>
</div>
</template>
<script>
// import * as cornerstonejs from '@cornerstonejs/core'
import {
// RenderingEngine,
Enums,
// imageLoader,
metaData,
getRenderingEngine,
volumeLoader,
// eventTarget,
utilities as csUtils,
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { utilities as cstUtils } from '@cornerstonejs/tools';
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import setPetTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetTransferFunctionForVolumeActor'
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
const {
ToolGroupManager,
MIPJumpToClickTool,
VolumeRotateTool,
Enums: csToolsEnums,
} = cornerstoneTools
const { BlendModes, OrientationAxis } = Enums;
const { MouseBindings } = csToolsEnums
const { getColormap, getColormapNames } = csUtils.colormap;
const { ViewportColorbar } = cstUtils.voi.colorbar;
const { ColorbarRangeTextPosition } = cstUtils.voi.colorbar.Enums;
import { vec3, mat4 } from 'gl-matrix'
export default {
name: 'ImageViewport',
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
viewportIndex: {
type: Number,
required: true
},
},
data() {
return {
element: '',
series: {},
ctSeries: {},
petSeries: {},
isFusion: false,
isMip: false,
taskInfo: null,
sliderInfo: {
oldB: null,
oldM: null,
isMove: false,
height: 0
},
mousePosition: {
index: [],
value: null,
modalityUnit: '',
world: []
},
imageInfo: {
zoom: null,
size: null,
location: null,
sliceThickness: null,
wwwc: null
},
digitPlaces: 2,
orientationMarkers: [],
originalMarkers: [],
markers: { top: '', right: '', bottom: '', left: '' },
playClipState: false,
wwwcIdx: 2,
presetName: '',
volumeId: null,
defaultWindowLevel: {},
Colorbar: null,
rotateAngle: 0,
rotateBarLeft: 0,
rotateBarInfo: {
initX: null,
initLeft: null,
isMove: false
},
ptVolumeId: null,
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
this.initViewport()
})
},
methods: {
initViewport() {
this.element = this.$refs['viewport-fusion']
const resizeObserver = new ResizeObserver(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
if (renderingEngine) {
renderingEngine.resize(true, false)
}
})
this.element.oncontextmenu = (e) => e.preventDefault()
// resizeObserver.observe(this.element)
this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage)
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
this.element.addEventListener(cornerstoneTools.Enums.Events.MOUSE_WHEEL, this.handletoolsMouseWheel)
this.element.addEventListener('mouseleave', () => {
this.mousePosition.index = []
this.mousePosition.value = null
})
document.addEventListener('mouseup', () => {
this.sliderMouseup()
if (this.isMip) {
this.rotateBarMouseup()
}
})
document.addEventListener('mousemove', (e) => {
this.sliderMousemove(e)
if (this.isMip) {
this.rotateBarMousemove(e)
}
})
// console.log(cornerstoneTools)
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
},
stackNewImage(e) {
const { detail } = e
this.series.SliceIndex = detail.imageIndex
this.sliderInfo.height = detail.imageIndex * 100 / detail.numberOfSlices
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
let imageId = viewport.getCurrentImageId()
if (imageId) {
const imagePlaneModule = metaData.get('imagePlaneModule', imageId)
this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}`
this.imageInfo.location = imagePlaneModule.sliceLocation
this.getOrientationMarker()
// this.$emit('renderAnnotations', this.series)
let properties = viewport.getProperties()
if (this.isFusion) {
properties = viewport.getProperties(this.ptVolumeId)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const windowWidth = upper - lower
const windowCenter = (upper + lower) / 2
this.defaultWindowLevel.windowWidth = windowWidth
this.defaultWindowLevel.windowCenter = windowCenter
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
// const toolGroupId = `viewport-${this.viewportIndex}`
// const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
// toolGroup.setToolEnabled('ScaleOverlay')
}
},
setFullScreen(index) {
setTimeout(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
csUtils.jumpToSlice(viewport.element, { imageIndex: index })
viewport.render()
})
},
voiModified(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let properties = viewport.getProperties()
if (this.isFusion) {
properties = viewport.getProperties(this.volumeId)
}
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
this.$emit('upperRangeChange', Math.round(windowWidth))
}
},
getOrientationMarker() {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const { viewUp, viewPlaneNormal } = viewport.getCamera()
const viewRight = vec3.create()
vec3.cross(viewRight, viewUp, viewPlaneNormal)
const columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]]
const rowCosines = viewRight
const rowString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(rowCosines)
const columnString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(columnCosines)
const oppositeRowString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(rowString)
const oppositeColumnString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(columnString)
this.markers.top = oppositeColumnString
this.markers.right = rowString
this.markers.bottom = columnString
this.markers.left = oppositeRowString
this.orientationMarkers = [oppositeColumnString, rowString, columnString, oppositeRowString]
if (this.originalMarkers.length === 0) {
this.originalMarkers = [...this.orientationMarkers]
}
},
setMarkers() {
const markers = [...this.orientationMarkers]
for (const key in this.markers) {
const v = markers.shift(0)
this.markers[key] = v
}
},
resetOrientationMarkers() {
if (this.originalMarkers.length > 0) {
this.orientationMarkers = [...this.originalMarkers]
this.setMarkers()
}
},
rotateOrientationMarkers(type) {
if (this.orientationMarkers.length > 0) {
if (type === 1) {
this.resetOrientationMarkers()
return
}
const markers = [...this.orientationMarkers]
if (type === 2) {
//
this.orientationMarkers[0] = markers[2]
this.orientationMarkers[2] = markers[0]
} else if (type === 3) {
//
this.orientationMarkers[1] = markers[3]
this.orientationMarkers[3] = markers[1]
} else if (type === 4) {
// 90
this.orientationMarkers = markers.slice(1, 4).concat(markers[0])
} else if (type === 5) {
// 90
this.orientationMarkers = [markers[3]].concat(markers.slice(0, 3))
}
this.setMarkers()
}
},
toggleClipPlay(isPlay, framesPerSecond) {
this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: false })
} else {
cornerstoneTools.utilities.cine.stopClip(viewport.element)
}
},
scrollPage(type) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const numImages = viewport.getImageIds().length
let newImageIdIndex = null
if (type === 0) {
newImageIdIndex = 0
} else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) {
newImageIdIndex = numImages - 1
}
// viewport.setImageIdIndex(newImageIdIndex)
csUtils.jumpToSlice(viewport.element, { imageIndex: newImageIdIndex })
cornerstoneTools.utilities.cine.stopClip(viewport.element)
},
setZoom(ratio) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
if (ratio > 0) {
viewport.setZoom(zoom * 1.05)
} else {
viewport.setZoom(zoom / 1.05)
}
viewport.render()
},
resize(forceFitToWindow) {
console.log('resize: ', forceFitToWindow)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (!forceFitToWindow) {
viewport.setZoom(0.5)
viewport.render()
} else {
viewport.setZoom(1)
viewport.render()
}
},
voiChange(v) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const voiRange = { lower: 0, upper: v }
const viewport = renderingEngine.getViewport(this.viewportId)
if (!viewport) return
let volumeId = this.isFusion ? this.ptVolumeId : this.volumeId
const viewportsContainingVolumeUID = csUtils.getViewportsWithVolumeId(
volumeId,
viewport.renderingEngineId
)
viewport.setProperties({ voiRange }, volumeId)
viewportsContainingVolumeUID.forEach((vp) => {
vp.render()
// this.$refs[vp.id].voiModified()
this.voiModified()
})
},
renderColorBar(presetName) {
var colorMap = null
this.Colorbar = null
if (presetName === 'hsv') {
colorMap = vtkColorMaps.getPresetByName(presetName)
} else {
colorMap = getColormap(presetName)
}
if (!colorMap) return false
// let colormaps = getColormapNames().map(name => getColormap(name))
// console.log(colormaps)
// const canvas = document.getElementById('colorBar_Canvas')
// this.Colorbar = new ViewportColorbar({
// id: this.volumeId,
// element: this.element,
// container: canvas,
// colormaps,
// activeColormapName: presetName,
// ticks: {
// position: ColorbarRangeTextPosition.Left,
// style: {
// font: '12px Arial',
// color: '#fff',
// maxNumTicks: 8,
// tickSize: 5,
// tickWidth: 1,
// labelMargin: 3,
// },
// },
// });
const rgbPoints = colorMap.RGBPoints
const canvas = document.getElementById(`colorBar_Canvas_${this.viewportId}`)
if (!canvas) return false
const ctx = canvas.getContext('2d')
const canvasWidth = 160
const canvasHeight = 5
const rectWidth = 160
const rectHeight = canvasHeight
canvas.width = canvasWidth
canvas.height = canvasHeight
const gradient = ctx.createLinearGradient(0, 0, rectWidth, 0)
for (let i = 0; i < rgbPoints.length; i += 4) {
let position = 0
if (rgbPoints[0] === -1) {
position = (rgbPoints[i] + 1) / 2
} else {
position = rgbPoints[i]
}
const color = `rgb(${parseInt(rgbPoints[i + 1] * 255)}, ${parseInt(rgbPoints[i + 2] * 255)}, ${parseInt(rgbPoints[i + 3] * 255)})`
gradient.addColorStop(position, color)
}
ctx.fillStyle = gradient
ctx.fillRect(0, 0, rectWidth, rectHeight)
},
setPreset(presetName) {
this.presetName = presetName
},
setColorMap(presetName) {
if (this.Colorbar) {
this.Colorbar.activeColormapName = presetName;
}
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
viewport.setProperties({ colormap: { name: presetName } }, this.volumeId)
viewport.render()
},
async prefetchMetadataInformation(imageIdsToPrefetch) {
let taskPromises = []
for (let i = 0; i < imageIdsToPrefetch.length; i++) {
taskPromises.push(cornerstoneDICOMImageLoader.wadouri.loadImage(imageIdsToPrefetch[i]).promise)
if (taskPromises.length >= 6 || i === imageIdsToPrefetch.length - 1) {
await Promise.all(taskPromises)
taskPromises = []
}
}
},
async createImageIdsAndCacheMetaData(obj) {
await createImageIdsAndCacheMetaData({
modality: obj.Modality,
imageIds: obj.ImageIds
})
},
async setSeriesInfo(obj, option = {}) {
try {
let { data, volumeId } = obj
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description) {
data.SliceIndex = this.series.SliceIndex
}
this.ptVolumeId = null
this.series = {}
let { isFusion, isMip, colorMap } = option
this.isFusion = isFusion;
this.isMip = isMip;
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (this.isFusion) {
this.$nextTick(() => {
this.renderColorBar(this.presetName)
})
let { ct, data, ctVolumeId, ptVolumeId, fusionVolumeId } = obj
this.series = { ...data }
this.ctSeries = { ...ct }
this.petSeries = { ...data }
// const maxCount = Math.max(this.ctSeries.ImageIds.length, this.petSeries.ImageIds.length)
// this.$set(this.ctSeries, 'imageMaxLength', maxCount)
// this.$set(this.petSeries, 'imageMaxLength', maxCount)
// await this.createImageIdsAndCacheMetaData(this.ctSeries)
// await this.createImageIdsAndCacheMetaData(this.petSeries)
this.volumeId = ptVolumeId
this.ptVolumeId = fusionVolumeId
await viewport
.setVolumes([
{
volumeId: this.ptVolumeId, callback: (r) => {
setPetColorMapTransferFunctionForVolumeActor(r)
console.log("融合pet渲染成功");
}
},
{
volumeId: ctVolumeId, callback: (r) => {
setCtTransferFunctionForVolumeActor(r)
console.log("融合ct渲染成功")
}
},
{
volumeId: this.volumeId, callback: (r) => {
setPetColorMapTransferFunctionForVolumeActor(r)
console.log("融合pet渲染成功");
}
},
]).then(res => {
if (colorMap) {
this.setColorMap(this.presetName)
}
})
} else {
this.series = { ...data }
this.volumeId = volumeId
if (this.isMip) {
let { volume } = obj
const ptVolumeDimensions = volume.dimensions;
const slabThickness = Math.sqrt(
ptVolumeDimensions[0] * ptVolumeDimensions[0] +
ptVolumeDimensions[1] * ptVolumeDimensions[1] +
ptVolumeDimensions[2] * ptVolumeDimensions[2]
);
viewport
.setVolumes([{
volumeId: this.volumeId,
callback: (r) => {
setPetColorMapTransferFunctionForVolumeActor(r)
console.log("mip渲染成功")
},
slabThickness,
blendMode: BlendModes.MAXIMUM_INTENSITY_BLEND,
defaultOptions: {
orientation: OrientationAxis.CORONAL
}
}]).then(res => {
if (colorMap) {
this.setColorMap(this.presetName)
}
})
} else {
viewport
.setVolumes([{
volumeId: this.volumeId, callback: (r) => {
if (this.series.Modality === 'PT') {
setPetColorMapTransferFunctionForVolumeActor(r, true)
} else {
setCtTransferFunctionForVolumeActor(r)
}
console.log("渲染成功")
}
}]).then(res => {
if (colorMap) {
this.setColorMap(this.presetName)
}
})
}
}
viewport.render()
} catch (e) {
console.log(e)
}
},
cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail
const worldPoint = currentPoints.world
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const imageData = viewport.getImageData()
if (!imageData) return
const index = imageData.imageData.worldToIndex(worldPoint)
index[0] = Math.floor(index[0])
index[1] = Math.floor(index[1])
index[2] = Math.floor(index[2])
this.mousePosition.index = index
},
toggleTask(evt, visitTaskNum, i) {
this.$emit('activeViewport', this.viewportIndex)
const num = visitTaskNum + i
if (num >= 0 && num <= this.taskInfo.VisitNum) {
this.$emit('toggleTaskByViewport', { series: this.series, visitTaskNum: num })
}
evt.stopImmediatePropagation()
evt.stopPropagation()
evt.preventDefault()
},
viewCD(taskId) {
this.$emit('previewCD', taskId)
},
setWwwcIdx(idx) {
this.wwwcIdx = idx
},
clickSlider(e) {
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
this.sliderInfo.height = height
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseup(e) {
this.sliderInfo.isMove = false
},
sliderMousedown(e) {
const boxHeight = this.$refs['sliderBox'].clientHeight
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
this.sliderInfo.oldM = e.clientY
this.sliderInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
sliderMousemove(e) {
if (!this.sliderInfo.isMove) return
const delta = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
const boxHeight = this.$refs['sliderBox'].clientHeight
if (delta < 0) return
if (delta > boxHeight) return
const height = delta * 100 / boxHeight
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
this.sliderInfo.height = height
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseleave(e) {
if (!this.sliderInfo.isMove) return
this.sliderInfo.isMove = false
},
handletoolsMouseWheel(e) {
const { viewportId, wheel } = e.detail
if (this.isMip) {
const container = document.getElementById('rotateBar')
const slider = document.getElementById('rotateSlider')
const containerWidth = container.offsetWidth
const sliderWidth = slider.offsetWidth
const maxX = containerWidth - sliderWidth
const { direction } = wheel
var x = Math.trunc(30 * ((containerWidth - sliderWidth) / 360))
if (direction > 0 && (this.rotateBarLeft + x) > maxX) {
this.rotateBarLeft = x - (containerWidth - sliderWidth - this.rotateBarLeft)
} else if (direction < 0 && (this.rotateBarLeft < x)) {
this.rotateBarLeft = containerWidth - (x - this.rotateBarLeft + sliderWidth)
} else {
this.rotateBarLeft = x * direction + this.rotateBarLeft
}
}
},
rotateBarMouseup(e) {
this.rotateBarInfo.isMove = false
},
rotateBarMousemove(e) {
//
if (!this.rotateBarInfo.isMove) return
const container = document.getElementById('rotateBar')
const slider = document.getElementById('rotateSlider')
const containerWidth = container.offsetWidth
const sliderWidth = slider.offsetWidth
let x = Math.trunc(e.clientX - this.rotateBarInfo.initX + this.rotateBarInfo.initLeft)
if (x < 0) x = 0
if (x > containerWidth - sliderWidth) x = containerWidth - sliderWidth
const deltaX = x - this.rotateBarLeft
const angle = Math.sin((deltaX * (360 / (containerWidth - sliderWidth))) * Math.PI / 180)
this.rotate(angle)
this.rotateBarLeft = x
},
rotateBarMousedown(e) {
this.rotateBarInfo.initLeft = e.srcElement.offsetLeft
this.rotateBarInfo.initX = e.clientX
this.rotateBarInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
rotate(angle) {
let renderingEngine = getRenderingEngine(this.renderingEngineId)
let viewport = renderingEngine.getViewport(this.viewportId)
const camera = viewport.getCamera()
const { viewUp, position, focalPoint } = camera
const [cx, cy, cz] = focalPoint
const [ax, ay, az] = [0, 0, 1]
const newPosition = [0, 0, 0]
const newFocalPoint = [0, 0, 0]
const newViewUp = [0, 0, 0]
const transform = mat4.identity(new Float32Array(16))
mat4.translate(transform, transform, [cx, cy, cz])
mat4.rotate(transform, transform, angle, [ax, ay, az])
mat4.translate(transform, transform, [-cx, -cy, -cz])
vec3.transformMat4(newPosition, position, transform)
vec3.transformMat4(newFocalPoint, focalPoint, transform)
mat4.identity(transform)
mat4.rotate(transform, transform, angle, [ax, ay, az])
vec3.transformMat4(newViewUp, viewUp, transform)
viewport.setCamera({
position: newPosition,
viewUp: newViewUp,
focalPoint: newFocalPoint
})
viewport.render()
},
clickRotate(e) {
// console.log('clickRotate')
const container = document.getElementById('rotateBar')
const containerWidth = container.offsetWidth
const slider = document.getElementById('rotateSlider')
const sliderWidth = slider.offsetWidth
const x = Math.trunc(e.offsetX)
const deltaX = x - this.rotateBarLeft
const angle = Math.sin((deltaX * (360 / (containerWidth - sliderWidth))) * Math.PI / 180)
this.rotate(angle)
this.rotateBarLeft = x
},
preventDefault(e) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
}
}
}
</script>
<style lang="scss" scoped>
.viewport-wrapper {
width: 100%;
height: 100%;
position: relative;
.left-top-text {
position: absolute;
left: 5px;
top: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
.cd-info {
// color: #ddd;
font-size: 18px;
}
.subject-info {
color: #f44336;
padding: 5px 0px;
margin: 0;
}
}
.top-center-tool {
position: absolute;
left: 50%;
top: 5px;
transform: translateX(-50%);
z-index: 1;
.toggle-visit-container {
display: flex;
}
.arrw_icon {
width: 20px;
height: 20px;
background-color: #3f3f3f;
text-align: center;
line-height: 20px;
border-radius: 10%;
}
.arrow_text {
height: 20px;
line-height: 20px;
background-color: #00000057;
color: #fff;
padding: 0 10px;
font-size: 14px;
}
}
.right-top-text {
position: absolute;
right: 5px;
top: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.left-bottom-text {
position: absolute;
left: 5px;
bottom: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-bottom-text {
position: absolute;
right: 5px;
bottom: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-slider-box {
position: absolute;
right: 1px;
height: calc(100% - 140px);
transform: translateY(-50%);
top: calc(50% - 30px);
width: 10px;
background: #333;
z-index: 1;
cursor: pointer;
}
.right-slider-box:after {
content: '';
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
background: #333;
}
.slider {
height: 20px;
width: 100%;
position: absolute;
top: 0;
z-index: 10;
background: #9e9e9e;
cursor: move
}
.orientation-top {
position: absolute;
left: 50%;
top: 30px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-bottom {
position: absolute;
left: 50%;
bottom: 15px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-left {
position: absolute;
top: 50%;
left: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
.orientation-right {
position: absolute;
top: 50%;
right: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
}
.color_bar {
position: absolute;
transform: rotate(-90deg);
transform-origin: right;
left: -150px;
top: 30%;
z-index: 1;
}
.rotate_slider_box {
position: absolute;
width: 380px;
height: 10px;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
background: #333;
z-index: 10;
cursor: pointer;
.box {
z-index: 10;
background: #9e9e9e;
height: 100%;
width: 20px;
position: absolute;
top: 0;
cursor: move
}
}
</style>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,325 @@
<template>
<div>
<div
v-if="!!question.GroupName && question.Type==='group'"
>
<h4 style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?question.GroupEnName:question.GroupName }}
</h4>
</div>
<template v-else>
<el-form-item
v-if="(question.ShowQuestion===1 && question.ParentTriggerValueList.includes(String(questionForm[question.ParentId]))) || question.ShowQuestion===0 "
:label="`${question.QuestionName}`"
:prop="question.Id"
:rules="[
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (questionForm[question.RelevanceId] === question.RelevanceValue))) && question.Type!=='group' && question.Type!=='summary',
message: ['radio', 'select', 'checkbox'].includes(question.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']},
]"
:class="[question.Type==='group' ? 'mb' : (question.Type==='upload' || question.QuestionName.length > 15) ?'uploadWrapper' : '']"
>
<!-- 输入框 -->
<el-input
v-if="question.Type==='input'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
/>
<!-- 多行文本输入框 -->
<el-input
v-else-if="question.Type==='textarea'"
v-model="questionForm[question.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
maxlength="500"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
/>
<!-- 下拉框 -->
<el-select
v-else-if="question.Type==='select'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2 || ((question.TableQuestionType === 2 || question.QuestionGenre === 2) && !!question.DictionaryCode)"
clearable
@change="((val)=>{formItemChange(val, question)})"
>
<template v-if="question.TableQuestionType === 1">
<el-option
v-for="item in organList"
:key="item.Id"
:label="item[question.DataTableColumn]"
:value="item[question.DataTableColumn]"
/>
</template>
<template v-else-if="question.TableQuestionType === 3 || question.QuestionGenre === 3">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:label="item.label"
/>
</template>
<template v-else-if="(question.TableQuestionType === 2 || question.QuestionGenre === 2) && question.DictionaryCode">
<el-option
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:value="String(item.value)"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<!-- 单选 -->
<el-radio-group
v-else-if="question.Type==='radio'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
@change="((val)=>{formItemChange(val, question)})"
>
<template v-if="question.DictionaryCode">
<el-radio
v-for="item of $d[question.DictionaryCode]"
:key="item.id"
:label="String(item.value)"
>
{{ item.label }}
</el-radio>
</template>
<template v-else-if="question.TypeValue">
<el-radio
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</template>
</el-radio-group>
<!-- 复选框 -->
<el-checkbox-group
v-else-if="question.Type==='checkbox'"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
>
<el-checkbox
v-for="val in question.TypeValue.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-checkbox>
</el-checkbox-group>
<!-- 数值 -->
<template v-else-if="question.Type==='number'">
<el-input-number
v-if="question.ValueType === 0"
v-model="questionForm[question.Id]"
:precision="0"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 3"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 1 || question.ValueType === 2"
v-model="questionForm[question.Id]"
:precision="digitPlaces"
:disabled="readingTaskState >= 2"
/>
</template>
<el-input
v-else-if="question.Type==='calculation'"
v-model="questionForm[question.Id]"
disabled
>
<template v-if="question.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(question.Unit)) }}
</template>
</el-input>
<!-- 上传图像 -->
<el-upload
v-else-if="question.Type==='upload'"
action
:accept="accept"
:limit="question.ImageCount"
:on-preview="handlePictureCardPreview"
:before-upload="handleBeforeUpload"
:http-request="uploadScreenshot"
list-type="picture-card"
:on-remove="handleRemove"
:file-list="fileList"
:class="{disabled:fileList.length >= question.ImageCount}"
:disabled="readingTaskState >= 2"
>
<i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}">
<img
class="el-upload-list__item-thumbnail"
:src="OSSclientConfig.basePath + file.url"
alt=""
>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
v-if="readingTaskState < 2"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete" />
</span>
</span>
</div>
</el-upload>
<el-dialog
v-if="question.Type==='upload'"
append-to-body
:visible.sync="imgVisible"
width="600px"
>
<el-image :src="imageUrl" width="100%">
<div slot="placeholder" class="image-slot">
加载中<span class="dot">...</span>
</div>
</el-image>
</el-dialog>
</el-form-item>
</template>
<question-form-item
v-for="(item) in question.Childrens"
:key="item.Id"
:question="item"
:question-form="questionForm"
:reading-task-state="readingTaskState"
:visitTaskId="visitTaskId"
@resetFormItemData="resetFormItemData"
@setFormItemData="setFormItemData"
/>
</div>
</template>
<script>
// import { uploadReadingAnswerImage } from '@/api/trials'
import { mapGetters } from 'vuex'
export default {
name: 'QuestionFormItem',
props: {
questionForm: {
type: Object,
default() {
return {}
}
},
question: {
type: Object,
default() {
return {}
}
},
readingTaskState: {
type: Number,
required: true
},
visitTaskId: {
type: String,
default: ''
}
},
data() {
return {
fileList: [],
accept: '.png,.jpg,.jpeg',
imgVisible: false,
imageUrl: '',
urls: [],
digitPlaces: 2
}
},
computed: {
...mapGetters(['language'])
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v) {
// console.log(v)
}
}
},
mounted() {
let digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
},
methods: {
formItemChange(v, question) {
console.log('formItemChange')
if (question.Childrens.length > 0) {
this.resetChild(question.Childrens)
} else {
this.$emit('setFormItemData', { key: question.Id, val: v })
}
},
resetChild(obj) {
obj.forEach(i => {
this.$emit('resetFormItemData', i.Id)
if (i.Childrens && i.Childrens.length > 0) {
this.resetChild(i.Childrens)
}
})
},
resetFormItemData(v) {
this.$emit('resetFormItemData', v)
},
setFormItemData(obj) {
this.$emit('setFormItemData', obj)
},
}
}
</script>
<style lang="scss" scoped>
.mb{
margin-bottom: 0px;
}
.disabled{
::v-deep .el-upload--picture-card {
display: none;
}
}
.uploadWrapper{
display: flex;
flex-direction: column !important;
align-items: flex-start;
}
::v-deep .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-input-group__append, .el-input-group__prepend{
padding: 0 10px;
}
::v-deep .el-form-item__content {
width: 100%;
}
::v-deep .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
// ::v-deep .el-radio__input.is-disabled.is-checked .el-radio__inner {
// background-color: #428bca;
// border-color: #428bca;
// }
</style>
@@ -0,0 +1,357 @@
<template>
<div class="table-question-form">
<div style="display: flex;justify-content: space-between;">
<h3 v-if="qsForm.LesionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ qsForm.LesionName }}
</h3>
<!-- 关闭 -->
<div>
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="close" />
</div>
</div>
<el-form-item
:label="$t('trials:reading:title:lesionType')"
prop="LesionType"
:rules="[
{ required:true,message: $t('common:ruleMessage:select'), trigger: ['blur']},
]"
>
<!-- 下拉框 -->
<el-select
v-model="qsForm.LesionType"
filterable
:disabled="!isCurrentTask || readingTaskState>=2 || !isBaseLineTask"
@change="((val)=>{lesionTypeChange(val)})"
>
<el-option
v-for="item of $d.LesionType"
v-show="!(isBaseLineTask && item.value === 2)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item
v-for="qs in questions"
v-show="qs.ShowQuestion!==2"
:key="qs.Id"
:label="`${qs.QuestionName}`"
:prop="qs.Id"
:rules="[
{ required: (qs.IsRequired === 0 || (qs.IsRequired ===1 && qs.RelevanceId && (questionForm[qs.RelevanceId] === qs.RelevanceValue)) || (qs.QuestionMark === 6 && questionForm.IsCanEditPosition === true) || (questionForm.IsCanEditPosition && qs.QuestionMark === 10)) && qs.Type!=='group' && qs.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(qs.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<!-- 输入框 -->
<template v-if="qs.Type==='input' || qs.Type==='number'">
<el-input
v-if="qs.Type==='input' || qs.Type==='number'"
v-model="qsForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 || qs.QuestionMark === 0 || qs.QuestionMark === 1 || qs.QuestionMark === 2 || qs.QuestionMark === 5 || (qs.QuestionMark === 6 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))|| (qs.QuestionMark === 8 && (isCurrentTaskAdd === 'False' || !!answer.SplitOrMergeLesionName) && lesionType !== 2) || (qs.QuestionMark === 10 && (isCurrentTaskAdd === 'False' || !!answer.SplitOrMergeLesionName))"
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="(qs.QuestionMark===0 || qs.QuestionMark===1) && qs.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
</template>
</el-input>
</template>
<!-- 多行文本输入框 -->
<el-input
v-if="qs.Type==='textarea'"
v-model="qsForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<!-- 下拉框 -->
<el-select
v-if="qs.Type==='select'"
v-model="qsForm[qs.Id]"
filterable
:placeholder="qs.QuestionMark === 8 ? $t('common:placeholder:selectorsearch') : qs.QuestionMark === 2 ? '' : $t('common:placeholder:select')"
:disabled="!isCurrentTask || readingTaskState>=2 || qs.QuestionMark === 0 || qs.QuestionMark === 1 || qs.QuestionMark === 2 || qs.QuestionMark === 5 || (qs.QuestionMark === 6 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))|| (qs.QuestionMark === 8 && (isCurrentTaskAdd === 'False'|| !!answer.SplitOrMergeLesionName)) || (qs.QuestionMark === 10 && (isCurrentTaskAdd === 'False' || (isCurrentTaskAdd === 'True' && !questionForm.IsCanEditPosition) || !!answer.SplitOrMergeLesionName))"
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.QuestionMark === 8" #prefix>
<span style="padding-left: 5px;">
<i class="el-icon-search" />
</span>
</template>
<template v-if="qs.TableQuestionType === 1">
<el-option
v-for="item in organList"
:key="item.Id"
:label="item[qs.DataTableColumn]"
:value="item[qs.DataTableColumn]"
/>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark === 7 && isBaseLineTask">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="(lesionType === 0 && item.value ===0) || (lesionType === 1 && (item.value ===0))"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark === 7 && !isBaseLineTask">
<el-option-group
:label="!isNaN(parseFloat(answer.LastTaskState)) ? `${$t('trials:dicomReading:tip:lastVisitStatus')} ${$fd(qs.DictionaryCode,parseFloat(answer.LastTaskState))}` : ''"
>
<!-- 首次分裂的病灶只能选择存在 -->
<template v-if="answer.IsFristAdd=== 'True' && answer.SplitOrMergeType === '0'">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="item.value === 0"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<!-- 首次添加的新病灶不能为无法评估和消失 -->
<template v-else-if="isCurrentTaskAdd=== 'True' && lesionType === 2">
<el-option
v-for="item of $d[qs.DictionaryCode]"
v-show="item.value === 0 || item.value === 1"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="item of filterState($d[qs.DictionaryCode])"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
</el-option-group>
</template>
<template v-else-if="qs.DictionaryCode && qs.QuestionMark !== 7">
<el-option
v-for="item of $d[qs.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="val in qs.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<!-- 单选 -->
<el-radio-group
v-if="qs.Type==='radio'"
v-model="qsForm[qs.id]"
:disabled="!isCurrentTask || readingTaskState>=2"
>
<el-radio
v-for="val in qs.options.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</el-radio-group>
</el-form-item>
</div>
</template>
<script>
export default {
name: 'TableQuestionFormItem',
props: {
tableInfo: {
type: Object,
default() {
return {}
}
},
answer: {
type: Object,
default() {
return {}
}
},
questionForm: {
type: Object,
default() {
return {}
}
},
organs: {
type: Array,
default() {
return []
}
},
readingTaskState: {
type: Number,
required: true
},
isBaseLineTask: {
type: Boolean,
required: true
},
isCurrentTask: {
type: Boolean,
required: true
}
},
data() {
return {
isCurrentTaskAdd: null,
lesionType: null,
questions: [],
organList: [],
qsForm: {}
}
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v) {
if (v.MeasureData) {
const { markTool } = v.MeasureData
if (markTool === 'Bidirectional') {
this.getOrganList(1)
} else if (markTool === 'Length') {
this.getOrganList(0)
} else {
this.getOrganList()
}
} else {
this.getOrganList()
}
for (const key in v) {
this.$set(this.qsForm, key, v[key])
}
this.isCurrentTaskAdd = v.IsCurrentTaskAdd
}
},
tableInfo: {
deep: true,
immediate: true,
handler(v) {
if (v) {
this.lesionType = v.LesionType
this.questions = v.TableQuestions.Questions
}
}
}
},
methods: {
lesionTypeChange(v) {
this.$emit('lesionTypeChange', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex, newLesionType: v })
},
formItemChange(v, qs) {
const updateArr = []
if (qs.QuestionMark === 8 && qs.RelationQuestions.length > 0) {
//
const index = this.organList.findIndex(item => item[qs.DataTableColumn] === v)
if (index > -1) {
const selected = this.organList[index]
qs.RelationQuestions.map(q => {
const val = selected[q.DataTableColumn]
updateArr.push({ questionId: q.Id, val: val, questionMark: q.QuestionMark })
})
updateArr.push({ questionId: 'OrganInfoId', val: selected.OrganInfoId })
updateArr.push({ questionId: 'IsCanEditPosition', val: selected.IsCanEditPosition })
} else {
qs.RelationQuestions.map(q => {
updateArr.push({ questionId: q.Id, val: '', questionMark: q.QuestionMark })
})
}
}
this.$emit('update', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex, questionMark: qs.QuestionMark, questionId: qs.Id, val: v, updateArr })
},
getOrganList(isLymphNodes = null) {
const idx = this.organs.findIndex(i => i.LesionType === this.questionForm.LesionType)
if (idx > -1) {
const arr = this.organs[idx].OrganList
if (!isNaN(parseInt(isLymphNodes))) {
this.organList = arr.filter((item) => item.IsLymphNodes === parseInt(isLymphNodes))
} else {
this.organList = arr
}
}
},
filterState(arr) {
if (!this.isBaseLineTask) {
const isLymphLesion = this.questionForm.IsLymphNodes
const lesionLength = this.questionForm.LesionLength
const lesionShort = this.questionForm.LesionShort
const bLesionL = !isNaN(parseFloat(this.questionForm.BaseLineMajorAxis)) ? parseFloat(this.questionForm.BaseLineMajorAxis) : 0
const bLesionS = !isNaN(parseFloat(this.questionForm.BaseLineShortAxis)) ? parseFloat(this.questionForm.BaseLineShortAxis) : 0
if (this.lesionType === 1 && isLymphLesion === 1 && this.questionForm.MeasureData && this.questionForm.MeasureData.markTool === 'Bidirectional' && lesionShort < bLesionS) {
arr = arr.filter(i => i.value !== 1)
} else if (this.lesionType === 1 && isLymphLesion === 1 && this.questionForm.MeasureData && this.questionForm.MeasureData.markTool === 'Bidirectional' && lesionShort >= 10 && lesionShort > bLesionS) {
arr = arr.filter(i => i.value === 0 || i.value === 1)
} else if (this.lesionType === 1 && isLymphLesion === 0 && this.questionForm.MeasureData && (this.questionForm.MeasureData.markTool === 'Length' || this.questionForm.MeasureData.markTool === 'Bidirectional') && lesionLength < bLesionL) {
arr = arr.filter(i => i.value !== 1)
}
return arr
} else {
return arr
}
},
close() {
this.$emit('close', { tableId: this.tableInfo.Id, rowIndex: this.answer.RowIndex })
}
}
}
</script>
<style lang="scss" scoped>
.table-question-form{
::v-deep .el-form-item__label{
color: #c3c3c3;
}
::v-deep .el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
::v-deep .el-form-item{
display: flex;
flex-direction: row;
justify-content: flex-start;
}
::v-deep .el-form-item__content{
flex: 1;
}
::v-deep .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
::v-deep .el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
.el-form-item__content
.el-select{
width: 100%;
}
.input-width1{
width: calc(100% - 60px)!important;
}
.input-width2{
width: 100% !important;
}
}
</style>
@@ -0,0 +1,914 @@
<template>
<div class="report-wrapper">
<el-card v-loading="loading" shadow="never">
<div slot="header" class="clearfix report-header">
<!-- 电子影像病例报告表eICRF -->
<h3 style="margin:0;padding:0;">{{ $t('trials:readingReport:title:eicrf') }}</h3>
<div style="margin-left:auto">
<el-switch
v-model="isShowDetail"
:active-text="$t('trials:readingReport:title:expandDetails')"
:inactive-text="$t('trials:readingReport:title:collapseDetails')"
style="margin-right:5px;"
@change="handleShowDetail"
/>
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="skipTask"
>
<!-- 跳过 -->
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="getReportInfo(false)"
>
<!-- 刷新 -->
{{ $t('trials:readingReport:button:refresh') }}
</el-button>
<el-button
v-if="readingTaskState<2 && criterionType !== 10"
type="primary"
size="small"
@click="handleSave(true)"
>
<!-- 保存 -->
{{ $t('common:button:save') }}
</el-button>
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="beforeLeave"
>
<!-- 提交 -->
{{ $t('common:button:submit') }}
</el-button>
</div>
</div>
<div ref="tableWrapper" style="height:100%;overflow-y: auto;">
<el-table
v-if="height"
ref="reportList"
:data="taskQuestions"
row-key="Id"
border
:expand-row-keys="expandedRows"
:height="height"
:tree-props="{children: 'Childrens', hasChildren: 'hasChildren'}"
size="mini"
>
<el-table-column
prop=""
label=""
show-overflow-tooltip
width="350px"
>
<template slot-scope="scope">
<span v-if="scope.row.QuestionName" :style="{color: ((scope.row.isLymphNodes === 1 && scope.row.QuestionMark === 1) || (scope.row.isLymphNodes === 0 && scope.row.QuestionMark === 0)) && (scope.row.LesionType === 0 || scope.row.LesionType === 5) ? '#f66' : '#fff'}">{{ scope.row.QuestionName }}</span>
<span
v-else
style="font-weight: bold;font-size: 16px;color: #f44336;"
>
{{ language==='en'?scope.row.GroupEnName:scope.row.GroupName }}
</span>
</template>
</el-table-column>
<el-table-column
v-for="task in visitTaskList"
:key="task.VisitTaskId"
prop="date"
show-overflow-tooltip
width="150px"
>
<template slot="header">
<div v-if="task.IsCurrentTask">
<div>
{{ task.BlindName }}
</div>
</div>
<div v-else>
<div>
{{ task.BlindName }}
<el-button type="text" size="small" @click="previewDicoms(task)">
<span class="el-icon-view" />
</el-button>
</div>
</div>
</template>
<template slot-scope="scope">
<span :style="{color: ((scope.row.isLymphNodes === 1 && scope.row.QuestionMark === 1) || (scope.row.isLymphNodes === 0 && scope.row.QuestionMark === 0)) && (scope.row.LesionType === 0 || scope.row.LesionType === 5) || (scope.row.QuestionMark === 12) || scope.row.HighlightAnswerList.includes(`${scope.row.Answers[task.VisitTaskId]}`) ? '#f66' : '#fff'}">
<template v-if="task.VisitTaskId === visitTaskId && readingTaskState < 2 && [13,14,15,42].includes(scope.row.QuestionType)">
<!-- 是否存在疾病基线时可修改 -->
<template v-if="task.IsBaseLine && scope.row.QuestionType=== 15">
<el-select
v-if="scope.row.Type==='select' && scope.row.DictionaryCode"
v-model="currentExistDisease"
size="mini"
@change="handleExistDiseaseChange"
>
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</el-select>
</template>
<!-- 整体肿瘤评估非基线可修改 -->
<template v-else-if="!task.IsBaseLine && (scope.row.QuestionType=== 13 || scope.row.QuestionType=== 42)">
<el-select
v-if="scope.row.Type==='select' && scope.row.DictionaryCode"
v-model="currentEvaluateResult"
size="mini"
@change="handleEvaluateResultChange"
>
<template v-if="criterionType === 1 && tLesionCount">
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
v-show="(!task.IsBaseLine && item.value > -1) && (task.CrterionDictionaryGroup.indexOf(item.raw.CrterionDictionaryGroup) > -1) && (item.value !== 1 && item.value !== 3)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else-if="criterionType === 1 && ntLesionCount">
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
v-show="(!task.IsBaseLine && item.value > -1) && (task.CrterionDictionaryGroup.indexOf(item.raw.CrterionDictionaryGroup) > -1) && (item.value !== 1)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="item of $d[ scope.row.DictionaryCode]"
v-show="(!task.IsBaseLine && item.value > -1) && (task.CrterionDictionaryGroup.indexOf(item.raw.CrterionDictionaryGroup) > -1)"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
</el-select>
</template>
<!-- <template v-else-if="task.IsBaseLine && scope.row.QuestionType=== 13">
{{ $fd(scope.row.DictionaryCode, currentEvaluateResult) }}
</template> -->
<!-- 访视点备注是否存在疾病与系统不一致或者整体肿瘤评估与系统不一致时必填 -->
<!-- tumorEvaluate && task.VisitTaskId === visitTaskId && scope.row.QuestionType=== 14 && (currentEvaluateResult !== tumorEvaluate || currentExistDisease !== isExistDisease) -->
<template v-else-if="task.VisitTaskId === visitTaskId && scope.row.QuestionType=== 14 ">
<!-- v-if="tumorEvaluate && (currentEvaluateResult !== tumorEvaluate || currentExistDisease !== isExistDisease)" -->
<template>
<!-- 输入框 -->
<el-input
v-if="scope.row.Type==='input'"
v-model="currentTaskReason"
size="mini"
@change="evaluateReasonChange"
/>
<el-input
v-else-if="scope.row.Type==='textarea'"
v-model="currentTaskReason"
:autosize="{ minRows: 2, maxRows: 4}"
size="mini"
maxlength="500"
@change="evaluateReasonChange"
/>
<!-- 系统评估结果为xxx,与当前调整的结果不一致请填写调整原因 -->
<p v-if="currentEvaluateResult !== tumorEvaluate" style="width: 140px;padding:0 2px;white-space: normal;word-break: break-all;word-wrap: break-word;" v-html="getWarningText()" />
<p v-else-if="currentExistDisease !== isExistDisease" style="width: 140px;padding:0 2px;white-space: normal;word-break: break-all;word-wrap: break-word;">{{ $t('trials:readingReport:title:sysEvaluationRes') }}<span style="color:red">{{ $fd('ExistDisease',isExistDisease) }}</span>{{ $t('trials:readingReport:message:msg1') }}
</p>
</template>
<!-- <template v-else>
<span>{{ currentTaskReason }}</span>
</template> -->
</template>
<template v-else-if="scope.row.DictionaryCode">
{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}
</template>
<template v-else>
{{ scope.row.Answers[task.VisitTaskId] }}
</template>
</template>
<template v-else-if="scope.row.QuestionType=== 15">
<el-tooltip v-if="getAnswerInfo(scope.row.Answer,task.VisitTaskId,'IsGlobalChange')" :content="`${$t('trials:reading:warnning:msg55')}${$fd(scope.row.DictionaryCode, getAnswerInfo(scope.row.Answer,task.VisitTaskId,'GlobalChangeAnswer'))}`" placement="top" effect="light">
<span style="color:red;"> {{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</el-tooltip>
<span v-else>{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</template>
<template v-else-if="scope.row.QuestionType=== 13 || scope.row.QuestionType=== 42">
<el-tooltip v-if="getAnswerInfo(scope.row.Answer,task.VisitTaskId,'IsGlobalChange')" :content="`${$t('trials:reading:warnning:msg55')}${$fd(scope.row.DictionaryCode, getAnswerInfo(scope.row.Answer,task.VisitTaskId,'GlobalChangeAnswer'))}`" placement="top" effect="light">
<span style="color:red;"> {{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</el-tooltip>
<span v-else>{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}</span>
</template>
<template v-else-if="scope.row.QuestionType=== 22">
{{ scope.row.Answers[task.VisitTaskId] === '-1' ? $t('trials:readingReport:title:unknow') : scope.row.Answers[task.VisitTaskId] }}
</template>
<template v-else-if="scope.row.DictionaryCode">
{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}
</template>
<template v-else-if="criterionType === 10">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]}` }}
</template>
<template v-else-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ `${scope.row.Answers[task.VisitTaskId]}` }}
<span v-if="scope.row.Answers[task.VisitTaskId] !== 'NA' && !isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))">{{ `${$fd('ValueUnit',scope.row.Unit)}` }}</span>
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]}%` }}
</template>
<template v-else-if="scope.row.Answers && scope.row.Answers.hasOwnProperty(task.VisitTaskId)">
{{ scope.row.Answers[task.VisitTaskId] }}
</template>
</span>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 附加评估 -->
<el-dialog
v-if="additionalAssessmentsDig.visible"
:visible.sync="additionalAssessmentsDig.visible"
:close-on-click-modal="false"
:title="additionalAssessmentsDig.title"
width="600px"
>
<additional-assessment
:questions="assessmentQuestions"
:visit-task-id="visitTaskId"
@close="additionalAssessmentsDig.visible = false"
@sign="sign"
/>
</el-dialog>
<!-- 签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
custom-class="base-dialog-wrapper"
>
<div slot="title">
<span style="font-size:18px;">{{ $t('common:dialogTitle:sign') }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${ currentUser })` }}</span>
</div>
<SignForm ref="signForm" :sign-code-enum="signCode" @closeDialog="closeSignDialog" />
</el-dialog>
</div>
</template>
<script>
import { getReadingReportEvaluation, changeDicomReadingQuestionAnswer, submitDicomVisitTask, verifyVisitTaskQuestions, getTaskAdditionalQuestion } from '@/api/trials'
import { setSkipReadingCache } from '@/api/reading'
import { getAutoCutNextTask } from '@/api/user'
import const_ from '@/const/sign-code'
import SignForm from '@/views/trials/components/newSignForm'
import { getToken } from '@/utils/auth'
// import store from '@/store'
import { mapGetters } from 'vuex'
import { changeURLStatic } from '@/utils/history.js'
import AdditionalAssessment from '@/views/trials/trials-panel/reading/dicoms/components/AdditionalAssessment'
export default {
name: 'ReportPage',
components: { SignForm, AdditionalAssessment },
data() {
return {
currentUser: zzSessionStorage.getItem('userName'),
signVisible: false,
signCode: null,
visitTaskList: [],
taskQuestions: [],
loading: false,
answers: [],
readingTaskState: 2,
tumorEvaluate: null,
currentEvaluateResult: null,
isExistDisease: null,
currentExistDisease: null,
currentTaskReason: '',
answerArr: [],
questions: [],
isShowDetail: false,
criterionType: 0,
height: 0,
additionalAssessmentsDig: { visible: false, title: this.$t('trials:trials-panel:setting:reading-unit:TrialCriterionAdditionalAssessmentTypeList') },
assessmentQuestions: [],
tLesionCount: null,
ntLesionCount: null,
openWindow: null,
expandedRows: [],
taskInfo: {},
visitTaskId: '',
isBaselineTask: false
}
},
computed: {
...mapGetters(['language'])
},
watch: {
taskQuestions() {
this.$nextTick(() => {
this.getTableHeight()
this.$refs.reportList && this.$refs.reportList.doLayout()
this.setScrollTop()
})
}
},
created() { this.getTableHeight() },
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
this.criterionType = this.taskInfo.CriterionType
this.visitTaskId = this.taskInfo.VisitTaskId
this.isBaselineTask = this.taskInfo.IsBaseLine
window.addEventListener('resize', () => {
this.handleResize()
this.setScrollTop()
})
this.getReportInfo()
},
beforeDestroy() {
if (this.openWindow) {
this.openWindow.close()
}
},
methods: {
myConfirm(msg) {
return new Promise(resolve => {
this.$confirm(msg, {
type: 'warning',
showCancelButton: true
}).then(() => {
resolve(true)
}).catch(() => {
resolve(false)
})
})
},
async beforeLeave() {
this.handleConfirm()
},
getAnswerInfo(answerArr, visitTaskId, prop) {
var i = answerArr.findIndex(i => i.VisitTaskId === visitTaskId)
if (i === -1) return ''
var val = answerArr[i][prop]
return isNaN(parseInt(val)) ? val : parseInt(val)
},
getTableHeight() {
this.height = window.innerHeight - 170
},
async getReportInfo(IsCalculate) {
this.loading = true
try {
var params = {
visitTaskId: this.visitTaskId,
trialId: this.$router.currentRoute.query.trialId,
IsCalculate: IsCalculate !== false
}
const res = await getReadingReportEvaluation(params)
if (res.IsSuccess) {
this.readingTaskState = res.Result.ReadingTaskState
this.tumorEvaluate = res.Result.CalculateResult && res.Result.CalculateResult.TumorEvaluate ? parseInt(res.Result.CalculateResult.TumorEvaluate) : null
this.isExistDisease = res.Result.CalculateResult && res.Result.CalculateResult.IsExistDisease ? parseInt(res.Result.CalculateResult.IsExistDisease) : null
this.answerArr = []
this.questions = res.Result.TaskQuestions.concat()
this.visitTaskList = res.Result.VisitTaskList
var taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null, null)
this.taskQuestions = []
taskQuestions.forEach(item => {
this.$set(this.taskQuestions, this.taskQuestions.length, item)
})
const tLesion = res.Result.LesionCountList.find(i => i.LesionType === 0)
this.tLesionCount = tLesion ? tLesion.Count : 0
const ntLesion = res.Result.LesionCountList.find(i => i.LesionType === 1)
this.ntLesionCount = ntLesion ? ntLesion.Count : 0
this.setScrollTop()
}
this.loading = false
} catch (e) {
this.loading = false
console.log(e)
}
},
setScrollTop(a) {
setTimeout(() => {
this.$nextTick(() => {
if (this.$refs.reportList) {
this.getTableHeight()
this.$refs.reportList.bodyWrapper.scrollTop = this.$refs.reportList.bodyWrapper.scrollHeight
}
})
}, 50)
},
getQuestions(questions, isNTFilterLength, lesionType, isLymphNodes) {
const arr = []
if (questions.length !== 0) {
questions.forEach((item) => {
if (this.criterionType === 21) {
if (!this.isShowDetail) {
if (!item.RowId) {
this.expandedRows.push(item.Id)
}
} else {
this.expandedRows.push(item.Id)
}
} else {
this.expandedRows.push(item.Id)
}
//
//
//
lesionType = item.LesionType
var filterArr = [7]
// 0 5
// 12678irecisit
// 0123ID4567810
// 11051106
if ((item.LesionType === 1 || item.LesionType === 2 || item.LesionType === 6 || item.LesionType === 7 || item.LesionType === 8) && isNTFilterLength) {
filterArr = [0, 1, 3, 4, 5, 6, 2, 8, 10, 7, 1105]
} else {
filterArr = [3, 4, 5, 6, 2, 8, 10, 7, 1106, 1105]
}
if ((lesionType === 0 || lesionType === 5) && isLymphNodes === 0 && !this.isShowDetail && (this.criterionType === 1 || this.criterionType === 3 || this.criterionType === 7 || this.criterionType === 17)) {
filterArr.push(1)
}
if (isLymphNodes === 0) {
filterArr.push(1)
}
if (!(filterArr.includes(item.QuestionMark))) {
const obj = item
obj.Answers = {}
if (item.RowIndex > 0) {
try {
var idx = item.Childrens.findIndex(i => i.QuestionMark === 8)
var idxLoc = item.Childrens.findIndex(i => i.QuestionMark === 10)
var state = item.Childrens.findIndex(i => i.QuestionMark === 7)
if (idx > -1) {
if (item.Childrens[idx].Answer.length > 0) {
var k = item.Childrens[idx].Answer.findIndex(v => v.Answer !== '')
var part = ''
if (obj.IsCanEditPosition) {
part = `${item.Childrens[idx].Answer[k].Answer}--${item.Childrens[idxLoc].Answer[k].Answer}`
} else {
part = `${item.Childrens[idx].Answer[k].Answer}`
}
if (item.SplitOrMergeLesionName && k > -1) {
// obj.QuestionName = `${obj.QuestionName} --${part} (Split from ${item.SplitOrMergeLesionName})`
obj.QuestionName = `${obj.QuestionName} --${part}`
var Answers = {}
if (state >= 0) {
this.visitTaskList.forEach(v => {
const o = item.Childrens[state].Answer.find(v1 => {
return v1.VisitTaskId === v.VisitTaskId
})
if (o) {
Answers[o.VisitTaskId] = this.$fd(item.Childrens[state].DictionaryCode, parseInt(o.Answer))
}
})
}
this.$set(obj, 'Answers', Answers)
// obj.QuestionName = `${obj.QuestionName} `
} else if (!item.SplitOrMergeLesionName && k > -1) {
obj.QuestionName = `${obj.QuestionName}--${part}`
const Answers = {}
if (state >= 0) {
this.visitTaskList.forEach(v => {
const o = item.Childrens[state].Answer.find(v1 => {
return v1.VisitTaskId === v.VisitTaskId
})
if (o) {
Answers[o.VisitTaskId] = this.$fd(item.Childrens[state].DictionaryCode, parseInt(o.Answer))
}
})
}
this.$set(obj, 'Answers', Answers)
// obj.QuestionName = `${obj.QuestionName} `
} else {
obj.QuestionName = `${obj.QuestionName} `
}
if (item.ReportMark) {
obj.QuestionName = `${obj.QuestionName} (${item.ReportMark})`
}
if (this.criterionType === 1 || this.criterionType === 3 || this.criterionType === 7 || this.criterionType === 17) {
var idxLymphNode = item.Childrens.findIndex(i => i.QuestionMark === 2)
if (idxLymphNode > -1) {
isLymphNodes = item.Childrens[idxLymphNode].Answer[k].Answer ? parseInt(item.Childrens[idxLymphNode].Answer[k].Answer) : null
item.Childrens.forEach(v => {
this.$set(v, 'isLymphNodes', isLymphNodes)
})
}
}
}
}
if (this.criterionType === 21) {
var liverSegmentIdx = item.Childrens.findIndex(i => i.QuestionMark === 1106)
if (liverSegmentIdx > -1) {
if (item.Childrens[liverSegmentIdx].Answer.length > 0) {
const v = item.Childrens[liverSegmentIdx].Answer[0].Answer
obj.QuestionName = this.$fd(item.Childrens[liverSegmentIdx].DictionaryCode, parseInt(v))
const Answers = {}
const mean = item.Childrens.findIndex(i => i.QuestionMark === 1104)
if (mean > -1) {
this.visitTaskList.forEach(v => {
const o = item.Childrens[mean].Answer.find(v1 => {
return v1.VisitTaskId === v.VisitTaskId
})
if (o) {
Answers[o.VisitTaskId] = isNaN(parseFloat(o.Answer)) ? o.Answer : `${o.Answer}%`
}
})
}
this.$set(obj, 'Answers', Answers)
}
}
}
} catch (e) {
console.log(e)
}
}
item.Answer.forEach(i => {
if (item.DictionaryCode) {
obj.Answers[i.VisitTaskId] = i.Answer ? parseInt(i.Answer) : null
} else {
obj.Answers[i.VisitTaskId] = i.Answer
}
})
if (item.QuestionType === 15) {
this.currentExistDisease = obj.Answers[this.visitTaskId]
this.answerArr.push({ id: item.QuestionId, answer: obj.Answers[this.visitTaskId], questionType: 15 })
}
if (item.QuestionType === 13 || item.QuestionType === 42) {
this.currentEvaluateResult = obj.Answers[this.visitTaskId]
this.answerArr.push({ id: item.QuestionId, answer: obj.Answers[this.visitTaskId], questionType: item.QuestionType })
}
if (item.QuestionType === 14) {
this.currentTaskReason = obj.Answers[this.visitTaskId]
this.answerArr.push({ id: item.QuestionId, answer: obj.Answers[this.visitTaskId], questionType: 14 })
}
if (item.Childrens.length >= 1) {
obj.Childrens = this.getQuestions(item.Childrens, isNTFilterLength, lesionType, isLymphNodes)
}
arr.push(obj)
}
})
}
return arr
},
handleShowDetail(val) {
this.getReportInfo()
// this.taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null)
},
handleExistDiseaseChange(val) {
// this.currentExistDisease = parseInt(val)
if (val === this.isExistDisease && this.tumorEvaluate === this.currentEvaluateResult) {
this.currentTaskReason = ''
this.evaluateReasonChange('')
}
this.currentTaskReason = ''
this.evaluateReasonChange('')
var idx = this.answerArr.findIndex(i => i.questionType === 15)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
handleEvaluateResultChange(val) {
// this.currentEvaluateResult = parseInt(val)
if (val === this.tumorEvaluate && this.isExistDisease === this.currentExistDisease) {
this.currentTaskReason = ''
this.evaluateReasonChange('')
}
this.currentTaskReason = ''
this.evaluateReasonChange('')
var idx = this.answerArr.findIndex(i => i.questionType === 13 || i.questionType === 42)
if (idx > -1) {
this.answerArr[idx].answer = val
}
this.setScrollTop()
},
evaluateReasonChange(val) {
var idx = this.answerArr.findIndex(i => i.questionType === 14)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
async handleConfirm() {
this.loading = true
try {
await this.handleSave(false)
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
var i = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
var isBaseline = this.visitTaskList[i].IsBaseLine
if (isBaseline) {
const res = await getTaskAdditionalQuestion({ visitTaskId: this.visitTaskId })
this.assessmentQuestions = res.Result
if (this.assessmentQuestions.length > 0) {
//
this.additionalAssessmentsDig.visible = true
} else {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
}
} else {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
}
this.loading = false
} catch (e) {
this.loading = false
}
},
sign() {
this.additionalAssessmentsDig.visible = false
this.$nextTick(() => {
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
})
},
handleResize() {
this.$nextTick(() => {
this.$refs.reportList && this.$refs.reportList.doLayout()
})
},
//
closeSignDialog(isSign, signInfo) {
if (isSign) {
this.signConfirm(signInfo)
} else {
this.signVisible = false
}
},
//
async signConfirm(signInfo) {
this.loading = true
try {
var params = {
data: {
visitTaskId: this.visitTaskId
},
signInfo: signInfo
}
const res = await submitDicomVisitTask(params)
if (res.IsSuccess) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
if (this.$refs['signForm']) {
this.$refs['signForm'].btnLoading = false
}
this.signVisible = false
// window.location.reload()
window.opener.postMessage('refreshTaskList', window.location)
//
this.readingTaskState = 2
this.$emit('setReadingTaskState', 2)
const res = await getAutoCutNextTask()
var isAutoTask = res.Result.AutoCutNextTask
if (isAutoTask) {
window.location.reload()
} else {
// ''
this.$confirm(this.$t('trials:readingReport:message:msg4'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
window.location.reload()
})
.catch(action => {
changeURLStatic('visitTaskId', this.visitTaskId)
})
}
window.opener.postMessage('refreshTaskList', window.location)
}
this.loading = false
} catch (e) {
this.loading = false
if (this.$refs['signForm'] && this.$refs['signForm'].btnLoading) {
this.$refs['signForm'].btnLoading = false
}
}
},
previewDicoms(task) {
if (this.openWindow) {
this.openWindow.close()
}
var token = getToken()
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
// var subjectCode = this.$router.currentRoute.query.subjectCode
var subjectCode = localStorage.getItem('subjectCode')
var subjectId = this.$router.currentRoute.query.subjectId
var trialId = this.$router.currentRoute.query.trialId
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var criterionType = this.$router.currentRoute.query.criterionType
var readingTool = this.$router.currentRoute.query.readingTool
var path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${task.VisitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
const routeData = this.$router.resolve({ path })
this.openWindow = window.open(routeData.href, '_blank')
},
handleSave(isPrompt) {
return new Promise(async(resolve, reject) => {
var isBeill
var evaluateResult = ''
var evaluateAjustReason = ''
this.answers = []
var isExistEvaluateResult = false
this.answerArr.map(item => {
if (item.questionType === 13 || item.questionType === 42) {
evaluateResult = item.answer
isExistEvaluateResult = true
}
if (item.questionType === 14) {
evaluateAjustReason = item.answer
}
if (item.questionType === 15) {
isBeill = item.answer
}
this.answers.push({ id: item.id, answer: item.answer })
})
console.log(this.currentExistDisease, this.isExistDisease, evaluateAjustReason, isBeill)
if (this.currentExistDisease !== this.isExistDisease && !evaluateAjustReason) {
this.$confirm(this.$t('trials:readingReport:message:msg2'), {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
resolve()
return
}
if (isExistEvaluateResult && (evaluateResult === null && !this.isBaselineTask)) {
//
this.$confirm(this.$t('trials:readingReport:message:msg2'), {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
resolve()
return
}
if (isExistEvaluateResult && (evaluateResult !== this.tumorEvaluate) && !evaluateAjustReason) {
//
this.$confirm(this.$t('trials:readingReport:message:msg3'), {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
resolve()
return
}
this.loading = true
try {
var params = {
visitTaskId: this.visitTaskId,
answers: this.answers
}
const res = await changeDicomReadingQuestionAnswer(params)
if (res.IsSuccess && isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
this.loading = false
resolve()
} catch (e) {
this.loading = false
reject()
}
})
},
getWarningText() {
var sysRes = ''
var curRes = ''
if (this.CriterionType === 2) {
sysRes = this.$fd('ImagingOverallAssessment_Lugano', this.tumorEvaluate)
curRes = this.$fd('ImagingOverallAssessment_Lugano', this.currentEvaluateResult)
} else {
sysRes = this.$fd('OverallAssessment', this.tumorEvaluate)
curRes = this.$fd('OverallAssessment', this.currentEvaluateResult)
}
if (!curRes) {
return ''
}
const msg = this.$t('trials:readingReport:message:msg9').replace('xxx', '<font color="red">' + sysRes + '</font>').replace('yyy', '<font color="red">' + curRes + '</font>')
return msg
},
async skipTask() {
try {
//
const confirm = await this.$confirm(
this.$t('trials:readingReport:message:skipConfirm'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.loading = true
const res = await setSkipReadingCache({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
window.location.reload()
}
} catch (e) {
this.loading = false
console.log(e)
}
}
}
}
</script>
<style lang="scss" scoped>
.report-wrapper{
height: 100%;
padding: 10px 0px;
// background-color: #fff;
background-color: #000;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
.report-header{
display: flex;
}
.el-card{
display:flex;flex-direction: column;height: 100%;
background-color: #000;
color: #ffffff;
border:none;
::v-deep .el-card__body{
flex: 1;
}
}
// ::v-deep .el-table__cell{
// background-color: #000;
// color: #ffffff;
// }
// ::v-deep .el-table{
// background-color: #000;
// color: #ffffff;
// }
// ::v-deep .el-table__cell{
// background-color: #000;
// color: #ffffff;
// }
::v-deep .el-table, .el-table__expanded-cell {
background-color: #000;
color: #fff;
border-color:#444444;
}
::v-deep .el-table th, .el-table tr {
background-color: #000;
color: #fff;
border-color:#444444;
}
::v-deep .el-table__body tr > td{
background-color:#000 !important;
color: #fff;
border-color:#444444;
}
::v-deep .el-table__body tr:hover > td{
background-color:#858282 !important;
color: #fff;
border-color:#444444;
}
::v-deep .el-table--border th.gutter:last-of-type{
border: none;
}
::v-deep .el-card__header{
border: none;
padding: 10px;
}
}
::v-deep .el-switch__label{
color:#fff;
}
::v-deep .el-switch__label.is-active{
color: #428bca;
}
.colorOfRed{
color: #f66;
}
</style>
@@ -0,0 +1,333 @@
<template>
<div v-loading="loading" class="study-wrapper">
<div class="study-info">
<div
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
:title="taskInfo.SubjectCode"
>
{{ taskInfo.SubjectCode }}
</div>
<div
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
:title="visitTaskInfo.TaskBlindName"
>
{{ visitTaskInfo.TaskBlindName }}
</div>
</div>
<div class="ps">
<el-collapse v-model="activeNames">
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`">
<template slot="title">
<div
v-if="!study.IsCriticalSequence"
class="dicom-desc"
>
<template v-if="taskInfo && taskInfo.IsShowStudyName">
<div style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
<span v-if="study.StudyName" :title="study.StudyName" style="margin-left: 5px;">{{ study.StudyName }}</span>
<span v-else :title="study.Modalities" style="margin-left: 5px;">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
</div>
<div v-if="study.StudyName" style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
</div>
</template>
<template v-else-if="taskInfo && !taskInfo.IsShowStudyName">
<div style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
</div>
</template>
</div>
<div v-else>
<!-- 关键序列 -->
{{ $t('trials:reading:title:keySeries') }}
</div>
</template>
<div class="dicom-list-container">
<div
v-for="(series, i) in study.SeriesList"
:key="series.Id"
style="position:relative;margin-top:1px;"
@click="activeSeries(series, i, index)"
>
<div
:class="{'series-active': index === activeStudyIndex && i === activeSeriesIndex}"
class="series-wrapper"
>
<div class="series-image">
<el-image
style="width: 100%;height: 100%;"
:src="`${OSSclientConfig.basePath}${series.ImageResizePath}`"
fit="fill"
crossorigin="anonymous"
/>
</div>
<div class="series-text">
<div v-if="series.IsExistMutiFrames && series.InstanceCount > 1"
style="position: absolute;right: 0;top: 0;">
<el-popover
placement="right"
trigger="hover"
popper-class="instance_frame_wrapper"
>
<div class="frame_list">
<div
v-for="(instance, idx) in series.InstanceInfoList"
:key="instance.Id"
class="frame_content"
:style="{'margin-bottom':idx<series.InstanceInfoList.length-1? '5px':'0px'}"
@click.stop="showMultiFrames(index,series, i, instance)"
>
<div>
<div>{{ instance.InstanceNumber }}</div>
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
</el-popover>
</div>
<div v-if="!study.IsCriticalSequence" class="text-desc" :title="series.SeriesNumber">
#{{ series.SeriesNumber }}
</div>
<div v-if="series.Description" class="text-desc" :title="series.Description">
{{ series.Description }}
</div>
<div v-if="series.SliceThickness && !study.IsCriticalSequence" class="text-desc">
T: {{ parseFloat(series.SliceThickness).toFixed(digitPlaces) }}
</div>
<div class="text-desc">
<span v-show="series.LoadedImageCount < series.InstanceCount">
{{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image
</span>
<span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{ series.InstanceCount }} image</span>
</div>
<div style="line-height: 12px;">
<i v-show="series.IsBeMark || markedSeriesIds.includes(series.Id)" class="el-icon-star-on" style="font-size: 12px;color: #ff5722;" />
</div>
</div>
</div>
<div v-if="series.LoadedImageCount > 0 && series.LoadedImageCount < series.InstanceCount" style="width: 100%;">
<el-progress
:percentage="parseInt((series.LoadedImageProgress / series.InstanceCount).toFixed(2))"
/>
</div>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
</template>
<script>
export default {
name: 'StudyList',
props: {
visitTaskInfo: {
type: Object,
default() {
return {}
}
},
markedSeriesIds: {
type: Array,
default() {
return []
}
}
},
data() {
return {
loading: false,
activeNames: [],
activeStudyIndex: -1,
activeSeriesIndex: -1,
taskInfo: null,
studyList: [],
annotations: [],
digitPlaces: 2
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.studyList = this.visitTaskInfo.StudyList
this.annotations = this.visitTaskInfo.Annotations
if (this.studyList.length === 0) return
this.$nextTick(() => {
this.activeStudy(this.studyList[0].StudyId)
})
},
methods: {
activeSeries(series, seriesIndex, studyIndex) {
this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex
this.$emit('activeSeries', series)
},
activeStudy(id) {
if (this.activeNames.indexOf(id) > -1) return
this.activeNames.push(id)
},
setSeriesActive(studyIndex, seriesIndex) {
this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex
const studyId = this.studyList[studyIndex].StudyId
if (!studyId) return
this.activeStudy(studyId)
},
showMultiFrames(studyIndex, series, seriesIndex, instance) {
let obj = Object.assign({}, series)
this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex
let taskId = this.visitTaskInfo.VisitTaskId
const nFrames = instance.NumberOfFrames || 0
let imageIds = []
const stack = []
if (nFrames === 0) {
//
stack.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
} else {
//
for (let i = 0; i < nFrames; i++) {
const newImageId = `wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}&frame=${i + 1}`
stack.push(newImageId)
}
}
imageIds.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
obj.Stack = stack
obj.ImageIds = imageIds
obj.SliceIndex = 0
this.$emit('showMultiFrame', obj)
},
getPreviousOrNextSeries(type, series) {
const seriseList = this.studyList.map(s => s.SeriesList).flat()
const i = seriseList.findIndex(i => i.Id === series.Id && i.StudyId === series.StudyId)
if (i === -1) return
let newIndex = null
if (type === -1) {
newIndex = i === 0 ? i : i - 1
} else {
newIndex = i >= seriseList.length - 1 ? i : i + 1
}
const studyIndex = seriseList[newIndex].StudyIndex
const seriesIndex = seriseList[newIndex].SeriesIndex
this.setSeriesActive(studyIndex, seriesIndex)
this.activeSeries(seriseList[newIndex], seriesIndex, studyIndex)
}
}
}
</script>
<style lang="scss" scoped>
.study-wrapper{
width:100%;
height: 100%;
overflow-y: hidden;
overflow-x: hidden;
display: flex;
flex-direction: column;
.study-info {
font-size: 16px;
font-weight: bold;
color: #ddd;
padding: 5px 0px;
margin: 0;
text-align: center;
background-color: #4c4c4c;
height: 50px;
}
.dicom-desc{
font-weight: bold;
font-size: 13px;
text-align: left;
color: #d0d0d0;
padding: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ps {
flex: 1;
overflow-anchor: none;
touch-action: auto;
overflow-y: auto;
}
.series-active {
background-color: #607d8b!important;
border: 1px solid #607d8b!important;
}
::v-deep.el-progress__text{
color: #ccc;
font-size: 12px;
}
.dicom-list-container{
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
.series-wrapper {
width: 100%;
padding: 5px;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
background-color: #3a3a3a;
.el-progress__text{
display: none;
}
.el-progress-bar{
padding-right:0px;
}
.series-image {
width: 50px;
height: 50px;
}
.series-text {
flex: 1;
padding-left: 5px;
color: #ddd;
position: relative;
.text-desc {
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
line-height: 16px;
}
}
}
}
::v-deep.el-collapse{
border: none;
.el-collapse-item{
background-color: #000!important;
color: #ddd;
}
.el-collapse-item__content{
padding-bottom:0px;
background-color: #000!important;
}
.el-collapse-item__header{
background-color: #000!important;
color: #ddd;
border-bottom-color:#5a5a5a;
padding-left: 5px;
// height: 50px;
line-height: 20px;
}
}
::v-deep .el-progress-bar__inner{
transition: width 0s ease;
}
}
</style>
@@ -0,0 +1,673 @@
<template>
<div
ref="viewport"
class="viewport-wrapper"
@mouseup="sliderMouseup"
@mousemove="sliderMousemove"
@mouseleave="sliderMouseleave"
>
<div v-if="series && taskInfo" class="left-top-text">
<div
v-if="taskInfo.IsExistsClinicalData"
class="cd-info"
:title="$t('trials:reading:button:clinicalData')"
>
<svg-icon
style="cursor: pointer;"
icon-class="documentation"
class="svg-icon"
@click.stop="viewCD(series.TaskInfo.VisitTaskId)"
/>
</div>
<h2
v-if="taskInfo.IsReadingShowSubjectInfo"
class="subject-info"
>
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
</h2>
<div>Series: #{{ series.SeriesNumber }}</div>
<div v-if="series.Stack">Image: #{{ `${series.SliceIndex + 1}/${series.Stack.length}` }}</div>
<div>{{ series.Modality }}</div>
</div>
<div
v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1"
class="top-center-tool"
>
<div class="toggle-visit-container">
<div
class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum !== 0 ? '#fff': '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
@dblclick.stop="preventDefault($event)"
>
<i class="el-icon-caret-left" />
</div>
<div class="arrow_text">
{{ series.TaskInfo.TaskBlindName }}
</div>
<div
class="arrw_icon"
:style="{ cursor: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff': '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
@dblclick.stop="preventDefault($event)"
>
<i class="el-icon-caret-right" />
</div>
</div>
</div>
<div v-if="series" class="right-top-text">
<div>{{ series.Description }}</div>
</div>
<div v-if="series" class="left-bottom-text">
<div v-show="mousePosition.index.length > 0">
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}
</div>
<div v-if="(series.Modality === 'CT' || series.Modality === 'DR' || series.Modality === 'CR') && mousePosition.value">
HU: {{ mousePosition.value }}
</div>
<div v-else-if="(series.Modality === 'PT' && mousePosition.value)">
{{mousePosition.modalityUnit}}: {{ digitPlaces === -1 ?mousePosition.value.toFixed(3) :mousePosition.value.toFixed(digitPlaces) }}
</div>
<div v-else-if="mousePosition.value">
Density: {{ mousePosition.value }}
</div>
<div v-show="imageInfo.size">
W*H: {{ imageInfo.size }}
</div>
<div v-show="imageInfo.zoom">
Zoom: {{ imageInfo.zoom }}
</div>
</div>
<div v-if="series" class="right-bottom-text">
<div v-show="imageInfo.location">Location: {{ `${Number(imageInfo.location).toFixed(digitPlaces)} mm` }}</div>
<div v-show="series.SliceThickness">Slice Thickness: {{ `${Number(series.SliceThickness).toFixed(digitPlaces)} mm` }}</div>
<div v-show="imageInfo.wwwc ">WW/WL: {{ imageInfo.wwwc }}</div>
</div>
<div class="orientation-top">
{{ markers.top }}
</div>
<div class="orientation-right">
{{ markers.right }}
</div>
<div class="orientation-bottom">
{{ markers.bottom }}
</div>
<div class="orientation-left">
{{ markers.left }}
</div>
<div ref="sliderBox" class="right-slider-box" @click.stop="clickSlider($event)">
<div :style="{top: sliderInfo.height + '%'}" class="slider" @click.stop.prevent="() => {return}" @mousedown.stop="sliderMousedown($event)" />
</div>
</div>
</template>
<script>
// import * as cornerstonejs from '@cornerstonejs/core'
import {
// RenderingEngine,
// Enums,
// imageLoader,
metaData,
getRenderingEngine,
// eventTarget,
utilities as csUtils
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import {
utilities as csToolsUtils
} from '@cornerstonejs/tools'
import { getPTImageIdInstanceMetadata } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/getPTImageIdInstanceMetadata'
import ptScalingMetaDataProvider from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/ptScalingMetaDataProvider'
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv'
import { vec3 } from 'gl-matrix'
export default {
name: 'ImageViewport',
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
viewportIndex: {
type: Number,
required: true
}
},
data() {
return {
element: '',
series: null,
taskInfo: null,
sliderInfo: {
oldB: null,
oldM: null,
isMove: false,
height: 0
},
mousePosition: {
index: [],
value: null,
modalityUnit: '',
world: []
},
imageInfo: {
zoom: null,
size: null,
location: null,
sliceThickness: null,
wwwc: null
},
digitPlaces: 2,
orientationMarkers: [],
originalMarkers: [],
markers: { top: '', right: '', bottom: '', left: '' },
playClipState: false,
wwwcIdx: 2
}
},
mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
this.initViewport()
})
},
methods: {
initViewport() {
this.element = this.$refs['viewport']
const resizeObserver = new ResizeObserver(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
if (renderingEngine) {
renderingEngine.resize(true, false)
}
})
this.element.oncontextmenu = (e) => e.preventDefault()
resizeObserver.observe(this.element)
this.element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
// this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
// this.element.addEventListener('CORNERSTONE_CAMERA_MODIFIED', this.cameraModified)
this.element.addEventListener('CORNERSTONE_IMAGE_RENDERED', this.imageRendered)
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
this.element.addEventListener('mouseleave', () => {
this.mousePosition.index = []
this.mousePosition.value = null
})
// console.log(cornerstoneTools)
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
},
stackNewImage(e) {
const { detail } = e
this.series.SliceIndex = detail.imageIdIndex
this.sliderInfo.height = detail.imageIdIndex * 100 / (this.series.Stack.length - 1)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
this.imageInfo.size = `${detail.image.columns}*${detail.image.rows}`
const imagePlaneModule = metaData.get('imagePlaneModule', detail.imageId)
this.imageInfo.location = imagePlaneModule.sliceLocation
// this.imageInfo.wwwc = `${Math.round(detail.image.windowWidth)}/${Math.round(detail.image.windowCenter)}`
this.getOrientationMarker()
this.$emit('renderAnnotations', this.series)
// const toolGroupId = `viewport-${this.viewportIndex}`
// const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
// toolGroup.setToolEnabled('ScaleOverlay')
},
imageRendered(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
},
cameraModified(e) {
console.log(e)
},
voiModified(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
},
getOrientationMarker() {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const { viewUp, viewPlaneNormal } = viewport.getCamera()
const viewRight = vec3.create()
vec3.cross(viewRight, viewUp, viewPlaneNormal)
const columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]]
const rowCosines = viewRight
const rowString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(rowCosines)
const columnString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(columnCosines)
const oppositeRowString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(rowString)
const oppositeColumnString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(columnString)
this.markers.top = oppositeColumnString
this.markers.right = rowString
this.markers.bottom = columnString
this.markers.left = oppositeRowString
this.orientationMarkers = [oppositeColumnString, rowString, columnString, oppositeRowString]
if (this.originalMarkers.length === 0) {
this.originalMarkers = [...this.orientationMarkers]
}
},
setMarkers() {
const markers = [...this.orientationMarkers]
for (const key in this.markers) {
const v = markers.shift(0)
this.markers[key] = v
}
},
resetOrientationMarkers() {
if (this.originalMarkers.length > 0) {
this.orientationMarkers = [...this.originalMarkers]
this.setMarkers()
}
},
rotateOrientationMarkers(type) {
if (this.orientationMarkers.length > 0) {
if (type === 1) {
this.resetOrientationMarkers()
return
}
const markers = [...this.orientationMarkers]
if (type === 2) {
//
this.orientationMarkers[0] = markers[2]
this.orientationMarkers[2] = markers[0]
} else if (type === 3) {
//
this.orientationMarkers[1] = markers[3]
this.orientationMarkers[3] = markers[1]
} else if (type === 4) {
// 90
this.orientationMarkers = markers.slice(1, 4).concat(markers[0])
} else if (type === 5) {
// 90
this.orientationMarkers = [markers[3]].concat(markers.slice(0, 3))
}
this.setMarkers()
}
},
toggleClipPlay(isPlay, framesPerSecond) {
this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true })
} else {
cornerstoneTools.utilities.cine.stopClip(viewport.element)
}
},
scrollPage(type) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const numImages = viewport.getImageIds().length
let newImageIdIndex = null
if (type === 0) {
newImageIdIndex = 0
} else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) {
newImageIdIndex = numImages - 1
}
// viewport.setImageIdIndex(newImageIdIndex)
csUtils.jumpToSlice(viewport.element, { imageIndex: newImageIdIndex })
cornerstoneTools.utilities.cine.stopClip(viewport.element)
},
setZoom(ratio) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
if (ratio > 0) {
viewport.setZoom(zoom * 1.05)
} else {
viewport.setZoom(zoom / 1.05)
}
viewport.render()
},
resize(forceFitToWindow) {
console.log('resize: ', forceFitToWindow)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (!forceFitToWindow) {
viewport.setZoom(0.5)
viewport.render()
} else {
viewport.setZoom(1)
viewport.render()
}
},
async prefetchMetadataInformation(imageIdsToPrefetch, modality) {
let taskPromises = []
for (let i = 0; i < imageIdsToPrefetch.length; i++) {
taskPromises.push(cornerstoneDICOMImageLoader.wadouri.loadImage(imageIdsToPrefetch[i]).promise)
if (taskPromises.length >= 6 || i === imageIdsToPrefetch.length - 1) {
let res = await Promise.all(taskPromises)
if (modality === 'PT') {
this.cachePTMetadata(res)
}
taskPromises = []
}
}
},
cachePTMetadata(images) {
images.map(i=>{
const instanceMetadata = getPTImageIdInstanceMetadata(i.imageId)
if (typeof instanceMetadata.CorrectedImage === 'string') {
instanceMetadata.CorrectedImage = instanceMetadata.CorrectedImage.split('\\')
}
if (instanceMetadata) {
const suvScalingFactors = calculateSUVScalingFactors([instanceMetadata])
ptScalingMetaDataProvider.addInstance(i.imageId, suvScalingFactors[0])
}
})
},
async setSeriesInfo(obj, isLocate = false) {
try {
if (this.series && obj.Id === this.series.Id && obj.Description === this.series.Description && !isLocate) {
obj.SliceIndex = this.series.SliceIndex
}
// if (isLocate && obj.SliceIndex === this.series.SliceIndex) return
if (this.series?.Stack && obj.Stack[obj.SliceIndex] === this.series.Stack[this.series.SliceIndex]) return
this.toggleClipPlay(false)
this.series = { ...obj }
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let imageId = obj.ImageIds[obj.SliceIndex] ? obj.ImageIds[obj.SliceIndex] : obj.ImageIds[0]
const image = await cornerstoneDICOMImageLoader.wadouri.loadImage(imageId).promise
if (obj.Modality === 'PT') {
this.cachePTMetadata([image])
}
this.prefetchMetadataInformation(obj.ImageIds, obj.Modality)
await viewport.setStack(this.series.Stack, obj.SliceIndex)
viewport.render()
} catch (e) {
console.log(e)
}
},
cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail
const worldPoint = currentPoints.world
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let referencedImageId = viewport.getCurrentImageId()
const data = viewport.getImageData()
if (!data) return
const { dimensions, imageData, metadata, voxelManager } = data
const index = imageData.worldToIndex(worldPoint)
index[0] = Math.floor(index[0])
index[1] = Math.floor(index[1])
index[2] = Math.floor(index[2])
this.mousePosition.index = index
const modality = metadata.Modality
let ijk = csUtils.transformWorldToIndex(imageData, worldPoint)
ijk = vec3.round(ijk, ijk);
if (csUtils.indexWithinDimensions(ijk, dimensions)) {
this.isHandleOutsideImage = false
let value = voxelManager.getAtIJKPoint(ijk)
ijk[2] = viewport.getCurrentImageIdIndex()
let modalityUnit
if (modality === 'US') {
const calibratedResults = csToolsUtils.getCalibratedProbeUnitsAndValue(image, [ijk])
const hasEnhancedRegionValues = calibratedResults.values.every(
(value) => value !== null
)
value = (hasEnhancedRegionValues ? calibratedResults.values : value)
modalityUnit = hasEnhancedRegionValues
? calibratedResults.units
: 'raw';
} else {
const scalingModule = referencedImageId && metaData.get('scalingModule', referencedImageId)
const isSuvScaled = typeof scalingModule?.suvbw === 'number'
const pixelUnitsOptions = {
isPreScaled: csToolsUtils.viewport.isViewportPreScaled(viewport, referencedImageId),
isSuvScaled: isSuvScaled,
}
modalityUnit = csToolsUtils.getPixelValueUnits(
modality,
referencedImageId,
pixelUnitsOptions
);
}
this.mousePosition.value = value
this.mousePosition.modalityUnit = modalityUnit
}
},
toggleTask(evt, visitTaskNum, i) {
this.$emit('activeViewport', this.viewportIndex)
const num = visitTaskNum + i
if (num >= 0 && num <= this.taskInfo.VisitNum) {
this.$emit('toggleTaskByViewport', { series: this.series, visitTaskNum: num })
}
evt.stopImmediatePropagation()
evt.stopPropagation()
evt.preventDefault()
},
viewCD(taskId) {
this.$emit('previewCD', taskId)
},
setWwwcIdx(idx) {
this.wwwcIdx = idx
},
clickSlider(e) {
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
this.sliderInfo.height = height
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseup(e) {
this.sliderInfo.isMove = false
},
sliderMousedown(e) {
const boxHeight = this.$refs['sliderBox'].clientHeight
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
this.sliderInfo.oldM = e.clientY
this.sliderInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
sliderMousemove(e) {
if (!this.sliderInfo.isMove) return
const delta = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
const boxHeight = this.$refs['sliderBox'].clientHeight
if (delta < 0) return
if (delta > boxHeight) return
const height = delta * 100 / boxHeight
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
this.sliderInfo.height = height
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseleave(e) {
if (!this.sliderInfo.isMove) return
this.sliderInfo.isMove = false
},
preventDefault(e) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
}
}
}
</script>
<style lang="scss" scoped>
.viewport-wrapper {
width:100%;
height:100%;
position: relative;
.left-top-text {
position: absolute;
left: 5px;
top: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
.cd-info {
color: #ddd;
font-size: 18px;
}
.subject-info {
color:#f44336;
padding: 5px 0px;
margin: 0;
}
}
.top-center-tool {
position: absolute;
left:50%;
top: 5px;
transform: translateX(-50%);
z-index: 1;
.toggle-visit-container {
display: flex;
}
.arrw_icon{
width: 20px;
height: 20px;
background-color: #3f3f3f;
text-align: center;
line-height: 20px;
border-radius: 10%;
}
.arrow_text{
height: 20px;
line-height: 20px;
background-color: #00000057;
color: #fff;
padding:0 10px;
font-size: 14px;
}
}
.right-top-text {
position: absolute;
right: 5px;
top: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
}
.left-bottom-text {
position: absolute;
left: 5px;
bottom: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-bottom-text {
position: absolute;
right: 5px;
bottom: 5px;
color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-slider-box {
position: absolute;
right: 1px;
height: calc(100% - 140px);
transform: translateY(-50%);
top: calc(50% - 30px);
width: 10px;
background: #333;
z-index: 1;
cursor: pointer;
}
.right-slider-box:after{
content: '';
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
background: #333;
}
.slider {
height: 20px;
width: 100%;
position: absolute;
top: 0;
z-index:10;
background: #9e9e9e;
cursor: move
}
.orientation-top {
position: absolute;
left: 50%;
top: 30px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-bottom {
position: absolute;
left: 50%;
bottom: 15px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-left {
position: absolute;
top: 50%;
left: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
.orientation-right {
position: absolute;
top: 50%;
right: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
}
</style>

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