923 Commits

Author SHA1 Message Date
wangxiaoshuang 65e4192312 初始化 2026-07-13 12:59:14 +08:00
wangxiaoshuang 28ac64747b 锁定模糊度修改
continuous-integration/drone/push Build is passing
2026-07-03 10:00:28 +08:00
wangxiaoshuang 5e014120c1 非dicom匿名矩形工具问题修复
continuous-integration/drone/push Build is passing
2026-07-02 17:03:53 +08:00
wangxiaoshuang 76a937066d 中心调研表状态已锁定pm也不允许修改
continuous-integration/drone/push Build is passing
2026-07-02 16:09:30 +08:00
caiyiling 414af5db9e 路由更改
continuous-integration/drone/push Build is passing
2026-07-02 14:53:50 +08:00
caiyiling 8cc04c8bcf Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-07-02 14:47:26 +08:00
caiyiling 3592fe7ec7 列宽调整 2026-07-02 14:47:14 +08:00
wangxiaoshuang 22705f6035 中心调研表在选择仅上传文件时进行联系人和联系人电话必填校验
continuous-integration/drone/push Build is pending
2026-07-02 14:16:10 +08:00
caiyiling 698dca94d4 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-07-02 14:06:40 +08:00
caiyiling e1f3669aab 列宽调整 2026-07-02 14:06:17 +08:00
wangxiaoshuang 8f2109b4cd 中心调研表提交校验修改
continuous-integration/drone/push Build is passing
2026-07-02 13:51:44 +08:00
wangxiaoshuang 433cfdc123 【中心调研】中文环境登录后,中心调研表是英文的
continuous-integration/drone/push Build is passing
2026-07-02 11:50:02 +08:00
wangxiaoshuang a278b032e2 非dicom匿名对比添加匿名前、匿名后提示 2026-07-02 10:50:11 +08:00
wangxiaoshuang 2ec96a82f0 像素匿名按钮显示条件修改
continuous-integration/drone/push Build is passing
2026-07-02 10:37:28 +08:00
wangxiaoshuang b7b763651f 完全随机判断修改
continuous-integration/drone/push Build is passing
2026-07-02 10:01:09 +08:00
wangxiaoshuang a07cf5f4d0 1
continuous-integration/drone/push Build is passing
2026-07-01 18:01:14 +08:00
wangxiaoshuang 77f0c91e74 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-07-01 17:58:46 +08:00
wangxiaoshuang 54e9e6f6ad 阅片中上传影像后,查看后处理的影像时,关联访视的Tab需要处理 2026-07-01 17:58:36 +08:00
caiyiling ba71d73407 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-07-01 17:46:34 +08:00
caiyiling 9a64fd1bfd 拦截搜索表单默认提交事件 2026-07-01 17:44:00 +08:00
wangxiaoshuang 9b7d9d3c88 中心调研链接有效期为空时验证码不展示
continuous-integration/drone/push Build is passing
2026-07-01 17:32:37 +08:00
wangxiaoshuang 5ec234c9dd 中心调研支持上传文件
continuous-integration/drone/push Build is passing
2026-07-01 17:24:25 +08:00
caiyiling 4709125107 非dicom图像质控视口信息更改;添加适应窗口、适应图像功能
continuous-integration/drone/push Build is passing
2026-07-01 16:59:24 +08:00
caiyiling 0bbf537ddf 非dicom质控检查列表添加排序
continuous-integration/drone/push Build is passing
2026-07-01 11:03:20 +08:00
caiyiling aba5dec904 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-07-01 10:01:30 +08:00
caiyiling b04530ddd2 阅片保存病灶逻辑更改 2026-07-01 10:00:29 +08:00
wangxiaoshuang 27bacd95d2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-07-01 09:23:43 +08:00
wangxiaoshuang 9385b1f671 非DICOM阅片影像中存储在标记信息,需要在质控时进行处理 2026-07-01 09:23:33 +08:00
caiyiling cdcc98efeb 1
continuous-integration/drone/push Build is passing
2026-07-01 09:09:11 +08:00
caiyiling bb00ac10f8 阅片完成状态下radio样式更改;阅片中提交和保存优化;
continuous-integration/drone/push Build is passing
2026-06-30 16:00:52 +08:00
caiyiling e184b5255d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-30 09:53:47 +08:00
caiyiling 095536ca33 反馈按钮更改 2026-06-30 09:53:29 +08:00
wangxiaoshuang 83a1d2d5a4 1
continuous-integration/drone/push Build is passing
2026-06-30 09:34:47 +08:00
caiyiling e91ce47f28 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-29 17:57:05 +08:00
caiyiling 02b153c524 历史自定义阅片样式及反馈按钮显隐维护 2026-06-29 17:56:27 +08:00
wangxiaoshuang 2b93fd18ff 阅片中上传影像后,查看后处理的影像时,关联访视的Tab需要处理
continuous-integration/drone/push Build is passing
2026-06-29 17:25:04 +08:00
caiyiling c80e7ca5a9 当浏览器窗口的大小有改变时,适应窗口/1:1分辨率图像效果保持不变
continuous-integration/drone/push Build is passing
2026-06-29 17:19:29 +08:00
caiyiling e7562fbe83 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main 2026-06-29 16:29:13 +08:00
caiyiling 92da42f010 QC质控查看非dicom文件页面更改 2026-06-29 16:28:33 +08:00
wangxiaoshuang 92bc105281 管理员重置账号密码后,用户登录后重新设置密码的页面存在问题
continuous-integration/drone/push Build is passing
2026-06-29 16:09:28 +08:00
wangxiaoshuang 105bd48201 Merge branch 'uat'
continuous-integration/drone/push Build is passing
2026-06-29 13:26:45 +08:00
wangxiaoshuang d57c3b5157 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is running
2026-06-29 11:41:37 +08:00
wangxiaoshuang 30fdd91764 非DICOM阅片页面样式问题 2026-06-29 11:41:17 +08:00
caiyiling f03db6f995 阅片页面下拉工具框大小调整
continuous-integration/drone/push Build is passing
2026-06-29 11:12:00 +08:00
caiyiling 022a2005f1 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-25 16:52:37 +08:00
caiyiling e64498858d 受试者编号列宽调整 2026-06-25 16:52:12 +08:00
wangxiaoshuang ffbf12f845 分割球体工具图标更改
continuous-integration/drone/push Build is passing
2026-06-24 15:17:18 +08:00
wangxiaoshuang c0523e2855 【中心调研】调研表过期修改,跳转至过期页面
continuous-integration/drone/push Build is passing
2026-06-24 15:13:21 +08:00
caiyiling 794ebeb42c 1
continuous-integration/drone/push Build is pending
2026-06-24 13:46:55 +08:00
caiyiling ffdf3d2376 非dicom标记更改
continuous-integration/drone/push Build is passing
2026-06-24 13:36:40 +08:00
caiyiling f69a297b2b 角色列表移除IsInternal属性
continuous-integration/drone/push Build is passing
2026-06-24 11:07:58 +08:00
caiyiling 39bd20e880 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-24 10:49:46 +08:00
caiyiling 8a5be1a0ea 1 2026-06-24 10:49:20 +08:00
wangxiaoshuang b6f8b41615 阅片页面阅片问题点击保存后,无法提交了
continuous-integration/drone/push Build is passing
2026-06-23 15:10:27 +08:00
wangxiaoshuang bddcadeb89 sulpeak计算公式修改
continuous-integration/drone/push Build is passing
2026-06-23 10:31:10 +08:00
wangxiaoshuang 2e388db02c 分割新工具禁用修改
continuous-integration/drone/push Build is passing
2026-06-22 17:43:22 +08:00
wangxiaoshuang 370f99eabc 分割球体工具触发自动计算修改
continuous-integration/drone/push Build is passing
2026-06-22 16:58:39 +08:00
wangxiaoshuang e2bd9feae6 中心调研表分享信息修改
continuous-integration/drone/push Build is passing
2026-06-22 15:17:00 +08:00
wangxiaoshuang abbc15cb09 增加对于SULpeak测量的支持
continuous-integration/drone/push Build is passing
2026-06-22 15:08:51 +08:00
wangxiaoshuang 87f088ac05 中兴调研表链接过期判断
continuous-integration/drone/push Build is passing
2026-06-18 17:55:23 +08:00
wangxiaoshuang 0971f2b922 1 2026-06-18 17:22:50 +08:00
wangxiaoshuang e93be4cf9c 中心调研表国际化判断
continuous-integration/drone/push Build is passing
2026-06-18 17:05:54 +08:00
wangxiaoshuang 2fca310327 【项目权限】切换角色后进入了没有权限的项目
continuous-integration/drone/push Build is passing
2026-06-18 13:55:09 +08:00
wangxiaoshuang 97411b7eaf 中心调研二维码和链接的时间有效性
continuous-integration/drone/push Build is passing
2026-06-18 13:31:20 +08:00
caiyiling 0631af4d9b 序列切换bug修复
continuous-integration/drone/push Build is passing
2026-06-18 12:34:39 +08:00
caiyiling 2794cabdc8 关键序列面板展示信息补充 2026-06-18 11:28:50 +08:00
caiyiling 8203b3d738 关键序列逻辑更改
continuous-integration/drone/push Build is passing
2026-06-18 09:58:04 +08:00
caiyiling 4d16ebb488 受试者状态变更表单更改
continuous-integration/drone/push Build is running
2026-06-17 16:44:37 +08:00
caiyiling b241682fa9 补充定圆工具标注复制功能
continuous-integration/drone/push Build is passing
2026-06-17 13:31:00 +08:00
wangxiaoshuang cb16658190 Merge branch 'uat'
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/read-task/index.vue
2026-06-17 09:23:22 +08:00
wangxiaoshuang 8b766672b5 中心调研表选择中心时可选择禁用中心
continuous-integration/drone/push Build is passing
2026-06-16 17:16:07 +08:00
wangxiaoshuang b7d45456a6 演示项目可以添加虚拟阅片人
continuous-integration/drone/push Build is passing
2026-06-16 14:23:22 +08:00
wangxiaoshuang a4241bccf7 获取字典接口统一添加trialId
continuous-integration/drone/push Build is passing
2026-06-16 14:22:17 +08:00
wangxiaoshuang 212a545aa9 演示项目可以添加虚拟阅片人
continuous-integration/drone/push Build is passing
2026-06-16 13:45:00 +08:00
caiyiling 11c4df2852 阅片页面注意事项更改
continuous-integration/drone/push Build is passing
2026-06-16 13:33:53 +08:00
wangxiaoshuang 05bcb982dd 影像汇总关键图下载可下载分割文件
continuous-integration/drone/push Build is passing
2026-06-16 13:30:41 +08:00
wangxiaoshuang af62056962 Merge branch 'uat'
continuous-integration/drone/push Build is passing
2026-06-16 10:26:50 +08:00
caiyiling de7cd64c9b 关键序列更改;lugano标准交互更改 2026-06-15 13:53:04 +08:00
wangxiaoshuang 83f73db692 中心调研表设备调研备注改为非必填
continuous-integration/drone/push Build is passing
2026-06-15 09:27:41 +08:00
caiyiling 71418c393e 图标更改
continuous-integration/drone/push Build is running
2026-06-11 15:48:53 +08:00
caiyiling 6629fc0a17 1
continuous-integration/drone/push Build is pending
2026-06-11 13:25:00 +08:00
caiyiling b7c00a0b70 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-11 13:18:42 +08:00
caiyiling 3907123c1d 系统通知功能优化 2026-06-11 13:18:28 +08:00
wangxiaoshuang e1822126bb 当裁判阅片完成后,列表中高亮或加粗显示最近一次裁判选中的阅片结果
continuous-integration/drone/push Build is passing
2026-06-11 11:36:47 +08:00
caiyiling 05e9bbb050 当前访视增加关键序列
continuous-integration/drone/push Build is passing
2026-06-10 15:59:55 +08:00
caiyiling 6b1fffb800 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-10 13:58:43 +08:00
caiyiling d0d8819ab4 关键序列更改 2026-06-10 13:58:25 +08:00
wangxiaoshuang 0e430ef8c9 Merge branch 'uat'
continuous-integration/drone/push Build is running
2026-06-10 13:58:19 +08:00
wangxiaoshuang 0b87a1845c 表格问题字段默认值
continuous-integration/drone/push Build is passing
2026-06-10 13:57:57 +08:00
wangxiaoshuang e7a13be6e4 分割标记边框调节刻度设置为1
continuous-integration/drone/push Build is passing
2026-06-10 10:39:20 +08:00
caiyiling f7b5ab0281 1
continuous-integration/drone/push Build is passing
2026-06-10 10:33:33 +08:00
caiyiling e3be28ca17 非dicom阅片截图文件名称更改
continuous-integration/drone/push Build is running
2026-06-10 10:31:35 +08:00
wangxiaoshuang ee34e6cdc2 受试者阅片结果趋势图优化
continuous-integration/drone/push Build is passing
2026-06-09 16:39:22 +08:00
wangxiaoshuang 8c83897c6e 阅片人页面的工作量统计,改为二级查询 2026-06-09 16:15:26 +08:00
caiyiling 3a6956c031 列宽调整
continuous-integration/drone/push Build is passing
2026-06-09 15:18:53 +08:00
caiyiling 73e7b4c3fa Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-09 15:09:29 +08:00
caiyiling 7f9080398a 稽查列表更改 2026-06-09 15:08:54 +08:00
wangxiaoshuang 4c7c0cce47 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is running
2026-06-09 14:57:41 +08:00
wangxiaoshuang eda4b31dda DICOM分割工具的个性化配置 2026-06-09 14:57:38 +08:00
caiyiling dc84d0e96f Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is pending
2026-06-09 13:43:46 +08:00
caiyiling 7fea4b938f 非DICOM阅片工具-支持视频阅片 2026-06-09 13:43:20 +08:00
wangxiaoshuang 7325760c23 在账号长时间未访问,锁定或者退出时,不能展示页面数据
continuous-integration/drone/push Build is passing
2026-06-09 13:39:02 +08:00
wangxiaoshuang 1a26d3885a 1
continuous-integration/drone/push Build is passing
2026-06-08 15:42:58 +08:00
caiyiling f9c9d0be6d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-06-08 14:37:22 +08:00
caiyiling ebfbe27d0c 全局阅片、裁判阅片时不显示复制后续访视数据 2026-06-08 14:36:51 +08:00
wangxiaoshuang 37257da722 1
continuous-integration/drone/push Build is passing
2026-06-08 14:11:09 +08:00
wangxiaoshuang 6d214727b5 Merge branch 'uat'
continuous-integration/drone/push Build is passing
2026-06-08 13:24:38 +08:00
wangxiaoshuang 1db50cff3b 质控搜索条件字段变更
continuous-integration/drone/push Build is passing
2026-06-08 13:23:09 +08:00
wangxiaoshuang 6d17a1f3cd Merge branch 'uat'
continuous-integration/drone/push Build is passing
2026-06-08 09:06:08 +08:00
wangxiaoshuang f38f1f465a 自动发布
continuous-integration/drone/push Build is passing
2026-06-05 21:53:04 +08:00
wangxiaoshuang db627afeda 1 2026-06-05 18:15:19 +08:00
caiyiling fef7215bdb Merge branch 'uat' of https://gitea.frp.extimaging.com/XCKJ/irc_web into uat
continuous-integration/drone/push Build was killed
2026-06-05 15:04:21 +08:00
caiyiling 0718a70f91 Merge branch 'main' into uat 2026-06-05 15:02:32 +08:00
wangxiaoshuang da21972c63 Merge branch 'main' into uat
continuous-integration/drone/push Build is pending
2026-06-05 15:01:31 +08:00
wangxiaoshuang 361ab4e2fd 已阅片访视表格添加查看按钮
continuous-integration/drone/push Build is pending
2026-06-05 15:01:07 +08:00
caiyiling 7a52507d27 阅片页面检查列表更改
continuous-integration/drone/push Build is passing
2026-06-05 14:58:46 +08:00
caiyiling 83dc28008f Merge branch 'main' into uat
continuous-integration/drone/push Build is failing
2026-06-04 17:38:19 +08:00
caiyiling 323b76036a mri-pdff标注清除修改
continuous-integration/drone/push Build is passing
2026-06-04 17:00:02 +08:00
wangxiaoshuang 4b7bb8df95 表格问题增加属性 2026-06-04 14:59:05 +08:00
caiyiling 46aa64365f Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-06-03 10:24:47 +08:00
caiyiling d2fae40100 上传预览多帧更改 2026-06-03 10:24:24 +08:00
wangxiaoshuang 4030b1c95b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-06-02 14:57:26 +08:00
wangxiaoshuang d689c23f5a 分割工具半径区间增加 2026-06-02 14:57:22 +08:00
caiyiling 4a7f8a0a93 非dicom自定义阅片报告页更改
continuous-integration/drone/push Build is passing
2026-06-02 11:38:09 +08:00
caiyiling 7daa7fda0c 是否可测量限制更改 2026-06-02 11:14:52 +08:00
caiyiling b25426711a 1
continuous-integration/drone/push Build is passing
2026-06-02 10:59:46 +08:00
caiyiling f06f7827cf Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-02 10:46:42 +08:00
caiyiling 3ea46b5d1e MRI-PDFF肝脏分段保存接口更改;自定义标准报告更改 2026-06-02 10:46:02 +08:00
wangxiaoshuang 72634c785d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-06-02 10:24:03 +08:00
wangxiaoshuang 2dbf6a1fb3 分割画笔工具添加半径区间选项 2026-06-02 10:23:53 +08:00
caiyiling 755f305389 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-06-02 10:14:13 +08:00
caiyiling 29a6870fb5 Enhanced MRI-PDFF标准更改 2026-06-02 10:13:30 +08:00
wangxiaoshuang 2d99e074b8 后处理上传处理
continuous-integration/drone/push Build is passing
2026-06-01 14:51:19 +08:00
wangxiaoshuang 6e6e2d11d0 影像上传列表受试者状态查询字段变更
continuous-integration/drone/push Build is passing
2026-05-29 17:29:22 +08:00
wangxiaoshuang 6b8711232e 1
continuous-integration/drone/push Build is passing
2026-05-29 10:13:55 +08:00
wangxiaoshuang eb0b9d6fb8 中心调研表配置修改 2026-05-29 10:08:57 +08:00
wangxiaoshuang 7ef1cafeff 1
continuous-integration/drone/push Build is passing
2026-05-29 09:58:23 +08:00
wangxiaoshuang 3ac3e41d0d 中心调研部分字段添加必填标识 2026-05-29 09:13:44 +08:00
wangxiaoshuang 1763e49650 中心调研表添加字段
continuous-integration/drone/push Build is passing
2026-05-28 15:02:18 +08:00
caiyiling 016a5e93ea 1
continuous-integration/drone/push Build is passing
2026-05-28 10:45:29 +08:00
caiyiling e4d731222b 1
continuous-integration/drone/push Build is passing
2026-05-27 17:55:00 +08:00
caiyiling aeeba1dfb7 1
continuous-integration/drone/push Build is passing
2026-05-27 15:37:55 +08:00
caiyiling d7ebed0b05 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-27 15:06:56 +08:00
caiyiling 312e85d9b3 融合视口标注绑定信息更改 2026-05-27 15:06:19 +08:00
wangxiaoshuang 3ee32c2e56 质控风险控制修改
continuous-integration/drone/push Build is passing
2026-05-27 09:43:18 +08:00
wangxiaoshuang 2778b34f14 1
continuous-integration/drone/push Build is passing
2026-05-26 17:52:27 +08:00
wangxiaoshuang 6736121309 1 2026-05-26 14:10:50 +08:00
wangxiaoshuang e48c00f817 影像质控时,可以下载阅片影像
continuous-integration/drone/push Build is pending
2026-05-26 13:45:06 +08:00
wangxiaoshuang e5f7ad3b31 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-26 10:40:01 +08:00
wangxiaoshuang b7a0a336dd 部分问题解决 2026-05-26 10:39:52 +08:00
caiyiling d83a086087 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is pending
2026-05-26 10:24:43 +08:00
caiyiling d03ce19b02 阅片页面多帧预览高亮更改 2026-05-26 10:24:16 +08:00
wangxiaoshuang a2668b39be 部分问题解决
continuous-integration/drone/push Build is passing
2026-05-26 10:19:37 +08:00
caiyiling a30fd58d79 多帧图像预览更改;数据同步检查列表补充排序字段
continuous-integration/drone/push Build is passing
2026-05-26 09:40:04 +08:00
caiyiling 31d0872653 SPECT测量更改 2026-05-25 13:26:06 +08:00
caiyiling e63e38222e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-25 13:17:17 +08:00
caiyiling 65d7a95d5f 1 2026-05-25 13:17:04 +08:00
wangxiaoshuang 298619717a 项目配置修改
continuous-integration/drone/push Build is passing
2026-05-25 10:38:56 +08:00
caiyiling d6713ba9a4 circleROI测量数据更改
continuous-integration/drone/push Build is passing
2026-05-25 09:16:31 +08:00
caiyiling 0e252b0377 添加自定义MIPJumpToClickTool工具
continuous-integration/drone/push Build is passing
2026-05-22 17:58:08 +08:00
caiyiling 52ab454860 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-22 17:10:28 +08:00
caiyiling 0e2e57446b 预览访视影像样式更改;融合视口工具优化; 2026-05-22 17:09:47 +08:00
wangxiaoshuang 94b0354fe4 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-22 15:25:25 +08:00
wangxiaoshuang 93ed9943fa 中心调研修改 2026-05-22 15:25:21 +08:00
caiyiling e04e94a792 total数值绑定更改
continuous-integration/drone/push Build is passing
2026-05-22 13:57:58 +08:00
caiyiling b7c57c3c27 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-22 12:29:04 +08:00
caiyiling 015eb78b70 lugano阅片标准页面十字线工具更改 2026-05-22 12:28:28 +08:00
wangxiaoshuang 04580ed1bb 项目逻辑配置中增加:质控时,可下载影像、访视失访时,后续访视可阅片
continuous-integration/drone/push Build is passing
2026-05-21 15:31:54 +08:00
wangxiaoshuang b6877d4fe8 1
continuous-integration/drone/push Build is passing
2026-05-21 15:01:43 +08:00
wangxiaoshuang b53f566160 系统配置、中心调研配置
continuous-integration/drone/push Build is passing
2026-05-21 14:41:33 +08:00
caiyiling c767004a2d 1
continuous-integration/drone/push Build is running
2026-05-21 13:53:02 +08:00
caiyiling 3a546e6e89 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-05-21 13:52:42 +08:00
caiyiling 6af2f0555e 十字线功能优化;MR图像显示默认使用图像的窗宽窗位; 2026-05-21 13:41:39 +08:00
wangxiaoshuang a82526e21d 中心调研配置切换设备调研时初始化采集参数
continuous-integration/drone/push Build is pending
2026-05-21 09:34:42 +08:00
wangxiaoshuang c65ad92d39 中心调研设备调研修改
continuous-integration/drone/push Build is passing
2026-05-20 17:41:08 +08:00
wangxiaoshuang 36d5661044 分割标记与表格问题绑定修改
continuous-integration/drone/push Build is passing
2026-05-20 14:58:38 +08:00
wangxiaoshuang feb94dc832 1
continuous-integration/drone/push Build is passing
2026-05-20 09:31:13 +08:00
wangxiaoshuang 756750783c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-05-20 09:12:22 +08:00
wangxiaoshuang db3f7b4cde 分割标记与表格问题进行绑定 2026-05-20 09:12:19 +08:00
caiyiling a9d62cf28d 任务级别列表更改
continuous-integration/drone/push Build is passing
2026-05-20 09:01:43 +08:00
caiyiling 04014ab524 其他类型文件同步数据更改
continuous-integration/drone/push Build is passing
2026-05-19 15:26:06 +08:00
caiyiling 2a68b40875 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is pending
2026-05-19 13:32:40 +08:00
caiyiling 375a7e7071 1 2026-05-19 13:32:23 +08:00
wangxiaoshuang efc3b03392 分割部分功能按钮添加国际化
continuous-integration/drone/push Build is passing
2026-05-18 15:28:56 +08:00
wangxiaoshuang 730a375509 1
continuous-integration/drone/push Build is passing
2026-05-15 17:01:08 +08:00
wangxiaoshuang d34b4b796c 关于弹框修改
continuous-integration/drone/push Build is passing
2026-05-15 11:35:23 +08:00
wangxiaoshuang 427f060935 1
continuous-integration/drone/push Build is passing
2026-05-15 10:17:38 +08:00
wangxiaoshuang 6a10cb1afe Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-15 09:55:47 +08:00
wangxiaoshuang 962ac2e693 时区显示增加配置 2026-05-15 09:55:42 +08:00
caiyiling 3567f2d625 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-14 15:12:58 +08:00
caiyiling bd980cd867 1 2026-05-14 15:12:36 +08:00
wangxiaoshuang 284432ffa4 支持在个人中心修改工作语言
continuous-integration/drone/push Build is passing
2026-05-14 09:39:59 +08:00
wangxiaoshuang 16e2fbc8ff 1
continuous-integration/drone/push Build is passing
2026-05-13 16:22:20 +08:00
wangxiaoshuang ac6be424ee 视口为单视口且不在mpr、融合模式时双击放大视口功能屏蔽 2026-05-13 15:37:23 +08:00
wangxiaoshuang 351b2a627f 退出mpr模式后去除对mpr窗口监听
continuous-integration/drone/push Build is pending
2026-05-13 15:30:58 +08:00
caiyiling dd919f123e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-13 14:07:49 +08:00
caiyiling 3a33abf02e 数据同步检查列表默认排序字段更改 2026-05-13 14:06:00 +08:00
wangxiaoshuang 917373e081 分割恢复提示语修改
continuous-integration/drone/push Build is passing
2026-05-13 11:23:55 +08:00
wangxiaoshuang 632463327c 多帧像素匿名和其他影像全序列应用匿名自动更新缩略图 2026-05-13 09:46:16 +08:00
wangxiaoshuang 59a14c0e37 多个分割分组恢复分割报错问题
continuous-integration/drone/push Build is passing
2026-05-13 09:36:52 +08:00
wangxiaoshuang 511640f66f 分割恢复时清除分割片段弹框
continuous-integration/drone/push Build is passing
2026-05-12 15:12:06 +08:00
wangxiaoshuang c26f5df102 国际多中心的项目,用户UI的语言匹配问题 2026-05-12 14:52:44 +08:00
caiyiling 98e9af71a3 解决Photometric Interpretation为YBR_FULL_422编码格式的dicom文件渲染异常问题
continuous-integration/drone/push Build is passing
2026-05-12 14:09:50 +08:00
wangxiaoshuang b59e0c12f6 1
continuous-integration/drone/push Build is passing
2026-05-12 11:27:56 +08:00
wangxiaoshuang fed2677689 分割分组重命名时传入文件大小
continuous-integration/drone/push Build is passing
2026-05-12 10:55:07 +08:00
wangxiaoshuang a55278e323 分割标记橡皮檫工具问题解决
continuous-integration/drone/push Build is passing
2026-05-12 10:29:35 +08:00
wangxiaoshuang 8f808d73b5 反馈修改
continuous-integration/drone/push Build is passing
2026-05-11 14:15:58 +08:00
wangxiaoshuang 717c5a6529 分割恢复问题解决
continuous-integration/drone/push Build is passing
2026-05-11 13:58:51 +08:00
wangxiaoshuang ec676d8d2b 数据匿名样式调整
continuous-integration/drone/push Build is passing
2026-05-11 13:26:03 +08:00
wangxiaoshuang 2ce14c6d72 热键s下载
continuous-integration/drone/push Build is passing
2026-05-11 11:17:03 +08:00
wangxiaoshuang 10b5bba0dd 分割恢复优化 2026-05-11 10:35:14 +08:00
wangxiaoshuang 159a36cd70 图标功能修改
continuous-integration/drone/push Build is pending
2026-05-11 10:30:27 +08:00
wangxiaoshuang 4a17946598 分割恢复部分问题解决
continuous-integration/drone/push Build is passing
2026-05-09 18:00:26 +08:00
wangxiaoshuang d6f36cbbda 数据匿名按钮样式修改
continuous-integration/drone/push Build is passing
2026-05-09 15:33:35 +08:00
wangxiaoshuang e6a15e35f6 看板页面的地图需要展示
continuous-integration/drone/push Build is passing
2026-05-09 14:33:15 +08:00
wangxiaoshuang 27a9ccd3c2 数据匿名多个编辑选框应用时清除
continuous-integration/drone/push Build is failing
2026-05-09 10:56:21 +08:00
wangxiaoshuang e8dda21459 数据匿名回复全部判断条件变更 2026-05-09 10:29:23 +08:00
wangxiaoshuang 7ebbfb9621 数据匿名应用时清除遮盖标记
continuous-integration/drone/push Build is passing
2026-05-09 09:45:16 +08:00
caiyiling 9da7c1a159 1
continuous-integration/drone/push Build is passing
2026-05-08 17:21:33 +08:00
caiyiling 197f17fc99 1
continuous-integration/drone/push Build is passing
2026-05-08 15:28:10 +08:00
caiyiling d680c57482 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main 2026-05-08 15:04:58 +08:00
caiyiling 7266d0a4f5 截图更改及长短径工具更改 2026-05-08 15:04:26 +08:00
wangxiaoshuang 3e19e85a8d 提示语添加限制条件
continuous-integration/drone/push Build is pending
2026-05-08 15:00:03 +08:00
caiyiling c9057e12cd 多帧影像切换bug修复
continuous-integration/drone/push Build is passing
2026-05-08 13:56:09 +08:00
caiyiling 10bac01371 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-08 11:39:40 +08:00
caiyiling 67d54aedb7 1 2026-05-08 11:39:30 +08:00
wangxiaoshuang 1a21aa38f3 下载、数据匿名问题修改
continuous-integration/drone/push Build is pending
2026-05-08 11:38:56 +08:00
caiyiling 64f0998896 样式调整
continuous-integration/drone/push Build is passing
2026-05-08 11:33:39 +08:00
caiyiling 04d9a53a0e 临床数据状态重置更改
continuous-integration/drone/push Build is passing
2026-05-08 10:22:06 +08:00
wangxiaoshuang fd0412004e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-07 17:43:35 +08:00
wangxiaoshuang 64ef1e513c 影像匿名多帧优化 2026-05-07 17:43:28 +08:00
caiyiling a83349387a 注射时间、成像时间输入添加限制
continuous-integration/drone/push Build is passing
2026-05-07 17:23:53 +08:00
caiyiling 9500842628 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-07 16:41:17 +08:00
caiyiling 998e340919 临床数据更新状态按钮功能更改 2026-05-07 16:40:33 +08:00
wangxiaoshuang 753127381f 1
continuous-integration/drone/push Build is passing
2026-05-07 16:05:42 +08:00
wangxiaoshuang a5c3dac047 下载失败跳过进入下一个任务 2026-05-07 16:01:09 +08:00
wangxiaoshuang a7337a347b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-05-07 15:20:18 +08:00
wangxiaoshuang 85b88d4564 下载文件 2026-05-07 15:20:13 +08:00
wangxiaoshuang 763e00a6ca 分割数据恢复 2026-05-07 15:20:01 +08:00
caiyiling 6a345e35cd 表格列宽调整
continuous-integration/drone/push Build was killed
2026-05-07 13:59:31 +08:00
caiyiling 09e9c62f3c pt临床数据弹窗取消点击modal关闭Dialog
continuous-integration/drone/push Build is passing
2026-05-07 13:52:28 +08:00
caiyiling af97e2b4ed crc修改pt临床数据更改
continuous-integration/drone/push Build is passing
2026-05-07 12:16:01 +08:00
caiyiling e0dd443d84 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-07 11:10:45 +08:00
caiyiling 1c0cdde9ad 质控临床数据更改 2026-05-07 11:08:57 +08:00
wangxiaoshuang e100d45bc1 文件上传信息获取
continuous-integration/drone/push Build is passing
2026-05-07 10:20:53 +08:00
wangxiaoshuang 49c7482d76 匿名数据部分问题解决
continuous-integration/drone/push Build is pending
2026-05-06 17:55:11 +08:00
wangxiaoshuang 22b77ff70f Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-06 17:01:43 +08:00
wangxiaoshuang 3a35f4a966 匿名数据部分问题解决 2026-05-06 17:01:31 +08:00
caiyiling 8ff9e3b232 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-05-06 16:11:35 +08:00
caiyiling e189080e5c 样式更改 2026-05-06 16:11:18 +08:00
wangxiaoshuang 07b1e5d1f9 匿名失败进行提示
continuous-integration/drone/push Build is passing
2026-05-06 15:32:51 +08:00
wangxiaoshuang 2f92bf6dfb pet、mr分割视图重置调窗问题
continuous-integration/drone/push Build is passing
2026-05-06 15:01:47 +08:00
wangxiaoshuang 391e696d8a Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-06 14:38:30 +08:00
wangxiaoshuang 9ff7928b16 数据匿名更改 2026-05-06 14:38:26 +08:00
caiyiling 3c0971e961 国际化排序更改
continuous-integration/drone/push Build is running
2026-05-06 14:33:15 +08:00
wangxiaoshuang 1f20834dd3 个性化配置热键tab,高度加高一屏展示所有热键
continuous-integration/drone/push Build is passing
2026-05-06 13:35:00 +08:00
wangxiaoshuang f34665fcb9 体积分割对象的统计值,Count应该为整型
continuous-integration/drone/push Build is running
2026-05-06 13:32:33 +08:00
wangxiaoshuang 00e03c782d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-05-06 13:28:04 +08:00
wangxiaoshuang 5e6c8e6936 AB视口,A视口放大后进入mpr,只显示了一个视口,需要显示mpr的全部视口 2026-05-06 13:27:53 +08:00
wangxiaoshuang cd2c56c510 适应窗口调整后,影像页数应该不变 2026-05-06 13:21:49 +08:00
caiyiling ec7cb78018 lugano标准融合修复colormap bar
continuous-integration/drone/push Build is passing
2026-05-06 13:21:45 +08:00
caiyiling 6a65b6507f 1
continuous-integration/drone/push Build is passing
2026-05-06 11:38:18 +08:00
caiyiling d08df877d7 样式更改
continuous-integration/drone/push Build is passing
2026-05-06 11:23:57 +08:00
caiyiling 10a43d4c04 自动添加肿瘤学阅片期bug修复
continuous-integration/drone/push Build is passing
2026-05-06 10:23:56 +08:00
wangxiaoshuang a87769a60f 1
continuous-integration/drone/push Build is passing
2026-04-30 17:31:34 +08:00
wangxiaoshuang 4d808ed87c 历史访视分割组显示按钮
continuous-integration/drone/push Build is passing
2026-04-30 17:08:15 +08:00
wangxiaoshuang 0a3a4e3bb4 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-30 17:03:19 +08:00
wangxiaoshuang 0aab18924b 切换序列提示保存分割 2026-04-30 17:03:06 +08:00
caiyiling 2bf9b21f40 1
continuous-integration/drone/push Build is passing
2026-04-30 16:54:34 +08:00
caiyiling 06d0ce2290 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-04-30 16:45:03 +08:00
caiyiling 1b6e53819c 融合页面工具优化 2026-04-30 16:44:00 +08:00
wangxiaoshuang a59509dd7d 新增分割片段名规则变更
continuous-integration/drone/push Build is passing
2026-04-30 16:26:14 +08:00
wangxiaoshuang d88f7c43b2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue
2026-04-30 16:01:34 +08:00
wangxiaoshuang c3543e19c8 1 2026-04-30 15:58:54 +08:00
caiyiling 72b1a3906d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-04-30 15:58:45 +08:00
caiyiling 06794447ec 阅片页面pt数据,放在检查级别显示 2026-04-30 15:51:57 +08:00
wangxiaoshuang 00c5570692 分割长短经按钮修改
continuous-integration/drone/push Build is passing
2026-04-30 15:48:18 +08:00
wangxiaoshuang cd2df6e576 分割标记缓存问题
continuous-integration/drone/push Build is passing
2026-04-30 15:24:33 +08:00
wangxiaoshuang 52f9c17234 1
continuous-integration/drone/push Build is passing
2026-04-30 15:15:05 +08:00
wangxiaoshuang 0b78561331 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-30 14:54:21 +08:00
wangxiaoshuang c12da4de3e 分割部分问题解决 2026-04-30 14:54:16 +08:00
caiyiling 4f16060a46 样式未隔离导致阅片人编辑页,右侧排版错位
continuous-integration/drone/push Build is passing
2026-04-30 14:35:17 +08:00
caiyiling 212bd65bc1 阅片期临床数据添加更新功能
continuous-integration/drone/push Build is passing
2026-04-30 14:25:48 +08:00
wangxiaoshuang afc35daffa Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-04-30 13:41:48 +08:00
caiyiling 5bf8e7ecf6 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-30 13:36:04 +08:00
caiyiling 192f7a3316 自动增加肿瘤学阅片期 2026-04-30 13:35:52 +08:00
wangxiaoshuang d88535b75e 【dicom分割】有的影像无法渲染,需要增加提示 2026-04-30 11:46:57 +08:00
wangxiaoshuang 128cdc0f75 【dicom分割】直方图x轴坐标应该是从小到大,现在坐标数显示异常 2026-04-30 11:23:31 +08:00
wangxiaoshuang 4a8b1da094 部分问题修复
continuous-integration/drone/push Build is passing
2026-04-30 09:12:03 +08:00
wangxiaoshuang 728f3238ca 防止内存泄漏
continuous-integration/drone/push Build is passing
2026-04-29 17:35:25 +08:00
wangxiaoshuang e245057bb2 切换视口快速提交监测 2026-04-29 17:34:12 +08:00
wangxiaoshuang 7bf80c10eb 切换视口重置分割分组和分割片段
continuous-integration/drone/push Build is passing
2026-04-29 16:58:41 +08:00
wangxiaoshuang ecf4c8a2c7 1
continuous-integration/drone/push Build is passing
2026-04-29 16:17:49 +08:00
wangxiaoshuang c532babf98 视口变动时重新选中当前选择分割
continuous-integration/drone/push Build is passing
2026-04-29 15:56:18 +08:00
wangxiaoshuang 2fa54eaac6 保存分割时去除同步提示
continuous-integration/drone/push Build is passing
2026-04-29 15:42:08 +08:00
wangxiaoshuang 50de867772 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-29 15:04:52 +08:00
wangxiaoshuang 24a48e3d23 切换ab视图时ecrf表单未刷新 2026-04-29 15:04:47 +08:00
caiyiling 13429f45ed 1
continuous-integration/drone/push Build is passing
2026-04-29 14:34:11 +08:00
caiyiling 8545e8f1d6 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-29 14:15:59 +08:00
caiyiling 619a7b2ee3 质控通过后编辑临床数据信息更改 2026-04-29 14:15:33 +08:00
wangxiaoshuang 544f83d118 1
continuous-integration/drone/push Build is passing
2026-04-29 14:07:05 +08:00
wangxiaoshuang 1541e3d353 退出MPR时ecrf表显示不正确 2026-04-29 14:06:55 +08:00
wangxiaoshuang 7a454d09ff Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-29 13:42:20 +08:00
wangxiaoshuang 06f52f4f24 分割数据不一致问题 2026-04-29 13:42:16 +08:00
caiyiling 877e47ccb1 阅片规则单位更改
continuous-integration/drone/push Build is passing
2026-04-29 13:30:42 +08:00
caiyiling c373b59f23 质控通过时pt临床数据可再次修改
continuous-integration/drone/push Build is passing
2026-04-29 12:41:00 +08:00
caiyiling 73e8f24c3d 阅片页面图标更改;适应图像逻辑更改;petct工具更改
continuous-integration/drone/push Build is passing
2026-04-29 11:48:21 +08:00
wangxiaoshuang 1e57777d3b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-28 15:41:13 +08:00
wangxiaoshuang aca7f07d00 分割列表样式调整 2026-04-28 15:41:09 +08:00
caiyiling 35e52fbdcf 融合标记跳转更改
continuous-integration/drone/push Build is passing
2026-04-28 15:33:51 +08:00
wangxiaoshuang aaeadbc440 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-28 15:08:49 +08:00
wangxiaoshuang 60d3dfa6e7 1 2026-04-28 15:08:45 +08:00
caiyiling 417fefb04b 1
continuous-integration/drone/push Build is passing
2026-04-28 14:13:51 +08:00
caiyiling 27646e2c46 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-04-28 14:07:44 +08:00
wangxiaoshuang 48b154bf87 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is running
2026-04-28 14:07:09 +08:00
wangxiaoshuang acfa552cbe mpr十字线颜色更改 2026-04-28 14:07:05 +08:00
caiyiling aa6a226ce1 添加日志 2026-04-28 14:06:30 +08:00
caiyiling 09144f2b98 1
continuous-integration/drone/push Build is passing
2026-04-28 13:59:43 +08:00
caiyiling 9b8c6788bf Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-28 13:39:52 +08:00
caiyiling 4aa1a05ea9 定位工具更改 2026-04-28 13:39:18 +08:00
wangxiaoshuang 45790141df 分割导出按钮宽度调整
continuous-integration/drone/push Build is passing
2026-04-28 13:33:15 +08:00
caiyiling 6804d909b8 more图标title更改
continuous-integration/drone/push Build is passing
2026-04-28 13:23:26 +08:00
caiyiling 1a1bf6810c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-28 13:13:30 +08:00
caiyiling c9e7719c71 测量工具图标更改 2026-04-28 13:13:08 +08:00
wangxiaoshuang 07b23fce1d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-28 11:44:34 +08:00
wangxiaoshuang 9f5cbad22e 分割及mpr部分问题解决 2026-04-28 11:44:30 +08:00
caiyiling 3cf4f95770 1
continuous-integration/drone/push Build is passing
2026-04-28 11:23:49 +08:00
caiyiling 5a01f10957 1
continuous-integration/drone/push Build is passing
2026-04-28 11:16:55 +08:00
caiyiling 4ed0ebc913 数据同步页面国际化
continuous-integration/drone/push Build is passing
2026-04-28 10:18:31 +08:00
caiyiling 9971c3ecca Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-28 09:15:22 +08:00
caiyiling 3c10ae73dd 融合视口十字线定位工具更改 2026-04-28 09:14:54 +08:00
wangxiaoshuang 5cbd13cc3d 1
continuous-integration/drone/push Build is passing
2026-04-27 16:14:43 +08:00
wangxiaoshuang 7dcc524bd3 切换分割与ecrf表时显示全部分割标记
continuous-integration/drone/push Build is passing
2026-04-27 15:37:59 +08:00
wangxiaoshuang bc4639a238 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-27 13:12:39 +08:00
wangxiaoshuang 0f25958d9b 分割部分问题解决 2026-04-27 13:12:35 +08:00
caiyiling ff0d204612 融合视口新增定位工具
continuous-integration/drone/push Build is passing
2026-04-27 11:49:07 +08:00
wangxiaoshuang 91386589ae 删除分组后,会出现分段的气泡窗口
continuous-integration/drone/push Build is passing
2026-04-27 11:16:03 +08:00
wangxiaoshuang b2a9f279a1 窗口联动关闭 2026-04-27 11:15:49 +08:00
wangxiaoshuang b4fc5d970f 项目列表查询条件
continuous-integration/drone/push Build is passing
2026-04-24 17:06:36 +08:00
wangxiaoshuang e046bffdbd EICS关于页面 2026-04-24 16:55:14 +08:00
wangxiaoshuang 38ea9ddb0b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-24 16:49:46 +08:00
wangxiaoshuang 1194e56139 对于问题反馈列表增加的状态增加:无法解决。 2026-04-24 16:49:35 +08:00
caiyiling 741c723bab Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-24 16:10:51 +08:00
caiyiling fea0047f58 数据同步更改 2026-04-24 16:10:35 +08:00
wangxiaoshuang 5a943fbefe 分割问题解决
continuous-integration/drone/push Build is passing
2026-04-24 16:03:23 +08:00
caiyiling 6c88af0a03 质控更改
continuous-integration/drone/push Build is passing
2026-04-24 15:52:07 +08:00
caiyiling 26412931a9 样式冲突更改
continuous-integration/drone/push Build is passing
2026-04-24 14:49:32 +08:00
wangxiaoshuang 5a1b64a023 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/components/Dicom/DicomViewer.vue
2026-04-24 14:41:39 +08:00
wangxiaoshuang 64d8c853b3 质控像素匿名 2026-04-24 14:37:36 +08:00
caiyiling 0261fb04c6 1
continuous-integration/drone/push Build is passing
2026-04-24 14:33:16 +08:00
caiyiling ab372a9c29 PT临床数据更改
continuous-integration/drone/push Build is running
2026-04-24 14:30:36 +08:00
caiyiling f7dd68f7f3 pt临床数据更改
continuous-integration/drone/push Build is passing
2026-04-23 16:32:25 +08:00
wangxiaoshuang 946203f124 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/components/Dicom/DicomViewer.vue
#	src/views/dicom-show/dicom-study.vue
2026-04-23 15:53:04 +08:00
wangxiaoshuang f0eb814492 质控数据匿名 2026-04-23 15:50:15 +08:00
caiyiling 6c36c48b82 自动切换任务更改;PT序列支持修改检查的患者数据
continuous-integration/drone/push Build is passing
2026-04-23 11:39:07 +08:00
wangxiaoshuang 47b05526a2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-04-22 15:06:47 +08:00
wangxiaoshuang f7afca6e73 注释(未完成) 2026-04-22 15:06:39 +08:00
caiyiling 04aa61658c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-22 13:41:44 +08:00
caiyiling 86c506bc1d 非dicom阅片页面快捷键功能补充 2026-04-22 13:41:03 +08:00
wangxiaoshuang 06959b4465 双屏问题修复
continuous-integration/drone/push Build is running
2026-04-22 13:37:57 +08:00
caiyiling 838ab975cc Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-22 11:09:56 +08:00
caiyiling 7aa33672a9 质控更改 2026-04-22 11:08:48 +08:00
wangxiaoshuang 81297954d3 查看历史访视黑屏问题
continuous-integration/drone/push Build is passing
2026-04-22 11:01:12 +08:00
wangxiaoshuang 25e348f428 上传问题解决
continuous-integration/drone/push Build is passing
2026-04-22 10:15:08 +08:00
caiyiling c101302cca 指控添加跳过功能
continuous-integration/drone/push Build is passing
2026-04-21 17:04:57 +08:00
caiyiling c4fd8c3ea3 融合视口crosshairsTool更改;数据同步页面更改;项目中培训文档路径更改
continuous-integration/drone/push Build is passing
2026-04-21 16:49:40 +08:00
caiyiling a7e7419a20 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is failing
2026-04-21 13:16:14 +08:00
caiyiling 55da1d9219 数据同步 2026-04-21 13:15:23 +08:00
wangxiaoshuang 2a842fd2f8 上传影像添加字段
continuous-integration/drone/push Build is running
2026-04-21 13:15:18 +08:00
caiyiling ca2e9e0253 数据同步列表更改
continuous-integration/drone/push Build is passing
2026-04-21 11:14:00 +08:00
caiyiling b4c06990f6 审批信息补充
continuous-integration/drone/push Build is passing
2026-04-21 10:17:49 +08:00
caiyiling 599fad48ba Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-04-21 09:33:26 +08:00
caiyiling 72b5d515ba 融合页面crosshairsTool更改 2026-04-21 09:32:41 +08:00
wangxiaoshuang 608bd42836 查看历史访视在新窗口打开
continuous-integration/drone/push Build is passing
2026-04-20 17:59:45 +08:00
caiyiling 040f66f182 定圆工具更改及国际化全局替换IRC逻辑更改
continuous-integration/drone/push Build is passing
2026-04-20 15:20:46 +08:00
wangxiaoshuang 7afbc360e5 新增的分段后,点击计算长短径保存,刷新页面后计算值全部变为0
continuous-integration/drone/push Build is passing
2026-04-17 15:52:55 +08:00
wangxiaoshuang 74c5d032fb 分割清除内存问题
continuous-integration/drone/push Build is passing
2026-04-17 11:49:00 +08:00
wangxiaoshuang 43aa371c36 分段显隐时对应长短径标记同步
continuous-integration/drone/push Build is passing
2026-04-17 11:33:35 +08:00
wangxiaoshuang 398ec90fae 分割问题查看、更改按钮位置变更
continuous-integration/drone/push Build is passing
2026-04-17 11:28:34 +08:00
wangxiaoshuang 890910a763 分割部分问题修复
continuous-integration/drone/push Build is passing
2026-04-17 11:17:25 +08:00
wangxiaoshuang 3b5ebfcba1 1
continuous-integration/drone/push Build is passing
2026-04-17 10:00:31 +08:00
wangxiaoshuang b971235164 体数据播放功能修改
continuous-integration/drone/push Build is passing
2026-04-16 17:55:33 +08:00
wangxiaoshuang e53a18f212 直方图修改
continuous-integration/drone/push Build is passing
2026-04-16 16:00:06 +08:00
wangxiaoshuang 774f43a6d0 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-16 15:22:03 +08:00
wangxiaoshuang 88f274ab89 分割部分问题修复 2026-04-16 15:21:53 +08:00
caiyiling 3345a989ae 定圆工具默认值更改
continuous-integration/drone/push Build is running
2026-04-16 15:19:37 +08:00
wangxiaoshuang 11000ef9f8 重置问题时清空问题与分割标记绑定关系
continuous-integration/drone/push Build is passing
2026-04-16 13:42:49 +08:00
wangxiaoshuang 57be74aea8 部分分割问题修复
continuous-integration/drone/push Build is running
2026-04-16 13:39:52 +08:00
wangxiaoshuang 8724eeeafb 分割部分问题解决
continuous-integration/drone/push Build is passing
2026-04-16 11:32:48 +08:00
caiyiling 7c71a6d342 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-16 10:03:46 +08:00
caiyiling cb04be1b56 融合视口添加crosshairsTool工具 2026-04-16 10:02:06 +08:00
wangxiaoshuang 63709b414d 阅片单元分割组配置修改
continuous-integration/drone/push Build is passing
2026-04-16 09:41:23 +08:00
wangxiaoshuang 7001bc9ec0 分割部分问题解决
continuous-integration/drone/push Build is passing
2026-04-15 17:21:19 +08:00
wangxiaoshuang c12833d283 切换分割分组时添加限制
continuous-integration/drone/push Build is passing
2026-04-15 16:48:38 +08:00
wangxiaoshuang 22baa213ae 新建若干分段后保存,保存卡死
continuous-integration/drone/push Build is passing
2026-04-15 16:00:49 +08:00
wangxiaoshuang 09c1c3ff12 分割部分问题修复
continuous-integration/drone/push Build is passing
2026-04-15 15:00:13 +08:00
wangxiaoshuang 94f43f4b11 用橡皮擦除分割标记后,绑定的分割问题显示为-Infinity
continuous-integration/drone/push Build is passing
2026-04-15 14:24:49 +08:00
wangxiaoshuang 1a42cfd47c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is running
2026-04-15 14:22:59 +08:00
wangxiaoshuang b6b918efbf 创建分割分组时,分组和分割分段的名称可以设置默认值、部分分割问题解决 2026-04-15 14:22:50 +08:00
caiyiling a16d86d942 数据同步列表更改
continuous-integration/drone/push Build is passing
2026-04-14 21:54:27 +08:00
caiyiling 266698cc79 定圆工具配置及功能实现
continuous-integration/drone/push Build is passing
2026-04-14 21:19:00 +08:00
wangxiaoshuang eac6b25b9e 分割部分问题修复
continuous-integration/drone/push Build is passing
2026-04-14 18:01:21 +08:00
wangxiaoshuang 47d7fb00e2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-14 16:19:41 +08:00
wangxiaoshuang 312ab754e1 分割标记渲染结构变更 2026-04-14 16:19:36 +08:00
caiyiling 0ff5a21d04 同步列表更改
continuous-integration/drone/push Build is passing
2026-04-14 13:05:18 +08:00
wangxiaoshuang 5a7fa1fb77 分割部分问题解决
continuous-integration/drone/push Build is passing
2026-04-09 18:08:20 +08:00
wangxiaoshuang 5289c156c0 1
continuous-integration/drone/push Build is passing
2026-04-09 17:28:59 +08:00
wangxiaoshuang a68c27fd43 分割部分问题解决
continuous-integration/drone/push Build is running
2026-04-09 17:19:12 +08:00
wangxiaoshuang 641c2e6ade 直方图取值及样式修改
continuous-integration/drone/push Build is passing
2026-04-08 16:22:29 +08:00
wangxiaoshuang 5b4cc097bc 分割视图添加直方图
continuous-integration/drone/push Build is passing
2026-04-08 14:58:26 +08:00
wangxiaoshuang b1de662677 aws插件版本问题
continuous-integration/drone/push Build is passing
2026-04-07 17:11:04 +08:00
caiyiling d2d1063ed5 数据同步模块更改
continuous-integration/drone/push Build is passing
2026-04-03 17:27:12 +08:00
wangxiaoshuang 2bc4b32d3a Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-04-03 14:02:17 +08:00
wangxiaoshuang 366ec62cd7 1 2026-04-03 14:02:05 +08:00
caiyiling 866e2e5c6b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is failing
2026-04-03 13:49:35 +08:00
caiyiling 16e2db37cd 文件级别列表更改 2026-04-03 13:48:38 +08:00
wangxiaoshuang ee6c5bf8a5 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is pending
2026-04-03 13:45:48 +08:00
wangxiaoshuang 48cfe99f12 echarts版本升级v4=>v6 2026-04-03 13:45:39 +08:00
caiyiling f65264a2a6 1
continuous-integration/drone/push Build is running
2026-04-03 13:45:02 +08:00
caiyiling 769c5f8440 任务级别列表更改
continuous-integration/drone/push Build is running
2026-04-03 13:42:14 +08:00
caiyiling 6321bddfd3 数据同步更改
continuous-integration/drone/push Build is passing
2026-04-03 13:33:46 +08:00
caiyiling e30fb2a041 1
continuous-integration/drone/push Build is passing
2026-04-02 17:37:24 +08:00
caiyiling 478adcde21 1
continuous-integration/drone/push Build is running
2026-04-02 17:35:20 +08:00
caiyiling 34ce5142f2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-04-02 17:33:03 +08:00
caiyiling 3b993bcd46 数据同步更改 2026-04-02 17:32:35 +08:00
wangxiaoshuang 3f2e39f46c 当加载Volume体数据时,页面显示的现在速度需要按照Series来计算。现在一直都是0。
continuous-integration/drone/push Build is passing
2026-04-02 15:01:32 +08:00
wangxiaoshuang d317402f85 1
continuous-integration/drone/push Build is passing
2026-04-02 14:40:24 +08:00
wangxiaoshuang 6cb63bdc59 浏览器窗口大小调整后,渲染的标记、比例尺等位置偏移
continuous-integration/drone/push Build is failing
2026-04-02 14:36:15 +08:00
wangxiaoshuang 8db641db16 分割重命名时默认值填入
continuous-integration/drone/push Build is failing
2026-04-02 14:07:58 +08:00
wangxiaoshuang 9da9515930 aws插件版本升级3.7.4=>3.726
continuous-integration/drone/push Build is passing
2026-04-02 09:33:38 +08:00
wangxiaoshuang 2be119de6b 分割橡皮檫国际化
continuous-integration/drone/push Build is passing
2026-04-01 15:23:20 +08:00
wangxiaoshuang c9f9615488 mpr切换单视口时分割列表报错问题
continuous-integration/drone/push Build is passing
2026-04-01 14:53:14 +08:00
wangxiaoshuang be137b3840 分割字段变更SegmentMumber=>SegmentNumber
continuous-integration/drone/push Build is passing
2026-04-01 12:21:07 +08:00
wangxiaoshuang d80101f86b 分割标记与分割段绑定错误问题
continuous-integration/drone/push Build is passing
2026-04-01 11:30:59 +08:00
wangxiaoshuang 3c0b084f7e 分割文件保存分割段与分割标记不一致问题
continuous-integration/drone/push Build is passing
2026-04-01 09:58:45 +08:00
wangxiaoshuang 8a88a64c36 比例尺页面放大缩小报错问题
continuous-integration/drone/push Build is failing
2026-04-01 09:35:36 +08:00
wangxiaoshuang 3d538d6e67 1
continuous-integration/drone/push Build is passing
2026-03-31 17:59:10 +08:00
wangxiaoshuang 67d2a83ec8 1
continuous-integration/drone/push Build is passing
2026-03-31 17:38:36 +08:00
wangxiaoshuang 2efb229c96 1
continuous-integration/drone/push Build is passing
2026-03-31 17:13:29 +08:00
wangxiaoshuang c930480336 体数据放大变形问题解决
continuous-integration/drone/push Build is passing
2026-03-31 16:47:16 +08:00
wangxiaoshuang b39ea3a032 分割标记数据值计算完成后才可保存
continuous-integration/drone/push Build is passing
2026-03-31 16:30:37 +08:00
wangxiaoshuang ff5aea17a5 样式修改
continuous-integration/drone/push Build is passing
2026-03-31 15:43:34 +08:00
wangxiaoshuang 477b6935ff 分割窗口放大页面跳转与分割片段默认跳转功能互不干扰
continuous-integration/drone/push Build is running
2026-03-31 15:41:45 +08:00
wangxiaoshuang 8b6432ad14 分割标记长短径的小数位数需要一致
continuous-integration/drone/push Build is passing
2026-03-31 15:23:23 +08:00
wangxiaoshuang ca35fe6df4 部分问题修复
continuous-integration/drone/push Build is passing
2026-03-31 15:17:13 +08:00
wangxiaoshuang 307c02725f 分割对象的体素统计以及长短径计算优化、分割组添加状态
continuous-integration/drone/push Build is passing
2026-03-31 13:47:06 +08:00
caiyiling 72d0494baa Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-31 10:07:50 +08:00
caiyiling d1017bc565 MIM关闭医学审核任务逻辑更改 2026-03-31 10:07:17 +08:00
wangxiaoshuang 76e6ef087f 分割标记的颜色需要随机,不能重复
continuous-integration/drone/push Build is passing
2026-03-30 17:33:52 +08:00
wangxiaoshuang c5c9e4364c 【dicom分割】分段菜单按钮点击后,再点击另一个分段菜单按钮,上一个展示的弹窗应该消失
continuous-integration/drone/push Build is passing
2026-03-30 17:17:17 +08:00
wangxiaoshuang 920d0b21c6 【dicom分割】当前分组选择为分组2,分组2没有标记数据,当切入mpr模式时,此时显示了分组1的标记,这里影像标记应该与右侧分割选择组同步
continuous-integration/drone/push Build is passing
2026-03-30 16:50:25 +08:00
wangxiaoshuang 3fe16b4166 体数据阅片四角信息
continuous-integration/drone/push Build is passing
2026-03-30 16:19:05 +08:00
wangxiaoshuang bc2d5463ff MPR视图的:十字线和窗宽窗位
continuous-integration/drone/push Build is passing
2026-03-30 16:10:56 +08:00
caiyiling c63811d55c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-30 15:45:52 +08:00
caiyiling 832fa82d4b 融合伪彩更改 2026-03-30 15:45:16 +08:00
wangxiaoshuang b3ae801fe9 没有分割数据的Segmentation,从二维进入MPR时,会显示3个
continuous-integration/drone/push Build is passing
2026-03-30 14:36:43 +08:00
caiyiling 0dbd74270d Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-30 14:14:18 +08:00
caiyiling aae5968d74 nm/ct融合更改 2026-03-30 14:13:52 +08:00
wangxiaoshuang 79a7ad0cf7 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue
2026-03-30 13:29:16 +08:00
wangxiaoshuang a35309d9b5 普通标记在多个三维序列渲染问题 2026-03-30 13:27:24 +08:00
caiyiling a987ac086b 1
continuous-integration/drone/push Build is passing
2026-03-30 10:57:27 +08:00
caiyiling fdc2bc5f8a 1
continuous-integration/drone/push Build is running
2026-03-30 10:54:07 +08:00
caiyiling 84f68c79f0 1
continuous-integration/drone/push Build is running
2026-03-30 10:52:28 +08:00
caiyiling b77dc34523 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-03-30 10:49:44 +08:00
caiyiling 91554e0e30 1 2026-03-30 10:48:04 +08:00
wangxiaoshuang 2efb7fd36a 普通标记在多个序列渲染问题
continuous-integration/drone/push Build is passing
2026-03-27 18:01:41 +08:00
caiyiling dbdec93efc Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-03-27 17:59:51 +08:00
caiyiling e631ce73f2 伪彩组件更改 2026-03-27 17:59:35 +08:00
wangxiaoshuang 5931dcdc67 mpr加载
continuous-integration/drone/push Build is passing
2026-03-27 16:40:45 +08:00
wangxiaoshuang b55ffc0821 mpr加载
continuous-integration/drone/push Build is passing
2026-03-27 16:32:34 +08:00
caiyiling 8600054405 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-27 16:24:54 +08:00
caiyiling 9a88539294 融合视口调节透明度功能更改 2026-03-27 16:24:24 +08:00
wangxiaoshuang 09211c8841 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/dicoms3D/components/PetCtViewport.vue
2026-03-27 15:47:24 +08:00
wangxiaoshuang 2724e0267f 三维调窗、分割保存 2026-03-27 15:46:40 +08:00
caiyiling a0e355d69b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-27 13:53:45 +08:00
caiyiling 04a0a1ccc3 SPECT多帧图像融合更改 2026-03-27 13:52:59 +08:00
wangxiaoshuang c3e967acaa 分割标记序号修改
continuous-integration/drone/push Build is passing
2026-03-27 10:50:18 +08:00
wangxiaoshuang 740a0aa221 删除分割标记同步问题
continuous-integration/drone/push Build is passing
2026-03-27 10:31:06 +08:00
wangxiaoshuang e8f95d09ba 1
continuous-integration/drone/push Build is passing
2026-03-26 17:49:39 +08:00
wangxiaoshuang 2c305af49e 【dicom分割】删除已绑定问题的分割标记时,eicrf页面没有刷新状态
continuous-integration/drone/push Build is failing
2026-03-26 17:40:22 +08:00
wangxiaoshuang 5c76bda1e7 分割添加阈值工具
continuous-integration/drone/push Build is passing
2026-03-26 16:05:34 +08:00
wangxiaoshuang 0273601f7b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-03-25 17:46:45 +08:00
wangxiaoshuang c3a154f762 分割长短径工具问题修复 2026-03-25 17:46:31 +08:00
caiyiling cdb97f6405 w/l预设模板移除CT Bone1
continuous-integration/drone/push Build is passing
2026-03-25 17:31:59 +08:00
caiyiling 4794429a57 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-25 16:51:31 +08:00
caiyiling 77a633d699 SPECT融合更改 2026-03-25 16:45:44 +08:00
wangxiaoshuang 64d1ebf350 导入分割数据与分段进行绑定
continuous-integration/drone/push Build is passing
2026-03-25 16:44:55 +08:00
wangxiaoshuang 5336cb5353 分割标记删除进行提示
continuous-integration/drone/push Build is passing
2026-03-25 14:11:52 +08:00
wangxiaoshuang 0a288b9f47 分割标记重命名问题修改
continuous-integration/drone/push Build is passing
2026-03-25 14:03:04 +08:00
wangxiaoshuang 674d483cbf Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-03-25 13:52:23 +08:00
wangxiaoshuang cbcb396441 分割标记跳转修改 2026-03-25 13:52:14 +08:00
caiyiling 9a3e972723 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-25 11:00:20 +08:00
caiyiling b593615e9e Lugano标准融合页面伪彩更改 2026-03-25 10:59:55 +08:00
wangxiaoshuang d30c9a5f3b 图像滚动问题解决
continuous-integration/drone/push Build is passing
2026-03-25 09:26:11 +08:00
caiyiling dd3d738eed Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-25 09:10:25 +08:00
caiyiling d9edaf4c27 OCT标准FCT平均值计算逻辑更改 2026-03-25 09:09:35 +08:00
wangxiaoshuang a5e0dd89ff 1
continuous-integration/drone/push Build is running
2026-03-25 09:07:21 +08:00
wangxiaoshuang 73f8f816b7 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is failing
2026-03-24 17:56:10 +08:00
wangxiaoshuang 19d5144b70 问题绑定分割标记后查看 2026-03-24 17:55:57 +08:00
caiyiling e0ecd3f4ac Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-03-24 17:55:31 +08:00
caiyiling 30e0e374bc 调窗更改 2026-03-24 17:54:59 +08:00
wangxiaoshuang 25b909c660 分割默认工具功能修复
continuous-integration/drone/push Build is passing
2026-03-24 16:45:44 +08:00
caiyiling 5cb3e8e606 同步调窗更改
continuous-integration/drone/push Build is passing
2026-03-24 15:46:25 +08:00
wangxiaoshuang 619af2e874 分割问题绑定标记显示问题
continuous-integration/drone/push Build is passing
2026-03-24 15:27:17 +08:00
wangxiaoshuang 43f1736b05 1
continuous-integration/drone/push Build is passing
2026-03-24 15:12:49 +08:00
wangxiaoshuang c9be5678bd Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is running
2026-03-24 15:09:51 +08:00
wangxiaoshuang 4e5ecb3938 分割添加轮廓工具 2026-03-24 15:09:45 +08:00
caiyiling 7870c3d74b CT/NM融合更改
continuous-integration/drone/push Build is passing
2026-03-24 14:54:46 +08:00
wangxiaoshuang d07adc4948 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
# Conflicts:
#	src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/StudyList.vue
2026-03-23 15:10:29 +08:00
wangxiaoshuang 266886fa64 阅片添加分割工具 2026-03-23 10:01:22 +08:00
caiyiling e012eba0c2 阅片页面样式更改
continuous-integration/drone/push Build is passing
2026-03-19 16:54:25 +08:00
caiyiling 75d296405b cornerstone版本升级
continuous-integration/drone/push Build is passing
2026-03-19 15:12:54 +08:00
caiyiling 07c92c48a4 融合图像筛选更改
continuous-integration/drone/push Build is passing
2026-03-13 14:11:52 +08:00
hang b5427dd17b 修改打包文件配置
continuous-integration/drone/push Build is passing
2026-03-13 13:49:27 +08:00
hang 385643643e uat合并main 导致打包文件被覆盖,重新编写 2026-03-13 13:47:23 +08:00
caiyiling 756f1293aa 融合图像补充模态为NM类型的影像 2026-03-13 13:35:38 +08:00
caiyiling eee19f0ae9 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main 2026-03-13 13:20:27 +08:00
caiyiling 78c0910db7 选择融合图像时扩充NM模态的影像 2026-03-13 13:18:24 +08:00
wangxiaoshuang 18a71725f9 自动化脚本变更
continuous-integration/drone/push Build is passing
2026-03-06 09:44:56 +08:00
wangxiaoshuang 87332ae9d8 Merge branch 'main' into uat
continuous-integration/drone/push Build is passing
2026-03-05 17:53:07 +08:00
caiyiling 401762dca7 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-05 17:07:34 +08:00
caiyiling 7b694d4afb 对OCT标准中自动计算类型问题国际化翻译 2026-03-05 17:06:19 +08:00
hang 6e285d900b irc-uat 使用uat分支以uat 模式自动打包发布增加
continuous-integration/drone/push Build is passing
2026-03-05 14:55:01 +08:00
hang c5d3b44c2c irc web 提交自动打包发布uat分支
continuous-integration/drone/push Build was killed
2026-03-05 14:52:28 +08:00
hang cf4dbc2914 irc uat分支,自动打包配置修改 2026-03-05 14:49:41 +08:00
wangxiaoshuang 3cef5afebd logo更改
continuous-integration/drone/push Build is passing
2026-03-05 10:11:50 +08:00
caiyiling 060b61eafb ivus和oct阅片页面样式调整
continuous-integration/drone/push Build is passing
2026-03-04 14:50:02 +08:00
caiyiling 0d3571f672 导入模板更改
continuous-integration/drone/push Build is passing
2026-03-04 13:31:28 +08:00
caiyiling 8b3bd101b6 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-04 11:27:38 +08:00
caiyiling da252ae4df 数值问题答案为NE保存bug修复 2026-03-04 11:26:48 +08:00
wangxiaoshuang fdb7251b62 v2.0.0发布遗留问题
continuous-integration/drone/push Build is passing
2026-03-04 11:23:15 +08:00
caiyiling 1f51bbd178 OCT导入测量值获取模板接口变更
continuous-integration/drone/push Build is passing
2026-03-04 10:17:06 +08:00
caiyiling 597ca07fcf Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-03-03 16:50:28 +08:00
caiyiling b43c75dd9f oct表格问题更改 2026-03-03 16:50:02 +08:00
wangxiaoshuang 94f3e6c757 代码合并
continuous-integration/drone/push Build is passing
2026-03-03 14:15:04 +08:00
wangxiaoshuang 1d95cd15f2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-03-03 14:14:46 +08:00
wangxiaoshuang a1f9283262 Merge branch 'uat' 2026-03-03 13:54:59 +08:00
caiyiling a0abba71dd 1
continuous-integration/drone/push Build is passing
2026-03-03 12:41:50 +08:00
caiyiling 02d85e19a6 多选问题保存报错更改
continuous-integration/drone/push Build is passing
2026-03-03 11:36:36 +08:00
caiyiling 9ad916f860 表格问题标识更改
continuous-integration/drone/push Build is passing
2026-03-03 11:04:51 +08:00
caiyiling e0094c01d8 1
continuous-integration/drone/push Build is passing
2026-03-03 10:52:59 +08:00
caiyiling 0eb2135185 IVUS数值问题提示语更改
continuous-integration/drone/push Build is running
2026-03-03 10:50:37 +08:00
caiyiling 8ddfe34f72 IVUS标准更改
continuous-integration/drone/push Build is passing
2026-03-03 10:26:02 +08:00
caiyiling c603d10ff5 IVUS & OCT 移除测量值触发自动计算更改
continuous-integration/drone/push Build is passing
2026-03-03 09:41:56 +08:00
caiyiling 3fca2e76cb 自动计算ROI测量值更改
continuous-integration/drone/push Build is passing
2026-03-02 11:13:29 +08:00
caiyiling c0ae4732fc 数值问题更改
continuous-integration/drone/push Build is passing
2026-02-28 13:16:05 +08:00
caiyiling 4ec0a178b4 IVUS & OCT标准更改
continuous-integration/drone/push Build is passing
2026-02-28 12:57:17 +08:00
wangxiaoshuang 4057f1893f 非dicom测量值与比例尺转化问题
continuous-integration/drone/push Build is passing
2026-02-12 20:50:00 -05:00
wangxiaoshuang 5c05a11ec4 阅片人预览文件修改
continuous-integration/drone/push Build is passing
2026-02-10 04:44:30 -05:00
wangxiaoshuang eec23b9d42 登录邮箱问题
continuous-integration/drone/push Build is passing
2026-02-10 02:40:06 -05:00
wangxiaoshuang f7d01f6ad7 部分问题修复
continuous-integration/drone/push Build is passing
2026-02-10 10:31:18 +08:00
wangxiaoshuang cb46f89ee1 DICOM阅片和非DICOM阅片工具,CRF问题与影像标记绑定时,信息明确下
continuous-integration/drone/push Build is passing
2026-02-06 10:45:19 +08:00
wangxiaoshuang b0ad500f7a 90天后未修改密码,跳转到修改账户界面,管理员重置密码跳转界面,不应该为初始化账户信息,应为修改账户信息
continuous-integration/drone/push Build is passing
2026-02-06 10:21:34 +08:00
wangxiaoshuang 0327937f02 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is failing
2026-02-06 09:40:58 +08:00
wangxiaoshuang 2f3eab6119 【质控风险控制】提交质控任务后,提示跳转进入下个任务,跳转到下个任务不会触发风险控制 2026-02-06 09:40:45 +08:00
hang 575840490f git 全局设置userName
continuous-integration/drone/push Build is passing
2026-02-05 20:30:50 +08:00
zhouhang 9b013059ba 继续测试用户名
continuous-integration/drone/push Build is failing
2026-02-05 20:03:43 +08:00
zhouhang 987831ff22 为啥没有用户名?
continuous-integration/drone/push Build is failing
2026-02-05 20:00:13 +08:00
zhouhang 7691fd12ac 全局设置git用户名测试 用户名显示
continuous-integration/drone/push Build is failing
2026-02-05 19:55:40 +08:00
hang 0cecb91984 工程统一前端打包,并增加微信通知测试
continuous-integration/drone/push Build is passing
2026-02-05 19:46:01 +08:00
caiyiling 849142bd23 简历批量下载更改
continuous-integration/drone/push Build is passing
2026-02-05 14:41:28 +08:00
caiyiling 231a993f8b 1
continuous-integration/drone/push Build is passing
2026-01-30 14:36:28 +08:00
caiyiling ab1a2889bc Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is failing
2026-01-30 14:34:17 +08:00
wangxiaoshuang f04f0ce929 非DICOM阅片,切换最右边的访视时,CRF表中的访视名称切换了,但是问题的内容没有切换
continuous-integration/drone/push Build is failing
2026-02-05 10:46:41 +08:00
wangxiaoshuang bc3e00c8b4 重置密码接口修改
continuous-integration/drone/push Build is failing
2026-02-05 10:21:06 +08:00
wangxiaoshuang 953033b768 非dicom阅片鼠标滚动翻页时取消选中工具
continuous-integration/drone/push Build is failing
2026-02-05 10:17:00 +08:00
wangxiaoshuang c337f95693 代码合并
continuous-integration/drone/push Build is failing
2026-02-02 16:06:47 +08:00
wangxiaoshuang d2021a281e Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-02-02 16:05:05 +08:00
wangxiaoshuang 66ae27cc56 非dicom报告页展示有误 2026-02-02 16:04:52 +08:00
caiyiling 3137bca8f6 标注标记更改
continuous-integration/drone/push Build is passing
2026-02-02 15:08:00 +08:00
wangxiaoshuang e35f6c5471 非dicom阅片更改比例尺弹框去除取消按钮
continuous-integration/drone/push Build is passing
2026-02-02 15:02:41 +08:00
wangxiaoshuang 46b532b858 非dicom长短径工具与问题进行绑定值错误问题
continuous-integration/drone/push Build is passing
2026-02-02 14:06:04 +08:00
wangxiaoshuang 5a8e1e5af7 系统时间的定位,应该根据显示器的分别率可以适配
continuous-integration/drone/push Build is passing
2026-02-02 11:04:44 +08:00
wangxiaoshuang 9b9c83797a 冲突解决
continuous-integration/drone/push Build is passing
2026-02-02 10:26:30 +08:00
wangxiaoshuang 8a4b4fc9fb Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web 2026-02-02 10:19:51 +08:00
wangxiaoshuang 91d8d1797a 非diocm阅片部分问题解决 2026-02-02 10:19:39 +08:00
caiyiling 0d2bfa8d82 1
continuous-integration/drone/push Build is passing
2026-01-30 18:08:55 +08:00
caiyiling 742b60bba2 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is running
2026-01-30 18:06:28 +08:00
caiyiling 536fc7bbc8 1 2026-01-30 18:02:52 +08:00
wangxiaoshuang 6f0f7a7d3a mp4缩略图修改
continuous-integration/drone/push Build is passing
2026-01-30 16:10:42 +08:00
wangxiaoshuang 4ed0feb1da 非dicom阅片修改
continuous-integration/drone/push Build is passing
2026-01-30 16:02:43 +08:00
wangxiaoshuang 45cc714942 阅片修改
continuous-integration/drone/push Build is passing
2026-01-30 15:22:55 +08:00
caiyiling 147b5cadfa 非dicom阅片切换访视ecrf表同步更新 2026-01-30 14:30:10 +08:00
wangxiaoshuang d34f1f462a 阅片规则下拉框显示修改
continuous-integration/drone/push Build is passing
2026-01-30 14:19:49 +08:00
wangxiaoshuang c89aa8bd87 登录页title修改
continuous-integration/drone/push Build is passing
2026-01-30 13:55:05 +08:00
wangxiaoshuang 98324c27e6 1
continuous-integration/drone/push Build is passing
2026-01-30 10:56:47 +08:00
wangxiaoshuang ae1014c70b crc上传添加MP4预览
continuous-integration/drone/push Build is passing
2026-01-30 09:38:05 +08:00
wangxiaoshuang 7dc7236c16 阅片人筛选列表查询修改
continuous-integration/drone/push Build is passing
2026-01-29 16:30:49 +08:00
wangxiaoshuang b7a5015e21 1
continuous-integration/drone/push Build is passing
2026-01-29 11:38:33 +08:00
wangxiaoshuang e491265bb4 1
continuous-integration/drone/push Build is passing
2026-01-28 17:48:45 +08:00
wangxiaoshuang 8a4a035b2c 添加影像指控风险配置字段
continuous-integration/drone/push Build is passing
2026-01-28 16:10:54 +08:00
wangxiaoshuang 4e0fbb3f31 邮件配置发件人禁止编辑
continuous-integration/drone/push Build is passing
2026-01-28 15:11:23 +08:00
wangxiaoshuang d44aeac36d 肿瘤学阅片跳过按钮显示修改
continuous-integration/drone/push Build is passing
2026-01-28 13:22:11 +08:00
wangxiaoshuang f6eb5b8cd5 暂时去除i18n
continuous-integration/drone/push Build is passing
2026-01-28 10:58:18 +08:00
wangxiaoshuang 71e00ecf5b Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-01-27 15:05:05 +08:00
wangxiaoshuang fdc2572477 时间样式调整 2026-01-27 15:04:51 +08:00
caiyiling 7ab9d0f285 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-01-27 13:50:28 +08:00
caiyiling 64b8214985 1 2026-01-27 13:50:14 +08:00
wangxiaoshuang ba6bcebe1f 添加悬浮时间
continuous-integration/drone/push Build is passing
2026-01-26 17:08:01 +08:00
wangxiaoshuang 8703b28470 新增更新缩略图功能 2026-01-26 11:41:11 +08:00
caiyiling dc8fb450fb 非DICOM页面添加关键图像和标注图像的标识,阅片工具添加定圆工具
continuous-integration/drone/push Build is passing
2026-01-23 15:40:50 +08:00
wangxiaoshuang 377cdb968d 实施阅片预览
continuous-integration/drone/push Build is passing
2026-01-23 10:15:35 +08:00
wangxiaoshuang 8c84cb5101 1
continuous-integration/drone/push Build is passing
2026-01-23 09:25:59 +08:00
wangxiaoshuang 5a0cc41d5a 非必填的CRF问题,影像标记为非必选。如果画了标记,没有保存时,访视可以提交。提交后,值存在,标记不存在
continuous-integration/drone/push Build is passing
2026-01-22 17:36:33 +08:00
wangxiaoshuang 86a1312b60 dicom阅片添加椭圆工具
continuous-integration/drone/push Build is passing
2026-01-22 16:57:24 +08:00
wangxiaoshuang a3ca9fe4d0 【实时报告】受试者页面发送实时报告,阅片标准未显示,发送报告时报错
continuous-integration/drone/push Build is passing
2026-01-22 15:44:26 +08:00
wangxiaoshuang c6770e71a5 1
continuous-integration/drone/push Build is passing
2026-01-21 15:44:22 +08:00
wangxiaoshuang c70970a6f6 非dicom长短径问题修改
continuous-integration/drone/push Build is passing
2026-01-21 10:23:03 +08:00
wangxiaoshuang d059d016a6 下载文件中文乱码问题
continuous-integration/drone/push Build is passing
2026-01-19 17:51:11 +08:00
wangxiaoshuang 44519c5f8e 【阅片单元】当阅片模式选择完全随机和受试者内随机时,禁用存在阅片期、全局阅片、肿瘤学阅片,且全部置为否,除了PCWG
continuous-integration/drone/push Build is passing
2026-01-19 16:59:08 +08:00
wangxiaoshuang f3a4a7cd09 分别支持PET/CT和PET/MR融合
continuous-integration/drone/push Build is passing
2026-01-19 16:40:43 +08:00
wangxiaoshuang 463e4728d0 mpr和nm时切换访视视口切换为单视口
continuous-integration/drone/push Build is passing
2026-01-19 16:34:10 +08:00
wangxiaoshuang 5d04fb869d 阅片单元阅片工具的测量工具选择后,保存阅片规则。但是在CRF配置时,不能选择选择的影像工具,需要刷新页面内后才行
continuous-integration/drone/push Build is passing
2026-01-19 16:00:26 +08:00
wangxiaoshuang ec83609139 下载文件支持zip64
continuous-integration/drone/push Build is passing
2026-01-19 15:53:11 +08:00
wangxiaoshuang a5824cecac 影像无法阅片问题修复
continuous-integration/drone/push Build is passing
2026-01-17 12:21:44 +08:00
wangxiaoshuang 416f8f82d6 修复阅片页面影像缺失像素间的距离tag导致测量异常(暂时退回)
continuous-integration/drone/push Build is passing
2026-01-17 11:24:04 +08:00
wangxiaoshuang f0a7090ab4 阅片临床数据问题
continuous-integration/drone/push Build is passing
2026-01-17 00:10:31 +08:00
wangxiaoshuang a13ddf70b4 邮件通知更新调研表去除更新调研表按钮
continuous-integration/drone/push Build is passing
2026-01-16 17:47:20 +08:00
wangxiaoshuang ecf4c74259 非DICOM阅片工具,增加图像标识信息
continuous-integration/drone/push Build is passing
2026-01-16 15:40:00 +08:00
wangxiaoshuang e712333a79 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-01-16 11:36:25 +08:00
wangxiaoshuang 6900cc8a25 浏览器指纹校验 2026-01-16 11:36:10 +08:00
caiyiling d5acb0a27c Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-01-16 10:31:23 +08:00
wangxiaoshuang 0f845df8dd CRC在影像上传时录入的是英文的部位,但是在Study页面和Reading页面显示的部位却为中文
continuous-integration/drone/push Build is running
2026-01-16 10:29:57 +08:00
caiyiling 0b2cdd12a7 修复阅片页面影像缺失像素间的距离tag导致测量异常 2026-01-16 10:29:37 +08:00
wangxiaoshuang 785ca4ad47 非dicom阅片检查部位翻译问题
continuous-integration/drone/push Build is passing
2026-01-15 16:54:29 +08:00
wangxiaoshuang 20ad1c894a DICOM上传影像页面,预览本地影像的页面,增加标题
continuous-integration/drone/push Build is passing
2026-01-15 16:16:54 +08:00
wangxiaoshuang 95aa3e0be7 【受试者】受试者-受试者页面,操作按钮趋势图悬浮提示语错误
continuous-integration/drone/push Build is passing
2026-01-15 16:12:51 +08:00
wangxiaoshuang 46fdee6c01 SPM发送有限让中心人员更新人员信息,中心人员的邮件中进入中心调研链接页面,交互错误
continuous-integration/drone/push Build is running
2026-01-15 16:10:58 +08:00
wangxiaoshuang f997cec4fb 非DICOM阅片工具支持测量与标注
continuous-integration/drone/push Build is passing
2026-01-15 16:02:19 +08:00
caiyiling 1586643fc2 自定义阅片分类问题自动计算bug修复
continuous-integration/drone/push Build is passing
2026-01-15 12:26:24 +08:00
wangxiaoshuang 5ad0da7a4a 阅片单元配置外层问题ABS无法选择
continuous-integration/drone/push Build is passing
2026-01-15 10:56:45 +08:00
wangxiaoshuang 16c0e84ca0 阅片问题处理
continuous-integration/drone/push Build is passing
2026-01-14 16:56:48 +08:00
wangxiaoshuang e58fbdcab6 非dicom阅片添加视频查看
continuous-integration/drone/push Build is passing
2026-01-08 15:17:18 +08:00
caiyiling e17a89e151 管理后台国际化补充
continuous-integration/drone/push Build is passing
2026-01-08 12:34:47 +08:00
caiyiling bf35797282 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing
2026-01-07 13:31:42 +08:00
caiyiling 21bdd0b07e 菜单国际化更改 2026-01-07 13:31:19 +08:00
wangxiaoshuang 47798750a4 项目配置不显示图表后去除项目报表tab
continuous-integration/drone/push Build is passing
2026-01-07 11:31:37 +08:00
wangxiaoshuang 8d1d5cb43a 图像不需要查看原始数据,数据显示不对
continuous-integration/drone/push Build is passing
2026-01-07 10:39:18 +08:00
wangxiaoshuang ef08a5277d 1
continuous-integration/drone/push Build is passing
2026-01-06 13:46:30 +08:00
wangxiaoshuang 98a3f9c5b5 受试者图表只显示肿瘤标准
continuous-integration/drone/push Build is passing
2026-01-06 13:36:38 +08:00
wangxiaoshuang a0b39e7a0b 项目报表修改
continuous-integration/drone/push Build is passing
2026-01-06 11:06:11 +08:00
wangxiaoshuang 1191b97688 临床数据为空时下载模板按钮置灰
continuous-integration/drone/push Build is passing
2026-01-05 17:13:02 +08:00
wangxiaoshuang c662e6cc3a 项目报表PCWG3去除ORR
continuous-integration/drone/push Build is passing
2026-01-05 16:37:48 +08:00
wangxiaoshuang 30b5ee24a0 项目报表质疑统计接口添加项目I查询字段
continuous-integration/drone/push Build is passing
2026-01-05 15:54:56 +08:00
wangxiaoshuang 2781d02afa 1
continuous-integration/drone/push Build is passing
2026-01-05 15:41:11 +08:00
wangxiaoshuang 034f9528e5 Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is passing
2026-01-05 15:24:07 +08:00
wangxiaoshuang d8712f26cd 项目报表添加ORR分布、项目报表添加权限 2026-01-05 15:23:30 +08:00
caiyiling feab37c4ac 1
continuous-integration/drone/push Build is passing
2026-01-05 09:32:50 +08:00
wangxiaoshuang 443a31df97 1
continuous-integration/drone/push Build encountered an error
2026-01-04 16:38:53 +08:00
wangxiaoshuang 99955b2eff 报告页面:问题值出现了 【Object object】的字段
continuous-integration/drone/push Build is passing
2026-01-04 13:13:07 +08:00
wangxiaoshuang e36ae0404d 1
continuous-integration/drone/push Build is passing
2025-12-31 16:09:03 +08:00
wangxiaoshuang 65edc78152 项目报表柱状图上显示数字
continuous-integration/drone/push Build is passing
2025-12-31 15:56:54 +08:00
wangxiaoshuang 78f2f530c4 影像质控页面,列表下方是空白的。应该是需要铺满底部。
continuous-integration/drone/push Build is passing
2025-12-31 15:51:40 +08:00
wangxiaoshuang fdc23361f9 磁共振的图像在做MPR时,重建的体数据,在各个轴向上的图像数量不正确
continuous-integration/drone/push Build is running
2025-12-31 15:50:01 +08:00
wangxiaoshuang b4db6b4990 mRECIST HCC标准在评估报告未通过验证时,弹了签名框
continuous-integration/drone/push Build is passing
2025-12-31 11:29:10 +08:00
wangxiaoshuang a45ab4edf8 提示框优化
continuous-integration/drone/push Build is passing
2025-12-31 11:04:18 +08:00
wangxiaoshuang 2f20696827 Lugano2014病灶使用箭头工具时设置长短经为0
continuous-integration/drone/push Build is passing
2025-12-31 10:53:53 +08:00
wangxiaoshuang 2ffffd2bf0 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-31 10:09:53 +08:00
wangxiaoshuang d21c01076d 阅片跟踪添加靶段标注
continuous-integration/drone/push Build encountered an error
2025-12-30 17:05:27 +08:00
wangxiaoshuang 8d0f0094ba 图表修改
continuous-integration/drone/push Build is passing
2025-12-30 15:25:01 +08:00
wangxiaoshuang 08dba4b364 项目汇总图表需要优化
continuous-integration/drone/push Build is passing
2025-12-30 14:00:40 +08:00
wangxiaoshuang 2716b379b5 项目的邮件模板中,增加查询条件:邮件主题
continuous-integration/drone/push Build is passing
2025-12-30 13:22:34 +08:00
wangxiaoshuang 5216bf9f62 受试者页面添加图表查看入口
continuous-integration/drone/push Build is passing
2025-12-30 11:44:10 +08:00
wangxiaoshuang 040814c3d6 项目报表修改
continuous-integration/drone/push Build is passing
2025-12-30 10:24:50 +08:00
wangxiaoshuang 264f00f5a8 1
continuous-integration/drone/push Build is passing
2025-12-30 09:16:31 +08:00
wangxiaoshuang 3f48bc0ba5 项目报表修改
continuous-integration/drone/push Build is passing
2025-12-29 16:01:24 +08:00
wangxiaoshuang 2c47541737 电脑及浏览器兼容性检测
continuous-integration/drone/push Build is passing
2025-12-29 14:53:28 +08:00
wangxiaoshuang 0c2ed13cd4 【LiLi & EICS】项目数据汇总统计分析
continuous-integration/drone/push Build is passing
2025-12-29 13:55:00 +08:00
wangxiaoshuang f1c36ea688 阅片更改
continuous-integration/drone/push Build is passing
2025-12-29 13:11:34 +08:00
wangxiaoshuang 9568186497 中心调研退出调用接口 2025-12-29 13:11:15 +08:00
wangxiaoshuang a48dc114e8 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-29 09:13:58 +08:00
wangxiaoshuang abb224a8fb Merge branch 'uat'
continuous-integration/drone/push Build is failing
# Conflicts:
#	src/api/reading.js
#	src/api/trials.js
#	src/components/PreviewFile/index.vue
#	src/views/dictionary/template/components/CriterionQuestionForm.vue
#	src/views/dictionary/template/components/TableQsForm.vue
#	src/views/dictionary/template/email/components/EmailList.vue
#	src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue
#	src/views/trials/trials-panel/reading/dicoms/components/IVUS/QuestionTableFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms/components/OCT/QuestionList.vue
#	src/views/trials/trials-panel/reading/dicoms/components/OCT/QuestionTableFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms/components/QuestionItem.vue
#	src/views/trials/trials-panel/reading/dicoms/components/Questions.vue
#	src/views/trials/trials-panel/reading/dicoms/components/ReadPage.vue
#	src/views/trials/trials-panel/reading/dicoms/components/Recist/QuestionForm.vue
#	src/views/trials/trials-panel/reading/dicoms/components/Recist/QuestionList.vue
#	src/views/trials/trials-panel/reading/dicoms/components/ReportPage.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/Recist/QuestionFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/Recist/QuestionList.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/Recist/TableQuestionFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/ReportPage.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionFormItem.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionList.vue
#	src/views/trials/trials-panel/reading/dicoms3D/components/customize/QuestionTableFormItem.vue
#	src/views/trials/trials-panel/reading/mim-medical-audit/components/GlobalReview.vue
#	src/views/trials/trials-panel/reading/reading-task/index.vue
#	src/views/trials/trials-panel/reading/reading-tracking/components/exportList.vue
#	src/views/trials/trials-panel/setting/reading-unit/components/TableQsForm.vue
2025-12-26 17:09:35 +08:00
wangxiaoshuang 754fe5f797 1
continuous-integration/drone/push Build is passing
2025-12-26 15:48:40 +08:00
wangxiaoshuang f72cab082a 中心调研表配置样式更改
continuous-integration/drone/push Build is passing
2025-12-26 15:27:46 +08:00
wangxiaoshuang 03c7aa3d99 1
continuous-integration/drone/push Build is passing
2025-12-26 15:08:41 +08:00
wangxiaoshuang 24c7c61398 1
continuous-integration/drone/push Build is passing
2025-12-26 15:00:51 +08:00
wangxiaoshuang 281c900e0c 阅片单元的基础数据中,字典需要有描述
continuous-integration/drone/push Build is passing
2025-12-26 14:51:25 +08:00
wangxiaoshuang 63772f46f8 【邮件管理】后台邮件管理中,是否加急筛选项中选项应该是紧急、普通加急、不加急
continuous-integration/drone/push Build is passing
2025-12-26 14:45:22 +08:00
wangxiaoshuang accac374ff 中心调研表的编辑页面,页面布局需要调整
continuous-integration/drone/push Build is passing
2025-12-26 14:42:27 +08:00
wangxiaoshuang 4ee7906dcd 被融合病灶不允许画标记
continuous-integration/drone/push Build is passing
2025-12-26 14:14:55 +08:00
wangxiaoshuang 3dc99d096d 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-26 13:46:21 +08:00
wangxiaoshuang 096e11e9fd irecist 转变任务不显示融合按钮
continuous-integration/drone/push Build is passing
2025-12-26 13:24:26 +08:00
wangxiaoshuang cce6122e9e 已融合的消失的病灶不允许画标记
continuous-integration/drone/push Build is passing
2025-12-26 13:10:47 +08:00
wangxiaoshuang 47594536f1 【医学审核】医学审核页面数据需要显示单位,包括访视、裁判、全局、肿瘤学任务类型
continuous-integration/drone/push Build encountered an error
2025-12-26 10:47:52 +08:00
wangxiaoshuang 6f3ca769a6 被融合的病灶状态不可更改
continuous-integration/drone/push Build is passing
2025-12-25 15:38:29 +08:00
wangxiaoshuang da41fa1139 融合图像伪彩问题
continuous-integration/drone/push Build is passing
2025-12-25 15:14:52 +08:00
wangxiaoshuang 17b1cc476f 非dicom阅片排序修改、IVUS添加多选字段
continuous-integration/drone/push Build encountered an error
2025-12-25 14:50:44 +08:00
wangxiaoshuang 11940798e8 1
continuous-integration/drone/push Build is passing
2025-12-24 17:39:07 +08:00
wangxiaoshuang ef46e4cb08 mpr视图时禁止切换多视图
continuous-integration/drone/push Build is passing
2025-12-24 17:13:31 +08:00
wangxiaoshuang b2119c3acd 表格问题标记绑定时未触发自动计算
continuous-integration/drone/push Build is passing
2025-12-24 17:06:30 +08:00
wangxiaoshuang e7fdee1147 MPR修改
continuous-integration/drone/push Build is passing
2025-12-24 16:45:22 +08:00
wangxiaoshuang b5f327fc3c MPR增加影像加载前的验证:验证条件:序列的文件数量>5,影像具备imageOrientationPatient,imagePositionPatient
continuous-integration/drone/push Build is passing
2025-12-24 16:24:23 +08:00
wangxiaoshuang 93b7477aa6 阅片人申请重阅时:是否复制后续访视阅片表单的选项,需要根据阅片标准设置
continuous-integration/drone/push Build is passing
2025-12-24 15:09:41 +08:00
wangxiaoshuang 73e9f30f7e 【病灶融合】当前访视,融合病灶融合后,分裂按钮需要隐藏
continuous-integration/drone/push Build is passing
2025-12-24 14:29:48 +08:00
wangxiaoshuang 35cc08e53c 【病灶融合】融合按钮显示的位置其他标准调整与lugano一致
continuous-integration/drone/push Build is passing
2025-12-24 14:26:37 +08:00
wangxiaoshuang 97dda302e1 融合页面交互工具存在问题
continuous-integration/drone/push Build is passing
2025-12-24 14:22:30 +08:00
wangxiaoshuang f59b205324 自定义融合阅片标记问题绑定修改
continuous-integration/drone/push Build is passing
2025-12-24 13:35:26 +08:00
wangxiaoshuang 7328ea55df 阅片临床数据弹框修改
continuous-integration/drone/push Build is passing
2025-12-24 11:47:23 +08:00
wangxiaoshuang 5773a93df3 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-24 11:18:17 +08:00
wangxiaoshuang e6e9ab03a3 1
continuous-integration/drone/push Build is passing
2025-12-24 11:10:08 +08:00
wangxiaoshuang a663f6fa4e 1
continuous-integration/drone/push Build is passing
2025-12-24 10:54:57 +08:00
wangxiaoshuang 80fe969fe1 1
continuous-integration/drone/push Build is passing
2025-12-24 10:36:32 +08:00
wangxiaoshuang bdbca21550 邮件日志收件人、抄送人显示修改
continuous-integration/drone/push Build is passing
2025-12-24 10:17:45 +08:00
wangxiaoshuang 3901ceec45 中心调研模板设备字段修改
continuous-integration/drone/push Build is passing
2025-12-24 10:06:09 +08:00
wangxiaoshuang 2f8b88b51f 1
continuous-integration/drone/push Build is passing
2025-12-23 17:43:53 +08:00
wangxiaoshuang bed842ec88 1
continuous-integration/drone/push Build is passing
2025-12-23 17:28:27 +08:00
wangxiaoshuang 72d9872b20 申请重阅添加保留后续访视数据的选项
continuous-integration/drone/push Build is passing
2025-12-23 17:13:15 +08:00
wangxiaoshuang bdca45a505 影像汇总文件下载
continuous-integration/drone/push Build is passing
2025-12-23 16:36:22 +08:00
wangxiaoshuang 68fa0edfe5 申请重阅添加保留后续访视数据的选项
continuous-integration/drone/push Build is running
2025-12-23 16:19:54 +08:00
wangxiaoshuang 17ad103c34 【邮件日志】邮件日志页面相关问题
continuous-integration/drone/push Build is passing
2025-12-23 14:55:12 +08:00
wangxiaoshuang 7bebb8900e 1
continuous-integration/drone/push Build is passing
2025-12-22 17:10:52 +08:00
wangxiaoshuang fc72e141bf 1
continuous-integration/drone/push Build is passing
2025-12-22 16:29:54 +08:00
wangxiaoshuang 3eb28d2baa dicom预览问题
continuous-integration/drone/push Build is passing
2025-12-22 15:52:50 +08:00
wangxiaoshuang 7892b8cf01 发件人在新建项目时需要自动生成
continuous-integration/drone/push Build is passing
2025-12-22 14:15:45 +08:00
wangxiaoshuang 6cd5e7b957 非dicom阅片、预览添加排序
continuous-integration/drone/push Build encountered an error
2025-12-22 13:58:23 +08:00
wangxiaoshuang 8122464fbb 【页面刷新】靶段标记等页面关闭时,需要刷新数据
continuous-integration/drone/push Build encountered an error
2025-12-19 16:27:43 +08:00
wangxiaoshuang 56bc2bc5cd 上传、下载文件添加参数 2025-12-19 16:27:32 +08:00
wangxiaoshuang 9f5fc1dc9d 同步邮件添加参数
continuous-integration/drone/push Build is passing
2025-12-18 17:15:46 +08:00
wangxiaoshuang 4b5fee5739 mpr添加十字准星
continuous-integration/drone/push Build is running
2025-12-18 17:13:13 +08:00
wangxiaoshuang f5143fe11c PET-CT融合页面,测量值默认显示SUV
continuous-integration/drone/push Build is passing
2025-12-18 14:35:20 +08:00
wangxiaoshuang 363ffa58b3 影像质控风险管理
continuous-integration/drone/push Build is passing
2025-12-18 13:38:02 +08:00
wangxiaoshuang 4e46bbac84 项目自定义标准-NM DICOM工具可配置测量标注工具,影像标记可以与CRF问题关联
continuous-integration/drone/push Build is passing
2025-12-18 11:36:50 +08:00
wangxiaoshuang fb8135d985 【LiLi】中心人员定期管理
continuous-integration/drone/push Build is passing
2025-12-18 11:28:54 +08:00
wangxiaoshuang 691a3721a0 部分问题修复
continuous-integration/drone/push Build encountered an error
2025-12-17 13:46:10 +08:00
wangxiaoshuang 4efcaa915c 1
continuous-integration/drone/push Build encountered an error
2025-12-16 10:21:22 +08:00
wangxiaoshuang 903faf405e 邮件附件预览
continuous-integration/drone/push Build encountered an error
2025-12-16 09:40:36 +08:00
wangxiaoshuang e5233c8894 PET-CT融合页面,测量值和问题没有关联
continuous-integration/drone/push Build is passing
2025-12-15 17:13:34 +08:00
wangxiaoshuang 4143eb6279 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-15 14:34:42 +08:00
wangxiaoshuang 9da598862a trcist1.1新增阅片图表
continuous-integration/drone/push Build encountered an error
2025-12-15 14:07:59 +08:00
wangxiaoshuang f3d9b31313 病灶融合
continuous-integration/drone/push Build is passing
2025-12-12 17:24:39 +08:00
wangxiaoshuang 726f6499f9 项目报表
continuous-integration/drone/push Build is passing
2025-12-12 16:58:50 +08:00
wangxiaoshuang aab9c4576c 病灶融合功能
continuous-integration/drone/push Build is passing
2025-12-11 16:33:31 +08:00
wangxiaoshuang b661a51ec2 下载进度提示 2025-12-11 16:24:37 +08:00
wangxiaoshuang edb03fef23 隐私政策和用户协议更新日期和生效日期格式修改
continuous-integration/drone/push Build is passing
2025-12-11 11:36:54 +08:00
wangxiaoshuang 7ca31d8a5e 自动计算可以配置高亮显示值
continuous-integration/drone/push Build is passing
2025-12-11 11:18:59 +08:00
wangxiaoshuang 365791624e 新增自动计算规则绝对值
continuous-integration/drone/push Build encountered an error
2025-12-11 11:02:10 +08:00
wangxiaoshuang d7a8112441 导表添加 2025-12-11 11:01:30 +08:00
wangxiaoshuang d05ea6c28d oct表单父项修改子项清空 2025-12-11 11:01:02 +08:00
wangxiaoshuang 74547d7bff dicom多帧文件解析修改 2025-12-11 11:00:25 +08:00
wangxiaoshuang 5ec5eda344 【lugano2014】消失状态可使用的工具调整
continuous-integration/drone/push Build is passing
2025-12-08 16:43:25 +08:00
wangxiaoshuang 61a1b1b1c2 【国际化】一致性核查和人员中心管理的上传页面的上传文件文字的国际化需要相互独立
continuous-integration/drone/push Build is passing
2025-12-08 16:26:25 +08:00
wangxiaoshuang f93274080a 邮件日志重发记录
continuous-integration/drone/push Build is passing
2025-12-08 16:21:53 +08:00
wangxiaoshuang fbb9899b55 系统标准报告高亮显示修改
continuous-integration/drone/push Build is passing
2025-12-08 15:39:26 +08:00
wangxiaoshuang f7af9999e4 邮件日志接口添加项目Id 2025-12-08 15:39:03 +08:00
wangxiaoshuang 41eb974496 OCT系统标准修改,表单下拉框增加多选(OCT、自定义)
continuous-integration/drone/push Build encountered an error
2025-12-08 15:13:35 +08:00
wangxiaoshuang d64bea0d27 1
continuous-integration/drone/push Build is passing
2025-12-05 09:12:30 +08:00
wangxiaoshuang 6ee3a06eb2 问题修复
continuous-integration/drone/push Build encountered an error
2025-12-05 09:07:56 +08:00
wangxiaoshuang b4821ace59 oct标准修改
continuous-integration/drone/push Build encountered an error
2025-12-04 15:10:57 +08:00
wangxiaoshuang 3a7eadb41c mpr图标修改
continuous-integration/drone/push Build is passing
2025-12-04 14:57:44 +08:00
wangxiaoshuang 1b25f6538e MPR调窗同步
continuous-integration/drone/push Build is passing
2025-12-04 14:43:35 +08:00
wangxiaoshuang dbc84b2f58 1
continuous-integration/drone/push Build is passing
2025-12-04 13:43:23 +08:00
wangxiaoshuang 9d601b4a46 工作台时间显示问题
continuous-integration/drone/push Build is running
2025-12-04 13:40:44 +08:00
wangxiaoshuang 09e5bcb3b7 mpr查看标记和标记截图问题 2025-12-04 13:40:23 +08:00
wangxiaoshuang ae536a7fc4 mpr阅片
continuous-integration/drone/push Build is passing
2025-12-03 16:52:52 +08:00
wangxiaoshuang 1b6f48a5a5 1
continuous-integration/drone/push Build is passing
2025-12-03 11:13:02 +08:00
wangxiaoshuang d57c080916 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-02 17:52:47 +08:00
wangxiaoshuang c2cb5b1999 部分问题修复
continuous-integration/drone/push Build is passing
2025-12-02 17:12:49 +08:00
wangxiaoshuang cc5ac4c2a9 自定义dicom阅片添加mpr
continuous-integration/drone/push Build is passing
2025-12-02 16:28:42 +08:00
wangxiaoshuang 653d3c6228 拖拽上传文件夹未读取全部文件修复
continuous-integration/drone/push Build is passing
2025-12-02 13:31:29 +08:00
wangxiaoshuang eefb42c3f6 阅片图像修改
continuous-integration/drone/push Build is passing
2025-12-02 09:12:53 +08:00
wangxiaoshuang 612270eaad 添加排序
continuous-integration/drone/push Build encountered an error
2025-11-28 16:36:20 +08:00
wangxiaoshuang ba6cb87648 阅片融合分组区分颜色
continuous-integration/drone/push Build is passing
2025-11-28 16:30:29 +08:00
wangxiaoshuang 5cce828ad9 后处理上传访视id获取修改
continuous-integration/drone/push Build encountered an error
2025-11-28 15:19:03 +08:00
wangxiaoshuang 17f738aa5d 1
continuous-integration/drone/push Build is passing
2025-11-28 14:34:09 +08:00
wangxiaoshuang 7a91ccac80 淋巴结非靶病灶和淋巴结新病灶在状态为消失时且长短径不符合标准的不允许保存
continuous-integration/drone/push Build is passing
2025-11-28 10:50:43 +08:00
wangxiaoshuang 38d8ac5ae5 后处理上传影像路径修改
continuous-integration/drone/push Build encountered an error
2025-11-27 17:28:11 +08:00
wangxiaoshuang b8dfcfea1d 1
continuous-integration/drone/push Build encountered an error
2025-11-27 14:46:26 +08:00
wangxiaoshuang 47f885b551 1
continuous-integration/drone/push Build encountered an error
2025-11-27 14:15:41 +08:00
wangxiaoshuang 010a5867b5 靶段标注问题修改
continuous-integration/drone/push Build encountered an error
2025-11-27 13:30:42 +08:00
wangxiaoshuang 6f2bc9f7f5 靶段标注问题修改
continuous-integration/drone/push Build encountered an error
2025-11-27 10:29:59 +08:00
wangxiaoshuang c31bc89746 靶段标注问题修改
continuous-integration/drone/push Build encountered an error
2025-11-27 09:40:32 +08:00
wangxiaoshuang b57076d41d 阅片问题配置修改
continuous-integration/drone/push Build is passing
2025-11-26 16:20:22 +08:00
wangxiaoshuang a037209770 1
continuous-integration/drone/push Build encountered an error
2025-11-26 16:08:55 +08:00
wangxiaoshuang c675e21c40 靶段标注问题修改
continuous-integration/drone/push Build encountered an error
2025-11-26 14:57:44 +08:00
wangxiaoshuang 633a169467 中心调研编辑注意事项添加默认值
continuous-integration/drone/push Build is passing
2025-11-25 14:28:58 +08:00
wangxiaoshuang f2d50e7465 【邮件日志】邮件日志中收件人、抄送人未显示,发送时间错误
continuous-integration/drone/push Build is passing
2025-11-25 14:23:15 +08:00
wangxiaoshuang e65e6e2208 淋巴结非靶病灶和淋巴结新病灶在状态为消失时,允许测量
continuous-integration/drone/push Build is passing
2025-11-25 14:15:47 +08:00
wangxiaoshuang 196a20cbc0 【培训管理】新建培训文档,未发布直接下线,发布按钮仍可以点击,需要禁用
continuous-integration/drone/push Build is passing
2025-11-25 10:36:20 +08:00
wangxiaoshuang f002fed9e2 在查看多帧文件时,序列的图像数字出现了:31/1了。
continuous-integration/drone/push Build is passing
2025-11-25 10:30:52 +08:00
wangxiaoshuang 8aa067e52f 非dicom更正检查部位修改
continuous-integration/drone/push Build encountered an error
2025-11-24 17:17:47 +08:00
wangxiaoshuang 423b71c702 鼠标滚动时,切换图像,图像可以循环的从头到尾
continuous-integration/drone/push Build is passing
2025-11-24 17:12:10 +08:00
wangxiaoshuang f79084b599 阅片图表修改
continuous-integration/drone/push Build is passing
2025-11-24 15:27:15 +08:00
wangxiaoshuang ca99572f19 工作台的时间格式
continuous-integration/drone/push Build is passing
2025-11-24 13:29:59 +08:00
wangxiaoshuang 0d9db63f88 阅片图表显示修改
continuous-integration/drone/push Build is passing
2025-11-21 14:55:13 +08:00
wangxiaoshuang 3f9beb6dee 1
continuous-integration/drone/push Build is passing
2025-11-20 18:00:01 +08:00
wangxiaoshuang 3243b33b33 阅片报告中数值的统计与可视化
continuous-integration/drone/push Build is passing
2025-11-20 15:48:40 +08:00
wangxiaoshuang ca44352b9e 阅片图表展示配置
continuous-integration/drone/push Build is passing
2025-11-20 10:49:22 +08:00
wangxiaoshuang 20c257be4f 阅片前对影像进行靶段标注
continuous-integration/drone/push Build encountered an error
2025-11-19 15:51:10 +08:00
wangxiaoshuang e5d86abf92 阅片报告中数值的统计与可视化(未完成)
continuous-integration/drone/push Build is passing
2025-11-19 13:13:29 +08:00
wangxiaoshuang 8dedd1068a 阅片关键点添加查看全部
continuous-integration/drone/push Build is passing
2025-11-17 13:28:51 +08:00
wangxiaoshuang f58e52585f 阅片人简历采集验证码按钮样式修改
continuous-integration/drone/push Build is passing
2025-11-17 13:21:48 +08:00
wangxiaoshuang 1dd153448c 1
continuous-integration/drone/push Build is passing
2025-11-17 11:26:39 +08:00
wangxiaoshuang b60b0f8de7 1
continuous-integration/drone/push Build is passing
2025-11-17 11:07:10 +08:00
wangxiaoshuang 9de73b9d44 【验证码优化】等待时按钮需要置为灰色
continuous-integration/drone/push Build is passing
2025-11-14 17:17:16 +08:00
wangxiaoshuang b55245a83a 项目阅片关键点添加、首次进入阅片弹框提示阅片关键点
continuous-integration/drone/push Build is passing
2025-11-14 16:03:32 +08:00
wangxiaoshuang cf1af92c2f 阅片关键点系统添加
continuous-integration/drone/push Build is passing
2025-11-14 11:43:12 +08:00
wangxiaoshuang 64cec20d7d 补传影像
continuous-integration/drone/push Build encountered an error
2025-11-14 10:08:27 +08:00
wangxiaoshuang c7740493f8 1
continuous-integration/drone/push Build is passing
2025-11-13 15:26:45 +08:00
wangxiaoshuang cca8a0df9d 验证码发送与确认页面优化
continuous-integration/drone/push Build is passing
2025-11-12 15:31:00 +08:00
wangxiaoshuang a75f4a38f6 登录进行勾选
continuous-integration/drone/push Build is passing
2025-11-11 16:00:01 +08:00
wangxiaoshuang 49b3b056e3 中心调研与中心影像手册的逻辑关系
continuous-integration/drone/push Build is passing
2025-11-11 15:56:26 +08:00
wangxiaoshuang 937ab0899e 影像归档时,增加影像信息
continuous-integration/drone/push Build is passing
2025-11-10 15:56:20 +08:00
wangxiaoshuang f7d7d2b742 1
continuous-integration/drone/push Build is passing
2025-11-10 14:22:26 +08:00
wangxiaoshuang 7c9cde00a9 1
continuous-integration/drone/push Build is passing
2025-11-10 13:45:01 +08:00
wangxiaoshuang b56834e8ed 人员核对提醒按钮只需要pm显示
continuous-integration/drone/push Build is passing
2025-11-10 11:36:26 +08:00
wangxiaoshuang 29e785243e 阅片页面增加章程和阅片手册的入口
continuous-integration/drone/push Build is passing
2025-11-07 14:38:18 +08:00
wangxiaoshuang 7d57f6b5f6 阅片比例尺工具问题修复
continuous-integration/drone/push Build is passing
2025-11-07 13:23:18 +08:00
wangxiaoshuang ecb146bd67 1
continuous-integration/drone/push Build is passing
2025-11-06 16:10:26 +08:00
wangxiaoshuang 795423182d 邮件日志及状态管理
continuous-integration/drone/push Build is passing
2025-11-06 16:07:07 +08:00
wangxiaoshuang 5dd13b58c5 1
continuous-integration/drone/push Build is passing
2025-11-06 13:43:11 +08:00
wangxiaoshuang bbd8e8b510 1
continuous-integration/drone/push Build is passing
2025-11-06 10:04:14 +08:00
wangxiaoshuang 6c02793d2f 【LiLi】支持影像拖拽上传
continuous-integration/drone/push Build is passing
2025-11-05 16:33:03 +08:00
wangxiaoshuang 4f5fb17bb8 已有阅片期修改左侧条件时,右侧查询结果需要清空或刷新
continuous-integration/drone/push Build is passing
2025-11-05 14:45:42 +08:00
wangxiaoshuang 5f89d7d10c 影像阅片时,支持双屏、竖屏
continuous-integration/drone/push Build is passing
2025-11-05 14:21:23 +08:00
wangxiaoshuang 0002bd0165 去除列表项指定中心
continuous-integration/drone/push Build is passing
2025-11-05 13:58:12 +08:00
wangxiaoshuang 5cd5e3c34d 1
continuous-integration/drone/push Build is passing
2025-11-05 13:18:12 +08:00
wangxiaoshuang 9c0ca0a831 非dicom阅片配置矩形标记可绑定项修改
continuous-integration/drone/push Build is passing
2025-11-04 16:46:07 +08:00
wangxiaoshuang 181eaed3f5 批量设置阅片期
continuous-integration/drone/push Build is passing
2025-11-04 16:17:39 +08:00
wangxiaoshuang b88657fda0 1
continuous-integration/drone/push Build is passing
2025-11-04 09:14:52 +08:00
wangxiaoshuang d4aa02e0e5 系统标准阅片页面竖屏适配
continuous-integration/drone/push Build is passing
2025-11-03 15:59:50 +08:00
wangxiaoshuang d13a5edfda 全屏显示按钮,没有作用
continuous-integration/drone/push Build is passing
2025-11-03 14:39:51 +08:00
wangxiaoshuang b6ee9d5f62 【LiLi】工作台的时间格式
continuous-integration/drone/push Build is passing
2025-11-03 14:10:05 +08:00
wangxiaoshuang 134f2471a6 【自定义非dicom】增加比例尺后,表格中的数据没有刷新
continuous-integration/drone/push Build is passing
2025-10-31 17:12:13 +08:00
wangxiaoshuang 746278681d 1
continuous-integration/drone/push Build is passing
2025-10-31 09:16:47 +08:00
wangxiaoshuang 081263d34f 1
continuous-integration/drone/push Build is passing
2025-10-30 15:28:48 +08:00
wangxiaoshuang 199fe6aed3 【自定义非dicom】标记已与问题绑定,删除比例尺后,问题中的值应该恢复为px
continuous-integration/drone/push Build is passing
2025-10-30 15:04:28 +08:00
wangxiaoshuang 273932f9cc 【自定义dicom】表格数值问题移除标记后保存报错
continuous-integration/drone/push Build is passing
2025-10-30 14:32:33 +08:00
wangxiaoshuang 3832312041 标记值不正确
continuous-integration/drone/push Build is passing
2025-10-30 14:24:59 +08:00
wangxiaoshuang b6500c62c5 非dicom标记保存修改
continuous-integration/drone/push Build is passing
2025-10-30 13:20:21 +08:00
wangxiaoshuang 42839a925d 【阅片单元】数值问题配置测量工具,选项中不应该有箭头问题
continuous-integration/drone/push Build is passing
2025-10-30 11:09:44 +08:00
wangxiaoshuang 342f135d23 【自定义非dicom】绑定问题显示的小数取值与标记显示的值有差异
continuous-integration/drone/push Build is passing
2025-10-30 10:58:29 +08:00
wangxiaoshuang 7f47936f8a 【自定义dicom】数值问题中多边形工具的测量值,不应该有radius和max,缺少perimeter
continuous-integration/drone/push Build is passing
2025-10-30 10:55:09 +08:00
wangxiaoshuang a7b9218952 dicom阅片比例尺修改
continuous-integration/drone/push Build is passing
2025-10-30 10:48:54 +08:00
wangxiaoshuang 8590808cb9 1
continuous-integration/drone/push Build is passing
2025-10-29 16:20:48 +08:00
wangxiaoshuang 5394a2cde5 非dicom角度工具添加注释
continuous-integration/drone/push Build is passing
2025-10-29 16:04:08 +08:00
wangxiaoshuang fe0ba42736 【非dicom】重置crf时,需要清除所有标记,包括标尺
continuous-integration/drone/push Build is passing
2025-10-29 14:05:55 +08:00
wangxiaoshuang b6bc22af72 非dicom阅片问题修改
continuous-integration/drone/push Build is passing
2025-10-28 17:55:48 +08:00
wangxiaoshuang 9b67760ffd 中心人员定期管理
continuous-integration/drone/push Build is passing
2025-10-28 15:35:54 +08:00
wangxiaoshuang aee12347dc 非dicom阅片标记绑定问题
continuous-integration/drone/push Build is passing
2025-10-27 15:25:13 +08:00
wangxiaoshuang 7426be2e50 非dicom阅片问题绑定标记
continuous-integration/drone/push Build is passing
2025-10-24 17:58:10 +08:00
wangxiaoshuang 5565b1389d 隐私政策样式调整
continuous-integration/drone/push Build is passing
2025-10-24 15:53:10 +08:00
wangxiaoshuang 0e029369a3 隐私政策修改
continuous-integration/drone/push Build is passing
2025-10-24 11:23:19 +08:00
wangxiaoshuang 5d09bd2159 全量核查文件下载问题修改
continuous-integration/drone/push Build is passing
2025-10-24 09:49:16 +08:00
wangxiaoshuang 98757b6c06 1
continuous-integration/drone/push Build is passing
2025-10-23 16:28:39 +08:00
wangxiaoshuang c197c077a7 非dicom阅片工具配置修改
continuous-integration/drone/push Build is passing
2025-10-23 15:49:59 +08:00
wangxiaoshuang 2ce7fa7552 一致性核查结果,在做全量核查时,对于已经核查过的数据也进行校验
continuous-integration/drone/push Build is passing
2025-10-21 17:35:17 +08:00
wangxiaoshuang 5456d7a40b 阅片重置窗宽窗位不重置反色
continuous-integration/drone/push Build is passing
2025-10-21 16:46:01 +08:00
wangxiaoshuang 8299fd8958 隐私政策去除删除功能 2025-10-21 16:45:31 +08:00
wangxiaoshuang 06b505544b 1
continuous-integration/drone/push Build is passing
2025-10-21 16:09:39 +08:00
wangxiaoshuang 19d472bfb3 用户协议和数据隐私采集说明
continuous-integration/drone/push Build is passing
2025-10-21 16:04:23 +08:00
wangxiaoshuang 62f601a7be 接口变更
continuous-integration/drone/push Build is passing
2025-10-21 13:36:59 +08:00
wangxiaoshuang 689527b61e 错误字段修改
continuous-integration/drone/push Build is passing
2025-10-21 13:26:13 +08:00
wangxiaoshuang 7478472e33 1
continuous-integration/drone/push Build is passing
2025-10-21 13:09:58 +08:00
wangxiaoshuang 7f48e37779 1
continuous-integration/drone/push Build is passing
2025-10-21 11:48:41 +08:00
wangxiaoshuang 2a27e1fbae 【Lugano2014 无pet】报告页的整体肿瘤评估结果需要可以修改结果,为下拉框
continuous-integration/drone/push Build is passing
2025-10-21 11:38:35 +08:00
wangxiaoshuang 02a5e2fdc2 MFA登录状态持久管理和页面优化
continuous-integration/drone/push Build is passing
2025-10-20 14:59:58 +08:00
wangxiaoshuang 0f6da34395 1
continuous-integration/drone/push Build is passing
2025-10-17 15:14:15 +08:00
wangxiaoshuang 2c567e3530 培训记录受训人查询条件修改
continuous-integration/drone/push Build is passing
2025-10-17 13:58:58 +08:00
wangxiaoshuang b7f113c109 【Lugano2014 no pet】阅片报告整体肿瘤评估结果在全局阅片时有修改,鼠标悬浮在结果上时需要显示全局修改的结果
continuous-integration/drone/push Build is passing
2025-10-17 10:03:48 +08:00
wangxiaoshuang 7c79e4b1f3 项目信息编辑,申办方和CRO选择后无法清空,增加删除按钮
continuous-integration/drone/push Build is passing
2025-10-17 10:00:11 +08:00
wangxiaoshuang 88a7634ed3 阅片快捷键注册
continuous-integration/drone/push Build encountered an error
2025-10-16 19:35:53 +08:00
wangxiaoshuang 5528188a8b 非dicom阅片问题标记绑定(待完成)
continuous-integration/drone/push Build is passing
2025-10-16 18:41:01 +08:00
wangxiaoshuang c0aa89c6ca 调窗开启后,无法进行调窗
continuous-integration/drone/push Build is passing
2025-10-16 15:41:24 +08:00
wangxiaoshuang 5bbbdb0a97 Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-10-16 14:55:03 +08:00
wangxiaoshuang cbb73d68e1 阅片预设列表按钮国际化修改
continuous-integration/drone/push Build encountered an error
2025-10-16 14:54:53 +08:00
wangxiaoshuang feb205d05e 阅片单元新增配置是否预设
continuous-integration/drone/push Build encountered an error
2025-10-16 13:26:47 +08:00
wangxiaoshuang ccc6ee90cb 阅片期列表数量选择添加100、500、1000
continuous-integration/drone/push Build encountered an error
2025-10-16 09:05:05 +08:00
wangxiaoshuang cbcc11fe97 非dicom阅片单元配置
continuous-integration/drone/push Build is running
2025-10-15 17:10:18 +08:00
wangxiaoshuang 7f20bfecdc 新标准全局阅片修改
continuous-integration/drone/push Build is passing
2025-10-15 15:37:46 +08:00
wangxiaoshuang f58c116382 阅片期列表数量选择添加100、500、1000
continuous-integration/drone/push Build is passing
2025-10-15 14:47:41 +08:00
wangxiaoshuang b44d832241 1
continuous-integration/drone/push Build is passing
2025-10-15 14:32:15 +08:00
wangxiaoshuang bf2a2818ce Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-10-15 09:54:33 +08:00
wangxiaoshuang 75059297ad 样式调整
continuous-integration/drone/push Build encountered an error
2025-10-15 09:34:28 +08:00
wangxiaoshuang 58c33bc008 是否预设添加限制下拉框、单选框
continuous-integration/drone/push Build is passing
2025-10-14 14:48:17 +08:00
wangxiaoshuang 1e49dedd23 Lugano 2014 without FDG-PET
continuous-integration/drone/push Build is passing
2025-10-14 13:33:15 +08:00
wangxiaoshuang 3c661ae86a 1
continuous-integration/drone/push Build is passing
2025-10-14 11:13:48 +08:00
wangxiaoshuang 7238b12424 Lugano 2014全局更新类型,配置时数据被清空
continuous-integration/drone/push Build is passing
2025-10-13 16:17:48 +08:00
wangxiaoshuang 341a707c80 独立阅片人简历查看修改
continuous-integration/drone/push Build is passing
2025-10-13 14:01:46 +08:00
wangxiaoshuang 877535f579 1
continuous-integration/drone/push Build is passing
2025-10-13 10:20:09 +08:00
wangxiaoshuang 602f942e9e 附加评估问题修改
continuous-integration/drone/push Build is passing
2025-10-13 10:01:22 +08:00
wangxiaoshuang a804ba40f0 阅片单元新增配置是否预设
continuous-integration/drone/push Build is passing
2025-10-10 17:26:04 +08:00
wangxiaoshuang 38eef44d79 表单固定列
continuous-integration/drone/push Build is passing
2025-10-10 16:47:44 +08:00
wangxiaoshuang ff1b4f6f21 阅片比例尺 2025-10-10 16:47:25 +08:00
wangxiaoshuang ef336eafe6 登录隐私政策 2025-10-10 16:46:50 +08:00
wangxiaoshuang 553014be79 稽查记录的子项,增加属性:指定标准显示
continuous-integration/drone/push Build is passing
2025-10-10 15:19:17 +08:00
wangxiaoshuang e7491501cf 阅片人筛选-选择,编辑阅片人简历时,需要可以修改自动生成的临床试验经历
continuous-integration/drone/push Build is passing
2025-10-10 15:12:27 +08:00
wangxiaoshuang d64d5a523d 在报告页面增加附件评估结果评估和查看入口
continuous-integration/drone/push Build is passing
2025-10-10 11:26:18 +08:00
wangxiaoshuang b2e7eeaeb4 增加受试者中止状态筛选项
continuous-integration/drone/push Build is passing
2025-10-10 11:05:29 +08:00
wangxiaoshuang 0df193c474 排序删除
continuous-integration/drone/push Build encountered an error
2025-09-30 12:19:21 +08:00
wangxiaoshuang 7d9be5e2b3 1
continuous-integration/drone/push Build is passing
2025-09-30 10:01:49 +08:00
wangxiaoshuang df417afbbb 语言转换简体繁体
continuous-integration/drone/push Build is passing
2025-09-30 09:43:22 +08:00
wangxiaoshuang 48c76cb0bb 国际化跟随浏览器变更
continuous-integration/drone/push Build is passing
2025-09-29 15:29:28 +08:00
wangxiaoshuang 83182a4d0f 稽查管理页面样式调整
continuous-integration/drone/push Build is passing
2025-09-29 14:55:12 +08:00
wangxiaoshuang 10408bde30 培训记录查看ea过滤文件类型
continuous-integration/drone/push Build is passing
2025-09-29 14:21:50 +08:00
wangxiaoshuang 1705469056 1
continuous-integration/drone/push Build is passing
2025-09-29 13:58:35 +08:00
wangxiaoshuang 8f5b75fcd5 1
continuous-integration/drone/push Build is running
2025-09-29 13:56:33 +08:00
wangxiaoshuang 0c3a69d4d0 稽查管理修改
continuous-integration/drone/push Build is passing
2025-09-29 13:48:27 +08:00
wangxiaoshuang 2683a5a7c9 1
continuous-integration/drone/push Build is passing
2025-09-29 13:08:28 +08:00
wangxiaoshuang d17b95a200 稽查管理人员添加修改
continuous-integration/drone/push Build is passing
2025-09-29 11:06:01 +08:00
wangxiaoshuang 9a8bf1e637 EA查看工作台培训记录修改
continuous-integration/drone/push Build is passing
2025-09-29 10:37:17 +08:00
wangxiaoshuang 4aa43b009b 工作台稽查文档查看修改
continuous-integration/drone/push Build is passing
2025-09-28 16:20:51 +08:00
wangxiaoshuang bb798ce4ad 工作台新增稽查管理
continuous-integration/drone/push Build is passing
2025-09-28 15:48:30 +08:00
wangxiaoshuang da4cc0a8ef 检查部位未显示问题修改
continuous-integration/drone/push Build encountered an error
2025-09-24 09:59:20 +08:00
wangxiaoshuang fb55a1d536 【问题反馈】影像异常反馈,在邮件通知的的类型为IR影像异常无法阅片,而在反馈记录中显示的类型为其他
continuous-integration/drone/push Build is passing
2025-09-23 10:15:20 +08:00
wangxiaoshuang 2986d43f39 检查部位修改
continuous-integration/drone/push Build is passing
2025-09-22 14:41:59 +08:00
wangxiaoshuang 13c9c9b4c3 检查部位修改
continuous-integration/drone/push Build is passing
2025-09-22 14:26:28 +08:00
wangxiaoshuang d0a7a4132f usa环境logo替换
continuous-integration/drone/push Build is passing
2025-09-22 13:39:51 +08:00
wangxiaoshuang dffad5a122 检查部位修改
continuous-integration/drone/push Build is passing
2025-09-22 13:28:47 +08:00
wangxiaoshuang ef3ca59842 1
continuous-integration/drone/push Build is passing
2025-09-22 11:50:59 +08:00
wangxiaoshuang 1aaf1927f5 后处理上传检查部位修改
continuous-integration/drone/push Build is passing
2025-09-22 11:43:16 +08:00
wangxiaoshuang 6fab860497 【检查部位】阅片页面检查部位弹窗中,增加Modality字段
continuous-integration/drone/push Build is passing
2025-09-22 11:13:42 +08:00
wangxiaoshuang f3ff162cdd 1
continuous-integration/drone/push Build is passing
2025-09-18 18:12:57 +08:00
wangxiaoshuang b7655ebad0 编辑其他检查部位
continuous-integration/drone/push Build is passing
2025-09-18 17:55:05 +08:00
wangxiaoshuang 79df77b30c 1
continuous-integration/drone/push Build is passing
2025-09-18 17:25:37 +08:00
wangxiaoshuang cfe03844a7 1
continuous-integration/drone/push Build is passing
2025-09-18 16:57:39 +08:00
wangxiaoshuang 6eebf590f8 【PCWG3】查看已阅任务,病灶上信息显示缺少部位状态
continuous-integration/drone/push Build is passing
2025-09-17 17:14:43 +08:00
wangxiaoshuang c09220dbd3 【mRecist】新病灶的后续访视中,典型肝内病灶为是,直径测量小于10mm设为疑似,大于等于10mm设为明确 2025-09-17 17:11:34 +08:00
wangxiaoshuang 2dd2aeede7 recist1.1和mrecist的病灶列表淋巴病灶上显示的长度应该为短径长度 2025-09-17 16:51:42 +08:00
wangxiaoshuang 5ae8348765 阅片页面查看检查部位
continuous-integration/drone/push Build is passing
2025-09-16 16:36:29 +08:00
wangxiaoshuang 3b8505ba3a Merge branch 'uat'
continuous-integration/drone/push Build is passing
2025-09-16 14:41:19 +08:00
wangxiaoshuang fe8398df9d IVUS和OCT阅片前准备
continuous-integration/drone/push Build encountered an error
2025-09-16 14:41:07 +08:00
wangxiaoshuang 27caa4ff77 受试者中止状态,需要填写原因
continuous-integration/drone/push Build encountered an error
2025-09-16 10:47:34 +08:00
wangxiaoshuang 3b96a5326e 排序修改
continuous-integration/drone/push Build encountered an error
2025-09-15 14:23:21 +08:00
437 changed files with 66864 additions and 36226 deletions
+28 -19
View File
@@ -1,3 +1,4 @@
kind: pipeline
type: ssh
name: ssh-linux-uat-irc-publish
@@ -10,23 +11,29 @@ clone:
disable: true #禁用默认克隆
server:
host: 47.117.164.182
host: 101.132.253.119
user: root
password:
from_secret: local_pwd
steps:
- name: uat-branch-publish-irc-vue
commands:
- cd /opt/1panel/vue-devops/Uat_IRC/Uat-To-Uat
- sh uat-to-uat.sh v${DRONE_BUILD_NUMBER}
- name: publish-uat-irc-web
commands:
- bash /opt/1panel/xc-deploy-new/devops-center/build-vue-then-publish.sh IRC_Web uat --mode uat
- name: notify-wecom
commands:
- echo $DRONE_COMMIT_AUTHOR "$DRONE_COMMIT_MESSAGE"
- bash /opt/1panel/xc-deploy-new/devops-center/drone-notify-wecom.sh "$DRONE_BUILD_STATUS" "$DRONE_REPO_NAME" "$DRONE_BRANCH" "$DRONE_BUILD_NUMBER" "4355b98e-1e72-4678-8dfb-2fc6ad0bf449" "$DRONE_COMMIT_MESSAGE" "$DRONE_COMMIT_AUTHOR" "Uat_IRC_WEB" "irc.uat.extimaging.com"
when:
status:
- success
- failure
trigger:
branch:
- uat
---
---
kind: pipeline
type: ssh
name: ssh-linux-test-irc-publish
@@ -45,17 +52,19 @@ server:
from_secret: local_pwd
steps:
- name: publish-test-irc-vue
commands:
- echo start publish test-irc-vue
- cd /opt/1panel/hang/vue/test-irc
- sh test-irc.sh v${DRONE_BUILD_NUMBER}
- name: publish-test-irc-web
commands:
- bash /opt/1panel/xc-deploy-new/devops-center/build-vue-then-publish.sh IRC_Web main
- name: notify-wecom
commands:
- echo $DRONE_COMMIT_AUTHOR "$DRONE_COMMIT_MESSAGE"
- bash /opt/1panel/xc-deploy-new/devops-center/drone-notify-wecom.sh "$DRONE_BUILD_STATUS" "$DRONE_REPO_NAME" "$DRONE_BRANCH" "$DRONE_BUILD_NUMBER" "4355b98e-1e72-4678-8dfb-2fc6ad0bf449" "$DRONE_COMMIT_MESSAGE" "$DRONE_COMMIT_AUTHOR" "Test_IRC_WEB" "irc.test.extimaging.com"
when:
status:
- success
- failure
trigger:
branch:
- main
- main
+5200 -6005
View File
File diff suppressed because it is too large Load Diff
+15 -11
View File
@@ -9,23 +9,25 @@
"build:usa": "vue-cli-service build --mode usa",
"build:usa_prod": "vue-cli-service build --mode usa_prod",
"pre": "vue-cli-service build --mode pre",
"postinstall": "patch-package",
"i18n": "npm run i18n:zh && npm run i18n:en",
"i18n:zh": "node i18nGenerate.js lang=zh keyCol=5 valCol=6",
"i18n:en": "node i18nGenerate.js lang=en keyCol=5 valCol=7"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.701.0",
"@cornerstonejs/adapters": "^2.19.7",
"@aws-sdk/client-s3": "3.726.1",
"@cornerstonejs/adapters": "^4.19.2",
"@cornerstonejs/calculate-suv": "^1.1.0",
"@cornerstonejs/core": "^2.19.7",
"@cornerstonejs/dicom-image-loader": "^2.19.7",
"@cornerstonejs/tools": "^2.19.7",
"@cornerstonejs/core": "^4.19.2",
"@cornerstonejs/dicom-image-loader": "^4.19.2",
"@cornerstonejs/polymorphic-segmentation": "^4.19.2",
"@cornerstonejs/tools": "^4.19.2",
"@fingerprintjs/fingerprintjs": "^4.6.2",
"@icr/polyseg-wasm": "^0.4.0",
"@microsoft/signalr": "^8.0.7",
"@riophae/vue-treeselect": "^0.4.0",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.11",
"@vue/composition-api": "^1.7.2",
"ali-oss": "^6.17.1",
"axios": "^0.18.1",
"core-js": "^3.8.3",
@@ -37,7 +39,8 @@
"dcmjs": "^0.29.8",
"dicom-parser": "^1.8.9",
"dicomedit": "^0.1.0",
"echarts": "^4.8.0",
"echarts": "^6.0.0",
"echarts-map": "^3.0.1",
"element-ui": "^2.15.14",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
@@ -59,11 +62,10 @@
"screenfull": "^6.0.2",
"sortablejs": "^1.15.5",
"streamsaver": "^2.0.6",
"svg-sprite-loader": "^4.1.3",
"svgo": "^1.2.2",
"v-viewer": "^1.7.4",
"vcrontab": "^0.3.5",
"vue": "^2.6.14",
"vue": "2.7.16",
"vue-clipboard2": "^0.3.3",
"vue-contextmenujs": "^1.4.11",
"vue-count-to": "^1.0.13",
@@ -94,12 +96,14 @@
"html-webpack-plugin": "^5.6.3",
"mini-css-extract-plugin": "^2.9.2",
"node-polyfill-webpack-plugin": "^4.0.0",
"patch-package": "^8.0.0",
"path-browserify": "^1.0.1",
"process": "^0.11.10",
"sass": "^1.63.2",
"sass-loader": "^10.4.1",
"sass-loader": "^16.0.7",
"svg-sprite-loader": "^6.0.11",
"terser-webpack-plugin": "^5.3.10",
"vue-template-compiler": "^2.6.14",
"vue-template-compiler": "2.7.16",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
@@ -0,0 +1,16 @@
diff --git a/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js b/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js
index 33469a3..f39736f 100644
--- a/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js
+++ b/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js
@@ -14,10 +14,7 @@ export default function isColorConversionRequired(imageFrame) {
(3 * Math.ceil(columns / 2) + Math.floor(columns / 2)) * rows);
}
else if (photometricInterpretation.endsWith('422')) {
- return (pixelDataLength ===
- (3 * Math.ceil(columns / 2) + Math.floor(columns / 2)) *
- Math.ceil(rows / 2) +
- Math.floor(rows / 2) * columns);
+ return pixelDataLength === rows * columns * 2;
}
else {
return photometricInterpretation !== 'RGB' || planarConfiguration === 1;
+1 -1
View File
@@ -10,7 +10,7 @@
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-store,no-cache,must-revalidate">
<meta http-equiv="Cache" content="no-cache">
<title>IRC Imaging System</title>
<title>EIC lmaging Trial Management System</title>
</head>
<body>
+3
View File
@@ -0,0 +1,3 @@
window.config = {
timeZone: false
}
+2 -2
View File
@@ -31,7 +31,7 @@
<div class="title-container" style="display: flex;padding-top:180px;justify-content: flex-start;height: 100%;box-sizing: border-box">
<!-- IRC Management System -->
<!-- <div class="title" style="text-align: center;font-size: 28px;margin-top: 100px;padding-right: 120px"></div>-->
<!-- <div class="title" v-show="false">IRC Imaging System</div>-->
<!-- <div class="title" v-show="false">EIC lmaging Trial Management System</div>-->
<div style="color: #0a84ff;text-align: left;font-size: 28px">
{{message}}
</div>
@@ -63,7 +63,7 @@
<div style="margin: 0 auto;width: 600px;line-height: 28px;text-align: center" >
<h1 style="text-align: center;margin-bottom: 20px">关于</h1>
<p style="margin-bottom: 20px">
IRC Imaging System
EIC lmaging Trial Management System
</p>
<p style="margin-bottom: 20px">
V1.3.0.001
+1 -1
View File
@@ -31,7 +31,7 @@
<div class="title-container" style="display: flex;padding-top:180px;justify-content: flex-start;height: 100%;box-sizing: border-box">
<!-- IRC Management System -->
<!-- <div class="title" style="text-align: center;font-size: 28px;margin-top: 100px;padding-right: 120px"></div>-->
<!-- <div class="title" v-show="false">IRC Imaging System</div>-->
<!-- <div class="title" v-show="false">EIC lmaging Trial Management System</div>-->
<div style="color: #0a84ff;text-align: left;font-size: 28px">
{{message}}
</div>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

+1
View File
@@ -67,6 +67,7 @@
num = e.data
}
</script>
<script src="/config.js"></script>
</head>
<body>
<noscript>
BIN
View File
Binary file not shown.
+91 -109
View File
@@ -1,12 +1,7 @@
<template>
<div id="app" style="position: relative">
<div id="app" style="position: relative" :class="{ mask: isLock }">
<router-view />
<div
v-show="show"
v-if="$route.matched.length > 0"
v-adaptive
@click="openI18n"
style="
<div v-show="show" v-if="$route.matched.length > 0" v-adaptive @click="openI18n" style="
position: fixed;
bottom: 50px;
left: 50px;
@@ -19,58 +14,27 @@
color: #fff;
border-radius: 50%;
cursor: pointer;
"
>
">
i18n
</div>
<el-drawer
:title="$t('il8n:title')"
:visible.sync="drawer"
direction="rtl"
size="80%"
>
<el-drawer :title="$t('il8n:title')" :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 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 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="handleSortByColumn"
>
<el-table-column
prop="Code"
:label="$t('il8n:table:label')"
width="300"
show-overflow-tooltip
sortable="custom"
>
<el-table :data="tableData" v-adaptive="{ bottomOffset: 50 }" height="100" style="width: 100%"
@sort-change="handleSortByColumn">
<el-table-column prop="Code" :label="$t('il8n:table:label')" width="300" show-overflow-tooltip
sortable="custom">
</el-table-column>
<!-- <el-table-column-->
<!-- prop="Description"-->
@@ -81,71 +45,37 @@
<!-- {{scope.row.Description}}-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column
prop="Value"
:label="$t('il8n:table:en')"
sortable="custom"
>
<el-table-column prop="Value" :label="$t('il8n:table:en')" sortable="custom">
<template slot-scope="scope">
<el-input
v-model="scope.row.Value"
@input="
(e) => {
$set(scope.row, 'Value', e)
}
"
size="mini"
></el-input>
<el-input v-model="scope.row.Value" @input="
(e) => {
$set(scope.row, 'Value', e)
}
" size="mini"></el-input>
</template>
</el-table-column>
<el-table-column
prop="ValueCN"
:label="$t('il8n:table:cn')"
sortable="custom"
>
<el-table-column prop="ValueCN" :label="$t('il8n:table:cn')" sortable="custom">
<template slot-scope="scope">
<el-input
v-model="scope.row.ValueCN"
@input="
(e) => {
$set(scope.row, 'ValueCN', e)
}
"
size="mini"
></el-input>
<el-input v-model="scope.row.ValueCN" @input="
(e) => {
$set(scope.row, 'ValueCN', e)
}
" size="mini"></el-input>
</template>
</el-table-column>
<el-table-column
prop="ValueCN"
:label="$t('il8n:table:state')"
sortable="custom"
>
<el-table-column prop="State" :label="$t('il8n:table:state')" sortable="custom">
<template slot-scope="scope">
<el-select
v-model="scope.row.State"
clearable
filterable
size="mini"
>
<el-option
v-for="item of $d.InternationalizationKeyState"
:key="'InternationalizationKeyState' + item.value"
:label="item.label"
:value="item.value"
/>
<el-select v-model="scope.row.State" clearable filterable size="mini">
<el-option v-for="item of $d.InternationalizationKeyState"
:key="'InternationalizationKeyState' + item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column
prop="Version"
:label="$t('il8n:table:Version')"
sortable="custom"
>
<el-table-column prop="Version" :label="$t('il8n:table:Version')" sortable="custom">
</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 size="mini" @click="drawer = false">{{ $t('common:button:cancel') }}
</el-button>
<el-button size="mini" type="primary" @click="handleSave">{{
$t('common:button:save')
@@ -153,6 +83,7 @@
</div>
</el-drawer>
<feedBack v-if="$route.matched.length > 0" />
<timeTag v-if="config.timeZone" />
</div>
</template>
@@ -163,11 +94,16 @@ import {
} from '@/api/dictionary/dictionary'
import { getTrialExtralConfig } from '@/api/trials'
import feedBack from '@/views/trials/trials-layout/components/feedBack'
import timeTag from '@/components/timeTag'
import Vue from 'vue'
import i18n from './lang'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
export default {
name: 'App',
components: { feedBack },
components: {
feedBack,
timeTag
},
data() {
return {
drawer: false,
@@ -177,11 +113,17 @@ export default {
arr: [],
il8nExternal: false,
State: null,
config: window.config,
isLock: false
}
},
mounted() {
this.show = process.env.VUE_APP_OSS_PATH === '/test/dist'
Vue.prototype.$openI18n = this.openI18n
this.getIsLock()
DicomEvent.$on("isLock", (isLock) => {
this.isLock = isLock
})
},
// watch: {
// '$route.query': {
@@ -213,17 +155,30 @@ export default {
// },
// },
methods: {
getIsLock() {
if (zzSessionStorage.getItem('isLock') === 'true') {
this.isLock = true
} else {
this.isLock = false
}
},
// 排序
handleSortByColumn(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])
)
const { prop, order } = column
if (!prop || !order) {
this.tableData = [...this.tableData]
return
}
const collator = new Intl.Collator('zh-Hans-CN', {
numeric: true,
sensitivity: 'base',
})
this.tableData.sort((a, b) => {
const result = collator.compare(a[prop], b[prop])
return order === 'ascending' ? result : -result
})
},
handleStateChange() {
this.tableData.forEach((item) => {
@@ -365,14 +320,34 @@ export default {
</script>
<style lang="scss">
.mask {
position: relative;
filter: blur(5px);
user-select: none;
}
.mask::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: '';
display: block;
background: rgba(255, 253, 253, 0.5);
}
$light_gray: #606266;
.el-tooltip__popper {
max-width: 400px;
}
.my_multiple {
.el-input--medium .el-input__inner {
height: 36px !important;
}
.el-select__tags {
flex-wrap: nowrap;
overflow: hidden;
@@ -381,6 +356,7 @@ $light_gray: #606266;
display: block;
}
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none !important;
@@ -393,6 +369,7 @@ input[type='number'] {
.viewer-fixed.viewer-container {
z-index: 10000;
}
textarea {
white-space: break-spaces;
word-break: normal;
@@ -401,12 +378,15 @@ textarea {
* {
word-break: normal !important;
}
.box-body .el-button.is-circle:not(.is-disabled) i:before {
color: #428bca;
}
.box-body .el-button.is-circle i.el-icon-question:before {
color: #fff;
}
.system-title {
font-size: 35px;
color: $light_gray;
@@ -415,9 +395,11 @@ textarea {
font-family: 'Times New Roman';
text-shadow: 1px 0.5px 1.5px #666;
}
.title-logo {
height: 40px;
}
.title-logo {
height: 40px;
}
+76 -3
View File
@@ -89,10 +89,11 @@ export function UpdateUserRole(param) {
})
}
export function resetPassword(userId) {
export function resetPassword(data) {
return request({
url: `/user/resetPassword/${userId}`,
method: 'get'
url: `/user/resetPassword`,
method: 'post',
data
})
}
@@ -350,3 +351,75 @@ export function getUserJoinedTrialList(data) {
data
})
}
// 邮件日志-日志列表
export function getEmailLogList(data) {
return request({
url: `/EmailLog/getEmailLogList`,
method: 'post',
data
})
}
// 邮件日志-日志详情
export function getEmailInfo(data) {
return request({
url: `/EmailLog/getEmailInfo`,
method: 'post',
data
})
}
// 邮件日志-重发邮件
export function resendEmail(data) {
return request({
url: `/EmailLog/resendEmail`,
method: 'post',
data
})
}
// 邮件日志-同步邮件
export function synchronizationEmail(data) {
return request({
url: `/EmailLog/synchronizationEmail`,
method: 'post',
data
})
}
// 邮件日志-重发列表
export function getReSendEmail(data) {
return request({
url: `/EmailLog/getReSendEmail`,
method: 'post',
data
})
}
// 获取系统基础配置
export function getSystemBasicConfigInfo() {
return request({
url: `/DeployConfig/getSystemBasicConfigInfo`,
method: 'get',
})
}
// 更新系统基础配置
export function updateSystemBasicConfig(data) {
return request({
url: `/DeployConfig/updateSystemBasicConfig`,
method: 'post',
data
})
}
// 获取系统邮件配置
export function getEmailConfigInfo() {
return request({
url: `/DeployConfig/getEmailConfigInfo`,
method: 'get',
})
}
// 更新系统邮件配置
export function updateSystemEmailConfig(data) {
return request({
url: `/DeployConfig/updateSystemEmailConfig`,
method: 'post',
data
})
}
+71
View File
@@ -1403,3 +1403,74 @@ export function batchUpdateEmail(data) {
data
})
}
// 隐私政策和用户协议-获取列表
export function getUserAgreementList(data) {
return request({
url: `/UserAgreement/getUserAgreementList`,
method: 'post',
data
})
}
// 隐私政策和用户协议-设置当前版本
export function setCurrentVersion(data) {
return request({
url: `/UserAgreement/setCurrentVersion`,
method: 'post',
data
})
}
// 隐私政策和用户协议-新增或修改
export function addOrUpdateUserAgreement(data) {
return request({
url: `/UserAgreement/addOrUpdateUserAgreement`,
method: 'post',
data
})
}
// 隐私政策和用户协议-删除
export function deleteUserAgreement(id) {
return request({
url: `/UserAgreement/deleteUserAgreement/${id}`,
method: 'delete',
})
}
// 隐私政策和用户协议-详情
export function getUserAgreementById(data) {
return request({
url: `/UserAgreement/getUserAgreementById`,
method: 'post',
data
})
}
// 隐私政策和用户协议-当前版本
export function getCurrentVersionUserAgreements(data) {
return request({
url: `/UserAgreement/getCurrentVersionUserAgreements`,
method: 'post',
data
})
}
// 获取系统阅片关键点文件列表
export function getSystemCriterionKeyFileList(data) {
return request({
url: `/SystemCriterionKeyFile/getSystemCriterionKeyFileList`,
method: 'post',
data
})
}
// 新增/修改系统阅片关键点文件
export function addOrUpdateSystemCriterionKeyFile(data) {
return request({
url: `/SystemCriterionKeyFile/addOrUpdateSystemCriterionKeyFile`,
method: 'post',
data
})
}
// 删除系统阅片关键点文件
export function deleteSystemCriterionKeyFile(systemCriterionKeyFileId) {
return request({
url: `/SystemCriterionKeyFile/deleteSystemCriterionKeyFile/${systemCriterionKeyFileId}`,
method: 'delete'
})
}
+16
View File
@@ -239,6 +239,14 @@ export function getPatientList_Export(data) {
data
})
}
export function getTumor_CDISC_IVUSOCT_Export(data) {
return requestDownload({
url: `/IVUS_OCTExport/getTumor_CDISC_Export`,
responseType: 'blob',
method: 'post',
data
})
}
export function getCommonEvaluationList_Export(data) {
return requestDownload({
url: `/ExcelExport/getCommonEvaluationList_Export`,
@@ -255,6 +263,14 @@ export function getCommonJudgeRatioList_Export(data) {
data
})
}
export function getTumor_CDISC_Export(data) {
return requestDownload({
url: `/Tumor_CDISC_Export/getTumor_CDISC_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出国际化列表
export function GetInternationalizationList_Export(data) {
return requestDownload({
+41
View File
@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function addOrUpdateFileUploadRecord(params) {
return request({
url: `/FileUploadRecord/addOrUpdateFileUploadRecord`,
method: 'post',
data: params
})
}
export function batchAddSyncFileTask(params) {
return request({
url: `/FileUploadRecord/batchAddSyncFileTask`,
method: 'post',
data: params
})
}
export function getSubjectUploadRecordList(params) {
return request({
url: `/FileUploadRecord/getSubjectUploadRecordList`,
method: 'post',
data: params
})
}
export function getFileUploadRecordList(params) {
return request({
url: `/FileUploadRecord/getFileUploadRecordList`,
method: 'post',
data: params
})
}
export function getUploadFileSyncRecordList(params) {
return request({
url: `/FileUploadRecord/getUploadFileSyncRecordList`,
method: 'post',
data: params
})
}
+186
View File
@@ -294,3 +294,189 @@ export function readingImport(param) {
data: param
})
}
// 非dicom阅片保存标记
export function saveAnswerAndBindingNoneDicomMark(param) {
return request({
url: `/ReadingImageTask/saveAnswerAndBindingNoneDicomMark`,
method: 'post',
data: param
})
}
// 非dicom按比例修改答案
export function changePlottingScaleChangeAnswer(param) {
return request({
url: `/ReadingImageTask/changePlottingScaleChangeAnswer`,
method: 'post',
data: param
})
}
// 阅片获取图表数据
export function getReportsChartData(param) {
return request({
url: `/ReadingImageTask/getReportsChartData`,
method: 'post',
data: param
})
}
// 分割相关
// 获取分割组
export function getSegmentationList(param) {
return request({
url: `/Segmentation/getSegmentationList`,
method: 'post',
data: param
})
}
// 新增修改分割组
export function addOrUpdateSegmentation(param) {
return request({
url: `/Segmentation/addOrUpdateSegmentation`,
method: 'post',
data: param
})
}
// 删除分割组
export function deleteSegmentation(segmentationId) {
return request({
url: `/Segmentation/deleteSegmentation/${segmentationId}`,
method: 'delete'
})
}
// 获取分割
export function getSegmentList(param) {
return request({
url: `/Segmentation/getSegmentList`,
method: 'post',
data: param
})
}
// 新增修改分割
export function addOrUpdateSegment(param) {
return request({
url: `/Segmentation/addOrUpdateSegment`,
method: 'post',
data: param
})
}
// 删除分割
export function deleteSegment(segmentId) {
return request({
url: `/Segmentation/deleteSegment/${segmentId}`,
method: 'delete'
})
}
// 获取分割绑定关系
export function getSegmentBindingList(param) {
return request({
url: `/Segmentation/getSegmentBindingList`,
method: 'post',
data: param
})
}
// 保存分割绑定关系(可用作修改删除)
export function saveSegmentBindingAndAnswer(param) {
return request({
url: `/Segmentation/saveSegmentBindingAndAnswer`,
method: 'post',
data: param
})
}
// 获取表格问题配置
export function getReadingTableQuestionTrialById(params) {
return request({
url: `/ReadingQuestion/getReadingTableQuestionTrialById`,
method: 'post',
params
})
}
// 获取外层问题配置
export function getReadingQuestionTrialById(params) {
return request({
url: `/ReadingQuestion/getReadingQuestionTrialById`,
method: 'post',
params
})
}
// 修改分割组保存状态
export function changeSegmentationSavedStatus(data) {
return request({
url: `/Segmentation/changeSegmentationSavedStatus`,
method: 'post',
data
})
}
// 修改分割片段锁定状态
export function lockOrUnLockSegment(data) {
return request({
url: `/Segmentation/lockOrUnLockSegment`,
method: 'post',
data
})
}
// 图像数据匿名
export function studyMaskImage(data) {
return request({
url: `/Study/studyMaskImage`,
method: 'post',
data
})
}
// 撤销匿名
export function studyUndoMaskImage(data) {
return request({
url: `/Study/studyUndoMaskImage`,
method: 'post',
data
})
}
// 非dicom图像数据匿名
export function noneDicomStudyMaskImage(data) {
return request({
url: `/NoneDicomStudy/noneDicomStudyMaskImage`,
method: 'post',
data
})
}
// 非dicom图像数据撤销匿名
export function noneDicomStudyUndoMaskImage(data) {
return request({
url: `/NoneDicomStudy/noneDicomStudyUndoMaskImage`,
method: 'post',
data
})
}
// 获取分割组历史版本
export function getSegmentationVersionList(data) {
return request({
url: `/Segmentation/getSegmentationVersionList`,
method: 'post',
data
})
}
// 恢复分割历史版本
export function restoreSegmentationVersion(data) {
return request({
url: `/Segmentation/restoreSegmentationVersion`,
method: 'post',
data
})
}
// 获取标记信息
export function getMarkList(data) {
return request({
url: `/ReadingImageTask/getMarkList`,
method: 'post',
data
})
}
export function getNoneDicomMarkList(data) {
return request({
url: `/ReadingImageTask/getNoneDicomMarkList`,
method: 'post',
data
})
}
+5 -2
View File
@@ -26,8 +26,11 @@ export function getTrialSurveyInitInfo(trialId) {
export function getSiteSurveyInfo(trialId, id) {
return request({
url: `/TrialSiteSurvey/getSiteSurveyInfo/${trialId}/${id}`,
method: 'get'
url: `/TrialSiteSurvey/getSiteSurveyInfo/${trialId}`,
method: 'get',
params: {
TrialsiteSurveyId: id
}
})
}
+305 -11
View File
@@ -357,10 +357,11 @@ export function getSubjectList(param) {
})
}
export function getTrialSiteSelect(trialId) {
export function getTrialSiteSelect(trialId, params) {
return request({
url: `/trialMaintenance/getTrialSiteSelect/${trialId}`,
method: 'get'
method: 'get',
params
})
}
@@ -1203,7 +1204,13 @@ export function getConsistencyVerificationList(param) {
data: param
})
}
export function getConsistencyCheckFileList(param) {
return request({
url: `/QCList/getConsistencyCheckFileList`,
method: 'post',
data: param
})
}
export function getCheckChallengeDialogList(subjectVisitId) {
return request({
url: `/QCList/getCheckChallengeDialogList/${subjectVisitId}`,
@@ -1256,11 +1263,11 @@ export function getCRCVisitChallengeAndDialog(subjectVisitId, trialQCProcess) {
})
}
export function uploadVisitCheckExcel(trialId, file) {
export function uploadVisitCheckExcel(trialId, file, isFullCheck = false) {
const formData = new FormData()
formData.append('file', file)
return request({
url: `/QCOperation/UploadVisitCheckExcel/${trialId}`,
url: `/QCOperation/UploadVisitCheckExcel/${trialId}?isFullCheck=${isFullCheck}`,
method: 'post',
data: formData
})
@@ -1405,9 +1412,9 @@ export function getForwardList(param) {
})
}
export function getNoneDicomStudyList(subjectVisitId, sudyId = '', isFilterZip = false, visitTaskId = '', IsReading = false) {
export function getNoneDicomStudyList(subjectVisitId, sudyId = '', isFilterZip = false, visitTaskId = '', IsReading = false, isImageSegmentLabel = '') {
return request({
url: `/NoneDicomStudy/getNoneDicomStudyList?subjectVisitId=${subjectVisitId}&nonedicomStudyId=${sudyId}&isFilterZip=${isFilterZip}&visitTaskId=${visitTaskId}&IsReading=${IsReading}`,
url: `/NoneDicomStudy/getNoneDicomStudyList?isImageSegmentLabel=${isImageSegmentLabel}&subjectVisitId=${subjectVisitId}&nonedicomStudyId=${sudyId}&isFilterZip=${isFilterZip}&visitTaskId=${visitTaskId}&IsReading=${IsReading}`,
method: 'get'
})
}
@@ -2833,7 +2840,13 @@ export function getSplitPPdSum(param) {
data: param
})
}
export function getSplitPPdSumNoPet(param) {
return request({
url: `/LuganoWithoutPETCalculate/getSplitPPdSum`,
method: 'post',
data: param
})
}
export function submitDicomVisitTask(param) {
return request({
url: `/Inspection/ReadingImageTask/SubmitDicomVisitTask`,
@@ -2872,7 +2885,13 @@ export function getIsSuvMaxLesion(param) {
data: param
})
}
export function getIsSuvMaxLesionNoPet(param) {
return request({
url: `/LuganoWithoutPETCalculate/getIsSuvMaxLesion`,
method: 'post',
data: param
})
}
export function getCanChooseNotMerge(param) {
return request({
url: `/LuganoCalculate/getCanChooseNotMerge`,
@@ -2880,6 +2899,13 @@ export function getCanChooseNotMerge(param) {
data: param
})
}
export function getCanChooseNotMergeNoPet(param) {
return request({
url: `/LuganoWithoutPETCalculate/getCanChooseNotMerge`,
method: 'post',
data: param
})
}
export function saveTaskQuestion(saveQuestionType, param) {
return request({
url: `/SaveTaskQuestion/${saveQuestionType}`,
@@ -3044,7 +3070,13 @@ export function readClinicalData(param) {
data: param
})
}
export function viewstudyPart(param) {
return request({
url: `/ReadingImageTask/viewstudyPart`,
method: 'post',
data: param
})
}
export function getCustomQuestionPreview(param) {
return request({
url: `/ReadingQuestion/getCustomQuestionPreview`,
@@ -3597,13 +3629,24 @@ export function getSplenicState(visitTaskId, spleenLength) {
method: 'post'
})
}
export function getSplenicStateNoPet(visitTaskId, spleenLength) {
return request({
url: `/LuganoWithoutPETCalculate/getSplenicState?visitTaskId=${visitTaskId}&spleenLength=${spleenLength}`,
method: 'post'
})
}
export function getSplenicVerify(visitTaskId) {
return request({
url: `/LuganoCalculate/getSplenicVerify?visitTaskId=${visitTaskId}`,
method: 'post'
})
}
export function getSplenicVerifyNoPet(visitTaskId) {
return request({
url: `/LuganoWithoutPETCalculate/getSplenicVerify?visitTaskId=${visitTaskId}`,
method: 'post'
})
}
export function uploadTrialSiteSurveyUser(trialId, baseUrl, routeUrl, param) {
return request({
url: `/TrialSiteSurvey/UploadTrialSiteSurveyUser?trialId=${trialId}&baseUrl=${baseUrl}&routeUrl=${routeUrl}`,
@@ -4228,4 +4271,255 @@ export function getVisitStage(data) {
method: 'post',
data
})
}
// 稽查管理-列表
export function getAuditRecordList(data) {
return request({
url: `/AuditDocument/getAuditRecordList`,
method: 'post',
data
})
}
// 稽查管理-列表(EA)
export function getAuditRecordSelectList(data) {
return request({
url: `/AuditDocument/getAuditRecordSelectList`,
method: 'post',
data
})
}
// 稽查管理-列表新增修改
export function addOrUpdateAuditRecord(data) {
return request({
url: `/AuditDocument/addOrUpdateAuditRecord`,
method: 'post',
data
})
}
// 稽查管理-文档授权
export function setAuditRecordPermission(data) {
return request({
url: `/AuditDocument/setAuditRecordPermission`,
method: 'post',
data
})
}
// 稽查管理-人员管理
export function addOrDeleteAuditRecordUser(data) {
return request({
url: `/AuditDocument/addOrDeleteAuditRecordUser`,
method: 'put',
data
})
}
// 稽查管理-删除
export function deleteAuditRecord(auditRecordId) {
return request({
url: `/AuditDocument/deleteAuditRecord/${auditRecordId}`,
method: 'delete'
})
}
// 核对中心人员发送邮件
export function sendCheckSiteSurveyUserEmail(data) {
return request({
url: `/TrialSiteSurvey/sendCheckSiteSurveyUserEmail`,
method: 'post',
data
})
}
// 更新中心人员发送邮件
export function sendUpdateSiteSurveyUserEmail(data) {
return request({
url: `/TrialSiteSurvey/sendUpdateSiteSurveyUserEmail`,
method: 'post',
data
})
}
// 更新中心人员发送邮件
export function getTrialSiteLatestSurvey(params) {
return request({
url: `/TrialSiteSurvey/getTrialSiteLatestSurvey`,
method: 'get',
params
})
}
// 阅片期计划列表
export function getReadModulePageList(data) {
return request({
url: `/ReadModule/getReadModulePageList`,
method: 'post',
data
})
}
// 移除阅片期
export function setBatchRemoveReadingPlan(data) {
return request({
url: `/ReadingPeriodSet/setBatchRemoveReadingPlan`,
method: 'post',
data
})
}
// 更新项目额外json配置
export function updateTrialExtralConfig(params, data) {
return request({
url: `/TrialConfig/updateTrialExtralConfig`,
method: 'put',
params,
data
})
}
// 获取项目标准阅片关键点列表
export function getTrialCriterionKeyFileList(data) {
return request({
url: `/TrialCriterionKeyFile/getTrialCriterionKeyFileList`,
method: 'post',
data
})
}
// 设置已阅读关键文件
export function setReadKeyFile(data) {
return request({
url: `/ReadingImageTask/setReadKeyFile`,
method: 'post',
data
})
}
// 项目报表-访视完成度
export function getTrialVisitFinishedStatList(data) {
return request({
url: `/TrialStat/getTrialVisitFinishedStatList`,
method: 'post',
data
})
}
// 项目报表-质疑统计表
export function getTrialQuestionStatList(data) {
return request({
url: `/TrialStat/getTrialQuestionStatList`,
method: 'post',
data
})
}
// 项目报表-疗效统计表
export function getTrialEfficacyEvaluationStatList(data) {
return request({
url: `/TrialStat/getTrialEfficacyEvaluationStatList`,
method: 'post',
data
})
}
// 受试者图表
export function getReportsChartSummary(data) {
return request({
url: `/ReadingImageTask/getReportsChartSummary`,
method: 'post',
data
})
}
// 靶段标注列表
export function getTrialSubjectVisitMarkList(data) {
return request({
url: `/DownloadAndUpload/getTrialSubjectVisitMarkList`,
method: 'post',
data
})
}
// 更新缩略图
export function updateImageResizePath(data) {
return request({
url: `/Series/updateImageResizePath`,
method: 'post',
data
})
}
// 获取PET图像上患者信息
export function getPatientInfo(data) {
return request({
url: `/Study/getPatientInfo`,
method: 'post',
data
})
}
//编辑患者基本信息
export function editPatientInfo(data) {
return request({
url: `/Study/editPatientInfo`,
method: 'post',
data
})
}
//修正患者基本信息
export function amendmentPatientInfo(data) {
return request({
url: `/Inspection/Study/amendmentPatientInfo`,
method: 'post',
data
})
}
//修改临床数据后 将签名状态变更为未签名
export function updateReadModuleClinicalData(data) {
return request({
url: `/ReadingClinicalData/updateReadModuleClinicalData`,
method: 'post',
data
})
}
export function getTrialUnreadVisitList(params) {
return request({
url: `/DownloadAndUpload/getTrialUnreadVisitList`,
method: 'get',
params,
})
}
export function getDoctorUserTrialReadingStat(data) {
return request({
url: `/DoctorWorkload/getDoctorUserTrialReadingStat`,
method: 'post',
data,
})
}
// 设置项目链接过期时间
export function setTrialLinkExpirationTime(data) {
return request({
url: `/TrialConfig/setTrialLinkExpirationTime`,
method: 'post',
data,
})
}
// 获取项目链接过期时间
export function getTrialLinkExpirationTime(data) {
return request({
url: `/TrialConfig/getTrialLinkExpirationTime`,
method: 'post',
data,
})
}
// 获取项目链接时间是否过期
export function getLinkLinkExpirationTime(data) {
return request({
url: `/TrialConfig/getLinkLinkExpirationTime`,
method: 'post',
data,
})
}
// 获取项目链接code是否有效
export function getLinkVerificationCodeIsEffective(data) {
return request({
url: `/TrialConfig/getLinkVerificationCodeIsEffective`,
method: 'post',
data,
})
}
// 上传通用文件记录
export function addOrUpdateCommonUploadRecord(data) {
return request({
url: `/FileUploadRecord/addOrUpdateCommonUploadRecord`,
method: 'post',
data,
})
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 54 KiB

+37
View File
@@ -0,0 +1,37 @@
import Vue from "vue";
import AGRCOMP from "./index.vue";
const MFAConstructor = Vue.extend(AGRCOMP);
let MFAINSTANCELIST = [];
const AGR = options => {
const { Id, IsEn_Us, callBack, cancelBack } = options;
if (!Id) throw `Id is requred.but ${Id}`
const id = `AGR${new Date().getTime()}`;
const instance = new MFAConstructor();
MFAINSTANCELIST.push(instance)
instance.id = id;
instance.vm = instance.$mount();
if (instance.vm.visible) return;
document.body.appendChild(instance.vm.$el);
instance.vm.open({ Id, IsEn_Us });
instance.vm.$on("success", (Id) => {
if (callBack) callBack(Id)
});
instance.vm.$on("closed", () => {
if (cancelBack) cancelBack();
document.body.removeChild(instance.vm.$el);
instance.vm.$destroy();
let index = MFAINSTANCELIST.findIndex(item => item.id === id);
MFAINSTANCELIST.splice(index, 1)
});
return instance.vm;
}
AGR.close = () => {
if (MFAINSTANCELIST.length <= 0) return;
MFAINSTANCELIST.forEach(item => {
document.body.removeChild(item.vm.$el);
item.vm.$destroy();
})
MFAINSTANCELIST = [];
}
export default AGR;
+7
View File
@@ -0,0 +1,7 @@
import AGRCOMP from "./index.vue";
import AGR from "./fun";
export default Vue => {
Vue.component(AGRCOMP.name, AGRCOMP);
Vue.prototype.$AGR = AGR;
};
+65
View File
@@ -0,0 +1,65 @@
<template>
<!--AGR-->
<el-dialog v-if="visible" :visible.sync="visible" width="60%" :close-on-click-modal="false" append-to-body center
:show-close="true" @close="cancel">
<!-- <div slot="title">
{{ agreement.FileName }}
</div> -->
<div v-html="agreement.FileEnContent" class="content" v-if="IsEn_Us"></div>
<div v-html="agreement.FileContent" class="content" v-else></div>
</el-dialog>
</template>
<script>
import {
getUserAgreementById
} from '@/api/dictionary'
export default {
name: "AGR",
data() {
return {
visible: false,
agreement: {},
IsEn_Us: false
}
},
mounted() {
},
methods: {
async getAgreement(Id) {
try {
let data = {
Id
}
let res = await getUserAgreementById(data)
if (res.IsSuccess) {
this.agreement = res.Result
}
} catch (err) {
console.log(err)
}
},
open(data) {
let { Id, IsEn_Us } = data;
this.IsEn_Us = IsEn_Us
this.getAgreement(Id)
this.visible = true
},
cancel() {
this.visible = false;
this.$emit("closed");
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .el-dialog__body {
height: 500px;
}
.content {
height: 100%;
overflow-y: auto;
}
</style>
+12 -3
View File
@@ -2,9 +2,17 @@
<el-breadcrumb class="app-breadcrumb" separator-class="el-icon-arrow-right">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<span v-else-if="item.name === 'TrialsPanel'" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">
<!-- {{ item.meta.title }} -->
{{ item.meta.i18n ? $t(item.meta.i18n) : item.meta.title }}
</span>
<span v-else-if="item.name === 'TrialsPanel'" class="no-redirect">
<!-- {{ item.meta.title }} -->
{{ item.meta.i18n ? $t(item.meta.i18n) : item.meta.title }}
</span>
<a v-else @click.prevent="handleLink(item)">
{{ item.meta.i18n ? $t(item.meta.i18n) : item.meta.title }}
</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
@@ -35,6 +43,7 @@ export default {
item.meta.title = this.$route.query.trialCode // 暂时处理
}
})
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
+262 -84
View File
@@ -6,6 +6,7 @@
<div>Series #{{ dicomInfo.series }}</div>
<div>Image #{{ dicomInfo.frame }}</div>
<div>{{ dicomInfo.modality }}</div>
<div v-if="isComparison" style="font-size: 30px;color: #428bca;">{{ tip }}</div>
</div>
<div v-show="dicomInfo.series" class="info-image">
<!-- <div>
@@ -15,7 +16,7 @@
<div v-show="dicomInfo.thick">Slice Thickness {{ dicomInfo.thick }}mm</div>
<div>WW/WC {{ dicomInfo.wwwc }}</div>
<div>Zoom {{ dicomInfo.zoom }}</div>
<div v-show="dicomInfo.location">Location {{ dicomInfo.location }}mm</div> -->
<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) :
@@ -23,24 +24,18 @@
</div>
<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)">
SUVbw(g/ml): {{ mousePosition.suv.toFixed(3) }}
</div>
<div v-else-if="mousePosition.mo">
Density: {{ mousePosition.mo }}
</div>
<div>
W*H: {{ dicomInfo.size }}
</div>
HU: {{ mousePosition.mo }}</div>
<div v-else-if="(dicomInfo.modality === 'PT' && mousePosition.suv)">SUVbw(g/ml): {{ mousePosition.suv.toFixed(3)
}}</div>
<div v-else-if="mousePosition.mo">Density: {{ mousePosition.mo }}</div>
<div>W*H: {{ dicomInfo.size }}</div>
<div>Zoom: {{ dicomInfo.zoom }}</div>
</div>
<div class="info-subject">
<div v-if="series.subjectCode">{{ series.subjectCode }}</div>
<div v-if="series.visitName">{{ series.visitName }}</div>
<div v-if="series.subjectCode && IsReadingTaskViewInOrder !== 0">{{ series.subjectCode }}</div>
<div v-if="series.visitName && IsReadingTaskViewInOrder !== 0">{{ series.visitName }}</div>
<div>{{ stack.description }}</div>
<!-- <div>{{ dicomInfo.hospital }}</div> -->
<!-- <div v-show="dicomInfo.pid">{{ dicomInfo.pid }}</div> -->
@@ -56,24 +51,17 @@
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 }}
</div>
<div style="position: absolute;top: 50%;right: 15px;color: #f44336;">
{{ markers.right }}
</div>
<div style="position: absolute;left: 50%;top: 15px;color: #f44336;">{{ markers.top }}</div>
<div style="position: absolute;top: 50%;right: 15px;color: #f44336;">{{ markers.right }}</div>
<div style="position: absolute;left: 50%;bottom: 15px;color: #f44336;">
{{ markers.bottom }}
</div>
<div style="position: absolute;top: 50%;left: 15px;color: #f44336;">
{{ markers.left }}
</div>
<div style="position: absolute;left: 50%;bottom: 15px;color: #f44336;">{{ markers.bottom }}</div>
<div style="position: absolute;top: 50%;left: 15px;color: #f44336;">{{ markers.left }}</div>
<div class="info-instance">
<svg-icon icon-class="IsMasked" style="font-size:20px;" v-show="dicomInfo.IsMasked" />
<!-- <div v-show="dicomInfo.pixel">
Pixel: {{ dicomInfo.pixel }}mm
</div> -->
</div>-->
<div v-show="dicomInfo.location">Location: {{ dicomInfo.location }}</div>
<div v-show="dicomInfo.thick">Slice Thickness: {{ dicomInfo.thick }}mm</div>
<div v-show="dicomInfo.wwwc">WW/WL: {{ dicomInfo.wwwc }}</div>
@@ -92,15 +80,18 @@
import * as cornerstone from 'cornerstone-core'
import * as cornerstoneMath from 'cornerstone-math'
import * as cornerstoneTools from 'cornerstone-tools'
import metaDataProvider from '@/utils/metaDataProvider'
const scroll = cornerstoneTools.import('util/scrollToIndex')
import Hammer from 'hammerjs'
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
import invertOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/invertOrientationString'
import calculateSUV from '@/views/trials/trials-panel/reading/dicoms/tools/calculateSUV'
const calculateSUV = cornerstoneTools.import('util/calculateSUV')
// import requestPoolManager from '@/utils/request-pool'
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
import Note_RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/Note_RectangleRoiTool'
let isMetaDataProviderAdded = false
cornerstoneTools.external.cornerstone = cornerstone
cornerstoneTools.external.Hammer = Hammer
cornerstoneTools.external.cornerstoneMath = cornerstoneMath
@@ -110,6 +101,7 @@ cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)')
// cornerstoneTools.init({ showSVGCursors: true })
cornerstoneTools.init()
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
console.log(cornerstoneTools, 'cornerstoneTools')
import DicomTags from './DicomTags'
export default {
name: 'DicomCanvas',
@@ -117,6 +109,12 @@ export default {
computed: {
NSTip() {
return `${this.$store.state.trials.downloadSize}, NS: ${this.$store.state.trials.downloadTip}`
},
},
props: {
isComparison: {
type: Boolean,
default: false
}
},
data() {
@@ -130,7 +128,7 @@ export default {
seriesNumber: '',
imageIds: [],
currentImageIdIndex: 0,
firstImageLoading: false
firstImageLoading: false,
// preventCache: true
},
dicomInfo: {
@@ -150,14 +148,15 @@ export default {
wwwc: '',
zoom: 0,
location: '',
fps: 5
fps: 5,
IsMasked: false
},
toolState: {
initialized: false,
activeTool: 'none',
dicomInfoVisible: false,
clipPlaying: false,
viewportInvert: false
viewportInvert: false,
},
loadImagePromise: null,
AnnotationSync: null,
@@ -168,18 +167,25 @@ export default {
sliderInfo: {
oldB: null,
oldM: null,
isMove: false
isMove: false,
},
mousePosition: { x: '', y: '', mo: '' },
markers: { top: '', right: '', bottom: '', left: '' },
orientationMarkers: [],
originalMarkers: [],
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') }
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') },
tip: '',
IsReadingTaskViewInOrder: 2
}
},
mounted() {
this.type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
this.type = this.$router.currentRoute.query.type
? this.$router.currentRoute.query.type
: ''
if (this.$router.currentRoute.query.IsReadingTaskViewInOrder) {
this.IsReadingTaskViewInOrder = Number(this.$router.currentRoute.query.IsReadingTaskViewInOrder)
}
this.canvas = this.$refs.canvas
this.canvas.addEventListener('cornerstonenewimage', this.onNewImage)
this.canvas.addEventListener(
@@ -200,17 +206,28 @@ export default {
document.addEventListener('mousemove', (e) => {
this.sliderMousemove(e)
})
this.canvas.addEventListener('cornerstonetoolsstackscroll', this.stackScrollCallback)
this.canvas.addEventListener(
'cornerstonetoolsstackscroll',
this.stackScrollCallback
)
},
methods: {
loadImageStack(dicomSeries) {
loadImageStack(dicomSeries, text = '') {
this.tip = text
this.$nextTick(() => {
if (!dicomSeries || !Array.isArray(dicomSeries.imageIds) || dicomSeries.imageIds.length === 0) {
return
}
this.series = dicomSeries
this.stack.seriesId = dicomSeries.seriesId
this.stack.seriesNumber = dicomSeries.seriesNumber
this.stack.imageIds = dicomSeries.imageIds
this.stack.currentImageIdIndex = dicomSeries.imageIdIndex && dicomSeries.imageIdIndex < dicomSeries.imageIds.length ? dicomSeries.imageIdIndex : 0
this.stack.currentImageIdIndex =
dicomSeries.imageIdIndex &&
dicomSeries.imageIdIndex < dicomSeries.imageIds.length
? dicomSeries.imageIdIndex
: 0
this.stack.firstImageLoading = true
this.stack.description = dicomSeries.description
this.toolState.viewportInvert = false
@@ -221,18 +238,27 @@ export default {
// this.stack.instanceId = instanceId
this.toolState.clipPlaying = false
const element = this.$refs.canvas
if (!isMetaDataProviderAdded) {
// 注册自定义 metaDataProvider:统一 SUV 口径(优先接口,缺失回退 DICOM)
cornerstone.metaData.addProvider(metaDataProvider, 100000)
isMetaDataProviderAdded = true
}
cornerstone.enable(element)
cornerstoneTools.stopClip(this.canvas)
this.toolState.clipPlaying = false
this.loading = true
cornerstone.loadAndCacheImage(this.stack.imageIds[this.stack.currentImageIdIndex])
.then(image => {
cornerstone
.loadAndCacheImage(
this.stack.imageIds[this.stack.currentImageIdIndex]
)
.then((image) => {
this.loading = false
if (this.stack.imageIds.indexOf(image.imageId) !== -1) {
this.onFirstImageLoaded(image)
}
}).catch((error) => {
})
.catch((error) => {
this.loading = false
if (error.error && error.error.message) {
this.$alert(error.error.message)
@@ -255,15 +281,17 @@ export default {
const apiTool = cornerstoneTools[`${toolName}Tool`]
if (apiTool) {
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(
element,
apiTool
)
const toolAlreadyAddedToElement =
cornerstoneTools.getToolForElement(element, apiTool)
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)
}
@@ -287,8 +315,28 @@ export default {
false
)
})
if (!cornerstoneTools.getToolForElement(element, cornerstoneTools.WwwcRegionTool)) {
cornerstoneTools.addToolForElement(element, cornerstoneTools.WwwcRegionTool)
if (
!cornerstoneTools.getToolForElement(element, Note_RectangleRoiTool)
) {
cornerstoneTools.addToolForElement(element, Note_RectangleRoiTool, {
configuration: {
color: '#f00',
lineWidth: 2,
drawHandles: false,
fillColor: 'rgba(0, 0, 0, 1)',
},
})
}
if (
!cornerstoneTools.getToolForElement(
element,
cornerstoneTools.WwwcRegionTool
)
) {
cornerstoneTools.addToolForElement(
element,
cornerstoneTools.WwwcRegionTool
)
}
if (
!cornerstoneTools.getToolForElement(
@@ -347,20 +395,27 @@ export default {
// var instanceId = image.imageId.split('/')[image.imageId.split('/').length - 1]
// instanceId = instanceId.split('.')[0]
// this.stack.instanceId = instanceId
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
this.height = this.getStackHeightPercent()
this.resetWwwc()
},
onNewImage(e) {
e.detail.enabledElement.options = {}
var data = e.detail.image.data
this.dicomInfo.hospital = data.string('x00080080')
// let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === e.detail.image.imageId)
let instanceInfo = this.series?.instanceInfoList?.find(item => {
let s1 = item.ImageId ? item.ImageId.split("?")[0] : ''
let s2 = e.detail.image.imageId ? e.detail.image.imageId.split("?")[0] : ''
return s1 === s2
})
this.dicomInfo.IsMasked = instanceInfo ? instanceInfo.IsMasked : false
// this.dicomInfo.pid = data.string('x00100020')
this.dicomInfo.pid = data.string('x00120040')
this.dicomInfo.name = data.string('x00100010')
this.dicomInfo.age = data.string('x00101010')
this.dicomInfo.sex = data.string('x00100040')
this.dicomInfo.acc = data.string('x00080050') // 登记号
this.dicomInfo.modality = data.string('x00080060')
this.dicomInfo.modality = (data.string('x00080060') || '').trim()
this.dicomInfo.time = this.formatDicomDateTime(
data.string('x00080020'),
data.string('x00080030')
@@ -379,21 +434,32 @@ export default {
if (this.dicomInfo.thick) {
this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2)
}
const newImageIdIndex = this.stack.imageIds.findIndex(i => i === e.detail.image.imageId)
const newImageIdIndex = this.stack.imageIds.findIndex(
(i) => i === e.detail.image.imageId
)
if (newImageIdIndex === -1) return
this.stack.currentImageIdIndex = newImageIdIndex
this.stack.imageIdIndex = newImageIdIndex
this.series.imageIdIndex = newImageIdIndex
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
this.resetWwwc()
this.height = this.getStackHeightPercent()
},
getStackHeightPercent() {
const imageCount = Array.isArray(this.stack.imageIds) ? this.stack.imageIds.length : 0
if (imageCount <= 1) {
return 0
}
return (this.stack.currentImageIdIndex * 100) / (imageCount - 1)
},
stackScrollCallback(e) {
const { detail } = e
if (this.isScrollSync) {
this.$emit('scrollSync', { canvasIndex: this.canvasIndex, direction: detail.direction })
this.$emit('scrollSync', {
canvasIndex: this.canvasIndex,
direction: detail.direction,
})
}
this.stack.currentImageIdIndex = e.detail.newImageIdIndex
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
this.height = this.getStackHeightPercent()
// var priority = new Date(new Date().setHours(23, 59, 59, 999)).getTime()
// requestPoolManager.loadAndCacheImagePlus(this.stack.imageIds[this.stack.currentImageIdIndex], this.stack.seriesId, priority)
@@ -408,7 +474,9 @@ export default {
if (date) {
date = `${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}`
}
if (time) { time = `${time.substr(0, 2)}:${time.substr(2, 2)}:${time.substr(4, 2)}` }
if (time) {
time = `${time.substr(0, 2)}:${time.substr(2, 2)}:${time.substr(4, 2)}`
}
return time ? `${date} ${time}` : `${date} 00:00:00`
},
@@ -453,7 +521,7 @@ export default {
top: oppositeColumn,
bottom: column,
left: oppositeRow,
right: row
right: row,
}
if (!markers) {
return
@@ -500,13 +568,7 @@ export default {
if (image.color) {
stats.storedPixels = this.getRGBPixels(element, x, y, 1, 1)
} else {
stats.storedPixels = cornerstone.getStoredPixels(
element,
x,
y,
1,
1
)
stats.storedPixels = cornerstone.getStoredPixels(element, x, y, 1, 1)
stats.sp = stats.storedPixels[0]
stats.mo = stats.sp * image.slope + image.intercept
stats.suv = calculateSUV(image, stats.sp)
@@ -533,7 +595,8 @@ export default {
if (enabledElement.image.color) {
for (row = 0; row < height; row++) {
for (column = 0; column < width; column++) {
spIndex = ((row + y) * enabledElement.image.columns + (column + x)) * 4
spIndex =
((row + y) * enabledElement.image.columns + (column + x)) * 4
const red = pixelData[spIndex]
const green = pixelData[spIndex + 1]
const blue = pixelData[spIndex + 2]
@@ -551,7 +614,8 @@ export default {
},
sliderMousedown(e) {
var boxHeight = this.$refs['sliderBox'].clientHeight
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
this.sliderInfo.oldB =
(parseInt(e.srcElement.style.top) * boxHeight) / 100
this.sliderInfo.oldM = e.clientY
this.sliderInfo.isMove = true
e.stopImmediatePropagation()
@@ -564,9 +628,14 @@ export default {
var boxHeight = this.$refs['sliderBox'].clientHeight
if (PX < 0) return
if (PX > boxHeight) return
var height = PX * 100 / boxHeight
var index = Math.trunc(this.stack.imageIds.length * this.height / 100)
index = index > this.stack.imageIds.length ? this.stack.imageIds.length : index < 0 ? 0 : index
var height = (PX * 100) / boxHeight
var index = Math.trunc((this.stack.imageIds.length * this.height) / 100)
index =
index > this.stack.imageIds.length
? this.stack.imageIds.length
: index < 0
? 0
: index
// if (!cornerstone.imageCache.getImageLoadObject(this.stack.imageIds[index])) return
this.height = height
if (this.stack.currentImageIdIndex !== index) {
@@ -578,9 +647,9 @@ export default {
},
goViewer(e) {
// console.log(this.$refs['sliderBox'].clientHeight)
var height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
var height = (e.offsetY * 100) / this.$refs['sliderBox'].clientHeight
this.height = height
var index = Math.trunc(this.stack.imageIds.length * this.height / 100)
var index = Math.trunc((this.stack.imageIds.length * this.height) / 100)
scroll(this.canvas, index)
},
onClipStopped() {
@@ -673,10 +742,7 @@ export default {
}
this.toolState.clipPlaying = true
cornerstoneTools.playClip(this.canvas, this.dicomInfo.fps)
cornerstoneTools.getToolState(
this.canvas,
'playClip'
).data[0].loop = true
cornerstoneTools.getToolState(this.canvas, 'playClip').data[0].loop = true
},
setFps(fps) {
this.dicomInfo.fps = fps
@@ -687,6 +753,7 @@ export default {
var viewport = cornerstone.getViewport(this.canvas)
// viewport.invert = false
var image = cornerstone.getImage(this.canvas)
if (!viewport || !image) return
viewport.voi.windowWidth = image.windowWidth
viewport.voi.windowCenter = image.windowCenter
cornerstone.setViewport(this.canvas, viewport)
@@ -712,8 +779,8 @@ export default {
invert: false,
preventZoomOutsideImage: false,
minScale: 0.1,
maxScale: 20.0
}
maxScale: 20.0,
},
})
cornerstoneTools.setToolActive('Zoom', { mouseButtonMask: 1 })
this.toolState.activeTool = 'zoom'
@@ -797,9 +864,120 @@ export default {
setToolPassive(toolName) {
cornerstoneTools.setToolPassiveForElement(this.canvas, toolName)
},
async reloadImage(newImageId = null) {
// 1. 获取当前imageId(如果未指定新imageId
let element = this.canvas
this.stack.imageIds.splice(this.stack.currentImageIdIndex, 1, newImageId)
const currentImageId =
newImageId || cornerstone.getImage(element)?.imageId
if (!currentImageId) {
console.error('没有找到可用的imageId')
return
}
// 2. 清除该影像关联的工具状态(标注数据)
this.clearToolStateForImage(element, currentImageId)
// 3. 从缓存中移除该影像
this.removeImageFromCache(currentImageId)
// 4. 重新加载并渲染
await this.loadAndRenderImage(element, currentImageId)
},
clearToolStateForImage(element, imageId) {
// 获取全局状态管理器
const globalToolStateManager =
cornerstoneTools.globalImageIdSpecificToolStateManager
if (globalToolStateManager) {
// 方式1:清空该影像的全部工具数据
globalToolStateManager.clearImageIdToolState(imageId)
console.log(`已清除影像 ${imageId} 的所有标注数据`)
}
// 方式2:如果使用元素级别的状态管理器
const elementToolStateManager =
cornerstoneTools.getElementToolStateManager(element)
if (elementToolStateManager && elementToolStateManager.get(element)) {
// 清空该元素上当前显示影像的数据
elementToolStateManager.clear(element)
}
},
removeImageFromCache(imageId) {
const imageCache = cornerstone.imageCache
if (imageCache && imageCache[imageId]) {
// 从缓存中移除
delete imageCache[imageId]
console.log(`已从缓存中移除影像: ${imageId}`)
}
// 也可以使用官方API(如果可用)
if (typeof cornerstone.imageCache.removeImage === 'function') {
cornerstone.imageCache.removeImageLoadObject(imageId)
}
},
async loadAndRenderImage(element, imageId) {
try {
// 1. 清除当前画布内容(可选)
const canvas = element.querySelector('canvas')
if (canvas) {
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
// 2. 重新加载图像(强制从源头重新获取)
const image = await cornerstone.loadAndCacheImage(imageId)
// 3. 获取或创建视口设置
let viewport = cornerstone.getViewport(element)
if (!viewport) {
viewport = cornerstone.getDefaultViewport(element, image)
}
// 4. 显示图像
cornerstone.displayImage(element, image, viewport)
// 5. 触发重绘
cornerstone.updateImage(element)
console.log(`影像 ${imageId} 重新加载并渲染完成`)
return image
} catch (error) {
console.error('加载图像失败:', error)
throw error
}
},
getNote_RectangleRoi() {
return new Promise(resolve => {
let toolInfo = cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi')
let image = cornerstone.getImage(this.canvas)
resolve({ toolInfo, image })
})
// console.log(
// cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi')
// )
// console.log(cornerstone.getImage(this.canvas))
// let image = cornerstone.getImage(this.canvas)
// // cornerstone.imageCache.removeImageLoadObject(image.imageId)
// this.reloadImage(this.canvas, image.imageId)
},
removeNote_RectangleRoi() {
const toolState = cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi');
if (toolState && toolState.data.length > 0) {
let arr = toolState.data.map(item => item)
arr.forEach(item => {
cornerstoneTools.removeToolState(this.canvas, 'Note_RectangleRoi', item);
})
cornerstone.updateImage(this.canvas);
}
},
setToolActive(toolName) {
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
mouseButtonMask: 1
mouseButtonMask: 1,
})
},
setAllToolsPassive() {
@@ -833,7 +1011,7 @@ export default {
)
}
cornerstoneTools.setToolEnabledForElement(this.canvas, 'ReferenceLines', {
synchronizationContext: synchronizer
synchronizationContext: synchronizer,
})
// cornerstoneTools.addTool(cornerstoneTools.CrosshairsTool)
@@ -864,7 +1042,7 @@ export default {
}
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
mouseButtonMask: 1,
synchronizationContext: synchronizer
synchronizationContext: synchronizer,
})
},
disabledViewPortToolSync(synchronizer, toolName) {
@@ -1095,7 +1273,7 @@ export default {
'CobbAngle',
'Angle',
'Bidirectional',
'FreehandRoi'
'FreehandRoi',
]
for (let i = 0; i < toolROITypes.length; i++) {
const toolROIType = toolROITypes[i]
@@ -1115,12 +1293,12 @@ export default {
removeLabel(item) {
const promise = scroll(this.canvas, item.data.imageIdIndex)
const scope = this
Promise.all([promise]).then(res => {
Promise.all([promise]).then((res) => {
cornerstoneTools.removeToolState(scope.canvas, item.type, item.data)
cornerstone.updateImage(scope.canvas)
})
}
}
},
},
}
</script>
File diff suppressed because it is too large Load Diff
+44 -36
View File
@@ -1,25 +1,11 @@
<template>
<!--MFA-->
<el-dialog
v-if="visible"
:visible.sync="visible"
width="540px"
:close-on-click-modal="false"
append-to-body
center
:show-close="status === 'login'"
@close="cancel"
>
<el-dialog v-if="visible" :visible.sync="visible" width="540px" :close-on-click-modal="false" append-to-body center
:show-close="status === 'login'" @close="cancel">
<div slot="title">
{{ status === "login" ? $t("mfa:title") : $t("mfa:lock:title") }}
</div>
<el-form
ref="mfaForm"
label-position="right"
:model="form"
:rules="rules"
label-width="100px"
>
<el-form ref="mfaForm" label-position="right" :model="form" :rules="rules" label-width="100px">
<!-- 邮箱 -->
<p class="tip_mfa">
<i class="el-icon-warning" style="color: #409eff"></i>
@@ -31,18 +17,13 @@
</el-form-item>
<!-- 验证码 -->
<el-form-item :label="$t('mfa:form:MFACode')" prop="Code">
<el-input
:placeholder="$t('mfa:form:input:placeholder:Codes')"
v-model="form.Code"
style="width: 240px; margin-right: 10px"
/>
<el-button
type="primary"
size="small"
@click.stop="sendMFACode"
:disabled="flag || sendFlag"
>{{ flag ? `${second}s` : $t("mfa:form:sendMFACode") }}</el-button
>
<div style="display: flex;justify-content: space-between;width: 90%;">
<el-input :placeholder="$t('mfa:form:input:placeholder:Codes')" v-model="form.Code" />
<el-button size="small" @click.stop="sendMFACode" :disabled="flag || sendFlag" style="margin-left: 10px;"
class="codeBtn">{{
flag ?
`${$t("mfa:form:sendMFACodeCountDown")} (${second}s)` : $t("mfa:form:sendMFACode") }}</el-button>
</div>
</el-form-item>
</el-form>
<div slot="footer">
@@ -51,19 +32,16 @@
{{ $t("mfa:button:cancel") }}
</el-button> -->
<!-- 保存 -->
<el-button
type="primary"
size="small"
@click="save"
:loading="loading"
style="width: 80%"
>
<el-button type="primary" size="small" @click="save" :loading="loading" style="width: 80%">
{{
status === "login"
? $t("mfa:button:save")
: $t("mfa:lock:button:save")
}}
</el-button>
<p style="text-align: left;font-size: 14px;margin:10px auto;width: 80%;">
<el-checkbox v-model="form.isRemember" /><span style="margin-left: 10px;">{{ $t("mfa:tip:noLogin") }}</span>
</p>
</div>
</el-dialog>
</template>
@@ -86,6 +64,7 @@ export default {
IdentityUserId: null,
EMail: null,
username: null,
isRemember: true
},
rules: {
Code: [
@@ -112,6 +91,18 @@ export default {
},
};
},
mounted() {
this.flag = true;
this.second = 60;
this.timer = setInterval(() => {
this.second--;
if (this.second <= 0) {
this.flag = false;
clearInterval(this.timer);
this.timer = null;
}
}, 1000);
},
methods: {
open(data) {
let { UserId, status, username, EMail } = data;
@@ -189,6 +180,21 @@ export default {
};
</script>
<style lang="scss" scoped>
.codeBtn {
color: #409EFF;
border-color: #409EFF;
}
.codeBtn.is-disabled,
.codeBtn.is-disabled:focus,
.codeBtn.is-disabled:hover {
color: #c0c4cc;
cursor: not-allowed;
background-image: none;
background-color: #fff;
border-color: #ebeef5;
}
.tip_mfa {
width: 86%;
margin: auto;
@@ -198,10 +204,12 @@ export default {
line-height: 30px;
border-radius: 5px;
background-color: #eee;
i {
margin-right: 5px;
}
}
::v-deep .el-dialog__header {
font-weight: bold;
}
+2 -2
View File
@@ -4,7 +4,7 @@ import Preview from "./index.vue";
const PreviewConstructor = Vue.extend(Preview);
const preview = options => {
const { path, type, title } = options;
const { path, type, title, isLocal = false } = options;
if (!path) throw `path is requred.but ${path}`
const id = `Preview_${new Date().getTime()}`;
const instance = new PreviewConstructor();
@@ -12,7 +12,7 @@ const preview = options => {
instance.vm = instance.$mount();
if (instance.vm.visible) return;
document.body.appendChild(instance.vm.$el);
instance.vm.open(path, type, title);
instance.vm.open(path, type, title, isLocal);
instance.vm.$on("closed", () => {
document.body.removeChild(instance.vm.$el);
instance.vm.$destroy();
+6 -11
View File
@@ -1,15 +1,8 @@
<template>
<el-dialog
v-if="visible"
:visible.sync="visible"
:title="title"
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
@close="handleClose"
>
<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">
<PreviewFile v-if="visible" :file-path="path" :file-type="type" />
<PreviewFile v-if="visible" :file-path="path" :file-type="type" :is-local="isLocal" />
</div>
</el-dialog>
</template>
@@ -24,13 +17,15 @@ export default {
path: null,
type: null,
title: null,
isLocal: false
};
},
methods: {
open(path, type, title) {
open(path, type, title, isLocal) {
this.path = path;
this.type = type;
this.title = title;
this.isLocal = isLocal;
this.visible = true;
},
handleClose() {
+11 -5
View File
@@ -5,16 +5,17 @@
<!-- <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}`"
:src="`/static/pdfjs/web/viewer.html?file=${isLocal ? window.location.origin : 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>-->
<video :src="`${OSSclientConfig.basePath}${filePath}`" style="width: 100%;height: 99%;" autoplay controls
controlsList="nodownload" v-else-if="fileType.indexOf('mp4') !== -1"></video>
<video :src="`${isLocal ? window.location.origin : 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}`"
:src="`/static/onlyOffice/viewer.html?url=${isLocal ? window.location.origin : 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') }}
@@ -43,12 +44,17 @@ export default {
type: String,
default: ''
},
isLocal: {
type: Boolean,
default: false
}
},
data() {
return {
currentUser: zzSessionStorage.getItem('userName'),
COMPANY: process.env.VUE_APP_COMPANY_NAME,
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL,
window,
}
},
computed: {
+3 -3
View File
@@ -22,7 +22,7 @@ export default {
},
methods: {
click() {
if (!screenfull.enabled) {
if (!screenfull.isEnabled) {
this.$message({
message: 'you browser can not work',
type: 'warning'
@@ -35,12 +35,12 @@ export default {
this.isFullscreen = screenfull.isFullscreen
},
init() {
if (screenfull.enabled) {
if (screenfull.isEnabled) {
screenfull.on('change', this.change)
}
},
destroy() {
if (screenfull.enabled) {
if (screenfull.isEnabled) {
screenfull.off('change', this.change)
}
}
+131 -81
View File
@@ -2,19 +2,21 @@
<template>
<div class="trialsTab">
<el-tabs v-model="trialsTab" @tab-click="clickTab">
<el-tab-pane v-for="item of trialsRouter.children.find(v => {return v.name == 'TrialsPanel'}).children" :key="`tab${item.path}`" :disabled="TotalNeedSignTrialDocCount !== 0 && item.path !== '/trials/trials-panel/attachments'" :label="$t(item.LanguageMark)" :name="item.path">
<el-tabs v-if="!item.tabHiddn" v-model="trialsTabChild" @tab-click="clickTab" style="background-color: #f5f7fa;">
<template v-for="item1 of item.children">
<el-tab-pane
v-if="TrialConfig && isShow(item1.path)"
:key="`tab1${item1.path}`"
:disabled="TotalNeedSignTrialDocCount !== 0 && item1.path !== '/trials/trials-panel/attachments/self-attachment' || (TrialStatusStr === 'Initializing' && (item1.path === '/trials/trials-panel/setting/personnel-manage' || item1.path === '/trials/trials-panel/setting/qc-question' || item1.path === '/trials/trials-panel/setting/reading-unit' || item1.path === '/trials/trials-panel/setting/medical-audit' || item1.path === '/trials/trials-panel/setting/email-manage'))"
:label="$t(item1.LanguageMark)"
:name="item1.path"
/>
</template>
</el-tabs>
</el-tab-pane>
<template v-for="item of trialsRouter.children.find(v => { return v.name == 'TrialsPanel' }).children">
<el-tab-pane :key="`tab${item.path}`"
:disabled="TotalNeedSignTrialDocCount !== 0 && item.path !== '/trials/trials-panel/attachments'"
:label="$t(item.LanguageMark)" :name="item.path" v-if="isShowNode(item)">
<el-tabs v-if="!item.tabHiddn" v-model="trialsTabChild" @tab-click="clickTab"
style="background-color: #f5f7fa;">
<template v-for="item1 of item.children">
<el-tab-pane v-if="TrialConfig && isShow(item1.path)" :key="`tab1${item1.path}`"
:disabled="TotalNeedSignTrialDocCount !== 0 && item1.path !== '/trials/trials-panel/attachments/self-attachment' || (TrialStatusStr === 'Initializing' && (item1.path === '/trials/trials-panel/setting/personnel-manage' || item1.path === '/trials/trials-panel/setting/qc-question' || item1.path === '/trials/trials-panel/setting/reading-unit' || item1.path === '/trials/trials-panel/setting/medical-audit' || item1.path === '/trials/trials-panel/setting/email-manage'))"
:label="$t(item1.LanguageMark)" :name="item1.path" />
</template>
</el-tabs>
</el-tab-pane>
</template>
</el-tabs>
<div style="position: absolute;top: 0;right: 0;display: flex;justify-content: space-between;align-items: center">
<trials-select />
@@ -54,7 +56,8 @@ export default {
TrialConfig: {},
TrialStatusStr: null,
trialId: null,
IsAdditionalAssessment: false
IsAdditionalAssessment: false,
isReload: false
}
},
computed: {
@@ -69,21 +72,27 @@ export default {
if (~url.indexOf('?')) {
query = url.split('?')[1]
}
zzSessionStorage.setItem('lastWorkbench', `${v.path}${query ? '?' : ''}${query}`)
if (!this.isReload) {
zzSessionStorage.setItem('lastWorkbench', `${v.path}${query ? '?' : ''}${query}`)
} else {
this.isReload = false
}
var firstGoIn = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children[0]
if (this.trialsTab === '/trials/trials-panel') {
this.$router.replace({ path: `${firstGoIn.path}${query ? '?' : ''}${query}` })
var targetPath = firstGoIn.path
if (firstGoIn.children && firstGoIn.children.length > 0) {
this.$router.replace({ path: `${firstGoIn.children[0].path}${query ? '?' : ''}${query}` })
targetPath = firstGoIn.children[0].path
}
this.$router.replace({ path: `${targetPath}${query ? '?' : ''}${query}` })
}
// document.cookie = 'TrialId=' + this.$route.query.trialId + ';path=/'
},
trialId(v) {
if (!this.$route.query.trialId) return
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
var total = res.OtherInfo.NeedSignCount
var TrialStatusStr = res.OtherInfo.TrialStatusStr
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
this.TrialStatusStr = TrialStatusStr
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
@@ -92,33 +101,51 @@ export default {
}
},
mounted() {
this.$EventBus.$on("reload", () => {
this.isReload = true
})
var query = ``
var url = window.location.href
if (~url.indexOf('?')) {
query = url.split('?')[1]
}
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
var total = res.OtherInfo.NeedSignCount
var TrialStatusStr = res.OtherInfo.TrialStatusStr
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
this.TrialStatusStr = TrialStatusStr
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
this.TrialConfig = res.OtherInfo.TrialConfig
})
if (this.$route.query.trialId) {
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
var total = res.OtherInfo.NeedSignCount
var TrialStatusStr = res.OtherInfo.TrialStatusStr
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
this.TrialStatusStr = TrialStatusStr
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
this.TrialConfig = res.OtherInfo.TrialConfig
})
}
this.selectedTab()
this.getTrialList()
var firstGoIn = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children[0]
if (this.trialsTab === '/trials/trials-panel') {
this.$router.replace({ path: `${firstGoIn.path}${query ? '?' : ''}${query}` })
var targetPath = firstGoIn.path
if (firstGoIn.children && firstGoIn.children.length > 0) {
this.$router.replace({ path: `${firstGoIn.children[0].path}${query ? '?' : ''}${query}` })
targetPath = firstGoIn.children[0].path
}
this.$router.replace({ path: `${targetPath}${query ? '?' : ''}${query}` })
}
},
methods: {
isShow: function(path) {
isShowNode(item) {
if (item.path === '/trials/trials-panel/trial-summary' && item.children.length === 1 && item.children[0].path === '/trials/trials-panel/trial-summary/report-forms' && !this.$store.state.trials.config.IsExternalViewTrialChart && this.hasPermi(['role:cmm', 'role:cpm', 'role:ea', 'role:mc', 'role:smm', 'role:spm'])) {
return false
}
return true
},
isShow: function (path) {
var isShow = true
let chartList = [
'/trials/trials-panel/trial-summary/report-forms'
]
let dataSyncList = [
`/trials/trials-panel/trial-summary/data-sync`
]
var qualityList = [
'/trials/trials-panel/visit/crc-question',
'/trials/trials-panel/visit/qc-check',
@@ -134,6 +161,12 @@ export default {
'/trials/trials-panel/trial-summary/image-inspect',
'/trials/trials-panel/trial-summary/push-record',
]
if (this.$store.state.trials.config.TrialDataStoreType !== 1 && ~dataSyncList.indexOf(path)) {
isShow = false
}
if (!this.$store.state.trials.config.IsExternalViewTrialChart && ~chartList.indexOf(path) && this.hasPermi(['role:cmm', 'role:cpm', 'role:ea', 'role:mc', 'role:smm', 'role:spm'])) {
isShow = false
}
if (this.TrialConfig.QCProcessEnum === 0 && ~qualityList.indexOf(path)) {
isShow = false
}
@@ -187,15 +220,19 @@ export default {
if (~url.indexOf('?')) {
query = url.split('?')[1]
}
this.$router.push({ path: `${v.name}${query ? '?' : ''}${query}` })
var trialsPanelList = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children
var isHasChild = trialsPanelList.find(c => { return c.path === v.name }) && trialsPanelList.find(c => { return c.path === v.name }).children
if (trialsPanelList.find(c => { return c.path === v.name }) && trialsPanelList.find(c => { return c.path === v.name }).tabHiddn) {
var trialsPanelList = this.trialsRouter.children.find(item => { return item.name === 'TrialsPanel' }).children
var currentRoute = trialsPanelList.find(c => { return c.path === v.name })
if (currentRoute && currentRoute.tabHiddn) {
this.$router.push({ path: `${v.name}${query ? '?' : ''}${query}` })
return
}
var isHasChild = currentRoute && currentRoute.children
if (isHasChild && isHasChild.length > 0) {
this.trialsTabChild = isHasChild[0].path
this.$router.push({ path: `${this.trialsTabChild}${query ? '?' : ''}${query}` })
} else {
this.$router.push({ path: `${v.name}${query ? '?' : ''}${query}` })
}
} catch (e) {
console.log(e)
@@ -205,56 +242,69 @@ export default {
}
</script>
<style lang="scss">
.trialsTab{
.my_icon_box{
padding:0 20px 0 0;
transition: color,transform .3s;
cursor: pointer;
color: #666;
display: flex;
justify-content: center;
align-items: center;
&:hover{
color: #428bca;
}
span{
margin-left: 3px;
font-size: 14px;
}
.trialsTab {
.my_icon_box {
padding: 0 20px 0 0;
transition: color, transform .3s;
cursor: pointer;
color: #666;
display: flex;
justify-content: center;
align-items: center;
&:hover {
color: #428bca;
}
.el-tabs__header{
margin-bottom: 3px;
}
.el-tabs__item.is-active{
font-weight: bold;
}
position: relative;
.el-input--medium .el-input__inner{
height: 44px;line-height: 44px;width: 280px;
border: none;
text-align: right;
span {
margin-left: 3px;
font-size: 14px;
}
}
.base-model-wrapper{
.el-dialog__header{
padding: 10px;
.el-dialog__headerbtn{
top: 10px;
right: 10px;
}
}
.el-dialog__body{
padding:10px 10px 10px 10px;
.base-modal-body{
min-height: 100px;
max-height:650px;
overflow-y: auto;
padding: 10px;
border: 1px solid #e0e0e0;
}
}
.el-dialog__footer{
padding: 10px;
.el-tabs__header {
margin-bottom: 3px;
}
.el-tabs__item.is-active {
font-weight: bold;
}
position: relative;
.el-input--medium .el-input__inner {
height: 44px;
line-height: 44px;
width: 280px;
border: none;
text-align: right;
}
}
.base-model-wrapper {
.el-dialog__header {
padding: 10px;
.el-dialog__headerbtn {
top: 10px;
right: 10px;
}
}
.el-dialog__body {
padding: 10px 10px 10px 10px;
.base-modal-body {
min-height: 100px;
max-height: 650px;
overflow-y: auto;
padding: 10px;
border: 1px solid #e0e0e0;
}
}
.el-dialog__footer {
padding: 10px;
}
}
</style>
@@ -33,10 +33,12 @@
<el-table-column type="index" width="40" />
<!--受试者-->
<el-table-column :label="$t('download:table:subjectCode')" min-width="130" prop="SubjectCode"
show-overflow-tooltip />
show-overflow-tooltip v-if="isReadingTaskViewInOrder !== 0" />
<!--访视名称-->
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" sortable v-if="IsImageSegment" />
<!--任务名称-->
<el-table-column :label="$t('download:table:taskName')" min-width="130" show-overflow-tooltip prop="TaskBlindName"
sortable />
sortable v-else />
<!--检查类型-->
<el-table-column :label="$t('download:table:studyType')" min-width="130" show-overflow-tooltip prop="IsDicom"
sortable>
@@ -66,7 +68,7 @@
<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')"
<el-button circle icon="el-icon-view" :title="$t('download:button:preview')" :disabled="forbid"
@click.stop="preview(scope.row)" />
<!--下载--->
<el-button circle icon="el-icon-download" :title="$t('download:button:download')"
@@ -75,7 +77,8 @@
</el-table-column>
</el-table>
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :modelList="modelList" :bodyPart="bodyPart"
:IsDicom="IsDicom" :visitTaskId="modelTaskId" />
:subjectVisitId="modelSubjectVisitId" :IsDicom="IsDicom" :isDownload="true" :visitTaskId="modelTaskId"
:IsImageSegment="IsImageSegment" :Criterion="Criterion" :IsReadingTaskViewInOrder="isReadingTaskViewInOrder" />
</el-dialog>
</template>
<script>
@@ -108,6 +111,10 @@ export default {
type: Boolean,
default: false,
},
forbid: {
type: Boolean,
default: false,
},
SubjectId: {
type: String,
default: '',
@@ -126,6 +133,14 @@ export default {
return {}
},
},
IsImageSegment: {
type: Boolean,
default: false,
},
isReadingTaskViewInOrder: {
type: Number,
default: 2,
},
},
data() {
return {
@@ -149,14 +164,17 @@ export default {
open: null,
downloadId: null,
IsReadingTaskViewInOrder: 0, // 阅片规则
bodyPart: [],
bodyPart: {},
modelTaskId: null,
modelSubjectVisitId: null,
}
},
async mounted() {
this.bodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
this.getList()
this.bodyPart = await this.$getBodyPart(this.$route.query.trialId)
this.title = `Download Images${this.SubjectCode}${this.Criterion.TrialReadingCriterionName}`
if (this.IsImageSegment) this.title = `Download Images${this.SubjectCode}`
if (this.isReadingTaskViewInOrder === 0) this.title = ''
},
beforeDestroy() {
store.dispatch('trials/setUnLock', false)
@@ -175,6 +193,12 @@ export default {
if (this.TaskId) {
this.searchData.VisitTaskId = this.TaskId
}
if (this.IsImageSegment) {
this.searchData.IsImageSegmentLabel = true
}
else if (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20) {
this.searchData.IsImageSegmentLabel = false
}
this.loading = true
let res = await getSubjectImageDownloadSelectList(this.searchData)
this.loading = false
@@ -257,6 +281,12 @@ export default {
data.NoneDicomStudyIdList = [...data.NoneDicomStudyIdList, ...arr]
}
}
if (this.IsImageSegment) {
data.IsImageSegmentLabel = true
}
else if (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20) {
data.IsImageSegmentLabel = false
}
this.btnLoading = true
let res = await getIRReadingDownloadStudyInfo(data)
this.btnLoading = false
@@ -286,13 +316,18 @@ export default {
formatDownloadFile(list) {
let files = [],
name = `${list[0].SubjectCode}_${new Date().getTime()}.zip`
if (this.IsReadingTaskViewInOrder === 1) {
name = `${list[0].SubjectCode}_${list[0].TaskBlindName}.zip`
}
if (this.IsReadingTaskViewInOrder === 0) {
// name = `${list[0].TaskBlindName}.zip`
name = `${list[0].SubjectCode}_${list[0].TaskBlindName}.zip`
if (this.IsImageSegment) {
name = `${list[0].SubjectCode}.zip`
} else {
if (this.IsReadingTaskViewInOrder === 1) {
name = `${list[0].SubjectCode}_${list[0].TaskBlindName}.zip`
}
if (this.IsReadingTaskViewInOrder === 0) {
// name = `${list[0].TaskBlindName}.zip`
name = `${list[0].SubjectCode}_${list[0].TaskBlindName}.zip`
}
}
list.forEach((data) => {
if (data.StudyList && data.StudyList.length > 0) {
let StudyList = data.StudyList
@@ -304,7 +339,14 @@ export default {
}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
if (this.IsReadingTaskViewInOrder === 0) {
if (this.IsImageSegment) {
obj = {
name: `${data.SubjectCode}/${data.VisitName
}/${this.$fd('IsDicom', true)}/${study.StudyCode
}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
} else if (this.IsReadingTaskViewInOrder === 0) {
obj = {
name: `${data.TaskBlindName}/${this.$fd(
'IsDicom',
@@ -330,7 +372,15 @@ export default {
url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
}
if (this.IsReadingTaskViewInOrder === 0) {
if (this.IsImageSegment) {
obj = {
name: `${data.SubjectCode}/${data.VisitName
}/${this.$fd('IsDicom', true)}/${study.StudyCode
}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
}
} else if (this.IsReadingTaskViewInOrder === 0) {
obj = {
name: `${data.TaskBlindName}/${this.$fd(
'IsDicom',
@@ -360,7 +410,16 @@ export default {
)}/${study.StudyCode}/${item.FileName}`,
url: this.OSSclientConfig.basePath + item.Path,
}
if (this.IsReadingTaskViewInOrder === 0) {
if (this.IsImageSegment) {
obj = {
name: `${data.SubjectCode}/${data.VisitName}/${this.$fd(
'IsDicom',
false
)}/${study.StudyCode}/${item.FileName}`,
url: this.OSSclientConfig.basePath + item.Path,
}
}
else if (this.IsReadingTaskViewInOrder === 0) {
obj = {
name: `${data.TaskBlindName}/${this.$fd(
'IsDicom',
@@ -390,6 +449,12 @@ export default {
},
handleOpenDialog(item) {
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.TaskBlindName}`
if (this.IsImageSegment) {
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.VisitName}`
}
if (this.isReadingTaskViewInOrder === 0) {
this.model_cfg.title = ''
}
if (item.IsDicom) {
this.modelList = item.DicomStudyList
} else {
@@ -399,6 +464,7 @@ export default {
})
}
this.modelTaskId = item.VisitTaskId
this.modelSubjectVisitId = item.SourceSubjectVisitId
this.IsDicom = item.IsDicom
this.model_cfg.visible = true
},
@@ -427,9 +493,16 @@ export default {
}
let trialId = this.$route.query.trialId
var token = getToken()
const routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true`,
})
let routeData = null
if (!this.IsImageSegment && (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20)) {
routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
})
} else {
routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
})
}
this.open = window.open(routeData.href, '_blank')
},
// 预览阅片影像
@@ -440,7 +513,7 @@ export default {
var token = getToken()
let trialId = this.$route.query.trialId
const routeData = this.$router.resolve({
path: `/showvisitdicoms?page=download&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
path: `/showvisitdicoms?page=download&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
})
this.open = window.open(routeData.href, '_blank')
},
+44 -89
View File
@@ -2,36 +2,21 @@
<!--FEEDBACK-->
<div v-if="visible" @click.stop="() => false" class="feedBack-box">
<div class="feedBack-box-modal"></div>
<el-dialog
:visible.sync="visible"
v-dialogDrag
width="800px"
:close-on-click-modal="false"
@close="cancel"
:modal="false"
>
<el-dialog :visible.sync="visible" v-dialogDrag width="800px" :close-on-click-modal="false" @close="cancel"
:modal="false">
<div slot="title">
{{ title }}
</div>
<!-- 项目详情 -->
<div class="trialsBox" v-if="visitTaskId || SubjectVisitId">
<el-form
label-position="right"
:model="form"
:inline="true"
class="trialsForm"
v-if="type === 'detail'"
>
<el-form label-position="right" :model="form" :inline="true" class="trialsForm" v-if="type === 'detail'">
<el-form-item :label="$t('feedBack:trials:code')" style="width: 40%">
<span>{{ form.TrialCode }}</span>
</el-form-item>
<el-form-item :label="$t('feedBack:trials:name')" style="width: 40%">
<span>{{ form.ExperimentName }}</span>
</el-form-item>
<el-form-item
:label="$t('feedBack:trials:siteCode')"
style="width: 40%"
>
<el-form-item :label="$t('feedBack:trials:siteCode')" style="width: 40%">
<span>{{ form.TrialSiteCode }}</span>
</el-form-item>
<el-form-item :label="$t('feedBack:trials:visit')" style="width: 40%">
@@ -39,47 +24,21 @@
</el-form-item>
</el-form>
</div>
<el-form
ref="feedBackForm"
label-position="right"
:model="form"
:rules="rules"
label-width="100px"
>
<el-form ref="feedBackForm" label-position="right" :model="form" :rules="rules" label-width="100px">
<!-- 影像异常tip -->
<p class="tip" v-if="type === 'imgfail'">
<i
class="el-icon-warning-outline"
style="color: #f56c6c; font-size: 24px"
></i>
<i class="el-icon-warning-outline" style="color: #f56c6c; font-size: 24px"></i>
<span>{{ $t('feedBack:imgfail:tip') }}</span>
</p>
<!-- 问题反馈 -->
<el-form-item
:label="$t('feedBack:form:feedBack')"
prop="QuestionType"
v-if="type === 'feedback' && trialId"
>
<el-select
v-model="form.QuestionType"
style="width: 100%"
popper-class="feedBack-select-box"
>
<el-option
v-for="item in QuestionTypeOptions"
:key="item.id"
:label="item.label"
:value="item.value"
>
<el-form-item :label="$t('feedBack:form:feedBack')" prop="QuestionType" v-if="type === 'feedback' && trialId">
<el-select v-model="form.QuestionType" style="width: 100%" popper-class="feedBack-select-box">
<el-option v-for="item in QuestionTypeOptions" :key="item.id" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 问题反馈 -->
<el-form-item
:label="$t('feedBack:form:feedBack')"
prop="QuestionType"
v-if="type === 'detail'"
>
<el-form-item :label="$t('feedBack:form:feedBack')" prop="QuestionType" v-if="type === 'detail'">
<span>{{
QuestionTypeOptions.filter(
(item) => item.value === form.QuestionType
@@ -87,43 +46,22 @@
}}</span>
</el-form-item>
<!-- 问题描述 -->
<el-form-item
:label="$t('feedBack:form:description')"
prop="QuestionDescription"
>
<el-input
v-model="form.QuestionDescription"
type="textarea"
:rows="4"
:maxlength="500"
:disabled="type === 'detail'"
/>
<el-form-item :label="$t('feedBack:form:description')" prop="QuestionDescription">
<el-input v-model="form.QuestionDescription" type="textarea" :rows="4" :maxlength="500"
:disabled="type === 'detail'" />
</el-form-item>
<!-- 截图 -->
<el-form-item :label="$t('feedBack:form:screenshot')" prop="screenshot">
<uploadImage
:path.sync="form.ScreenshotList"
:isUpload.sync="loading"
:trialId="trialId"
:disabled="type === 'detail'"
ref="uploadImage"
/>
<uploadImage :path.sync="form.ScreenshotList" :isUpload.sync="loading" :trialId="trialId"
:disabled="type === 'detail'" ref="uploadImage" />
</el-form-item>
<!-- 反馈时间 -->
<el-form-item
:label="$t('feedBack:form:time')"
prop="screenshot"
v-if="type === 'detail'"
>
<el-form-item :label="$t('feedBack:form:time')" prop="screenshot" v-if="type === 'detail'">
<span>{{ form.CreateTime }}</span>
</el-form-item>
<!-- 状态 -->
<el-form-item
:label="$t('feedBack:form:status')"
prop="screenshot"
v-if="type === 'detail' && level > 7"
>
<el-switch
<el-form-item :label="$t('feedBack:form:status')" prop="screenshot" v-if="type === 'detail' && level >= 7">
<!-- <el-switch
v-model="form.State"
active-color="#13ce66"
inactive-color="#ff4949"
@@ -134,21 +72,27 @@
:disabled="level < 8 || !isStateChange"
@change="changeState"
>
</el-switch>
</el-switch> -->
<el-select v-model="form.State" :popper-append-to-body="false" :disabled="level < 8">
<el-option v-for="item in $d.FeedBackStatus" :key="item.id" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<!-- 无法解决原因 -->
<el-form-item :label="$t('feedBack:form:Reason')" prop="Reason"
v-if="type === 'detail' && level >= 7 && form.State === 2">
<el-input v-model="form.Reason" type="textarea" :rows="4" :maxlength="500" :disabled="level < 8" />
</el-form-item>
</el-form>
<div slot="footer" v-if="type !== 'detail' || isImgfail">
<!--type !== 'detail'-->
<div slot="footer" v-if="level >= 7 || isImgfail">
<!-- 取消 -->
<el-button size="small" @click.stop="cancel">
<el-button size="small" @click.stop="cancel" v-if="type !== 'detail' || level >= 8">
{{ $t('feedBack:button:cancel') }}
</el-button>
<!-- 保存 -->
<el-button
type="primary"
size="small"
@click.stop="save"
:loading="loading"
>
<el-button type="primary" size="small" @click.stop="save" :loading="loading"
v-if="type !== 'detail' || level >= 8">
{{ $t('feedBack:button:save') }}
</el-button>
</div>
@@ -190,6 +134,7 @@ export default {
SubjectVisitId: null,
ScreenshotList: [],
ScreenshotListStr: null,
Reason: null
},
rules: {
QuestionType: [
@@ -283,6 +228,7 @@ export default {
}
if (this.visitTaskId) {
this.form.VisitTaskId = this.visitTaskId
this.form.QuestionType = 6
}
if (this.SubjectVisitId) {
this.form.SubjectVisitId = this.SubjectVisitId
@@ -306,6 +252,7 @@ export default {
// 修改状态
async changeState() {
if (this.isImgfail) return
if (this.form.State !== 1 && this.form.State !== 0) return false
try {
let data = {
IdList: [this.Id],
@@ -380,6 +327,10 @@ export default {
}
</script>
<style lang="scss" scoped>
::v-deep.el-popper {
z-index: 4000 !important;
}
.tip {
width: 86%;
margin: auto;
@@ -388,12 +339,14 @@ export default {
padding: 0 10px;
display: flex;
align-items: center;
// border-radius: 5px;
// background-color: #eee;
i {
margin-right: 5px;
}
}
.trialsBox {
margin: auto;
margin-bottom: 20px;
@@ -404,11 +357,13 @@ export default {
border-radius: 5px;
background-color: #eee;
}
.trialsForm {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
.el-form-item {
margin-bottom: 10px;
}
+243
View File
@@ -0,0 +1,243 @@
<template>
<div :id="key" class="readingChart" v-show="visible" :style="{
'z-index': zIndex
}">
<div ref="chartContainer" style="width: 490px; height: 290px;" v-loading="loading"></div>
</div>
</template>
<script>
import { getReportsChartData } from "@/api/reading"
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
LegendComponent,
DatasetComponent,
// (filter, sort)
TransformComponent
} from 'echarts/components';
//
import { LabelLayout, UniversalTransition } from 'echarts/features';
// Canvas CanvasRenderer SVGRenderer
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
DataZoomComponent,
LegendComponent,
LineChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
// let echarts = require('echarts/lib/echarts');
//
// require('echarts/lib/chart/bar');
// require('echarts/lib/chart/line');
// require('echarts/lib/chart/pie');
// require('echarts/lib/chart/scatter');
//
// require('echarts/lib/component/tooltip');
// require('echarts/lib/component/title');
// require('echarts/lib/component/legend');
// require('echarts/lib/component/grid');
// require('echarts/lib/component/dataZoom');
export default {
name: "readingChart",
props: {
},
data() {
return {
visible: false,
zIndex: 9,
chart: null,
loading: false,
key: 'readingChart',
isInteger: false
};
},
methods: {
init(event, obj, zIndex = 9) {
this.loading = true
this.zIndex = zIndex
let { key } = obj
if (key) {
this.key = key
}
this.$nextTick(() => {
this.visible = true
let readingChart = document.querySelector(`#${this.key}`);
let chaY = document.body.clientHeight - event.clientY;
let chaX = document.body.clientWidth - event.clientX;
if (chaY < 250) {
readingChart.style.top = event.clientY - 220 + "px";
} else {
readingChart.style.top = event.clientY + "px";
}
if (chaX < 500) {
readingChart.style.left = event.clientX - 520 + "px";
} else {
readingChart.style.left = event.clientX + 15 + "px";
}
this.getInfo(obj)
})
},
async getInfo(data) {
try {
let { VisitTaskId = null, TrialId = null, QuestionId = null, QuestionName = null, TableQuestionId = null, RowIndex = null, ReportChartTypeEnum = null } = data
let params = {
VisitTaskId, TrialId, QuestionId, TableQuestionId, RowIndex, ReportChartTypeEnum
}
this.loading = true
let res = await getReportsChartData(params)
this.loading = false
if (res.IsSuccess) {
this.isInteger = res.Result.Type === 'number' && res.Result.ValueType === 0
let LatestScanDateList = res.Result.LatestScanDateList.map(item => item.split(" ")[0])
let obj = {
title: QuestionName,
xAxisData: LatestScanDateList || [],
series: [],
unit: res.Result.Unit === 0 ? '' : res.Result.Unit === 4 ? res.Result.CustomUnit : this.$fd("ValueUnit", res.Result.Unit),
visitName: res.Result.VisitTaskNameList,
min: null,
max: null
}
res.Result.ChartDataList.forEach((item) => {
let arr = []
item.Value.forEach((d, index) => {
// arr.push([LatestScanDateList[index], d])
arr.push(d)
})
obj.series.push({
name: item.Name,
data: arr,
type: 'line'
})
});
this.initChart(obj)
}
} catch (err) {
this.loading = false
console.log(err)
}
},
foo() {
this.visible = false
this.$emit("foo");
this.dispose()
},
initChart(obj) {
this.chart = echarts.init(this.$refs.chartContainer);
// ...
const option = {
title: {
text: obj.title,
textStyle: {
color: "#fff"
},
left: 0,
top: 0
},
grid: {
left: 50,
bottom: 30
},
tooltip: {
trigger: 'axis',
// formatter: function (params) {
// let index = obj.xAxisData.findIndex(item => item === params[0].value[0])
// let result = obj.visitName[index] + ' ' + params[0].value[0] + '<br>'; //
// params.forEach(function (item) {
// result += item.marker + ' ' + item.seriesName + ': ' + item.value[1] + '<br>'; //
// });
// return result;
// }
},
xAxis: {
// type: 'time',
// data: obj.xAxisData,
data: obj.visitName,
axisLine: { // x 线
lineStyle: {
color: '#fff',
}
},
axisLabel: { // x
textStyle: {
color: '#fff'
}
},
// splitLine: {
// show: false // 线
// },
// min: obj.min,
// max: obj.max
},
yAxis: {
name: obj.unit,
type: 'value',
axisLabel: {
textStyle: {
color: '#fff',
}
},
axisLine: {
show: true,
lineStyle: {
color: '#fff',
}
},
},
series: obj.series
};
if (this.isInteger) {
option.yAxis.minInterval = 1
}
// 4. 使
this.chart.setOption(option);
},
resize() {
if (this.chart) {
this.chart.resize()
}
},
dispose() {
if (this.chart) {
this.chart.dispose()
this.chart = null
}
}
},
};
</script>
<style lang="scss" scoped>
.readingChart {
min-width: 500px;
max-width: 500px;
font-size: 14px;
display: inline-block;
background: #000;
border: 1px solid #ebeef5;
border-radius: 4px;
position: fixed;
padding: 10px 6px;
list-style-type: none;
min-height: 300px;
max-height: 80vh;
// overflow: hidden;
// overflow-y: auto;
box-sizing: border-box;
}
</style>
+134
View File
@@ -0,0 +1,134 @@
<template>
<div id="timeTag" :style="`color:${suggestionTextColor};background-color: inherit;`">{{ time }}</div>
</template>
<script>
import moment from 'moment'
export default {
name: "timeTag",
data() {
return {
time: '',
timer: null,
suggestionTextColor: '#909399',
resizeObserver: null
}
},
created() {
this.getTime()
},
async mounted() {
this.resizeObserver = new ResizeObserver(entries => {
entries.forEach(entry => {
//
// const { width, height } = entry.contentRect;
// console.log(`${width}px, ${height}px`);
// data
// this.elementWidth = width;
// this.elementHeight = height;
this.dragDoc()
});
});
const body = document.getElementsByTagName('body')[0]
//
this.resizeObserver.observe(body);
this.dragDoc()
this.setColor()
},
methods: {
getTime() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.timer = setInterval(async () => {
this.time = moment(new Date()).format('YYYY-MM-DD HH:mm:ss Z z')
}, 1000)
},
dragDoc() {
const box = document.querySelector('#timeTag')
const body = document.getElementsByTagName('body')[0]
let maxLeft = body.offsetWidth - box.offsetWidth
let maxTop = body.offsetHeight - box.offsetHeight - 30
box.style.cssText += `left:${maxLeft}px;top:7px;`
const sty = (function () {
if (window.document.currentStyle) {
return (dom, attr) => dom.currentStyle[attr]
} else {
return (dom, attr) => getComputedStyle(dom, false)[attr]
}
})()
box.onmousedown = (e) => {
//
const disX = e.clientX - box.offsetLeft
const disY = e.clientY - box.offsetTop
// px
let styL = sty(box, 'left')
let styT = sty(box, 'top')
// ie 50% px
if (styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
} else {
styL = +styL.replace(/\px/g, '')
styT = +styT.replace(/\px/g, '')
}
const oldMousemove = document.onmousemove
document.onmousemove = function (e) {
oldMousemove(e)
//
let left = e.clientX - disX
let top = e.clientY - disY
if (left < 0) {
left = 0
}
if (left > maxLeft) {
left = maxLeft
}
if (top < 0) {
top = 0
}
if (top > maxTop) {
top = maxTop
}
//
box.style.cssText += `;left:${left}px;top:${top}px;`
}
document.onmouseup = function (e) {
document.onmousemove = oldMousemove
document.onmouseup = null
}
}
},
setColor() {
this.suggestionTextColor = "#909399"
let pathList = ['/showvisitdicoms', '/showdicom', '/readingDicoms', '/petct', '/noneDicomReading']
if (pathList.includes(window.location.pathname)) {
this.suggestionTextColor = "#fff"
}
}
},
destroyed() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
}
}
</script>
<style lang="scss" scoped>
#timeTag {
position: fixed;
z-index: 99999;
cursor: move;
width: 195px;
font-size: 14px;
}
</style>
+1 -1
View File
@@ -116,7 +116,7 @@ export default {
display: none !important; /* 隐藏原生 radio 输入,但仍然允许交互 */
}
::v-deep.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled)
::v-deep .el-radio:focus:not(.is-focus):not(:active):not(.is-disabled)
.el-radio__inner {
box-shadow: none !important;
}
@@ -10,9 +10,12 @@
<!--检查列表-->
<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')" sortable
v-if="isReadingTaskViewInOrder !== 0" />
<!--访视名称-->
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" v-if="IsImageSegment" sortable />
<!--任务名称-->
<el-table-column prop="TaskBlindName" :label="$t('upload:dicom:table:taskBlindName')" />
<el-table-column prop="TaskBlindName" :label="$t('upload:dicom:table:taskBlindName')" v-else sortable />
<!--原始检查数-->
<el-table-column prop="OrginalStudyList" :label="$t('upload:dicom:table:orginalStudyListNum')">
<template slot-scope="scope">
@@ -40,7 +43,7 @@
<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" v-if="!forbid">
<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"
@@ -67,17 +70,14 @@
</el-table>
<div style="margin: 10px 0" class="top">
<span>{{ $t('upload:dicom:uploadTitle') }}</span>
<div class="btnBox">
<span style="margin-right: 10px">
{{ $store.state.trials.uploadTip }}
</span>
<div class="btnBox" v-if="!forbid">
<span style="margin-right: 10px">{{ $store.state.trials.uploadTip }}</span>
<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">
{{ $t('upload:dicom:button:batchUpload') }}
</el-button>
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title=""
<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)" />
</div>
</div>
@@ -92,8 +92,10 @@
<template slot="header">
<el-tooltip placement="top">
<div slot="content">
{{ $t('trials:uploadDicomList:table:studyDetail1') }}<br />
{{ $t('trials:uploadDicomList:table:studyDetail2') }}<br />
{{ $t('trials:uploadDicomList:table:studyDetail1') }}
<br />
{{ $t('trials:uploadDicomList:table:studyDetail2') }}
<br />
{{ $t('trials:uploadedDicoms:table:studyDate') }}
</div>
<span>{{ $t('trials:uploadDicomList:table:studyInfo') }}</span>
@@ -103,13 +105,15 @@
<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>
<span v-if="scope.row.dicomInfo.modality.length > 0">{{ scope.row.dicomInfo.modality.join('')
}},</span>
<span v-else style="color: #f44336">N/A,</span>
</div>
<div style="display: inline-block; margin-right: 2px">
@@ -124,20 +128,15 @@
<div>
<div style="display: inline-block; margin-right: 2px">
<span v-if="scope.row.dicomInfo.bodyPart">
{{ scope.row.dicomInfo.bodyPart }},
</span>
<span v-else style="color: #f44336">N/A, </span>
<span v-if="scope.row.dicomInfo.bodyPart">{{ scope.row.dicomInfo.bodyPart }},</span>
<span v-else style="color: #f44336">N/A,</span>
</div>
<div style="display: inline-block">
<span v-if="scope.row.dicomInfo.description">
{{ scope.row.dicomInfo.description }}</span>
<span v-if="scope.row.dicomInfo.description">{{ scope.row.dicomInfo.description }}</span>
<span v-else style="color: #f44336">N/A</span>
</div>
</div>
<div>
{{ scope.row.dicomInfo.studyTime }}
</div>
<div>{{ scope.row.dicomInfo.studyTime }}</div>
</div>
</template>
</el-table-column>
@@ -145,8 +144,10 @@
<template slot="header">
<el-tooltip placement="top">
<div slot="content">
{{ $t('trials:uploadDicomList:table:pId') }}<br />
{{ $t('trials:uploadDicomList:table:patientName') }}<br />
{{ $t('trials:uploadDicomList:table:pId') }}
<br />
{{ $t('trials:uploadDicomList:table:patientName') }}
<br />
{{ $t('trials:uploadDicomList:table:pInfo') }}
</div>
<span>{{ $t('trials:uploadDicomList:table:patientInfo') }}</span>
@@ -155,8 +156,11 @@
<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>
@@ -225,8 +229,7 @@
<span v-if="
!scope.row.dicomInfo.failedFileCount &&
!scope.row.dicomInfo.isInit
">
{{ $t('trials:uploadDicomList:table:status1') }}</span>
">{{ $t('trials:uploadDicomList:table:status1') }}</span>
<span style="color: #409eff" v-else-if="
!scope.row.dicomInfo.failedFileCount &&
scope.row.dicomInfo.isInit &&
@@ -244,9 +247,11 @@
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>
<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>
@@ -257,49 +262,51 @@
{{ $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">
{{ item }}
</div>
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">
{{ item }}
</div>
style="font-size: 12px; color: #24b837">{{ item }}</div>
</div>
<div v-else>&nbsp;</div>
<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">
{{ item }}
</div>
style="font-size: 12px; color: #f66">{{ item }}</div>
</div>
<div v-else>&nbsp;</div>
</div>
</div>
<el-button size="mini" style="cursor: pointer">
<span style="font-size: 12px; color: #baa72a">{{
scope.row.uploadState.record.Existed.length
}}</span>
<span style="font-size: 12px; color: #baa72a">
{{
scope.row.uploadState.record.Existed.length
}}
</span>
/
<span style="font-size: 12px; color: #24b837">{{
scope.row.uploadState.record.Uploaded.length
}}</span>
<span style="font-size: 12px; color: #24b837">
{{
scope.row.uploadState.record.Uploaded.length
}}
</span>
/
<span style="font-size: 12px; color: #f66">{{
scope.row.uploadState.record.Failed.length
}}</span>
<span style="font-size: 12px; color: #f66">
{{
scope.row.uploadState.record.Failed.length
}}
</span>
</el-button>
</el-tooltip>
</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" />
:subjectVisitId="openSubjectVisitId" :modelList="modelList" :isUpload="openIsUpload"
:visitTaskId="openVisitTaskId" :TrialModality="TrialModality" :IsReadingTaskViewInOrder="IsReadingTaskViewInOrder"
@getList="getList" />
</div>
</template>
<script>
@@ -332,6 +339,7 @@ cornerstoneWADOImageLoader.external.cornerstone = cornerstone
import { convertBytes } from '@/utils/dicom-character-set'
import { parseDicom } from '@/utils/parseDicom.js'
import { dcmUpload } from '@/utils/dcmUpload/dcmUpload'
import dcmjs from '@/utils/dcmUpload/dcmjs'
import store from '@/store'
import { getToken } from '@/utils/auth'
export default {
@@ -351,6 +359,10 @@ export default {
return {}
},
},
forbid: {
type: Boolean,
default: false,
},
TaskId: {
type: String,
default: '',
@@ -363,12 +375,17 @@ export default {
type: Number,
default: 0,
},
IsImageSegment: {
type: Boolean,
default: false,
},
},
components: {
'study-view': studyView,
},
data() {
return {
loading: false,
list: [],
StudyInstanceUidList: [],
SopInstanceUidList: [],
@@ -406,17 +423,18 @@ export default {
subjectVisitId: null,
errStudyUidList: [],
open: null,
bodyPart: [],
bodyPart: {},
openIsUpload: false,
openSubjectVisitId: null,
openVisitTaskId: null,
TrialModality: [],
IsReadingTaskViewInOrder: 2
}
},
created() {
this.getList()
},
async mounted() {
this.trialId = this.$route.query.trialId
this.bodyPart = await this.$getBodyPart(this.$route.query.trialId)
this.bodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
this.getList()
this.uploadQueues = []
this.OSSclient.close()
},
@@ -441,11 +459,20 @@ export default {
if (this.TaskId) {
params.VisitTaskId = this.TaskId
}
if (this.IsImageSegment) {
params.IsImageSegmentLabel = true
} else if (
this.Criterion.CriterionType == 19 ||
this.Criterion.CriterionType == 20
) {
params.IsImageSegmentLabel = false
}
this.loading = true
let res = await getSubjectImageUploadList(params)
this.loading = false
if (res.IsSuccess) {
this.TrialModality = res.OtherInfo.TrialModality.split('|')
this.IsReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder || res.OtherInfo.IsReadingTaskViewInOrder === 0 ? res.OtherInfo.IsReadingTaskViewInOrder : 2
this.StudyInstanceUidList = []
this.SopInstanceUidList = []
this.UploadStudyList = []
@@ -456,7 +483,7 @@ export default {
data.SubjectId = item.SubejctId
data.VisitTaskId = item.VisitTaskId
data.SourceSubjectVisitId = item.SourceSubjectVisitId
this.subjectVisitId = item.SourceSubjectVisitId
// this.subjectVisitId = item.SourceSubjectVisitId
this.StudyInstanceUidList.push(data)
})
}
@@ -490,6 +517,7 @@ export default {
if (confirm !== 'confirm') return
let params = {
VisitTaskId: item.VisitTaskId,
SubjectVisitId: item.SourceSubjectVisitId || item.SubjectVisitId,
IsDicom: true,
}
let res = await deleteTaskStudy(params)
@@ -522,7 +550,11 @@ export default {
//
handleOpenDialog(item, list, isUpload = false) {
this.openIsUpload = isUpload
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.TaskBlindName}`
this.openSubjectVisitId = item.SubjectVisitId || item.SourceSubjectVisitId
this.openVisitTaskId = item.VisitTaskId
this.model_cfg.title = `${item.SubjectCode || ''} > ${this.IsImageSegment ? item.VisitName : item.TaskBlindName
}`
if (this.isReadingTaskViewInOrder === 0) this.model_cfg.title = ''
this.modelList = item[list]
this.model_cfg.visible = true
},
@@ -538,6 +570,9 @@ export default {
if (this.VisitTaskId) {
data.VisitTaskId = this.VisitTaskId
}
if (this.IsImageSegment) {
data.IsImageSegmentLabel = true
}
let res = await verifyIRStudyAllowUpload(data)
if (res.IsSuccess) {
return res.Result
@@ -564,8 +599,9 @@ export default {
confirmMessage = null
for (let i = 0; i < checkFiles.length; i++) {
let item = checkFiles[i]
var dicom = await parseDicom(item, 'StudyInstanceUid')
var dicom = await parseDicom(item, ['StudyInstanceUid', 'Modality'])
if (!dicom.StudyInstanceUid) continue
if (this.IsImageSegment && dicom.Modality !== 'IVUS') continue
let has = true,
has2 = false,
has3 = false
@@ -619,8 +655,11 @@ export default {
if (this.errStudyUidList && this.errStudyUidList.length > 0) {
for (let i = 0; i < checkFiles.length; i++) {
let item = checkFiles[i]
var dicom = await parseDicom(item, 'StudyInstanceUid')
if (!!~this.errStudyUidList.indexOf(dicom.StudyInstanceUid)) {
var dicom = await parseDicom(item, ['StudyInstanceUid', 'Modality'])
if (
!!~this.errStudyUidList.indexOf(dicom.StudyInstanceUid) ||
(this.IsImageSegment && dicom.Modality !== 'IVUS')
) {
this.hasOtherStudy = true
checkFiles.splice(i, 1)
i--
@@ -687,12 +726,13 @@ export default {
var studyUid = data.string('x0020000d')
if (!studyUid) return resolve()
var pixelDataElement = data.elements.x7fe00010
if (!pixelDataElement && modality !== 'SR') return resolve()
if (!pixelDataElement && modality !== 'SR' && modality !== 'ECG')
return resolve()
var studyIndex = 0
while (
studyIndex < scope.uploadQueues.length &&
scope.uploadQueues[studyIndex].dicomInfo.studyUid !== studyUid &&
(pixelDataElement || modality === 'SR') &&
(pixelDataElement || modality === 'SR' || modality === 'ECG') &&
modality != ''
) {
++studyIndex
@@ -732,6 +772,13 @@ export default {
fileList: [],
dicomInfo: {
studyId: data.string('x00200010'),
Manufacturer: data.string('x00080070') || '',
ManufacturerModelName: data.string('x000801090') || '',
DeviceSerialNumber: data.string('x00181000') || '',
DeviceUID: data.string('x00181002') || '',
SoftwareVersions: data.string('x00181020') || '',
PatientWeight: data.string('x00101030') || '',
DicomStudyDate: data.string('x00080020'),
DicomStudyTime: data.string('x00080030'),
studyUid: studyUid,
@@ -777,6 +824,39 @@ export default {
},
})
}
if (
!scope.uploadQueues[studyIndex].dicomInfo.RadionuclideTotalDose
) {
let dataset = dcmjs.data.DicomMessage.readFile(e.target.result)
if (
dataset.dict['00540016'] &&
dataset.dict['00540016'].Value &&
dataset.dict['00540016'].Value[0]
) {
let RadionuclideTotalDose = dataset.dict['00540016'].Value[0][
'00181074'
]
? dataset.dict['00540016'].Value[0]['00181074'].Value[0]
: null
let RadionuclideHalfLife = dataset.dict['00540016'].Value[0][
'00181075'
]
? dataset.dict['00540016'].Value[0]['00181075'].Value[0]
: null
let RadiopharmaceuticalStartTime = dataset.dict['00540016']
.Value[0]['00181072']
? dataset.dict['00540016'].Value[0]['00181072'].Value[0]
: null
scope.uploadQueues[studyIndex].dicomInfo.RadionuclideTotalDose =
RadionuclideTotalDose
scope.uploadQueues[studyIndex].dicomInfo.RadionuclideHalfLife =
RadionuclideHalfLife
scope.uploadQueues[
studyIndex
].dicomInfo.RadiopharmaceuticalStartTime =
RadiopharmaceuticalStartTime
}
}
var modality = scope.uploadQueues[studyIndex].dicomInfo.modality
var currentModality = data.string('x00080060')
if (!(modality.indexOf(currentModality) > -1)) {
@@ -844,6 +924,10 @@ export default {
)
seriesItem = {
seriesUid: seriesUid,
RadiopharmaceuticalInformationSequence:
data.string('x00540016') || '',
AcquisitionDate: data.string('x00080022') || '',
DicomSeriesDate: data.string('x00080021'),
DicomSeriesTime: data.string('x00080031'),
seriesNumber: data.intString('x00200011') || 1,
@@ -884,6 +968,20 @@ export default {
instanceTime = time ? `${date} ${time}` : `${date} 00:00:00`
}
instanceItem = {
PhotometricInterpretation: data.string('x00280004') || '',
BitsAllocated: data.uint16('x00280100') || '',
PixelRepresentation: data.uint16('x00280103') || '',
RescaleIntercept: data.string('x00281052') || '',
RescaleSlope: data.string('x00281053') || '',
ImagePositionPatient: data.string('x00200032') || '',
ImageOrientationPatient: data.string('x00200037') || '',
SequenceOfUltrasoundRegions: data.string('x00186011') || '',
FrameTime: data.string('x00181063') || '',
CorrectedImage: data.string('x00280051') || '',
Units: data.string('x00541001') || '',
DecayCorrection: data.string('x00541102') || '',
EncapsulatedDocument: data.string('x00420011') || '',
instanceUid: instanceUid,
SOPClassUID: data.string('x00080016'),
TransferSytaxUID: data.string('x00020010'),
@@ -1036,10 +1134,29 @@ export default {
var scope = this
return new Promise(function (resolve, reject) {
try {
let subjectVisitId = null
let dicomInfo = {}
if (scope.VisitTaskId) {
scope.StudyInstanceUidList.forEach((item) => {
if (item.VisitTaskId === scope.VisitTaskId) {
subjectVisitId = item.SourceSubjectVisitId
}
})
} else {
scope.StudyInstanceUidList.forEach((item) => {
if (
item.StudyInstanceUid ===
scope.uploadQueues[index].dicomInfo.studyUid
) {
subjectVisitId = item.SourceSubjectVisitId
}
})
}
if (!subjectVisitId) return reject('subjectVisitId is notFind')
preArchiveDicomStudy({
trialId: scope.trialId,
subjectId: scope.SubjectId,
subjectVisitId: scope.subjectVisitId,
subjectVisitId: subjectVisitId,
fileSize: scope.uploadQueues[index].dicomInfo.fileSize,
fileCount: scope.uploadQueues[index].dicomInfo.fileCount,
IsDicomReUpload:
@@ -1048,14 +1165,14 @@ export default {
.then(async (res) => {
scope.uploadQueues[index].dicomInfo.failedFileCount = 0
scope.$set(scope.uploadQueues[index].dicomInfo, 'isInit', true)
let dicomInfo = scope.uploadQueues[index].dicomInfo
dicomInfo = scope.uploadQueues[index].dicomInfo
let seriesNum = scope.uploadQueues[index].seriesList.length
let fileNum = scope.uploadQueues[index].fileList.length
let seriesList = scope.uploadQueues[index].seriesList
dicomInfo.seriesNum = seriesNum
dicomInfo.fileNum = fileNum
dicomInfo.subjectId = scope.SubjectId
dicomInfo.subjectVisitId = scope.subjectVisitId
dicomInfo.subjectVisitId = subjectVisitId
let t = setInterval(() => {
dicomUploadInProgress({
trialId: scope.trialId,
@@ -1075,11 +1192,16 @@ export default {
let params = {
trialId: scope.trialId,
subjectId: scope.SubjectId,
subjectVisitId: scope.subjectVisitId,
subjectVisitId: subjectVisitId,
studyMonitorId: res.Result,
failedFileCount: 0,
RecordPath: null,
study: {
RadionuclideTotalDose: dicomInfo.RadionuclideTotalDose,
RadionuclideHalfLife: dicomInfo.RadionuclideHalfLife,
RadiopharmaceuticalStartTime:
dicomInfo.RadiopharmaceuticalStartTime,
studyId: dicomInfo.studyId,
studyInstanceUid: dicomInfo.studyUid,
studyTime: dicomInfo.studyTime,
@@ -1089,8 +1211,8 @@ export default {
institutionName: dicomInfo.institutionName,
patientId: dicomInfo.patientId,
patientName: '',
patientAge: '',
patientSex: dicomInfo.patientSex,
patientAge: dicomInfo.patientAge,
patientSex: config?.DicomStoreInfo.SubjectSex || dicomInfo.patientSex,
accessionNumber: dicomInfo.accNumber,
patientBirthDate: '',
acquisitionTime: dicomInfo.acquisitionTime,
@@ -1100,9 +1222,17 @@ export default {
DicomStudyDate: dicomInfo.DicomStudyDate,
DicomStudyTime: dicomInfo.DicomStudyTime,
seriesList: [],
Manufacturer: dicomInfo.Manufacturer,
ManufacturerModelName: dicomInfo.ManufacturerModelName,
DeviceSerialNumber: dicomInfo.DeviceSerialNumber,
DeviceUID: dicomInfo.DeviceUID,
SoftwareVersions: dicomInfo.SoftwareVersions,
PatientWeight: dicomInfo.PatientWeight,
},
}
let arr = []
let uploadBatchId = scope.$guid()
for (let i = 0; i < seriesList.length; i++) {
let v = seriesList[i]
let instanceList = []
@@ -1125,8 +1255,10 @@ export default {
seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID:
o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID:
o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime,
@@ -1142,6 +1274,23 @@ export default {
windowWidth: o.windowWidth,
path: o.myPath,
FileSize: o.FileSize,
PhotometricInterpretation:
o.PhotometricInterpretation,
BitsAllocated: o.BitsAllocated,
PixelRepresentation: o.PixelRepresentation,
RescaleIntercept: o.RescaleIntercept,
RescaleSlope: o.RescaleSlope,
ImagePositionPatient: o.ImagePositionPatient,
ImageOrientationPatient:
o.ImageOrientationPatient,
SequenceOfUltrasoundRegions:
o.SequenceOfUltrasoundRegions,
FrameTime: o.FrameTime,
CorrectedImage: o.CorrectedImage,
Units: o.Units,
DecayCorrection: o.DecayCorrection,
EncapsulatedDocument: o.EncapsulatedDocument,
})
Record.Uploaded.push(name)
dicomInfo.failedFileCount++
@@ -1155,6 +1304,16 @@ export default {
o.instanceUid +
params.trialId
)}`
if (scope.IsImageSegment) {
path = `/${params.trialId}/Image/${params.subjectId
}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId
}/${scope.getGuid(
dicomInfo.studyUid +
v.seriesUid +
o.instanceUid +
params.trialId
)}`
}
if (scope.isClose) return
let res = await dcmUpload(
{
@@ -1171,6 +1330,16 @@ export default {
) {
dicomInfo.uploadFileSize = dicomInfo.fileSize
}
},
{
fileName: o.file.name,
fileSize: o.file.size,
fileType: 'application/dicom',
uploadBatchId: uploadBatchId,
batchDataType: 5,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId,
}
)
if (!res || !res.url) {
@@ -1188,10 +1357,23 @@ export default {
o.imageRows
)
let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
if (scope.IsImageSegment) {
thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
}
let OSSclient = scope.OSSclient
let seriesRes = await OSSclient.put(
thumbnailPath,
blob
blob,
{
fileName: `${v.seriesUid}.jpg`,
fileSize: blob.size,
fileType: 'image/jpeg',
uploadBatchId: uploadBatchId,
batchDataType: 6,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId,
}
)
if (seriesRes && seriesRes.url) {
ImageResizePath = scope.$getObjectName(
@@ -1210,8 +1392,10 @@ export default {
sopInstanceUid: o.instanceUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID:
o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID:
o.MediaStorageSOPClassUID,
instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime,
imageRows: o.imageRows,
@@ -1226,6 +1410,23 @@ export default {
windowWidth: o.windowWidth,
path: scope.$getObjectName(res.url),
FileSize: o.FileSize,
PhotometricInterpretation:
o.PhotometricInterpretation,
BitsAllocated: o.BitsAllocated,
PixelRepresentation: o.PixelRepresentation,
RescaleIntercept: o.RescaleIntercept,
RescaleSlope: o.RescaleSlope,
ImagePositionPatient: o.ImagePositionPatient,
ImageOrientationPatient:
o.ImageOrientationPatient,
SequenceOfUltrasoundRegions:
o.SequenceOfUltrasoundRegions,
FrameTime: o.FrameTime,
CorrectedImage: o.CorrectedImage,
Units: o.Units,
DecayCorrection: o.DecayCorrection,
EncapsulatedDocument: o.EncapsulatedDocument,
})
o.myPath = scope.$getObjectName(res.url)
Record.Uploaded.push(name)
@@ -1274,11 +1475,18 @@ export default {
bodyPartExamined: dicomInfo.bodyPart,
instanceList: instanceList,
ImageResizePath: ImageResizePath,
RadiopharmaceuticalInformationSequence:
v.RadiopharmaceuticalInformationSequence,
AcquisitionDate: v.AcquisitionDate,
})
}
let text = JSON.stringify(Record)
let logJsonBlob = scope.generateTxtFile(text)
let logJsonObjectName = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${params.studyMonitorId}.txt`
if (scope.IsImageSegment) {
logJsonObjectName = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${params.studyMonitorId}.txt`
}
let logRes
try {
logRes = await scope.OSSclient.put(
@@ -1307,9 +1515,21 @@ export default {
v.instanceList[0].imageRows
)
let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
if (scope.IsImageSegment) {
thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
}
let OSSclient = scope.OSSclient
try {
let seriesRes = await OSSclient.put(thumbnailPath, blob)
let seriesRes = await OSSclient.put(thumbnailPath, blob, {
fileName: `${v.seriesUid}.jpg`,
fileSize: blob.size,
fileType: 'image/jpeg',
uploadBatchId: uploadBatchId,
batchDataType: 6,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId,
})
if (seriesRes && seriesRes.url) {
o.ImageResizePath = scope.$getObjectName(seriesRes.url)
}
@@ -1324,6 +1544,10 @@ export default {
if (scope.isClose) return false
console.log(params)
params.VisitTaskId = dicomInfo.visitTaskId
if (scope.IsImageSegment) {
params.IsImageSegmentLabel = true
}
params.UploadBatchId = uploadBatchId
addOrUpdateArchiveTaskStudy(params)
.then((res) => {
if (dicomInfo.failedFileCount === dicomInfo.fileCount) {
@@ -1418,7 +1642,9 @@ export default {
var token = getToken()
let trialId = this.$route.query.trialId
const routeData = this.$router.resolve({
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${this.IsImageSegment ? 'undefined' : row.VisitTaskId
}&subjectVisitId=${row.SourceSubjectVisitId
}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
})
this.open = window.open(routeData.href, '_blank')
},
@@ -1,40 +1,17 @@
<template>
<el-dialog
:visible.sync="visible"
:fullscreen="true"
:close-on-click-modal="false"
:before-close="beforeClose"
:append-to-body="true"
class="uploadDicomAndNonedicom"
>
<el-dialog :visible.sync="visible" :fullscreen="true" :close-on-click-modal="false" :before-close="beforeClose"
:append-to-body="true" class="uploadDicomAndNonedicom">
<span slot="title">{{ title }}</span>
<el-tabs type="border-card" v-model="activeName">
<el-tab-pane
:label="$t('uploadDicomAndNonedicom:label:dicom')"
name="dicom"
>
<dicomFile
v-if="activeName === 'dicom'"
:SubjectId="SubjectId"
:SubjectCode="SubjectCode"
:Criterion="Criterion"
:TaskId="VisitTaskId"
:isUpload.sync="isUpload"
:isReadingTaskViewInOrder="isReadingTaskViewInOrder"
/>
<el-tab-pane :label="$t('uploadDicomAndNonedicom:label:dicom')" name="dicom">
<dicomFile v-if="activeName === 'dicom'" :SubjectId="SubjectId" :SubjectCode="SubjectCode"
:Criterion="Criterion" :TaskId="VisitTaskId" :isUpload.sync="isUpload"
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :IsImageSegment="IsImageSegment" :forbid="forbid" />
</el-tab-pane>
<el-tab-pane
:label="$t('uploadDicomAndNonedicom:label:nonedicom')"
name="nonedicom"
>
<nonedicomFile
v-if="activeName === 'nonedicom'"
:SubjectId="SubjectId"
:SubjectCode="SubjectCode"
:Criterion="Criterion"
:VisitTaskId="VisitTaskId"
:isUpload.sync="isUpload"
/>
<el-tab-pane :label="$t('uploadDicomAndNonedicom:label:nonedicom')" name="nonedicom">
<nonedicomFile v-if="activeName === 'nonedicom'" :SubjectId="SubjectId" :SubjectCode="SubjectCode"
:Criterion="Criterion" :VisitTaskId="VisitTaskId" :isUpload.sync="isUpload" :IsImageSegment="IsImageSegment"
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :forbid="forbid" />
</el-tab-pane>
</el-tabs>
</el-dialog>
@@ -52,6 +29,10 @@ export default {
type: Boolean,
default: false,
},
forbid: {
type: Boolean,
default: false,
},
SubjectId: {
type: String,
default: '',
@@ -74,6 +55,10 @@ export default {
type: Number,
default: 0,
},
IsImageSegment: {
type: Boolean,
default: false,
}
},
data() {
return {
@@ -84,6 +69,8 @@ export default {
},
mounted() {
this.title = `Upload Images${this.SubjectCode}${this.Criterion.TrialReadingCriterionName}`
if (this.IsImageSegment) this.title = `Upload Images${this.SubjectCode}`
if (this.isReadingTaskViewInOrder === 0) this.title = ''
store.dispatch('trials/setUnLock', true)
},
methods: {
@@ -100,14 +87,16 @@ export default {
}
</script>
<style lang="scss" scoped>
::v-deep.el-tabs--left .el-tabs__header.is-left {
::v-deep .el-tabs--left .el-tabs__header.is-left {
margin-right: 0;
}
.uploadDicomAndNonedicom {
::v-deep.el-tabs--border-card > .el-tabs__header .el-tabs__item {
::v-deep .el-tabs--border-card>.el-tabs__header .el-tabs__item {
color: #909399;
}
::v-deep.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active {
::v-deep .el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active {
color: #428bca;
background-color: #fff;
border-right-color: #dcdfe6;
@@ -4,21 +4,32 @@
<span>{{ $t('upload:nonedicom:title') }}</span>
<div class="tip">
<i class="el-icon-warning-outline"></i>
<div v-html="$t('upload:nonedicom:tip:message')"></div>
<div v-html="$t('upload:nonedicom:tip:message').replace(
'xxx',
relationInfo.ImageFormatList.join('、')
)"></div>
</div>
</div>
<!--检查列表-->
<!--检查列表 @sort-change="handleSortByColumn"-->
<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')" />
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
<!--受试者 sortable="custom"-->
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')"
v-if="isReadingTaskViewInOrder !== 0" />
<!--访视名称-->
<el-table-column prop="VisitName" :label="$t('upload:nonedicom:table:VisitName')" sortable
v-if="IsImageSegment" />
<!--任务名称-->
<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 v-else />
<!--检查类型-->
<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>
</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>
<template slot-scope="scope">
<span>{{ getBodyPart(scope.row.BodyPart, scope.row.BodyPartForEditOther) }}</span>
</template>
</el-table-column>
<!--原文件数-->
<el-table-column prop="FileCount" :label="$t('upload:nonedicom:table:fileCount')">
<template slot-scope="scope">
@@ -99,7 +110,7 @@
<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')"
<el-button circle icon="el-icon-upload2" :title="$t('upload:nonedicom:button:upload')" v-if="!forbid"
@click.native.prevent="handleUpload(scope.row)" />
<!--删除--->
<el-button :disabled="scope.row.UploadedFileCount <= 0 ||
@@ -124,7 +135,10 @@
<!-- 多文件上传 -->
<form id="inputForm" ref="uploadForm">
<el-divider content-position="left">{{
$t('trials:uploadNonDicoms:label:fileType')
$t('trials:uploadNonDicoms:label:fileType').replace(
'xxx',
relationInfo.ImageFormatList.join('、')
)
}}</el-divider>
<div class="form-group">
<div class="upload" style="margin-right: 10px">
@@ -215,8 +229,8 @@ let defaultSearchData = () => {
SubjectId: null,
TrialReadingCriterionId: null,
SubjectCode: null,
Asc: false,
SortField: 'TaskBlindName',
// Asc: false,
// SortField: 'TaskBlindName',
}
}
export default {
@@ -226,6 +240,10 @@ export default {
type: String,
default: '',
},
forbid: {
type: Boolean,
default: false,
},
SubjectCode: {
type: String,
default: '',
@@ -244,6 +262,14 @@ export default {
type: Boolean,
default: false,
},
IsImageSegment: {
type: Boolean,
default: false,
},
isReadingTaskViewInOrder: {
type: Number,
default: 0,
},
},
data() {
return {
@@ -262,6 +288,10 @@ export default {
currentRow: {},
studyMonitorId: null,
open: null,
BodyPart: {},
relationInfo: {
ImageFormatList: []
}
}
},
watch: {
@@ -289,7 +319,8 @@ export default {
store.dispatch('trials/setUnLock', this.btnLoading)
},
},
created() {
async created() {
this.BodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
this.getList()
},
beforeDestroy() {
@@ -305,11 +336,22 @@ export default {
if (this.VisitTaskId) {
this.searchData.VisitTaskId = this.VisitTaskId
}
if (this.IsImageSegment) {
this.searchData.IsImageSegmentLabel = true
}
else if (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20) {
this.searchData.IsImageSegmentLabel = false
}
this.loading = true
let res = await getIRUploadTaskNoneDicomStudyList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result
this.relationInfo = res.OtherInfo
this.faccept = []
this.relationInfo.ImageFormatList.forEach((item) => {
this.faccept.push(`.${item}`)
})
}
} catch (err) {
this.loading = false
@@ -438,7 +480,7 @@ export default {
let trialId = this.$route.query.trialId
var token = getToken()
const routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}`,
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
})
this.open = window.open(routeData.href, '_blank')
},
@@ -473,16 +515,16 @@ export default {
}
},
//
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()
},
// 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()
// },
//
handleSelectionChange(selection) {
this.selectArr = selection
@@ -511,8 +553,9 @@ export default {
})
if (res.IsSuccess) {
this.studyMonitorId = res.Result
let uploadBatchId = this.$guid()
for (let i = 0; i < num; i++) {
funArr.push(this.handleUploadTask(this.selectArr, i))
funArr.push(this.handleUploadTask(this.selectArr, i, uploadBatchId))
}
if (funArr.length > 0) {
let res = await Promise.all(funArr)
@@ -523,17 +566,23 @@ export default {
}
},
//
async handleUploadTask(arr, index) {
async handleUploadTask(arr, index, uploadBatchId) {
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
}/${this.currentRow.SourceSubjectVisitId}/${this.currentRow.VisitTaskId}/${this.$guid()}${file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
if (this.IsImageSegment) {
path = `/${this.$route.query.trialId}/TaskImage/${this.currentRow.SubjectId
}/${this.currentRow.SourceSubjectVisitId}/AnnotationImage/${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)
let res = await this.fileToOss(path, fileData, file, uploadBatchId)
if (res) {
file.status = 2
this.successFileList.push({
@@ -567,13 +616,13 @@ export default {
}
let ind = arr.findIndex((item) => item.status === 0)
if (ind >= 0) {
return this.handleUploadTask(arr, ind)
return this.handleUploadTask(arr, ind, uploadBatchId)
} else {
return false
}
},
// fileoss
async fileToOss(path, file, item) {
async fileToOss(path, file, item, uploadBatchId) {
try {
let res = await this.OSSclient.multipartUpload(
{
@@ -586,6 +635,17 @@ export default {
if (item.uploadFileSize > file.fileSize) {
item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1
}
},
{
fileName: item.name,
fileSize: item.size,
fileType: item.fileType,
uploadBatchId: uploadBatchId,
batchDataType: 7,
trialId: this.$route.query.trialId,
subjectId: this.currentRow.SubjectId,
subjectVisitId: this.currentRow.SourceSubjectVisitId,
studyCode: this.SubjectCode
}
)
if (res) {
@@ -614,6 +674,9 @@ export default {
params.RecordPath = RecordPath.path
params.FailedFileCount = RecordPath.Record.Failed.length
}
if (this.IsImageSegment) {
params.IsImageSegmentLabel = true
}
uploadNoneDicomFile(params)
.then((res) => {
if (!isReLoad) {
@@ -652,7 +715,10 @@ export default {
})
let text = JSON.stringify(Record)
let logJsonBlob = this.generateTxtFile(text)
let logJsonObjectName = `/${this.$route.query.trialId}/TaskImage/${this.currentRow.SubjectId}/${this.currentRow.VisitTaskId}/${this.studyMonitorId}.txt`
let logJsonObjectName = `/${this.$route.query.trialId}/TaskImage/${this.currentRow.SubjectId}/${this.currentRow.SourceSubjectVisitId}/${this.currentRow.VisitTaskId}/${this.studyMonitorId}.txt`
if (this.IsImageSegment) {
logJsonObjectName = `/${this.$route.query.trialId}/TaskImage/${this.currentRow.SubjectId}/${this.currentRow.SourceSubjectVisitId}/AnnotationImage/${this.currentRow.VisitTaskId}/${this.studyMonitorId}.txt`
}
let logRes
try {
logRes = await this.OSSclient.put(logJsonObjectName, logJsonBlob)
@@ -674,6 +740,26 @@ export default {
let blob = new Blob(['\ufeff', text], { type: 'text/plain' })
return blob
},
getBodyPart(bodyPart, other) {
if (!bodyPart && !other) return ''
var separator = ','
if (bodyPart.indexOf('|') > -1) {
separator = '|'
} else if (bodyPart.indexOf(',') > -1) {
separator = ','
} else if (bodyPart.indexOf('') > -1) {
separator = ''
}
var arr = bodyPart.split(separator)
var newArr = arr.map((i) => {
return this.$fd('Bodypart', i.trim(), 'Code', this.BodyPart, 'Name')
})
if (other) {
newArr.push(other)
}
newArr = newArr.filter(Boolean)
return newArr.join(' | ')
},
},
}
</script>
@@ -2,120 +2,55 @@
<div v-if="model_cfg.visible">
<base-model :config="model_cfg">
<div slot="dialog-body">
<el-button v-if="!isUpload && !isDownload" type='primary' size="small" style="float:right;" @click="preview">
{{ $t("common:button:preview") }}
</el-button>
<el-table :data="modelList" style="width: 100%" height="300">
<!--检查编号-->
<el-table-column
prop="StudyCode"
:label="$t('trials:uploadImage:table:StudyCode')"
/>
<el-table-column prop="StudyCode" :label="$t('trials:uploadImage:table:StudyCode')"
v-if="IsReadingTaskViewInOrder !== 0" />
<!--检查类型-->
<el-table-column
prop="ModalityForEdit"
:label="$t('trials:uploadImage:table:ModalityForEdit')"
v-if="IsDicom"
/>
<el-table-column prop="ModalityForEdit" :label="$t('trials:uploadImage:table:ModalityForEdit')"
v-if="IsDicom" />
<!--检查模态-->
<el-table-column
prop="Modalities"
:label="$t('trials:uploadImage:table:Modalities')"
v-if="IsDicom"
/>
<el-table-column prop="Modalities" :label="$t('trials:uploadImage:table:Modalities')" v-if="IsDicom" />
<!--检查部位-->
<el-table-column
prop="BodyPartForEdit"
:label="$t('trials:uploadImage:table:BodyPartForEdit')"
v-if="IsDicom"
>
<el-table-column prop="BodyPartForEdit" :label="$t('trials:uploadImage:table:BodyPartForEdit')"
v-if="IsDicom">
<template slot-scope="scope">
<span>{{
$fd(
'Bodypart',
scope.row.BodyPartForEdit,
'Code',
{ Bodypart: bodyPart },
'Name'
)
}}</span>
<span>{{ getBodyPart(scope.row.BodyPartForEdit, scope.row.BodyPartForEditOther) }}</span>
</template>
</el-table-column>
<!--序列数量-->
<el-table-column
prop="ReadingSeriesCount"
:label="$t('trials:uploadImage:table:SeriesCount')"
v-if="IsDicom"
/>
<el-table-column prop="ReadingSeriesCount" :label="$t('trials:uploadImage:table:SeriesCount')"
v-if="IsDicom" />
<!--图像数量-->
<el-table-column
prop="ReadingInstanceCount"
:label="$t('trials:uploadImage:table:InstanceCount')"
v-if="IsDicom"
/>
<el-table-column prop="ReadingInstanceCount" :label="$t('trials:uploadImage:table:InstanceCount')"
v-if="IsDicom" />
<!--检查时间-->
<el-table-column
prop="StudyTime"
:label="$t('trials:uploadImage:table:StudyTime')"
v-if="IsDicom"
min-width="130"
/>
<el-table-column prop="StudyTime" :label="$t('trials:uploadImage:table:StudyTime')" v-if="IsDicom"
min-width="130" />
<!--检查模态-->
<el-table-column
prop="Modality"
:label="$t('trials:uploadImage:table:Modalities')"
v-if="!IsDicom"
/>
<el-table-column prop="Modality" :label="$t('trials:uploadImage:table:Modalities')" v-if="!IsDicom" />
<!--检查部位-->
<el-table-column
prop="BodyPart"
:label="$t('trials:uploadImage:table:BodyPartForEdit')"
v-if="!IsDicom"
>
<el-table-column prop="BodyPart" :label="$t('trials:uploadImage:table:BodyPartForEdit')" v-if="!IsDicom">
<template slot-scope="scope">
<span>{{
$fd(
'Bodypart',
scope.row.BodyPart,
'Code',
{ Bodypart: bodyPart },
'Name'
)
}}</span>
<span>{{ getBodyPart(scope.row.BodyPart, scope.row.BodyPartForEditOther) }}</span>
</template>
</el-table-column>
<!--文件数量-->
<el-table-column
prop="ReadingFileCount"
:label="$t('trials:uploadImage:table:FileCount')"
v-if="!IsDicom"
/>
<el-table-column prop="ReadingFileCount" :label="$t('trials:uploadImage:table:FileCount')" v-if="!IsDicom" />
<!--检查时间-->
<el-table-column
prop="ImageDate"
:label="$t('trials:uploadImage:table:StudyTime')"
v-if="!IsDicom"
min-width="130"
/>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="80"
>
<el-table-column prop="ImageDate" :label="$t('trials:uploadImage:table:StudyTime')" v-if="!IsDicom"
min-width="130" />
<el-table-column :label="$t('common:action:action')" fixed="right" width="80" v-if="isUpload">
<template slot-scope="scope">
<!--预览--->
<el-button
circle
icon="el-icon-view"
:title="$t('trials:uploadImage:button:preview')"
v-if="!isUpload"
@click.stop="preview(scope.row)"
/>
<!-- <el-button circle icon="el-icon-view" :title="$t('trials:uploadImage:button:preview')" v-if="!isUpload"
@click.stop="preview(scope.row)" /> -->
<!--编辑--->
<el-button
circle
icon="el-icon-edit-outline"
:title="$t('trials:uploadImage:button:edit')"
v-else
@click.stop="openEdit(scope.row)"
/>
<el-button circle icon="el-icon-edit-outline" :title="$t('trials:uploadImage:button:edit')"
@click.stop="openEdit(scope.row)" />
</template>
</el-table-column>
</el-table>
@@ -124,42 +59,20 @@
<!--新增检查部位-->
<base-model v-if="editModality_model.visible" :config="editModality_model">
<template slot="dialog-body">
<el-form
ref="editModalityform"
:inline="true"
:model="form"
class="demo-form-inline"
:rules="rules"
>
<el-form-item
:label="$t('trials:uploadImage:form:ModalityForEdit')"
prop="Modality"
label-width="150px"
>
<el-form ref="editModalityform" :inline="true" :model="form" class="demo-form-inline" :rules="rules">
<el-form-item :label="$t('trials:uploadImage:form:ModalityForEdit')" prop="Modality" label-width="150px">
<el-select v-model="form.Modality" placeholder="">
<el-option
v-for="item in TrialModality"
:key="item"
:label="item"
:value="item"
>
<el-option v-for="item in TrialModality" :key="item" :label="item" :value="item">
</el-option>
</el-select>
</el-form-item>
</el-form>
</template>
<template slot="dialog-footer">
<el-button
type="primary"
@click="updateTaskStudyModality"
:loading="loading"
>
<el-button type="primary" @click="updateTaskStudyModality" :loading="loading">
{{ $t('common:button:confirm') }}
</el-button>
<el-button
@click="editModality_model.visible = false"
:loading="loading"
>
<el-button @click="editModality_model.visible = false" :loading="loading">
{{ $t('common:button:cancel') }}
</el-button>
</template>
@@ -180,9 +93,9 @@ export default {
},
},
bodyPart: {
type: Array,
type: Object,
default: () => {
return []
return {}
},
},
modelList: {
@@ -200,6 +113,10 @@ export default {
visitTaskId: {
type: String,
},
subjectVisitId: {
type: String,
default: ''
},
IsDicom: {
required: true,
type: Boolean,
@@ -209,6 +126,24 @@ export default {
type: Boolean,
default: false,
},
IsImageSegment: {
type: Boolean,
default: false,
},
isDownload: {
type: Boolean,
default: false,
},
Criterion: {
type: Object,
default: () => {
return {}
},
},
IsReadingTaskViewInOrder: {
type: Number,
default: 2,
}
},
components: {
'base-model': baseModel,
@@ -235,6 +170,7 @@ export default {
],
},
loading: false,
BodyPart: {}
}
},
methods: {
@@ -243,15 +179,23 @@ export default {
let routeData = null
if (this.IsDicom) {
var token = getToken()
let trialId = this.$route.query.trialId
routeData = this.$router.resolve({
path: `/showdicom?studyId=${row.Id}&TokenKey=${token}&type=Study&visitTaskId=${this.visitTaskId}&isReading=true`,
path: `/showvisitdicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
})
} else {
let trialId = this.$route.query.trialId
var token = getToken()
routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&TokenKey=${token}&isReading=true`,
})
if (!this.IsImageSegment && (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20)) {
routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
})
} else {
routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
})
}
}
window.open(routeData.href, '_blank')
},
@@ -283,8 +227,28 @@ export default {
console.log(err)
}
},
getBodyPart(bodyPart, other) {
if (!bodyPart && !other) return ''
var separator = ','
if (bodyPart.indexOf('|') > -1) {
separator = '|'
} else if (bodyPart.indexOf(',') > -1) {
separator = ','
} else if (bodyPart.indexOf('') > -1) {
separator = ''
}
var arr = bodyPart.split(separator)
console.log(this.bodyPart)
var newArr = arr.map((i) => {
return this.$fd('Bodypart', i.trim(), 'Code', this.bodyPart, 'Name')
})
if (other) {
newArr.push(other)
}
newArr = newArr.filter(Boolean)
return newArr.join(' | ')
},
},
}
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>
+16
View File
@@ -0,0 +1,16 @@
import resize from './resize'
const install = function (Vue) {
// 绑定v-adaptive指令
Vue.directive('resize', resize)
}
// if (window.Vue) {
// window['adaptive'] = adaptive
// // eslint-disable-next-line no-undef
// Vue.use(install)
// }
resize.install = install
export default resize
+19
View File
@@ -0,0 +1,19 @@
const map = new WeakMap()
const ob = new ResizeObserver(entries => {
for (const entry of entries) {
const handler = map.get(entry.target)
if (handler) {
const { inlineSize, blockSize } = entry.contentBoxSize[0]
handler({ width: inlineSize, height: blockSize })
}
}
})
export default {
bind(el, binding) {
map.set(el, binding.value)
ob.observe(el)
},
unbind(el) {
ob.unobserve(el)
}
}
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777010831812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1646" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 896c-230.058667 0-421.461333-165.546667-461.610667-384a468.565333 468.565333 0 0 1 142.506667-258.816L89.6 149.973333A42.666667 42.666667 0 1 1 149.930667 89.6L934.4 874.112a42.666667 42.666667 0 0 1-60.373333 60.330667l-111.061334-111.061334A466.901333 466.901333 0 0 1 512 896zM253.226667 313.6A382.506667 382.506667 0 0 0 137.514667 512a384.213333 384.213333 0 0 0 563.242666 249.088l-86.528-86.528A192 192 0 0 1 349.44 409.770667L253.226667 313.6z m297.770666 297.728l-138.325333-138.325333a106.666667 106.666667 0 0 0 138.282667 138.282666l0.042666 0.042667z m285.312 22.357333l10.24-18.218666A381.226667 381.226667 0 0 0 886.485333 512a384.213333 384.213333 0 0 0-440.661333-292.949333c-2.944 0.512-9.173333 1.877333-18.730667 4.096a42.88 42.88 0 1 1-19.2-83.541334A470.912 470.912 0 0 1 512 128c230.058667 0 421.461333 165.546667 461.610667 384a467.072 467.072 0 0 1-57.685334 153.856 94.933333 94.933333 0 0 1-8.021333 11.178667 44.373333 44.373333 0 0 1-58.794667 9.088 39.552 39.552 0 0 1-12.8-52.437334z m-188.501333-257.493333a192 192 0 0 1 55.850667 147.626667l-203.52-203.477334a192 192 0 0 1 147.626666 55.893334z" fill="#e6e6e6" p-id="1647"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" class="h-6 w-6"><g id="tool-seg-brush" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><rect id="Rectangle" x="0" y="0" width="24" height="24"></rect><path d="M3.24640621,21.8286833 C3.09173375,21.7551472 2.99513748,21.5971513 3.00018895,21.4259625 C3.00524042,21.2547737 3.11098486,21.1027485 3.26972426,21.0384606 C5.3260304,20.2059201 4.66362518,17.8620247 5.27421252,16.6088957 C6.02197747,15.1026514 7.84114758,14.4766383 9.35746132,15.2037675 C13.9485253,17.4422999 8.48346644,24.3211232 3.24640621,21.8286833 Z" id="Path" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M21.5968442,2.302022 C21.1256527,1.8826075 20.4094461,1.90228142 19.9619901,2.34693083 L9.69255027,12.5887345 C11.0536437,13.0051578 12.1843437,13.9616637 12.8206229,15.2349008 L21.7410706,3.93687606 C22.1347378,3.44008272 22.0714081,2.72222021 21.5968442,2.302022 Z" id="Path" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1762494352859" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22987" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M896 832a128 128 0 0 1-128 128H256a128 128 0 0 1-128-128V192a128 128 0 0 1 128-128h512a128 128 0 0 1 128 128v640zM192 768v64a64 64 0 0 0 56.512 63.552L256 896h512a64 64 0 0 0 63.552-56.512L832 832v-64H192z m448-640H512v206.912l64-38.4 64 38.464V128z m-448 576h640V192a64 64 0 0 0-56.512-63.552L768 128h-64v263.488a32 32 0 0 1-48.448 27.456L576 371.2l-79.552 47.744A32 32 0 0 1 448 391.424V128H256a64 64 0 0 0-63.552 56.512L192 192v512z" fill="#e6e6e6" p-id="22988"></path></svg>

After

Width:  |  Height:  |  Size: 812 B

+12
View File
@@ -0,0 +1,12 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="h-6 w-6" color="#fff">
<path
d="M10.3945 12.6113C10.043 12.6113 9.78516 12.3945 9.78516 12.0371C9.78516 11.6855 10.043 11.4688 10.3945 11.4688H13.2012C13.5527 11.4688 13.8164 11.6855 13.8164 12.0371C13.8164 12.3945 13.5527 12.6113 13.2012 12.6113H10.3945Z"
fill="currentColor"></path>
<path opacity="0.5"
d="M18.312 6.84473C21.8473 8.88583 22.9225 13.6424 20.7134 17.4687C18.5042 21.2951 13.8473 22.7422 10.312 20.7011C9.51661 20.2419 8.84737 19.6439 8.31042 18.9512C11.3012 19.3598 14.4827 17.8251 16.1946 14.8598C17.9067 11.8945 17.6457 8.3712 15.7963 5.98538C16.6645 6.10409 17.5167 6.38556 18.312 6.84473Z"
fill="currentColor"></path>
<circle cx="13.7852" cy="13.4688" r="8" stroke="currentColor"></circle>
<path
d="M4.50586 8.22266C4.14844 8.22266 3.92578 7.9707 3.92578 7.60742V5.68555H2.10352C1.74609 5.68555 1.5 5.46875 1.5 5.11719C1.5 4.76562 1.74609 4.54297 2.10352 4.54297H3.92578V2.61523C3.92578 2.25195 4.14844 2 4.50586 2C4.85742 2 5.08008 2.25195 5.08008 2.61523V4.54297H6.89648C7.25391 4.54297 7.50586 4.76562 7.50586 5.11719C7.50586 5.46875 7.25391 5.68555 6.89648 5.68555H5.08008V7.60742C5.08008 7.9707 4.85742 8.22266 4.50586 8.22266Z"
fill="currentColor"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1766048712120" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6026" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M924.520311 484.074997c7.439436 0 13.884218 2.726088 19.336394 8.16496 5.437849 5.452175 8.16496 11.897981 8.16496 19.336394 0 7.452739-2.726088 13.898545-8.16496 19.336394-5.452175 5.452175-11.897981 8.16496-19.336394 8.16496l-83.363639 0c-3.437286 40.110533-13.617136 77.777411-30.508851 113.012913-16.906042 35.236526-38.673811 66.175165-65.315588 92.816942s-57.58144 48.422849-92.816942 65.315588c-35.236526 16.906042-72.915683 26.790156-113.012913 29.650297l0 84.223217c0 7.439436-2.726088 13.884218-8.16496 19.336394-5.451152 5.437849-11.896958 8.16496-19.336394 8.16496-7.452739 0-13.898545-2.726088-19.336394-8.16496-5.452175-5.452175-8.16496-11.897981-8.16496-19.336394l0-84.223217c-40.110533-2.860141-77.777411-12.743232-113.012913-29.650297-35.236526-16.892739-66.175165-38.673811-92.816942-65.315588s-48.422849-57.58144-65.315588-92.816942c-16.906042-35.236526-27.071565-72.90238-30.508851-113.012913L99.479689 539.077705c-7.452739 0-13.898545-2.711761-19.336394-8.16496-5.452175-5.437849-8.16496-11.883655-8.16496-19.336394 0-7.439436 2.712785-13.884218 8.16496-19.336394 5.437849-5.437849 11.883655-8.16496 19.336394-8.16496l83.363639 0c3.437286-40.09723 13.602809-77.777411 30.508851-113.012913 16.892739-35.236526 38.673811-66.175165 65.315588-92.816942s57.58144-48.409546 92.816942-65.315588c35.236526-16.892739 72.90238-26.77583 113.012913-29.650297L484.497623 99.05604c0-7.439436 2.712785-13.885242 8.16496-19.336394 5.437849-5.437849 11.883655-8.16496 19.336394-8.16496 7.440459 0 13.885242 2.726088 19.336394 8.16496 5.437849 5.452175 8.16496 11.896958 8.16496 19.336394l0 84.223217c40.098253 2.874467 77.777411 12.757558 113.012913 29.650297 35.236526 16.906042 66.175165 38.673811 92.816942 65.315588s48.409546 57.58144 65.315588 92.816942c16.892739 35.236526 27.071565 72.916706 30.508851 113.012913L924.520311 484.074997zM484.498646 238.281965c-32.657794 2.874467-63.167668 11.320836-91.527576 25.352411-28.360931 14.046924-53.431933 31.946596-75.198679 53.713342-21.781072 21.781072-39.680744 46.837748-53.713342 75.198679-14.045901 28.360931-22.49227 58.869782-25.352411 91.527576L484.498646 484.073974 484.498646 238.281965zM238.70459 539.077705c2.860141 32.657794 11.30651 63.166645 25.352411 91.527576 14.032598 28.360931 31.933293 53.431933 53.713342 75.198679 21.766746 21.781072 46.837748 39.680744 75.198679 53.713342 28.360931 14.046924 58.869782 22.49227 91.527576 25.352411L484.496599 539.077705 238.70459 539.077705zM539.501354 484.074997l245.793032 0c-2.874467-32.657794-11.320836-63.167668-25.352411-91.527576-14.046924-28.360931-31.946596-53.417607-53.713342-75.198679-21.780049-21.766746-46.837748-39.667441-75.198679-53.713342-28.360931-14.032598-58.869782-22.478967-91.527576-25.352411L539.502377 484.074997zM539.501354 784.870738c32.657794-2.860141 63.167668-11.30651 91.527576-25.352411 28.360931-14.032598 53.41863-31.93227 75.198679-53.713342 21.766746-21.766746 39.667441-46.837748 53.713342-75.198679 14.032598-28.360931 22.478967-58.869782 25.352411-91.527576L539.501354 539.078729 539.501354 784.870738z" p-id="6027" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 5.2 KiB

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1751350116150" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20392" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M870.4 819.2a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4zM512 179.2a332.8 332.8 0 1 1 0 665.6 332.8 332.8 0 0 1 0-665.6z m0 51.2a281.6 281.6 0 1 0 0 563.2 281.6 281.6 0 0 0 0-563.2zM153.6 102.4a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4z" fill="#ADAEB8" p-id="20393"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597744457882" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10125" width="285.64453125" height="250" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M926.216214 404.588947l1.511115-151.84272H1079.570048c18.035893 0 33.098301-15.062408 33.098301-33.0983a33.390775 33.390775 0 0 0-33.098301-33.098301H927.727329V33.195792a33.390775 33.390775 0 0 0-33.049555-33.049555 33.390775 33.390775 0 0 0-33.0983 33.049555c0 3.022231 0 4.533346 1.511115 7.555577v144.287142H711.24787a33.390775 33.390775 0 0 0-33.098301 33.147046c0 18.035893 15.062408 33.049555 33.098301 33.049555H863.090589v139.802542c0 3.022231-1.46237 4.533346-1.46237 7.506831 0 18.035893 15.013662 33.098301 33.049555 33.098301 15.013662 1.46237 28.564955-10.529062 31.53844-27.053839zM1032.969201 790.995763a29.393631 29.393631 0 0 0-22.520493 10.480316 546.000095 546.000095 0 0 1-117.282049 88.717095 29.101157 29.101157 0 0 0-15.062408 25.591469c0 16.524777 13.551292 30.027324 30.07607 30.027324 4.533346 0 10.529062-1.46237 13.551292-2.973485 1.46237 0 1.46237-1.511115 1.46237-1.511115a523.235874 523.235874 0 0 0 127.811111-97.735041c6.044461-5.995716 10.529062-13.551292 10.529061-22.569238a28.028752 28.028752 0 0 0-28.564954-30.027325zM793.920503 935.282906c-2.973485 0-7.506831 0-10.529062 1.511115-46.600847 15.062408-96.223925 24.080354-145.798258 27.053839-15.062408 1.511115-25.59147 15.062408-25.591469 30.07607 0 16.573523 13.551292 30.07607 30.07607 30.07607 55.618794-4.4846 108.215357-13.502547 159.398295-30.07607a28.95492 28.95492 0 0 0 22.520494-28.564954 30.173561 30.173561 0 0 0-30.07607-30.07607zM535.324796 960.874375c-12.040177-1.511115-24.031609-1.511115-36.071785-3.02223a564.962155 564.962155 0 0 1-49.623078-7.506832c-230.030752-45.089732-389.380302-202.976912-389.380302-380.362355 0-139.851288 99.19741-269.124768 260.106822-339.805969 13.502547-5.995716 27.053839-12.040177 40.556386-16.573523 10.529062-4.4846 22.569239-7.506831 33.0983-10.480317 12.040177-4.533346 21.058123-15.062408 21.058124-28.564954a30.173561 30.173561 0 0 0-30.07607-30.07607 25.396487 25.396487 0 0 0-15.062408 4.4846c-10.529062 3.022231-19.498262 6.044461-28.564955 9.017947l-45.089732 18.035893C114.357309 254.257343 0.097491 406.148808 0.097491 568.471843c0 207.510258 180.407674 387.917932 439.00338 440.563241l54.107679 9.017946c12.040177 1.46237 25.59147 3.022231 37.631646 3.022231h1.46237c16.573523 0 30.07607-13.551292 30.07607-30.07607a30.758509 30.758509 0 0 0-27.05384-30.07607zM1169.798258 569.982958a30.173561 30.173561 0 0 0-30.07607-30.07607 30.173561 30.173561 0 0 0-30.07607 30.07607v1.46237c0 46.649593-10.529062 93.25044-33.049555 136.829057-1.511115 3.022231-1.511115 7.506831-1.511115 12.040177 0 16.573523 13.551292 30.07607 30.07607 30.07607 13.502547 0 24.031609-9.017946 28.564954-21.058124a361.985243 361.985243 0 0 0 36.071786-157.88718v-1.46237z" p-id="10126"></path><path d="M1052.516209 297.835959c-5.995716-4.533346-13.502547-9.017946-22.520493-9.017946a30.173561 30.173561 0 0 0-30.07607 30.07607c0 7.506831 2.973485 15.013662 9.017946 21.009378a375.14657 375.14657 0 0 1 79.699148 118.793164c4.4846 10.529062 15.013662 19.547008 27.053839 19.547008 16.524777 0 30.07607-13.551292 30.07607-30.07607 0-4.4846-1.511115-7.506831-3.02223-12.040177a422.039891 422.039891 0 0 0-90.179464-138.291427zM666.158138 182.065026h4.4846c16.573523 0 30.07607-13.551292 30.07607-30.07607 0-15.013662-12.040177-28.564955-27.053839-28.564954v-1.46237a761.602133 761.602133 0 0 0-154.86495-1.559861h-3.022231a30.173561 30.173561 0 0 0-30.07607 30.07607c0 16.573523 13.551292 30.07607 30.07607 30.07607h3.022231v1.462369c46.600847-5.94697 97.735041-4.4846 147.358119 0z" p-id="10127"></path></svg>

Before

Width:  |  Height:  |  Size: 623 B

After

Width:  |  Height:  |  Size: 3.8 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777014169186" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4736" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1024 739.560727V1024H739.560727v-84.898909h199.540364v-199.540364H1024z m-939.101091 0v199.540364h199.540364V1024H0V739.560727h84.898909zM824.878545 199.121455v625.75709H199.121455V199.121455h625.75709z m-85.317818 85.317818H284.439273v455.121454h455.121454V284.439273zM1024 0v284.439273h-84.898909V84.898909h-199.540364V0H1024zM284.439273 0v84.898909H84.898909v199.540364H0V0h284.439273z" fill="#e6e6e6" p-id="4737"></path></svg>

After

Width:  |  Height:  |  Size: 764 B

+1
View File
@@ -0,0 +1 @@
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-fill" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" fill="currentColor" x="2" y="2" width="14" height="14" rx="1"></rect></g></g></svg>

After

Width:  |  Height:  |  Size: 338 B

+1
View File
@@ -0,0 +1 @@
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-outline-fill" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" stroke="currentColor" x="1.5" y="1.5" width="15" height="15" rx="1"></rect><rect id="Rectangle" fill="currentColor" x="3.5" y="3.5" width="11" height="11" rx="1"></rect></g></g></svg>

After

Width:  |  Height:  |  Size: 446 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1609205172733" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2919" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M320 640v256H256v-192H64v-64h256z m640 0v64h-192v192h-64v-256h256zM512 384a128 128 0 1 1 0 256 128 128 0 0 1 0-256zM320 128v256H64V320h192V128h64z m448 0v192h192v64h-256V128h64z" p-id="2920"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777426164195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5541" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M316 672h60c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v304c0 4.4 3.6 8 8 8zM512 622c22.1 0 40-17.9 40-39 0-23.1-17.9-41-40-41s-40 17.9-40 41c0 21.1 17.9 39 40 39zM512 482c22.1 0 40-17.9 40-39 0-23.1-17.9-41-40-41s-40 17.9-40 41c0 21.1 17.9 39 40 39z" p-id="5542"></path><path d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32z m-40 728H184V184h656v656z" p-id="5543"></path><path d="M648 672h60c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v304c0 4.4 3.6 8 8 8z" p-id="5544"></path></svg>

Before

Width:  |  Height:  |  Size: 581 B

After

Width:  |  Height:  |  Size: 908 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777352764855" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10736" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M587.808 383.392l-102.208 102.208A37.472 37.472 0 0 0 512 549.408a36.288 36.288 0 0 0 26.272-11.104l315.84-315.232a454.976 454.976 0 1 0 43.52 61.888l-54.688 54.752a372.704 372.704 0 1 1-94.816-116.928l-106.56 106.496-53.792 54.144z" p-id="10737"></path></svg>

After

Width:  |  Height:  |  Size: 594 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1775115523115" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5347" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M458.105263 970.105263h-215.578947V264.084211h215.578947V970.105263z m-161.68421-53.894737h107.789473V317.978947h-107.789473V916.210526z" fill="#ffffff" p-id="5348"></path><path d="M296.421053 970.105263h-215.578948V479.663158h215.578948V970.105263z m-161.684211-53.894737h107.789474V533.557895h-107.789474V916.210526zM943.157895 970.105263h-215.578948V479.663158h215.578948V970.105263z m-161.684211-53.894737h107.789474V533.557895h-107.789474V916.210526zM619.789474 970.105263h-215.578948V53.894737h215.578948v916.210526z m-161.684211-53.894737h107.789474V107.789474h-107.789474v808.421052z" fill="#ffffff" p-id="5349"></path><path d="M781.473684 970.105263h-215.578947V264.084211h215.578947V970.105263z m-161.68421-53.894737h107.789473V317.978947h-107.789473V916.210526z" fill="#ffffff" p-id="5350"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1762485648235" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10985" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M543.378286 515.949714V104.521143a31.451429 31.451429 0 0 0-62.976 0v411.501714a125.44 125.44 0 0 0 0.292571 242.834286 31.670857 31.670857 0 0 0-0.292571 3.949714v156.745143a31.451429 31.451429 0 0 0 62.902857 0v-156.745143a31.597714 31.597714 0 0 0-0.219429-3.876571 125.513143 125.513143 0 0 0 0.292572-242.980572z m12.946285 165.814857a62.683429 62.683429 0 1 1-88.649142-88.722285 62.683429 62.683429 0 0 1 88.649142 88.722285zM229.522286 202.459429a31.597714 31.597714 0 0 0 0.292571-3.949715V104.594286a31.305143 31.305143 0 1 0-62.610286 0v93.988571c0 1.389714 0 2.706286 0.146286 4.022857a125.44 125.44 0 0 0 0 242.907429 31.670857 31.670857 0 0 0-0.146286 3.876571v470.235429a31.305143 31.305143 0 1 0 62.610286 0V449.316571a31.597714 31.597714 0 0 0-0.292571-3.803428 125.44 125.44 0 0 0 0-243.053714z m13.312 165.888a62.683429 62.683429 0 1 1-88.649143-88.722286 62.683429 62.683429 0 0 1 88.649143 88.722286zM950.857143 324.022857c0-58.587429-40.228571-107.739429-94.500572-121.563428a31.670857 31.670857 0 0 0 0.146286-3.949715V104.594286a31.305143 31.305143 0 0 0-62.610286 0v93.988571c0 1.389714 0.146286 2.706286 0.292572 4.022857a125.44 125.44 0 0 0 0 242.907429 31.670857 31.670857 0 0 0-0.292572 3.949714v470.162286a31.305143 31.305143 0 1 0 62.610286 0V449.389714c0-1.316571 0-2.56-0.146286-3.876571A125.513143 125.513143 0 0 0 950.857143 324.022857z m-81.042286 44.324572a62.683429 62.683429 0 1 1-88.649143-88.722286 62.683429 62.683429 0 0 1 88.649143 88.722286z" p-id="10986" fill="#e6e6e6"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774331916694" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1627" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M198.4 960A134.4 134.4 0 0 1 64 825.6V198.4A134.4 134.4 0 0 1 198.4 64h268.8a44.8 44.8 0 0 1 44.8 44.8 44.8 44.8 0 0 1-44.8 44.8H198.4a44.8 44.8 0 0 0-44.8 44.8v627.2a44.8 44.8 0 0 0 44.8 44.8h627.2a44.8 44.8 0 0 0 44.8-44.8V556.8a44.8 44.8 0 0 1 44.8-44.8 44.8 44.8 0 0 1 44.8 44.8v268.8A134.4 134.4 0 0 1 825.6 960z m281.984-416.384a44.8 44.8 0 0 1 0-63.296L807.232 153.6H646.464a44.8 44.8 0 0 1-44.8-44.8 44.8 44.8 0 0 1 44.8-44.8h267.264a44.8 44.8 0 0 1 28.288 8.896l1.408 1.152 0.64 0.512 1.024 0.96a41.216 41.216 0 0 1 3.136 3.072l0.896 1.088 0.512 0.64 1.152 1.344a44.8 44.8 0 0 1 8.832 28.288V377.28a44.8 44.8 0 0 1-44.8 44.8 44.8 44.8 0 0 1-44.8-44.8V216.512l-326.4 326.4a44.8 44.8 0 0 1-32 13.248A44.8 44.8 0 0 1 480 543.616z" p-id="1628" fill="#2c2c2c"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1764830990216" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5566" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M192 170.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v640a21.333333 21.333333 0 0 0 21.333333 21.333333h640a21.333333 21.333333 0 0 0 21.333333-21.333333v-640a21.333333 21.333333 0 0 0-21.333333-21.333333h-640zM85.333333 192A106.666667 106.666667 0 0 1 192 85.333333h640A106.666667 106.666667 0 0 1 938.666667 192v640a106.666667 106.666667 0 0 1-106.666667 106.666667h-640A106.666667 106.666667 0 0 1 85.333333 832v-640z" fill="#ffffff" p-id="5567"></path><path d="M173.653333 170.666667c-1.621333 5.034667-2.986667 12.373333-2.986666 21.333333v640c0 8.96 1.365333 16.298667 2.986666 21.333333h292.693334c1.621333-5.034667 2.986667-12.373333 2.986666-21.333333v-640c0-8.96-1.365333-16.298667-2.986666-21.333333H173.653333zM99.157333 127.658667C107.306667 111.530667 126.293333 85.333333 160 85.333333h320c33.706667 0 52.736 26.197333 60.8 42.325334 9.301333 18.688 13.866667 41.472 13.866667 64.341333v640c0 22.869333-4.565333 45.653333-13.866667 64.341333-8.106667 16.128-27.093333 42.325333-60.8 42.325334h-320c-33.706667 0-52.736-26.197333-60.8-42.325334C89.856 877.653333 85.333333 854.869333 85.333333 832v-640c0-22.869333 4.522667-45.653333 13.866667-64.341333z" fill="#ffffff" p-id="5568"></path><path d="M170.666667 170.666667v298.666666h298.666666V170.666667H170.666667z m-85.333334-10.666667C85.333333 118.784 118.784 85.333333 160 85.333333h320c41.216 0 74.666667 33.450667 74.666667 74.666667v320A74.666667 74.666667 0 0 1 480 554.666667h-320A74.666667 74.666667 0 0 1 85.333333 480v-320z" fill="#ffffff" p-id="5569"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" stroke="currentColor" x="1.5" y="1.5" width="15" height="15" rx="1"></rect></g></g></svg>

After

Width:  |  Height:  |  Size: 347 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597744457882" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10125" width="285.64453125" height="250" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M926.216214 404.588947l1.511115-151.84272H1079.570048c18.035893 0 33.098301-15.062408 33.098301-33.0983a33.390775 33.390775 0 0 0-33.098301-33.098301H927.727329V33.195792a33.390775 33.390775 0 0 0-33.049555-33.049555 33.390775 33.390775 0 0 0-33.0983 33.049555c0 3.022231 0 4.533346 1.511115 7.555577v144.287142H711.24787a33.390775 33.390775 0 0 0-33.098301 33.147046c0 18.035893 15.062408 33.049555 33.098301 33.049555H863.090589v139.802542c0 3.022231-1.46237 4.533346-1.46237 7.506831 0 18.035893 15.013662 33.098301 33.049555 33.098301 15.013662 1.46237 28.564955-10.529062 31.53844-27.053839zM1032.969201 790.995763a29.393631 29.393631 0 0 0-22.520493 10.480316 546.000095 546.000095 0 0 1-117.282049 88.717095 29.101157 29.101157 0 0 0-15.062408 25.591469c0 16.524777 13.551292 30.027324 30.07607 30.027324 4.533346 0 10.529062-1.46237 13.551292-2.973485 1.46237 0 1.46237-1.511115 1.46237-1.511115a523.235874 523.235874 0 0 0 127.811111-97.735041c6.044461-5.995716 10.529062-13.551292 10.529061-22.569238a28.028752 28.028752 0 0 0-28.564954-30.027325zM793.920503 935.282906c-2.973485 0-7.506831 0-10.529062 1.511115-46.600847 15.062408-96.223925 24.080354-145.798258 27.053839-15.062408 1.511115-25.59147 15.062408-25.591469 30.07607 0 16.573523 13.551292 30.07607 30.07607 30.07607 55.618794-4.4846 108.215357-13.502547 159.398295-30.07607a28.95492 28.95492 0 0 0 22.520494-28.564954 30.173561 30.173561 0 0 0-30.07607-30.07607zM535.324796 960.874375c-12.040177-1.511115-24.031609-1.511115-36.071785-3.02223a564.962155 564.962155 0 0 1-49.623078-7.506832c-230.030752-45.089732-389.380302-202.976912-389.380302-380.362355 0-139.851288 99.19741-269.124768 260.106822-339.805969 13.502547-5.995716 27.053839-12.040177 40.556386-16.573523 10.529062-4.4846 22.569239-7.506831 33.0983-10.480317 12.040177-4.533346 21.058123-15.062408 21.058124-28.564954a30.173561 30.173561 0 0 0-30.07607-30.07607 25.396487 25.396487 0 0 0-15.062408 4.4846c-10.529062 3.022231-19.498262 6.044461-28.564955 9.017947l-45.089732 18.035893C114.357309 254.257343 0.097491 406.148808 0.097491 568.471843c0 207.510258 180.407674 387.917932 439.00338 440.563241l54.107679 9.017946c12.040177 1.46237 25.59147 3.022231 37.631646 3.022231h1.46237c16.573523 0 30.07607-13.551292 30.07607-30.07607a30.758509 30.758509 0 0 0-27.05384-30.07607zM1169.798258 569.982958a30.173561 30.173561 0 0 0-30.07607-30.07607 30.173561 30.173561 0 0 0-30.07607 30.07607v1.46237c0 46.649593-10.529062 93.25044-33.049555 136.829057-1.511115 3.022231-1.511115 7.506831-1.511115 12.040177 0 16.573523 13.551292 30.07607 30.07607 30.07607 13.502547 0 24.031609-9.017946 28.564954-21.058124a361.985243 361.985243 0 0 0 36.071786-157.88718v-1.46237z" p-id="10126"></path><path d="M1052.516209 297.835959c-5.995716-4.533346-13.502547-9.017946-22.520493-9.017946a30.173561 30.173561 0 0 0-30.07607 30.07607c0 7.506831 2.973485 15.013662 9.017946 21.009378a375.14657 375.14657 0 0 1 79.699148 118.793164c4.4846 10.529062 15.013662 19.547008 27.053839 19.547008 16.524777 0 30.07607-13.551292 30.07607-30.07607 0-4.4846-1.511115-7.506831-3.02223-12.040177a422.039891 422.039891 0 0 0-90.179464-138.291427zM666.158138 182.065026h4.4846c16.573523 0 30.07607-13.551292 30.07607-30.07607 0-15.013662-12.040177-28.564955-27.053839-28.564954v-1.46237a761.602133 761.602133 0 0 0-154.86495-1.559861h-3.022231a30.173561 30.173561 0 0 0-30.07607 30.07607c0 16.573523 13.551292 30.07607 30.07607 30.07607h3.022231v1.462369c46.600847-5.94697 97.735041-4.4846 147.358119 0z" p-id="10127"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777352032068" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5387" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M924.8 337.8c-22.6-53.4-54.9-101.3-96-142.4s-89-73.4-142.4-96C631.2 76.1 572.5 64.2 512 64.2S392.9 76.1 337.6 99.4c-53.4 22.6-101.3 54.9-142.4 96s-73.4 89-96 142.4C75.9 393.1 64 451.8 64 512.2c0 60.5 11.8 119.1 35.2 174.4 22.6 53.4 54.9 101.3 96 142.4 41.1 41.1 89 73.4 142.4 96 55.3 23.4 113.9 35.2 174.4 35.2s119.1-11.8 174.4-35.2c53.4-22.6 101.3-54.9 142.4-96 41.1-41.1 73.4-89 96-142.4 23.4-55.3 35.2-113.9 35.2-174.4 0-60.4-11.8-119.1-35.2-174.4zM780.3 780.5C708.6 852.2 613.4 891.6 512 891.6c-101.3 0-196.6-39.5-268.3-111.1S132.6 613.6 132.6 512.2c0-101.3 39.5-196.6 111.1-268.3s167-111.1 268.3-111.1c101.3 0 196.6 39.5 268.3 111.1s111.1 166.9 111.1 268.3S852 708.8 780.3 780.5z" p-id="5388"></path><path d="M512 512.2m-106.2 0a106.2 106.2 0 1 0 212.4 0 106.2 106.2 0 1 0-212.4 0Z" p-id="5389"></path></svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1779246817161" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5348" width="200" height="200" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M473 71a8 8 0 0 1 8-8h64a8 8 0 0 1 8 8v77.161C722.848 166.622 857.812 301.289 876.729 471H952a8 8 0 0 1 8 8v64a8 8 0 0 1-8 8h-75.053C858.871 721.652 723.515 857.305 553 875.839V951a8 8 0 0 1-8 8h-64a8 8 0 0 1-8-8v-75.161C302.818 857.341 167.659 722.182 149.161 552H72a8 8 0 0 1-8-8v-64a8 8 0 0 1 8-8h77.161C167.659 301.818 302.818 166.659 473 148.161V71z m326 441c0-157.953-128.047-286-286-286S227 354.047 227 512s128.047 286 286 286 286-128.047 286-286z m-286 60c33.137 0 60-26.863 60-60s-26.863-60-60-60-60 26.863-60 60 26.863 60 60 60z" fill="#ffffff" p-id="5349"></path></svg>

After

Width:  |  Height:  |  Size: 913 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1763446648844" class="icon" viewBox="0 0 1321 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3570" xmlns:xlink="http://www.w3.org/1999/xlink" width="258.0078125" height="200"><path d="M1187.981 845.871H200.885V120.065C200.885 91.032 177.659 62 142.82 62s-58.064 23.226-58.064 58.065v783.87c0 29.033 23.225 58.065 58.064 58.065h1045.161c29.033 0 58.065-23.226 58.065-58.065s-29.032-58.064-58.065-58.064z" fill="#1296db" p-id="3571"></path><path d="M287.981 317.484L555.078 485.87c11.613 5.806 17.42 5.806 29.032 5.806 17.42 0 34.84-5.806 46.452-23.225l185.806-255.484 191.613 145.161c23.226 17.42 58.065 11.613 75.484-11.613 17.42-23.226 11.613-58.064-11.613-75.484L839.594 96.84c-23.226-17.42-58.064-11.613-75.484 11.613L572.497 363.935 346.046 224.581c-23.226-17.42-58.065-5.807-75.484 17.419s-5.806 58.065 17.42 75.484z m29.033 505.161c29.032 0 58.064-23.226 58.064-58.064V532.323c0-29.033-23.226-58.065-58.064-58.065s-58.065 23.226-58.065 58.065v238.064c5.807 29.032 29.032 52.258 58.065 52.258zM502.82 619.42v150.968c0 29.032 23.226 58.065 58.065 58.065s58.064-23.226 58.064-58.065V619.42c0-29.032-23.226-58.064-58.064-58.064s-58.065 29.032-58.065 58.064z" fill="#1296db" p-id="3572"></path><path d="M740.885 416.194v354.193c0 29.032 23.225 58.065 58.064 58.065s58.065-23.226 58.065-58.065V416.194c0-29.033-23.226-58.065-58.065-58.065s-58.064 29.032-58.064 58.065z m296.129 92.903c-29.033 0-58.065 23.226-58.065 58.064v203.226c0 29.032 23.226 58.065 58.065 58.065s58.064-23.226 58.064-58.065V567.161c0-29.032-29.032-58.064-58.064-58.064z" fill="#1296db" p-id="3573"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777432778355" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2607" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M954.026667 913.6128H600.746667a35.908267 35.908267 0 0 1-35.771734-35.771733V116.736a35.703467 35.703467 0 0 1 68.266667-15.018667l353.143467 761.0368a35.566933 35.566933 0 0 1-2.2528 34.269867 35.362133 35.362133 0 0 1-30.173867 16.5888z" fill="#FFFFFF" p-id="2608"></path><path d="M465.373867 913.544533H112.162133a35.6352 35.6352 0 0 1-32.494933-50.722133L432.878933 101.717333a35.6352 35.6352 0 0 1 40.277334-19.8656 35.566933 35.566933 0 0 1 27.989333 34.952534V877.909333a35.771733 35.771733 0 0 1-35.771733 35.6352z" fill="#FFFFFF" fill-opacity=".4" p-id="2609"></path></svg>

After

Width:  |  Height:  |  Size: 916 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777426622063" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8288" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M667.69962 294.974152l0 589.688383 316.384787 0L667.69962 294.974152zM632.522446 884.662535 632.522446 572.426231 34.882973 884.662535 632.522446 884.662535zM510.16777 357.862457l-137.677663-31.323403c0 0 97.523127-217.392192 349.512279-98.842169 0 0-196.516746-248.618381-487.190965 67.571978l-137.677663-31.273261 158.803819 250.082732L510.16777 357.862457z" p-id="8289"></path></svg>

After

Width:  |  Height:  |  Size: 719 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777426691300" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2490" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M34.884 883.64h316.385V293.95L34.884 883.64z m949.201 0L386.446 571.402v312.236h597.64zM763.03 513.053l158.805-250.083-137.678 31.274c-290.674-316.19-487.191-67.572-487.191-67.572 251.99-118.55 349.512 98.842 349.512 98.842l-137.677 31.323L763.03 513.054z" fill="" p-id="2491"></path></svg>

After

Width:  |  Height:  |  Size: 623 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777432945307" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4263" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M106.496 928.426667V575.2832c0-19.729067 16.042667-35.771733 35.771733-35.771733h761.0368a35.703467 35.703467 0 0 1 15.086934 68.266666L157.354667 960.9216a35.566933 35.566933 0 0 1-34.269867-2.321067 35.362133 35.362133 0 0 1-16.5888-30.173866z" fill="#FFFFFF" p-id="4264"></path><path d="M106.496 439.842133V86.6304a35.6352 35.6352 0 0 1 50.7904-32.494933l761.0368 353.211733a35.6352 35.6352 0 0 1 19.933867 40.209067 35.566933 35.566933 0 0 1-34.952534 27.989333H142.199467a35.771733 35.771733 0 0 1-35.703467-35.703467z" fill="#FFFFFF" fill-opacity=".4" p-id="4265"></path></svg>

After

Width:  |  Height:  |  Size: 916 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1782284218093" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4982" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 51.2a460.8 460.8 0 1 1 0 921.6 460.8 460.8 0 0 1 0-921.6z m0 51.2a409.6 409.6 0 1 0 0 819.2 409.6 409.6 0 0 0 0-819.2z" fill="#ffffff" p-id="4983"></path><path d="M512 358.4c70.4 0 137.1136 5.2736 196.7616 14.6432l27.0336 4.6592C877.1584 403.9168 972.8 454.2464 972.8 512c0 57.7536-95.6416 108.032-237.0048 134.2976l-27.0336 4.608A1275.1872 1275.1872 0 0 1 512 665.6c-70.4 0-137.1136-5.2736-196.7616-14.6432l-27.0336-4.6592C146.8416 620.0832 51.2 569.7536 51.2 512c0-57.7536 95.6416-108.032 237.0048-134.2976l27.0336-4.608c55.0912-8.704 116.1728-13.824 180.5824-14.592L512 358.4z m0 51.2c-31.5904 0-62.3104 1.1776-91.8528 3.328l-29.0816 2.5088-28.2112 3.072c-23.1424 2.7648-45.2096 6.144-66.048 9.984l-24.4224 4.7616-23.0912 5.12-21.76 5.5296C150.3744 464.5376 102.4 490.8544 102.4 512c0 21.1456 47.9744 47.4624 125.1328 68.096l21.76 5.4784 23.0912 5.1712 24.4224 4.7616c20.8384 3.84 42.9056 7.168 66.048 9.984l28.16 3.072 29.1328 2.5088a1261.4656 1261.4656 0 0 0 183.7056 0l29.0816-2.5088 28.2112-3.072c23.1424-2.7648 45.2096-6.144 66.048-9.984l24.4224-4.7616 23.0912-5.12 21.76-5.5296C873.6256 559.4624 921.6 533.1456 921.6 512c0-21.1456-47.9744-47.4624-125.1328-68.096l-21.76-5.4784-23.0912-5.1712-24.4224-4.7616c-20.8384-3.84-42.9056-7.168-66.048-9.984l-28.16-3.072-29.1328-2.5088c-24.576-1.792-50.0736-2.9184-76.1344-3.2256L512 409.6z" fill="#ffffff" p-id="4984"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="24px" height="24px" viewBox="0 0 24 24" class="h-6 w-6"><g id="tool-seg-threshold" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><rect id="Rectangle" x="0" y="0" width="24" height="24"></rect><g id="Group" transform="translate(2.4184, 14.3673)" stroke="currentColor" stroke-width="1.5"><line x1="16.5816327" y1="2.13265306" x2="19.0816327" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><line x1="0.0816326531" y1="2.13265306" x2="12.0816327" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><circle id="Oval" cx="14.2244898" cy="2.09183673" r="2.09183673"></circle></g><g id="Group" transform="translate(11.7092, 7.4592) scale(-1, 1) translate(-11.7092, -7.4592)translate(1.9184, 5.3673)" stroke="currentColor" stroke-width="1.5"><line x1="16" y1="2.13265306" x2="19.0816327" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><line x1="0.0816326531" y1="2.13265306" x2="11" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><circle id="Oval" cx="13.2244898" cy="2.09183673" r="2.09183673"></circle></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+2 -2
View File
@@ -1608,7 +1608,7 @@ Enroll: Enrolled Confirmation`,
'trials:notice:table:appendix': `Attachment`,
'trials:notice:table:isRead': `Readed`,
'trials:notice:action:detail': `Details`,
'login:title:system': `IRC Imaging System`,
'login:title:system': `EIC lmaging Trial Management System`,
'login:form:userName': `User ID`,
'login:form:password': `Password`,
'login:button:login': `Login`,
@@ -1672,7 +1672,7 @@ Enroll: Enrolled Confirmation`,
'trials:tab:trials': `My Trials`,
'trials:trials:title:back': `Return`,
'trials:trials:title:backTrialList': `Return to trial list`,
'trials:trials:title:eics': `IRC Imaging System`,
'trials:trials:title:eics': `EIC lmaging Trial Management System`,
'trials:tab:reading': `Reads`,
'trials:tab:pendingReadingTasks': `Pending`,
'trials:pendingReadingTasks:table:subjectCode': `Subject ID`,
+11 -12
View File
@@ -2,11 +2,7 @@
<div class="navbar navbar-flex-wrapper">
<div class="leftMenu">
<div class="navbar-flex-wrapper">
<hamburger
:is-active="sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb class="breadcrumb-container" />
</div>
@@ -51,12 +47,8 @@
<TopLang></TopLang>
</div>
</div>
<toggleRole
v-if="toggleRoleVisible"
:visible.sync="toggleRoleVisible"
:loading="toggleRoleLoading"
@save="loginByRole"
/>
<toggleRole v-if="toggleRoleVisible" :visible.sync="toggleRoleVisible" :loading="toggleRoleLoading"
@save="loginByRole" />
</div>
</template>
@@ -192,12 +184,14 @@ export default {
flex-direction: row;
justify-content: space-between;
}
.navbar {
height: 50px;
overflow: hidden;
// position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 46px;
height: 100%;
@@ -218,7 +212,8 @@ export default {
.right-menu {
// float: right;
height: 100%;
line-height: 50px;
line-height: 65px;
// position: relative;
&:focus {
outline: none;
@@ -245,6 +240,7 @@ export default {
.avatar-container {
display: inline-block;
margin-right: 200px;
.user-avatar {
margin-top: 5px;
width: 40px;
@@ -252,16 +248,19 @@ export default {
border-radius: 10px;
}
}
.dropdown-container {
// margin-left: 30px;
// position: absolute;
// right: 20px;
// top: 0px;
cursor: pointer;
.el-icon-caret-bottom {
font-size: 12px;
}
}
.el-dropdown-link {
color: #999c9e;
cursor: pointer;
@@ -3,14 +3,16 @@
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="!onlyOneChild.hidden" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}" @click="handleClick(onlyOneChild.meta.title)">
<item :icon="onlyOneChild.meta ? (onlyOneChild.meta.icon||(item.meta&&item.meta.icon)) : null" :title="onlyOneChild.meta ? onlyOneChild.meta.title : null" />
<!-- :title="onlyOneChild.meta ? onlyOneChild.meta.title : null" -->
<item :icon="onlyOneChild.meta ? (onlyOneChild.meta.icon||(item.meta&&item.meta.icon)) : null" :title="onlyOneChild.meta.i18n ? $t(onlyOneChild.meta.i18n) : null" />
</el-menu-item>
</app-link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
<!-- :title="item.meta.title" -->
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.i18n ? $t(item.meta.i18n) : null" />
</template>
<sidebar-item
v-for="child in item.children"
+2 -2
View File
@@ -1,11 +1,11 @@
<template>
<el-dropdown
style="height:50px;line-height: 60px;"
style="height:50px;line-height: 65px;"
@command="handleSetLanguage"
>
<span class="el-dropdown-link">
<svg-icon icon-class="language" style="font-size:25px;margin:0 10px;" />
<svg-icon icon-class="language" style="font-size:20px;margin:0 10px;" />
<!-- {{ language==='zh'?'语言:中文':'Language: English' }} -->
<!-- <i class="el-icon-arrow-down el-icon--right" /> -->
</span>
+4 -2
View File
@@ -56,8 +56,10 @@ export default {
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.module.scss";
@use "@/styles/mixin.scss" as *;
@use "@/styles/variables.module.scss" as *;
// @import "~@/styles/mixin.scss";
// @import "~@/styles/variables.module.scss";
.app-wrapper {
@include clearfix;
+165 -149
View File
@@ -1,5 +1,6 @@
import Vue from 'vue'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
// import { createVersionPolling } from "@/utils/version-polling.esm.js";
import ElementUI, { MessageBox } from 'element-ui'
@@ -26,8 +27,9 @@ Vue.use(VueClipboard)
import permission from './utils/permission'
Vue.use(permission)
import { formatSize } from "./utils"
import { formatSize, guidToColor } from "./utils"
Vue.prototype.$FormatSize = formatSize
Vue.prototype.$GuidToColor = guidToColor
import Viewer from 'v-viewer'
import './assets/css/viewer.css'
@@ -61,12 +63,17 @@ import Onlyoffice from '@/components/Preview_onlyoffice/index'
Vue.use(Onlyoffice)
import Video from '@/components/Preview_video/index'
Vue.use(Video)
import AGR from '@/components/AGR/index'
Vue.use(AGR)
import MFA from '@/components/MFA/index'
Vue.use(MFA)
import FB from '@/components/feedBack/index'
Vue.use(FB)
import FBT from '@/components/feedBackTable/index'
Vue.use(FBT)
import resize from '@/directive/resize/index'
// 表格自适应指令
Vue.use(resize)
import adaptive from '@/directive/adaptive/index'
// 表格自适应指令
Vue.use(adaptive)
@@ -331,8 +338,10 @@ async function VueInit() {
})
}
let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo'))
if (CompanyInfo && CompanyInfo.SystemShortName && text.toUpperCase() !== "CIRCLE") {
let test = new RegExp('IRC', 'ig')
if (CompanyInfo && CompanyInfo.SystemShortName && (text.toUpperCase() !== "CIRCLE")) {
// 精准匹配独立单词 IRC
// let test = new RegExp('IRC', 'ig')
let test = new RegExp('\\bIRC\\b', 'ig')
text = text.replace(test, CompanyInfo.SystemShortName)
}
// return i18n.t(key)
@@ -443,6 +452,7 @@ async function VueInit() {
isOpen = false
isLock = null
zzSessionStorage.removeItem('isLock')
DicomEvent.$emit('isLock', false)
router.push("/login")
}).then(() => {
// _vm.$alert(lang === 'zh' ? '由于您长时间未操作,为保护您的数据安全已强制将您下线,如果需要继续操作请重新登陆!' : 'No operation for a long time non-operation, you have been forced logout to protect data security. If continue to operate, please login again!', {
@@ -454,160 +464,166 @@ async function VueInit() {
})
} : () => { }, process.env.VUE_APP_LOGOUT_FOR_TIME,
eval(process.env.VUE_APP_LOCK_FOR_PERMISSION) ? () => {
var lang = zzSessionStorage.getItem('lang') ? zzSessionStorage.getItem('lang') : 'zh'
if (_vm.$store.state.trials.unlock || WHITELIST.includes(_vm.$route.path)) {
count = 0;
localStorage.setItem('count', '0')
if (_vm.$route.path === '/login') {
zzSessionStorage.removeItem('lastWorkbench')
zzSessionStorage.removeItem('isLock')
isLock = null
}
return
}
if (isOpen) {
return
}
isOpen = true
zzSessionStorage.setItem('isLock', 'true')
_vm.$msgbox({
title: _vm.$t("env:lock:msgBox:title"),
confirmButtonText: _vm.$t("env:lock:msgBox:confirmButtonText"),
showClose: false,
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
if (!_vm.unlock.my_username) {
_vm.$message.warning(_vm.$t("env:lock:msgBox:iupUser"))
return
}
if (!_vm.unlock.my_password) {
_vm.$message.warning(_vm.$t("env:lock:msgBox:inpPassword"))
return
}
var my_username = zzSessionStorage.getItem('my_username')
var my_password = zzSessionStorage.getItem('my_password')
let my_userid = zzSessionStorage.getItem('userId')
let my_EMail = zzSessionStorage.getItem('my_EMail') || ''
if (md5(_vm.unlock.my_password) === my_password && (my_username === _vm.unlock.my_username || my_EMail.toUpperCase() === _vm.unlock.my_username.toUpperCase())) {
resetReadingRestTime().then(() => {
})
const closeLock = (_vm) => {
_vm.$message.success(_vm.$t("env:lock:msgBox:lockSuccess"))
_vm.unlock = {
my_username: null,
my_password: null,
view: false
}
isOpen = false
count = 0;
isLock = null
zzSessionStorage.removeItem('isLock')
localStorage.setItem('count', '0')
document.querySelector('#my_username').value = null
document.querySelector('#my_password').value = null
setTimeout(() => {
done()
}, 500)
}
// if (eval(process.env.VUE_APP_LOCK_FOR_PERMISSION_MFA)) {
// sendMFAEmail({ UserId: my_userid, MfaType: 1 }).then((res) => {
// done();
// Vue.prototype.$MFA({
// status: "lock",
// UserId: my_userid,
// EMail: res.Result,
// username: my_username,
// callBack: () => {
// closeLock(_vm)
// },
// })
// })
// } else {
closeLock(_vm)
// }
} else {
// console.log(111)
_vm.$message.error(_vm.$t('env:lock:msgBox:userFail'))
}
eval(process.env.VUE_APP_LOCK_FOR_PERMISSION)
? () => {
var lang = zzSessionStorage.getItem('lang') ? zzSessionStorage.getItem('lang') : 'zh'
if (_vm.$store.state.trials.unlock || WHITELIST.includes(_vm.$route.path)) {
count = 0;
localStorage.setItem('count', '0')
if (_vm.$route.path === '/login') {
zzSessionStorage.removeItem('lastWorkbench')
zzSessionStorage.removeItem('isLock')
DicomEvent.$emit('isLock', false)
isLock = null
}
},
message: h('div', {}, [
h('el-form', {
props: { labelWidth: "80px" }
}, [
h('el-form-item', {
props: { label: _vm.$t("env:lock:msgBox:form:username") },
}, [
h('input', {
props: {
value: _vm.unlock.my_username
},
attrs: {
id: 'my_username',
class: 'el-input__inner',
autocomplete: 'new-password'
},
on: {
change: (event) => {
_vm.unlock.my_username = event.target.value
},
input: (event) => {
_vm.unlock.my_username = event.target.value
}
}
})
]),
h('el-form-item', {
props: { label: _vm.$t("env:lock:msgBox:form:Password") },
attrs: {
style: "position: relative;"
return
}
if (isOpen) {
return
}
isOpen = true
zzSessionStorage.setItem('isLock', 'true')
DicomEvent.$emit('isLock', true)
_vm.$msgbox({
title: _vm.$t("env:lock:msgBox:title"),
confirmButtonText: _vm.$t("env:lock:msgBox:confirmButtonText"),
showClose: false,
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
if (!_vm.unlock.my_username) {
_vm.$message.warning(_vm.$t("env:lock:msgBox:iupUser"))
return
}
}, [
h('input', {
props: {
value: _vm.unlock.my_password
},
ref: "unlock_my_password_input",
attrs: {
id: 'my_password',
class: 'el-input__inner',
type: _vm.unlock.view ? 'text' : 'password',
autocomplete: 'new-password',
style: "padding-right:25px"
},
on: {
change: (event) => {
_vm.unlock.my_password = event.target.value
},
input: (event) => {
_vm.unlock.my_password = event.target.value
if (!_vm.unlock.my_password) {
_vm.$message.warning(_vm.$t("env:lock:msgBox:inpPassword"))
return
}
var my_username = zzSessionStorage.getItem('my_username')
var my_password = zzSessionStorage.getItem('my_password')
let my_userid = zzSessionStorage.getItem('userId')
let my_EMail = zzSessionStorage.getItem('my_EMail') || ''
if (md5(_vm.unlock.my_password) === my_password && (my_username === _vm.unlock.my_username || my_EMail.toUpperCase() === _vm.unlock.my_username.toUpperCase())) {
resetReadingRestTime().then(() => {
})
const closeLock = (_vm) => {
_vm.$message.success(_vm.$t("env:lock:msgBox:lockSuccess"))
_vm.unlock = {
my_username: null,
my_password: null,
view: false
}
isOpen = false
count = 0;
isLock = null
zzSessionStorage.removeItem('isLock')
DicomEvent.$emit('isLock', false)
localStorage.setItem('count', '0')
document.querySelector('#my_username').value = null
document.querySelector('#my_password').value = null
setTimeout(() => {
done()
}, 500)
}
}),
h('i', {
attrs: {
id: 'my_password_view',
class: "el-icon-view",
style: "cursor: pointer;position: absolute;top:35%;right:10px"
},
on: {
click: (event) => {
_vm.unlock.view = !_vm.unlock.view
if (_vm.unlock.view) {
_vm.$refs['unlock_my_password_input'].type = "text"
} else {
_vm.$refs['unlock_my_password_input'].type = "password"
}
// if (eval(process.env.VUE_APP_LOCK_FOR_PERMISSION_MFA)) {
// sendMFAEmail({ UserId: my_userid, MfaType: 1 }).then((res) => {
// done();
// Vue.prototype.$MFA({
// status: "lock",
// UserId: my_userid,
// EMail: res.Result,
// username: my_username,
// callBack: () => {
// closeLock(_vm)
// },
// })
// })
// } else {
closeLock(_vm)
// }
} else {
// console.log(111)
_vm.$message.error(_vm.$t('env:lock:msgBox:userFail'))
}
}
},
message: h('div', {}, [
h('el-form', {
props: { labelWidth: "80px" }
}, [
h('el-form-item', {
props: { label: _vm.$t("env:lock:msgBox:form:username") },
}, [
h('input', {
props: {
value: _vm.unlock.my_username
},
attrs: {
id: 'my_username',
class: 'el-input__inner',
autocomplete: 'new-password'
},
on: {
change: (event) => {
_vm.unlock.my_username = event.target.value
},
input: (event) => {
_vm.unlock.my_username = event.target.value
}
}
})
]),
h('el-form-item', {
props: { label: _vm.$t("env:lock:msgBox:form:Password") },
attrs: {
style: "position: relative;"
}
}),
}, [
h('input', {
props: {
value: _vm.unlock.my_password
},
ref: "unlock_my_password_input",
attrs: {
id: 'my_password',
class: 'el-input__inner',
type: _vm.unlock.view ? 'text' : 'password',
autocomplete: 'new-password',
style: "padding-right:25px"
},
on: {
change: (event) => {
_vm.unlock.my_password = event.target.value
},
input: (event) => {
_vm.unlock.my_password = event.target.value
}
}
}),
h('i', {
attrs: {
id: 'my_password_view',
class: "el-icon-view",
style: "cursor: pointer;position: absolute;top:35%;right:10px"
},
on: {
click: (event) => {
_vm.unlock.view = !_vm.unlock.view
if (_vm.unlock.view) {
_vm.$refs['unlock_my_password_input'].type = "text"
} else {
_vm.$refs['unlock_my_password_input'].type = "password"
}
},
}
}),
])
])
])
])
})
} : () => { }, process.env.VUE_APP_LOCK_FOR_TIME)
})
} : () => { },
process.env.VUE_APP_LOCK_FOR_TIME
)
}
VueInit()
// createVersionPolling({
+2 -2
View File
@@ -15,7 +15,7 @@ NProgress.configure({ showSpinner: false })
const whiteList = WHITELIST
store.state.trials.whiteList = whiteList
router.beforeEach(async(to, from, next) => {
router.beforeEach(async (to, from, next) => {
NProgress.start()
// 设置页面标题
// document.title = getPageTitle(to.meta.title) store.state.trials.whiteList.indexOf(to.path) === -1
@@ -60,7 +60,7 @@ router.beforeEach(async(to, from, next) => {
Vue.prototype.toPath = to.path
Vue.prototype.$path = []
if (hasToken) {
if (to.path === '/login' || to.path === '/recompose' || to.path === '/email-recompose' || to.path === '/error' || to.path === '/ReviewersResearchForm' || to.path === '/ReviewersResearch') {
if (to.path === '/login' || to.path === '/recompose' || to.path === '/email-recompose' || to.path === '/link_expired' || to.path === '/error' || to.path === '/ReviewersResearchForm' || to.path === '/ReviewersResearch') {
if (to.path === '/ReviewersResearch') {
await OSSclient()
await store.dispatch('user/logout')
+16 -6
View File
@@ -79,6 +79,12 @@ export const constantRoutes = [
name: 'emailRecompose',
hidden: true
},
{
path: '/user-recompose',
component: () => import('@/views/email-recompose/index'),
name: 'userRecompose',
hidden: true
},
{
path: '/joinVerify',
component: () => import('@/views/joinVerify/index'),
@@ -122,6 +128,11 @@ export const constantRoutes = [
hidden: true,
component: () => import('@/views/none-dicom-show/index')
},
{
path: '/none_dicoms',
hidden: true,
component: () => import('@/views/none-dicoms/index')
},
{
path: '/noneDicomReading',
name: 'noneDicomReading',
@@ -150,12 +161,6 @@ export const constantRoutes = [
hidden: true,
component: () => import('@/views/trials/trials-panel/reading/dicoms/components/Fusion/PetCt')
},
{
path: '/fusion',
name: 'fusion',
hidden: true,
component: () => import('@/views/trials/trials-panel/reading/dicoms/components/Fusion/demo/index')
},
{
path: '/historyScreenshot',
@@ -278,6 +283,11 @@ export const constantRoutes = [
component: () => import('@/views/error'),
hidden: true
},
{
path: '/link_expired',
component: () => import('@/views/linkExpired'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
+1 -1
View File
@@ -1,7 +1,7 @@
// eslint-disable-next-line no-undef
module.exports = {
title: 'IRC Imaging System',
title: 'HASC lmaging Trial Management System',
/**
* @type {boolean} true | false
+1
View File
@@ -34,6 +34,7 @@ const getters = {
paymentHistoryQuery: state => state.financials.paymentHistoryQuery,
revenusQuery: state => state.financials.revenusQuery,
visitTaskList: state => state.reading.visitTaskList,
BodyPart: state => state.reading.BodyPart,
organList: state => state.reading.organList,
seriesStack: state => state.reading.seriesStack,
activeHangingAgreement: state => state.reading.activeHangingAgreement,
+8 -1
View File
@@ -128,7 +128,14 @@ const actions = {
if (response.IsSuccess) {
var noticeList = []
response.Result.forEach(el => {
noticeList.push({ Id: el.Id, Content: el.NoticeContent, NoticeTypeEnum: el.NoticeTypeEnum })
noticeList.push({
Id: el.Id,
Content: el.NoticeContent,
NoticeTypeEnum: el.NoticeTypeEnum,
PublishedTime: el.PublishedTime,
FileName: el.FileName,
Path: el.Path
})
})
commit('SET_NOTICE', noticeList)
+1
View File
@@ -39,6 +39,7 @@ function filterAsyncRouter(asyncRouterMap = [], lastRouter = false, type = false
// eslint-disable-next-line
route.meta = eval('(' + route.Meta + ')')
route.meta.icon = route.MenuIcon
route.meta.i18n = route.LanguageMark
delete route.Meta
}
delete route.MenuIcon
+69 -2
View File
@@ -32,13 +32,21 @@ const getDefaultState = () => {
lastCanvasTaskId: '',
imageQuality: null,
imageQualityIssues: null,
currentLoadIns: []
currentLoadIns: [],
BodyPart: []
}
}
function getQuestions(questions) {
const criterionType = parseInt(localStorage.getItem('CriterionType'))
questions.forEach(item => {
if ((item.Type === 'table' || item.Type === 'basicTable') && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
item.TableQuestions.Questions.forEach(question => {
if (question.Type === 'select' && question.OptionTypeEnum === 1) {
item.TableQuestions.Answers.forEach((answer) => {
answer[question.Id] = answer[question.Id] ? JSON.parse(answer[question.Id]) : []
})
}
})
item.TableQuestions.Answers.forEach(answerObj => {
answerObj.isDicomReading = answerObj.IsDicomReading === 'True'
@@ -71,7 +79,7 @@ function getQuestions(questions) {
answerObj.angle = angle
answerObj.saveTypeEnum = isNaN(parseFloat(angle)) ? 1 : 2
}
} else if (criterionType === 21) {
} else if (criterionType === 21 || criterionType === 22) {
// MRI-PDFF
let isMeasurable = getQuestionAnswer(item.TableQuestions.Questions, 1105, answerObj)
answerObj.isMeasurable = isMeasurable
@@ -171,6 +179,45 @@ function getQuestionAnswer(questions, questionMark, answers) {
return ''
}
}
function getQuerys(e) {
if (!e) return "";
var t = {},
r = [],
n = "",
a = "";
try {
var i = [];
if (e.indexOf("?") >= 0 && (i = e.substring(e.indexOf("?") + 1, e.length).split("&")), i.length > 0) for (var o in i) n = (r = i[o].split("="))[0],
a = r[1],
t[n] = a
} catch (s) {
t = {}
}
return t
}
async function getBodyPart(bodyPart, other) {
if (!bodyPart && !other) return ''
var separator = ','
if (bodyPart.indexOf('|') > -1) {
separator = '|'
} else if (bodyPart.indexOf(',') > -1) {
separator = ','
} else if (bodyPart.indexOf('') > -1) {
separator = ''
}
let BodyPart = {}
let query = getQuerys(window.location.href)
BodyPart.Bodypart = await Vue.prototype.$getBodyPart(query.trialId)
var arr = bodyPart.split(separator)
var newArr = arr.map((i) => {
return Vue.prototype.$fd('Bodypart', i.trim(), 'Code', BodyPart, 'Name')
})
if (other) {
newArr.push(other)
}
newArr = newArr.filter(Boolean)
return newArr
}
// function getKeySeriesInfo(keyInstance, series) {
// const obj = {}
// const set = new Set()
@@ -850,6 +897,20 @@ const actions = {
var studyList = []
var keyImages = []
getReadingVisitStudyList(obj.trialId, obj.subjectVisitId, obj.visitTaskId).then(res => {
try {
state.BodyPart = []
res.Result.forEach(async item => {
let arr = await getBodyPart(item.BodyPartForEdit, item.BodyPartForEditOther)
state.BodyPart.push({
StudyId: item.StudyId,
StudyCode: item.StudyCode,
BodyPart: arr,
Modalities: item.Modalities
})
})
} catch (err) {
console.log(err)
}
const i = res.Result.findIndex(i => i.IsCriticalSequence)
if (i > -1) {
const seriesList = res.Result[i].SeriesList && res.Result[i].SeriesList
@@ -871,6 +932,12 @@ const actions = {
data.IsDicom = study.IsDicom
data.PreviewImageCount = 0
data.IsCriticalSequence = study.IsCriticalSequence
data.PatientSex = study.PatientSex
data.PatientWeight = study.PatientWeight
data.RadionuclideHalfLife = study.RadionuclideHalfLife
data.RadionuclideTotalDose = study.RadionuclideTotalDose
data.RadiopharmaceuticalStartTime = study.RadiopharmaceuticalStartTime
data.AcquisitionTime = study.AcquisitionTime
var seriesList = []
study.SeriesList.forEach((series, seriesIndex) => {
const imageIds = []
+9 -1
View File
@@ -121,7 +121,7 @@ const actions = {
localStorage.setItem('CompanyInfo', JSON.stringify(response.Result.CompanyInfo))
const data = response.Result
commit('SET_ROLES', data.BasicInfo.AccountList)
if (data.BasicInfo.IsFirstAdd || data.BasicInfo.LoginState === 1) {
if (data.BasicInfo.IsFirstAdd || data.BasicInfo.LoginState === 1 || data.BasicInfo.IsNeedResetPwd) {
try {
zzSessionStorage.setItem('userId', data.BasicInfo.Id)
commit('SET_TOKEN', data.JWTStr)
@@ -276,6 +276,14 @@ const actions = {
async logout({ commit, state }) {
try {
removeToken() // must remove token first
let data = {
IdentityUserId: zzSessionStorage.getItem('identityUserId')
}
if (zzSessionStorage.getItem('userId') && zzSessionStorage.getItem('userId') !== 'undefined') {
data.UserRoleId = zzSessionStorage.getItem('userId')
} else {
data.UserRoleId = null
}
await loginOut({
UserRoleId: zzSessionStorage.getItem('userId'),
IdentityUserId: zzSessionStorage.getItem('identityUserId'),
+58 -35
View File
@@ -1,15 +1,16 @@
@import "./variables.module.scss";
@import "./mixin.scss";
@import "./transition.scss";
@import "./element-ui.scss";
@import "./sidebar.scss";
@use "./variables.module.scss";
@use "./mixin.scss";
@use "./transition.scss";
@use "./element-ui.scss";
@use "./sidebar.scss";
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
// font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
// "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial,
@@ -205,139 +206,143 @@ body .el-table th.gutter {
.el-descriptions {
box-sizing: border-box;
font-size: 14px;
color: #303133
color: #303133;
}
.el-descriptions__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px
margin-bottom: 20px;
}
.el-descriptions__title {
font-size: 16px;
font-weight: 700
font-weight: 700;
}
.el-descriptions__body {
color: #606266;
background-color: #fff
background-color: #fff;
}
.el-descriptions__body .el-descriptions__table {
border-collapse: collapse;
width: 100%;
table-layout: fixed
table-layout: fixed;
}
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell {
box-sizing: border-box;
text-align: left;
font-weight: 400;
line-height: 1.5
line-height: 1.5;
}
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-left {
text-align: left
text-align: left;
}
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center {
text-align: center
text-align: center;
}
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right {
text-align: right
text-align: right;
}
.el-descriptions .is-bordered {
table-layout: auto
table-layout: auto;
}
.el-descriptions .is-bordered .el-descriptions-item__cell {
border: 1px solid #ebeef5;
padding: 12px 10px
padding: 12px 10px;
}
.el-descriptions :not(.is-bordered) .el-descriptions-item__cell {
padding-bottom: 12px
padding-bottom: 12px;
}
.el-descriptions--medium.is-bordered .el-descriptions-item__cell {
padding: 10px
padding: 10px;
}
.el-descriptions--medium:not(.is-bordered) .el-descriptions-item__cell {
padding-bottom: 10px
padding-bottom: 10px;
}
.el-descriptions--small {
font-size: 12px
font-size: 12px;
}
.el-descriptions--small.is-bordered .el-descriptions-item__cell {
padding: 8px 10px
padding: 8px 10px;
}
.el-descriptions--small:not(.is-bordered) .el-descriptions-item__cell {
padding-bottom: 8px
padding-bottom: 8px;
}
.el-descriptions--mini {
font-size: 12px
font-size: 12px;
}
.el-descriptions--mini.is-bordered .el-descriptions-item__cell {
padding: 6px 10px
padding: 6px 10px;
}
.el-descriptions--mini:not(.is-bordered) .el-descriptions-item__cell {
padding-bottom: 6px
padding-bottom: 6px;
}
.el-descriptions-item {
vertical-align: top
vertical-align: top;
}
.el-descriptions-item__container {
display: flex
display: flex;
}
.el-descriptions-item__container .el-descriptions-item__content,
.el-descriptions-item__container .el-descriptions-item__label {
display: inline-flex;
align-items: baseline
align-items: baseline;
}
.el-descriptions-item__container .el-descriptions-item__content {
flex: 1
flex: 1;
}
.el-descriptions-item__label.has-colon:after {
content: ":";
position: relative;
top: -.5px
top: -0.5px;
}
.el-descriptions-item__label.is-bordered-label {
font-weight: 700;
color: #909399;
background: #fafafa
background: #fafafa;
}
.el-descriptions-item__label:not(.is-bordered-label) {
margin-right: 10px
margin-right: 10px;
}
.el-descriptions-item__content {
word-break: break-word;
overflow-wrap: break-word
overflow-wrap: break-word;
}
.feedBack-box {
.el-dialog__wrapper {
z-index: 3999 !important;
}
.el-popper {
z-index: 4000 !important;
}
}
.feedBack-select-box {
@@ -350,11 +355,29 @@ body .el-table th.gutter {
top: 0;
width: 100%;
height: 100%;
opacity: .5;
opacity: 0.5;
background: #000;
z-index: 3999;
}
.el-message-box__wrapper {
z-index: 9999 !important;
}
.svg-readingChart {
width: 28px !important;
height: 30px !important;
margin-left: 10px;
cursor: pointer;
}
.svg-readingChart-mini {
width: 18px !important;
height: 20px !important;
vertical-align: -0.4em !important;
cursor: pointer;
}
.mobile_confirm {
width: 200px;
}
+346
View File
@@ -0,0 +1,346 @@
class FileNameSorter {
/**
* 判断是否为纯数字字符串
* @param {any} value - 要检查的值
* @returns {boolean} 是否为纯数字
*/
static isPureNumber(value) {
if (typeof value !== 'string') return false;
return /^\d+$/.test(value);
}
/**
* 获取排序键值
* @param {any} item - 要排序的项目
* @returns {Array} 排序键值数组
*/
static getSortKey(item) {
const str = String(item);
const isNumber = this.isPureNumber(str);
// 排序优先级: [类型优先级, 数字值/字符串值]
if (isNumber) {
// 纯数字: 类型优先级为0, 使用数字值排序
return [0, BigInt(str)];
} else {
// 非纯数字: 类型优先级为1, 使用字符串排序
return [1, str.toLowerCase()];
}
}
/**
* 文件名排序
* @param {Array} arr - 要排序的数组
* @param {Object} options - 排序选项
* @returns {Array} 排序后的数组
*/
static sortFileNames(arr, options = {}) {
if (!Array.isArray(arr)) {
throw new TypeError('输入必须是一个数组');
}
const {
direction = 'asc', // 'asc' 升序, 'desc' 降序
caseSensitive = false, // 是否区分大小写
trim = true, // 是否去除前后空格
key = null
} = options;
// 创建数组的副本
const result = [...arr];
return result.sort((a, b) => {
let aStr = key ? String(a[key]).split(".")[0] : String(a);
let bStr = key ? String(b[key]).split(".")[0] : String(b);
// 处理空格
if (trim) {
aStr = aStr.trim();
bStr = bStr.trim();
}
// 处理大小写
if (!caseSensitive) {
aStr = aStr.toLowerCase();
bStr = bStr.toLowerCase();
}
// 获取排序键值
const aKey = this.getSortKey(aStr);
const bKey = this.getSortKey(bStr);
// 比较类型优先级
if (aKey[0] !== bKey[0]) {
// 纯数字(0) < 非纯数字(1)
return direction === 'asc' ? aKey[0] - bKey[0] : bKey[0] - aKey[0];
}
// 相同类型下的比较
if (aKey[0] === 0) {
// 都是纯数字,按数字大小比较
if (aKey[1] < bKey[1]) return direction === 'asc' ? -1 : 1;
if (aKey[1] > bKey[1]) return direction === 'asc' ? 1 : -1;
return 0;
} else {
// 都是非纯数字,按字符串比较
if (aStr < bStr) return direction === 'asc' ? -1 : 1;
if (aStr > bStr) return direction === 'asc' ? 1 : -1;
return 0;
}
});
}
/**
* 自然排序 - 处理文件名中的数字序列
* 例如: file1, file2, file10
* @param {Array} arr - 要排序的数组
* @param {Object} options - 排序选项
* @returns {Array} 排序后的数组
*/
static naturalSort(arr, options = {}) {
const {
direction = 'asc',
caseSensitive = false
} = options;
return [...arr].sort((a, b) => {
const aStr = String(a);
const bStr = String(b);
// 检查是否都是纯数字
const aIsPureNumber = this.isPureNumber(aStr);
const bIsPureNumber = this.isPureNumber(bStr);
// 如果一个纯数字,一个非纯数字
if (aIsPureNumber && !bIsPureNumber) {
return direction === 'asc' ? -1 : 1;
}
if (!aIsPureNumber && bIsPureNumber) {
return direction === 'asc' ? 1 : -1;
}
// 都是纯数字,按数字比较
if (aIsPureNumber && bIsPureNumber) {
const aNum = BigInt(aStr);
const bNum = BigInt(bStr);
if (aNum < bNum) return direction === 'asc' ? -1 : 1;
if (aNum > bNum) return direction === 'asc' ? 1 : -1;
return 0;
}
// 都是非纯数字,使用自然排序算法
return this.naturalCompare(aStr, bStr, direction, caseSensitive);
});
}
/**
* 自然比较算法
* @private
*/
static naturalCompare(a, b, direction = 'asc', caseSensitive = false) {
let aStr = caseSensitive ? a : a.toLowerCase();
let bStr = caseSensitive ? b : b.toLowerCase();
const regex = /(\d+|\D+)/g;
const aParts = aStr.match(regex) || [];
const bParts = bStr.match(regex) || [];
const maxLength = Math.max(aParts.length, bParts.length);
for (let i = 0; i < maxLength; i++) {
const aPart = aParts[i] || '';
const bPart = bParts[i] || '';
const aIsNumber = /^\d+$/.test(aPart);
const bIsNumber = /^\d+$/.test(bPart);
// 如果都是数字,按数字比较
if (aIsNumber && bIsNumber) {
const aNum = BigInt(aPart);
const bNum = BigInt(bPart);
if (aNum < bNum) return direction === 'asc' ? -1 : 1;
if (aNum > bNum) return direction === 'asc' ? 1 : -1;
continue;
}
// 都是文本,按字符串比较
if (aPart < bPart) return direction === 'asc' ? -1 : 1;
if (aPart > bPart) return direction === 'asc' ? 1 : -1;
}
return 0;
}
/**
* 分组排序 - 将纯数字和非纯数字分开显示
* @param {Array} arr - 要排序的数组
* @param {Object} options - 排序选项
* @returns {Array} 排序后的数组
*/
static groupSort(arr, options = {}) {
const {
direction = 'asc',
groupOrder = 'numbers-first' // 'numbers-first' 或 'names-first'
} = options;
// 分组
const numbers = [];
const names = [];
arr.forEach(item => {
const str = String(item);
if (this.isPureNumber(str)) {
numbers.push(item);
} else {
names.push(item);
}
});
// 对各组排序
const sortedNumbers = this.sortFileNames(numbers, { direction });
const sortedNames = this.sortFileNames(names, { direction });
// 按指定顺序合并
if (groupOrder === 'numbers-first') {
return [...sortedNumbers, ...sortedNames];
} else {
return [...sortedNames, ...sortedNumbers];
}
}
/**
* 文件扩展名排序 - 先按扩展名排序再按文件名排序
* @param {Array} arr - 要排序的数组
* @param {Object} options - 排序选项
* @returns {Array} 排序后的数组
*/
static sortByExtension(arr, options = {}) {
const {
direction = 'asc',
extensionsFirst = false // 扩展名优先还是文件名优先
} = options;
return [...arr].sort((a, b) => {
const aStr = String(a);
const bStr = String(b);
// 分离文件名和扩展名
const getFileParts = (str) => {
const lastDotIndex = str.lastIndexOf('.');
if (lastDotIndex > 0) {
return {
name: str.substring(0, lastDotIndex),
ext: str.substring(lastDotIndex + 1)
};
}
return { name: str, ext: '' };
};
const aParts = getFileParts(aStr);
const bParts = getFileParts(bStr);
let compareResult;
if (extensionsFirst) {
// 先比较扩展名
compareResult = this.sortFileNames([aParts.ext, bParts.ext], { direction })[0] === aParts.ext ? -1 : 1;
if (compareResult !== 0) return compareResult;
// 扩展名相同,再比较文件名
return this.sortFileNames([aParts.name, bParts.name], { direction })[0] === aParts.name ? -1 : 1;
} else {
// 先比较文件名
compareResult = this.sortFileNames([aParts.name, bParts.name], { direction })[0] === aParts.name ? -1 : 1;
if (compareResult !== 0) return compareResult;
// 文件名相同,再比较扩展名
return this.sortFileNames([aParts.ext, bParts.ext], { direction })[0] === aParts.ext ? -1 : 1;
}
});
}
/**
* 测试和演示函数
*/
static demonstrate() {
const testData = [
'100',
'23',
'1',
'003',
'file.txt',
'10',
'5',
'alpha',
'beta',
'gamma',
'00100',
'zebra',
'apple',
'banana',
'123',
'file10.txt',
'file2.txt',
'File1.txt',
'file20.txt',
'image.jpg',
'document.pdf',
'data.xlsx'
];
console.log('=== 文件名排序演示 ===\n');
console.log('原始数据:');
console.log(testData);
console.log('\n1. 基本排序 (纯数字 < 非纯数字):');
const basicSorted = this.sortFileNames(testData);
console.log(basicSorted);
console.log('\n2. 自然排序 (智能数字识别):');
const naturalSorted = this.naturalSort(testData);
console.log(naturalSorted);
console.log('\n3. 分组排序 (数字组和文件组):');
const groupSorted = this.groupSort(testData);
console.log(groupSorted);
console.log('\n4. 降序排序:');
const descSorted = this.sortFileNames(testData, { direction: 'desc' });
console.log(descSorted);
console.log('\n5. 按扩展名排序:');
const extSorted = this.sortByExtension(testData);
console.log(extSorted);
console.log('\n6. 大小写敏感排序:');
const caseSensitiveSorted = this.sortFileNames(testData, { caseSensitive: true });
console.log(caseSensitiveSorted);
// 验证排序规则
console.log('\n=== 排序规则验证 ===');
const validationData = ['100', '23', 'file.txt', '1', 'alpha', '003', '10'];
console.log('验证数据:', validationData);
console.log('排序结果:', this.sortFileNames(validationData));
console.log('规则验证:');
console.log(' - 纯数字: 1, 3(003), 10, 23, 100 (按数字大小)');
console.log(' - 非纯数字: alpha, file.txt (按字母顺序)');
console.log(' - 非纯数字 > 纯数字');
return {
basic: basicSorted,
natural: naturalSorted,
group: groupSorted,
descending: descSorted,
byExtension: extSorted,
caseSensitive: caseSensitiveSorted
};
}
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = FileNameSorter;
} else if (typeof window !== 'undefined') {
window.FileNameSorter = FileNameSorter;
}
+3 -2
View File
@@ -1,6 +1,6 @@
import Vue from 'vue'
import { anonymization } from './anonymization'
export const dcmUpload = async function (data, config, progressFn) {
export const dcmUpload = async function (data, config, progressFn, fileInfo) {
return new Promise(async resolve => {
try {
// let blob = await encoder(file, config)
@@ -8,7 +8,8 @@ export const dcmUpload = async function (data, config, progressFn) {
if (config) {
blob = await anonymization(data.file, config)
}
let res = await Vue.prototype.OSSclient.multipartUpload(Object.assign(data, { file: blob.blob }), progressFn)
let res = await Vue.prototype.OSSclient.multipartUpload(Object.assign(data, { file: blob.blob }), progressFn, fileInfo)
resolve({
...res,
image: blob.pixelDataElement
+6 -2
View File
@@ -8366,7 +8366,7 @@
for (var i = 0; i < valarr.length; i++) {
var checkValue = valarr[i],
checklen = lengths[i],
checklen = lengths[i] || 0,
isString = false,
displaylen = checklen;
@@ -8508,6 +8508,8 @@
var binaryStream;
var _writeOptions$fragmen = writeOptions.fragmentMultiframe,
fragmentMultiframe = _writeOptions$fragmen === void 0 ? true : _writeOptions$fragmen;
var _writeOptions$offset = writeOptions.startOffset,
isNeedStartOffset = _writeOptions$offset === void 0 ? true : _writeOptions$offset;
value = value === null || value === undefined ? [] : value;
if (isEncapsulated) {
@@ -8535,7 +8537,9 @@
for (i = 0; i < frames; i++) {
var _needsPadding = Boolean(value[i].byteLength & 1);
startOffset.push(binaryStream.size);
if (isNeedStartOffset) {
startOffset.push(binaryStream.size);
}
var frameBuffer = value[i],
frameStream = new ReadBufferStream(frameBuffer);
var fragmentsLength = 1;
+343
View File
@@ -0,0 +1,343 @@
import getNumberValues from "./getNumberValues";
import isNMReconstructable from "./isNMReconstructable";
/**
* Get a subpart of Image Type dicom tag defined by index
* @param {*} dataSet
* @param {*} index 0 based index of the subtype
*/
function getImageTypeSubItemFromDataset(dataSet, index) {
const imageType = dataSet.string("x00080008");
if (imageType) {
const subTypes = imageType.split("\\");
if (subTypes.length > index) {
return subTypes[index];
}
}
return undefined;
}
// DICOM 标准中针对 Enhanced CT/MR/PET 等“增强型多帧”(Enhanced Multi-frame)影像, 强制要求为每一帧显式记录真实的独立空间坐标 。
// - 它们的数据通常存放在: Per-frame Functional Groups Sequence (5200,9230) -> 对应的 Frame Item -> Plane Position Sequence (0020,9113) -> ImagePositionPatient (0020,0032) 。
function getSharedFunctionalGroupsDataSet(dataSet) {
const seq = dataSet?.elements?.x52009229;
if (!seq?.items?.length) {
return;
}
return seq.items[0].dataSet;
}
function getPerFrameFunctionalGroupsDataSet(dataSet, frameIndex) {
const seq = dataSet?.elements?.x52009230;
if (!seq?.items?.length) {
return;
}
if (
!Number.isInteger(frameIndex) ||
frameIndex < 0 ||
frameIndex >= seq.items.length
) {
return;
}
return seq.items[frameIndex].dataSet;
}
function getOrientationFromPlaneOrientationSequence(dataSet) {
const seq = dataSet?.elements?.x00209116;
if (!seq?.items?.length) {
return;
}
return getNumberValues(seq.items[0].dataSet, "x00200037", 6);
}
function getPositionFromPlanePositionSequence(dataSet) {
const seq = dataSet?.elements?.x00209113;
if (!seq?.items?.length) {
return;
}
return getNumberValues(seq.items[0].dataSet, "x00200032", 3);
}
function getPixelSpacingFromPixelMeasuresSequence(dataSet) {
const seq = dataSet?.elements?.x00289110;
if (!seq?.items?.length) {
return;
}
return getNumberValues(seq.items[0].dataSet, "x00280030", 2);
}
function getSliceThicknessFromPixelMeasuresSequence(dataSet) {
const seq = dataSet?.elements?.x00289110;
if (!seq?.items?.length) {
return;
}
if (!seq.items[0]?.dataSet?.elements?.x00180050) {
return;
}
return seq.items[0].dataSet.floatString("x00180050");
}
/**
* Extracts the orientation from NM multiframe dataset, if image type
* equal to RECON TOMO or RECON GATED TOMO
* @param {*} dataSet
* @returns
*/
function extractOrientationFromNMMultiframeDataset(dataSet) {
let imageOrientationPatient;
const modality = dataSet.string("x00080060");
if (modality?.includes("NM")) {
const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2);
if (imageSubType && isNMReconstructable(imageSubType)) {
if (dataSet.elements.x00540022) {
imageOrientationPatient = getNumberValues(
dataSet.elements.x00540022.items[0].dataSet,
"x00200037",
6
);
}
}
}
return imageOrientationPatient;
}
/**
* Extracts the position from NM multiframe dataset, if image type
* equal to RECON TOMO or RECON GATED TOMO
* @param {*} dataSet
* @returns
*/
function extractPositionFromNMMultiframeDataset(dataSet) {
let imagePositionPatient;
const modality = dataSet.string("x00080060");
if (modality?.includes("NM")) {
const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2);
if (imageSubType && isNMReconstructable(imageSubType)) {
if (dataSet.elements.x00540022) {
imagePositionPatient = getNumberValues(
dataSet.elements.x00540022.items[0].dataSet,
"x00200032",
3
);
}
}
}
return imagePositionPatient;
}
function isMultiFrame(dataSet) {
const numberOfFrames =
dataSet.string("x00280008") || dataSet.uint16("x00280008");
return numberOfFrames !== undefined && Number(numberOfFrames) > 1;
}
/**
* Extract orientation information from a dataset. It tries to get the orientation
* from the Detector Information Sequence (for NM images) if image type equal
* to RECON TOMO or RECON GATED TOMO
* @param {*} dataSet
* @returns
*/
function extractOrientationFromDataset(dataSet) {
// let imageOrientationPatient;
// if (isMultiFrame(dataSet)) {
// const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
// dataSet,
// frameIndex
// );
// imageOrientationPatient =
// getOrientationFromPlaneOrientationSequence(perFrameDataSet);
// if (!imageOrientationPatient) {
// const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
// imageOrientationPatient =
// getOrientationFromPlaneOrientationSequence(sharedDataSet);
// }
// }
// if (!imageOrientationPatient) {
// imageOrientationPatient = getNumberValues(dataSet, "x00200037", 6);
// }
let imageOrientationPatient = getNumberValues(dataSet, "x00200037", 6)
// Trying to get the orientation from the Plane Orientation Sequence
if (!imageOrientationPatient && dataSet.elements.x00209116) {
imageOrientationPatient = getNumberValues(
dataSet.elements.x00209116.items[0].dataSet,
"x00200037",
6
);
}
// If orientation not valid to this point, trying to get the orientation
// from the Detector Information Sequence (for NM images) with image type
// equal to RECON TOMO or RECON GATED TOMO
if (!imageOrientationPatient) {
imageOrientationPatient =
extractOrientationFromNMMultiframeDataset(dataSet);
}
return imageOrientationPatient;
}
/**
* Extract position information from a dataset. It tries to get the position
* from the Detector Information Sequence (for NM images) if image type equal
* to RECON TOMO or RECON GATED TOMO
* @param {*} dataSet
* @returns
*/
function extractPositionFromDataset(dataSet) {
// let imagePositionPatient;
// if (isMultiFrame(dataSet)) {
// const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
// dataSet,
// frameIndex
// );
// imagePositionPatient =
// getPositionFromPlanePositionSequence(perFrameDataSet);
// if (!imagePositionPatient) {
// const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
// imagePositionPatient =
// getPositionFromPlanePositionSequence(sharedDataSet);
// }
// }
// if (!imagePositionPatient) {
// imagePositionPatient = getNumberValues(dataSet, "x00200032", 3);
// }
let imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
// Trying to get the position from the Plane Position Sequence
if (!imagePositionPatient && dataSet.elements.x00209113) {
imagePositionPatient = getNumberValues(
dataSet.elements.x00209113.items[0].dataSet,
"x00200032",
3
);
}
// If position not valid to this point, trying to get the position
// from the Detector Information Sequence (for NM images)
if (!imagePositionPatient) {
imagePositionPatient = extractPositionFromNMMultiframeDataset(dataSet);
}
return imagePositionPatient;
}
/**
* Extract the pixelSpacing information. If exists, extracts this information
* from Pixel Measures Sequence
* @param {*} dataSet
* @returns
*/
function extractSpacingFromDataset(dataSet) {
// let pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
// // If pixelSpacing not valid to this point, trying to get the spacing
// // from the Pixel Measures Sequence
// if (!pixelSpacing && dataSet.elements.x00289110) {
// pixelSpacing = getNumberValues(
// dataSet.elements.x00289110.items[0].dataSet,
// 'x00280030',
// 2
// );
// }
// return pixelSpacing;
let rowPixelSpacing = null;
let columnPixelSpacing = null;
// let pixelSpacing;
// if (isMultiFrame(dataSet)) {
// const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
// dataSet,
// frameIndex
// );
// const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
// pixelSpacing =
// getPixelSpacingFromPixelMeasuresSequence(perFrameDataSet) ||
// getPixelSpacingFromPixelMeasuresSequence(sharedDataSet);
// }
// if (!pixelSpacing) {
// pixelSpacing =
// getNumberValues(dataSet, "x00280030", 2) ||
// getPixelSpacingFromPixelMeasuresSequence(dataSet);
// }
let pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
const imagePixelSpacing = getNumberValues(dataSet, "x00181164", 2);
const estimatedRadiographicMagnificationFactor = getNumberValues(
dataSet,
"x00181114",
2
);
if (pixelSpacing) {
rowPixelSpacing = pixelSpacing[0];
columnPixelSpacing = pixelSpacing[1];
} else if (imagePixelSpacing && estimatedRadiographicMagnificationFactor) {
rowPixelSpacing =
imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0];
columnPixelSpacing =
imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1];
} else if (imagePixelSpacing && !estimatedRadiographicMagnificationFactor) {
rowPixelSpacing = imagePixelSpacing[0];
columnPixelSpacing = imagePixelSpacing[1];
}
return rowPixelSpacing !== null
? [rowPixelSpacing, columnPixelSpacing]
: undefined;
}
/**
* Extract the sliceThickness information. If exists, extracts this information
* from Pixel Measures Sequence
* @param {*} dataSet
* @returns
*/
function extractSliceThicknessFromDataset(dataSet) {
let sliceThickness;
if (dataSet.elements.x00180050) {
sliceThickness = dataSet.floatString('x00180050');
}
else if (dataSet.elements.x00289110 &&
dataSet.elements.x00289110.items.length &&
dataSet.elements.x00289110.items[0].dataSet.elements.x00180050) {
sliceThickness =
dataSet.elements.x00289110.items[0].dataSet.floatString('x00180050');
}
// if (sliceThickness === undefined && isMultiFrame(dataSet)) {
// const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
// dataSet,
// frameIndex
// );
// const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
// sliceThickness =
// getSliceThicknessFromPixelMeasuresSequence(perFrameDataSet) ||
// getSliceThicknessFromPixelMeasuresSequence(sharedDataSet);
// }
return sliceThickness;
}
export {
getImageTypeSubItemFromDataset,
extractOrientationFromDataset,
extractPositionFromDataset,
extractSpacingFromDataset,
extractSliceThicknessFromDataset,
};
+32
View File
@@ -0,0 +1,32 @@
import FingerprintJS from '@fingerprintjs/fingerprintjs';
export const customAgent = () => {
return new Promise(async resolve => {
const fpPromise = await FingerprintJS.load({
monitoring: false
});
const result = await fpPromise.get({
products: ['fonts', 'screen', 'canvas'],
extendedData: true,
debug: false
})
// const filteredComponents = Object.fromEntries(
// Object.entries(result.components)
// .filter(([key, value]) => value.confidence > 0.5)
// );
resolve({
...result,
});
// fpPromise
// .then(fp => fp.get({
// products: ['fonts', 'screen', 'canvas'],
// extendedData: true,
// debug: true
// }))
// .then(result => {
// // 自定义数据转换
// });
});
}
+1 -1
View File
@@ -1,6 +1,6 @@
import defaultSettings from '@/settings'
const title = defaultSettings.title || 'IRC Imaging System'
const title = defaultSettings.title || 'HASC lmaging Trial Management System'
export default function getPageTitle(pageTitle) {
if (pageTitle) {
+24
View File
@@ -0,0 +1,24 @@
function getNumberValues(
dataSet,
tag,
minimumLength
){
const values = [];
const valueAsString = dataSet.string(tag);
if (!valueAsString) {
return;
}
const split = valueAsString.split('\\');
if (minimumLength && split.length < minimumLength) {
return;
}
for (let i = 0; i < split.length; i++) {
values.push(parseFloat(split[i]));
}
return values;
}
export default getNumberValues;
+106
View File
@@ -196,4 +196,110 @@ export function workSpeedclose(isForce = false) {
lastPercentage = 0;
imageId = null;
percentageById = {};
}
function readDirectoryEntries(directoryReader) {
return new Promise((resolve, reject) => {
let entries = [];
function readBatch() {
directoryReader.readEntries(
(results) => {
if (results.length) {
entries = entries.concat(results);
readBatch();
} else {
resolve(entries);
}
},
(error) => reject(error)
);
}
readBatch();
});
}
export async function readEntry(entry) {
const files = [];
// 如果是文件夹,创建读取器并递归读取其内容
if (entry.isDirectory) {
const directoryReader = entry.createReader();
const entries = await readDirectoryEntries(directoryReader)
// 递归读取文件夹内的每一项
for (const subEntry of entries) {
const subFiles = await readEntry(subEntry);
files.push(...subFiles);
}
}
// 如果是文件,则将其转换为File对象
else if (entry.isFile) {
const file = await new Promise((resolve, reject) => {
entry.file(resolve, reject); // entry.file()是异步的
});
files.push(file);
}
return files;
}
// 使用FNV-1a哈希算法确保相同GUID产生相同结果
function fnv1aHash(str) {
const FNV_OFFSET_BASIS = 2166136261;
const FNV_PRIME = 16777619;
let hash = FNV_OFFSET_BASIS;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash = (hash * FNV_PRIME) >>> 0; // 使用无符号右移确保结果为无符号32位整数
}
return hash;
}
// RGB转十六进制
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}
// HSL转RGB函数
function hslToRgb(h, s, l) {
let r, g, b;
if (s === 0) {
r = g = b = l; // 灰色
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return { r, g, b };
}
export function guidToColor(guid) {
// 移除GUID中的连字符和花括号(如果有)
let cleanGuid = guid.replace(/[{}()-]/g, '');
// 计算GUID的哈希值
const hash = fnv1aHash(cleanGuid);
// 使用哈希值生成HLS颜色(确保高区分度)
// 将哈希值映射到0-1之间
const h = (hash & 0xFFFF) / 0xFFFF; // 使用前16位作为色相
const s = ((hash >> 16) & 0xFF) / 0xFF * 0.6 + 0.4; // 饱和度在0.4-1.0之间
const l = ((hash >> 24) & 0xFF) / 0xFF * 0.4 + 0.4; // 亮度在0.3-0.7之间,避免太暗或太亮
// 返回RGB对象
let rgb = hslToRgb(h, s, l);
let obj = {
r: Math.round(rgb.r * 255),
g: Math.round(rgb.g * 255),
b: Math.round(rgb.b * 255)
}
let str = rgbToHex(obj.r, obj.g, obj.b)
return str;
}
+3
View File
@@ -0,0 +1,3 @@
export default function isNMReconstructable(imageSubType) {
return imageSubType === 'RECON TOMO' || imageSubType === 'RECON GATED TOMO';
}
+327 -56
View File
@@ -1,25 +1,123 @@
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
import * as cornerstoneWADOImageLoader from "cornerstone-wado-image-loader";
import store from "@/store";
import { getPTClinicalDataForInstance } from "@/utils/ptClinicalDataCache";
import {
getImageTypeSubItemFromDataset,
extractOrientationFromDataset,
extractPositionFromDataset,
extractSpacingFromDataset,
extractSliceThicknessFromDataset,
} from "./extractPositioningFromDataset";
function toNumber(val) {
if (val === undefined || val === null || val === "") return null;
const n = typeof val === "number" ? val : parseFloat(val);
return Number.isFinite(n) ? n : null;
}
function normalizeDicomTime(value) {
if (value === undefined || value === null || value === "") return null;
const num = toNumber(value);
if (num != null) {
return String(Math.floor(num)).padStart(6, "0");
}
if (typeof value !== "string") return null;
const trimmed = value.trim();
if (!trimmed) return null;
const plain = trimmed.replace(/:/g, "");
const parts = plain.split(".");
const main = parts[0];
const fractional = parts[1];
if (!/^\d+$/.test(main)) {
return trimmed;
}
const normalizedMain = main.padStart(6, "0");
return fractional ? `${normalizedMain}.${fractional}` : normalizedMain;
}
function getPTClinicalOverrideFromImageId(imageId) {
try {
const qIndex = imageId.indexOf("?");
if (qIndex === -1) return null;
const params = new URLSearchParams(imageId.slice(qIndex + 1));
const visitTaskId = params.get("visitTaskId");
const idx = params.get("idx");
// 场景1trials/dicomsimageId 带 visitTaskId + idx,优先使用列表中的最新 study 值
if (visitTaskId && idx) {
const parts = idx.split("|");
const studyIndex = toNumber(parts[0]);
if (Number.isInteger(studyIndex) && studyIndex >= 0) {
const visitTaskList = store.state.reading.visitTaskList;
if (Array.isArray(visitTaskList)) {
const visitTaskInfo = visitTaskList.find(
(v) => v && String(v.VisitTaskId) === visitTaskId
);
const study = visitTaskInfo?.StudyList?.[studyIndex];
if (
study &&
!(
study.PatientWeight == null &&
study.RadionuclideTotalDose == null &&
study.RadionuclideHalfLife == null &&
study.RadiopharmaceuticalStartTime == null &&
study.AcquisitionTime == null &&
study.PatientSex == null
)
) {
return study;
}
}
}
}
// 场景2src/components/DicomimageId 仅带 instanceId,回退到实例缓存
const instanceId = params.get("instanceId");
if (instanceId) {
const cached = getPTClinicalDataForInstance(instanceId);
if (cached) return cached;
}
return null;
} catch (e) {
return null;
}
}
function parseImageId(imageId) {
// build a url by parsing out the url scheme and frame index from the imageId
const firstColonIndex = imageId.indexOf(':');
let url = imageId.substring(firstColonIndex + 1);
const frameIndex = url.indexOf('frame=');
// 兼容 frame 参数不在最后的情况:只移除 frame 参数本身,保留 instanceId/visitTaskId/idx 等其余 query
const firstColonIndex = imageId.indexOf(":");
const scheme = imageId.substr(0, firstColonIndex);
const urlPart = imageId.substring(firstColonIndex + 1);
let url = urlPart;
let frame;
const qIndex = urlPart.indexOf("?");
if (qIndex !== -1) {
const base = urlPart.slice(0, qIndex);
const query = urlPart.slice(qIndex + 1);
const parts = query.split("&").filter(Boolean);
const preservedParts = [];
if (frameIndex !== -1) {
const frameStr = url.substr(frameIndex + 6);
parts.forEach((part) => {
const eqIndex = part.indexOf("=");
const key = eqIndex === -1 ? part : part.slice(0, eqIndex);
const value = eqIndex === -1 ? "" : part.slice(eqIndex + 1);
frame = parseInt(frameStr, 10);
url = url.substr(0, frameIndex - 1);
if (key === "frame") {
const n = value !== "" ? parseInt(value, 10) : NaN;
if (Number.isFinite(n)) {
frame = n;
}
return;
}
// 保留原始 query 片段,避免 URLSearchParams 把 | 编码成 %7C 导致 dataSetCache key 对不上
preservedParts.push(part);
});
url = preservedParts.length ? `${base}?${preservedParts.join("&")}` : base;
}
return {
scheme: imageId.substr(0, firstColonIndex),
url,
frame,
};
return { scheme, url, frame };
}
function getNumberValues(dataSet, tag, minimumLength) {
const values = [];
@@ -28,7 +126,7 @@ function getNumberValues(dataSet, tag, minimumLength) {
if (!valueAsString) {
return;
}
const split = valueAsString.split('\\');
const split = valueAsString.split("\\");
if (minimumLength && split.length < minimumLength) {
return;
@@ -67,28 +165,31 @@ function getLutData(lutDataSet, tag, lutDescriptor) {
return lut;
}
function populateSmallestLargestPixelValues(dataSet, imagePixelModule) {
const pixelRepresentation = dataSet.uint16('x00280103');
const pixelRepresentation = dataSet.uint16("x00280103");
if (pixelRepresentation === 0) {
imagePixelModule.smallestPixelValue = dataSet.uint16('x00280106');
imagePixelModule.largestPixelValue = dataSet.uint16('x00280107');
imagePixelModule.smallestPixelValue = dataSet.uint16("x00280106");
imagePixelModule.largestPixelValue = dataSet.uint16("x00280107");
} else {
imagePixelModule.smallestPixelValue = dataSet.int16('x00280106');
imagePixelModule.largestPixelValue = dataSet.int16('x00280107');
imagePixelModule.smallestPixelValue = dataSet.int16("x00280106");
imagePixelModule.largestPixelValue = dataSet.int16("x00280107");
}
imagePixelModule.largestPixelValue = imagePixelModule.largestPixelValue === 0 ? undefined : imagePixelModule.largestPixelValue;
imagePixelModule.largestPixelValue =
imagePixelModule.largestPixelValue === 0
? undefined
: imagePixelModule.largestPixelValue;
}
function populatePaletteColorLut(dataSet, imagePixelModule) {
imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281101'
"x00281101"
);
imagePixelModule.greenPaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281102'
"x00281102"
);
imagePixelModule.bluePaletteColorLookupTableDescriptor = getLutDescriptor(
dataSet,
'x00281103'
"x00281103"
);
// The first Palette Color Lookup Table Descriptor value is the number of entries in the lookup table.
@@ -127,33 +228,196 @@ function populatePaletteColorLut(dataSet, imagePixelModule) {
imagePixelModule.redPaletteColorLookupTableData = getLutData(
dataSet,
'x00281201',
"x00281201",
imagePixelModule.redPaletteColorLookupTableDescriptor
);
imagePixelModule.greenPaletteColorLookupTableData = getLutData(
dataSet,
'x00281202',
"x00281202",
imagePixelModule.greenPaletteColorLookupTableDescriptor
);
imagePixelModule.bluePaletteColorLookupTableData = getLutData(
dataSet,
'x00281203',
"x00281203",
imagePixelModule.bluePaletteColorLookupTableDescriptor
);
}
function getSpacingBetweenSlices(dataSet) {
if (dataSet?.elements?.x00180088) {
return dataSet.floatString("x00180088");
}
const pixelMeasuresSequence = dataSet?.elements?.x00289110;
if (
pixelMeasuresSequence?.items?.length &&
pixelMeasuresSequence.items[0]?.dataSet?.elements?.x00180088
) {
return pixelMeasuresSequence.items[0].dataSet.floatString("x00180088");
}
}
function metaDataProvider(type, imageId) {
const parsedImageId = parseImageId(imageId);
const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(parsedImageId.url);
const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(
parsedImageId.url
);
if (!dataSet) {
return;
}
if (type === 'imagePlaneModule') {
const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6);
const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
const imagePixelSpacing = getNumberValues(dataSet, 'x00181164', 2);
const estimatedRadiographicMagnificationFactor = getNumberValues(dataSet, 'x00181114', 2);
const ptOverride = getPTClinicalOverrideFromImageId(imageId);
if (type === "generalSeriesModule") {
const { dicomParser } = cornerstoneWADOImageLoader.external || {};
const overrideTime = normalizeDicomTime(ptOverride?.AcquisitionTime);
const seriesTimeRaw =
overrideTime ||
dataSet.string("x00080031") ||
dataSet.string("x00080032") ||
"";
const acquisitionTimeRaw =
overrideTime ||
dataSet.string("x00080032") ||
dataSet.string("x00080031") ||
"";
return {
modality: dataSet.string("x00080060"),
seriesInstanceUID: dataSet.string("x0020000e"),
seriesNumber: dataSet.intString("x00200011"),
studyInstanceUID: dataSet.string("x0020000d"),
seriesDate: dicomParser.parseDA(dataSet.string("x00080021")),
// 2D SUV 计算读取的是 seriesTime,这里同步使用用户录入采集时间
// seriesTime: dicomParser.parseTM(String(seriesTimeRaw)),
seriesTime: dicomParser.parseTM(dataSet.string('x00080031') || ''),
acquisitionDate: dicomParser.parseDA(dataSet.string("x00080022") || ""),
acquisitionTime: dicomParser.parseTM(String(acquisitionTimeRaw)),
};
}
if (type === "patientStudyModule") {
const weightOverride = ptOverride?.PatientWeight;
const weight =
weightOverride
? toNumber(weightOverride)
: dataSet.floatString("x00101030");
return {
patientAge: dataSet.intString("x00101010"),
patientSize: dataSet.floatString("x00101020"),
patientWeight: weight,
};
}
if (type === "petIsotopeModule") {
const { dicomParser } = cornerstoneWADOImageLoader.external || {};
const radiopharmaceuticalInfo = dataSet.elements.x00540016;
if (radiopharmaceuticalInfo === undefined) {
return;
}
const firstRadiopharmaceuticalInfoDataSet =
radiopharmaceuticalInfo.items[0].dataSet;
const startTimeRaw =
firstRadiopharmaceuticalInfoDataSet.string("x00181072") || "";
const totalDoseRaw =
firstRadiopharmaceuticalInfoDataSet.floatString("x00181074");
const halfLifeRaw =
firstRadiopharmaceuticalInfoDataSet.floatString("x00181075");
let startTimeValue = normalizeDicomTime(
ptOverride?.RadiopharmaceuticalStartTime
);
if (!startTimeValue && startTimeRaw) {
startTimeValue = normalizeDicomTime(startTimeRaw) || startTimeRaw;
}
const radiopharmaceuticalStartTime = dicomParser.parseTM(
String(startTimeValue)
);
const overrideTotalDose =
ptOverride?.RadionuclideTotalDose != null &&
ptOverride.RadionuclideTotalDose !== ""
? toNumber(ptOverride.RadionuclideTotalDose)
: null;
const overrideHalfLife =
ptOverride?.RadionuclideHalfLife != null &&
ptOverride.RadionuclideHalfLife !== ""
? toNumber(ptOverride.RadionuclideHalfLife)
: null;
const radionuclideTotalDose =
overrideTotalDose != null ? overrideTotalDose : toNumber(totalDoseRaw);
const radionuclideHalfLife =
overrideHalfLife != null ? overrideHalfLife : toNumber(halfLifeRaw);
return {
radiopharmaceuticalInfo: {
radiopharmaceuticalStartTime,
radionuclideTotalDose,
radionuclideHalfLife,
},
};
}
if (type === "imagePlaneModule") {
// const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6);
// const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
// const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
const imagePixelSpacing = getNumberValues(dataSet, "x00181164", 2);
const frameIndex =
parsedImageId.frame !== undefined ? parsedImageId.frame - 1 : undefined;
const imageOrientationPatient = extractOrientationFromDataset(
dataSet,
frameIndex
);
let imagePositionPatient = extractPositionFromDataset(dataSet, frameIndex);
const pixelSpacing = extractSpacingFromDataset(dataSet, frameIndex);
const sliceThickness = extractSliceThicknessFromDataset(
dataSet,
frameIndex
);
const modality = dataSet.string("x00080060");
if (
modality &&
modality.includes("NM") &&
parsedImageId.frame !== undefined &&
parsedImageId.frame > 1
) {
const spacingBetweenSlices = getSpacingBetweenSlices(dataSet);
const step =
spacingBetweenSlices !== undefined
? spacingBetweenSlices
: sliceThickness;
if (
imageOrientationPatient &&
imagePositionPatient &&
step !== undefined &&
frameIndex !== undefined
) {
const rowCosines = [
parseFloat(imageOrientationPatient[0]),
parseFloat(imageOrientationPatient[1]),
parseFloat(imageOrientationPatient[2]),
];
const columnCosines = [
parseFloat(imageOrientationPatient[3]),
parseFloat(imageOrientationPatient[4]),
parseFloat(imageOrientationPatient[5]),
];
const normal = [
rowCosines[1] * columnCosines[2] - rowCosines[2] * columnCosines[1],
rowCosines[2] * columnCosines[0] - rowCosines[0] * columnCosines[2],
rowCosines[0] * columnCosines[1] - rowCosines[1] * columnCosines[0],
];
const offset = frameIndex * parseFloat(step);
imagePositionPatient = [
parseFloat(imagePositionPatient[0]) + normal[0] * offset,
parseFloat(imagePositionPatient[1]) + normal[1] * offset,
parseFloat(imagePositionPatient[2]) + normal[2] * offset,
];
}
}
const estimatedRadiographicMagnificationFactor = getNumberValues(
dataSet,
"x00181114",
2
);
let columnPixelSpacing = null;
let rowPixelSpacing = null;
@@ -162,8 +426,10 @@ function metaDataProvider(type, imageId) {
rowPixelSpacing = pixelSpacing[0];
columnPixelSpacing = pixelSpacing[1];
} else if (imagePixelSpacing && estimatedRadiographicMagnificationFactor) {
rowPixelSpacing = imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0];
columnPixelSpacing = imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1];
rowPixelSpacing =
imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0];
columnPixelSpacing =
imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1];
} else if (imagePixelSpacing && !estimatedRadiographicMagnificationFactor) {
rowPixelSpacing = imagePixelSpacing[0];
columnPixelSpacing = imagePixelSpacing[1];
@@ -187,43 +453,48 @@ function metaDataProvider(type, imageId) {
}
return {
frameOfReferenceUID: dataSet.string('x00200052'),
rows: dataSet.uint16('x00280010'),
columns: dataSet.uint16('x00280011'),
frameOfReferenceUID: dataSet.string("x00200052"),
rows: dataSet.uint16("x00280010"),
columns: dataSet.uint16("x00280011"),
imageOrientationPatient,
rowCosines,
columnCosines,
imagePositionPatient,
sliceThickness: dataSet.floatString('x00180050'),
sliceLocation: dataSet.floatString('x00201041'),
sliceThickness,
sliceLocation: dataSet.floatString("x00201041"),
pixelSpacing,
rowPixelSpacing,
columnPixelSpacing,
};
}
if (type === 'imagePixelModule') {
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'),
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' &&
imagePixelModule.photometricInterpretation === "PALETTE COLOR" &&
dataSet.elements.x00281101
) {
populatePaletteColorLut(dataSet, imagePixelModule);
}
return imagePixelModule;
}
// if (type === "multiframeModule") {
// return {
// NumberOfFrames: dataSet.uint16("x00280008") || dataSet.string("x00280008")
// };
// }
// if (type === 'imagePixelModule') {
// return {
// samplesPerPixel: dataSet.uint16('x00280002'),
@@ -249,4 +520,4 @@ function metaDataProvider(type, imageId) {
// }
// }
}
export default metaDataProvider;
export default metaDataProvider;
+85 -8
View File
@@ -5,6 +5,7 @@ const stream = require('stream')
import Vue from 'vue'
import { customerHttp, OSSclose } from "@/utils/multipartUpload/oss"
import { exist, AWSclose } from "@/utils/multipartUpload/aws"
import { addOrUpdateFileUploadRecord } from '@/api/file'
const { GetObjectStoreToken } = require('../api/user.js')
const {
S3Client,
@@ -22,7 +23,6 @@ async function ossGenerateSTS() {
res = await GetObjectStoreToken()
localStorage.setItem('stsToken', JSON.stringify(res))
}
// res.Result.ObjectStoreUse = 'AWS';
Vue.prototype.OSSclientConfig = { ...res.Result[res.Result.ObjectStoreUse] }
Vue.prototype.OSSclientConfig.ObjectStoreUse = res.Result.ObjectStoreUse;
@@ -34,7 +34,8 @@ async function ossGenerateSTS() {
Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000
let OSSclient = new OSS(Vue.prototype.OSSclientConfig)
Vue.prototype.OSSclient = {
put: async function (objectName, object) {
put: async function (objectName, object, fileInfo = {}) {
OSSclient = await RefreshClient(OSSclient)
return new Promise(async (resolve, reject) => {
try {
@@ -52,6 +53,20 @@ async function ossGenerateSTS() {
}
let res = await OSSclient.put(objectName, object)
if (res && res.url) {
const urlParams = new URLSearchParams(window.location.search)
const trialId = urlParams.get('trialId')
if (Object.keys(fileInfo).length !== 0) {
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
let params = Object.assign({path: objectName}, fileInfo)
addOrUpdateFileUploadRecord(params)
} else if (trialId) {
const fileName = objectName.split('/').pop()
const fileType = fileName.includes('.')
? fileName.split('.').pop().toLowerCase()
: ''
let params = { trialId, path: objectName, fileName, fileType }
addOrUpdateFileUploadRecord(params)
}
resolve({
name: objectName,
url: res.url
@@ -65,7 +80,7 @@ async function ossGenerateSTS() {
}
})
},
multipartUpload: async (data, progress) => {
multipartUpload: async (data, progress, fileInfo = {}) => {
OSSclient = await RefreshClient(OSSclient)
return new Promise(async (resolve, reject) => {
try {
@@ -95,6 +110,21 @@ async function ossGenerateSTS() {
}
let res = await customerHttp(OSSclient, data, progress);
if (res) {
const urlParams = new URLSearchParams(window.location.search)
const trialId = urlParams.get('trialId')
if (Object.keys(fileInfo).length !== 0) {
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
let params = Object.assign({path: data.path}, fileInfo)
addOrUpdateFileUploadRecord(params)
} else if (trialId) {
const fileName = data.path.split('/').pop()
const fileType = fileName.includes('.')
? fileName.split('.').pop().toLowerCase()
: ''
let params = { trialId, path: data.path, fileName, fileType }
addOrUpdateFileUploadRecord(params)
}
resolve({
name: data.path,
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name)
@@ -169,17 +199,17 @@ async function ossGenerateSTS() {
}
});
Vue.prototype.OSSclient = {
put: async function (objectName, object) {
put: async function (objectName, object, fileInfo = {}) {
let data = {
file: object,
path: objectName
}
aws = await RefreshClient(aws);
return uploadAWS(aws, data, () => { });
return uploadAWS(aws, data, () => { }, fileInfo);
},
multipartUpload: async (data, progress) => {
multipartUpload: async (data, progress, fileInfo = {}) => {
aws = await RefreshClient(aws);
return uploadAWS(aws, data, progress);
return uploadAWS(aws, data, progress, fileInfo);
},
close: () => {
AWSclose();
@@ -189,7 +219,7 @@ async function ossGenerateSTS() {
return
}
// AWS上传函数
function uploadAWS(aws, data, progress) {
function uploadAWS(aws, data, progress, fileInfo) {
return new Promise(async (resolve, reject) => {
try {
const { file, path } = data;
@@ -211,6 +241,21 @@ function uploadAWS(aws, data, progress) {
data.path = data.path.replace(`/${bucketName}/`, '');
await exist(aws, bucketName, data, progress, (path, status) => {
if (status === 'success') {
const urlParams = new URLSearchParams(window.location.search)
const trialId = urlParams.get('trialId')
if (Object.keys(fileInfo).length !== 0) {
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
let params = Object.assign({path: decodeUtf8(curPath)}, fileInfo)
addOrUpdateFileUploadRecord(params)
} else if (trialId) {
const fileName = decodeUtf8(curPath).split('/').pop()
const fileType = fileName.includes('.')
? fileName.split('.').pop().toLowerCase()
: ''
let params = { trialId, path: decodeUtf8(curPath), fileName, fileType }
addOrUpdateFileUploadRecord(params)
}
resolve({
name: decodeUtf8(curPath),
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(curPath)
@@ -320,5 +365,37 @@ function isCredentialsExpired(credentials) {
return expireDate.getTime() - now.getTime() <= 300000;
}
function mimeTypeToExt(mimeType) {
const map = {
// 图片
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
'image/png': 'png',
'image/gif': 'gif',
'image/webp': 'webp',
'image/svg+xml': 'svg',
'image/bmp': 'bmp',
// 文档
'application/dicom': 'dcm',
'application/pdf': 'pdf',
'application/msword': 'doc',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
'application/vnd.ms-excel': 'xls',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
'application/vnd.ms-powerpoint': 'ppt',
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
'text/plain': 'txt',
// 音频/视频
'audio/mpeg': 'mp3',
'audio/wav': 'wav',
'video/mp4': 'mp4',
'video/mpeg': 'mpeg',
// 压缩包
'application/zip': 'zip',
'application/x-rar-compressed': 'rar',
'application/x-7z-compressed': '7z',
};
return map[mimeType] || ''; // 找不到返回空字符串
}
export const OSSclient = ossGenerateSTS
+31
View File
@@ -0,0 +1,31 @@
// PT 临床数据缓存:用于统一 SUV 口径(优先接口,缺失则回退 DICOM 元数据)
const instanceIdToClinicalData = new Map()
function normalizeId(id) {
if (id === undefined || id === null) return null
const s = String(id).trim()
return s ? s : null
}
export function setPTClinicalDataForInstance(instanceId, clinicalData) {
const key = normalizeId(instanceId)
if (!key) return
if (!clinicalData || typeof clinicalData !== 'object') return
instanceIdToClinicalData.set(key, { ...clinicalData })
}
export function getPTClinicalDataForInstance(instanceId) {
const key = normalizeId(instanceId)
if (!key) return null
return instanceIdToClinicalData.get(key) || null
}
export function deletePTClinicalDataForInstance(instanceId) {
const key = normalizeId(instanceId)
if (!key) return
instanceIdToClinicalData.delete(key)
}
export function clearPTClinicalDataCache() {
instanceIdToClinicalData.clear()
}
+1 -1
View File
@@ -28,7 +28,7 @@ async function executeTask() {
task.callback({ success: true, res: result })
}).catch((error) => {
task.callback({ success: true, err: error })
task.callback({ success: false, err: error })
})
})
// let starLoadTime = performance.now()

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