Compare commits
452 Commits
v1.12.2
...
47d7fb00e2
| Author | SHA1 | Date | |
|---|---|---|---|
| 47d7fb00e2 | |||
| 312ab754e1 | |||
| 0ff5a21d04 | |||
| 5a7fa1fb77 | |||
| 5289c156c0 | |||
| a68c27fd43 | |||
| 641c2e6ade | |||
| 5b4cc097bc | |||
| b1de662677 | |||
| d2d1063ed5 | |||
| 2bc4b32d3a | |||
| 366ec62cd7 | |||
| 866e2e5c6b | |||
| 16e2db37cd | |||
| ee6c5bf8a5 | |||
| 48cfe99f12 | |||
| f65264a2a6 | |||
| 769c5f8440 | |||
| 6321bddfd3 | |||
| e30fb2a041 | |||
| 478adcde21 | |||
| 34ce5142f2 | |||
| 3b993bcd46 | |||
| 3f2e39f46c | |||
| d317402f85 | |||
| 6cb63bdc59 | |||
| 8db641db16 | |||
| 9da9515930 | |||
| 2be119de6b | |||
| c9f9615488 | |||
| be137b3840 | |||
| d80101f86b | |||
| 3c0b084f7e | |||
| 8a88a64c36 | |||
| 3d538d6e67 | |||
| 67d2a83ec8 | |||
| 2efb229c96 | |||
| c930480336 | |||
| b39ea3a032 | |||
| ff5aea17a5 | |||
| 477b6935ff | |||
| 8b6432ad14 | |||
| ca35fe6df4 | |||
| 307c02725f | |||
| 72d0494baa | |||
| d1017bc565 | |||
| 76e6ef087f | |||
| c5c9e4364c | |||
| 920d0b21c6 | |||
| 3fe16b4166 | |||
| bc2d5463ff | |||
| c63811d55c | |||
| 832fa82d4b | |||
| b3ae801fe9 | |||
| 0dbd74270d | |||
| aae5968d74 | |||
| 79a7ad0cf7 | |||
| a35309d9b5 | |||
| a987ac086b | |||
| fdc2bc5f8a | |||
| 84f68c79f0 | |||
| b77dc34523 | |||
| 91554e0e30 | |||
| 2efb7fd36a | |||
| dbdec93efc | |||
| e631ce73f2 | |||
| 5931dcdc67 | |||
| b55ffc0821 | |||
| 8600054405 | |||
| 9a88539294 | |||
| 09211c8841 | |||
| 2724e0267f | |||
| a0e355d69b | |||
| 04a0a1ccc3 | |||
| c3e967acaa | |||
| 740a0aa221 | |||
| e8f95d09ba | |||
| 2c305af49e | |||
| 5c76bda1e7 | |||
| 0273601f7b | |||
| c3a154f762 | |||
| cdb97f6405 | |||
| 4794429a57 | |||
| 77a633d699 | |||
| 64d1ebf350 | |||
| 5336cb5353 | |||
| 0a288b9f47 | |||
| 674d483cbf | |||
| cbcb396441 | |||
| 9a3e972723 | |||
| b593615e9e | |||
| d30c9a5f3b | |||
| dd3d738eed | |||
| d9edaf4c27 | |||
| a5e0dd89ff | |||
| 73f8f816b7 | |||
| 19d5144b70 | |||
| e0ecd3f4ac | |||
| 30e0e374bc | |||
| 25b909c660 | |||
| 5cb3e8e606 | |||
| 619af2e874 | |||
| 43f1736b05 | |||
| c9be5678bd | |||
| 4e5ecb3938 | |||
| 7870c3d74b | |||
| d07adc4948 | |||
| 266886fa64 | |||
| e012eba0c2 | |||
| 75d296405b | |||
| 07c92c48a4 | |||
| b5427dd17b | |||
| 385643643e | |||
| 756f1293aa | |||
| eee19f0ae9 | |||
| 78c0910db7 | |||
| 18a71725f9 | |||
| 87332ae9d8 | |||
| 401762dca7 | |||
| 7b694d4afb | |||
| 6e285d900b | |||
| c5d3b44c2c | |||
| cf4dbc2914 | |||
| 3cef5afebd | |||
| 060b61eafb | |||
| 0d3571f672 | |||
| 8b3bd101b6 | |||
| da252ae4df | |||
| fdb7251b62 | |||
| 1f51bbd178 | |||
| 597ca07fcf | |||
| b43c75dd9f | |||
| 94f3e6c757 | |||
| 1d95cd15f2 | |||
| a1f9283262 | |||
| a0abba71dd | |||
| 02d85e19a6 | |||
| 9ad916f860 | |||
| e0094c01d8 | |||
| 0eb2135185 | |||
| 8ddfe34f72 | |||
| c603d10ff5 | |||
| 3fca2e76cb | |||
| c0ae4732fc | |||
| 4ec0a178b4 | |||
| 4057f1893f | |||
| 5c05a11ec4 | |||
| eec23b9d42 | |||
| f7d01f6ad7 | |||
| cb46f89ee1 | |||
| b0ad500f7a | |||
| 0327937f02 | |||
| 2f3eab6119 | |||
| 575840490f | |||
| 9b013059ba | |||
| 987831ff22 | |||
| 7691fd12ac | |||
| 0cecb91984 | |||
| 849142bd23 | |||
| 231a993f8b | |||
| ab1a2889bc | |||
| f04f0ce929 | |||
| bc3e00c8b4 | |||
| 953033b768 | |||
| c337f95693 | |||
| d2021a281e | |||
| 66ae27cc56 | |||
| 3137bca8f6 | |||
| e35f6c5471 | |||
| 46b532b858 | |||
| 5a8e1e5af7 | |||
| 9b9c83797a | |||
| 8a4b4fc9fb | |||
| 91d8d1797a | |||
| 0d2bfa8d82 | |||
| 742b60bba2 | |||
| 536fc7bbc8 | |||
| 6f0f7a7d3a | |||
| 4ed0feb1da | |||
| 45cc714942 | |||
| 147b5cadfa | |||
| d34f1f462a | |||
| c89aa8bd87 | |||
| 98324c27e6 | |||
| ae1014c70b | |||
| 7dc7236c16 | |||
| b7a5015e21 | |||
| e491265bb4 | |||
| 8a4a035b2c | |||
| 4e0fbb3f31 | |||
| d44aeac36d | |||
| f6eb5b8cd5 | |||
| 71e00ecf5b | |||
| fdc2572477 | |||
| 7ab9d0f285 | |||
| 64b8214985 | |||
| ba6bcebe1f | |||
| 8703b28470 | |||
| dc8fb450fb | |||
| 377cdb968d | |||
| 8c84cb5101 | |||
| 5a0cc41d5a | |||
| 86a1312b60 | |||
| a3ca9fe4d0 | |||
| c6770e71a5 | |||
| c70970a6f6 | |||
| d059d016a6 | |||
| 44519c5f8e | |||
| f3a4a7cd09 | |||
| 463e4728d0 | |||
| 5d04fb869d | |||
| ec83609139 | |||
| a5824cecac | |||
| 416f8f82d6 | |||
| f0a7090ab4 | |||
| a13ddf70b4 | |||
| ecf4c74259 | |||
| e712333a79 | |||
| 6900cc8a25 | |||
| d5acb0a27c | |||
| 0f845df8dd | |||
| 0b2cdd12a7 | |||
| 785ca4ad47 | |||
| 20ad1c894a | |||
| 95aa3e0be7 | |||
| 46fdee6c01 | |||
| f997cec4fb | |||
| 1586643fc2 | |||
| 5ad0da7a4a | |||
| 16c0e84ca0 | |||
| e58fbdcab6 | |||
| e17a89e151 | |||
| bf35797282 | |||
| 21bdd0b07e | |||
| 47798750a4 | |||
| 8d1d5cb43a | |||
| ef08a5277d | |||
| 98a3f9c5b5 | |||
| a0b39e7a0b | |||
| 1191b97688 | |||
| c662e6cc3a | |||
| 30b5ee24a0 | |||
| 2781d02afa | |||
| 034f9528e5 | |||
| d8712f26cd | |||
| feab37c4ac | |||
| 443a31df97 | |||
| 99955b2eff | |||
| e36ae0404d | |||
| 65edc78152 | |||
| 78f2f530c4 | |||
| fdc23361f9 | |||
| b4db6b4990 | |||
| a45ab4edf8 | |||
| 2f20696827 | |||
| 2ffffd2bf0 | |||
| d21c01076d | |||
| 8d0f0094ba | |||
| 08dba4b364 | |||
| 2716b379b5 | |||
| 5216bf9f62 | |||
| 040814c3d6 | |||
| 264f00f5a8 | |||
| 3f48bc0ba5 | |||
| 2c47541737 | |||
| 0c2ed13cd4 | |||
| f1c36ea688 | |||
| 9568186497 | |||
| a48dc114e8 | |||
| abb224a8fb | |||
| 754fe5f797 | |||
| f72cab082a | |||
| 03c7aa3d99 | |||
| 24c7c61398 | |||
| 281c900e0c | |||
| 63772f46f8 | |||
| accac374ff | |||
| 4ee7906dcd | |||
| 3dc99d096d | |||
| 096e11e9fd | |||
| cce6122e9e | |||
| 6f3ca769a6 | |||
| da41fa1139 | |||
| 11940798e8 | |||
| ef46e4cb08 | |||
| b2119c3acd | |||
| e7fdee1147 | |||
| b5f327fc3c | |||
| 93b7477aa6 | |||
| 73e9f30f7e | |||
| 35cc08e53c | |||
| 97dda302e1 | |||
| f59b205324 | |||
| 7328ea55df | |||
| 5773a93df3 | |||
| e6e9ab03a3 | |||
| a663f6fa4e | |||
| 80fe969fe1 | |||
| bdbca21550 | |||
| 3901ceec45 | |||
| 2f8b88b51f | |||
| bed842ec88 | |||
| 72d9872b20 | |||
| bdca45a505 | |||
| 68fa0edfe5 | |||
| 17ad103c34 | |||
| 7bebb8900e | |||
| fc72e141bf | |||
| 3eb28d2baa | |||
| 7892b8cf01 | |||
| 9f5fc1dc9d | |||
| 4b5fee5739 | |||
| f5143fe11c | |||
| 363ffa58b3 | |||
| 4e46bbac84 | |||
| fb8135d985 | |||
| e5233c8894 | |||
| 4143eb6279 | |||
| f3d9b31313 | |||
| 726f6499f9 | |||
| aab9c4576c | |||
| b661a51ec2 | |||
| edb03fef23 | |||
| 7ca31d8a5e | |||
| 5ec5eda344 | |||
| 61a1b1b1c2 | |||
| f93274080a | |||
| fbb9899b55 | |||
| f7af9999e4 | |||
| d64bea0d27 | |||
| 3a7eadb41c | |||
| 1b25f6538e | |||
| dbc84b2f58 | |||
| 9d601b4a46 | |||
| 09e5bcb3b7 | |||
| ae536a7fc4 | |||
| 1b6f48a5a5 | |||
| d57c080916 | |||
| c2cb5b1999 | |||
| cc5ac4c2a9 | |||
| 653d3c6228 | |||
| eefb42c3f6 | |||
| ba6cb87648 | |||
| 17f738aa5d | |||
| 7a91ccac80 | |||
| b57076d41d | |||
| 633a169467 | |||
| f2d50e7465 | |||
| e65e6e2208 | |||
| 196a20cbc0 | |||
| f002fed9e2 | |||
| 423b71c702 | |||
| f79084b599 | |||
| ca99572f19 | |||
| 0d9db63f88 | |||
| 3f9beb6dee | |||
| 3243b33b33 | |||
| ca44352b9e | |||
| e5d86abf92 | |||
| 8dedd1068a | |||
| f58e52585f | |||
| 1dd153448c | |||
| b60b0f8de7 | |||
| 9de73b9d44 | |||
| b55245a83a | |||
| cf1af92c2f | |||
| c7740493f8 | |||
| cca8a0df9d | |||
| a75f4a38f6 | |||
| 49b3b056e3 | |||
| 937ab0899e | |||
| f7d7d2b742 | |||
| 7c9cde00a9 | |||
| b56834e8ed | |||
| 29e785243e | |||
| 7d57f6b5f6 | |||
| ecb146bd67 | |||
| 795423182d | |||
| 5dd13b58c5 | |||
| bbd8e8b510 | |||
| 6c02793d2f | |||
| 4f5fb17bb8 | |||
| 5f89d7d10c | |||
| 0002bd0165 | |||
| 5cd5e3c34d | |||
| 9c0ca0a831 | |||
| 181eaed3f5 | |||
| b88657fda0 | |||
| d4aa02e0e5 | |||
| d13a5edfda | |||
| b6ee9d5f62 | |||
| 134f2471a6 | |||
| 746278681d | |||
| 081263d34f | |||
| 199fe6aed3 | |||
| 273932f9cc | |||
| 3832312041 | |||
| b6500c62c5 | |||
| 42839a925d | |||
| 342f135d23 | |||
| 7f47936f8a | |||
| a7b9218952 | |||
| 8590808cb9 | |||
| 5394a2cde5 | |||
| fe0ba42736 | |||
| b6bc22af72 | |||
| 9b67760ffd | |||
| aee12347dc | |||
| 7426be2e50 | |||
| 5565b1389d | |||
| 0e029369a3 | |||
| 5d09bd2159 | |||
| 98757b6c06 | |||
| c197c077a7 | |||
| 2ce7fa7552 | |||
| 5456d7a40b | |||
| 8299fd8958 | |||
| 06b505544b | |||
| 19d472bfb3 | |||
| 62f601a7be | |||
| 689527b61e | |||
| 7478472e33 | |||
| 7f48e37779 | |||
| 2a27e1fbae | |||
| 02a5e2fdc2 | |||
| 0f6da34395 | |||
| 2c567e3530 | |||
| b7f113c109 | |||
| 7c79e4b1f3 | |||
| 5528188a8b | |||
| c0aa89c6ca | |||
| 5bbbdb0a97 | |||
| cbcc11fe97 | |||
| 7f20bfecdc | |||
| f58c116382 | |||
| b44d832241 | |||
| bf2a2818ce | |||
| 58c33bc008 | |||
| 1e49dedd23 | |||
| 3c661ae86a | |||
| 7238b12424 | |||
| 341a707c80 | |||
| 877535f579 | |||
| 602f942e9e | |||
| a804ba40f0 | |||
| 38eef44d79 | |||
| ff1b4f6f21 | |||
| ef336eafe6 | |||
| 553014be79 | |||
| e7491501cf | |||
| d64d5a523d | |||
| b2e7eeaeb4 |
@@ -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
|
||||
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
"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/polymorphic-segmentation": "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/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 +38,7 @@
|
||||
"dcmjs": "^0.29.8",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"dicomedit": "^0.1.0",
|
||||
"echarts": "^4.8.0",
|
||||
"echarts": "^6.0.0",
|
||||
"element-ui": "^2.15.14",
|
||||
"exceljs": "^4.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -59,11 +60,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",
|
||||
@@ -97,9 +97,10 @@
|
||||
"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"
|
||||
},
|
||||
@@ -124,4 +125,4 @@
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<template>
|
||||
<div id="app" style="position: relative">
|
||||
<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="ValueCN" :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 /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -163,11 +94,15 @@ 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'
|
||||
export default {
|
||||
name: 'App',
|
||||
components: { feedBack },
|
||||
components: {
|
||||
feedBack,
|
||||
// timeTag
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawer: false,
|
||||
@@ -366,13 +301,16 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
$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 +319,7 @@ $light_gray: #606266;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none !important;
|
||||
@@ -393,6 +332,7 @@ input[type='number'] {
|
||||
.viewer-fixed.viewer-container {
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
textarea {
|
||||
white-space: break-spaces;
|
||||
word-break: normal;
|
||||
@@ -401,12 +341,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 +358,11 @@ textarea {
|
||||
font-family: 'Times New Roman';
|
||||
text-shadow: 1px 0.5px 1.5px #666;
|
||||
}
|
||||
|
||||
.title-logo {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.title-logo {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@@ -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,43 @@ 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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
})
|
||||
}
|
||||
@@ -239,7 +239,7 @@ export function getPatientList_Export(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
export function getTumor_CDISC_Export(data) {
|
||||
export function getTumor_CDISC_IVUSOCT_Export(data) {
|
||||
return requestDownload({
|
||||
url: `/IVUS_OCTExport/getTumor_CDISC_Export`,
|
||||
responseType: 'blob',
|
||||
@@ -263,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({
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -295,6 +295,22 @@ export function readingImport(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({
|
||||
@@ -303,3 +319,92 @@ export function getReportsChartData(param) {
|
||||
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
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1203,7 +1203,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 +1262,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
|
||||
})
|
||||
@@ -2833,7 +2839,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 +2884,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 +2898,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}`,
|
||||
@@ -3603,13 +3628,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}`,
|
||||
@@ -4282,7 +4318,103 @@ export function 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({
|
||||
@@ -4290,4 +4422,12 @@ export function getTrialSubjectVisitMarkList(data) {
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 更新缩略图
|
||||
export function updateImageResizePath(data) {
|
||||
return request({
|
||||
url: `/Series/updateImageResizePath`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 320 KiB |
@@ -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;
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
currentUser: zzSessionStorage.getItem('userName'),
|
||||
COMPANY: process.env.VUE_APP_COMPANY_NAME,
|
||||
onlyOffice_url: process.env.VUE_APP_ONLYOFFICE_URL,
|
||||
window
|
||||
window,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 />
|
||||
@@ -72,10 +74,11 @@ export default {
|
||||
zzSessionStorage.setItem('lastWorkbench', `${v.path}${query ? '?' : ''}${query}`)
|
||||
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=/'
|
||||
},
|
||||
@@ -83,7 +86,7 @@ export default {
|
||||
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)
|
||||
@@ -100,7 +103,7 @@ export default {
|
||||
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)
|
||||
@@ -110,15 +113,25 @@ export default {
|
||||
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'
|
||||
]
|
||||
var qualityList = [
|
||||
'/trials/trials-panel/visit/crc-question',
|
||||
'/trials/trials-panel/visit/qc-check',
|
||||
@@ -134,6 +147,9 @@ export default {
|
||||
'/trials/trials-panel/trial-summary/image-inspect',
|
||||
'/trials/trials-panel/trial-summary/push-record',
|
||||
]
|
||||
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 +203,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 +225,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>
|
||||
|
||||
@@ -68,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')"
|
||||
@@ -111,6 +111,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
SubjectId: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -8,21 +8,49 @@
|
||||
|
||||
<script>
|
||||
import { getReportsChartData } from "@/api/reading"
|
||||
import moment from "moment"
|
||||
let echarts = require('echarts/lib/echarts');
|
||||
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/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');
|
||||
// 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: {
|
||||
@@ -152,7 +180,13 @@ export default {
|
||||
text: obj.title,
|
||||
textStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
grid: {
|
||||
left: 50,
|
||||
bottom: 30
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
@@ -194,6 +228,7 @@ export default {
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,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"
|
||||
@@ -69,7 +69,7 @@
|
||||
</el-table>
|
||||
<div style="margin: 10px 0" class="top">
|
||||
<span>{{ $t('upload:dicom:uploadTitle') }}</span>
|
||||
<div class="btnBox">
|
||||
<div class="btnBox" v-if="!forbid">
|
||||
<span style="margin-right: 10px">
|
||||
{{ $store.state.trials.uploadTip }}
|
||||
</span>
|
||||
@@ -354,6 +354,10 @@ export default {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
TaskId: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -708,12 +712,12 @@ 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
|
||||
@@ -753,6 +757,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,
|
||||
@@ -865,6 +876,9 @@ 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,
|
||||
@@ -905,6 +919,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'),
|
||||
@@ -1136,9 +1164,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 = []
|
||||
@@ -1178,6 +1214,20 @@ 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++
|
||||
@@ -1217,6 +1267,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) {
|
||||
@@ -1240,7 +1300,17 @@ export default {
|
||||
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(
|
||||
@@ -1275,6 +1345,20 @@ 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)
|
||||
@@ -1323,6 +1407,9 @@ export default {
|
||||
bodyPartExamined: dicomInfo.bodyPart,
|
||||
instanceList: instanceList,
|
||||
ImageResizePath: ImageResizePath,
|
||||
|
||||
RadiopharmaceuticalInformationSequence: v.RadiopharmaceuticalInformationSequence,
|
||||
AcquisitionDate: v.AcquisitionDate,
|
||||
})
|
||||
}
|
||||
let text = JSON.stringify(Record)
|
||||
@@ -1364,7 +1451,20 @@ export default {
|
||||
}
|
||||
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)
|
||||
}
|
||||
@@ -1382,6 +1482,7 @@ export default {
|
||||
if (scope.IsImageSegment) {
|
||||
params.IsImageSegmentLabel = true
|
||||
}
|
||||
params.UploadBatchId = uploadBatchId
|
||||
addOrUpdateArchiveTaskStudy(params)
|
||||
.then((res) => {
|
||||
if (dicomInfo.failedFileCount === dicomInfo.fileCount) {
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
<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" />
|
||||
: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"
|
||||
:IsImageSegment="IsImageSegment" />
|
||||
:Criterion="Criterion" :VisitTaskId="VisitTaskId" :isUpload.sync="isUpload" :IsImageSegment="IsImageSegment"
|
||||
:forbid="forbid" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
@@ -29,6 +29,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
SubjectId: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -82,16 +86,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;
|
||||
|
||||
@@ -109,7 +109,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 ||
|
||||
@@ -239,6 +239,10 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
SubjectCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -544,8 +548,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)
|
||||
@@ -556,7 +561,7 @@ 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
|
||||
@@ -572,7 +577,7 @@ export default {
|
||||
}
|
||||
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({
|
||||
@@ -606,13 +611,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
|
||||
}
|
||||
},
|
||||
// file上传到oss
|
||||
async fileToOss(path, file, item) {
|
||||
async fileToOss(path, file, item, uploadBatchId) {
|
||||
try {
|
||||
let res = await this.OSSclient.multipartUpload(
|
||||
{
|
||||
@@ -625,6 +630,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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 5.2 KiB |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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`,
|
||||
|
||||
@@ -218,7 +218,7 @@ export default {
|
||||
.right-menu {
|
||||
// float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
line-height: 65px;
|
||||
// position: relative;
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -26,8 +26,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 +62,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)
|
||||
|
||||
@@ -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'),
|
||||
@@ -150,12 +156,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',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
|
||||
title: 'IRC Imaging System',
|
||||
title: 'EIC lmaging Trial Management System',
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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,133 +206,139 @@ 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
|
||||
.el-descriptions__body
|
||||
.el-descriptions__table
|
||||
.el-descriptions-item__cell.is-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center {
|
||||
text-align: center
|
||||
.el-descriptions__body
|
||||
.el-descriptions__table
|
||||
.el-descriptions-item__cell.is-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right {
|
||||
text-align: right
|
||||
.el-descriptions__body
|
||||
.el-descriptions__table
|
||||
.el-descriptions-item__cell.is-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 {
|
||||
@@ -350,7 +357,7 @@ body .el-table th.gutter {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
background: #000;
|
||||
z-index: 3999;
|
||||
}
|
||||
@@ -371,4 +378,4 @@ body .el-table th.gutter {
|
||||
height: 20px !important;
|
||||
vertical-align: -0.4em !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,6 +1,6 @@
|
||||
import defaultSettings from '@/settings'
|
||||
|
||||
const title = defaultSettings.title || 'IRC Imaging System'
|
||||
const title = defaultSettings.title || 'EIC lmaging Trial Management System'
|
||||
|
||||
export default function getPageTitle(pageTitle) {
|
||||
if (pageTitle) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function isNMReconstructable(imageSubType) {
|
||||
return imageSubType === 'RECON TOMO' || imageSubType === 'RECON GATED TOMO';
|
||||
}
|
||||
@@ -1,4 +1,11 @@
|
||||
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
|
||||
import {
|
||||
getImageTypeSubItemFromDataset,
|
||||
extractOrientationFromDataset,
|
||||
extractPositionFromDataset,
|
||||
extractSpacingFromDataset,
|
||||
extractSliceThicknessFromDataset,
|
||||
} from './extractPositioningFromDataset';
|
||||
function parseImageId(imageId) {
|
||||
// build a url by parsing out the url scheme and frame index from the imageId
|
||||
const firstColonIndex = imageId.indexOf(':');
|
||||
@@ -141,6 +148,19 @@ function populatePaletteColorLut(dataSet, imagePixelModule) {
|
||||
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);
|
||||
@@ -149,10 +169,47 @@ function metaDataProvider(type, imageId) {
|
||||
return;
|
||||
}
|
||||
if (type === 'imagePlaneModule') {
|
||||
const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6);
|
||||
const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
|
||||
const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
|
||||
// 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;
|
||||
|
||||
@@ -194,7 +251,7 @@ function metaDataProvider(type, imageId) {
|
||||
rowCosines,
|
||||
columnCosines,
|
||||
imagePositionPatient,
|
||||
sliceThickness: dataSet.floatString('x00180050'),
|
||||
sliceThickness,
|
||||
sliceLocation: dataSet.floatString('x00201041'),
|
||||
pixelSpacing,
|
||||
rowPixelSpacing,
|
||||
@@ -224,6 +281,11 @@ function metaDataProvider(type, imageId) {
|
||||
}
|
||||
return imagePixelModule;
|
||||
}
|
||||
// if (type === "multiframeModule") {
|
||||
// return {
|
||||
// NumberOfFrames: dataSet.uint16("x00280008") || dataSet.string("x00280008")
|
||||
// };
|
||||
// }
|
||||
// if (type === 'imagePixelModule') {
|
||||
// return {
|
||||
// samplesPerPixel: dataSet.uint16('x00280002'),
|
||||
@@ -249,4 +311,4 @@ function metaDataProvider(type, imageId) {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
export default metaDataProvider;
|
||||
export default metaDataProvider;
|
||||
|
||||
@@ -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,15 @@ 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) {
|
||||
let params = Object.assign({path: objectName}, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
let params = { trialId }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
resolve({
|
||||
name: objectName,
|
||||
url: res.url
|
||||
@@ -65,7 +75,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 +105,16 @@ 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) {
|
||||
let params = Object.assign({path: data.path}, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
let params = { trialId }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
|
||||
resolve({
|
||||
name: data.path,
|
||||
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name)
|
||||
@@ -169,17 +189,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 +209,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 +231,16 @@ 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) {
|
||||
let params = Object.assign({path: decodeUtf8(curPath)}, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
let params = { trialId }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
resolve({
|
||||
name: decodeUtf8(curPath),
|
||||
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(curPath)
|
||||
|
||||
@@ -5,8 +5,10 @@ import router from '@/router'
|
||||
import WHITELIST from "./whiteList"
|
||||
import moment from 'moment-timezone';
|
||||
import { encryptConfig } from "@/utils/encrypt"
|
||||
import SystemInfo from "@/utils/systemInfo";
|
||||
const ROUTER = require('@/router');
|
||||
axios.defaults.withCredentials = false
|
||||
const systemInfo = new SystemInfo();
|
||||
const service = axios.create({
|
||||
baseURL: '/api',
|
||||
// baseURL: process.env.NODE_ENV === 'prod' ? "https://api.irc.extimaging.com" : '/api',
|
||||
@@ -26,6 +28,40 @@ service.interceptors.request.use(
|
||||
var language = zzSessionStorage.getItem('lang')
|
||||
config.headers['Accept-Language'] = language === 'en' ? 'en-US,en;q=0.5' : 'zh-CN,zh;q=0.9'
|
||||
config.headers['TimeZoneId'] = moment.tz.guess()
|
||||
const allInfo = systemInfo.getAllInfo();
|
||||
let obj = {
|
||||
browser: {
|
||||
name: allInfo.browser.name,
|
||||
version: allInfo.browser.version,
|
||||
},
|
||||
platform: allInfo.platform,
|
||||
os: {
|
||||
name: allInfo.os.name,
|
||||
version: allInfo.os.version
|
||||
},
|
||||
hardware: {
|
||||
logicalCores: allInfo.hardware.logicalCores,
|
||||
deviceMemory: allInfo.hardware.deviceMemory
|
||||
},
|
||||
webgl: {
|
||||
version: allInfo.webgl.version,
|
||||
renderer: allInfo.webgl.renderer,
|
||||
vendor: allInfo.webgl.vendor,
|
||||
shadingLanguage: allInfo.webgl.shadingLanguage,
|
||||
gpuType: {
|
||||
type: allInfo.webgl.gpuType.type,
|
||||
discrete: allInfo.webgl.gpuType.discrete,
|
||||
},
|
||||
performance: {
|
||||
tier: allInfo.webgl.performance.tier,
|
||||
},
|
||||
extensions: {
|
||||
length: allInfo.webgl.extensions.length,
|
||||
}
|
||||
}
|
||||
}
|
||||
let guid = await systemInfo.generateGuid(obj)
|
||||
config.headers['BrowserFingerprint'] = guid
|
||||
if (config.ENCRYPT) {
|
||||
try {
|
||||
config = await encryptConfig(config)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
async function queryWindowManagement() {
|
||||
return await navigator.permissions.query({ name: 'window-management' });;
|
||||
}
|
||||
async function getPermission() {
|
||||
const permission = await queryWindowManagement();
|
||||
console.log(permission.state, 'permission.state')
|
||||
if (permission.state === "granted") { // 已经授权
|
||||
return true
|
||||
} else if (permission.state === "prompt") { // 询问是否授权
|
||||
// 请求授权
|
||||
if (navigator.permissions.request) {
|
||||
navigator.permissions.request({ name: 'window-management' })
|
||||
}
|
||||
return false
|
||||
} else if (permission.state === "denied") {
|
||||
// 权限被拒绝
|
||||
return false
|
||||
}
|
||||
}
|
||||
function getScreen() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let multiScreen = []
|
||||
if (window.getScreenDetails) {
|
||||
let getScreensProsime1 = window.getScreenDetails();
|
||||
getScreensProsime1.then((c) => {
|
||||
if (c instanceof Array) {
|
||||
multiScreen = c
|
||||
} else if (c instanceof Object) {
|
||||
multiScreen = c.screens
|
||||
} else {
|
||||
multiScreen = []
|
||||
}
|
||||
resolve(multiScreen)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
});
|
||||
} else if (window.getScreens) {
|
||||
let getScreensProsime = window.getScreens();
|
||||
getScreensProsime.then((c) => {
|
||||
if (c instanceof Array) {
|
||||
multiScreen = c
|
||||
} else if (c instanceof Object) {
|
||||
multiScreen = c.screens
|
||||
} else {
|
||||
multiScreen = []
|
||||
}
|
||||
resolve(multiScreen)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
export async function openWindow(url, name, Skip = false) {
|
||||
// 判断浏览器是否兼容
|
||||
// 高版本的谷歌,edge不支持跨屏,需要降低浏览器版本86.0版
|
||||
if (!window.getScreens && !window.getScreenDetails) {
|
||||
console.log('你的浏览器版本不支持多屏展示功能!');
|
||||
return window.open(url, name);
|
||||
}
|
||||
let permission = await getPermission()
|
||||
if (!permission) {
|
||||
// alert('使用多屏功能请先进行授权')
|
||||
if (Skip) {
|
||||
return window.open(url, name);
|
||||
}
|
||||
return false
|
||||
}
|
||||
let multiScreen = await getScreen()
|
||||
console.log(multiScreen, 'multiScreen')
|
||||
// 判断是否2个屏幕
|
||||
if (multiScreen.length < 2) {
|
||||
console.log('请接入多个显示屏!');
|
||||
return window.open(url, name);
|
||||
}
|
||||
console.log(screen, 'screen')
|
||||
// 获取当前屏幕availLeft信息和所有信息比对,取另一个屏幕数据
|
||||
let currentAvailLeft = screen.availLeft ? screen.availLeft : '0'
|
||||
let newCurr = multiScreen.find((t) => t.availLeft != currentAvailLeft)
|
||||
console.log(newCurr, 'newCurr')
|
||||
let fulls = ''
|
||||
for (let key in newCurr) {
|
||||
fulls += `${key}=${(newCurr[key] || newCurr[key] === 0) ? newCurr[key] : 0},`
|
||||
}
|
||||
console.log(fulls, 'fulls')
|
||||
return window.open(url, name, fulls);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import streamSaver from "streamsaver";
|
||||
import "streamsaver/examples/zip-stream.js";
|
||||
import "./zip-stream.js";
|
||||
import store from '@/store'
|
||||
import dcmjs from './dcmUpload/dcmjs'
|
||||
streamSaver.mitm = `${window.location.origin}/mitm.html?version=2.0.0`
|
||||
|
||||
@@ -0,0 +1,686 @@
|
||||
// 浏览器信息检测
|
||||
class SystemInfo {
|
||||
constructor() {
|
||||
this.info = {
|
||||
browser: this.getBrowserInfo(),
|
||||
os: this.getOSInfo(),
|
||||
hardware: this.getHardwareInfo(),
|
||||
webgl: this.getWebGLInfo()
|
||||
};
|
||||
}
|
||||
|
||||
// 获取浏览器信息
|
||||
getBrowserInfo() {
|
||||
const ua = navigator.userAgent;
|
||||
let browser = {
|
||||
name: 'Unknown',
|
||||
version: 'Unknown',
|
||||
fullVersion: navigator.appVersion
|
||||
};
|
||||
|
||||
// 检测浏览器类型
|
||||
if (ua.includes('Firefox')) {
|
||||
browser.name = 'Firefox';
|
||||
browser.version = this.extractVersion(ua, 'Firefox');
|
||||
} else if (ua.includes('Chrome') && !ua.includes('Edg') && !ua.includes('OPR')) {
|
||||
browser.name = 'Chrome';
|
||||
browser.version = this.extractVersion(ua, 'Chrome');
|
||||
} else if (ua.includes('Safari') && !ua.includes('Chrome')) {
|
||||
browser.name = 'Safari';
|
||||
browser.version = this.extractVersion(ua, 'Version');
|
||||
} else if (ua.includes('Edg')) {
|
||||
browser.name = 'Edge';
|
||||
browser.version = this.extractVersion(ua, 'Edg');
|
||||
} else if (ua.includes('OPR') || ua.includes('Opera')) {
|
||||
browser.name = 'Opera';
|
||||
browser.version = this.extractVersion(ua, 'OPR') || this.extractVersion(ua, 'Opera');
|
||||
} else if (ua.includes('Trident') || ua.includes('MSIE')) {
|
||||
browser.name = 'Internet Explorer';
|
||||
browser.version = this.extractVersion(ua, 'MSIE') || this.extractVersion(ua, 'rv:');
|
||||
}
|
||||
|
||||
return browser;
|
||||
}
|
||||
|
||||
// 提取版本号
|
||||
extractVersion(userAgent, browserName) {
|
||||
const match = userAgent.match(new RegExp(`${browserName}/([0-9]+(\\.[0-9]+)?)`));
|
||||
return match ? match[1] : 'Unknown';
|
||||
}
|
||||
|
||||
// 获取操作系统信息
|
||||
getOSInfo() {
|
||||
const ua = navigator.userAgent;
|
||||
let os = {
|
||||
name: 'Unknown',
|
||||
version: 'Unknown',
|
||||
architecture: this.getArchitecture()
|
||||
};
|
||||
|
||||
if (ua.includes('Windows')) {
|
||||
os.name = 'Windows';
|
||||
if (ua.includes('Windows NT 10.0')) os.version = '10';
|
||||
else if (ua.includes('Windows NT 6.3')) os.version = '8.1';
|
||||
else if (ua.includes('Windows NT 6.2')) os.version = '8';
|
||||
else if (ua.includes('Windows NT 6.1')) os.version = '7';
|
||||
else if (ua.includes('Windows NT 6.0')) os.version = 'Vista';
|
||||
else if (ua.includes('Windows NT 5.1')) os.version = 'XP';
|
||||
} else if (ua.includes('Mac OS X')) {
|
||||
os.name = 'macOS';
|
||||
const match = ua.match(/Mac OS X (\d+[._]\d+)/);
|
||||
if (match) os.version = match[1].replace('_', '.');
|
||||
} else if (ua.includes('Linux')) {
|
||||
os.name = 'Linux';
|
||||
} else if (ua.includes('Android')) {
|
||||
os.name = 'Android';
|
||||
const match = ua.match(/Android ([0-9.]+)/);
|
||||
if (match) os.version = match[1];
|
||||
} else if (ua.includes('like Mac')) {
|
||||
os.name = 'iOS';
|
||||
const match = ua.match(/OS (\d+[_]\d+)/);
|
||||
if (match) os.version = match[1].replace('_', '.');
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// 获取系统架构
|
||||
getArchitecture() {
|
||||
if (navigator.userAgent.includes('x64') || navigator.userAgent.includes('x86_64')) {
|
||||
return '64-bit';
|
||||
} else if (navigator.userAgent.includes('x86') || navigator.userAgent.includes('i686')) {
|
||||
return '32-bit';
|
||||
} else if (navigator.userAgent.includes('ARM')) {
|
||||
return 'ARM';
|
||||
} else if (navigator.userAgent.includes('Win64')) {
|
||||
return '64-bit';
|
||||
}
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
// 获取硬件信息
|
||||
getHardwareInfo() {
|
||||
return {
|
||||
logicalCores: navigator.hardwareConcurrency || 'Unknown',
|
||||
deviceMemory: navigator.deviceMemory ? `${navigator.deviceMemory} GB` : 'Unknown',
|
||||
maxTouchPoints: navigator.maxTouchPoints || 0
|
||||
};
|
||||
}
|
||||
|
||||
// 获取WebGL和显卡信息
|
||||
getWebGLInfo() {
|
||||
const webglInfo = {
|
||||
webgl1: this.getWebGLContextInfo('webgl'),
|
||||
webgl2: this.getWebGLContextInfo('webgl2'),
|
||||
supported: false,
|
||||
renderer: 'Unknown',
|
||||
vendor: 'Unknown',
|
||||
version: 'Unknown',
|
||||
shadingLanguage: 'Unknown',
|
||||
extensions: []
|
||||
};
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
let gl = null;
|
||||
|
||||
// 尝试获取WebGL2上下文
|
||||
try {
|
||||
gl = canvas.getContext('webgl2') || canvas.getContext('experimental-webgl2');
|
||||
} catch (e) {
|
||||
console.log('WebGL2 not supported:', e.message);
|
||||
}
|
||||
|
||||
// 如果WebGL2不可用,尝试WebGL1
|
||||
if (!gl) {
|
||||
try {
|
||||
gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
||||
} catch (e) {
|
||||
console.log('WebGL not supported:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (gl) {
|
||||
webglInfo.supported = true;
|
||||
|
||||
// 获取显卡信息
|
||||
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
if (debugInfo) {
|
||||
webglInfo.renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || 'Unknown';
|
||||
webglInfo.vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || 'Unknown';
|
||||
}
|
||||
|
||||
// 获取WebGL版本信息
|
||||
webglInfo.version = gl.getParameter(gl.VERSION) || 'Unknown';
|
||||
webglInfo.shadingLanguage = gl.getParameter(gl.SHADING_LANGUAGE_VERSION) || 'Unknown';
|
||||
|
||||
// 获取支持的扩展
|
||||
try {
|
||||
webglInfo.extensions = gl.getSupportedExtensions() || [];
|
||||
} catch (e) {
|
||||
console.log('无法获取WebGL扩展:', e.message);
|
||||
}
|
||||
|
||||
// 检查GPU性能级别
|
||||
webglInfo.performance = this.getGPUPerformanceInfo(gl);
|
||||
|
||||
// 检查内存信息(如果支持)
|
||||
webglInfo.memoryInfo = this.getGPUMemoryInfo(gl);
|
||||
|
||||
// 检查是否使用集成显卡
|
||||
if (webglInfo.renderer) {
|
||||
webglInfo.gpuType = this.detectGPUType(webglInfo.renderer);
|
||||
}
|
||||
}
|
||||
|
||||
return webglInfo;
|
||||
}
|
||||
|
||||
// 获取WebGL上下文的具体信息
|
||||
getWebGLContextInfo(contextType) {
|
||||
const canvas = document.createElement('canvas');
|
||||
let gl = null;
|
||||
|
||||
try {
|
||||
gl = canvas.getContext(contextType) ||
|
||||
canvas.getContext(`experimental-${contextType}`);
|
||||
} catch (e) {
|
||||
return { supported: false, error: e.message };
|
||||
}
|
||||
|
||||
if (!gl) {
|
||||
return { supported: false };
|
||||
}
|
||||
|
||||
return {
|
||||
supported: true,
|
||||
context: gl
|
||||
};
|
||||
}
|
||||
|
||||
// 获取GPU性能信息
|
||||
getGPUPerformanceInfo(gl) {
|
||||
const info = { tier: 'unknown', features: [] };
|
||||
|
||||
// 检查是否支持高性能特性
|
||||
try {
|
||||
// 检查帧缓冲
|
||||
if (gl.checkFramebufferStatus) {
|
||||
info.features.push('framebuffer');
|
||||
}
|
||||
|
||||
// 检查浮点纹理
|
||||
const floatExt = gl.getExtension('OES_texture_float') ||
|
||||
gl.getExtension('EXT_color_buffer_float');
|
||||
if (floatExt) info.features.push('float_textures');
|
||||
|
||||
// 检查多重采样
|
||||
const msaaExt = gl.getExtension('WEBGL_multisampled_render_to_texture');
|
||||
if (msaaExt) info.features.push('msaa');
|
||||
|
||||
// 检查实例化渲染
|
||||
const instancingExt = gl.getExtension('ANGLE_instanced_arrays') ||
|
||||
gl.getExtension('WEBGL_draw_buffers');
|
||||
if (instancingExt) info.features.push('instancing');
|
||||
|
||||
// 尝试检测性能级别(基于支持的扩展)
|
||||
if (info.features.includes('float_textures') &&
|
||||
info.features.includes('msaa') &&
|
||||
info.features.includes('instancing')) {
|
||||
info.tier = 'high';
|
||||
} else if (info.features.length >= 2) {
|
||||
info.tier = 'medium';
|
||||
} else {
|
||||
info.tier = 'low';
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('获取GPU性能信息失败:', e);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// 获取GPU内存信息
|
||||
getGPUMemoryInfo(gl) {
|
||||
const memoryInfo = { estimatedMemory: 'Unknown' };
|
||||
|
||||
// 尝试通过扩展获取内存信息
|
||||
try {
|
||||
// 检查是否支持内存信息扩展
|
||||
const memoryExt = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
if (memoryExt) {
|
||||
// 一些浏览器会通过UNMASKED_RENDERER_WEBGL暴露内存信息
|
||||
const renderer = gl.getParameter(memoryExt.UNMASKED_RENDERER_WEBGL);
|
||||
if (renderer) {
|
||||
// 尝试从渲染器字符串中提取内存信息
|
||||
const match = renderer.match(/(\d+)\s*MB|(\d+)\s*GB|VRAM\s*:\s*(\d+)/i);
|
||||
if (match) {
|
||||
memoryInfo.estimatedMemory = match[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过创建大纹理测试内存
|
||||
memoryInfo.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
|
||||
memoryInfo.maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
|
||||
} catch (e) {
|
||||
// 静默失败
|
||||
}
|
||||
|
||||
return memoryInfo;
|
||||
}
|
||||
|
||||
// 检测GPU类型
|
||||
detectGPUType(renderer) {
|
||||
const r = renderer.toLowerCase();
|
||||
|
||||
if (r.includes('nvidia') || r.includes('geforce') || r.includes('gtx') || r.includes('rtx')) {
|
||||
return { type: 'NVIDIA', discrete: true };
|
||||
} else if (r.includes('amd') || r.includes('radeon') || r.includes('rx')) {
|
||||
return { type: 'AMD', discrete: true };
|
||||
} else if (r.includes('intel') || r.includes('hd graphics') || r.includes('iris') || r.includes('uhd')) {
|
||||
return { type: 'Intel', discrete: false };
|
||||
} else if (r.includes('apple') || r.includes('apple gpu') || r.includes('apple m')) {
|
||||
return { type: 'Apple Silicon', discrete: false };
|
||||
} else if (r.includes('mali') || r.includes('adreno') || r.includes('powervr')) {
|
||||
return { type: 'Mobile GPU', discrete: false };
|
||||
} else if (r.includes('microsoft') || r.includes('basic')) {
|
||||
return { type: 'Software Renderer', discrete: false };
|
||||
}
|
||||
|
||||
return { type: 'Unknown', discrete: false };
|
||||
}
|
||||
|
||||
// 获取屏幕信息
|
||||
getScreenInfo() {
|
||||
return {
|
||||
width: window.screen.width,
|
||||
height: window.screen.height,
|
||||
colorDepth: window.screen.colorDepth,
|
||||
pixelDepth: window.screen.pixelDepth,
|
||||
devicePixelRatio: window.devicePixelRatio || 1,
|
||||
orientation: window.screen.orientation ? window.screen.orientation.type : 'unknown'
|
||||
};
|
||||
}
|
||||
|
||||
// 获取所有系统信息
|
||||
getAllInfo() {
|
||||
return {
|
||||
...this.info,
|
||||
screen: this.getScreenInfo(),
|
||||
userAgent: navigator.userAgent,
|
||||
platform: navigator.platform,
|
||||
language: navigator.language,
|
||||
languages: navigator.languages,
|
||||
cookiesEnabled: navigator.cookieEnabled,
|
||||
online: navigator.onLine,
|
||||
javaEnabled: navigator.javaEnabled ? navigator.javaEnabled() : false,
|
||||
pdfViewerEnabled: navigator.pdfViewerEnabled || false,
|
||||
doNotTrack: navigator.doNotTrack || 'unknown',
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
dateTimeFormat: new Date().toString()
|
||||
};
|
||||
}
|
||||
|
||||
// 格式化输出
|
||||
formatAsText() {
|
||||
const info = this.getAllInfo();
|
||||
let output = '========== 系统信息 ==========\n\n';
|
||||
|
||||
// 浏览器信息
|
||||
output += '=== 浏览器信息 ===\n';
|
||||
output += `浏览器: ${info.browser.name} ${info.browser.version}\n`;
|
||||
output += `完整版本: ${info.browser.fullVersion}\n`;
|
||||
output += `用户代理: ${info.userAgent}\n\n`;
|
||||
|
||||
// 操作系统信息
|
||||
output += '=== 操作系统信息 ===\n';
|
||||
output += `系统: ${info.os.name} ${info.os.version}\n`;
|
||||
output += `架构: ${info.os.architecture}\n`;
|
||||
output += `平台: ${info.platform}\n\n`;
|
||||
|
||||
// 硬件信息
|
||||
output += '=== 硬件信息 ===\n';
|
||||
output += `逻辑核心数: ${info.hardware.logicalCores}\n`;
|
||||
output += `设备内存: ${info.hardware.deviceMemory}\n`;
|
||||
output += `最大触摸点数: ${info.hardware.maxTouchPoints}\n\n`;
|
||||
|
||||
// 屏幕信息
|
||||
output += '=== 屏幕信息 ===\n';
|
||||
output += `分辨率: ${info.screen.width} × ${info.screen.height}\n`;
|
||||
output += `设备像素比: ${info.screen.devicePixelRatio}\n`;
|
||||
output += `颜色深度: ${info.screen.colorDepth} 位\n`;
|
||||
output += `像素深度: ${info.screen.pixelDepth} 位\n`;
|
||||
output += `方向: ${info.screen.orientation}\n\n`;
|
||||
|
||||
// WebGL信息
|
||||
output += '=== WebGL 信息 ===\n';
|
||||
output += `WebGL 支持: ${info.webgl.supported ? '是' : '否'}\n`;
|
||||
|
||||
if (info.webgl.supported) {
|
||||
output += `WebGL 版本: ${info.webgl.version}\n`;
|
||||
output += `显卡型号: ${info.webgl.renderer}\n`;
|
||||
output += `显卡厂商: ${info.webgl.vendor}\n`;
|
||||
output += `着色语言: ${info.webgl.shadingLanguage}\n`;
|
||||
|
||||
if (info.webgl.gpuType) {
|
||||
output += `GPU 类型: ${info.webgl.gpuType.type}\n`;
|
||||
output += `独立显卡: ${info.webgl.gpuType.discrete ? '是' : '否'}\n`;
|
||||
}
|
||||
|
||||
output += `性能等级: ${info.webgl.performance.tier}\n`;
|
||||
output += `支持特性: ${info.webgl.performance.features.join(', ')}\n`;
|
||||
|
||||
if (info.webgl.memoryInfo.estimatedMemory !== 'Unknown') {
|
||||
output += `显存估计: ${info.webgl.memoryInfo.estimatedMemory}\n`;
|
||||
}
|
||||
|
||||
if (info.webgl.memoryInfo.maxTextureSize) {
|
||||
output += `最大纹理尺寸: ${info.webgl.memoryInfo.maxTextureSize}\n`;
|
||||
}
|
||||
|
||||
output += `WebGL 扩展数: ${info.webgl.extensions.length}\n`;
|
||||
}
|
||||
|
||||
// 其他信息
|
||||
output += '\n=== 其他信息 ===\n';
|
||||
output += `语言: ${info.language}\n`;
|
||||
output += `支持语言: ${info.languages.join(', ')}\n`;
|
||||
output += `时区: ${info.timezone}\n`;
|
||||
output += `Cookie 支持: ${info.cookiesEnabled ? '是' : '否'}\n`;
|
||||
output += `在线状态: ${info.online ? '在线' : '离线'}\n`;
|
||||
output += `Java 支持: ${info.javaEnabled ? '是' : '否'}\n`;
|
||||
output += `PDF 查看器: ${info.pdfViewerEnabled ? '支持' : '不支持'}\n`;
|
||||
output += `Do Not Track: ${info.doNotTrack}\n`;
|
||||
output += `当前时间: ${info.dateTimeFormat}\n`;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// 创建HTML显示
|
||||
createInfoHTML() {
|
||||
const info = this.getAllInfo();
|
||||
let html = `
|
||||
<div class="system-info">
|
||||
<h2>系统信息</h2>
|
||||
|
||||
<div class="info-section">
|
||||
<h3>🌐 浏览器信息</h3>
|
||||
<table>
|
||||
<tr><td>浏览器</td><td>${info.browser.name} ${info.browser.version}</td></tr>
|
||||
<tr><td>用户代理</td><td><code>${info.userAgent}</code></td></tr>
|
||||
<tr><td>平台</td><td>${info.platform}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="info-section">
|
||||
<h3>💻 操作系统</h3>
|
||||
<table>
|
||||
<tr><td>系统</td><td>${info.os.name} ${info.os.version}</td></tr>
|
||||
<tr><td>架构</td><td>${info.os.architecture}</td></tr>
|
||||
<tr><td>语言</td><td>${info.language}</td></tr>
|
||||
<tr><td>时区</td><td>${info.timezone}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="info-section">
|
||||
<h3>🖥️ 硬件信息</h3>
|
||||
<table>
|
||||
<tr><td>CPU 核心数</td><td>${info.hardware.logicalCores}</td></tr>
|
||||
<tr><td>设备内存</td><td>${info.hardware.deviceMemory}</td></tr>
|
||||
<tr><td>屏幕分辨率</td><td>${info.screen.width} × ${info.screen.height}</td></tr>
|
||||
<tr><td>设备像素比</td><td>${info.screen.devicePixelRatio}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (info.webgl.supported) {
|
||||
html += `
|
||||
<div class="info-section">
|
||||
<h3>🎮 WebGL & 显卡信息</h3>
|
||||
<table>
|
||||
<tr><td>WebGL 支持</td><td>✅ 已支持</td></tr>
|
||||
<tr><td>WebGL 版本</td><td>${info.webgl.version}</td></tr>
|
||||
<tr><td>显卡型号</td><td><strong>${info.webgl.renderer}</strong></td></tr>
|
||||
<tr><td>显卡厂商</td><td>${info.webgl.vendor}</td></tr>
|
||||
<tr><td>GPU 类型</td><td>${info.webgl.gpuType.type} ${info.webgl.gpuType.discrete ? '(独立显卡)' : '(集成显卡)'}</td></tr>
|
||||
<tr><td>着色语言</td><td>${info.webgl.shadingLanguage}</td></tr>
|
||||
<tr><td>性能等级</td><td><span class="perf-${info.webgl.performance.tier}">${info.webgl.performance.tier}</span></td></tr>
|
||||
<tr><td>WebGL 扩展数</td><td>${info.webgl.extensions.length} 个</td></tr>
|
||||
`;
|
||||
|
||||
if (info.webgl.memoryInfo.estimatedMemory !== 'Unknown') {
|
||||
html += `<tr><td>显存估计</td><td>${info.webgl.memoryInfo.estimatedMemory}</td></tr>`;
|
||||
}
|
||||
|
||||
html += `</table></div>`;
|
||||
} else {
|
||||
html += `
|
||||
<div class="info-section">
|
||||
<h3>🎮 WebGL & 显卡信息</h3>
|
||||
<p style="color: red;">❌ WebGL 不支持</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
deepSortObject(obj) {
|
||||
if (obj === null || typeof obj !== 'object') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(deepSortObject);
|
||||
}
|
||||
|
||||
const sorted = {};
|
||||
Object.keys(obj).sort().forEach(key => {
|
||||
sorted[key] = this.deepSortObject(obj[key]);
|
||||
});
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
getCanonicalString(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
|
||||
const sorted = this.deepSortObject(obj);
|
||||
return JSON.stringify(sorted);
|
||||
}
|
||||
|
||||
// 简单哈希函数
|
||||
simpleHash(str) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// 简单SHA-256模拟
|
||||
simpleSHA256(str) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
|
||||
const hashArray = [];
|
||||
for (let i = 0; i < 8; i++) {
|
||||
hashArray[i] = (hash + i * 2654435761) >>> 0;
|
||||
}
|
||||
|
||||
return hashArray;
|
||||
}
|
||||
|
||||
// 格式化哈希为GUID
|
||||
formatHashAsGuid(hashArray) {
|
||||
const hexParts = hashArray.map(h => h.toString(16).padStart(8, '0'));
|
||||
return `${hexParts[0]}${hexParts[1].substring(0, 4)}-${hexParts[1].substring(4)}-${hexParts[2].substring(0, 4)}-${hexParts[3].substring(0, 4)}-${hexParts[3].substring(4)}${hexParts[4]}${hexParts[5]}`;
|
||||
}
|
||||
|
||||
// 1. 确定性哈希算法
|
||||
objectToGuidDeterministic(obj) {
|
||||
const canonicalString = this.getCanonicalString(obj);
|
||||
const hash = this.simpleSHA256(canonicalString);
|
||||
return this.formatHashAsGuid(hash).toUpperCase();
|
||||
}
|
||||
|
||||
// 2. 伪随机算法
|
||||
getSeedFromObject(obj) {
|
||||
const str = JSON.stringify(obj);
|
||||
return this.simpleHash(str);
|
||||
}
|
||||
|
||||
createSeededRandom(seed) {
|
||||
let state = seed;
|
||||
return function () {
|
||||
state = (state * 1664525 + 1013904223) >>> 0;
|
||||
return (state & 0x3FFFFFFF) / 0x3FFFFFFF;
|
||||
};
|
||||
}
|
||||
|
||||
generateVersion4Guid(randomFn) {
|
||||
let guid = '';
|
||||
|
||||
for (let i = 0; i < 32; i++) {
|
||||
if (i === 8 || i === 12 || i === 16 || i === 20) {
|
||||
guid += '-';
|
||||
}
|
||||
|
||||
if (i === 12) {
|
||||
guid += '4';
|
||||
} else if (i === 16) {
|
||||
const variant = Math.floor(randomFn() * 4);
|
||||
guid += (8 + variant).toString(16).toUpperCase();
|
||||
} else {
|
||||
const randomHex = Math.floor(randomFn() * 16).toString(16);
|
||||
guid += randomHex;
|
||||
}
|
||||
}
|
||||
|
||||
return guid.toUpperCase();
|
||||
}
|
||||
|
||||
objectToGuidPseudorandom(obj) {
|
||||
const seed = this.getSeedFromObject(obj);
|
||||
const prng = this.createSeededRandom(seed);
|
||||
return this.generateVersion4Guid(prng);
|
||||
}
|
||||
|
||||
// 3. Crypto API算法(同步版本)
|
||||
objectToGuidCryptoSync(obj) {
|
||||
try {
|
||||
const str = this.getCanonicalString(obj);
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
|
||||
const bytes = new Array(16);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
bytes[i] = (hash + i * 2654435761) & 0xFF;
|
||||
}
|
||||
|
||||
bytes[6] = (bytes[6] & 0x0F) | 0x40;
|
||||
bytes[8] = (bytes[8] & 0x3F) | 0x80;
|
||||
|
||||
return bytes.map(b => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5')
|
||||
.toUpperCase();
|
||||
} catch (error) {
|
||||
return this.objectToGuidDeterministic(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 组合算法
|
||||
combineComponents(deterministicHash, namespaceHash, timestamp, randomComponent) {
|
||||
const hashDigits = deterministicHash.replace(/-/g, '');
|
||||
const bytes = new Array(16);
|
||||
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const hashByte = parseInt(hashDigits.substr(i * 2, 2), 16) || 0;
|
||||
const nsByte = (namespaceHash >> (i * 2)) & 0xFF;
|
||||
const timeByte = (timestamp >> (i * 2)) & 0xFF;
|
||||
const randomByte = parseInt(randomComponent.substr(i % 8, 1), 16) || 0;
|
||||
|
||||
bytes[i] = (hashByte ^ nsByte ^ timeByte ^ randomByte) & 0xFF;
|
||||
}
|
||||
|
||||
bytes[6] = (bytes[6] & 0x0F) | 0x40;
|
||||
bytes[8] = (bytes[8] & 0x3F) | 0x80;
|
||||
|
||||
return bytes.map(b => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5')
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
objectToGuidCombined(obj, namespace = '') {
|
||||
const deterministicHash = this.objectToGuidDeterministic(obj);
|
||||
const namespaceHash = namespace ? this.simpleHash(namespace) : 0;
|
||||
const timestamp = Date.now();
|
||||
const randomComponent = Math.random().toString(16).substr(2, 8);
|
||||
|
||||
return this.combineComponents(deterministicHash, namespaceHash, timestamp, randomComponent);
|
||||
}
|
||||
|
||||
// 主生成函数
|
||||
async generateGuid(inputText, inputType, algorithmType = 'deterministic') {
|
||||
let obj;
|
||||
try {
|
||||
if (inputType === 'json') {
|
||||
obj = JSON.parse(inputText);
|
||||
} else {
|
||||
obj = inputText
|
||||
}
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
let guid;
|
||||
let algorithmName;
|
||||
try {
|
||||
switch (algorithmType) {
|
||||
case 'deterministic':
|
||||
guid = this.objectToGuidDeterministic(obj);
|
||||
algorithmName = '确定性哈希算法';
|
||||
break;
|
||||
case 'pseudorandom':
|
||||
guid = this.objectToGuidPseudorandom(obj);
|
||||
algorithmName = '伪随机算法';
|
||||
break;
|
||||
case 'crypto':
|
||||
guid = this.objectToGuidCryptoSync(obj);
|
||||
algorithmName = 'Crypto API算法';
|
||||
break;
|
||||
case 'combined':
|
||||
guid = this.objectToGuidCombined(obj, 'example-namespace');
|
||||
algorithmName = '组合算法';
|
||||
break;
|
||||
default:
|
||||
guid = '未知算法';
|
||||
algorithmName = '未知';
|
||||
}
|
||||
return guid;
|
||||
} catch (error) {
|
||||
return error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = SystemInfo;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
window.SystemInfo = SystemInfo;
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
class Crc32 {
|
||||
constructor() {
|
||||
this.crc = -1
|
||||
}
|
||||
|
||||
append(data) {
|
||||
var crc = this.crc | 0; var table = this.table
|
||||
for (var offset = 0, len = data.length | 0; offset < len; offset++) {
|
||||
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]
|
||||
}
|
||||
this.crc = crc
|
||||
}
|
||||
|
||||
get() {
|
||||
return ~this.crc
|
||||
}
|
||||
}
|
||||
Crc32.prototype.table = (() => {
|
||||
var i; var j; var t; var table = []
|
||||
for (i = 0; i < 256; i++) {
|
||||
t = i
|
||||
for (j = 0; j < 8; j++) {
|
||||
t = (t & 1)
|
||||
? (t >>> 1) ^ 0xEDB88320
|
||||
: t >>> 1
|
||||
}
|
||||
table[i] = t
|
||||
}
|
||||
return table
|
||||
})()
|
||||
|
||||
const getDataHelper = byteLength => {
|
||||
var uint8 = new Uint8Array(byteLength)
|
||||
return {
|
||||
array: uint8,
|
||||
view: new DataView(uint8.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
const ZIP_SIGNATURE_LOCAL = 0x04034b50
|
||||
const ZIP_SIGNATURE_CENTRAL = 0x02014b50
|
||||
const ZIP_SIGNATURE_EOCD = 0x06054b50
|
||||
const ZIP_SIGNATURE_ZIP64_EOCD = 0x06064b50
|
||||
const ZIP_SIGNATURE_ZIP64_LOCATOR = 0x07064b50
|
||||
|
||||
const ZIP64_MAGIC = 0xFFFFFFFF
|
||||
|
||||
function u16(view, offset, value) { view.setUint16(offset, value, true) }
|
||||
function u32(view, offset, value) { view.setUint32(offset, value >>> 0, true) }
|
||||
|
||||
function concatUint8(chunks, total) {
|
||||
const out = new Uint8Array(total)
|
||||
let off = 0
|
||||
for (const c of chunks) {
|
||||
out.set(c, off)
|
||||
off += c.length
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function createWriter(underlyingSource) {
|
||||
const files = Object.create(null)
|
||||
const filenames = []
|
||||
const encoder = new TextEncoder() // 保持UTF-8编码
|
||||
|
||||
let offset = 0 // bytes written to output so far
|
||||
let activeZipIndex = 0
|
||||
let ctrl
|
||||
let activeZipObject
|
||||
let closed = false
|
||||
|
||||
function processNextChunk() {
|
||||
if (!activeZipObject) return
|
||||
|
||||
// directory entry: just local header + immediate footer
|
||||
if (activeZipObject.directory) {
|
||||
if (!activeZipObject.headerWritten) {
|
||||
activeZipObject.writeLocalHeader()
|
||||
activeZipObject.headerWritten = true
|
||||
}
|
||||
if (!activeZipObject.footerWritten) {
|
||||
activeZipObject.writeDataDescriptor() // will be zeros
|
||||
activeZipObject.footerWritten = true
|
||||
next()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (!activeZipObject.reader) {
|
||||
if (!activeZipObject.fileLike || !activeZipObject.fileLike.stream) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
activeZipObject.crc = new Crc32()
|
||||
activeZipObject.reader = activeZipObject.fileLike.stream().getReader()
|
||||
activeZipObject.writeLocalHeader()
|
||||
activeZipObject.headerWritten = true
|
||||
return
|
||||
}
|
||||
|
||||
return activeZipObject.reader.read().then(({ done, value }) => {
|
||||
if (done) {
|
||||
activeZipObject.writeDataDescriptor()
|
||||
activeZipObject.footerWritten = true
|
||||
next()
|
||||
return
|
||||
}
|
||||
const chunk = value instanceof Uint8Array ? value : new Uint8Array(value)
|
||||
activeZipObject.crc.append(chunk)
|
||||
activeZipObject.uncompressedLength += chunk.length
|
||||
activeZipObject.compressedLength += chunk.length
|
||||
ctrl.enqueue(chunk)
|
||||
offset += chunk.length
|
||||
})
|
||||
}
|
||||
|
||||
function next() {
|
||||
activeZipIndex++
|
||||
activeZipObject = files[filenames[activeZipIndex]]
|
||||
if (activeZipObject) {
|
||||
processNextChunk()
|
||||
} else if (closed) {
|
||||
closeZip()
|
||||
}
|
||||
}
|
||||
|
||||
function dosDateTime(date) {
|
||||
const dt = new Date(date)
|
||||
const time = ((dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() / 2)) & 0xFFFF
|
||||
const d = (((dt.getFullYear() - 1980) << 9) | ((dt.getMonth() + 1) << 5) | dt.getDate()) & 0xFFFF
|
||||
return { time, date: d }
|
||||
}
|
||||
|
||||
const zipWriter = {
|
||||
enqueue(fileLike) {
|
||||
if (closed) throw new TypeError('Cannot enqueue after close()')
|
||||
|
||||
let name = String(fileLike.name || '').trim()
|
||||
if (!name) throw new Error('Missing file name')
|
||||
|
||||
if (fileLike.directory && !name.endsWith('/')) name += '/'
|
||||
if (files[name]) throw new Error('File already exists.')
|
||||
|
||||
const nameBuf = encoder.encode(name) // 保持UTF-8编码
|
||||
const commentBuf = encoder.encode(fileLike.comment || '')
|
||||
const { time, date } = dosDateTime(typeof fileLike.lastModified === 'undefined' ? Date.now() : fileLike.lastModified)
|
||||
|
||||
const zipObject = (files[name] = {
|
||||
fileLike,
|
||||
directory: !!fileLike.directory,
|
||||
nameBuf,
|
||||
comment: commentBuf,
|
||||
time,
|
||||
date,
|
||||
|
||||
// tracked
|
||||
offset: 0,
|
||||
crc: null,
|
||||
compressedLength: 0,
|
||||
uncompressedLength: 0,
|
||||
headerWritten: false,
|
||||
footerWritten: false,
|
||||
reader: null,
|
||||
|
||||
// whether sizes/offset require ZIP64
|
||||
needsZip64() {
|
||||
return (
|
||||
this.uncompressedLength > ZIP64_MAGIC ||
|
||||
this.compressedLength > ZIP64_MAGIC ||
|
||||
this.offset > ZIP64_MAGIC
|
||||
)
|
||||
},
|
||||
|
||||
writeLocalHeader() {
|
||||
this.offset = offset
|
||||
|
||||
// 关键修改:设置通用位标记,第11位(0x0800)表示文件名使用UTF-8编码
|
||||
// 保留原0x0008(数据描述符存在),新增0x0800(UTF-8编码)
|
||||
const generalPurposeBitFlag = 0x0808
|
||||
const compressionMethod = 0 // store
|
||||
const versionNeeded = this.needsZip64() ? 45 : 20 // 适配ZIP64
|
||||
|
||||
// We always use data descriptor; write zeros for crc/sizes in local header
|
||||
const local = getDataHelper(30 + this.nameBuf.length)
|
||||
u32(local.view, 0, ZIP_SIGNATURE_LOCAL)
|
||||
u16(local.view, 4, versionNeeded)
|
||||
u16(local.view, 6, generalPurposeBitFlag) // 应用UTF-8标记
|
||||
u16(local.view, 8, compressionMethod)
|
||||
u16(local.view, 10, this.time)
|
||||
u16(local.view, 12, this.date)
|
||||
u32(local.view, 14, 0)
|
||||
u32(local.view, 18, 0)
|
||||
u32(local.view, 22, 0)
|
||||
u16(local.view, 26, this.nameBuf.length)
|
||||
u16(local.view, 28, 0) // extra length
|
||||
local.array.set(this.nameBuf, 30)
|
||||
|
||||
ctrl.enqueue(local.array)
|
||||
offset += local.array.length
|
||||
},
|
||||
|
||||
writeDataDescriptor() {
|
||||
// data descriptor: optional signature + crc32 + sizes (32-bit or 64-bit)
|
||||
const crc = this.crc ? this.crc.get() >>> 0 : 0
|
||||
const useZip64 = this.needsZip64()
|
||||
|
||||
if (!useZip64) {
|
||||
const dd = getDataHelper(16)
|
||||
u32(dd.view, 0, 0x08074b50)
|
||||
u32(dd.view, 4, crc)
|
||||
u32(dd.view, 8, this.compressedLength)
|
||||
u32(dd.view, 12, this.uncompressedLength)
|
||||
ctrl.enqueue(dd.array)
|
||||
offset += dd.array.length
|
||||
} else {
|
||||
// 24 bytes: sig + crc32 + compSize(8) + uncompSize(8)
|
||||
const dd = getDataHelper(24)
|
||||
u32(dd.view, 0, 0x08074b50)
|
||||
u32(dd.view, 4, crc)
|
||||
// BigInt writes
|
||||
dd.view.setBigUint64(8, BigInt(this.compressedLength), true)
|
||||
dd.view.setBigUint64(16, BigInt(this.uncompressedLength), true)
|
||||
ctrl.enqueue(dd.array)
|
||||
offset += dd.array.length
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
filenames.push(name)
|
||||
|
||||
if (!activeZipObject) {
|
||||
activeZipObject = zipObject
|
||||
processNextChunk()
|
||||
}
|
||||
},
|
||||
|
||||
close() {
|
||||
if (closed) throw new TypeError('Cannot close twice')
|
||||
closed = true
|
||||
if (!activeZipObject) closeZip()
|
||||
}
|
||||
}
|
||||
|
||||
function closeZip() {
|
||||
// Build central directory in memory then enqueue once.
|
||||
const cdChunks = []
|
||||
let cdSize = 0
|
||||
|
||||
for (const name of filenames) {
|
||||
const file = files[name]
|
||||
const useZip64 = file.needsZip64()
|
||||
|
||||
const versionMadeBy = useZip64 ? 45 : 20
|
||||
const versionNeeded = useZip64 ? 45 : 20
|
||||
// 关键修改:中央目录也需要设置UTF-8标记
|
||||
const generalPurposeBitFlag = 0x0808
|
||||
const compressionMethod = 0
|
||||
|
||||
const crc = file.crc ? file.crc.get() >>> 0 : 0
|
||||
const compressed32 = useZip64 ? ZIP64_MAGIC : file.compressedLength
|
||||
const uncompressed32 = useZip64 ? ZIP64_MAGIC : file.uncompressedLength
|
||||
const offset32 = useZip64 ? ZIP64_MAGIC : file.offset
|
||||
|
||||
// ZIP64 extra field if needed
|
||||
let extra = new Uint8Array(0)
|
||||
if (useZip64) {
|
||||
// headerId(2)=0x0001, dataSize(2)=24, uncompressed(8), compressed(8), offset(8)
|
||||
extra = new Uint8Array(4 + 24)
|
||||
const ev = new DataView(extra.buffer)
|
||||
u16(ev, 0, 0x0001)
|
||||
u16(ev, 2, 24)
|
||||
ev.setBigUint64(4, BigInt(file.uncompressedLength), true)
|
||||
ev.setBigUint64(12, BigInt(file.compressedLength), true)
|
||||
ev.setBigUint64(20, BigInt(file.offset), true)
|
||||
}
|
||||
|
||||
const headerLen = 46 + file.nameBuf.length + extra.length + file.comment.length
|
||||
const cd = getDataHelper(headerLen)
|
||||
|
||||
u32(cd.view, 0, ZIP_SIGNATURE_CENTRAL)
|
||||
u16(cd.view, 4, versionMadeBy)
|
||||
u16(cd.view, 6, versionNeeded)
|
||||
u16(cd.view, 8, generalPurposeBitFlag) // 中央目录应用UTF-8标记
|
||||
u16(cd.view, 10, compressionMethod)
|
||||
u16(cd.view, 12, file.time)
|
||||
u16(cd.view, 14, file.date)
|
||||
u32(cd.view, 16, crc)
|
||||
u32(cd.view, 20, compressed32)
|
||||
u32(cd.view, 24, uncompressed32)
|
||||
u16(cd.view, 28, file.nameBuf.length)
|
||||
u16(cd.view, 30, extra.length)
|
||||
u16(cd.view, 32, file.comment.length)
|
||||
u16(cd.view, 34, 0) // disk number start
|
||||
u16(cd.view, 36, 0) // internal attrs
|
||||
|
||||
// external file attrs: mark directory
|
||||
u32(cd.view, 38, file.directory ? 0x10 : 0)
|
||||
|
||||
u32(cd.view, 42, offset32)
|
||||
|
||||
cd.array.set(file.nameBuf, 46)
|
||||
if (extra.length) cd.array.set(extra, 46 + file.nameBuf.length)
|
||||
if (file.comment.length) cd.array.set(file.comment, 46 + file.nameBuf.length + extra.length)
|
||||
|
||||
cdChunks.push(cd.array)
|
||||
cdSize += cd.array.length
|
||||
}
|
||||
|
||||
const centralDirectoryOffset = offset
|
||||
const centralDirectory = concatUint8(cdChunks, cdSize)
|
||||
ctrl.enqueue(centralDirectory)
|
||||
offset += centralDirectory.length
|
||||
|
||||
const entries = filenames.length
|
||||
|
||||
const needsZip64ForArchive =
|
||||
entries > 0xFFFF ||
|
||||
centralDirectoryOffset > ZIP64_MAGIC ||
|
||||
cdSize > ZIP64_MAGIC ||
|
||||
offset > ZIP64_MAGIC
|
||||
|
||||
const tailChunks = []
|
||||
let tailSize = 0
|
||||
|
||||
if (needsZip64ForArchive) {
|
||||
// ZIP64 EOCD
|
||||
const zip64eocd = getDataHelper(56)
|
||||
u32(zip64eocd.view, 0, ZIP_SIGNATURE_ZIP64_EOCD)
|
||||
zip64eocd.view.setBigUint64(4, BigInt(44), true) // remaining size
|
||||
u16(zip64eocd.view, 12, 45)
|
||||
u16(zip64eocd.view, 14, 45)
|
||||
u32(zip64eocd.view, 16, 0)
|
||||
u32(zip64eocd.view, 20, 0)
|
||||
zip64eocd.view.setBigUint64(24, BigInt(entries), true)
|
||||
zip64eocd.view.setBigUint64(32, BigInt(entries), true)
|
||||
zip64eocd.view.setBigUint64(40, BigInt(cdSize), true)
|
||||
zip64eocd.view.setBigUint64(48, BigInt(centralDirectoryOffset), true)
|
||||
|
||||
// ZIP64 locator
|
||||
const locator = getDataHelper(20)
|
||||
u32(locator.view, 0, ZIP_SIGNATURE_ZIP64_LOCATOR)
|
||||
u32(locator.view, 4, 0)
|
||||
locator.view.setBigUint64(8, BigInt(centralDirectoryOffset + cdSize), true) // offset of zip64eocd
|
||||
u32(locator.view, 16, 1)
|
||||
|
||||
tailChunks.push(zip64eocd.array, locator.array)
|
||||
tailSize += zip64eocd.array.length + locator.array.length
|
||||
}
|
||||
|
||||
// EOCD
|
||||
const eocd = getDataHelper(22)
|
||||
u32(eocd.view, 0, ZIP_SIGNATURE_EOCD)
|
||||
u16(eocd.view, 4, 0)
|
||||
u16(eocd.view, 6, 0)
|
||||
u16(eocd.view, 8, Math.min(entries, 0xFFFF))
|
||||
u16(eocd.view, 10, Math.min(entries, 0xFFFF))
|
||||
u32(eocd.view, 12, needsZip64ForArchive ? ZIP64_MAGIC : cdSize)
|
||||
u32(eocd.view, 16, needsZip64ForArchive ? ZIP64_MAGIC : centralDirectoryOffset)
|
||||
u16(eocd.view, 20, 0) // comment length
|
||||
|
||||
tailChunks.push(eocd.array)
|
||||
tailSize += eocd.array.length
|
||||
|
||||
ctrl.enqueue(concatUint8(tailChunks, tailSize))
|
||||
ctrl.close()
|
||||
}
|
||||
|
||||
return new ReadableStream({
|
||||
start: c => {
|
||||
ctrl = c
|
||||
underlyingSource.start && Promise.resolve(underlyingSource.start(zipWriter))
|
||||
},
|
||||
pull() {
|
||||
return processNextChunk() || (
|
||||
underlyingSource.pull &&
|
||||
Promise.resolve(underlyingSource.pull(zipWriter))
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.ZIP = createWriter
|
||||
@@ -23,7 +23,11 @@ export default {
|
||||
|
||||
})
|
||||
.then(() => {
|
||||
resetPassword(this.userId).then(res => {
|
||||
let data = {
|
||||
BaseUrl: `${location.protocol}//${location.host}/login`,
|
||||
IdentityUserId: this.userId
|
||||
}
|
||||
resetPassword(data).then(res => {
|
||||
if (res.IsSuccess) {
|
||||
this.$message({
|
||||
message: 'Reset password successfully',
|
||||
|
||||
@@ -112,7 +112,7 @@ export default {
|
||||
this.currentTime = moment().format('YYYY-MM-DD HH:mm:ss')
|
||||
},
|
||||
handleTitleClick() {
|
||||
if (!screenfull.enabled) {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'Your browser can not work',
|
||||
type: 'warning'
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div ref="mapbox" class="map-wrapper" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import 'modules/echarts/map/js/world.js'
|
||||
import * as echarts from 'echarts'
|
||||
// import 'modules/echarts/map/js/world.js'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
export default {
|
||||
props: {
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
watch: {
|
||||
area() {
|
||||
const that = this
|
||||
this.$nextTick(function() {
|
||||
this.$nextTick(function () {
|
||||
that.myChart.resize()
|
||||
})
|
||||
}
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
}
|
||||
]
|
||||
]
|
||||
var convertData = function(data) {
|
||||
var convertData = function (data) {
|
||||
var res = []
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var dataItem = data[i]
|
||||
@@ -77,67 +77,67 @@ export default {
|
||||
return res
|
||||
}
|
||||
var series = []
|
||||
;[['Shanghai', BJData]].forEach(function(item, i) {
|
||||
series.push(
|
||||
{
|
||||
type: 'lines',
|
||||
zlevel: 1,
|
||||
effect: {
|
||||
show: true,
|
||||
color: '#fff',
|
||||
period: 6,
|
||||
trailLength: 0.7,
|
||||
symbolSize: fontSize(0.05)
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: fontSize(0.03),
|
||||
color: '#9ae5fc',
|
||||
opacity: 0.02,
|
||||
curveness: -0.2
|
||||
}
|
||||
},
|
||||
|
||||
data: convertData(item[1])
|
||||
},
|
||||
|
||||
{
|
||||
type: 'effectScatter',
|
||||
coordinateSystem: 'geo',
|
||||
zlevel: 3,
|
||||
rippleEffect: {
|
||||
// 涟漪特效
|
||||
period: 5, // 动画时间,值越小速度越快
|
||||
brushType: 'fill', // 波纹绘制方式 stroke, fill
|
||||
scale: 5 // 波纹圆环最大限制,值越大波纹越大
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
;[['Shanghai', BJData]].forEach(function (item, i) {
|
||||
series.push(
|
||||
{
|
||||
type: 'lines',
|
||||
zlevel: 1,
|
||||
effect: {
|
||||
show: true,
|
||||
color: '#fce630',
|
||||
position: 'right', // 显示位置
|
||||
offset: [10, 0], // 偏移设置
|
||||
fontSize: fontSize(0.16),
|
||||
formatter: '{b}' // 圆环显示文字
|
||||
color: '#fff',
|
||||
period: 6,
|
||||
trailLength: 0.7,
|
||||
symbolSize: fontSize(0.05)
|
||||
},
|
||||
emphasis: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: function(val) {
|
||||
return fontSize(0.08) // 圆环大小
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: fontSize(0.03),
|
||||
color: '#9ae5fc',
|
||||
opacity: 0.02,
|
||||
curveness: -0.2
|
||||
}
|
||||
},
|
||||
|
||||
data: convertData(item[1])
|
||||
},
|
||||
|
||||
data: item[1].map(function(dataItem) {
|
||||
return {
|
||||
name: dataItem[0].name,
|
||||
value: geoCoordMap[dataItem[0].name]
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
{
|
||||
type: 'effectScatter',
|
||||
coordinateSystem: 'geo',
|
||||
zlevel: 3,
|
||||
rippleEffect: {
|
||||
// 涟漪特效
|
||||
period: 5, // 动画时间,值越小速度越快
|
||||
brushType: 'fill', // 波纹绘制方式 stroke, fill
|
||||
scale: 5 // 波纹圆环最大限制,值越大波纹越大
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
color: '#fce630',
|
||||
position: 'right', // 显示位置
|
||||
offset: [10, 0], // 偏移设置
|
||||
fontSize: fontSize(0.16),
|
||||
formatter: '{b}' // 圆环显示文字
|
||||
},
|
||||
emphasis: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: function (val) {
|
||||
return fontSize(0.08) // 圆环大小
|
||||
},
|
||||
|
||||
data: item[1].map(function (dataItem) {
|
||||
return {
|
||||
name: dataItem[0].name,
|
||||
value: geoCoordMap[dataItem[0].name]
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
var option = {
|
||||
// backgroundColor: '#fff',
|
||||
title: {
|
||||
@@ -161,7 +161,7 @@ export default {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
fontSize: fontSize(0.16),
|
||||
formatter: function(params) {
|
||||
formatter: function (params) {
|
||||
if (typeof params.value === 'undefined') {
|
||||
return ''
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div ref="trials_stats" style="width:100%;height:100%;" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import * as echarts from 'echarts'
|
||||
import { getTrialCountRank } from '@/api/dashboard'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
const Count = 5
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div ref="enroll_stats" style="width:100%;height:100%;" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import * as echarts from 'echarts'
|
||||
import { getEnrollDataByQuarter } from '@/api/dashboard'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
const Count = 6
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div ref="reviewers_stats" style="width:100%;height:100%;padding:5px;" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import * as echarts from 'echarts'
|
||||
import { getReviewersByRank } from '@/api/dashboard'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
export default {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div ref="monthly_reading_stats" style="width:100%;height:100%;" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import * as echarts from 'echarts'
|
||||
import { getReadingDataByMonth } from '@/api/dashboard'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
const Count = 6
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div ref="reading_rank" class="reading-rank" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import * as echarts from 'echarts'
|
||||
import { getReadingDataRank } from '@/api/dashboard'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
const Count = 5
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div ref="reading_stats" style="width:100%;height:100%;padding-top:5px;" />
|
||||
</template>
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import * as echarts from 'echarts'
|
||||
import { getReadingDataByType } from '@/api/dashboard'
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
export default {
|
||||
|
||||
@@ -29,8 +29,12 @@
|
||||
:src="item.previewImageUrl"
|
||||
fit="fill"
|
||||
/> -->
|
||||
<img class="image-preview" :src="item.previewImageUrl" crossorigin="anonymous" alt=""
|
||||
style="width: 72px;height:72px;" fit="fill">
|
||||
<div class="imageBox" style="width: 72px;height:72px;">
|
||||
<img class="image-preview" :src="item.previewImageUrl" crossorigin="anonymous" alt=""
|
||||
style="width: 72px;height:72px;" fit="fill" />
|
||||
<i class="el-icon-refresh" :title="$t('tip:refreshImage')"
|
||||
@click.stop="refreshImage(item)"></i>
|
||||
</div>
|
||||
<div class="viewernavitextwrapper">
|
||||
<div style="padding: 1px 5px 1px 1px;display: flex;justify-content: space-between;">
|
||||
<div v-if="item.keySeries" style="color:red">
|
||||
@@ -83,33 +87,36 @@
|
||||
{{ item.description }}
|
||||
</div>
|
||||
<div v-if="!item.keySeries" style="padding: 1px;">
|
||||
{{ item.imageloadedArr.length }}/{{ item.instanceCount }}
|
||||
{{ item.imageloadedArr.length <= item.instanceCount ? item.imageloadedArr.length :
|
||||
item.instanceCount }}/{{ item.instanceCount }} </div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showDelete" style="display: flex;flex-direction: row;justify-content: space-between;"
|
||||
@click.stop="">
|
||||
<div v-if="showDelete" style="display: flex;flex-direction: row;justify-content: space-between;"
|
||||
@click.stop="">
|
||||
|
||||
<div>
|
||||
<span style="font-size: 12px;margin-right: 5px">{{ $t('trials:audit:table:isReading')
|
||||
}}</span>
|
||||
<el-switch v-model="item.isReading" size="mini" @change="changeReadingStatus($event, item)" />
|
||||
<div>
|
||||
<span style="font-size: 12px;margin-right: 5px">{{ $t('trials:audit:table:isReading')
|
||||
}}</span>
|
||||
<el-switch v-model="item.isReading" size="mini"
|
||||
@change="changeReadingStatus($event, item)" />
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size: 12px;margin-right: 5px">{{ $t('trials:audit:table:isDelete')
|
||||
}}</span>
|
||||
<el-switch v-model="item.isDeleted" size="mini"
|
||||
@change="changeDeleteStatus($event, item)" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size: 12px;margin-right: 5px">{{ $t('trials:audit:table:isDelete') }}</span>
|
||||
<el-switch v-model="item.isDeleted" size="mini" @change="changeDeleteStatus($event, item)" />
|
||||
<div
|
||||
v-if="item.prefetchInstanceCount > 0 && item.prefetchInstanceCount < item.instanceCount * 100">
|
||||
<el-progress
|
||||
:percentage="parseInt((item.prefetchInstanceCount / item.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="item.prefetchInstanceCount > 0 && item.prefetchInstanceCount < item.instanceCount * 100">
|
||||
<el-progress
|
||||
:percentage="parseInt((item.prefetchInstanceCount / item.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@@ -133,7 +140,7 @@ import * as cornerstone from 'cornerstone-core'
|
||||
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
|
||||
import dicomViewer from '@/components/Dicom/DicomViewer'
|
||||
import { getStudyInfo, getSeriesList } from '@/api/reading'
|
||||
import { getInstanceList, getPatientSeriesList, setSeriesStatus, setInstanceStatus } from '@/api/trials'
|
||||
import { getInstanceList, getPatientSeriesList, setSeriesStatus, setInstanceStatus, updateImageResizePath } from '@/api/trials'
|
||||
|
||||
import requestPoolManager from '@/utils/request-pool'
|
||||
import store from '@/store'
|
||||
@@ -244,6 +251,62 @@ export default {
|
||||
workSpeedclose(true)
|
||||
},
|
||||
methods: {
|
||||
async updateImageResizePath(data) {
|
||||
try {
|
||||
let res = await updateImageResizePath(data)
|
||||
if (res.IsSuccess) {
|
||||
this.$message.success(this.$t("message:tip:updateImageResizePath:success"))
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
async refreshImage(item) {
|
||||
let thumbnailPath = item.previewImageUrl.split(this.OSSclientConfig.basePath)[1]
|
||||
let blob = await this.dicomToPng(item.imageIds[0])
|
||||
let OSSclient = this.OSSclient
|
||||
try {
|
||||
let seriesRes = await OSSclient.put(thumbnailPath, blob)
|
||||
if (seriesRes && seriesRes.url) {
|
||||
let path = this.$getObjectName(seriesRes.url)
|
||||
item.previewImageUrl = seriesRes.url
|
||||
let data = {
|
||||
seriesId: item.seriesId,
|
||||
ImageResizePath: path
|
||||
}
|
||||
this.updateImageResizePath(data)
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
},
|
||||
dicomToPng(imageId) {
|
||||
return new Promise((resolve) => {
|
||||
cornerstone.loadImage(imageId).then(async (image) => {
|
||||
let width = image.columns, height = image.rows;
|
||||
let canvas = document.createElement('canvas')
|
||||
canvas.width = (width * 60) / height
|
||||
canvas.height = 60
|
||||
if (image) {
|
||||
cornerstone.renderToCanvas(canvas, image)
|
||||
// 将 Canvas 图像对象转换为 PNG 格式
|
||||
let blob = await this.canvasToBlob(canvas)
|
||||
resolve(blob)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
}).catch((reason) => {
|
||||
reason()
|
||||
})
|
||||
},
|
||||
canvasToBlob(canvas) {
|
||||
return new Promise((resolve) => {
|
||||
canvas.toBlob((blob) => {
|
||||
resolve(blob)
|
||||
})
|
||||
})
|
||||
},
|
||||
async loadStudy() {
|
||||
let params = {}
|
||||
if (this.isPacs) {
|
||||
@@ -891,6 +954,7 @@ export default {
|
||||
// 设置当前序列状态为已下载完成
|
||||
this.seriesList[seriesIndex].loadStatus = true
|
||||
workSpeedclose()
|
||||
localStorage.setItem("QCRiskControl", 1)
|
||||
if (!this.isFromCRCUpload) {
|
||||
this.loadAllImages()
|
||||
}
|
||||
@@ -901,7 +965,18 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.viewerContainer .imageBox {
|
||||
position: relative;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.viewerContainer .el-tabs--border-card {
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
@@ -45,8 +45,12 @@
|
||||
style="position: relative;margin-bottom:5px;border-radius: 2px;border: 1px solid #404040;"
|
||||
series-type="current" @click="showSeriesImage($event, index, i, series)">
|
||||
<div class="viewernavigatorwrapper">
|
||||
<img class="image-preview" :src="series.previewImageUrl" crossorigin="anonymous" alt=""
|
||||
style="width: 85px;height:85px;" fit="fill">
|
||||
<div class="imageBox" style="width: 72px;height:72px;">
|
||||
<img class="image-preview" :src="series.previewImageUrl" crossorigin="anonymous" alt=""
|
||||
style="width: 72px;height:72px;" fit="fill" />
|
||||
<i class="el-icon-refresh" :title="$t('tip:refreshImage')"
|
||||
@click.stop="refreshImage(series)"></i>
|
||||
</div>
|
||||
<div class="viewernavitextwrapper">
|
||||
<div style="padding: 1px 5px 1px 1px;display: flex;justify-content: space-between;">
|
||||
<div>#{{ series.seriesNumber }}</div>
|
||||
@@ -113,35 +117,35 @@
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div style="padding: 1px;">
|
||||
{{ series.imageloadedArr.length }}/{{ series.instanceCount }}
|
||||
{{ series.imageloadedArr.length <= series.instanceCount ? series.imageloadedArr.length :
|
||||
series.instanceCount }}/{{ series.instanceCount }} </div>
|
||||
<div />
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showDelete"
|
||||
style="display: flex;flex-direction: row;justify-content: space-between;" @click.stop="">
|
||||
<div v-if="showDelete"
|
||||
style="display: flex;flex-direction: row;justify-content: space-between;" @click.stop="">
|
||||
|
||||
<div>
|
||||
<span style="font-size: 12px;">{{ $t('trials:audit:table:isReading') }}</span>
|
||||
<el-switch v-model="series.isReading" size="mini"
|
||||
@change="changeReadingStatus($event, series)" />
|
||||
<div>
|
||||
<span style="font-size: 12px;">{{ $t('trials:audit:table:isReading') }}</span>
|
||||
<el-switch v-model="series.isReading" size="mini"
|
||||
@change="changeReadingStatus($event, series)" />
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size: 12px;">{{ $t('trials:audit:table:isDelete') }}</span>
|
||||
<el-switch v-model="series.isDeleted" size="mini"
|
||||
@change="changeDeleteStatus($event, series)" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size: 12px;">{{ $t('trials:audit:table:isDelete') }}</span>
|
||||
<el-switch v-model="series.isDeleted" size="mini"
|
||||
@change="changeDeleteStatus($event, series)" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div style="position: absolute;bottom: -10px;left: 0;width: 100%;">
|
||||
<!-- <div style="position: absolute;bottom: -10px;left: 0;width: 100%;">
|
||||
<el-progress v-if="series.prefetchInstanceCount>0 && series.prefetchInstanceCount<series.instanceCount" :percentage="Number(series.prefetchInstanceCount/series.instanceCount)*100" />
|
||||
</div> -->
|
||||
<div
|
||||
v-if="series.prefetchInstanceCount > 0 && series.prefetchInstanceCount < series.instanceCount * 100">
|
||||
<el-progress
|
||||
:percentage="parseInt((series.prefetchInstanceCount / series.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
<div
|
||||
v-if="series.prefetchInstanceCount > 0 && series.prefetchInstanceCount < series.instanceCount * 100">
|
||||
<el-progress
|
||||
:percentage="parseInt((series.prefetchInstanceCount / series.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
||||
</el-collapse>
|
||||
@@ -154,104 +158,105 @@
|
||||
<div class="viewerSidethumbinner">
|
||||
|
||||
<el-collapse v-model="relationActiveName" @change="handelRelationActiveChange">
|
||||
<template v-for="item in relationStudyListByVisitName">
|
||||
<div :key="`${item.VisitName}`">
|
||||
<div v-show="item.VisitName" class="text-desc" style="background-color: #1f1f1f;">
|
||||
{{ item.VisitName }}
|
||||
</div>
|
||||
<template v-for="(study, studyIndex) in relationStudyList">
|
||||
<el-collapse-item :key="`${study.StudyId}`" :name="`${study.StudyId}`"
|
||||
v-if="study.VisitName === item.VisitName">
|
||||
<template slot="title">
|
||||
<div v-for="item in relationStudyListByVisitName" :key="`${item.VisitName}`">
|
||||
<div v-show="item.VisitName" class="text-desc" style="background-color: #1f1f1f;">
|
||||
{{ item.VisitName }}
|
||||
</div>
|
||||
<template v-for="(study, studyIndex) in relationStudyList">
|
||||
<el-collapse-item :key="`${study.StudyId}`" :name="`${study.StudyId}`"
|
||||
v-if="study.VisitName === item.VisitName">
|
||||
<template slot="title">
|
||||
|
||||
<div class="text-desc">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
{{ study.Description }}
|
||||
</div> -->
|
||||
|
||||
<div v-show="study.SeriesCount" class="text-desc">
|
||||
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
||||
</div>
|
||||
</template>
|
||||
<div v-show="study.Description" class="text-desc" style="background-color: #1f1f1f;">
|
||||
{{ study.Description }}
|
||||
<div class="text-desc">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<div class="viewerSidethumbs ps" style="position: relative;">
|
||||
<div class="viewerSidethumbinner">
|
||||
<div v-for="(seriesItem, index) in study.seriesList" :key="seriesItem.seriesId">
|
||||
<div class="viewernavigatorwrapper"
|
||||
style="position: relative;border:1px solid #434343;" series-type="relation"
|
||||
@click="showRelationSeriesImage($event, seriesItem, studyIndex, index)">
|
||||
<img class="image-preview" :src="seriesItem.previewImageUrl" crossorigin="anonymous"
|
||||
alt="" style="width: 85px;height:85px;" fit="fill">
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
{{ study.Description }}
|
||||
</div> -->
|
||||
|
||||
<div class="viewernavitextwrapper">
|
||||
<div
|
||||
style="padding: 1px 5px 1px 1px;display: flex;justify-content: space-between;">
|
||||
<div v-if="seriesItem.keySeries" style="color:red">
|
||||
Key Images
|
||||
</div>
|
||||
<div v-else>#{{ seriesItem.seriesNumber }}</div>
|
||||
<div v-if="seriesItem.isExistMutiFrames && seriesItem.instanceCount > 1">
|
||||
<el-popover placement="right-start" trigger="click"
|
||||
popper-class="instance_frame_wrapper">
|
||||
<div class="frame_list">
|
||||
<div v-for="(instance, idx) in seriesItem.instanceInfoList"
|
||||
:key="instance.Id" class="frame_content"
|
||||
:style="{ 'margin-bottom': idx < seriesItem.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||
@click="showMultiFrames(studyIndex, seriesItem, index, instance)">
|
||||
<div>
|
||||
<div>{{ instance.InstanceNumber }}</div>
|
||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.NumberOfFrames : 1}
|
||||
frame`
|
||||
}}</div>
|
||||
</div>
|
||||
<div v-show="study.SeriesCount" class="text-desc">
|
||||
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
||||
</div>
|
||||
</template>
|
||||
<div v-show="study.Description" class="text-desc" style="background-color: #1f1f1f;">
|
||||
{{ study.Description }}
|
||||
</div>
|
||||
<div class="viewerSidethumbs ps" style="position: relative;">
|
||||
<div class="viewerSidethumbinner">
|
||||
<div v-for="(seriesItem, index) in study.seriesList" :key="seriesItem.seriesId">
|
||||
<div class="viewernavigatorwrapper"
|
||||
style="position: relative;border:1px solid #434343;" series-type="relation"
|
||||
@click="showRelationSeriesImage($event, seriesItem, studyIndex, index)">
|
||||
<div class="imageBox" style="width: 72px;height:72px;">
|
||||
<img class="image-preview" :src="seriesItem.previewImageUrl"
|
||||
crossorigin="anonymous" alt="" style="width: 72px;height:72px;" fit="fill" />
|
||||
<i class="el-icon-refresh" :title="$t('tip:refreshImage')"
|
||||
@click.stop="refreshImage(item)"></i>
|
||||
</div>
|
||||
|
||||
<div class="viewernavitextwrapper">
|
||||
<div
|
||||
style="padding: 1px 5px 1px 1px;display: flex;justify-content: space-between;">
|
||||
<div v-if="seriesItem.keySeries" style="color:red">
|
||||
Key Images
|
||||
</div>
|
||||
<div v-else>#{{ seriesItem.seriesNumber }}</div>
|
||||
<div v-if="seriesItem.isExistMutiFrames && seriesItem.instanceCount > 1">
|
||||
<el-popover placement="right-start" trigger="click"
|
||||
popper-class="instance_frame_wrapper">
|
||||
<div class="frame_list">
|
||||
<div v-for="(instance, idx) in seriesItem.instanceInfoList"
|
||||
:key="instance.Id" class="frame_content"
|
||||
:style="{ 'margin-bottom': idx < seriesItem.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||
@click="showMultiFrames(studyIndex, seriesItem, index, instance)">
|
||||
<div>
|
||||
<div>{{ instance.InstanceNumber }}</div>
|
||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.NumberOfFrames : 1}
|
||||
frame`
|
||||
}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-connection"
|
||||
style="font-size: 15px;cursor: pointer;" />
|
||||
</el-popover>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-connection"
|
||||
style="font-size: 15px;cursor: pointer;" />
|
||||
</el-popover>
|
||||
</div>
|
||||
<div v-show="seriesItem.instanceCount" style="padding: 1px;">
|
||||
{{ seriesItem.modality }}: {{ seriesItem.instanceCount }} image
|
||||
</div>
|
||||
<div v-show="seriesItem.sliceThickness" style="padding: 1px;">
|
||||
T: {{ seriesItem.sliceThickness }}
|
||||
</div>
|
||||
<el-tooltip v-show="seriesItem.description" class="item" effect="dark"
|
||||
:content="seriesItem.description" placement="bottom">
|
||||
<div v-show="seriesItem.description"
|
||||
style="width: 120px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;padding: 1x;">
|
||||
{{ seriesItem.description }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
</div>
|
||||
<div v-show="seriesItem.instanceCount" style="padding: 1px;">
|
||||
{{ seriesItem.modality }}: {{ seriesItem.instanceCount }} image
|
||||
</div>
|
||||
<div v-show="seriesItem.sliceThickness" style="padding: 1px;">
|
||||
T: {{ seriesItem.sliceThickness }}
|
||||
</div>
|
||||
<el-tooltip v-show="seriesItem.description" class="item" effect="dark"
|
||||
:content="seriesItem.description" placement="bottom">
|
||||
<div v-show="seriesItem.description"
|
||||
style="width: 120px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;padding: 1x;">
|
||||
{{ seriesItem.description }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<!-- <el-image
|
||||
class="image-preview"
|
||||
style="height:72px;width:72px;"
|
||||
:src="seriesItem.previewImageUrl"
|
||||
fit="fill"
|
||||
/> -->
|
||||
<div
|
||||
v-if="seriesItem.prefetchInstanceCount > 0 && seriesItem.prefetchInstanceCount < seriesItem.instanceCount * 100">
|
||||
<el-progress
|
||||
:percentage="parseInt((seriesItem.prefetchInstanceCount / seriesItem.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <el-image
|
||||
class="image-preview"
|
||||
style="height:72px;width:72px;"
|
||||
:src="seriesItem.previewImageUrl"
|
||||
fit="fill"
|
||||
/> -->
|
||||
<div
|
||||
v-if="seriesItem.prefetchInstanceCount > 0 && seriesItem.prefetchInstanceCount < seriesItem.instanceCount * 100">
|
||||
<el-progress
|
||||
:percentage="parseInt((seriesItem.prefetchInstanceCount / seriesItem.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</el-collapse>
|
||||
|
||||
</div>
|
||||
@@ -273,7 +278,7 @@ import * as cornerstone from 'cornerstone-core'
|
||||
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
|
||||
import dicomViewer from '@/components/Dicom/DicomViewer'
|
||||
import { getVisitStudyList, getAllRelationStudyList, getSeriesList } from '@/api/reading'
|
||||
import { setSeriesStatus, setInstanceStatus } from '@/api/trials'
|
||||
import { setSeriesStatus, setInstanceStatus, updateImageResizePath } from '@/api/trials'
|
||||
import { getTaskUploadedDicomStudyList } from '@/api/reading'
|
||||
import requestPoolManager from '@/utils/request-pool'
|
||||
import store from '@/store'
|
||||
@@ -358,6 +363,62 @@ export default {
|
||||
workSpeedclose(true)
|
||||
},
|
||||
methods: {
|
||||
async updateImageResizePath(data) {
|
||||
try {
|
||||
let res = await updateImageResizePath(data)
|
||||
if (res.IsSuccess) {
|
||||
this.$message.success(this.$t("message:tip:updateImageResizePath:success"))
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
async refreshImage(item) {
|
||||
let thumbnailPath = item.previewImageUrl.split(this.OSSclientConfig.basePath)[1]
|
||||
let blob = await this.dicomToPng(item.imageIds[0])
|
||||
let OSSclient = this.OSSclient
|
||||
try {
|
||||
let seriesRes = await OSSclient.put(thumbnailPath, blob)
|
||||
if (seriesRes && seriesRes.url) {
|
||||
let path = this.$getObjectName(seriesRes.url)
|
||||
item.previewImageUrl = seriesRes.url
|
||||
let data = {
|
||||
seriesId: item.seriesId,
|
||||
ImageResizePath: path
|
||||
}
|
||||
this.updateImageResizePath(data)
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
},
|
||||
dicomToPng(imageId) {
|
||||
return new Promise((resolve) => {
|
||||
cornerstone.loadImage(imageId).then(async (image) => {
|
||||
let width = image.columns, height = image.rows;
|
||||
let canvas = document.createElement('canvas')
|
||||
canvas.width = (width * 60) / height
|
||||
canvas.height = 60
|
||||
if (image) {
|
||||
cornerstone.renderToCanvas(canvas, image)
|
||||
// 将 Canvas 图像对象转换为 PNG 格式
|
||||
let blob = await this.canvasToBlob(canvas)
|
||||
resolve(blob)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
}).catch((reason) => {
|
||||
reason()
|
||||
})
|
||||
},
|
||||
canvasToBlob(canvas) {
|
||||
return new Promise((resolve) => {
|
||||
canvas.toBlob((blob) => {
|
||||
resolve(blob)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 获取某个访视下所有的检查信息
|
||||
async getStudiesInfo() {
|
||||
this.studyList = []
|
||||
@@ -940,13 +1001,25 @@ export default {
|
||||
this.loadAllImages()
|
||||
}
|
||||
workSpeedclose()
|
||||
localStorage.setItem("QCRiskControl", 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.viewerContainer .imageBox {
|
||||
position: relative;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.viewerContainer .el-tabs--border-card {
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
@@ -106,6 +106,16 @@ export default {
|
||||
isTrial: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isExternal: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
ExternalList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -122,7 +132,8 @@ export default {
|
||||
rowData: {},
|
||||
list: [],
|
||||
searchData: defaultSearchData(),
|
||||
title: this.$t('dictionary:signature:fileList')
|
||||
title: this.$t('dictionary:signature:fileList'),
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -131,6 +142,16 @@ export default {
|
||||
this.getList()
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
isExternal: {
|
||||
handler() {
|
||||
if (this.isExternal) {
|
||||
this.list = this.ExternalList
|
||||
this.rowData = this.list[0] || {}
|
||||
this.title = this.$t('dictionary:signature:view')
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -145,6 +166,7 @@ export default {
|
||||
},
|
||||
async getList() {
|
||||
try {
|
||||
if (this.isExternal) return
|
||||
if (!this.SystemDocumentId) return false
|
||||
this.loading = true
|
||||
if (!this.isTrial) {
|
||||
|
||||
@@ -1,75 +1,118 @@
|
||||
<template>
|
||||
<div class="app-container my_menu">
|
||||
<el-form :inline="true">
|
||||
<el-form-item label="模块">
|
||||
<el-select v-model="queryParams.ModuleTypeId" placeholder="模块" clearable>
|
||||
<!-- 模块 -->
|
||||
<el-form-item :label="$t('audit:label:moduleType')">
|
||||
<el-select v-model="queryParams.ModuleTypeId" clearable>
|
||||
<el-option v-for="item of dict.type.ModuleType" :key="`ModuleTypeId${item.value}`" :value="item.value"
|
||||
:label="item.raw.ValueCN" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">
|
||||
{{ $t('common:button:search') }}
|
||||
</el-button>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div>
|
||||
<el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
|
||||
<!-- 展开/折叠 -->
|
||||
<el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">
|
||||
{{ $t('audit:button:fold') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table v-if="refreshTable" v-adaptive="{ bottomOffset: 45 }" v-loading="loading" height="100" :data="menuList"
|
||||
:default-expand-all="isExpandAll" row-key="Id" :tree-props="{ children: 'Children', hasChildren: 'hasChildren' }">
|
||||
<el-table-column prop="ModuleTypeValueCN" label="模块" show-overflow-tooltip align="left" min-width="230px" />
|
||||
<el-table-column prop="Description" label="操作名称" :show-overflow-tooltip="true" min-width="200px">
|
||||
<!-- 模块 -->
|
||||
<el-table-column prop="ModuleTypeValueCN" :label="$t('audit:label:moduleType')" show-overflow-tooltip align="left" min-width="230px" />
|
||||
<!-- 操作名称 -->
|
||||
<el-table-column prop="Description" :label="$t('audit:label:desc')" :show-overflow-tooltip="true" min-width="200px">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.DescriptionCN }}({{ scope.row.Description }})</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="DescriptionCN" label="其他" :show-overflow-tooltip="true" min-width="140px">
|
||||
<!-- 其他 -->
|
||||
<el-table-column prop="DescriptionCN" :label="$t('audit:label:descCN')" :show-overflow-tooltip="true" min-width="140px">
|
||||
<template slot-scope="scope">
|
||||
<!-- 被禁用 -->
|
||||
<!-- 禁 -->
|
||||
<span v-if="!scope.row.IsEnable"
|
||||
style="cursor:pointer;line-height:20px;text-align:center;font-size: 12px;display: inline-block;width: 20px;height: 20px;border-radius: 50%;background: #DC143C;color: #fff;"
|
||||
title="被禁用">禁</span>
|
||||
:title="$t('audit:label:disable')">{{ $t('audit:label:disable1') }}</span>
|
||||
<!-- 需要电签 签 -->
|
||||
<span v-if="scope.row.IsHaveSign"
|
||||
style="cursor:pointer;line-height:20px;text-align:center;font-size: 12px;display: inline-block;width: 20px;height: 20px;border-radius: 50%;background: #428bca;color: #fff;"
|
||||
title="需要电签">签</span>
|
||||
:title="$t('audit:label:needSign')">{{ $t('audit:label:needSign1') }}</span>
|
||||
<!-- 需要原因 因 -->
|
||||
<span v-if="scope.row.IsHaveReason"
|
||||
style="cursor:pointer;line-height:20px;text-align:center;font-size: 12px;display: inline-block;width: 20px;height: 20px;border-radius: 50%;background: #fab6b6;color: #fff;"
|
||||
title="需要原因">因</span>
|
||||
:title="$t('audit:label:needReason')">{{ $t('audit:label:needReason1') }}</span>
|
||||
<!-- 已经记录 记 -->
|
||||
<span v-if="scope.row.IsFinish"
|
||||
style="cursor:pointer;line-height:20px;text-align:center;font-size: 12px;display: inline-block;width: 20px;height: 20px;border-radius: 50%;background:#3CB371;color: #fff;"
|
||||
title="已经记录">记</span>
|
||||
:title="$t('audit:label:isFinish')">{{ $t('audit:label:isFinish1') }}</span>
|
||||
<!-- 核对完 核 -->
|
||||
<span v-if="scope.row.IsJoinPlan"
|
||||
style="cursor:pointer;line-height:20px;text-align:center;font-size: 12px;display: inline-block;width: 20px;height: 20px;border-radius: 50%;background: #FFA500;color: #fff;"
|
||||
title="核对完">核</span>
|
||||
:title="$t('audit:label:isJoinPlan')">{{ $t('audit:label:isJoinPlan1') }}</span>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Identification" label="标识" :show-overflow-tooltip="true" min-width="200px" />
|
||||
<el-table-column prop="OptTypeValueCN" label="操作类型" show-overflow-tooltip width="100px" />
|
||||
<el-table-column prop="ObjectTypeValueCN" label="对象类型" show-overflow-tooltip min-width="100px" />
|
||||
<el-table-column prop="ChildrenTypeValueCN" label="数据类型" show-overflow-tooltip min-width="100px" />
|
||||
<el-table-column prop="Sort" label="显示顺序" min-width="80" show-overflow-tooltip />
|
||||
<el-table-column label="启用" align="center" prop="CreateTime" min-width="80">
|
||||
<!-- 标识 -->
|
||||
<el-table-column prop="Identification" :label="$t('audit:label:identification')" :show-overflow-tooltip="true" min-width="200px" />
|
||||
<!-- 操作类型 -->
|
||||
<el-table-column prop="OptTypeValueCN" :label="$t('audit:label:optType')" show-overflow-tooltip width="100px" />
|
||||
<!-- 对象类型 -->
|
||||
<el-table-column prop="ObjectTypeValueCN" :label="$t('audit:label:objectType')" show-overflow-tooltip min-width="100px" />
|
||||
<!-- 数据类型 -->
|
||||
<el-table-column prop="ChildrenTypeValueCN" :label="$t('audit:label:dataType')" show-overflow-tooltip min-width="100px" />
|
||||
<!-- 显示顺序 -->
|
||||
<el-table-column prop="Sort" :label="$t('audit:label:sort')" min-width="80" show-overflow-tooltip />
|
||||
<!-- 启用 -->
|
||||
<el-table-column :label="$t('audit:label:isEnable')" align="center" prop="CreateTime" min-width="80">
|
||||
<!-- 启用/禁用 -->
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.IsEnable" size="success">启用</el-tag>
|
||||
<el-tag v-else size="danger">禁用</el-tag>
|
||||
<!-- <el-tag v-if="scope.row.IsEnable" size="success">启用</el-tag>
|
||||
<el-tag v-else size="danger">禁用</el-tag> -->
|
||||
<el-tag :type="!scope.row.IsEnable ? 'info' : ''">
|
||||
{{ $fd('IsEnable', scope.row.IsEnable) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" min-width="340" class-name="small-padding fixed-width">
|
||||
<el-table-column :label="$t('common:action:action')" align="center" fixed="right" min-width="340" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<!-- 上移 -->
|
||||
<el-button
|
||||
v-if="scope.row.ModuleTypeValueCN && scope.row.ObjectTypeValueCN && scope.row.OptTypeValueCN && scope.row.ChildrenTypeValueCN"
|
||||
type="text" @click="handleUpMove(scope.row)">上移</el-button>
|
||||
<el-button type="text" @click="handleUpdate(scope.row)">修改</el-button>
|
||||
type="text" @click="handleUpMove(scope.row)"
|
||||
>
|
||||
{{ $t('audit:button:upward') }}
|
||||
</el-button>
|
||||
<!-- 修改 -->
|
||||
<el-button type="text" @click="handleUpdate(scope.row)">
|
||||
{{ $t('audit:button:modify') }}
|
||||
</el-button>
|
||||
<!-- 新增 -->
|
||||
<el-button
|
||||
v-if="!(scope.row.ModuleTypeValueCN && scope.row.ObjectTypeValueCN && scope.row.OptTypeValueCN && scope.row.ChildrenTypeValueCN)"
|
||||
type="text" @click="handleAdd(scope.row)">新增</el-button>
|
||||
type="text" @click="handleAdd(scope.row)">{{ $t('common:button:new') }}</el-button>
|
||||
<!-- Children -->
|
||||
<el-button
|
||||
v-if="scope.row.ModuleTypeValueCN && scope.row.ObjectTypeValueCN && scope.row.OptTypeValueCN && scope.row.ChildrenTypeValueCN"
|
||||
type="text" @click="handleChildren(scope.row)">Children</el-button>
|
||||
type="text" @click="handleChildren(scope.row)"
|
||||
>
|
||||
{{ $t('audit:button:children') }}
|
||||
</el-button>
|
||||
<!-- 复制到 -->
|
||||
<el-button
|
||||
v-if="scope.row.ModuleTypeValueCN && scope.row.ObjectTypeValueCN && scope.row.OptTypeValueCN && scope.row.ChildrenTypeValueCN"
|
||||
type="text" @click="handleCopy(scope.row)">复制到</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
|
||||
type="text" @click="handleCopy(scope.row)">
|
||||
{{ $t('audit:button:copyTo') }}
|
||||
</el-button>
|
||||
<!-- 删除 -->
|
||||
<el-button type="text" @click="handleDelete(scope.row)">{{ $t('common:button:delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -191,6 +234,17 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item>
|
||||
<span slot="label">
|
||||
适用的标准
|
||||
</span>
|
||||
<el-select v-model="form.ApplyCriterionList" placeholder="" clearable multiple>
|
||||
<el-option v-for="item in $d.CriterionType" :key="item.id" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-show="form.ConfigType === 'C' && title !== '复制'" :span="12">
|
||||
<el-form-item>
|
||||
<span slot="label">
|
||||
@@ -1008,6 +1062,7 @@ export default {
|
||||
ValueCN: null,
|
||||
EnumType: '',
|
||||
IsShowByTrialConfig: false,
|
||||
ApplyCriterionList: [],
|
||||
TrialConfigRelyFieldName: null,
|
||||
Identification: null,
|
||||
IsForwardPosition: false,
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<!-- 搜索框 -->
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form-item label="字典表名称:">
|
||||
<el-form-item :label="$t('dic:all:label:code')">
|
||||
<el-input v-model="searchData.Code" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典分组:">
|
||||
<el-select v-model="searchData.ConfigTypeId" placeholder="字典分组" clearable size="small">
|
||||
<el-form-item :label="$t('dic:all:label:group')">
|
||||
<el-select v-model="searchData.ConfigTypeId" clearable size="small">
|
||||
<el-option v-for="item of basicDicList" :key="item.Id" :value="item.Id" :label="item.Code" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -29,7 +29,9 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span style="margin-left:auto">
|
||||
<el-button type="primary" @click="handleAdd">新建</el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<el-table
|
||||
@@ -44,33 +46,33 @@
|
||||
<el-table-column type="index" width="60" />
|
||||
<el-table-column
|
||||
prop="Code"
|
||||
label="字典表名称"
|
||||
:label="$t('dic:all:label:code')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ConfigType"
|
||||
label="字典分组"
|
||||
:label="$t('dic:all:label:group')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="Description"
|
||||
label="描述"
|
||||
:label="$t('dic:all:label:desc')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ShowOrder"
|
||||
label="显示顺序"
|
||||
:label="$t('dic:all:label:showOrder')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="是否可用" width="100" fixed="right">
|
||||
<el-table-column :label="$t('dic:all:label:isEnable')" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.IsEnable"
|
||||
@@ -80,25 +82,25 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="200" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
{{ $t('common:action:edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleChild(scope.row)"
|
||||
>
|
||||
子项
|
||||
{{ $t('dic:all:label:childItem') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -174,7 +176,7 @@ export default {
|
||||
switchChange(event, item) {
|
||||
this.loading = true
|
||||
addOrUpdateBasicDic(item).then(res => {
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
@@ -182,12 +184,12 @@ export default {
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', row)
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:action:edit'), row)
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', { DataTypeEnum: 3 })
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:button:new'), { DataTypeEnum: 3 })
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
|
||||
@@ -4,32 +4,39 @@
|
||||
<div class="search">
|
||||
<el-form :inline="true" size="mini" class="base-search-form" />
|
||||
<span style="margin-left:auto">
|
||||
<el-button type="primary" size="mini" @click="handleAdd">新建</el-button>
|
||||
<el-button type="primary" size="mini" @click="handleAdd">{{ $t('common:button:new') }}</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" :data="list" stripe size="small" height="100"
|
||||
@sort-change="handleSortByColumn">
|
||||
<el-table-column type="index" width="60" />
|
||||
<el-table-column v-if="!~$route.path.indexOf('select')" prop="Code" label="字典键值" min-width="180"
|
||||
<!-- 字典键值 -->
|
||||
<el-table-column v-if="!~$route.path.indexOf('select')" prop="Code" :label="$t('dic:all:label:keyCode')" min-width="180"
|
||||
show-overflow-tooltip sortable='custom' />
|
||||
<el-table-column prop="ValueCN" label="中文值" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<el-table-column prop="Value" label="英文值" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<el-table-column prop="ChildGroup" label="分组" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<el-table-column prop="ShowOrder" label="显示顺序" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<el-table-column prop="Description" label="描述" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<el-table-column label="是否可用" width="100" fixed="right">
|
||||
<!-- 中文值 -->
|
||||
<el-table-column prop="ValueCN" :label="$t('dic:all:label:valueCN')" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<!-- 英文值 -->
|
||||
<el-table-column prop="Value" :label="$t('dic:all:label:valueEN')" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<!-- 分组 -->
|
||||
<el-table-column prop="ChildGroup" :label="$t('dic:all:label:childGroup')" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<!-- 显示顺序 -->
|
||||
<el-table-column prop="ShowOrder" :label="$t('dic:all:label:showOrder')" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<!-- 描述 -->
|
||||
<el-table-column prop="Description" :label="$t('dic:all:label:desc')" min-width="180" show-overflow-tooltip sortable='custom' />
|
||||
<!-- 是否可用 -->
|
||||
<el-table-column :label="$t('dic:all:label:isEnable')" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-switch v-model="scope.row.IsEnable" :active-value="true" :inactive-value="false"
|
||||
@change="(event) => { return switchChange(event, scope.row) }" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="150" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="handleEdit(scope.row)">
|
||||
编辑
|
||||
{{ $t('common:action:edit') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)">
|
||||
删除
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -101,7 +108,7 @@ export default {
|
||||
switchChange(event, item) {
|
||||
this.loading = true
|
||||
addOrUpdateBasicDic(item).then(res => {
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
@@ -109,12 +116,12 @@ export default {
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryChildAddOrUpdateForm'].openDialog('DictionaryChild Edit', row, { DataTypeEnum: this.parent.DataTypeEnum })
|
||||
this.$refs['DictionaryChildAddOrUpdateForm'].openDialog(this.$t('common:action:edit'), row, { DataTypeEnum: this.parent.DataTypeEnum })
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryChildAddOrUpdateForm'].openDialog('DictionaryChild Add', {}, { ConfigTypeId: this.parent.ConfigTypeId, parentId: this.parent.Id, DataTypeEnum: this.parent.DataTypeEnum })
|
||||
this.$refs['DictionaryChildAddOrUpdateForm'].openDialog(this.$t('common:button:new'), {}, { ConfigTypeId: this.parent.ConfigTypeId, parentId: this.parent.Id, DataTypeEnum: this.parent.DataTypeEnum })
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
|
||||
@@ -8,25 +8,25 @@
|
||||
label-width="120px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item label="Enum Value: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:keyCode')" prop="Code">
|
||||
<el-input v-model="form.Code" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Value: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:valueCN')" prop="Code">
|
||||
<el-input v-model="form.ValueCN" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Value EN: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:valueEN')" prop="Code">
|
||||
<el-input v-model="form.Value" />
|
||||
</el-form-item>
|
||||
<el-form-item label="ChildGroup: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:childGroup')" prop="Code">
|
||||
<el-input v-model="form.ChildGroup" />
|
||||
</el-form-item>
|
||||
<el-form-item label="ShowOrder: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:showOrder')" prop="Code">
|
||||
<el-input-number v-model="form.ShowOrder" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Description: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:desc')" prop="Code">
|
||||
<el-input v-model="form.Description" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Is Enable: ">
|
||||
<el-form-item :label="$t('dic:all:label:isEnable')">
|
||||
<el-switch
|
||||
v-model="form.IsEnable"
|
||||
:active-value="true"
|
||||
@@ -36,8 +36,12 @@
|
||||
</el-form>
|
||||
</template>
|
||||
<template slot="dialog-footer">
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">Cancel</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">Save</el-button>
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">
|
||||
{{ $t('common:button:cancel') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</base-model>
|
||||
</template>
|
||||
@@ -90,7 +94,7 @@ export default {
|
||||
this.btnLoading = true
|
||||
addOrUpdateBasicDic(this.form).then(res => {
|
||||
this.btnLoading = false
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.model_cfg.visible = false
|
||||
this.$emit('getList')
|
||||
}).catch(() => {
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item label="ConfigTypeId: " prop="Code">
|
||||
>
|
||||
<!-- 字典分组 -->
|
||||
<el-form-item :label="$t('dic:all:label:group')" prop="Code">
|
||||
<el-select v-model="form.ConfigTypeId" filterable style="width:100%;">
|
||||
<el-option
|
||||
v-for="(item,index) of basicDicList"
|
||||
@@ -18,7 +19,8 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="TypeEnum: " prop="DataTypeEnum">
|
||||
<!-- 类型 -->
|
||||
<el-form-item :label="$t('dic:all:label:dataType')" prop="DataTypeEnum">
|
||||
<el-select v-model="form.DataTypeEnum" filterable style="width:100%;">
|
||||
<el-option
|
||||
:label="`config`"
|
||||
@@ -38,16 +40,19 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Code: " prop="Code">
|
||||
<!-- 字典表名称 -->
|
||||
<el-form-item :label="$t('dic:all:label:code')" prop="Code">
|
||||
<el-input v-model="form.Code" />
|
||||
</el-form-item>
|
||||
<!--<el-form-item label="KeyName: " prop="Code">-->
|
||||
<!--<el-input v-model="form.KeyName" />-->
|
||||
<!--</el-form-item>-->
|
||||
<el-form-item label="ShowOrder: " prop="Code">
|
||||
<!-- 显示顺序 -->
|
||||
<el-form-item :label="$t('dic:all:label:showOrder')" prop="Code">
|
||||
<el-input-number v-model="form.ShowOrder" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Description: " prop="Code">
|
||||
<!-- 描述 -->
|
||||
<el-form-item :label="$t('dic:all:label:desc')" prop="Code">
|
||||
<el-input v-model="form.Description" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="Value: " prop="Code">
|
||||
@@ -56,7 +61,8 @@
|
||||
<el-form-item label="ValueCN: " prop="Code">
|
||||
<el-input v-model="form.ValueCN" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="Is Enable: ">
|
||||
<!-- 是否启用 -->
|
||||
<el-form-item :label="$t('dic:all:label:isEnable')">
|
||||
<el-switch
|
||||
v-model="form.IsEnable"
|
||||
:active-value="true"
|
||||
@@ -66,8 +72,12 @@
|
||||
</el-form>
|
||||
</template>
|
||||
<template slot="dialog-footer">
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">Cancel</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">Save</el-button>
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">
|
||||
{{ $t('common:button:cancel') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</base-model>
|
||||
</template>
|
||||
@@ -103,8 +113,8 @@ export default {
|
||||
btnLoading: false,
|
||||
form: formDataDefault(),
|
||||
rules: {
|
||||
Code: [{ required: true, message: 'Please specify', trigger: 'blur' }],
|
||||
DataTypeEnum: [{ required: true, message: 'Please specify', trigger: 'blur' }]
|
||||
Code: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }],
|
||||
DataTypeEnum: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }]
|
||||
},
|
||||
model_cfg: { visible: false, showClose: true, width: '600px', title: '', appendToBody: true }
|
||||
}
|
||||
@@ -132,7 +142,7 @@ export default {
|
||||
this.btnLoading = true
|
||||
addOrUpdateBasicDic(this.form).then(res => {
|
||||
this.btnLoading = false
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.model_cfg.visible = false
|
||||
this.$emit('getList')
|
||||
}).catch(() => {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<!-- 搜索框 -->
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form-item label="字典表名称:">
|
||||
<el-form-item :label="$t('dic:all:label:code')">
|
||||
<el-input v-model="searchData.Code" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典分组:">
|
||||
<el-select v-model="searchData.ConfigTypeId" placeholder="字典分组" clearable size="small">
|
||||
<el-form-item :label="$t('dic:all:label:group')">
|
||||
<el-select v-model="searchData.ConfigTypeId" clearable size="small">
|
||||
<el-option v-for="item of basicDicList" :key="item.Id" :value="item.Id" :label="item.Code" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -29,7 +29,9 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span style="margin-left:auto">
|
||||
<el-button type="primary" @click="handleAdd">新建</el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<el-table
|
||||
@@ -44,33 +46,33 @@
|
||||
<el-table-column type="index" width="60" />
|
||||
<el-table-column
|
||||
prop="Code"
|
||||
label="字典表名称"
|
||||
:label="$t('dic:all:label:code')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ConfigType"
|
||||
label="字典分组"
|
||||
:label="$t('dic:all:label:group')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="Description"
|
||||
label="描述"
|
||||
:label="$t('dic:all:label:desc')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ShowOrder"
|
||||
label="显示顺序"
|
||||
:label="$t('dic:all:label:showOrder')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="是否可用" width="100" fixed="right">
|
||||
<el-table-column :label="$t('dic:all:label:isEnable')" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.IsEnable"
|
||||
@@ -80,25 +82,25 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="200" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
{{ $t('common:action:edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleChild(scope.row)"
|
||||
>
|
||||
子项
|
||||
{{ $t('dic:all:label:childItem') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -174,7 +176,7 @@ export default {
|
||||
switchChange(event, item) {
|
||||
this.loading = true
|
||||
addOrUpdateBasicDic(item).then(res => {
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
@@ -182,12 +184,12 @@ export default {
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', row)
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:action:edit'), row)
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', { DataTypeEnum: 2 })
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:button:new'), { DataTypeEnum: 2 })
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="activeTab" @tab-click="handleClick">
|
||||
<el-tab-pane label="全部" name="/dictionary/newDictionary/list">
|
||||
<!-- 全部 -->
|
||||
<el-tab-pane :label="$t('dic:label:all')" name="/dictionary/newDictionary/list">
|
||||
<dictList v-if="activeTab == '/dictionary/newDictionary/list'" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="下拉框字典" name="/dictionary/newDictionary/select">
|
||||
<!-- 下拉框字典 -->
|
||||
<el-tab-pane :label="$t('dic:label:select')" name="/dictionary/newDictionary/select">
|
||||
<dictSelect v-if="activeTab == '/dictionary/newDictionary/select'" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="枚举字典" name="/dictionary/newDictionary/enum">
|
||||
<!-- 枚举字典 -->
|
||||
<el-tab-pane :label="$t('dic:label:enum')" name="/dictionary/newDictionary/enum">
|
||||
<dictEnum v-if="activeTab == '/dictionary/newDictionary/enum'" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="布尔字典" name="/dictionary/newDictionary/bool">
|
||||
<!-- 布尔字典 -->
|
||||
<el-tab-pane :label="$t('dic:label:bool')" name="/dictionary/newDictionary/bool">
|
||||
<dictBool v-if="activeTab == '/dictionary/newDictionary/bool'" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="字典类型配置" name="/dictionary/newDictionary/config">
|
||||
<!-- 字典类型配置 -->
|
||||
<el-tab-pane :label="$t('dic:label:config')" name="/dictionary/newDictionary/config">
|
||||
<dictConfig v-if="activeTab == '/dictionary/newDictionary/config'" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
label-width="120px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item label="ConfigTypeId: " prop="Code">
|
||||
<!-- 字典分组 -->
|
||||
<el-form-item :label="$t('dic:all:label:group')" prop="Code">
|
||||
<el-select v-model="form.ConfigTypeId" filterable style="width:100%;">
|
||||
<el-option
|
||||
v-for="(item,index) of basicDicList"
|
||||
@@ -18,7 +19,8 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="DataTypeEnum: " prop="DataTypeEnum">
|
||||
<!-- 类型 -->
|
||||
<el-form-item :label="$t('dic:all:label:dataType')" prop="DataTypeEnum">
|
||||
<el-select v-model="form.DataTypeEnum" filterable style="width:100%;">
|
||||
<el-option
|
||||
:label="`config`"
|
||||
@@ -38,16 +40,19 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Code: " prop="Code">
|
||||
<!-- 字典表名称 -->
|
||||
<el-form-item :label="$t('dic:all:label:code')" prop="Code">
|
||||
<el-input v-model="form.Code" />
|
||||
</el-form-item>
|
||||
<!--<el-form-item label="KeyName: " prop="Code">-->
|
||||
<!--<el-input v-model="form.KeyName" />-->
|
||||
<!--</el-form-item>-->
|
||||
<el-form-item label="ShowOrder: " prop="Code">
|
||||
<!-- 显示顺序 -->
|
||||
<el-form-item :label="$t('dic:all:label:showOrder')" prop="Code">
|
||||
<el-input-number v-model="form.ShowOrder" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Description: " prop="Code">
|
||||
<!-- 描述 -->
|
||||
<el-form-item :label="$t('dic:all:label:desc')" prop="Code">
|
||||
<el-input v-model="form.Description" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="Value: " prop="Code">
|
||||
@@ -56,7 +61,8 @@
|
||||
<el-form-item label="ValueCN: " prop="Code">
|
||||
<el-input v-model="form.ValueCN" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="Is Enable: ">
|
||||
<!-- 是否启用 -->
|
||||
<el-form-item :label="$t('dic:all:label:isEnable')">
|
||||
<el-switch
|
||||
v-model="form.IsEnable"
|
||||
:active-value="true"
|
||||
@@ -66,8 +72,12 @@
|
||||
</el-form>
|
||||
</template>
|
||||
<template slot="dialog-footer">
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">Cancel</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">Save</el-button>
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">
|
||||
{{ $t('common:button:cancel') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</base-model>
|
||||
</template>
|
||||
@@ -103,8 +113,8 @@ export default {
|
||||
btnLoading: false,
|
||||
form: formDataDefault(),
|
||||
rules: {
|
||||
Code: [{ required: true, message: 'Please specify', trigger: 'blur' }],
|
||||
DataTypeEnum: [{ required: true, message: 'Please specify', trigger: 'blur' }]
|
||||
Code: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }],
|
||||
DataTypeEnum: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }]
|
||||
},
|
||||
model_cfg: { visible: false, showClose: true, width: '600px', title: '', appendToBody: true }
|
||||
}
|
||||
@@ -130,7 +140,7 @@ export default {
|
||||
this.btnLoading = true
|
||||
addOrUpdateBasicDic(this.form).then(res => {
|
||||
this.btnLoading = false
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.model_cfg.visible = false
|
||||
this.$emit('getList')
|
||||
}).catch(() => {
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
<!-- 搜索框 -->
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form-item label="字典表名称:">
|
||||
<!-- 字典表名称 -->
|
||||
<el-form-item :label="$t('dic:all:label:code')">
|
||||
<el-input v-model="searchData.Code" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典分组:">
|
||||
<el-select v-model="searchData.ConfigTypeId" placeholder="字典分组" clearable size="small">
|
||||
<!-- 字典分组 -->
|
||||
<el-form-item :label="$t('dic:all:label:group')">
|
||||
<el-select v-model="searchData.ConfigTypeId" clearable size="small">
|
||||
<el-option v-for="item of basicDicList" :key="item.Id" :value="item.Id" :label="item.Code" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键字:">
|
||||
<!-- 关键字 -->
|
||||
<el-form-item :label="$t('dic:all:label:keyWord')">
|
||||
<el-input v-model="searchData.KeyInfo" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@@ -32,8 +35,14 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span style="margin-left:auto">
|
||||
<el-button type="primary" @click="handleAdd">新建</el-button>
|
||||
<el-button type="primary" @click="handleBatchAdd">批量新建</el-button>
|
||||
<!-- 新建 -->
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
<!-- 批量新建 -->
|
||||
<el-button type="primary" @click="handleBatchAdd">
|
||||
{{ $t('common:button:batchNew') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<el-table
|
||||
@@ -46,16 +55,18 @@
|
||||
@sort-change="handleSortByColumn"
|
||||
>
|
||||
<el-table-column type="index" width="60" />
|
||||
<!-- 字典表名称 -->
|
||||
<el-table-column
|
||||
prop="Code"
|
||||
label="字典表名称"
|
||||
:label="$t('dic:all:label:code')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<!-- 类型 -->
|
||||
<el-table-column
|
||||
prop="DataTypeEnum"
|
||||
label="类型"
|
||||
:label="$t('dic:all:label:dataType')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
@@ -64,28 +75,32 @@
|
||||
{{ DataTypeEnumList[scope.row.DataTypeEnum] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 字典分组 -->
|
||||
<el-table-column
|
||||
prop="ConfigType"
|
||||
label="字典分组"
|
||||
:label="$t('dic:all:label:group')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<!-- 描述 -->
|
||||
<el-table-column
|
||||
prop="Description"
|
||||
label="描述"
|
||||
:label="$t('dic:all:label:desc')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<!-- 显示顺序 -->
|
||||
<el-table-column
|
||||
prop="ShowOrder"
|
||||
label="显示顺序"
|
||||
:label="$t('dic:all:label:showOrder')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="是否可用" width="100" fixed="right">
|
||||
<!-- 是否可用 -->
|
||||
<el-table-column :label="$t('dic:all:label:isEnable')" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.IsEnable"
|
||||
@@ -95,25 +110,28 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="300" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<!-- 编辑 -->
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
{{ $t('common:action:edit') }}
|
||||
</el-button>
|
||||
<!-- 子项 -->
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleChild(scope.row)"
|
||||
>
|
||||
子项
|
||||
{{ $t('dic:all:label:childItem') }}
|
||||
</el-button>
|
||||
<!-- 删除 -->
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -201,17 +219,17 @@ export default {
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', row)
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:action:edit'), row)
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', {})
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:button:new'), {})
|
||||
})
|
||||
},
|
||||
handleBatchAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['batchAddForm'].openDialog('批量新建', {})
|
||||
this.$refs['batchAddForm'].openDialog(this.$t('common:button:batchNew'), {})
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<!-- 搜索框 -->
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form-item label="字典表名称:">
|
||||
<el-form-item :label="$t('dic:all:label:code')">
|
||||
<el-input v-model="searchData.Code" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典分组:">
|
||||
<el-select v-model="searchData.ConfigTypeId" placeholder="字典分组" clearable size="small">
|
||||
<el-form-item :label="$t('dic:all:label:group')">
|
||||
<el-select v-model="searchData.ConfigTypeId" clearable size="small">
|
||||
<el-option v-for="item of basicDicList" :key="item.Id" :value="item.Id" :label="item.Code" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -29,8 +29,13 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span style="margin-left:auto">
|
||||
<el-button type="primary" @click="handleSetting">配置字典分组</el-button>
|
||||
<el-button type="primary" @click="handleAdd">新建</el-button>
|
||||
<!-- 配置字典分组 -->
|
||||
<el-button type="primary" @click="handleSetting">
|
||||
{{ $t('dic:select:button:setting') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<el-table
|
||||
@@ -45,33 +50,33 @@
|
||||
<el-table-column type="index" width="60" />
|
||||
<el-table-column
|
||||
prop="Code"
|
||||
label="字典表名称"
|
||||
:label="$t('dic:all:label:code')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ConfigType"
|
||||
label="字典分组"
|
||||
:label="$t('dic:all:label:group')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="Description"
|
||||
label="描述"
|
||||
:label="$t('dic:all:label:desc')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ShowOrder"
|
||||
label="显示顺序"
|
||||
:label="$t('dic:all:label:showOrder')"
|
||||
sortable="custom"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="是否可用" width="100" fixed="right">
|
||||
<el-table-column :label="$t('dic:all:label:isEnable')" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.IsEnable"
|
||||
@@ -81,25 +86,25 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="300" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
{{ $t('common:action:edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleChild(scope.row)"
|
||||
>
|
||||
子项
|
||||
{{ $t('dic:all:label:childItem') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -175,7 +180,7 @@ export default {
|
||||
switchChange(event, item) {
|
||||
this.loading = true
|
||||
addOrUpdateBasicDic(item).then(res => {
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
@@ -183,12 +188,12 @@ export default {
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', row)
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:action:edit'), row)
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', { DataTypeEnum: 1 })
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:button:new'), { DataTypeEnum: 1 })
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
label-width="150px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item label="Dictionary Type: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:group')"" prop="Code">
|
||||
<el-input v-model="form.Code" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Description: " prop="Code">
|
||||
<el-form-item :label="$t('dic:all:label:desc')">
|
||||
<el-input v-model="form.Description" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Is Enable: ">
|
||||
<el-form-item :label="$t('dic:all:label:isEnable')">
|
||||
<el-switch
|
||||
v-model="form.IsEnable"
|
||||
:active-value="true"
|
||||
@@ -24,8 +24,12 @@
|
||||
</el-form>
|
||||
</template>
|
||||
<template slot="dialog-footer">
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">Cancel</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">Save</el-button>
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancle">
|
||||
{{ $t('common:button:cancel') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</base-model>
|
||||
</template>
|
||||
@@ -52,7 +56,7 @@ export default {
|
||||
btnLoading: false,
|
||||
form: formDataDefault(),
|
||||
rules: {
|
||||
Code: [{ required: true, message: 'Please specify', trigger: 'blur' }]
|
||||
Code: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }]
|
||||
},
|
||||
model_cfg: { visible: false, showClose: true, width: '600px', title: '' }
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<!-- 搜索框 -->
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form-item label="Code:">
|
||||
<el-form-item :label="$t('dic:all:label:group')">
|
||||
<el-input v-model="searchData.Code" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="KeyName:">
|
||||
<el-form-item :label="$t('dic:all:label:keyWord')">
|
||||
<el-input v-model="searchData.KeyName" clearable style="width:120px;" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@@ -27,7 +27,9 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span style="margin-left:auto">
|
||||
<el-button type="primary" @click="handleAdd">New</el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<el-table
|
||||
@@ -41,15 +43,15 @@
|
||||
<el-table-column type="index" width="60" />
|
||||
<el-table-column
|
||||
prop="Code"
|
||||
label="Dictionary Type"
|
||||
:label="$t('dic:all:label:group')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="Description"
|
||||
label="Description"
|
||||
:label="$t('dic:all:label:desc')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="Is Enable" width="100" fixed="right">
|
||||
<el-table-column :label="$t('dic:all:label:isEnable')" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.IsEnable"
|
||||
@@ -59,19 +61,19 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="Action" width="200" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="200" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
{{ $t('common:action:edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -115,7 +117,7 @@ export default {
|
||||
switchChange(event, item) {
|
||||
this.loading = true
|
||||
addOrUpdateBasicDic(item).then(res => {
|
||||
this.$message.success('Saved successfully!')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
@@ -123,12 +125,12 @@ export default {
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', row)
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:action:edit'), row)
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog('DictionaryTypeConfig', {})
|
||||
this.$refs['DictionaryTypeConfigForm'].openDialog(this.$t('common:button:new'), {})
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<el-form ref="sysAgreementFrom" v-loading="loading" :model="form" label-width="140px" size="small" :rules="rules"
|
||||
class="upload-temporary-file">
|
||||
<div class="base-dialog-body">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('dictionary:agreement:table:UserAgreementTypeEnum')" prop="UserAgreementTypeEnum"
|
||||
style="width: 48%">
|
||||
<el-select v-model="form.UserAgreementTypeEnum" style="width: 100%" size="small" filterable>
|
||||
<el-option v-for="item of $d.UserAgreementType" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('dictionary:agreement:table:FileName')" prop="FileName" style="width: 48%">
|
||||
<el-input v-model="form.FileName" clearable style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('dictionary:agreement:table:FileVersion')" prop="FileVersion" style="width: 48%">
|
||||
<el-input v-model="form.FileVersion" clearable style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('dictionary:agreement:table:UpdateDate')" prop="UpdateDate" style="width: 48%">
|
||||
<el-date-picker v-model="form.UpdateDate" type="date"
|
||||
:placeholder="$t('trials:seletctedReviews:table:selectionTime')" value-format="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd" clearable style="width: 100%;">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('dictionary:agreement:table:EffectiveDate')" prop="EffectiveDate" style="width: 48%">
|
||||
<el-date-picker v-model="form.EffectiveDate" type="date"
|
||||
:placeholder="$t('trials:seletctedReviews:table:selectionTime')" value-format="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd" clearable style="width: 100%;">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item :label="$t('dictionary:agreement:table:FileContent')" prop="FileContent">
|
||||
<div class="html_temp">
|
||||
<prism-editor class="my-editor" v-model="form.FileContent" :highlight="highlighter" :line-numbers="true"
|
||||
style="width: 50%;max-height: 350px;"></prism-editor>
|
||||
<div v-html="form.FileContent" style="width: 45%;" class="content"></div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictionary:agreement:table:FileContentEn')" prop="FileEnContent">
|
||||
<div class="html_temp">
|
||||
<prism-editor class="my-editor" v-model="form.FileEnContent" :highlight="highlighter" :line-numbers="true"
|
||||
style="width: 50%;max-height: 350px;"></prism-editor>
|
||||
<div v-html="form.FileEnContent" style="width: 45%;" class="content"></div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
|
||||
<el-form-item style="text-align: right">
|
||||
<el-button size="small" type="primary" :loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save')
|
||||
}}</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
addOrUpdateUserAgreement,
|
||||
} from '@/api/dictionary'
|
||||
|
||||
import { PrismEditor } from 'vue-prism-editor';
|
||||
import 'vue-prism-editor/dist/prismeditor.min.css';
|
||||
import { highlight, languages } from 'prismjs/components/prism-core';
|
||||
import 'prismjs/components/prism-clike';
|
||||
import 'prismjs/components/prism-javascript';
|
||||
import 'prismjs/themes/prism.css';
|
||||
export default {
|
||||
name: 'TemplateForm',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
},
|
||||
components: { PrismEditor },
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
Id: '',
|
||||
UserAgreementTypeEnum: '',
|
||||
FileName: '',
|
||||
FileVersion: null,
|
||||
FileContent: '\n\n\n\n',
|
||||
FileEnContent: `\n\n\n\n`,
|
||||
UpdateDate: '',
|
||||
EffectiveDate: '',
|
||||
IsCurrentVersion: false
|
||||
},
|
||||
rules: {
|
||||
UserAgreementTypeEnum: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] },
|
||||
],
|
||||
FileName: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
],
|
||||
FileVersion: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
],
|
||||
FileContent: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
],
|
||||
FileEnContent: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
],
|
||||
UpdateDate: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] },
|
||||
],
|
||||
EffectiveDate: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] },
|
||||
],
|
||||
},
|
||||
saveBtnLoading: false,
|
||||
loading: false,
|
||||
dictionaryList: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initForm()
|
||||
},
|
||||
methods: {
|
||||
highlighter(code) {
|
||||
return highlight(code, languages.js);
|
||||
},
|
||||
async initForm() {
|
||||
if (Object.keys(this.data).length > 0) {
|
||||
for (const k in this.form) {
|
||||
if (this.data.hasOwnProperty(k)) {
|
||||
this.form[k] = this.data[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
handleSave() {
|
||||
this.$refs.sysAgreementFrom.validate((valid) => {
|
||||
if (!valid) return
|
||||
this.saveBtnLoading = true
|
||||
addOrUpdateUserAgreement(this.form)
|
||||
.then((res) => {
|
||||
this.saveBtnLoading = false
|
||||
this.$emit('closeDialog')
|
||||
this.$emit('getList')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
})
|
||||
.catch(() => {
|
||||
this.saveBtnLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.html_temp {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
.my-editor {
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.base-dialog-body {
|
||||
max-height: calc(100% - 60px);
|
||||
}
|
||||
|
||||
.upload-temporary-file {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,313 @@
|
||||
<template>
|
||||
<BaseContainer>
|
||||
<template slot="search-container">
|
||||
<el-form :inline="true" size="small">
|
||||
<!-- 文件类型 -->
|
||||
<el-form-item :label="$t('dictionary:agreement:table:UserAgreementTypeEnum')">
|
||||
<el-select v-model="searchData.UserAgreementTypeEnum" style="width: 150px">
|
||||
<el-option v-for="item of $d.UserAgreementType" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 文件名称 -->
|
||||
<el-form-item :label="$t('dictionary:agreement:table:FileName')">
|
||||
<el-input v-model="searchData.FileName" style="width: 130px" clearable />
|
||||
</el-form-item>
|
||||
<!-- 版本 -->
|
||||
<el-form-item :label="$t('dictionary:agreement:table:FileVersion')">
|
||||
<el-input v-model="searchData.FileVersion" style="width: 130px" clearable />
|
||||
</el-form-item>
|
||||
<!--更新日期-->
|
||||
<el-form-item :label="$t('dictionary:agreement:table:UpdateDate')">
|
||||
<el-date-picker v-model="UpdateDate" @change="changeTimeList('UpdateDate')" value-format="yyyy-MM-dd"
|
||||
type="daterange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<!--生效日期-->
|
||||
<el-form-item :label="$t('dictionary:agreement:table:EffectiveDate')">
|
||||
<el-date-picker v-model="EffectiveDate" @change="changeTimeList('EffectiveDate')" value-format="yyyy-MM-dd"
|
||||
type="daterange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<!-- 当前版本 -->
|
||||
<el-form-item :label="$t('dictionary:agreement:table:IsCurrentVersion')">
|
||||
<el-select v-model="searchData.IsCurrentVersion" style="width: 150px">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<!-- 查询 -->
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
|
||||
{{ $t('common:button:search') }}
|
||||
</el-button>
|
||||
<!-- 重置 -->
|
||||
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
|
||||
{{ $t('common:button:reset') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-button type="primary" style="float: right" size="small" @click="handleAdd">
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</el-form>
|
||||
</template>
|
||||
<template slot="main-container">
|
||||
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" stripe height="100"
|
||||
@sort-change="handleSortChange">
|
||||
<el-table-column type="index" width="40" />
|
||||
<!-- 文件类型 -->
|
||||
<el-table-column prop="UserAgreementTypeEnum" :label="$t('dictionary:agreement:table:UserAgreementTypeEnum')"
|
||||
show-overflow-tooltip sortable="custom">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
$fd(
|
||||
'UserAgreementType',
|
||||
scope.row.UserAgreementTypeEnum
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 文件名称 -->
|
||||
<el-table-column prop="FileName" :label="$t('dictionary:agreement:table:FileName')" show-overflow-tooltip
|
||||
sortable="custom" />
|
||||
<!-- 版本 -->
|
||||
<el-table-column prop="FileVersion" :label="$t('dictionary:agreement:table:FileVersion')" show-overflow-tooltip
|
||||
sortable="custom" />
|
||||
<!--内容-->
|
||||
<el-table-column prop="FileContent" :label="$t('dictionary:agreement:table:FileContent')">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click.stop="view(scope.row)">{{ $t('dictionary:agreement:button:view')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 更新日期 -->
|
||||
<el-table-column prop="UpdateDate" :label="$t('dictionary:agreement:table:UpdateDate')" show-overflow-tooltip
|
||||
sortable="custom">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.UpdateDate ? scope.row.UpdateDate.split(' ')[0] : '' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 生效日期 -->
|
||||
<el-table-column prop="EffectiveDate" :label="$t('dictionary:agreement:table:EffectiveDate')"
|
||||
show-overflow-tooltip sortable="custom">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.EffectiveDate ? scope.row.EffectiveDate.split(' ')[0] : '' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 当前版本 -->
|
||||
<el-table-column prop="IsCurrentVersion" :label="$t('dictionary:agreement:table:IsCurrentVersion')"
|
||||
show-overflow-tooltip sortable="custom">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
$fd(
|
||||
'YesOrNo',
|
||||
scope.row.IsCurrentVersion
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 创建日期 -->
|
||||
<el-table-column prop="CreateTime" :label="$t('dictionary:agreement:table:CreateTime')" show-overflow-tooltip
|
||||
sortable="custom" />
|
||||
<!-- 修改日期 -->
|
||||
<el-table-column prop="UpdateTime" :label="$t('dictionary:agreement:table:UpdateTime')" show-overflow-tooltip
|
||||
sortable="custom" />
|
||||
|
||||
<el-table-column :label="$t('common:action:action')" width="300">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" :disabled="scope.row.IsCurrentVersion" @click="setCurrentVersion(scope.row)">
|
||||
{{ $t('dictionary:agreement:button:setCurrentVersion') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="handleEdit(scope.row)">
|
||||
{{ $t('common:button:edit') }}
|
||||
</el-button>
|
||||
<!-- <el-button type="text" @click="handleDelete(scope.row)">
|
||||
{{ $t('common:button:delete') }}
|
||||
</el-button> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
|
||||
@pagination="getList" />
|
||||
|
||||
<!-- 新增/编辑 -->
|
||||
<el-dialog v-if="editDialog.visible" :visible.sync="editDialog.visible" :close-on-click-modal="false"
|
||||
:title="editDialog.title" custom-class="base-dialog-wrapper" :fullscreen="true">
|
||||
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
</BaseContainer>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getUserAgreementList,
|
||||
deleteUserAgreement,
|
||||
setCurrentVersion
|
||||
} from '@/api/dictionary'
|
||||
import BaseContainer from '@/components/BaseContainer'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import TemplateForm from './TemplateForm'
|
||||
const searchDataDefault = () => {
|
||||
return {
|
||||
StartEffectiveDate: null,
|
||||
EndEffectiveDate: null,
|
||||
FileName: null,
|
||||
FileVersion: null,
|
||||
IsCurrentVersion: null,
|
||||
StartUpdateDate: null,
|
||||
EndUpdateDate: null,
|
||||
UserAgreementTypeEnum: null,
|
||||
Asc: false,
|
||||
SortField: "",
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'Agreement',
|
||||
components: { BaseContainer, Pagination, TemplateForm },
|
||||
data() {
|
||||
return {
|
||||
searchData: searchDataDefault(),
|
||||
list: [],
|
||||
total: 0,
|
||||
currentRow: {},
|
||||
editDialog: { title: '', visible: false },
|
||||
loading: false,
|
||||
UpdateDate: [],
|
||||
EffectiveDate: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
},
|
||||
computed: {
|
||||
isEN() {
|
||||
return this.$i18n.locale !== 'zh'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async setCurrentVersion(row) {
|
||||
try {
|
||||
let data = {
|
||||
Id: row.Id
|
||||
}
|
||||
this.loading = true
|
||||
let res = await setCurrentVersion(data)
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.getList()
|
||||
}
|
||||
} catch (err) {
|
||||
this.loading = false
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
view(row) {
|
||||
this.$AGR({
|
||||
Id: row.Id,
|
||||
IsEn_Us: this.isEN
|
||||
})
|
||||
},
|
||||
changeTimeList(key) {
|
||||
if (this[key]) {
|
||||
this.searchData[`Start${key}`] = this[key][0]
|
||||
this.searchData[`End${key}`] = this[key][1]
|
||||
} else {
|
||||
this.searchData.BeginCreateTime = null
|
||||
this.searchData.EndCreateTime = null
|
||||
}
|
||||
},
|
||||
handleDelete(row) {
|
||||
// 确定删除该模版?
|
||||
this.$confirm(this.$t('dictionary:agreement:message:msg1')).then(() => {
|
||||
deleteUserAgreement(row.Id).then(() => {
|
||||
this.$message.success(this.$t('common:message:deletedSuccessfully'))
|
||||
this.getList()
|
||||
})
|
||||
}).catch(() => { })
|
||||
},
|
||||
PreviewFile(row) {
|
||||
let basePath = window.location.origin
|
||||
if (window.location.protocol !== 'https:') {
|
||||
basePath = 'https://irc.test.extimaging.com'
|
||||
}
|
||||
let data = {
|
||||
name: row.NameCN,
|
||||
path: basePath + row.Path,
|
||||
}
|
||||
this.$emit('PreviewFile', data)
|
||||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
getUserAgreementList(this.searchData)
|
||||
.then((res) => {
|
||||
this.loading = false
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 新增
|
||||
handleAdd() {
|
||||
this.editDialog.title = this.$t('common:button:new')
|
||||
this.currentRow = {}
|
||||
this.editDialog.visible = true
|
||||
},
|
||||
// 下载
|
||||
async handleDownload(row) {
|
||||
try {
|
||||
this.loading = true
|
||||
let fileName = this.isEN ? row.Name : row.NameCN;
|
||||
let type = fileName
|
||||
.substring(fileName.lastIndexOf('.'))
|
||||
.toLocaleLowerCase()
|
||||
if (!type) {
|
||||
let extendName = row.Path
|
||||
.substring(row.Path.lastIndexOf('.'))
|
||||
.toLocaleLowerCase()
|
||||
fileName += extendName
|
||||
}
|
||||
let res = await downLoadFile(this.OSSclientConfig.basePath + row.Path, fileName)
|
||||
this.loading = false
|
||||
} catch (err) {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
// 编辑
|
||||
handleEdit(row) {
|
||||
this.editDialog.title = this.$t('common:button:edit')
|
||||
this.currentRow = { ...row }
|
||||
this.editDialog.visible = true
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
},
|
||||
handleReset() {
|
||||
this.searchData = searchDataDefault()
|
||||
this.getList()
|
||||
},
|
||||
closeDialog() {
|
||||
this.editDialog.visible = false
|
||||
},
|
||||
// 排序
|
||||
handleSortChange(column) {
|
||||
if (column.order === 'ascending') {
|
||||
this.searchData.Asc = true
|
||||
} else {
|
||||
this.searchData.Asc = false
|
||||
}
|
||||
this.searchData.SortField = column.prop
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .search {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
@@ -6,12 +6,13 @@
|
||||
</template>
|
||||
<script>
|
||||
import { getExploreRecommentInfo } from "@/api/dictionary";
|
||||
import SystemInfo from "@/utils/systemInfo";
|
||||
export default {
|
||||
name: "browserTip",
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
tip: this.$t("browser:tip:changeBorwser"),
|
||||
tip: '',
|
||||
visible: false,
|
||||
};
|
||||
},
|
||||
@@ -36,6 +37,7 @@ export default {
|
||||
// console.log(type, No);
|
||||
if (type !== "Chrome" && type !== "Edge") {
|
||||
this.tip = this.$t("browser:tip:changeBorwser");
|
||||
// this.getSystemInfo()
|
||||
return (this.visible = true);
|
||||
}
|
||||
let res = await this.getInfo();
|
||||
@@ -51,12 +53,30 @@ export default {
|
||||
this.tip += "、";
|
||||
}
|
||||
});
|
||||
// this.getSystemInfo()
|
||||
return (this.visible = true);
|
||||
}
|
||||
// this.getSystemInfo()
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
getSystemInfo() {
|
||||
const systemInfo = new SystemInfo();
|
||||
const allInfo = systemInfo.getAllInfo();
|
||||
let deviceMemory = allInfo.hardware.deviceMemory; // 设备内存
|
||||
let { width, height } = allInfo.screen; // 分辨率
|
||||
// let discrete = allInfo.webgl.gpuType.discrete; // 是否独立显卡
|
||||
// let estimatedMemory = allInfo.webgl.memoryInfo.estimatedMemory; // 显卡内存
|
||||
// parseFloat(deviceMemory) < 16 ||
|
||||
if (width < 1920 || height < 1080) {
|
||||
if (this.tip) {
|
||||
this.tip += `<br/>`
|
||||
}
|
||||
this.tip += `<span>${this.$t("browser:tip:Configuration")}</span>`
|
||||
this.visible = true
|
||||
}
|
||||
},
|
||||
getExplore() {
|
||||
var Sys = {};
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
@@ -64,18 +84,18 @@ export default {
|
||||
(s = ua.match(/rv:([\d.]+)\) like gecko/))
|
||||
? (Sys.ie = s[1])
|
||||
: (s = ua.match(/msie ([\d\.]+)/))
|
||||
? (Sys.ie = s[1])
|
||||
: (s = ua.match(/edg\/([\d\.]+)/) || ua.match(/edge\/([\d\.]+)/))
|
||||
? (Sys.edge = s[1])
|
||||
: (s = ua.match(/firefox\/([\d\.]+)/))
|
||||
? (Sys.firefox = s[1])
|
||||
: (s = ua.match(/(?:opera|opr).([\d\.]+)/))
|
||||
? (Sys.opera = s[1])
|
||||
: (s = ua.match(/chrome\/([\d\.]+)/))
|
||||
? (Sys.chrome = s[1])
|
||||
: (s = ua.match(/version\/([\d\.]+).*safari/))
|
||||
? (Sys.safari = s[1])
|
||||
: 0;
|
||||
? (Sys.ie = s[1])
|
||||
: (s = ua.match(/edg\/([\d\.]+)/) || ua.match(/edge\/([\d\.]+)/))
|
||||
? (Sys.edge = s[1])
|
||||
: (s = ua.match(/firefox\/([\d\.]+)/))
|
||||
? (Sys.firefox = s[1])
|
||||
: (s = ua.match(/(?:opera|opr).([\d\.]+)/))
|
||||
? (Sys.opera = s[1])
|
||||
: (s = ua.match(/chrome\/([\d\.]+)/))
|
||||
? (Sys.chrome = s[1])
|
||||
: (s = ua.match(/version\/([\d\.]+).*safari/))
|
||||
? (Sys.safari = s[1])
|
||||
: 0;
|
||||
// 根据关系进行判断
|
||||
if (Sys.ie) return "IE: " + Sys.ie;
|
||||
if (Sys.edge) return "Edge: " + Sys.edge;
|
||||
@@ -100,6 +120,7 @@ export default {
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
color: #555;
|
||||
|
||||
i {
|
||||
color: red;
|
||||
font-size: 24px;
|
||||
|
||||