Compare commits
549 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65e4192312 | |||
| 28ac64747b | |||
| 5e014120c1 | |||
| 76a937066d | |||
| 414af5db9e | |||
| 8cc04c8bcf | |||
| 3592fe7ec7 | |||
| 22705f6035 | |||
| 698dca94d4 | |||
| e1f3669aab | |||
| 8f2109b4cd | |||
| 433cfdc123 | |||
| a278b032e2 | |||
| 2ec96a82f0 | |||
| b7b763651f | |||
| a07cf5f4d0 | |||
| 77f0c91e74 | |||
| 54e9e6f6ad | |||
| ba71d73407 | |||
| 9a64fd1bfd | |||
| 9b7d9d3c88 | |||
| 5ec234c9dd | |||
| 4709125107 | |||
| 0bbf537ddf | |||
| aba5dec904 | |||
| b04530ddd2 | |||
| 27bacd95d2 | |||
| 9385b1f671 | |||
| cdcc98efeb | |||
| bb00ac10f8 | |||
| e184b5255d | |||
| 095536ca33 | |||
| 83a1d2d5a4 | |||
| e91ce47f28 | |||
| 02b153c524 | |||
| 2b93fd18ff | |||
| c80e7ca5a9 | |||
| e7562fbe83 | |||
| 92da42f010 | |||
| 92bc105281 | |||
| 105bd48201 | |||
| d57c3b5157 | |||
| 30fdd91764 | |||
| f03db6f995 | |||
| 022a2005f1 | |||
| e64498858d | |||
| ffbf12f845 | |||
| c0523e2855 | |||
| 794ebeb42c | |||
| ffdf3d2376 | |||
| f69a297b2b | |||
| 39bd20e880 | |||
| 8a5be1a0ea | |||
| b6f8b41615 | |||
| bddcadeb89 | |||
| 2e388db02c | |||
| 370f99eabc | |||
| e2bd9feae6 | |||
| abbc15cb09 | |||
| 87f088ac05 | |||
| 0971f2b922 | |||
| e93be4cf9c | |||
| 2fca310327 | |||
| 97411b7eaf | |||
| 0631af4d9b | |||
| 2794cabdc8 | |||
| 8203b3d738 | |||
| 4d16ebb488 | |||
| b241682fa9 | |||
| cb16658190 | |||
| 8b766672b5 | |||
| b7d45456a6 | |||
| a4241bccf7 | |||
| 212a545aa9 | |||
| 11c4df2852 | |||
| 05bcb982dd | |||
| af62056962 | |||
| de7cd64c9b | |||
| 83f73db692 | |||
| 71418c393e | |||
| 6629fc0a17 | |||
| b7c00a0b70 | |||
| 3907123c1d | |||
| e1822126bb | |||
| 05e9bbb050 | |||
| 6b1fffb800 | |||
| d0d8819ab4 | |||
| 0e430ef8c9 | |||
| 0b87a1845c | |||
| e7a13be6e4 | |||
| f7b5ab0281 | |||
| e3be28ca17 | |||
| ee34e6cdc2 | |||
| 8c83897c6e | |||
| 3a6956c031 | |||
| 73e7b4c3fa | |||
| 7f9080398a | |||
| 4c7c0cce47 | |||
| eda4b31dda | |||
| dc84d0e96f | |||
| 7fea4b938f | |||
| 7325760c23 | |||
| 1a26d3885a | |||
| f9c9d0be6d | |||
| ebfbe27d0c | |||
| 37257da722 | |||
| 6d214727b5 | |||
| 1db50cff3b | |||
| 6d17a1f3cd | |||
| f38f1f465a | |||
| db627afeda | |||
| fef7215bdb | |||
| 0718a70f91 | |||
| da21972c63 | |||
| 361ab4e2fd | |||
| 7a52507d27 | |||
| 83dc28008f | |||
| 323b76036a | |||
| 4b7bb8df95 | |||
| 46aa64365f | |||
| d2fae40100 | |||
| 4030b1c95b | |||
| d689c23f5a | |||
| 4a7f8a0a93 | |||
| 7daa7fda0c | |||
| b25426711a | |||
| f06f7827cf | |||
| 3ea46b5d1e | |||
| 72634c785d | |||
| 2dbf6a1fb3 | |||
| 755f305389 | |||
| 29a6870fb5 | |||
| 2d99e074b8 | |||
| 6e6e2d11d0 | |||
| 6b8711232e | |||
| eb0b9d6fb8 | |||
| 7ef1cafeff | |||
| 3ac3e41d0d | |||
| 1763e49650 | |||
| 016a5e93ea | |||
| e4d731222b | |||
| aeeba1dfb7 | |||
| d7ebed0b05 | |||
| 312e85d9b3 | |||
| 3ee32c2e56 | |||
| 2778b34f14 | |||
| 6736121309 | |||
| e48c00f817 | |||
| e5f7ad3b31 | |||
| b7a0a336dd | |||
| d83a086087 | |||
| d03ce19b02 | |||
| a2668b39be | |||
| a30fd58d79 | |||
| 31d0872653 | |||
| e63e38222e | |||
| 65d7a95d5f | |||
| 298619717a | |||
| d6713ba9a4 | |||
| 0e252b0377 | |||
| 52ab454860 | |||
| 0e2e57446b | |||
| 94b0354fe4 | |||
| 93ed9943fa | |||
| e04e94a792 | |||
| b7c57c3c27 | |||
| 015eb78b70 | |||
| 04580ed1bb | |||
| b6877d4fe8 | |||
| b53f566160 | |||
| c767004a2d | |||
| 3a546e6e89 | |||
| 6af2f0555e | |||
| a82526e21d | |||
| c65ad92d39 | |||
| 36d5661044 | |||
| feb94dc832 | |||
| 756750783c | |||
| db3f7b4cde | |||
| a9d62cf28d | |||
| 04014ab524 | |||
| 2a68b40875 | |||
| 375a7e7071 | |||
| efc3b03392 | |||
| 730a375509 | |||
| d34b4b796c | |||
| 427f060935 | |||
| 6a10cb1afe | |||
| 962ac2e693 | |||
| 3567f2d625 | |||
| bd980cd867 | |||
| 284432ffa4 | |||
| 16e2fbc8ff | |||
| ac6be424ee | |||
| 351b2a627f | |||
| dd919f123e | |||
| 3a33abf02e | |||
| 917373e081 | |||
| 632463327c | |||
| 59a14c0e37 | |||
| 511640f66f | |||
| c26f5df102 | |||
| 98e9af71a3 | |||
| b59e0c12f6 | |||
| fed2677689 | |||
| a55278e323 | |||
| 8f808d73b5 | |||
| 717c5a6529 | |||
| ec676d8d2b | |||
| 2ce14c6d72 | |||
| 10b5bba0dd | |||
| 159a36cd70 | |||
| 4a17946598 | |||
| d6f36cbbda | |||
| e6a15e35f6 | |||
| 27a9ccd3c2 | |||
| e8dda21459 | |||
| 7ebbfb9621 | |||
| 9da7c1a159 | |||
| 197f17fc99 | |||
| d680c57482 | |||
| 7266d0a4f5 | |||
| 3e19e85a8d | |||
| c9057e12cd | |||
| 10bac01371 | |||
| 67d54aedb7 | |||
| 1a21aa38f3 | |||
| 64f0998896 | |||
| 04d9a53a0e | |||
| fd0412004e | |||
| 64ef1e513c | |||
| a83349387a | |||
| 9500842628 | |||
| 998e340919 | |||
| 753127381f | |||
| a5c3dac047 | |||
| a7337a347b | |||
| 85b88d4564 | |||
| 763e00a6ca | |||
| 6a345e35cd | |||
| 09e9c62f3c | |||
| af97e2b4ed | |||
| e0dd443d84 | |||
| 1c0cdde9ad | |||
| e100d45bc1 | |||
| 49c7482d76 | |||
| 22b77ff70f | |||
| 3a35f4a966 | |||
| 8ff9e3b232 | |||
| e189080e5c | |||
| 07b1e5d1f9 | |||
| 2f92bf6dfb | |||
| 391e696d8a | |||
| 9ff7928b16 | |||
| 3c0971e961 | |||
| 1f20834dd3 | |||
| f34665fcb9 | |||
| 00e03c782d | |||
| 5e6c8e6936 | |||
| cd2c56c510 | |||
| ec7cb78018 | |||
| 6a65b6507f | |||
| d08df877d7 | |||
| 10a43d4c04 | |||
| a87769a60f | |||
| 4d808ed87c | |||
| 0a3a4e3bb4 | |||
| 0aab18924b | |||
| 2bf9b21f40 | |||
| 06d0ce2290 | |||
| 1b6e53819c | |||
| a59509dd7d | |||
| d88f7c43b2 | |||
| c3543e19c8 | |||
| 72b1a3906d | |||
| 06794447ec | |||
| 00c5570692 | |||
| cd2df6e576 | |||
| 52f9c17234 | |||
| 0b78561331 | |||
| c12da4de3e | |||
| 4f16060a46 | |||
| 212bd65bc1 | |||
| afc35daffa | |||
| 5bf8e7ecf6 | |||
| 192f7a3316 | |||
| d88535b75e | |||
| 128cdc0f75 | |||
| 4a8b1da094 | |||
| 728f3238ca | |||
| e245057bb2 | |||
| 7bf80c10eb | |||
| ecf4c8a2c7 | |||
| c532babf98 | |||
| 2fa54eaac6 | |||
| 50de867772 | |||
| 24a48e3d23 | |||
| 13429f45ed | |||
| 8545e8f1d6 | |||
| 619a7b2ee3 | |||
| 544f83d118 | |||
| 1541e3d353 | |||
| 7a454d09ff | |||
| 06f52f4f24 | |||
| 877e47ccb1 | |||
| c373b59f23 | |||
| 73e8f24c3d | |||
| 1e57777d3b | |||
| aca7f07d00 | |||
| 35e52fbdcf | |||
| aaeadbc440 | |||
| 60d3dfa6e7 | |||
| 417fefb04b | |||
| 27646e2c46 | |||
| 48b154bf87 | |||
| acfa552cbe | |||
| aa6a226ce1 | |||
| 09144f2b98 | |||
| 9b8c6788bf | |||
| 4aa1a05ea9 | |||
| 45790141df | |||
| 6804d909b8 | |||
| 1a1bf6810c | |||
| c9e7719c71 | |||
| 07b23fce1d | |||
| 9f5cbad22e | |||
| 3cf4f95770 | |||
| 5a01f10957 | |||
| 4ed0ebc913 | |||
| 9971c3ecca | |||
| 3c10ae73dd | |||
| 5cbd13cc3d | |||
| 7dcc524bd3 | |||
| bc4639a238 | |||
| 0f25958d9b | |||
| ff0d204612 | |||
| 91386589ae | |||
| b2a9f279a1 | |||
| b4fc5d970f | |||
| e046bffdbd | |||
| 38ea9ddb0b | |||
| 1194e56139 | |||
| 741c723bab | |||
| fea0047f58 | |||
| 5a943fbefe | |||
| 6c88af0a03 | |||
| 26412931a9 | |||
| 5a1b64a023 | |||
| 64d8c853b3 | |||
| 0261fb04c6 | |||
| ab372a9c29 | |||
| f7dd68f7f3 | |||
| 946203f124 | |||
| f0eb814492 | |||
| 6c36c48b82 | |||
| 47b05526a2 | |||
| f7afca6e73 | |||
| 04aa61658c | |||
| 86c506bc1d | |||
| 06959b4465 | |||
| 838ab975cc | |||
| 7aa33672a9 | |||
| 81297954d3 | |||
| 25e348f428 | |||
| c101302cca | |||
| c4fd8c3ea3 | |||
| a7e7419a20 | |||
| 55da1d9219 | |||
| 2a842fd2f8 | |||
| ca2e9e0253 | |||
| b4c06990f6 | |||
| 599fad48ba | |||
| 72b5d515ba | |||
| 608bd42836 | |||
| 040f66f182 | |||
| 7afbc360e5 | |||
| 74c5d032fb | |||
| 43aa371c36 | |||
| 398ec90fae | |||
| 890910a763 | |||
| 3b5ebfcba1 | |||
| b971235164 | |||
| e53a18f212 | |||
| 774f43a6d0 | |||
| 88f274ab89 | |||
| 3345a989ae | |||
| 11000ef9f8 | |||
| 57be74aea8 | |||
| 8724eeeafb | |||
| 7c71a6d342 | |||
| cb04be1b56 | |||
| 63709b414d | |||
| 7001bc9ec0 | |||
| c12833d283 | |||
| 22baa213ae | |||
| 09c1c3ff12 | |||
| 94f43f4b11 | |||
| 1a42cfd47c | |||
| b6b918efbf | |||
| a16d86d942 | |||
| 266698cc79 | |||
| eac6b25b9e | |||
| 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 | |||
| 443a31df97 | |||
| d21c01076d |
@@ -1,4 +1,39 @@
|
||||
|
||||
kind: pipeline
|
||||
type: ssh
|
||||
name: ssh-linux-uat-irc-publish
|
||||
|
||||
platform:
|
||||
os: Linux
|
||||
arch: 386
|
||||
|
||||
clone:
|
||||
disable: true #禁用默认克隆
|
||||
|
||||
server:
|
||||
host: 101.132.253.119
|
||||
user: root
|
||||
password:
|
||||
from_secret: local_pwd
|
||||
|
||||
steps:
|
||||
- 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
|
||||
@@ -30,9 +65,6 @@ steps:
|
||||
- failure
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
|
||||
|
||||
- main
|
||||
|
||||
|
||||
@@ -9,24 +9,25 @@
|
||||
"build:usa": "vue-cli-service build --mode usa",
|
||||
"build:usa_prod": "vue-cli-service build --mode usa_prod",
|
||||
"pre": "vue-cli-service build --mode pre",
|
||||
"postinstall": "patch-package",
|
||||
"i18n": "npm run i18n:zh && npm run i18n:en",
|
||||
"i18n:zh": "node i18nGenerate.js lang=zh keyCol=5 valCol=6",
|
||||
"i18n:en": "node i18nGenerate.js lang=en keyCol=5 valCol=7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.701.0",
|
||||
"@cornerstonejs/adapters": "^2.19.7",
|
||||
"@aws-sdk/client-s3": "3.726.1",
|
||||
"@cornerstonejs/adapters": "^4.19.2",
|
||||
"@cornerstonejs/calculate-suv": "^1.1.0",
|
||||
"@cornerstonejs/core": "^2.19.7",
|
||||
"@cornerstonejs/dicom-image-loader": "^2.19.7",
|
||||
"@cornerstonejs/tools": "^2.19.7",
|
||||
"@cornerstonejs/core": "^4.19.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^4.19.2",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^4.19.2",
|
||||
"@cornerstonejs/tools": "^4.19.2",
|
||||
"@fingerprintjs/fingerprintjs": "^4.6.2",
|
||||
"@icr/polyseg-wasm": "^0.4.0",
|
||||
"@microsoft/signalr": "^8.0.7",
|
||||
"@riophae/vue-treeselect": "^0.4.0",
|
||||
"@vue-office/docx": "^1.6.2",
|
||||
"@vue-office/excel": "^1.7.11",
|
||||
"@vue/composition-api": "^1.7.2",
|
||||
"ali-oss": "^6.17.1",
|
||||
"axios": "^0.18.1",
|
||||
"core-js": "^3.8.3",
|
||||
@@ -38,7 +39,8 @@
|
||||
"dcmjs": "^0.29.8",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"dicomedit": "^0.1.0",
|
||||
"echarts": "^4.8.0",
|
||||
"echarts": "^6.0.0",
|
||||
"echarts-map": "^3.0.1",
|
||||
"element-ui": "^2.15.14",
|
||||
"exceljs": "^4.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -60,11 +62,10 @@
|
||||
"screenfull": "^6.0.2",
|
||||
"sortablejs": "^1.15.5",
|
||||
"streamsaver": "^2.0.6",
|
||||
"svg-sprite-loader": "^4.1.3",
|
||||
"svgo": "^1.2.2",
|
||||
"v-viewer": "^1.7.4",
|
||||
"vcrontab": "^0.3.5",
|
||||
"vue": "^2.6.14",
|
||||
"vue": "2.7.16",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-contextmenujs": "^1.4.11",
|
||||
"vue-count-to": "^1.0.13",
|
||||
@@ -95,12 +96,14 @@
|
||||
"html-webpack-plugin": "^5.6.3",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"node-polyfill-webpack-plugin": "^4.0.0",
|
||||
"patch-package": "^8.0.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"process": "^0.11.10",
|
||||
"sass": "^1.63.2",
|
||||
"sass-loader": "^10.4.1",
|
||||
"sass-loader": "^16.0.7",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue-template-compiler": "2.7.16",
|
||||
"webpack": "^5.96.1",
|
||||
"webpack-bundle-analyzer": "^4.10.2"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
diff --git a/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js b/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js
|
||||
index 33469a3..f39736f 100644
|
||||
--- a/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js
|
||||
+++ b/node_modules/@cornerstonejs/dicom-image-loader/dist/esm/imageLoader/isColorConversionRequired.js
|
||||
@@ -14,10 +14,7 @@ export default function isColorConversionRequired(imageFrame) {
|
||||
(3 * Math.ceil(columns / 2) + Math.floor(columns / 2)) * rows);
|
||||
}
|
||||
else if (photometricInterpretation.endsWith('422')) {
|
||||
- return (pixelDataLength ===
|
||||
- (3 * Math.ceil(columns / 2) + Math.floor(columns / 2)) *
|
||||
- Math.ceil(rows / 2) +
|
||||
- Math.floor(rows / 2) * columns);
|
||||
+ return pixelDataLength === rows * columns * 2;
|
||||
}
|
||||
else {
|
||||
return photometricInterpretation !== 'RGB' || planarConfiguration === 1;
|
||||
@@ -0,0 +1,3 @@
|
||||
window.config = {
|
||||
timeZone: false
|
||||
}
|
||||
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -67,6 +67,7 @@
|
||||
num = e.data
|
||||
}
|
||||
</script>
|
||||
<script src="/config.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="app" style="position: relative">
|
||||
<div id="app" style="position: relative" :class="{ mask: isLock }">
|
||||
<router-view />
|
||||
<div v-show="show" v-if="$route.matched.length > 0" v-adaptive @click="openI18n" style="
|
||||
position: fixed;
|
||||
@@ -63,7 +63,7 @@
|
||||
" size="mini"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ValueCN" :label="$t('il8n:table:state')" sortable="custom">
|
||||
<el-table-column prop="State" :label="$t('il8n:table:state')" sortable="custom">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.State" clearable filterable size="mini">
|
||||
<el-option v-for="item of $d.InternationalizationKeyState"
|
||||
@@ -83,7 +83,7 @@
|
||||
</div>
|
||||
</el-drawer>
|
||||
<feedBack v-if="$route.matched.length > 0" />
|
||||
<timeTag />
|
||||
<timeTag v-if="config.timeZone" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -97,9 +97,13 @@ import feedBack from '@/views/trials/trials-layout/components/feedBack'
|
||||
import timeTag from '@/components/timeTag'
|
||||
import Vue from 'vue'
|
||||
import i18n from './lang'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
export default {
|
||||
name: 'App',
|
||||
components: { feedBack, timeTag },
|
||||
components: {
|
||||
feedBack,
|
||||
timeTag
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawer: false,
|
||||
@@ -109,12 +113,17 @@ export default {
|
||||
arr: [],
|
||||
il8nExternal: false,
|
||||
State: null,
|
||||
config: window.config,
|
||||
isLock: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.show = process.env.VUE_APP_OSS_PATH === '/test/dist'
|
||||
this.show = false
|
||||
this.show = process.env.VUE_APP_OSS_PATH === '/test/dist'
|
||||
Vue.prototype.$openI18n = this.openI18n
|
||||
this.getIsLock()
|
||||
DicomEvent.$on("isLock", (isLock) => {
|
||||
this.isLock = isLock
|
||||
})
|
||||
},
|
||||
// watch: {
|
||||
// '$route.query': {
|
||||
@@ -146,17 +155,30 @@ export default {
|
||||
// },
|
||||
// },
|
||||
methods: {
|
||||
getIsLock() {
|
||||
if (zzSessionStorage.getItem('isLock') === 'true') {
|
||||
this.isLock = true
|
||||
} else {
|
||||
this.isLock = false
|
||||
}
|
||||
},
|
||||
// 排序
|
||||
handleSortByColumn(column) {
|
||||
if (column.order === 'ascending') {
|
||||
this.tableData.sort((a, b) =>
|
||||
a[column.prop].localeCompare(b[column.prop])
|
||||
)
|
||||
} else {
|
||||
this.tableData.sort((a, b) =>
|
||||
b[column.prop].localeCompare(a[column.prop])
|
||||
)
|
||||
const { prop, order } = column
|
||||
if (!prop || !order) {
|
||||
this.tableData = [...this.tableData]
|
||||
return
|
||||
}
|
||||
|
||||
const collator = new Intl.Collator('zh-Hans-CN', {
|
||||
numeric: true,
|
||||
sensitivity: 'base',
|
||||
})
|
||||
|
||||
this.tableData.sort((a, b) => {
|
||||
const result = collator.compare(a[prop], b[prop])
|
||||
return order === 'ascending' ? result : -result
|
||||
})
|
||||
},
|
||||
handleStateChange() {
|
||||
this.tableData.forEach((item) => {
|
||||
@@ -298,6 +320,23 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.mask {
|
||||
position: relative;
|
||||
filter: blur(5px);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.mask::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
display: block;
|
||||
background: rgba(255, 253, 253, 0.5);
|
||||
}
|
||||
|
||||
$light_gray: #606266;
|
||||
|
||||
.el-tooltip__popper {
|
||||
|
||||
@@ -391,3 +391,35 @@ export function getReSendEmail(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取系统基础配置
|
||||
export function getSystemBasicConfigInfo() {
|
||||
return request({
|
||||
url: `/DeployConfig/getSystemBasicConfigInfo`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
// 更新系统基础配置
|
||||
export function updateSystemBasicConfig(data) {
|
||||
return request({
|
||||
url: `/DeployConfig/updateSystemBasicConfig`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 获取系统邮件配置
|
||||
export function getEmailConfigInfo() {
|
||||
return request({
|
||||
url: `/DeployConfig/getEmailConfigInfo`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
// 更新系统邮件配置
|
||||
export function updateSystemEmailConfig(data) {
|
||||
return request({
|
||||
url: `/DeployConfig/updateSystemEmailConfig`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -319,3 +319,164 @@ 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
|
||||
})
|
||||
}
|
||||
// 修改分割片段锁定状态
|
||||
export function lockOrUnLockSegment(data) {
|
||||
return request({
|
||||
url: `/Segmentation/lockOrUnLockSegment`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 图像数据匿名
|
||||
export function studyMaskImage(data) {
|
||||
return request({
|
||||
url: `/Study/studyMaskImage`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 撤销匿名
|
||||
export function studyUndoMaskImage(data) {
|
||||
return request({
|
||||
url: `/Study/studyUndoMaskImage`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 非dicom图像数据匿名
|
||||
export function noneDicomStudyMaskImage(data) {
|
||||
return request({
|
||||
url: `/NoneDicomStudy/noneDicomStudyMaskImage`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 非dicom图像数据撤销匿名
|
||||
export function noneDicomStudyUndoMaskImage(data) {
|
||||
return request({
|
||||
url: `/NoneDicomStudy/noneDicomStudyUndoMaskImage`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 获取分割组历史版本
|
||||
export function getSegmentationVersionList(data) {
|
||||
return request({
|
||||
url: `/Segmentation/getSegmentationVersionList`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 恢复分割历史版本
|
||||
export function restoreSegmentationVersion(data) {
|
||||
return request({
|
||||
url: `/Segmentation/restoreSegmentationVersion`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取标记信息
|
||||
export function getMarkList(data) {
|
||||
return request({
|
||||
url: `/ReadingImageTask/getMarkList`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export function getNoneDicomMarkList(data) {
|
||||
return request({
|
||||
url: `/ReadingImageTask/getNoneDicomMarkList`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@@ -357,10 +357,11 @@ export function getSubjectList(param) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getTrialSiteSelect(trialId) {
|
||||
export function getTrialSiteSelect(trialId, params) {
|
||||
return request({
|
||||
url: `/trialMaintenance/getTrialSiteSelect/${trialId}`,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4430,4 +4431,95 @@ export function updateImageResizePath(data) {
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取PET图像上患者信息
|
||||
export function getPatientInfo(data) {
|
||||
return request({
|
||||
url: `/Study/getPatientInfo`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//编辑患者基本信息
|
||||
export function editPatientInfo(data) {
|
||||
return request({
|
||||
url: `/Study/editPatientInfo`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//修正患者基本信息
|
||||
export function amendmentPatientInfo(data) {
|
||||
return request({
|
||||
url: `/Inspection/Study/amendmentPatientInfo`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//修改临床数据后 将签名状态变更为未签名
|
||||
export function updateReadModuleClinicalData(data) {
|
||||
return request({
|
||||
url: `/ReadingClinicalData/updateReadModuleClinicalData`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getTrialUnreadVisitList(params) {
|
||||
return request({
|
||||
url: `/DownloadAndUpload/getTrialUnreadVisitList`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
export function getDoctorUserTrialReadingStat(data) {
|
||||
return request({
|
||||
url: `/DoctorWorkload/getDoctorUserTrialReadingStat`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
// 设置项目链接过期时间
|
||||
export function setTrialLinkExpirationTime(data) {
|
||||
return request({
|
||||
url: `/TrialConfig/setTrialLinkExpirationTime`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
// 获取项目链接过期时间
|
||||
export function getTrialLinkExpirationTime(data) {
|
||||
return request({
|
||||
url: `/TrialConfig/getTrialLinkExpirationTime`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
// 获取项目链接时间是否过期
|
||||
export function getLinkLinkExpirationTime(data) {
|
||||
return request({
|
||||
url: `/TrialConfig/getLinkLinkExpirationTime`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
// 获取项目链接code是否有效
|
||||
export function getLinkVerificationCodeIsEffective(data) {
|
||||
return request({
|
||||
url: `/TrialConfig/getLinkVerificationCodeIsEffective`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
// 上传通用文件记录
|
||||
export function addOrUpdateCommonUploadRecord(data) {
|
||||
return request({
|
||||
url: `/FileUploadRecord/addOrUpdateCommonUploadRecord`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 353 KiB |
@@ -6,6 +6,7 @@
|
||||
<div>Series #{{ dicomInfo.series }}</div>
|
||||
<div>Image #{{ dicomInfo.frame }}</div>
|
||||
<div>{{ dicomInfo.modality }}</div>
|
||||
<div v-if="isComparison" style="font-size: 30px;color: #428bca;">{{ tip }}</div>
|
||||
</div>
|
||||
<div v-show="dicomInfo.series" class="info-image">
|
||||
<!-- <div>
|
||||
@@ -15,7 +16,7 @@
|
||||
<div v-show="dicomInfo.thick">Slice Thickness {{ dicomInfo.thick }}mm</div>
|
||||
<div>WW/WC {{ dicomInfo.wwwc }}</div>
|
||||
<div>Zoom {{ dicomInfo.zoom }}</div>
|
||||
<div v-show="dicomInfo.location">Location {{ dicomInfo.location }}mm</div> -->
|
||||
<div v-show="dicomInfo.location">Location {{ dicomInfo.location }}mm</div>-->
|
||||
<!-- <div v-show="toolState.clipPlaying">FPS {{ dicomInfo.fps }}</div> -->
|
||||
<div v-show="mousePosition.mo">
|
||||
Pos: {{ mousePosition.x ? mousePosition.x.toFixed(0) : '' }}, {{ mousePosition.y ? mousePosition.y.toFixed(0) :
|
||||
@@ -23,24 +24,18 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="(dicomInfo.modality === 'CT' || dicomInfo.modality === 'DR' || dicomInfo.modality === 'CR') && mousePosition.mo">
|
||||
HU: {{ mousePosition.mo }}
|
||||
</div>
|
||||
<div v-else-if="(dicomInfo.modality === 'PT' && mousePosition.suv)">
|
||||
SUVbw(g/ml): {{ mousePosition.suv.toFixed(3) }}
|
||||
</div>
|
||||
<div v-else-if="mousePosition.mo">
|
||||
Density: {{ mousePosition.mo }}
|
||||
</div>
|
||||
<div>
|
||||
W*H: {{ dicomInfo.size }}
|
||||
</div>
|
||||
HU: {{ mousePosition.mo }}</div>
|
||||
<div v-else-if="(dicomInfo.modality === 'PT' && mousePosition.suv)">SUVbw(g/ml): {{ mousePosition.suv.toFixed(3)
|
||||
}}</div>
|
||||
<div v-else-if="mousePosition.mo">Density: {{ mousePosition.mo }}</div>
|
||||
<div>W*H: {{ dicomInfo.size }}</div>
|
||||
|
||||
<div>Zoom: {{ dicomInfo.zoom }}</div>
|
||||
</div>
|
||||
|
||||
<div class="info-subject">
|
||||
<div v-if="series.subjectCode">{{ series.subjectCode }}</div>
|
||||
<div v-if="series.visitName">{{ series.visitName }}</div>
|
||||
<div v-if="series.subjectCode && IsReadingTaskViewInOrder !== 0">{{ series.subjectCode }}</div>
|
||||
<div v-if="series.visitName && IsReadingTaskViewInOrder !== 0">{{ series.visitName }}</div>
|
||||
<div>{{ stack.description }}</div>
|
||||
<!-- <div>{{ dicomInfo.hospital }}</div> -->
|
||||
<!-- <div v-show="dicomInfo.pid">{{ dicomInfo.pid }}</div> -->
|
||||
@@ -56,24 +51,17 @@
|
||||
style="z-index:10;background: #9e9e9e;height: 20px;width: 100%;position: absolute;top: 0;cursor: move"
|
||||
@mousedown="sliderMousedown($event)" />
|
||||
</div>
|
||||
<div style="position: absolute;left: 50%;top: 15px;color: #f44336;">
|
||||
{{ markers.top }}
|
||||
</div>
|
||||
<div style="position: absolute;top: 50%;right: 15px;color: #f44336;">
|
||||
{{ markers.right }}
|
||||
</div>
|
||||
<div style="position: absolute;left: 50%;top: 15px;color: #f44336;">{{ markers.top }}</div>
|
||||
<div style="position: absolute;top: 50%;right: 15px;color: #f44336;">{{ markers.right }}</div>
|
||||
|
||||
<div style="position: absolute;left: 50%;bottom: 15px;color: #f44336;">
|
||||
{{ markers.bottom }}
|
||||
</div>
|
||||
<div style="position: absolute;top: 50%;left: 15px;color: #f44336;">
|
||||
{{ markers.left }}
|
||||
</div>
|
||||
<div style="position: absolute;left: 50%;bottom: 15px;color: #f44336;">{{ markers.bottom }}</div>
|
||||
<div style="position: absolute;top: 50%;left: 15px;color: #f44336;">{{ markers.left }}</div>
|
||||
|
||||
<div class="info-instance">
|
||||
<svg-icon icon-class="IsMasked" style="font-size:20px;" v-show="dicomInfo.IsMasked" />
|
||||
<!-- <div v-show="dicomInfo.pixel">
|
||||
Pixel: {{ dicomInfo.pixel }}mm
|
||||
</div> -->
|
||||
</div>-->
|
||||
<div v-show="dicomInfo.location">Location: {{ dicomInfo.location }}</div>
|
||||
<div v-show="dicomInfo.thick">Slice Thickness: {{ dicomInfo.thick }}mm</div>
|
||||
<div v-show="dicomInfo.wwwc">WW/WL: {{ dicomInfo.wwwc }}</div>
|
||||
@@ -92,15 +80,18 @@
|
||||
import * as cornerstone from 'cornerstone-core'
|
||||
import * as cornerstoneMath from 'cornerstone-math'
|
||||
import * as cornerstoneTools from 'cornerstone-tools'
|
||||
import metaDataProvider from '@/utils/metaDataProvider'
|
||||
|
||||
const scroll = cornerstoneTools.import('util/scrollToIndex')
|
||||
import Hammer from 'hammerjs'
|
||||
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
||||
import invertOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/invertOrientationString'
|
||||
|
||||
import calculateSUV from '@/views/trials/trials-panel/reading/dicoms/tools/calculateSUV'
|
||||
const calculateSUV = cornerstoneTools.import('util/calculateSUV')
|
||||
// import requestPoolManager from '@/utils/request-pool'
|
||||
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
|
||||
import Note_RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/Note_RectangleRoiTool'
|
||||
let isMetaDataProviderAdded = false
|
||||
cornerstoneTools.external.cornerstone = cornerstone
|
||||
cornerstoneTools.external.Hammer = Hammer
|
||||
cornerstoneTools.external.cornerstoneMath = cornerstoneMath
|
||||
@@ -110,6 +101,7 @@ cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)')
|
||||
// cornerstoneTools.init({ showSVGCursors: true })
|
||||
cornerstoneTools.init()
|
||||
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
|
||||
console.log(cornerstoneTools, 'cornerstoneTools')
|
||||
import DicomTags from './DicomTags'
|
||||
export default {
|
||||
name: 'DicomCanvas',
|
||||
@@ -117,6 +109,12 @@ export default {
|
||||
computed: {
|
||||
NSTip() {
|
||||
return `${this.$store.state.trials.downloadSize}, NS: ${this.$store.state.trials.downloadTip}`
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isComparison: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -130,7 +128,7 @@ export default {
|
||||
seriesNumber: '',
|
||||
imageIds: [],
|
||||
currentImageIdIndex: 0,
|
||||
firstImageLoading: false
|
||||
firstImageLoading: false,
|
||||
// preventCache: true
|
||||
},
|
||||
dicomInfo: {
|
||||
@@ -150,14 +148,15 @@ export default {
|
||||
wwwc: '',
|
||||
zoom: 0,
|
||||
location: '',
|
||||
fps: 5
|
||||
fps: 5,
|
||||
IsMasked: false
|
||||
},
|
||||
toolState: {
|
||||
initialized: false,
|
||||
activeTool: 'none',
|
||||
dicomInfoVisible: false,
|
||||
clipPlaying: false,
|
||||
viewportInvert: false
|
||||
viewportInvert: false,
|
||||
},
|
||||
loadImagePromise: null,
|
||||
AnnotationSync: null,
|
||||
@@ -168,18 +167,25 @@ export default {
|
||||
sliderInfo: {
|
||||
oldB: null,
|
||||
oldM: null,
|
||||
isMove: false
|
||||
isMove: false,
|
||||
},
|
||||
mousePosition: { x: '', y: '', mo: '' },
|
||||
markers: { top: '', right: '', bottom: '', left: '' },
|
||||
orientationMarkers: [],
|
||||
originalMarkers: [],
|
||||
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') }
|
||||
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') },
|
||||
tip: '',
|
||||
IsReadingTaskViewInOrder: 2
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
|
||||
this.type = this.$router.currentRoute.query.type
|
||||
? this.$router.currentRoute.query.type
|
||||
: ''
|
||||
if (this.$router.currentRoute.query.IsReadingTaskViewInOrder) {
|
||||
this.IsReadingTaskViewInOrder = Number(this.$router.currentRoute.query.IsReadingTaskViewInOrder)
|
||||
}
|
||||
this.canvas = this.$refs.canvas
|
||||
this.canvas.addEventListener('cornerstonenewimage', this.onNewImage)
|
||||
this.canvas.addEventListener(
|
||||
@@ -200,17 +206,28 @@ export default {
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
this.sliderMousemove(e)
|
||||
})
|
||||
this.canvas.addEventListener('cornerstonetoolsstackscroll', this.stackScrollCallback)
|
||||
this.canvas.addEventListener(
|
||||
'cornerstonetoolsstackscroll',
|
||||
this.stackScrollCallback
|
||||
)
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadImageStack(dicomSeries) {
|
||||
loadImageStack(dicomSeries, text = '') {
|
||||
this.tip = text
|
||||
this.$nextTick(() => {
|
||||
if (!dicomSeries || !Array.isArray(dicomSeries.imageIds) || dicomSeries.imageIds.length === 0) {
|
||||
return
|
||||
}
|
||||
this.series = dicomSeries
|
||||
this.stack.seriesId = dicomSeries.seriesId
|
||||
this.stack.seriesNumber = dicomSeries.seriesNumber
|
||||
this.stack.imageIds = dicomSeries.imageIds
|
||||
this.stack.currentImageIdIndex = dicomSeries.imageIdIndex && dicomSeries.imageIdIndex < dicomSeries.imageIds.length ? dicomSeries.imageIdIndex : 0
|
||||
this.stack.currentImageIdIndex =
|
||||
dicomSeries.imageIdIndex &&
|
||||
dicomSeries.imageIdIndex < dicomSeries.imageIds.length
|
||||
? dicomSeries.imageIdIndex
|
||||
: 0
|
||||
this.stack.firstImageLoading = true
|
||||
this.stack.description = dicomSeries.description
|
||||
this.toolState.viewportInvert = false
|
||||
@@ -221,18 +238,27 @@ export default {
|
||||
// this.stack.instanceId = instanceId
|
||||
this.toolState.clipPlaying = false
|
||||
const element = this.$refs.canvas
|
||||
if (!isMetaDataProviderAdded) {
|
||||
// 注册自定义 metaDataProvider:统一 SUV 口径(优先接口,缺失回退 DICOM)
|
||||
cornerstone.metaData.addProvider(metaDataProvider, 100000)
|
||||
isMetaDataProviderAdded = true
|
||||
}
|
||||
cornerstone.enable(element)
|
||||
cornerstoneTools.stopClip(this.canvas)
|
||||
this.toolState.clipPlaying = false
|
||||
this.loading = true
|
||||
|
||||
cornerstone.loadAndCacheImage(this.stack.imageIds[this.stack.currentImageIdIndex])
|
||||
.then(image => {
|
||||
cornerstone
|
||||
.loadAndCacheImage(
|
||||
this.stack.imageIds[this.stack.currentImageIdIndex]
|
||||
)
|
||||
.then((image) => {
|
||||
this.loading = false
|
||||
if (this.stack.imageIds.indexOf(image.imageId) !== -1) {
|
||||
this.onFirstImageLoaded(image)
|
||||
}
|
||||
}).catch((error) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false
|
||||
if (error.error && error.error.message) {
|
||||
this.$alert(error.error.message)
|
||||
@@ -255,15 +281,17 @@ export default {
|
||||
const apiTool = cornerstoneTools[`${toolName}Tool`]
|
||||
|
||||
if (apiTool) {
|
||||
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(
|
||||
element,
|
||||
apiTool
|
||||
)
|
||||
const toolAlreadyAddedToElement =
|
||||
cornerstoneTools.getToolForElement(element, apiTool)
|
||||
if (!toolAlreadyAddedToElement) {
|
||||
if (toolName === 'RectangleRoi') {
|
||||
cornerstoneTools.addToolForElement(element, apiTool, { configuration: { showMinMax: true, showStatsText: true } })
|
||||
cornerstoneTools.addToolForElement(element, apiTool, {
|
||||
configuration: { showMinMax: true, showStatsText: true },
|
||||
})
|
||||
} else if (toolName === 'EllipticalRoi') {
|
||||
cornerstoneTools.addToolForElement(element, apiTool, { configuration: { showMinMax: true } })
|
||||
cornerstoneTools.addToolForElement(element, apiTool, {
|
||||
configuration: { showMinMax: true },
|
||||
})
|
||||
} else {
|
||||
cornerstoneTools.addToolForElement(element, apiTool)
|
||||
}
|
||||
@@ -287,8 +315,28 @@ export default {
|
||||
false
|
||||
)
|
||||
})
|
||||
if (!cornerstoneTools.getToolForElement(element, cornerstoneTools.WwwcRegionTool)) {
|
||||
cornerstoneTools.addToolForElement(element, cornerstoneTools.WwwcRegionTool)
|
||||
if (
|
||||
!cornerstoneTools.getToolForElement(element, Note_RectangleRoiTool)
|
||||
) {
|
||||
cornerstoneTools.addToolForElement(element, Note_RectangleRoiTool, {
|
||||
configuration: {
|
||||
color: '#f00',
|
||||
lineWidth: 2,
|
||||
drawHandles: false,
|
||||
fillColor: 'rgba(0, 0, 0, 1)',
|
||||
},
|
||||
})
|
||||
}
|
||||
if (
|
||||
!cornerstoneTools.getToolForElement(
|
||||
element,
|
||||
cornerstoneTools.WwwcRegionTool
|
||||
)
|
||||
) {
|
||||
cornerstoneTools.addToolForElement(
|
||||
element,
|
||||
cornerstoneTools.WwwcRegionTool
|
||||
)
|
||||
}
|
||||
if (
|
||||
!cornerstoneTools.getToolForElement(
|
||||
@@ -347,20 +395,27 @@ export default {
|
||||
// var instanceId = image.imageId.split('/')[image.imageId.split('/').length - 1]
|
||||
// instanceId = instanceId.split('.')[0]
|
||||
// this.stack.instanceId = instanceId
|
||||
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
|
||||
this.height = this.getStackHeightPercent()
|
||||
this.resetWwwc()
|
||||
},
|
||||
onNewImage(e) {
|
||||
e.detail.enabledElement.options = {}
|
||||
var data = e.detail.image.data
|
||||
this.dicomInfo.hospital = data.string('x00080080')
|
||||
// let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === e.detail.image.imageId)
|
||||
let instanceInfo = this.series?.instanceInfoList?.find(item => {
|
||||
let s1 = item.ImageId ? item.ImageId.split("?")[0] : ''
|
||||
let s2 = e.detail.image.imageId ? e.detail.image.imageId.split("?")[0] : ''
|
||||
return s1 === s2
|
||||
})
|
||||
this.dicomInfo.IsMasked = instanceInfo ? instanceInfo.IsMasked : false
|
||||
// this.dicomInfo.pid = data.string('x00100020')
|
||||
this.dicomInfo.pid = data.string('x00120040')
|
||||
this.dicomInfo.name = data.string('x00100010')
|
||||
this.dicomInfo.age = data.string('x00101010')
|
||||
this.dicomInfo.sex = data.string('x00100040')
|
||||
this.dicomInfo.acc = data.string('x00080050') // 登记号
|
||||
this.dicomInfo.modality = data.string('x00080060')
|
||||
this.dicomInfo.modality = (data.string('x00080060') || '').trim()
|
||||
this.dicomInfo.time = this.formatDicomDateTime(
|
||||
data.string('x00080020'),
|
||||
data.string('x00080030')
|
||||
@@ -379,21 +434,32 @@ export default {
|
||||
if (this.dicomInfo.thick) {
|
||||
this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2)
|
||||
}
|
||||
const newImageIdIndex = this.stack.imageIds.findIndex(i => i === e.detail.image.imageId)
|
||||
const newImageIdIndex = this.stack.imageIds.findIndex(
|
||||
(i) => i === e.detail.image.imageId
|
||||
)
|
||||
if (newImageIdIndex === -1) return
|
||||
this.stack.currentImageIdIndex = newImageIdIndex
|
||||
this.stack.imageIdIndex = newImageIdIndex
|
||||
this.series.imageIdIndex = newImageIdIndex
|
||||
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
|
||||
this.resetWwwc()
|
||||
this.height = this.getStackHeightPercent()
|
||||
},
|
||||
getStackHeightPercent() {
|
||||
const imageCount = Array.isArray(this.stack.imageIds) ? this.stack.imageIds.length : 0
|
||||
if (imageCount <= 1) {
|
||||
return 0
|
||||
}
|
||||
return (this.stack.currentImageIdIndex * 100) / (imageCount - 1)
|
||||
},
|
||||
stackScrollCallback(e) {
|
||||
const { detail } = e
|
||||
if (this.isScrollSync) {
|
||||
this.$emit('scrollSync', { canvasIndex: this.canvasIndex, direction: detail.direction })
|
||||
this.$emit('scrollSync', {
|
||||
canvasIndex: this.canvasIndex,
|
||||
direction: detail.direction,
|
||||
})
|
||||
}
|
||||
this.stack.currentImageIdIndex = e.detail.newImageIdIndex
|
||||
this.height = (this.stack.currentImageIdIndex) * 100 / (this.stack.imageIds.length - 1)
|
||||
this.height = this.getStackHeightPercent()
|
||||
// var priority = new Date(new Date().setHours(23, 59, 59, 999)).getTime()
|
||||
|
||||
// requestPoolManager.loadAndCacheImagePlus(this.stack.imageIds[this.stack.currentImageIdIndex], this.stack.seriesId, priority)
|
||||
@@ -408,7 +474,9 @@ export default {
|
||||
if (date) {
|
||||
date = `${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}`
|
||||
}
|
||||
if (time) { time = `${time.substr(0, 2)}:${time.substr(2, 2)}:${time.substr(4, 2)}` }
|
||||
if (time) {
|
||||
time = `${time.substr(0, 2)}:${time.substr(2, 2)}:${time.substr(4, 2)}`
|
||||
}
|
||||
return time ? `${date} ${time}` : `${date} 00:00:00`
|
||||
},
|
||||
|
||||
@@ -453,7 +521,7 @@ export default {
|
||||
top: oppositeColumn,
|
||||
bottom: column,
|
||||
left: oppositeRow,
|
||||
right: row
|
||||
right: row,
|
||||
}
|
||||
if (!markers) {
|
||||
return
|
||||
@@ -500,13 +568,7 @@ export default {
|
||||
if (image.color) {
|
||||
stats.storedPixels = this.getRGBPixels(element, x, y, 1, 1)
|
||||
} else {
|
||||
stats.storedPixels = cornerstone.getStoredPixels(
|
||||
element,
|
||||
x,
|
||||
y,
|
||||
1,
|
||||
1
|
||||
)
|
||||
stats.storedPixels = cornerstone.getStoredPixels(element, x, y, 1, 1)
|
||||
stats.sp = stats.storedPixels[0]
|
||||
stats.mo = stats.sp * image.slope + image.intercept
|
||||
stats.suv = calculateSUV(image, stats.sp)
|
||||
@@ -533,7 +595,8 @@ export default {
|
||||
if (enabledElement.image.color) {
|
||||
for (row = 0; row < height; row++) {
|
||||
for (column = 0; column < width; column++) {
|
||||
spIndex = ((row + y) * enabledElement.image.columns + (column + x)) * 4
|
||||
spIndex =
|
||||
((row + y) * enabledElement.image.columns + (column + x)) * 4
|
||||
const red = pixelData[spIndex]
|
||||
const green = pixelData[spIndex + 1]
|
||||
const blue = pixelData[spIndex + 2]
|
||||
@@ -551,7 +614,8 @@ export default {
|
||||
},
|
||||
sliderMousedown(e) {
|
||||
var boxHeight = this.$refs['sliderBox'].clientHeight
|
||||
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
|
||||
this.sliderInfo.oldB =
|
||||
(parseInt(e.srcElement.style.top) * boxHeight) / 100
|
||||
this.sliderInfo.oldM = e.clientY
|
||||
this.sliderInfo.isMove = true
|
||||
e.stopImmediatePropagation()
|
||||
@@ -564,9 +628,14 @@ export default {
|
||||
var boxHeight = this.$refs['sliderBox'].clientHeight
|
||||
if (PX < 0) return
|
||||
if (PX > boxHeight) return
|
||||
var height = PX * 100 / boxHeight
|
||||
var index = Math.trunc(this.stack.imageIds.length * this.height / 100)
|
||||
index = index > this.stack.imageIds.length ? this.stack.imageIds.length : index < 0 ? 0 : index
|
||||
var height = (PX * 100) / boxHeight
|
||||
var index = Math.trunc((this.stack.imageIds.length * this.height) / 100)
|
||||
index =
|
||||
index > this.stack.imageIds.length
|
||||
? this.stack.imageIds.length
|
||||
: index < 0
|
||||
? 0
|
||||
: index
|
||||
// if (!cornerstone.imageCache.getImageLoadObject(this.stack.imageIds[index])) return
|
||||
this.height = height
|
||||
if (this.stack.currentImageIdIndex !== index) {
|
||||
@@ -578,9 +647,9 @@ export default {
|
||||
},
|
||||
goViewer(e) {
|
||||
// console.log(this.$refs['sliderBox'].clientHeight)
|
||||
var height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
|
||||
var height = (e.offsetY * 100) / this.$refs['sliderBox'].clientHeight
|
||||
this.height = height
|
||||
var index = Math.trunc(this.stack.imageIds.length * this.height / 100)
|
||||
var index = Math.trunc((this.stack.imageIds.length * this.height) / 100)
|
||||
scroll(this.canvas, index)
|
||||
},
|
||||
onClipStopped() {
|
||||
@@ -673,10 +742,7 @@ export default {
|
||||
}
|
||||
this.toolState.clipPlaying = true
|
||||
cornerstoneTools.playClip(this.canvas, this.dicomInfo.fps)
|
||||
cornerstoneTools.getToolState(
|
||||
this.canvas,
|
||||
'playClip'
|
||||
).data[0].loop = true
|
||||
cornerstoneTools.getToolState(this.canvas, 'playClip').data[0].loop = true
|
||||
},
|
||||
setFps(fps) {
|
||||
this.dicomInfo.fps = fps
|
||||
@@ -687,6 +753,7 @@ export default {
|
||||
var viewport = cornerstone.getViewport(this.canvas)
|
||||
// viewport.invert = false
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
if (!viewport || !image) return
|
||||
viewport.voi.windowWidth = image.windowWidth
|
||||
viewport.voi.windowCenter = image.windowCenter
|
||||
cornerstone.setViewport(this.canvas, viewport)
|
||||
@@ -712,8 +779,8 @@ export default {
|
||||
invert: false,
|
||||
preventZoomOutsideImage: false,
|
||||
minScale: 0.1,
|
||||
maxScale: 20.0
|
||||
}
|
||||
maxScale: 20.0,
|
||||
},
|
||||
})
|
||||
cornerstoneTools.setToolActive('Zoom', { mouseButtonMask: 1 })
|
||||
this.toolState.activeTool = 'zoom'
|
||||
@@ -797,9 +864,120 @@ export default {
|
||||
setToolPassive(toolName) {
|
||||
cornerstoneTools.setToolPassiveForElement(this.canvas, toolName)
|
||||
},
|
||||
async reloadImage(newImageId = null) {
|
||||
// 1. 获取当前imageId(如果未指定新imageId)
|
||||
let element = this.canvas
|
||||
this.stack.imageIds.splice(this.stack.currentImageIdIndex, 1, newImageId)
|
||||
const currentImageId =
|
||||
newImageId || cornerstone.getImage(element)?.imageId
|
||||
|
||||
if (!currentImageId) {
|
||||
console.error('没有找到可用的imageId')
|
||||
return
|
||||
}
|
||||
|
||||
// 2. 清除该影像关联的工具状态(标注数据)
|
||||
this.clearToolStateForImage(element, currentImageId)
|
||||
|
||||
// 3. 从缓存中移除该影像
|
||||
this.removeImageFromCache(currentImageId)
|
||||
|
||||
// 4. 重新加载并渲染
|
||||
await this.loadAndRenderImage(element, currentImageId)
|
||||
},
|
||||
clearToolStateForImage(element, imageId) {
|
||||
// 获取全局状态管理器
|
||||
const globalToolStateManager =
|
||||
cornerstoneTools.globalImageIdSpecificToolStateManager
|
||||
|
||||
if (globalToolStateManager) {
|
||||
// 方式1:清空该影像的全部工具数据
|
||||
globalToolStateManager.clearImageIdToolState(imageId)
|
||||
console.log(`已清除影像 ${imageId} 的所有标注数据`)
|
||||
}
|
||||
|
||||
// 方式2:如果使用元素级别的状态管理器
|
||||
const elementToolStateManager =
|
||||
cornerstoneTools.getElementToolStateManager(element)
|
||||
if (elementToolStateManager && elementToolStateManager.get(element)) {
|
||||
// 清空该元素上当前显示影像的数据
|
||||
elementToolStateManager.clear(element)
|
||||
}
|
||||
},
|
||||
removeImageFromCache(imageId) {
|
||||
const imageCache = cornerstone.imageCache
|
||||
|
||||
if (imageCache && imageCache[imageId]) {
|
||||
// 从缓存中移除
|
||||
delete imageCache[imageId]
|
||||
console.log(`已从缓存中移除影像: ${imageId}`)
|
||||
}
|
||||
|
||||
// 也可以使用官方API(如果可用)
|
||||
if (typeof cornerstone.imageCache.removeImage === 'function') {
|
||||
cornerstone.imageCache.removeImageLoadObject(imageId)
|
||||
}
|
||||
},
|
||||
async loadAndRenderImage(element, imageId) {
|
||||
try {
|
||||
// 1. 清除当前画布内容(可选)
|
||||
const canvas = element.querySelector('canvas')
|
||||
if (canvas) {
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
}
|
||||
|
||||
// 2. 重新加载图像(强制从源头重新获取)
|
||||
const image = await cornerstone.loadAndCacheImage(imageId)
|
||||
|
||||
// 3. 获取或创建视口设置
|
||||
let viewport = cornerstone.getViewport(element)
|
||||
if (!viewport) {
|
||||
viewport = cornerstone.getDefaultViewport(element, image)
|
||||
}
|
||||
|
||||
// 4. 显示图像
|
||||
cornerstone.displayImage(element, image, viewport)
|
||||
|
||||
// 5. 触发重绘
|
||||
cornerstone.updateImage(element)
|
||||
|
||||
console.log(`影像 ${imageId} 重新加载并渲染完成`)
|
||||
|
||||
return image
|
||||
} catch (error) {
|
||||
console.error('加载图像失败:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
getNote_RectangleRoi() {
|
||||
return new Promise(resolve => {
|
||||
let toolInfo = cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi')
|
||||
let image = cornerstone.getImage(this.canvas)
|
||||
resolve({ toolInfo, image })
|
||||
})
|
||||
// console.log(
|
||||
// cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi')
|
||||
// )
|
||||
// console.log(cornerstone.getImage(this.canvas))
|
||||
// let image = cornerstone.getImage(this.canvas)
|
||||
// // cornerstone.imageCache.removeImageLoadObject(image.imageId)
|
||||
|
||||
// this.reloadImage(this.canvas, image.imageId)
|
||||
},
|
||||
removeNote_RectangleRoi() {
|
||||
const toolState = cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi');
|
||||
if (toolState && toolState.data.length > 0) {
|
||||
let arr = toolState.data.map(item => item)
|
||||
arr.forEach(item => {
|
||||
cornerstoneTools.removeToolState(this.canvas, 'Note_RectangleRoi', item);
|
||||
})
|
||||
cornerstone.updateImage(this.canvas);
|
||||
}
|
||||
},
|
||||
setToolActive(toolName) {
|
||||
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
|
||||
mouseButtonMask: 1
|
||||
mouseButtonMask: 1,
|
||||
})
|
||||
},
|
||||
setAllToolsPassive() {
|
||||
@@ -833,7 +1011,7 @@ export default {
|
||||
)
|
||||
}
|
||||
cornerstoneTools.setToolEnabledForElement(this.canvas, 'ReferenceLines', {
|
||||
synchronizationContext: synchronizer
|
||||
synchronizationContext: synchronizer,
|
||||
})
|
||||
|
||||
// cornerstoneTools.addTool(cornerstoneTools.CrosshairsTool)
|
||||
@@ -864,7 +1042,7 @@ export default {
|
||||
}
|
||||
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
|
||||
mouseButtonMask: 1,
|
||||
synchronizationContext: synchronizer
|
||||
synchronizationContext: synchronizer,
|
||||
})
|
||||
},
|
||||
disabledViewPortToolSync(synchronizer, toolName) {
|
||||
@@ -1095,7 +1273,7 @@ export default {
|
||||
'CobbAngle',
|
||||
'Angle',
|
||||
'Bidirectional',
|
||||
'FreehandRoi'
|
||||
'FreehandRoi',
|
||||
]
|
||||
for (let i = 0; i < toolROITypes.length; i++) {
|
||||
const toolROIType = toolROITypes[i]
|
||||
@@ -1115,12 +1293,12 @@ export default {
|
||||
removeLabel(item) {
|
||||
const promise = scroll(this.canvas, item.data.imageIdIndex)
|
||||
const scope = this
|
||||
Promise.all([promise]).then(res => {
|
||||
Promise.all([promise]).then((res) => {
|
||||
cornerstoneTools.removeToolState(scope.canvas, item.type, item.data)
|
||||
cornerstone.updateImage(scope.canvas)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ export default {
|
||||
TrialConfig: {},
|
||||
TrialStatusStr: null,
|
||||
trialId: null,
|
||||
IsAdditionalAssessment: false
|
||||
IsAdditionalAssessment: false,
|
||||
isReload: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -71,17 +72,23 @@ export default {
|
||||
if (~url.indexOf('?')) {
|
||||
query = url.split('?')[1]
|
||||
}
|
||||
zzSessionStorage.setItem('lastWorkbench', `${v.path}${query ? '?' : ''}${query}`)
|
||||
if (!this.isReload) {
|
||||
zzSessionStorage.setItem('lastWorkbench', `${v.path}${query ? '?' : ''}${query}`)
|
||||
} else {
|
||||
this.isReload = false
|
||||
}
|
||||
var firstGoIn = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children[0]
|
||||
if (this.trialsTab === '/trials/trials-panel') {
|
||||
this.$router.replace({ path: `${firstGoIn.path}${query ? '?' : ''}${query}` })
|
||||
var targetPath = firstGoIn.path
|
||||
if (firstGoIn.children && firstGoIn.children.length > 0) {
|
||||
this.$router.replace({ path: `${firstGoIn.children[0].path}${query ? '?' : ''}${query}` })
|
||||
targetPath = firstGoIn.children[0].path
|
||||
}
|
||||
this.$router.replace({ path: `${targetPath}${query ? '?' : ''}${query}` })
|
||||
}
|
||||
// document.cookie = 'TrialId=' + this.$route.query.trialId + ';path=/'
|
||||
},
|
||||
trialId(v) {
|
||||
if (!this.$route.query.trialId) return
|
||||
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
||||
var total = res.OtherInfo.NeedSignCount
|
||||
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
||||
@@ -94,28 +101,34 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$EventBus.$on("reload", () => {
|
||||
this.isReload = true
|
||||
})
|
||||
var query = ``
|
||||
var url = window.location.href
|
||||
if (~url.indexOf('?')) {
|
||||
query = url.split('?')[1]
|
||||
}
|
||||
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
||||
var total = res.OtherInfo.NeedSignCount
|
||||
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
||||
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
|
||||
this.TrialStatusStr = TrialStatusStr
|
||||
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
|
||||
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
|
||||
this.TrialConfig = res.OtherInfo.TrialConfig
|
||||
})
|
||||
if (this.$route.query.trialId) {
|
||||
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
||||
var total = res.OtherInfo.NeedSignCount
|
||||
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
||||
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
|
||||
this.TrialStatusStr = TrialStatusStr
|
||||
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
|
||||
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
|
||||
this.TrialConfig = res.OtherInfo.TrialConfig
|
||||
})
|
||||
}
|
||||
this.selectedTab()
|
||||
this.getTrialList()
|
||||
var firstGoIn = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children[0]
|
||||
if (this.trialsTab === '/trials/trials-panel') {
|
||||
this.$router.replace({ path: `${firstGoIn.path}${query ? '?' : ''}${query}` })
|
||||
var targetPath = firstGoIn.path
|
||||
if (firstGoIn.children && firstGoIn.children.length > 0) {
|
||||
this.$router.replace({ path: `${firstGoIn.children[0].path}${query ? '?' : ''}${query}` })
|
||||
targetPath = firstGoIn.children[0].path
|
||||
}
|
||||
this.$router.replace({ path: `${targetPath}${query ? '?' : ''}${query}` })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -130,6 +143,9 @@ export default {
|
||||
let chartList = [
|
||||
'/trials/trials-panel/trial-summary/report-forms'
|
||||
]
|
||||
let dataSyncList = [
|
||||
`/trials/trials-panel/trial-summary/data-sync`
|
||||
]
|
||||
var qualityList = [
|
||||
'/trials/trials-panel/visit/crc-question',
|
||||
'/trials/trials-panel/visit/qc-check',
|
||||
@@ -145,6 +161,9 @@ export default {
|
||||
'/trials/trials-panel/trial-summary/image-inspect',
|
||||
'/trials/trials-panel/trial-summary/push-record',
|
||||
]
|
||||
if (this.$store.state.trials.config.TrialDataStoreType !== 1 && ~dataSyncList.indexOf(path)) {
|
||||
isShow = false
|
||||
}
|
||||
if (!this.$store.state.trials.config.IsExternalViewTrialChart && ~chartList.indexOf(path) && this.hasPermi(['role:cmm', 'role:cpm', 'role:ea', 'role:mc', 'role:smm', 'role:spm'])) {
|
||||
isShow = false
|
||||
}
|
||||
@@ -201,15 +220,19 @@ export default {
|
||||
if (~url.indexOf('?')) {
|
||||
query = url.split('?')[1]
|
||||
}
|
||||
this.$router.push({ path: `${v.name}${query ? '?' : ''}${query}` })
|
||||
var trialsPanelList = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children
|
||||
var isHasChild = trialsPanelList.find(c => { return c.path === v.name }) && trialsPanelList.find(c => { return c.path === v.name }).children
|
||||
if (trialsPanelList.find(c => { return c.path === v.name }) && trialsPanelList.find(c => { return c.path === v.name }).tabHiddn) {
|
||||
var trialsPanelList = this.trialsRouter.children.find(item => { return item.name === 'TrialsPanel' }).children
|
||||
var currentRoute = trialsPanelList.find(c => { return c.path === v.name })
|
||||
|
||||
if (currentRoute && currentRoute.tabHiddn) {
|
||||
this.$router.push({ path: `${v.name}${query ? '?' : ''}${query}` })
|
||||
return
|
||||
}
|
||||
var isHasChild = currentRoute && currentRoute.children
|
||||
if (isHasChild && isHasChild.length > 0) {
|
||||
this.trialsTabChild = isHasChild[0].path
|
||||
this.$router.push({ path: `${this.trialsTabChild}${query ? '?' : ''}${query}` })
|
||||
} else {
|
||||
this.$router.push({ path: `${v.name}${query ? '?' : ''}${query}` })
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<el-table-column type="index" width="40" />
|
||||
<!--受试者-->
|
||||
<el-table-column :label="$t('download:table:subjectCode')" min-width="130" prop="SubjectCode"
|
||||
show-overflow-tooltip />
|
||||
show-overflow-tooltip v-if="isReadingTaskViewInOrder !== 0" />
|
||||
<!--访视名称-->
|
||||
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" sortable v-if="IsImageSegment" />
|
||||
<!--任务名称-->
|
||||
@@ -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')"
|
||||
@@ -78,7 +78,7 @@
|
||||
</el-table>
|
||||
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :modelList="modelList" :bodyPart="bodyPart"
|
||||
:subjectVisitId="modelSubjectVisitId" :IsDicom="IsDicom" :isDownload="true" :visitTaskId="modelTaskId"
|
||||
:IsImageSegment="IsImageSegment" :Criterion="Criterion" />
|
||||
:IsImageSegment="IsImageSegment" :Criterion="Criterion" :IsReadingTaskViewInOrder="isReadingTaskViewInOrder" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
@@ -111,6 +111,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
SubjectId: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -132,7 +136,11 @@ export default {
|
||||
IsImageSegment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
isReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -166,6 +174,7 @@ export default {
|
||||
this.getList()
|
||||
this.title = `Download Images:${this.SubjectCode}(${this.Criterion.TrialReadingCriterionName})`
|
||||
if (this.IsImageSegment) this.title = `Download Images:${this.SubjectCode}`
|
||||
if (this.isReadingTaskViewInOrder === 0) this.title = ''
|
||||
},
|
||||
beforeDestroy() {
|
||||
store.dispatch('trials/setUnLock', false)
|
||||
@@ -443,6 +452,9 @@ export default {
|
||||
if (this.IsImageSegment) {
|
||||
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.VisitName}`
|
||||
}
|
||||
if (this.isReadingTaskViewInOrder === 0) {
|
||||
this.model_cfg.title = ''
|
||||
}
|
||||
if (item.IsDicom) {
|
||||
this.modelList = item.DicomStudyList
|
||||
} else {
|
||||
@@ -484,11 +496,11 @@ export default {
|
||||
let routeData = null
|
||||
if (!this.IsImageSegment && (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20)) {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
} else {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
}
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
@@ -501,7 +513,7 @@ export default {
|
||||
var token = getToken()
|
||||
let trialId = this.$route.query.trialId
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showvisitdicoms?page=download&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
|
||||
path: `/showvisitdicoms?page=download&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
},
|
||||
|
||||
@@ -2,36 +2,21 @@
|
||||
<!--FEEDBACK-->
|
||||
<div v-if="visible" @click.stop="() => false" class="feedBack-box">
|
||||
<div class="feedBack-box-modal"></div>
|
||||
<el-dialog
|
||||
:visible.sync="visible"
|
||||
v-dialogDrag
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
@close="cancel"
|
||||
:modal="false"
|
||||
>
|
||||
<el-dialog :visible.sync="visible" v-dialogDrag width="800px" :close-on-click-modal="false" @close="cancel"
|
||||
:modal="false">
|
||||
<div slot="title">
|
||||
{{ title }}
|
||||
</div>
|
||||
<!-- 项目详情 -->
|
||||
<div class="trialsBox" v-if="visitTaskId || SubjectVisitId">
|
||||
<el-form
|
||||
label-position="right"
|
||||
:model="form"
|
||||
:inline="true"
|
||||
class="trialsForm"
|
||||
v-if="type === 'detail'"
|
||||
>
|
||||
<el-form label-position="right" :model="form" :inline="true" class="trialsForm" v-if="type === 'detail'">
|
||||
<el-form-item :label="$t('feedBack:trials:code')" style="width: 40%">
|
||||
<span>{{ form.TrialCode }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('feedBack:trials:name')" style="width: 40%">
|
||||
<span>{{ form.ExperimentName }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('feedBack:trials:siteCode')"
|
||||
style="width: 40%"
|
||||
>
|
||||
<el-form-item :label="$t('feedBack:trials:siteCode')" style="width: 40%">
|
||||
<span>{{ form.TrialSiteCode }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('feedBack:trials:visit')" style="width: 40%">
|
||||
@@ -39,47 +24,21 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-form
|
||||
ref="feedBackForm"
|
||||
label-position="right"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form ref="feedBackForm" label-position="right" :model="form" :rules="rules" label-width="100px">
|
||||
<!-- 影像异常tip -->
|
||||
<p class="tip" v-if="type === 'imgfail'">
|
||||
<i
|
||||
class="el-icon-warning-outline"
|
||||
style="color: #f56c6c; font-size: 24px"
|
||||
></i>
|
||||
<i class="el-icon-warning-outline" style="color: #f56c6c; font-size: 24px"></i>
|
||||
<span>{{ $t('feedBack:imgfail:tip') }}</span>
|
||||
</p>
|
||||
<!-- 问题反馈 -->
|
||||
<el-form-item
|
||||
:label="$t('feedBack:form:feedBack')"
|
||||
prop="QuestionType"
|
||||
v-if="type === 'feedback' && trialId"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.QuestionType"
|
||||
style="width: 100%"
|
||||
popper-class="feedBack-select-box"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in QuestionTypeOptions"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
<el-form-item :label="$t('feedBack:form:feedBack')" prop="QuestionType" v-if="type === 'feedback' && trialId">
|
||||
<el-select v-model="form.QuestionType" style="width: 100%" popper-class="feedBack-select-box">
|
||||
<el-option v-for="item in QuestionTypeOptions" :key="item.id" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 问题反馈 -->
|
||||
<el-form-item
|
||||
:label="$t('feedBack:form:feedBack')"
|
||||
prop="QuestionType"
|
||||
v-if="type === 'detail'"
|
||||
>
|
||||
<el-form-item :label="$t('feedBack:form:feedBack')" prop="QuestionType" v-if="type === 'detail'">
|
||||
<span>{{
|
||||
QuestionTypeOptions.filter(
|
||||
(item) => item.value === form.QuestionType
|
||||
@@ -87,43 +46,22 @@
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
<!-- 问题描述 -->
|
||||
<el-form-item
|
||||
:label="$t('feedBack:form:description')"
|
||||
prop="QuestionDescription"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.QuestionDescription"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:maxlength="500"
|
||||
:disabled="type === 'detail'"
|
||||
/>
|
||||
<el-form-item :label="$t('feedBack:form:description')" prop="QuestionDescription">
|
||||
<el-input v-model="form.QuestionDescription" type="textarea" :rows="4" :maxlength="500"
|
||||
:disabled="type === 'detail'" />
|
||||
</el-form-item>
|
||||
<!-- 截图 -->
|
||||
<el-form-item :label="$t('feedBack:form:screenshot')" prop="screenshot">
|
||||
<uploadImage
|
||||
:path.sync="form.ScreenshotList"
|
||||
:isUpload.sync="loading"
|
||||
:trialId="trialId"
|
||||
:disabled="type === 'detail'"
|
||||
ref="uploadImage"
|
||||
/>
|
||||
<uploadImage :path.sync="form.ScreenshotList" :isUpload.sync="loading" :trialId="trialId"
|
||||
:disabled="type === 'detail'" ref="uploadImage" />
|
||||
</el-form-item>
|
||||
<!-- 反馈时间 -->
|
||||
<el-form-item
|
||||
:label="$t('feedBack:form:time')"
|
||||
prop="screenshot"
|
||||
v-if="type === 'detail'"
|
||||
>
|
||||
<el-form-item :label="$t('feedBack:form:time')" prop="screenshot" v-if="type === 'detail'">
|
||||
<span>{{ form.CreateTime }}</span>
|
||||
</el-form-item>
|
||||
<!-- 状态 -->
|
||||
<el-form-item
|
||||
:label="$t('feedBack:form:status')"
|
||||
prop="screenshot"
|
||||
v-if="type === 'detail' && level > 7"
|
||||
>
|
||||
<el-switch
|
||||
<el-form-item :label="$t('feedBack:form:status')" prop="screenshot" v-if="type === 'detail' && level >= 7">
|
||||
<!-- <el-switch
|
||||
v-model="form.State"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
@@ -134,21 +72,27 @@
|
||||
:disabled="level < 8 || !isStateChange"
|
||||
@change="changeState"
|
||||
>
|
||||
</el-switch>
|
||||
</el-switch> -->
|
||||
<el-select v-model="form.State" :popper-append-to-body="false" :disabled="level < 8">
|
||||
<el-option v-for="item in $d.FeedBackStatus" :key="item.id" :label="item.label"
|
||||
:value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 无法解决原因 -->
|
||||
<el-form-item :label="$t('feedBack:form:Reason')" prop="Reason"
|
||||
v-if="type === 'detail' && level >= 7 && form.State === 2">
|
||||
<el-input v-model="form.Reason" type="textarea" :rows="4" :maxlength="500" :disabled="level < 8" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" v-if="type !== 'detail' || isImgfail">
|
||||
<!--type !== 'detail'-->
|
||||
<div slot="footer" v-if="level >= 7 || isImgfail">
|
||||
<!-- 取消 -->
|
||||
<el-button size="small" @click.stop="cancel">
|
||||
<el-button size="small" @click.stop="cancel" v-if="type !== 'detail' || level >= 8">
|
||||
{{ $t('feedBack:button:cancel') }}
|
||||
</el-button>
|
||||
<!-- 保存 -->
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="save"
|
||||
:loading="loading"
|
||||
>
|
||||
<el-button type="primary" size="small" @click.stop="save" :loading="loading"
|
||||
v-if="type !== 'detail' || level >= 8">
|
||||
{{ $t('feedBack:button:save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -190,6 +134,7 @@ export default {
|
||||
SubjectVisitId: null,
|
||||
ScreenshotList: [],
|
||||
ScreenshotListStr: null,
|
||||
Reason: null
|
||||
},
|
||||
rules: {
|
||||
QuestionType: [
|
||||
@@ -307,6 +252,7 @@ export default {
|
||||
// 修改状态
|
||||
async changeState() {
|
||||
if (this.isImgfail) return
|
||||
if (this.form.State !== 1 && this.form.State !== 0) return false
|
||||
try {
|
||||
let data = {
|
||||
IdList: [this.Id],
|
||||
@@ -381,6 +327,10 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep.el-popper {
|
||||
z-index: 4000 !important;
|
||||
}
|
||||
|
||||
.tip {
|
||||
width: 86%;
|
||||
margin: auto;
|
||||
@@ -389,12 +339,14 @@ export default {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// border-radius: 5px;
|
||||
// background-color: #eee;
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.trialsBox {
|
||||
margin: auto;
|
||||
margin-bottom: 20px;
|
||||
@@ -405,11 +357,13 @@ export default {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.trialsForm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -8,20 +8,49 @@
|
||||
|
||||
<script>
|
||||
import { getReportsChartData } from "@/api/reading"
|
||||
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: {
|
||||
@@ -33,7 +62,8 @@ export default {
|
||||
zIndex: 9,
|
||||
chart: null,
|
||||
loading: false,
|
||||
key: 'readingChart'
|
||||
key: 'readingChart',
|
||||
isInteger: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -72,12 +102,13 @@ export default {
|
||||
let res = await getReportsChartData(params)
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.isInteger = res.Result.Type === 'number' && res.Result.ValueType === 0
|
||||
let LatestScanDateList = res.Result.LatestScanDateList.map(item => item.split(" ")[0])
|
||||
let obj = {
|
||||
title: QuestionName,
|
||||
xAxisData: LatestScanDateList || [],
|
||||
series: [],
|
||||
unit: this.$fd("ValueUnit", res.Result.Unit),
|
||||
unit: res.Result.Unit === 0 ? '' : res.Result.Unit === 4 ? res.Result.CustomUnit : this.$fd("ValueUnit", res.Result.Unit),
|
||||
visitName: res.Result.VisitTaskNameList,
|
||||
min: null,
|
||||
max: null
|
||||
@@ -94,43 +125,6 @@ export default {
|
||||
type: 'line'
|
||||
})
|
||||
});
|
||||
// if (Array.isArray(res.Result.LatestScanDateList) && res.Result.LatestScanDateList.length >= 2) {
|
||||
// let hours = moment(res.Result.LatestScanDateList[res.Result.LatestScanDateList.length - 1]).diff(moment(res.Result.LatestScanDateList[0]), 'hours');
|
||||
// let days = moment(res.Result.LatestScanDateList[res.Result.LatestScanDateList.length - 1]).diff(moment(res.Result.LatestScanDateList[0]), 'days');
|
||||
// let months = moment(res.Result.LatestScanDateList[res.Result.LatestScanDateList.length - 1]).diff(moment(res.Result.LatestScanDateList[0]), 'months');
|
||||
// console.log(hours, 'hours')
|
||||
// console.log(days, 'days')
|
||||
// console.log(months, 'months')
|
||||
// if (hours < 24) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[0]).format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// if (days >= 1 && days <= 7) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[0]).add(7, 'days').format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// if (days > 7 && days < 30) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).startOf('month').format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[0]).endOf('month').format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// if (months >= 1 && months <= 3) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).startOf('month').format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[0]).add(4, 'months').startOf('month').format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// if (months > 3 && months <= 6) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).startOf('month').format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[0]).add(7, 'months').startOf('month').format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// if (months > 6 && months <= 12) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).startOf('month').format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[0]).add(13, 'months').startOf('month').format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// if (months > 12) {
|
||||
// obj.min = moment(res.Result.LatestScanDateList[0]).startOf('month').format('YYYY-MM-DD') + ' 00:00:00'
|
||||
// obj.max = moment(res.Result.LatestScanDateList[res.Result.LatestScanDateList.length - 1]).add(1, 'months').startOf('month').format('YYYY-MM-DD') + ' 23:59:59'
|
||||
// }
|
||||
// }
|
||||
// console.log(obj)
|
||||
this.initChart(obj)
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -151,7 +145,13 @@ export default {
|
||||
text: obj.title,
|
||||
textStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
grid: {
|
||||
left: 50,
|
||||
bottom: 30
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
@@ -193,6 +193,7 @@ export default {
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
}
|
||||
@@ -200,6 +201,9 @@ export default {
|
||||
},
|
||||
series: obj.series
|
||||
};
|
||||
if (this.isInteger) {
|
||||
option.yAxis.minInterval = 1
|
||||
}
|
||||
// 4. 使用配置项渲染图表
|
||||
this.chart.setOption(option);
|
||||
},
|
||||
|
||||
@@ -116,7 +116,7 @@ export default {
|
||||
display: none !important; /* 隐藏原生 radio 输入,但仍然允许交互 */
|
||||
}
|
||||
|
||||
::v-deep.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled)
|
||||
::v-deep .el-radio:focus:not(.is-focus):not(:active):not(.is-disabled)
|
||||
.el-radio__inner {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
<!--检查列表-->
|
||||
<el-table :data="list" style="width: 100%" height="300" :loading="loading">
|
||||
<!--受试者-->
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" sortable />
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" sortable
|
||||
v-if="isReadingTaskViewInOrder !== 0" />
|
||||
<!--访视名称-->
|
||||
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" v-if="IsImageSegment" sortable />
|
||||
<!--任务名称-->
|
||||
@@ -42,7 +43,7 @@
|
||||
<template slot-scope="scope">
|
||||
<div class="btnBox">
|
||||
<!--上传--->
|
||||
<form id="inputForm" :ref="`uploadForm_${scope.row.Id}`" enctype="multipart/form-data">
|
||||
<form id="inputForm" :ref="`uploadForm_${scope.row.Id}`" enctype="multipart/form-data" v-if="!forbid">
|
||||
<div class="form-group" style="margin-right: 10px">
|
||||
<div :id="`directoryInputWrapper_${scope.row.Id}`" class="btn btn-link file-input">
|
||||
<el-button circle icon="el-icon-upload2" :disabled="btnLoading" :loading="btnLoading"
|
||||
@@ -69,17 +70,14 @@
|
||||
</el-table>
|
||||
<div style="margin: 10px 0" class="top">
|
||||
<span>{{ $t('upload:dicom:uploadTitle') }}</span>
|
||||
<div class="btnBox">
|
||||
<span style="margin-right: 10px">
|
||||
{{ $store.state.trials.uploadTip }}
|
||||
</span>
|
||||
<div class="btnBox" v-if="!forbid">
|
||||
<span style="margin-right: 10px">{{ $store.state.trials.uploadTip }}</span>
|
||||
<form id="inputForm" ref="uploadForm" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<div id="directoryInputWrapper" class="btn btn-link file-input">
|
||||
<el-button type="primary" :disabled="btnLoading" :loading="btnLoading" size="mini">
|
||||
{{ $t('upload:dicom:button:batchUpload') }}
|
||||
</el-button>
|
||||
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title=""
|
||||
<el-button type="primary" :disabled="btnLoading" :loading="btnLoading" size="mini">{{
|
||||
$t('upload:dicom:button:batchUpload') }}</el-button>
|
||||
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title
|
||||
@change="beginScanFiles($event)" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,8 +92,10 @@
|
||||
<template slot="header">
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">
|
||||
{{ $t('trials:uploadDicomList:table:studyDetail1') }}<br />
|
||||
{{ $t('trials:uploadDicomList:table:studyDetail2') }}<br />
|
||||
{{ $t('trials:uploadDicomList:table:studyDetail1') }}
|
||||
<br />
|
||||
{{ $t('trials:uploadDicomList:table:studyDetail2') }}
|
||||
<br />
|
||||
{{ $t('trials:uploadedDicoms:table:studyDate') }}
|
||||
</div>
|
||||
<span>{{ $t('trials:uploadDicomList:table:studyInfo') }}</span>
|
||||
@@ -105,13 +105,15 @@
|
||||
<div style="line-height: 15px">
|
||||
<div>
|
||||
<div>
|
||||
<span v-if="scope.row.dicomInfo.accNumber"><span style="font-weight: 500">Acc:</span>
|
||||
{{ scope.row.dicomInfo.accNumber }}</span>
|
||||
<span v-if="scope.row.dicomInfo.accNumber">
|
||||
<span style="font-weight: 500">Acc:</span>
|
||||
{{ scope.row.dicomInfo.accNumber }}
|
||||
</span>
|
||||
<span v-else style="color: #f44336">N/A</span>
|
||||
</div>
|
||||
<div style="display: inline-block; margin-right: 2px">
|
||||
<span v-if="scope.row.dicomInfo.modality.length > 0">
|
||||
{{ scope.row.dicomInfo.modality.join('、') }},</span>
|
||||
<span v-if="scope.row.dicomInfo.modality.length > 0">{{ scope.row.dicomInfo.modality.join('、')
|
||||
}},</span>
|
||||
<span v-else style="color: #f44336">N/A,</span>
|
||||
</div>
|
||||
<div style="display: inline-block; margin-right: 2px">
|
||||
@@ -126,20 +128,15 @@
|
||||
|
||||
<div>
|
||||
<div style="display: inline-block; margin-right: 2px">
|
||||
<span v-if="scope.row.dicomInfo.bodyPart">
|
||||
{{ scope.row.dicomInfo.bodyPart }},
|
||||
</span>
|
||||
<span v-else style="color: #f44336">N/A, </span>
|
||||
<span v-if="scope.row.dicomInfo.bodyPart">{{ scope.row.dicomInfo.bodyPart }},</span>
|
||||
<span v-else style="color: #f44336">N/A,</span>
|
||||
</div>
|
||||
<div style="display: inline-block">
|
||||
<span v-if="scope.row.dicomInfo.description">
|
||||
{{ scope.row.dicomInfo.description }}</span>
|
||||
<span v-if="scope.row.dicomInfo.description">{{ scope.row.dicomInfo.description }}</span>
|
||||
<span v-else style="color: #f44336">N/A</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ scope.row.dicomInfo.studyTime }}
|
||||
</div>
|
||||
<div>{{ scope.row.dicomInfo.studyTime }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -147,8 +144,10 @@
|
||||
<template slot="header">
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">
|
||||
{{ $t('trials:uploadDicomList:table:pId') }}<br />
|
||||
{{ $t('trials:uploadDicomList:table:patientName') }}<br />
|
||||
{{ $t('trials:uploadDicomList:table:pId') }}
|
||||
<br />
|
||||
{{ $t('trials:uploadDicomList:table:patientName') }}
|
||||
<br />
|
||||
{{ $t('trials:uploadDicomList:table:pInfo') }}
|
||||
</div>
|
||||
<span>{{ $t('trials:uploadDicomList:table:patientInfo') }}</span>
|
||||
@@ -157,8 +156,11 @@
|
||||
<template slot-scope="scope">
|
||||
<div style="line-height: 15px">
|
||||
<div>
|
||||
<span v-if="scope.row.dicomInfo.patientId"><span style="font-weight: 500">PID: </span>{{
|
||||
scope.row.dicomInfo.patientId }}</span>
|
||||
<span v-if="scope.row.dicomInfo.patientId">
|
||||
<span style="font-weight: 500">PID:</span>
|
||||
{{
|
||||
scope.row.dicomInfo.patientId }}
|
||||
</span>
|
||||
<span v-else style="color: #f44336">N/A</span>
|
||||
</div>
|
||||
<div>
|
||||
@@ -227,8 +229,7 @@
|
||||
<span v-if="
|
||||
!scope.row.dicomInfo.failedFileCount &&
|
||||
!scope.row.dicomInfo.isInit
|
||||
">
|
||||
{{ $t('trials:uploadDicomList:table:status1') }}</span>
|
||||
">{{ $t('trials:uploadDicomList:table:status1') }}</span>
|
||||
<span style="color: #409eff" v-else-if="
|
||||
!scope.row.dicomInfo.failedFileCount &&
|
||||
scope.row.dicomInfo.isInit &&
|
||||
@@ -246,9 +247,11 @@
|
||||
scope.row.uploadState.record &&
|
||||
scope.row.uploadState.record.fileCount === 0
|
||||
">{{ $t('trials:uploadDicomList:table:status5') }}</span>
|
||||
<span style="color: #f66" v-else>{{
|
||||
$t('trials:uploadDicomList:table:Failed')
|
||||
}}</span>
|
||||
<span style="color: #f66" v-else>
|
||||
{{
|
||||
$t('trials:uploadDicomList:table:Failed')
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('trials:uploadDicomList:table:record')" min-width="140" show-overflow-tooltip>
|
||||
@@ -259,42 +262,42 @@
|
||||
{{ $t('trials:uploadDicomList:table:Existed') }}:
|
||||
<div v-if="scope.row.uploadState.record.Existed.length">
|
||||
<div v-for="item of scope.row.uploadState.record.Existed" :key="item"
|
||||
style="font-size: 12px; color: #baa72a">
|
||||
{{ item }}
|
||||
</div>
|
||||
style="font-size: 12px; color: #baa72a">{{ item }}</div>
|
||||
</div>
|
||||
<div v-else> </div>
|
||||
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
|
||||
<div v-if="scope.row.uploadState.record.Uploaded.length">
|
||||
<div v-for="item of scope.row.uploadState.record.Uploaded" :key="item"
|
||||
style="font-size: 12px; color: #24b837">
|
||||
{{ item }}
|
||||
</div>
|
||||
style="font-size: 12px; color: #24b837">{{ item }}</div>
|
||||
</div>
|
||||
<div v-else> </div>
|
||||
<br />
|
||||
{{ $t('trials:uploadDicomList:table:Failed') }}:
|
||||
<div v-if="scope.row.uploadState.record.Failed.length">
|
||||
<div v-for="item of scope.row.uploadState.record.Failed" :key="item"
|
||||
style="font-size: 12px; color: #f66">
|
||||
{{ item }}
|
||||
</div>
|
||||
style="font-size: 12px; color: #f66">{{ item }}</div>
|
||||
</div>
|
||||
<div v-else> </div>
|
||||
</div>
|
||||
</div>
|
||||
<el-button size="mini" style="cursor: pointer">
|
||||
<span style="font-size: 12px; color: #baa72a">{{
|
||||
scope.row.uploadState.record.Existed.length
|
||||
}}</span>
|
||||
<span style="font-size: 12px; color: #baa72a">
|
||||
{{
|
||||
scope.row.uploadState.record.Existed.length
|
||||
}}
|
||||
</span>
|
||||
/
|
||||
<span style="font-size: 12px; color: #24b837">{{
|
||||
scope.row.uploadState.record.Uploaded.length
|
||||
}}</span>
|
||||
<span style="font-size: 12px; color: #24b837">
|
||||
{{
|
||||
scope.row.uploadState.record.Uploaded.length
|
||||
}}
|
||||
</span>
|
||||
/
|
||||
<span style="font-size: 12px; color: #f66">{{
|
||||
scope.row.uploadState.record.Failed.length
|
||||
}}</span>
|
||||
<span style="font-size: 12px; color: #f66">
|
||||
{{
|
||||
scope.row.uploadState.record.Failed.length
|
||||
}}
|
||||
</span>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
@@ -302,7 +305,8 @@
|
||||
</el-table>
|
||||
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :IsDicom="true" :bodyPart="bodyPart"
|
||||
:subjectVisitId="openSubjectVisitId" :modelList="modelList" :isUpload="openIsUpload"
|
||||
:visitTaskId="openVisitTaskId" :TrialModality="TrialModality" @getList="getList" />
|
||||
:visitTaskId="openVisitTaskId" :TrialModality="TrialModality" :IsReadingTaskViewInOrder="IsReadingTaskViewInOrder"
|
||||
@getList="getList" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -335,6 +339,7 @@ cornerstoneWADOImageLoader.external.cornerstone = cornerstone
|
||||
import { convertBytes } from '@/utils/dicom-character-set'
|
||||
import { parseDicom } from '@/utils/parseDicom.js'
|
||||
import { dcmUpload } from '@/utils/dcmUpload/dcmUpload'
|
||||
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
export default {
|
||||
@@ -354,6 +359,10 @@ export default {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
TaskId: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -369,7 +378,7 @@ export default {
|
||||
IsImageSegment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'study-view': studyView,
|
||||
@@ -419,6 +428,7 @@ export default {
|
||||
openSubjectVisitId: null,
|
||||
openVisitTaskId: null,
|
||||
TrialModality: [],
|
||||
IsReadingTaskViewInOrder: 2
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
@@ -451,8 +461,10 @@ export default {
|
||||
}
|
||||
if (this.IsImageSegment) {
|
||||
params.IsImageSegmentLabel = true
|
||||
}
|
||||
else if (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20) {
|
||||
} else if (
|
||||
this.Criterion.CriterionType == 19 ||
|
||||
this.Criterion.CriterionType == 20
|
||||
) {
|
||||
params.IsImageSegmentLabel = false
|
||||
}
|
||||
this.loading = true
|
||||
@@ -460,6 +472,7 @@ export default {
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.TrialModality = res.OtherInfo.TrialModality.split('|')
|
||||
this.IsReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder || res.OtherInfo.IsReadingTaskViewInOrder === 0 ? res.OtherInfo.IsReadingTaskViewInOrder : 2
|
||||
this.StudyInstanceUidList = []
|
||||
this.SopInstanceUidList = []
|
||||
this.UploadStudyList = []
|
||||
@@ -539,7 +552,9 @@ export default {
|
||||
this.openIsUpload = isUpload
|
||||
this.openSubjectVisitId = item.SubjectVisitId || item.SourceSubjectVisitId
|
||||
this.openVisitTaskId = item.VisitTaskId
|
||||
this.model_cfg.title = `${item.SubjectCode || ''} > ${this.IsImageSegment ? item.VisitName : item.TaskBlindName}`
|
||||
this.model_cfg.title = `${item.SubjectCode || ''} > ${this.IsImageSegment ? item.VisitName : item.TaskBlindName
|
||||
}`
|
||||
if (this.isReadingTaskViewInOrder === 0) this.model_cfg.title = ''
|
||||
this.modelList = item[list]
|
||||
this.model_cfg.visible = true
|
||||
},
|
||||
@@ -641,7 +656,10 @@ export default {
|
||||
for (let i = 0; i < checkFiles.length; i++) {
|
||||
let item = checkFiles[i]
|
||||
var dicom = await parseDicom(item, ['StudyInstanceUid', 'Modality'])
|
||||
if (!!~this.errStudyUidList.indexOf(dicom.StudyInstanceUid) || (this.IsImageSegment && dicom.Modality !== 'IVUS')) {
|
||||
if (
|
||||
!!~this.errStudyUidList.indexOf(dicom.StudyInstanceUid) ||
|
||||
(this.IsImageSegment && dicom.Modality !== 'IVUS')
|
||||
) {
|
||||
this.hasOtherStudy = true
|
||||
checkFiles.splice(i, 1)
|
||||
i--
|
||||
@@ -708,12 +726,13 @@ export default {
|
||||
var studyUid = data.string('x0020000d')
|
||||
if (!studyUid) return resolve()
|
||||
var pixelDataElement = data.elements.x7fe00010
|
||||
if (!pixelDataElement && modality !== 'SR') return resolve()
|
||||
if (!pixelDataElement && modality !== 'SR' && modality !== 'ECG')
|
||||
return resolve()
|
||||
var studyIndex = 0
|
||||
while (
|
||||
studyIndex < scope.uploadQueues.length &&
|
||||
scope.uploadQueues[studyIndex].dicomInfo.studyUid !== studyUid &&
|
||||
(pixelDataElement || modality === 'SR') &&
|
||||
(pixelDataElement || modality === 'SR' || modality === 'ECG') &&
|
||||
modality != ''
|
||||
) {
|
||||
++studyIndex
|
||||
@@ -805,6 +824,39 @@ export default {
|
||||
},
|
||||
})
|
||||
}
|
||||
if (
|
||||
!scope.uploadQueues[studyIndex].dicomInfo.RadionuclideTotalDose
|
||||
) {
|
||||
let dataset = dcmjs.data.DicomMessage.readFile(e.target.result)
|
||||
if (
|
||||
dataset.dict['00540016'] &&
|
||||
dataset.dict['00540016'].Value &&
|
||||
dataset.dict['00540016'].Value[0]
|
||||
) {
|
||||
let RadionuclideTotalDose = dataset.dict['00540016'].Value[0][
|
||||
'00181074'
|
||||
]
|
||||
? dataset.dict['00540016'].Value[0]['00181074'].Value[0]
|
||||
: null
|
||||
let RadionuclideHalfLife = dataset.dict['00540016'].Value[0][
|
||||
'00181075'
|
||||
]
|
||||
? dataset.dict['00540016'].Value[0]['00181075'].Value[0]
|
||||
: null
|
||||
let RadiopharmaceuticalStartTime = dataset.dict['00540016']
|
||||
.Value[0]['00181072']
|
||||
? dataset.dict['00540016'].Value[0]['00181072'].Value[0]
|
||||
: null
|
||||
scope.uploadQueues[studyIndex].dicomInfo.RadionuclideTotalDose =
|
||||
RadionuclideTotalDose
|
||||
scope.uploadQueues[studyIndex].dicomInfo.RadionuclideHalfLife =
|
||||
RadionuclideHalfLife
|
||||
scope.uploadQueues[
|
||||
studyIndex
|
||||
].dicomInfo.RadiopharmaceuticalStartTime =
|
||||
RadiopharmaceuticalStartTime
|
||||
}
|
||||
}
|
||||
var modality = scope.uploadQueues[studyIndex].dicomInfo.modality
|
||||
var currentModality = data.string('x00080060')
|
||||
if (!(modality.indexOf(currentModality) > -1)) {
|
||||
@@ -872,8 +924,9 @@ export default {
|
||||
)
|
||||
seriesItem = {
|
||||
seriesUid: seriesUid,
|
||||
RadiopharmaceuticalInformationSequence: data.string('x00540016') || "",
|
||||
AcquisitionDate: data.string('x00080022') || "",
|
||||
RadiopharmaceuticalInformationSequence:
|
||||
data.string('x00540016') || '',
|
||||
AcquisitionDate: data.string('x00080022') || '',
|
||||
|
||||
DicomSeriesDate: data.string('x00080021'),
|
||||
DicomSeriesTime: data.string('x00080031'),
|
||||
@@ -1081,16 +1134,20 @@ export default {
|
||||
var scope = this
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
let subjectVisitId = null;
|
||||
let subjectVisitId = null
|
||||
let dicomInfo = {}
|
||||
if (scope.VisitTaskId) {
|
||||
scope.StudyInstanceUidList.forEach(item => {
|
||||
scope.StudyInstanceUidList.forEach((item) => {
|
||||
if (item.VisitTaskId === scope.VisitTaskId) {
|
||||
subjectVisitId = item.SourceSubjectVisitId
|
||||
}
|
||||
})
|
||||
} else {
|
||||
scope.StudyInstanceUidList.forEach(item => {
|
||||
if (item.StudyInstanceUid === scope.uploadQueues[index].dicomInfo.studyUid) {
|
||||
scope.StudyInstanceUidList.forEach((item) => {
|
||||
if (
|
||||
item.StudyInstanceUid ===
|
||||
scope.uploadQueues[index].dicomInfo.studyUid
|
||||
) {
|
||||
subjectVisitId = item.SourceSubjectVisitId
|
||||
}
|
||||
})
|
||||
@@ -1108,7 +1165,7 @@ export default {
|
||||
.then(async (res) => {
|
||||
scope.uploadQueues[index].dicomInfo.failedFileCount = 0
|
||||
scope.$set(scope.uploadQueues[index].dicomInfo, 'isInit', true)
|
||||
let dicomInfo = scope.uploadQueues[index].dicomInfo
|
||||
dicomInfo = scope.uploadQueues[index].dicomInfo
|
||||
let seriesNum = scope.uploadQueues[index].seriesList.length
|
||||
let fileNum = scope.uploadQueues[index].fileList.length
|
||||
let seriesList = scope.uploadQueues[index].seriesList
|
||||
@@ -1140,6 +1197,11 @@ export default {
|
||||
failedFileCount: 0,
|
||||
RecordPath: null,
|
||||
study: {
|
||||
RadionuclideTotalDose: dicomInfo.RadionuclideTotalDose,
|
||||
RadionuclideHalfLife: dicomInfo.RadionuclideHalfLife,
|
||||
RadiopharmaceuticalStartTime:
|
||||
dicomInfo.RadiopharmaceuticalStartTime,
|
||||
|
||||
studyId: dicomInfo.studyId,
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyTime: dicomInfo.studyTime,
|
||||
@@ -1149,8 +1211,8 @@ export default {
|
||||
institutionName: dicomInfo.institutionName,
|
||||
patientId: dicomInfo.patientId,
|
||||
patientName: '',
|
||||
patientAge: '',
|
||||
patientSex: dicomInfo.patientSex,
|
||||
patientAge: dicomInfo.patientAge,
|
||||
patientSex: config?.DicomStoreInfo.SubjectSex || dicomInfo.patientSex,
|
||||
accessionNumber: dicomInfo.accNumber,
|
||||
patientBirthDate: '',
|
||||
acquisitionTime: dicomInfo.acquisitionTime,
|
||||
@@ -1170,6 +1232,7 @@ export default {
|
||||
},
|
||||
}
|
||||
let arr = []
|
||||
let uploadBatchId = scope.$guid()
|
||||
for (let i = 0; i < seriesList.length; i++) {
|
||||
let v = seriesList[i]
|
||||
let instanceList = []
|
||||
@@ -1192,8 +1255,10 @@ export default {
|
||||
seriesInstanceUid: v.seriesUid,
|
||||
SOPClassUID: o.SOPClassUID,
|
||||
TransferSytaxUID: o.TransferSytaxUID,
|
||||
MediaStorageSOPInstanceUID: o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
|
||||
MediaStorageSOPInstanceUID:
|
||||
o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID:
|
||||
o.MediaStorageSOPClassUID,
|
||||
sopInstanceUid: o.instanceUid,
|
||||
instanceNumber: o.instanceNumber,
|
||||
instanceTime: o.instanceTime,
|
||||
@@ -1210,14 +1275,17 @@ export default {
|
||||
path: o.myPath,
|
||||
FileSize: o.FileSize,
|
||||
|
||||
PhotometricInterpretation: o.PhotometricInterpretation,
|
||||
PhotometricInterpretation:
|
||||
o.PhotometricInterpretation,
|
||||
BitsAllocated: o.BitsAllocated,
|
||||
PixelRepresentation: o.PixelRepresentation,
|
||||
RescaleIntercept: o.RescaleIntercept,
|
||||
RescaleSlope: o.RescaleSlope,
|
||||
ImagePositionPatient: o.ImagePositionPatient,
|
||||
ImageOrientationPatient: o.ImageOrientationPatient,
|
||||
SequenceOfUltrasoundRegions: o.SequenceOfUltrasoundRegions,
|
||||
ImageOrientationPatient:
|
||||
o.ImageOrientationPatient,
|
||||
SequenceOfUltrasoundRegions:
|
||||
o.SequenceOfUltrasoundRegions,
|
||||
FrameTime: o.FrameTime,
|
||||
CorrectedImage: o.CorrectedImage,
|
||||
Units: o.Units,
|
||||
@@ -1262,6 +1330,16 @@ export default {
|
||||
) {
|
||||
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
||||
}
|
||||
},
|
||||
{
|
||||
fileName: o.file.name,
|
||||
fileSize: o.file.size,
|
||||
fileType: 'application/dicom',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 5,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
if (!res || !res.url) {
|
||||
@@ -1285,7 +1363,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(
|
||||
@@ -1304,8 +1392,10 @@ export default {
|
||||
sopInstanceUid: o.instanceUid,
|
||||
SOPClassUID: o.SOPClassUID,
|
||||
TransferSytaxUID: o.TransferSytaxUID,
|
||||
MediaStorageSOPInstanceUID: o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
|
||||
MediaStorageSOPInstanceUID:
|
||||
o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID:
|
||||
o.MediaStorageSOPClassUID,
|
||||
instanceNumber: o.instanceNumber,
|
||||
instanceTime: o.instanceTime,
|
||||
imageRows: o.imageRows,
|
||||
@@ -1321,14 +1411,17 @@ export default {
|
||||
path: scope.$getObjectName(res.url),
|
||||
FileSize: o.FileSize,
|
||||
|
||||
PhotometricInterpretation: o.PhotometricInterpretation,
|
||||
PhotometricInterpretation:
|
||||
o.PhotometricInterpretation,
|
||||
BitsAllocated: o.BitsAllocated,
|
||||
PixelRepresentation: o.PixelRepresentation,
|
||||
RescaleIntercept: o.RescaleIntercept,
|
||||
RescaleSlope: o.RescaleSlope,
|
||||
ImagePositionPatient: o.ImagePositionPatient,
|
||||
ImageOrientationPatient: o.ImageOrientationPatient,
|
||||
SequenceOfUltrasoundRegions: o.SequenceOfUltrasoundRegions,
|
||||
ImageOrientationPatient:
|
||||
o.ImageOrientationPatient,
|
||||
SequenceOfUltrasoundRegions:
|
||||
o.SequenceOfUltrasoundRegions,
|
||||
FrameTime: o.FrameTime,
|
||||
CorrectedImage: o.CorrectedImage,
|
||||
Units: o.Units,
|
||||
@@ -1383,7 +1476,8 @@ export default {
|
||||
instanceList: instanceList,
|
||||
ImageResizePath: ImageResizePath,
|
||||
|
||||
RadiopharmaceuticalInformationSequence: v.RadiopharmaceuticalInformationSequence,
|
||||
RadiopharmaceuticalInformationSequence:
|
||||
v.RadiopharmaceuticalInformationSequence,
|
||||
AcquisitionDate: v.AcquisitionDate,
|
||||
})
|
||||
}
|
||||
@@ -1426,7 +1520,16 @@ 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)
|
||||
}
|
||||
@@ -1444,6 +1547,7 @@ export default {
|
||||
if (scope.IsImageSegment) {
|
||||
params.IsImageSegmentLabel = true
|
||||
}
|
||||
params.UploadBatchId = uploadBatchId
|
||||
addOrUpdateArchiveTaskStudy(params)
|
||||
.then((res) => {
|
||||
if (dicomInfo.failedFileCount === dicomInfo.fileCount) {
|
||||
@@ -1538,7 +1642,9 @@ export default {
|
||||
var token = getToken()
|
||||
let trialId = this.$route.query.trialId
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${this.IsImageSegment ? 'undefined' : row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
|
||||
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${this.IsImageSegment ? 'undefined' : row.VisitTaskId
|
||||
}&subjectVisitId=${row.SourceSubjectVisitId
|
||||
}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :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: '',
|
||||
@@ -66,6 +70,7 @@ export default {
|
||||
mounted() {
|
||||
this.title = `Upload Images:${this.SubjectCode}(${this.Criterion.TrialReadingCriterionName})`
|
||||
if (this.IsImageSegment) this.title = `Upload Images:${this.SubjectCode}`
|
||||
if (this.isReadingTaskViewInOrder === 0) this.title = ''
|
||||
store.dispatch('trials/setUnLock', true)
|
||||
},
|
||||
methods: {
|
||||
@@ -82,16 +87,16 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep.el-tabs--left .el-tabs__header.is-left {
|
||||
::v-deep .el-tabs--left .el-tabs__header.is-left {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.uploadDicomAndNonedicom {
|
||||
::v-deep.el-tabs--border-card>.el-tabs__header .el-tabs__item {
|
||||
::v-deep .el-tabs--border-card>.el-tabs__header .el-tabs__item {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
::v-deep.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active {
|
||||
::v-deep .el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active {
|
||||
color: #428bca;
|
||||
background-color: #fff;
|
||||
border-right-color: #dcdfe6;
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
<el-table :data="list" style="width: 100%" v-adaptive="{ bottomOffset: 60 }" :loading="loading"
|
||||
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
|
||||
<!--受试者 sortable="custom"-->
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')" />
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')"
|
||||
v-if="isReadingTaskViewInOrder !== 0" />
|
||||
<!--访视名称-->
|
||||
<el-table-column prop="VisitName" :label="$t('upload:nonedicom:table:VisitName')" sortable
|
||||
v-if="IsImageSegment" />
|
||||
@@ -109,7 +110,7 @@
|
||||
<el-button circle :disabled="scope.row.UploadedFileCount <= 0" icon="el-icon-view"
|
||||
:title="$t('upload:nonedicom:button:preview')" @click.stop="handlePreviewNoneDicomFiles(scope.row)" />
|
||||
<!--上传--->
|
||||
<el-button circle icon="el-icon-upload2" :title="$t('upload:nonedicom:button:upload')"
|
||||
<el-button circle icon="el-icon-upload2" :title="$t('upload:nonedicom:button:upload')" v-if="!forbid"
|
||||
@click.native.prevent="handleUpload(scope.row)" />
|
||||
<!--删除--->
|
||||
<el-button :disabled="scope.row.UploadedFileCount <= 0 ||
|
||||
@@ -239,6 +240,10 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
SubjectCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -261,6 +266,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -471,7 +480,7 @@ export default {
|
||||
let trialId = this.$route.query.trialId
|
||||
var token = getToken()
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
},
|
||||
@@ -544,8 +553,9 @@ export default {
|
||||
})
|
||||
if (res.IsSuccess) {
|
||||
this.studyMonitorId = res.Result
|
||||
let uploadBatchId = this.$guid()
|
||||
for (let i = 0; i < num; i++) {
|
||||
funArr.push(this.handleUploadTask(this.selectArr, i))
|
||||
funArr.push(this.handleUploadTask(this.selectArr, i, uploadBatchId))
|
||||
}
|
||||
if (funArr.length > 0) {
|
||||
let res = await Promise.all(funArr)
|
||||
@@ -556,7 +566,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 +582,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 +616,13 @@ export default {
|
||||
}
|
||||
let ind = arr.findIndex((item) => item.status === 0)
|
||||
if (ind >= 0) {
|
||||
return this.handleUploadTask(arr, ind)
|
||||
return this.handleUploadTask(arr, ind, uploadBatchId)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// file上传到oss
|
||||
async fileToOss(path, file, item) {
|
||||
async fileToOss(path, file, item, uploadBatchId) {
|
||||
try {
|
||||
let res = await this.OSSclient.multipartUpload(
|
||||
{
|
||||
@@ -625,6 +635,17 @@ export default {
|
||||
if (item.uploadFileSize > file.fileSize) {
|
||||
item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1
|
||||
}
|
||||
},
|
||||
{
|
||||
fileName: item.name,
|
||||
fileSize: item.size,
|
||||
fileType: item.fileType,
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 7,
|
||||
trialId: this.$route.query.trialId,
|
||||
subjectId: this.currentRow.SubjectId,
|
||||
subjectVisitId: this.currentRow.SourceSubjectVisitId,
|
||||
studyCode: this.SubjectCode
|
||||
}
|
||||
)
|
||||
if (res) {
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
</el-button>
|
||||
<el-table :data="modelList" style="width: 100%" height="300">
|
||||
<!--检查编号-->
|
||||
<el-table-column prop="StudyCode" :label="$t('trials:uploadImage:table:StudyCode')" />
|
||||
<el-table-column prop="StudyCode" :label="$t('trials:uploadImage:table:StudyCode')"
|
||||
v-if="IsReadingTaskViewInOrder !== 0" />
|
||||
<!--检查类型-->
|
||||
<el-table-column prop="ModalityForEdit" :label="$t('trials:uploadImage:table:ModalityForEdit')"
|
||||
v-if="IsDicom" />
|
||||
@@ -139,6 +140,10 @@ export default {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
IsReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'base-model': baseModel,
|
||||
@@ -176,18 +181,18 @@ export default {
|
||||
var token = getToken()
|
||||
let trialId = this.$route.query.trialId
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showvisitdicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&isReading=1&TokenKey=${token}`,
|
||||
path: `/showvisitdicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
|
||||
})
|
||||
} else {
|
||||
let trialId = this.$route.query.trialId
|
||||
var token = getToken()
|
||||
if (!this.IsImageSegment && (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20)) {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
|
||||
})
|
||||
} else {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777010831812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1646" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 896c-230.058667 0-421.461333-165.546667-461.610667-384a468.565333 468.565333 0 0 1 142.506667-258.816L89.6 149.973333A42.666667 42.666667 0 1 1 149.930667 89.6L934.4 874.112a42.666667 42.666667 0 0 1-60.373333 60.330667l-111.061334-111.061334A466.901333 466.901333 0 0 1 512 896zM253.226667 313.6A382.506667 382.506667 0 0 0 137.514667 512a384.213333 384.213333 0 0 0 563.242666 249.088l-86.528-86.528A192 192 0 0 1 349.44 409.770667L253.226667 313.6z m297.770666 297.728l-138.325333-138.325333a106.666667 106.666667 0 0 0 138.282667 138.282666l0.042666 0.042667z m285.312 22.357333l10.24-18.218666A381.226667 381.226667 0 0 0 886.485333 512a384.213333 384.213333 0 0 0-440.661333-292.949333c-2.944 0.512-9.173333 1.877333-18.730667 4.096a42.88 42.88 0 1 1-19.2-83.541334A470.912 470.912 0 0 1 512 128c230.058667 0 421.461333 165.546667 461.610667 384a467.072 467.072 0 0 1-57.685334 153.856 94.933333 94.933333 0 0 1-8.021333 11.178667 44.373333 44.373333 0 0 1-58.794667 9.088 39.552 39.552 0 0 1-12.8-52.437334z m-188.501333-257.493333a192 192 0 0 1 55.850667 147.626667l-203.52-203.477334a192 192 0 0 1 147.626666 55.893334z" fill="#e6e6e6" p-id="1647"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -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,12 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="h-6 w-6" color="#fff">
|
||||
<path
|
||||
d="M10.3945 12.6113C10.043 12.6113 9.78516 12.3945 9.78516 12.0371C9.78516 11.6855 10.043 11.4688 10.3945 11.4688H13.2012C13.5527 11.4688 13.8164 11.6855 13.8164 12.0371C13.8164 12.3945 13.5527 12.6113 13.2012 12.6113H10.3945Z"
|
||||
fill="currentColor"></path>
|
||||
<path opacity="0.5"
|
||||
d="M18.312 6.84473C21.8473 8.88583 22.9225 13.6424 20.7134 17.4687C18.5042 21.2951 13.8473 22.7422 10.312 20.7011C9.51661 20.2419 8.84737 19.6439 8.31042 18.9512C11.3012 19.3598 14.4827 17.8251 16.1946 14.8598C17.9067 11.8945 17.6457 8.3712 15.7963 5.98538C16.6645 6.10409 17.5167 6.38556 18.312 6.84473Z"
|
||||
fill="currentColor"></path>
|
||||
<circle cx="13.7852" cy="13.4688" r="8" stroke="currentColor"></circle>
|
||||
<path
|
||||
d="M4.50586 8.22266C4.14844 8.22266 3.92578 7.9707 3.92578 7.60742V5.68555H2.10352C1.74609 5.68555 1.5 5.46875 1.5 5.11719C1.5 4.76562 1.74609 4.54297 2.10352 4.54297H3.92578V2.61523C3.92578 2.25195 4.14844 2 4.50586 2C4.85742 2 5.08008 2.25195 5.08008 2.61523V4.54297H6.89648C7.25391 4.54297 7.50586 4.76562 7.50586 5.11719C7.50586 5.46875 7.25391 5.68555 6.89648 5.68555H5.08008V7.60742C5.08008 7.9707 4.85742 8.22266 4.50586 8.22266Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1751350116150" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20392" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M870.4 819.2a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4zM512 179.2a332.8 332.8 0 1 1 0 665.6 332.8 332.8 0 0 1 0-665.6z m0 51.2a281.6 281.6 0 1 0 0 563.2 281.6 281.6 0 0 0 0-563.2zM153.6 102.4a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4z" fill="#ADAEB8" p-id="20393"></path></svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597744457882" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10125" width="285.64453125" height="250" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M926.216214 404.588947l1.511115-151.84272H1079.570048c18.035893 0 33.098301-15.062408 33.098301-33.0983a33.390775 33.390775 0 0 0-33.098301-33.098301H927.727329V33.195792a33.390775 33.390775 0 0 0-33.049555-33.049555 33.390775 33.390775 0 0 0-33.0983 33.049555c0 3.022231 0 4.533346 1.511115 7.555577v144.287142H711.24787a33.390775 33.390775 0 0 0-33.098301 33.147046c0 18.035893 15.062408 33.049555 33.098301 33.049555H863.090589v139.802542c0 3.022231-1.46237 4.533346-1.46237 7.506831 0 18.035893 15.013662 33.098301 33.049555 33.098301 15.013662 1.46237 28.564955-10.529062 31.53844-27.053839zM1032.969201 790.995763a29.393631 29.393631 0 0 0-22.520493 10.480316 546.000095 546.000095 0 0 1-117.282049 88.717095 29.101157 29.101157 0 0 0-15.062408 25.591469c0 16.524777 13.551292 30.027324 30.07607 30.027324 4.533346 0 10.529062-1.46237 13.551292-2.973485 1.46237 0 1.46237-1.511115 1.46237-1.511115a523.235874 523.235874 0 0 0 127.811111-97.735041c6.044461-5.995716 10.529062-13.551292 10.529061-22.569238a28.028752 28.028752 0 0 0-28.564954-30.027325zM793.920503 935.282906c-2.973485 0-7.506831 0-10.529062 1.511115-46.600847 15.062408-96.223925 24.080354-145.798258 27.053839-15.062408 1.511115-25.59147 15.062408-25.591469 30.07607 0 16.573523 13.551292 30.07607 30.07607 30.07607 55.618794-4.4846 108.215357-13.502547 159.398295-30.07607a28.95492 28.95492 0 0 0 22.520494-28.564954 30.173561 30.173561 0 0 0-30.07607-30.07607zM535.324796 960.874375c-12.040177-1.511115-24.031609-1.511115-36.071785-3.02223a564.962155 564.962155 0 0 1-49.623078-7.506832c-230.030752-45.089732-389.380302-202.976912-389.380302-380.362355 0-139.851288 99.19741-269.124768 260.106822-339.805969 13.502547-5.995716 27.053839-12.040177 40.556386-16.573523 10.529062-4.4846 22.569239-7.506831 33.0983-10.480317 12.040177-4.533346 21.058123-15.062408 21.058124-28.564954a30.173561 30.173561 0 0 0-30.07607-30.07607 25.396487 25.396487 0 0 0-15.062408 4.4846c-10.529062 3.022231-19.498262 6.044461-28.564955 9.017947l-45.089732 18.035893C114.357309 254.257343 0.097491 406.148808 0.097491 568.471843c0 207.510258 180.407674 387.917932 439.00338 440.563241l54.107679 9.017946c12.040177 1.46237 25.59147 3.022231 37.631646 3.022231h1.46237c16.573523 0 30.07607-13.551292 30.07607-30.07607a30.758509 30.758509 0 0 0-27.05384-30.07607zM1169.798258 569.982958a30.173561 30.173561 0 0 0-30.07607-30.07607 30.173561 30.173561 0 0 0-30.07607 30.07607v1.46237c0 46.649593-10.529062 93.25044-33.049555 136.829057-1.511115 3.022231-1.511115 7.506831-1.511115 12.040177 0 16.573523 13.551292 30.07607 30.07607 30.07607 13.502547 0 24.031609-9.017946 28.564954-21.058124a361.985243 361.985243 0 0 0 36.071786-157.88718v-1.46237z" p-id="10126"></path><path d="M1052.516209 297.835959c-5.995716-4.533346-13.502547-9.017946-22.520493-9.017946a30.173561 30.173561 0 0 0-30.07607 30.07607c0 7.506831 2.973485 15.013662 9.017946 21.009378a375.14657 375.14657 0 0 1 79.699148 118.793164c4.4846 10.529062 15.013662 19.547008 27.053839 19.547008 16.524777 0 30.07607-13.551292 30.07607-30.07607 0-4.4846-1.511115-7.506831-3.02223-12.040177a422.039891 422.039891 0 0 0-90.179464-138.291427zM666.158138 182.065026h4.4846c16.573523 0 30.07607-13.551292 30.07607-30.07607 0-15.013662-12.040177-28.564955-27.053839-28.564954v-1.46237a761.602133 761.602133 0 0 0-154.86495-1.559861h-3.022231a30.173561 30.173561 0 0 0-30.07607 30.07607c0 16.573523 13.551292 30.07607 30.07607 30.07607h3.022231v1.462369c46.600847-5.94697 97.735041-4.4846 147.358119 0z" p-id="10127"></path></svg>
|
||||
|
Before Width: | Height: | Size: 623 B After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777014169186" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4736" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1024 739.560727V1024H739.560727v-84.898909h199.540364v-199.540364H1024z m-939.101091 0v199.540364h199.540364V1024H0V739.560727h84.898909zM824.878545 199.121455v625.75709H199.121455V199.121455h625.75709z m-85.317818 85.317818H284.439273v455.121454h455.121454V284.439273zM1024 0v284.439273h-84.898909V84.898909h-199.540364V0H1024zM284.439273 0v84.898909H84.898909v199.540364H0V0h284.439273z" fill="#e6e6e6" p-id="4737"></path></svg>
|
||||
|
After Width: | Height: | Size: 764 B |
@@ -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 |
@@ -1 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1609205172733" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2919" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M320 640v256H256v-192H64v-64h256z m640 0v64h-192v192h-64v-256h256zM512 384a128 128 0 1 1 0 256 128 128 0 0 1 0-256zM320 128v256H64V320h192V128h64z m448 0v192h192v64h-256V128h64z" p-id="2920"></path></svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777426164195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5541" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M316 672h60c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v304c0 4.4 3.6 8 8 8zM512 622c22.1 0 40-17.9 40-39 0-23.1-17.9-41-40-41s-40 17.9-40 41c0 21.1 17.9 39 40 39zM512 482c22.1 0 40-17.9 40-39 0-23.1-17.9-41-40-41s-40 17.9-40 41c0 21.1 17.9 39 40 39z" p-id="5542"></path><path d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32z m-40 728H184V184h656v656z" p-id="5543"></path><path d="M648 672h60c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v304c0 4.4 3.6 8 8 8z" p-id="5544"></path></svg>
|
||||
|
Before Width: | Height: | Size: 581 B After Width: | Height: | Size: 908 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777352764855" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10736" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M587.808 383.392l-102.208 102.208A37.472 37.472 0 0 0 512 549.408a36.288 36.288 0 0 0 26.272-11.104l315.84-315.232a454.976 454.976 0 1 0 43.52 61.888l-54.688 54.752a372.704 372.704 0 1 1-94.816-116.928l-106.56 106.496-53.792 54.144z" p-id="10737"></path></svg>
|
||||
|
After Width: | Height: | Size: 594 B |
@@ -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="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 @@
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" stroke="currentColor" x="1.5" y="1.5" width="15" height="15" rx="1"></rect></g></g></svg>
|
||||
|
After Width: | Height: | Size: 347 B |
@@ -1 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597744457882" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10125" width="285.64453125" height="250" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M926.216214 404.588947l1.511115-151.84272H1079.570048c18.035893 0 33.098301-15.062408 33.098301-33.0983a33.390775 33.390775 0 0 0-33.098301-33.098301H927.727329V33.195792a33.390775 33.390775 0 0 0-33.049555-33.049555 33.390775 33.390775 0 0 0-33.0983 33.049555c0 3.022231 0 4.533346 1.511115 7.555577v144.287142H711.24787a33.390775 33.390775 0 0 0-33.098301 33.147046c0 18.035893 15.062408 33.049555 33.098301 33.049555H863.090589v139.802542c0 3.022231-1.46237 4.533346-1.46237 7.506831 0 18.035893 15.013662 33.098301 33.049555 33.098301 15.013662 1.46237 28.564955-10.529062 31.53844-27.053839zM1032.969201 790.995763a29.393631 29.393631 0 0 0-22.520493 10.480316 546.000095 546.000095 0 0 1-117.282049 88.717095 29.101157 29.101157 0 0 0-15.062408 25.591469c0 16.524777 13.551292 30.027324 30.07607 30.027324 4.533346 0 10.529062-1.46237 13.551292-2.973485 1.46237 0 1.46237-1.511115 1.46237-1.511115a523.235874 523.235874 0 0 0 127.811111-97.735041c6.044461-5.995716 10.529062-13.551292 10.529061-22.569238a28.028752 28.028752 0 0 0-28.564954-30.027325zM793.920503 935.282906c-2.973485 0-7.506831 0-10.529062 1.511115-46.600847 15.062408-96.223925 24.080354-145.798258 27.053839-15.062408 1.511115-25.59147 15.062408-25.591469 30.07607 0 16.573523 13.551292 30.07607 30.07607 30.07607 55.618794-4.4846 108.215357-13.502547 159.398295-30.07607a28.95492 28.95492 0 0 0 22.520494-28.564954 30.173561 30.173561 0 0 0-30.07607-30.07607zM535.324796 960.874375c-12.040177-1.511115-24.031609-1.511115-36.071785-3.02223a564.962155 564.962155 0 0 1-49.623078-7.506832c-230.030752-45.089732-389.380302-202.976912-389.380302-380.362355 0-139.851288 99.19741-269.124768 260.106822-339.805969 13.502547-5.995716 27.053839-12.040177 40.556386-16.573523 10.529062-4.4846 22.569239-7.506831 33.0983-10.480317 12.040177-4.533346 21.058123-15.062408 21.058124-28.564954a30.173561 30.173561 0 0 0-30.07607-30.07607 25.396487 25.396487 0 0 0-15.062408 4.4846c-10.529062 3.022231-19.498262 6.044461-28.564955 9.017947l-45.089732 18.035893C114.357309 254.257343 0.097491 406.148808 0.097491 568.471843c0 207.510258 180.407674 387.917932 439.00338 440.563241l54.107679 9.017946c12.040177 1.46237 25.59147 3.022231 37.631646 3.022231h1.46237c16.573523 0 30.07607-13.551292 30.07607-30.07607a30.758509 30.758509 0 0 0-27.05384-30.07607zM1169.798258 569.982958a30.173561 30.173561 0 0 0-30.07607-30.07607 30.173561 30.173561 0 0 0-30.07607 30.07607v1.46237c0 46.649593-10.529062 93.25044-33.049555 136.829057-1.511115 3.022231-1.511115 7.506831-1.511115 12.040177 0 16.573523 13.551292 30.07607 30.07607 30.07607 13.502547 0 24.031609-9.017946 28.564954-21.058124a361.985243 361.985243 0 0 0 36.071786-157.88718v-1.46237z" p-id="10126"></path><path d="M1052.516209 297.835959c-5.995716-4.533346-13.502547-9.017946-22.520493-9.017946a30.173561 30.173561 0 0 0-30.07607 30.07607c0 7.506831 2.973485 15.013662 9.017946 21.009378a375.14657 375.14657 0 0 1 79.699148 118.793164c4.4846 10.529062 15.013662 19.547008 27.053839 19.547008 16.524777 0 30.07607-13.551292 30.07607-30.07607 0-4.4846-1.511115-7.506831-3.02223-12.040177a422.039891 422.039891 0 0 0-90.179464-138.291427zM666.158138 182.065026h4.4846c16.573523 0 30.07607-13.551292 30.07607-30.07607 0-15.013662-12.040177-28.564955-27.053839-28.564954v-1.46237a761.602133 761.602133 0 0 0-154.86495-1.559861h-3.022231a30.173561 30.173561 0 0 0-30.07607 30.07607c0 16.573523 13.551292 30.07607 30.07607 30.07607h3.022231v1.462369c46.600847-5.94697 97.735041-4.4846 147.358119 0z" p-id="10127"></path></svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777352032068" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5387" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M924.8 337.8c-22.6-53.4-54.9-101.3-96-142.4s-89-73.4-142.4-96C631.2 76.1 572.5 64.2 512 64.2S392.9 76.1 337.6 99.4c-53.4 22.6-101.3 54.9-142.4 96s-73.4 89-96 142.4C75.9 393.1 64 451.8 64 512.2c0 60.5 11.8 119.1 35.2 174.4 22.6 53.4 54.9 101.3 96 142.4 41.1 41.1 89 73.4 142.4 96 55.3 23.4 113.9 35.2 174.4 35.2s119.1-11.8 174.4-35.2c53.4-22.6 101.3-54.9 142.4-96 41.1-41.1 73.4-89 96-142.4 23.4-55.3 35.2-113.9 35.2-174.4 0-60.4-11.8-119.1-35.2-174.4zM780.3 780.5C708.6 852.2 613.4 891.6 512 891.6c-101.3 0-196.6-39.5-268.3-111.1S132.6 613.6 132.6 512.2c0-101.3 39.5-196.6 111.1-268.3s167-111.1 268.3-111.1c101.3 0 196.6 39.5 268.3 111.1s111.1 166.9 111.1 268.3S852 708.8 780.3 780.5z" p-id="5388"></path><path d="M512 512.2m-106.2 0a106.2 106.2 0 1 0 212.4 0 106.2 106.2 0 1 0-212.4 0Z" p-id="5389"></path></svg>
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1779246817161" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5348" width="200" height="200" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M473 71a8 8 0 0 1 8-8h64a8 8 0 0 1 8 8v77.161C722.848 166.622 857.812 301.289 876.729 471H952a8 8 0 0 1 8 8v64a8 8 0 0 1-8 8h-75.053C858.871 721.652 723.515 857.305 553 875.839V951a8 8 0 0 1-8 8h-64a8 8 0 0 1-8-8v-75.161C302.818 857.341 167.659 722.182 149.161 552H72a8 8 0 0 1-8-8v-64a8 8 0 0 1 8-8h77.161C167.659 301.818 302.818 166.659 473 148.161V71z m326 441c0-157.953-128.047-286-286-286S227 354.047 227 512s128.047 286 286 286 286-128.047 286-286z m-286 60c33.137 0 60-26.863 60-60s-26.863-60-60-60-60 26.863-60 60 26.863 60 60 60z" fill="#ffffff" p-id="5349"></path></svg>
|
||||
|
After Width: | Height: | Size: 913 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777432778355" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2607" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M954.026667 913.6128H600.746667a35.908267 35.908267 0 0 1-35.771734-35.771733V116.736a35.703467 35.703467 0 0 1 68.266667-15.018667l353.143467 761.0368a35.566933 35.566933 0 0 1-2.2528 34.269867 35.362133 35.362133 0 0 1-30.173867 16.5888z" fill="#FFFFFF" p-id="2608"></path><path d="M465.373867 913.544533H112.162133a35.6352 35.6352 0 0 1-32.494933-50.722133L432.878933 101.717333a35.6352 35.6352 0 0 1 40.277334-19.8656 35.566933 35.566933 0 0 1 27.989333 34.952534V877.909333a35.771733 35.771733 0 0 1-35.771733 35.6352z" fill="#FFFFFF" fill-opacity=".4" p-id="2609"></path></svg>
|
||||
|
After Width: | Height: | Size: 916 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777426622063" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8288" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M667.69962 294.974152l0 589.688383 316.384787 0L667.69962 294.974152zM632.522446 884.662535 632.522446 572.426231 34.882973 884.662535 632.522446 884.662535zM510.16777 357.862457l-137.677663-31.323403c0 0 97.523127-217.392192 349.512279-98.842169 0 0-196.516746-248.618381-487.190965 67.571978l-137.677663-31.273261 158.803819 250.082732L510.16777 357.862457z" p-id="8289"></path></svg>
|
||||
|
After Width: | Height: | Size: 719 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777426691300" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2490" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M34.884 883.64h316.385V293.95L34.884 883.64z m949.201 0L386.446 571.402v312.236h597.64zM763.03 513.053l158.805-250.083-137.678 31.274c-290.674-316.19-487.191-67.572-487.191-67.572 251.99-118.55 349.512 98.842 349.512 98.842l-137.677 31.323L763.03 513.054z" fill="" p-id="2491"></path></svg>
|
||||
|
After Width: | Height: | Size: 623 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777432945307" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4263" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M106.496 928.426667V575.2832c0-19.729067 16.042667-35.771733 35.771733-35.771733h761.0368a35.703467 35.703467 0 0 1 15.086934 68.266666L157.354667 960.9216a35.566933 35.566933 0 0 1-34.269867-2.321067 35.362133 35.362133 0 0 1-16.5888-30.173866z" fill="#FFFFFF" p-id="4264"></path><path d="M106.496 439.842133V86.6304a35.6352 35.6352 0 0 1 50.7904-32.494933l761.0368 353.211733a35.6352 35.6352 0 0 1 19.933867 40.209067 35.566933 35.566933 0 0 1-34.952534 27.989333H142.199467a35.771733 35.771733 0 0 1-35.703467-35.703467z" fill="#FFFFFF" fill-opacity=".4" p-id="4265"></path></svg>
|
||||
|
After Width: | Height: | Size: 916 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1782284218093" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4982" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 51.2a460.8 460.8 0 1 1 0 921.6 460.8 460.8 0 0 1 0-921.6z m0 51.2a409.6 409.6 0 1 0 0 819.2 409.6 409.6 0 0 0 0-819.2z" fill="#ffffff" p-id="4983"></path><path d="M512 358.4c70.4 0 137.1136 5.2736 196.7616 14.6432l27.0336 4.6592C877.1584 403.9168 972.8 454.2464 972.8 512c0 57.7536-95.6416 108.032-237.0048 134.2976l-27.0336 4.608A1275.1872 1275.1872 0 0 1 512 665.6c-70.4 0-137.1136-5.2736-196.7616-14.6432l-27.0336-4.6592C146.8416 620.0832 51.2 569.7536 51.2 512c0-57.7536 95.6416-108.032 237.0048-134.2976l27.0336-4.608c55.0912-8.704 116.1728-13.824 180.5824-14.592L512 358.4z m0 51.2c-31.5904 0-62.3104 1.1776-91.8528 3.328l-29.0816 2.5088-28.2112 3.072c-23.1424 2.7648-45.2096 6.144-66.048 9.984l-24.4224 4.7616-23.0912 5.12-21.76 5.5296C150.3744 464.5376 102.4 490.8544 102.4 512c0 21.1456 47.9744 47.4624 125.1328 68.096l21.76 5.4784 23.0912 5.1712 24.4224 4.7616c20.8384 3.84 42.9056 7.168 66.048 9.984l28.16 3.072 29.1328 2.5088a1261.4656 1261.4656 0 0 0 183.7056 0l29.0816-2.5088 28.2112-3.072c23.1424-2.7648 45.2096-6.144 66.048-9.984l24.4224-4.7616 23.0912-5.12 21.76-5.5296C873.6256 559.4624 921.6 533.1456 921.6 512c0-21.1456-47.9744-47.4624-125.1328-68.096l-21.76-5.4784-23.0912-5.1712-24.4224-4.7616c-20.8384-3.84-42.9056-7.168-66.048-9.984l-28.16-3.072-29.1328-2.5088c-24.576-1.792-50.0736-2.9184-76.1344-3.2256L512 409.6z" fill="#ffffff" p-id="4984"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" class="h-6 w-6"><g id="tool-seg-threshold" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><rect id="Rectangle" x="0" y="0" width="24" height="24"></rect><g id="Group" transform="translate(2.4184, 14.3673)" stroke="currentColor" stroke-width="1.5"><line x1="16.5816327" y1="2.13265306" x2="19.0816327" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><line x1="0.0816326531" y1="2.13265306" x2="12.0816327" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><circle id="Oval" cx="14.2244898" cy="2.09183673" r="2.09183673"></circle></g><g id="Group" transform="translate(11.7092, 7.4592) scale(-1, 1) translate(-11.7092, -7.4592)translate(1.9184, 5.3673)" stroke="currentColor" stroke-width="1.5"><line x1="16" y1="2.13265306" x2="19.0816327" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><line x1="0.0816326531" y1="2.13265306" x2="11" y2="2.13265306" id="Line-2" stroke-linecap="round"></line><circle id="Oval" cx="13.2244898" cy="2.09183673" r="2.09183673"></circle></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -2,11 +2,7 @@
|
||||
<div class="navbar navbar-flex-wrapper">
|
||||
<div class="leftMenu">
|
||||
<div class="navbar-flex-wrapper">
|
||||
<hamburger
|
||||
:is-active="sidebar.opened"
|
||||
class="hamburger-container"
|
||||
@toggleClick="toggleSideBar"
|
||||
/>
|
||||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
</div>
|
||||
@@ -51,12 +47,8 @@
|
||||
<TopLang></TopLang>
|
||||
</div>
|
||||
</div>
|
||||
<toggleRole
|
||||
v-if="toggleRoleVisible"
|
||||
:visible.sync="toggleRoleVisible"
|
||||
:loading="toggleRoleLoading"
|
||||
@save="loginByRole"
|
||||
/>
|
||||
<toggleRole v-if="toggleRoleVisible" :visible.sync="toggleRoleVisible" :loading="toggleRoleLoading"
|
||||
@save="loginByRole" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -192,12 +184,14 @@ export default {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
// position: relative;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
@@ -219,6 +213,7 @@ export default {
|
||||
// float: right;
|
||||
height: 100%;
|
||||
line-height: 65px;
|
||||
|
||||
// position: relative;
|
||||
&:focus {
|
||||
outline: none;
|
||||
@@ -245,6 +240,7 @@ export default {
|
||||
.avatar-container {
|
||||
display: inline-block;
|
||||
margin-right: 200px;
|
||||
|
||||
.user-avatar {
|
||||
margin-top: 5px;
|
||||
width: 40px;
|
||||
@@ -252,16 +248,19 @@ export default {
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-container {
|
||||
// margin-left: 30px;
|
||||
// position: absolute;
|
||||
// right: 20px;
|
||||
// top: 0px;
|
||||
cursor: pointer;
|
||||
|
||||
.el-icon-caret-bottom {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-dropdown-link {
|
||||
color: #999c9e;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import Vue from 'vue'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||
// import { createVersionPolling } from "@/utils/version-polling.esm.js";
|
||||
import ElementUI, { MessageBox } from 'element-ui'
|
||||
@@ -70,6 +71,9 @@ 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)
|
||||
@@ -334,8 +338,10 @@ async function VueInit() {
|
||||
})
|
||||
}
|
||||
let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo'))
|
||||
if (CompanyInfo && CompanyInfo.SystemShortName && text.toUpperCase() !== "CIRCLE") {
|
||||
let test = new RegExp('IRC', 'ig')
|
||||
if (CompanyInfo && CompanyInfo.SystemShortName && (text.toUpperCase() !== "CIRCLE")) {
|
||||
// 精准匹配独立单词 IRC
|
||||
// let test = new RegExp('IRC', 'ig')
|
||||
let test = new RegExp('\\bIRC\\b', 'ig')
|
||||
text = text.replace(test, CompanyInfo.SystemShortName)
|
||||
}
|
||||
// return i18n.t(key)
|
||||
@@ -446,6 +452,7 @@ async function VueInit() {
|
||||
isOpen = false
|
||||
isLock = null
|
||||
zzSessionStorage.removeItem('isLock')
|
||||
DicomEvent.$emit('isLock', false)
|
||||
router.push("/login")
|
||||
}).then(() => {
|
||||
// _vm.$alert(lang === 'zh' ? '由于您长时间未操作,为保护您的数据安全已强制将您下线,如果需要继续操作请重新登陆!' : 'No operation for a long time non-operation, you have been forced logout to protect data security. If continue to operate, please login again!', {
|
||||
@@ -457,160 +464,166 @@ async function VueInit() {
|
||||
})
|
||||
|
||||
} : () => { }, process.env.VUE_APP_LOGOUT_FOR_TIME,
|
||||
eval(process.env.VUE_APP_LOCK_FOR_PERMISSION) ? () => {
|
||||
var lang = zzSessionStorage.getItem('lang') ? zzSessionStorage.getItem('lang') : 'zh'
|
||||
if (_vm.$store.state.trials.unlock || WHITELIST.includes(_vm.$route.path)) {
|
||||
count = 0;
|
||||
localStorage.setItem('count', '0')
|
||||
if (_vm.$route.path === '/login') {
|
||||
zzSessionStorage.removeItem('lastWorkbench')
|
||||
zzSessionStorage.removeItem('isLock')
|
||||
isLock = null
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isOpen) {
|
||||
return
|
||||
}
|
||||
isOpen = true
|
||||
zzSessionStorage.setItem('isLock', 'true')
|
||||
_vm.$msgbox({
|
||||
title: _vm.$t("env:lock:msgBox:title"),
|
||||
confirmButtonText: _vm.$t("env:lock:msgBox:confirmButtonText"),
|
||||
showClose: false,
|
||||
beforeClose: (action, instance, done) => {
|
||||
if (action === 'confirm') {
|
||||
if (!_vm.unlock.my_username) {
|
||||
_vm.$message.warning(_vm.$t("env:lock:msgBox:iupUser"))
|
||||
return
|
||||
}
|
||||
if (!_vm.unlock.my_password) {
|
||||
_vm.$message.warning(_vm.$t("env:lock:msgBox:inpPassword"))
|
||||
return
|
||||
}
|
||||
var my_username = zzSessionStorage.getItem('my_username')
|
||||
var my_password = zzSessionStorage.getItem('my_password')
|
||||
let my_userid = zzSessionStorage.getItem('userId')
|
||||
let my_EMail = zzSessionStorage.getItem('my_EMail') || ''
|
||||
if (md5(_vm.unlock.my_password) === my_password && (my_username === _vm.unlock.my_username || my_EMail.toUpperCase() === _vm.unlock.my_username.toUpperCase())) {
|
||||
resetReadingRestTime().then(() => {
|
||||
})
|
||||
const closeLock = (_vm) => {
|
||||
_vm.$message.success(_vm.$t("env:lock:msgBox:lockSuccess"))
|
||||
_vm.unlock = {
|
||||
my_username: null,
|
||||
my_password: null,
|
||||
view: false
|
||||
}
|
||||
isOpen = false
|
||||
count = 0;
|
||||
isLock = null
|
||||
zzSessionStorage.removeItem('isLock')
|
||||
localStorage.setItem('count', '0')
|
||||
document.querySelector('#my_username').value = null
|
||||
document.querySelector('#my_password').value = null
|
||||
setTimeout(() => {
|
||||
done()
|
||||
}, 500)
|
||||
}
|
||||
// if (eval(process.env.VUE_APP_LOCK_FOR_PERMISSION_MFA)) {
|
||||
// sendMFAEmail({ UserId: my_userid, MfaType: 1 }).then((res) => {
|
||||
// done();
|
||||
// Vue.prototype.$MFA({
|
||||
// status: "lock",
|
||||
// UserId: my_userid,
|
||||
// EMail: res.Result,
|
||||
// username: my_username,
|
||||
// callBack: () => {
|
||||
// closeLock(_vm)
|
||||
// },
|
||||
// })
|
||||
// })
|
||||
// } else {
|
||||
closeLock(_vm)
|
||||
// }
|
||||
|
||||
} else {
|
||||
// console.log(111)
|
||||
_vm.$message.error(_vm.$t('env:lock:msgBox:userFail'))
|
||||
}
|
||||
eval(process.env.VUE_APP_LOCK_FOR_PERMISSION)
|
||||
? () => {
|
||||
var lang = zzSessionStorage.getItem('lang') ? zzSessionStorage.getItem('lang') : 'zh'
|
||||
if (_vm.$store.state.trials.unlock || WHITELIST.includes(_vm.$route.path)) {
|
||||
count = 0;
|
||||
localStorage.setItem('count', '0')
|
||||
if (_vm.$route.path === '/login') {
|
||||
zzSessionStorage.removeItem('lastWorkbench')
|
||||
zzSessionStorage.removeItem('isLock')
|
||||
DicomEvent.$emit('isLock', false)
|
||||
isLock = null
|
||||
}
|
||||
},
|
||||
message: h('div', {}, [
|
||||
h('el-form', {
|
||||
props: { labelWidth: "80px" }
|
||||
}, [
|
||||
h('el-form-item', {
|
||||
props: { label: _vm.$t("env:lock:msgBox:form:username") },
|
||||
}, [
|
||||
h('input', {
|
||||
props: {
|
||||
value: _vm.unlock.my_username
|
||||
},
|
||||
attrs: {
|
||||
id: 'my_username',
|
||||
class: 'el-input__inner',
|
||||
autocomplete: 'new-password'
|
||||
},
|
||||
on: {
|
||||
change: (event) => {
|
||||
_vm.unlock.my_username = event.target.value
|
||||
},
|
||||
input: (event) => {
|
||||
_vm.unlock.my_username = event.target.value
|
||||
}
|
||||
}
|
||||
})
|
||||
]),
|
||||
h('el-form-item', {
|
||||
props: { label: _vm.$t("env:lock:msgBox:form:Password") },
|
||||
attrs: {
|
||||
style: "position: relative;"
|
||||
return
|
||||
}
|
||||
if (isOpen) {
|
||||
return
|
||||
}
|
||||
isOpen = true
|
||||
zzSessionStorage.setItem('isLock', 'true')
|
||||
DicomEvent.$emit('isLock', true)
|
||||
_vm.$msgbox({
|
||||
title: _vm.$t("env:lock:msgBox:title"),
|
||||
confirmButtonText: _vm.$t("env:lock:msgBox:confirmButtonText"),
|
||||
showClose: false,
|
||||
beforeClose: (action, instance, done) => {
|
||||
if (action === 'confirm') {
|
||||
if (!_vm.unlock.my_username) {
|
||||
_vm.$message.warning(_vm.$t("env:lock:msgBox:iupUser"))
|
||||
return
|
||||
}
|
||||
}, [
|
||||
h('input', {
|
||||
props: {
|
||||
value: _vm.unlock.my_password
|
||||
},
|
||||
ref: "unlock_my_password_input",
|
||||
attrs: {
|
||||
id: 'my_password',
|
||||
class: 'el-input__inner',
|
||||
type: _vm.unlock.view ? 'text' : 'password',
|
||||
autocomplete: 'new-password',
|
||||
style: "padding-right:25px"
|
||||
},
|
||||
on: {
|
||||
change: (event) => {
|
||||
_vm.unlock.my_password = event.target.value
|
||||
},
|
||||
input: (event) => {
|
||||
_vm.unlock.my_password = event.target.value
|
||||
if (!_vm.unlock.my_password) {
|
||||
_vm.$message.warning(_vm.$t("env:lock:msgBox:inpPassword"))
|
||||
return
|
||||
}
|
||||
var my_username = zzSessionStorage.getItem('my_username')
|
||||
var my_password = zzSessionStorage.getItem('my_password')
|
||||
let my_userid = zzSessionStorage.getItem('userId')
|
||||
let my_EMail = zzSessionStorage.getItem('my_EMail') || ''
|
||||
if (md5(_vm.unlock.my_password) === my_password && (my_username === _vm.unlock.my_username || my_EMail.toUpperCase() === _vm.unlock.my_username.toUpperCase())) {
|
||||
resetReadingRestTime().then(() => {
|
||||
})
|
||||
const closeLock = (_vm) => {
|
||||
_vm.$message.success(_vm.$t("env:lock:msgBox:lockSuccess"))
|
||||
_vm.unlock = {
|
||||
my_username: null,
|
||||
my_password: null,
|
||||
view: false
|
||||
}
|
||||
isOpen = false
|
||||
count = 0;
|
||||
isLock = null
|
||||
zzSessionStorage.removeItem('isLock')
|
||||
DicomEvent.$emit('isLock', false)
|
||||
localStorage.setItem('count', '0')
|
||||
document.querySelector('#my_username').value = null
|
||||
document.querySelector('#my_password').value = null
|
||||
setTimeout(() => {
|
||||
done()
|
||||
}, 500)
|
||||
}
|
||||
}),
|
||||
h('i', {
|
||||
attrs: {
|
||||
id: 'my_password_view',
|
||||
class: "el-icon-view",
|
||||
style: "cursor: pointer;position: absolute;top:35%;right:10px"
|
||||
},
|
||||
on: {
|
||||
click: (event) => {
|
||||
_vm.unlock.view = !_vm.unlock.view
|
||||
if (_vm.unlock.view) {
|
||||
_vm.$refs['unlock_my_password_input'].type = "text"
|
||||
} else {
|
||||
_vm.$refs['unlock_my_password_input'].type = "password"
|
||||
}
|
||||
// if (eval(process.env.VUE_APP_LOCK_FOR_PERMISSION_MFA)) {
|
||||
// sendMFAEmail({ UserId: my_userid, MfaType: 1 }).then((res) => {
|
||||
// done();
|
||||
// Vue.prototype.$MFA({
|
||||
// status: "lock",
|
||||
// UserId: my_userid,
|
||||
// EMail: res.Result,
|
||||
// username: my_username,
|
||||
// callBack: () => {
|
||||
// closeLock(_vm)
|
||||
// },
|
||||
// })
|
||||
// })
|
||||
// } else {
|
||||
closeLock(_vm)
|
||||
// }
|
||||
|
||||
} else {
|
||||
// console.log(111)
|
||||
_vm.$message.error(_vm.$t('env:lock:msgBox:userFail'))
|
||||
}
|
||||
}
|
||||
},
|
||||
message: h('div', {}, [
|
||||
h('el-form', {
|
||||
props: { labelWidth: "80px" }
|
||||
}, [
|
||||
h('el-form-item', {
|
||||
props: { label: _vm.$t("env:lock:msgBox:form:username") },
|
||||
}, [
|
||||
h('input', {
|
||||
props: {
|
||||
value: _vm.unlock.my_username
|
||||
},
|
||||
attrs: {
|
||||
id: 'my_username',
|
||||
class: 'el-input__inner',
|
||||
autocomplete: 'new-password'
|
||||
},
|
||||
on: {
|
||||
change: (event) => {
|
||||
_vm.unlock.my_username = event.target.value
|
||||
},
|
||||
input: (event) => {
|
||||
_vm.unlock.my_username = event.target.value
|
||||
}
|
||||
}
|
||||
})
|
||||
]),
|
||||
h('el-form-item', {
|
||||
props: { label: _vm.$t("env:lock:msgBox:form:Password") },
|
||||
attrs: {
|
||||
style: "position: relative;"
|
||||
}
|
||||
}),
|
||||
}, [
|
||||
h('input', {
|
||||
props: {
|
||||
value: _vm.unlock.my_password
|
||||
},
|
||||
ref: "unlock_my_password_input",
|
||||
attrs: {
|
||||
id: 'my_password',
|
||||
class: 'el-input__inner',
|
||||
type: _vm.unlock.view ? 'text' : 'password',
|
||||
autocomplete: 'new-password',
|
||||
style: "padding-right:25px"
|
||||
},
|
||||
on: {
|
||||
change: (event) => {
|
||||
_vm.unlock.my_password = event.target.value
|
||||
},
|
||||
input: (event) => {
|
||||
_vm.unlock.my_password = event.target.value
|
||||
}
|
||||
}
|
||||
}),
|
||||
h('i', {
|
||||
attrs: {
|
||||
id: 'my_password_view',
|
||||
class: "el-icon-view",
|
||||
style: "cursor: pointer;position: absolute;top:35%;right:10px"
|
||||
},
|
||||
on: {
|
||||
click: (event) => {
|
||||
_vm.unlock.view = !_vm.unlock.view
|
||||
if (_vm.unlock.view) {
|
||||
_vm.$refs['unlock_my_password_input'].type = "text"
|
||||
} else {
|
||||
_vm.$refs['unlock_my_password_input'].type = "password"
|
||||
}
|
||||
},
|
||||
}
|
||||
}),
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
})
|
||||
} : () => { }, process.env.VUE_APP_LOCK_FOR_TIME)
|
||||
})
|
||||
} : () => { },
|
||||
process.env.VUE_APP_LOCK_FOR_TIME
|
||||
)
|
||||
}
|
||||
VueInit()
|
||||
// createVersionPolling({
|
||||
|
||||
@@ -15,7 +15,7 @@ NProgress.configure({ showSpinner: false })
|
||||
|
||||
const whiteList = WHITELIST
|
||||
store.state.trials.whiteList = whiteList
|
||||
router.beforeEach(async(to, from, next) => {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start()
|
||||
// 设置页面标题
|
||||
// document.title = getPageTitle(to.meta.title) store.state.trials.whiteList.indexOf(to.path) === -1
|
||||
@@ -60,7 +60,7 @@ router.beforeEach(async(to, from, next) => {
|
||||
Vue.prototype.toPath = to.path
|
||||
Vue.prototype.$path = []
|
||||
if (hasToken) {
|
||||
if (to.path === '/login' || to.path === '/recompose' || to.path === '/email-recompose' || to.path === '/error' || to.path === '/ReviewersResearchForm' || to.path === '/ReviewersResearch') {
|
||||
if (to.path === '/login' || to.path === '/recompose' || to.path === '/email-recompose' || to.path === '/link_expired' || to.path === '/error' || to.path === '/ReviewersResearchForm' || to.path === '/ReviewersResearch') {
|
||||
if (to.path === '/ReviewersResearch') {
|
||||
await OSSclient()
|
||||
await store.dispatch('user/logout')
|
||||
|
||||
@@ -128,6 +128,11 @@ export const constantRoutes = [
|
||||
hidden: true,
|
||||
component: () => import('@/views/none-dicom-show/index')
|
||||
},
|
||||
{
|
||||
path: '/none_dicoms',
|
||||
hidden: true,
|
||||
component: () => import('@/views/none-dicoms/index')
|
||||
},
|
||||
{
|
||||
path: '/noneDicomReading',
|
||||
name: 'noneDicomReading',
|
||||
@@ -156,12 +161,6 @@ export const constantRoutes = [
|
||||
hidden: true,
|
||||
component: () => import('@/views/trials/trials-panel/reading/dicoms/components/Fusion/PetCt')
|
||||
},
|
||||
{
|
||||
path: '/fusion',
|
||||
name: 'fusion',
|
||||
hidden: true,
|
||||
component: () => import('@/views/trials/trials-panel/reading/dicoms/components/Fusion/demo/index')
|
||||
},
|
||||
|
||||
{
|
||||
path: '/historyScreenshot',
|
||||
@@ -284,6 +283,11 @@ export const constantRoutes = [
|
||||
component: () => import('@/views/error'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/link_expired',
|
||||
component: () => import('@/views/linkExpired'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/404'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
|
||||
title: 'EIC lmaging Trial Management System',
|
||||
title: 'HASC lmaging Trial Management System',
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
|
||||
@@ -128,7 +128,14 @@ const actions = {
|
||||
if (response.IsSuccess) {
|
||||
var noticeList = []
|
||||
response.Result.forEach(el => {
|
||||
noticeList.push({ Id: el.Id, Content: el.NoticeContent, NoticeTypeEnum: el.NoticeTypeEnum })
|
||||
noticeList.push({
|
||||
Id: el.Id,
|
||||
Content: el.NoticeContent,
|
||||
NoticeTypeEnum: el.NoticeTypeEnum,
|
||||
PublishedTime: el.PublishedTime,
|
||||
FileName: el.FileName,
|
||||
Path: el.Path
|
||||
})
|
||||
})
|
||||
|
||||
commit('SET_NOTICE', noticeList)
|
||||
|
||||
@@ -79,7 +79,7 @@ function getQuestions(questions) {
|
||||
answerObj.angle = angle
|
||||
answerObj.saveTypeEnum = isNaN(parseFloat(angle)) ? 1 : 2
|
||||
}
|
||||
} else if (criterionType === 21) {
|
||||
} else if (criterionType === 21 || criterionType === 22) {
|
||||
// MRI-PDFF
|
||||
let isMeasurable = getQuestionAnswer(item.TableQuestions.Questions, 1105, answerObj)
|
||||
answerObj.isMeasurable = isMeasurable
|
||||
@@ -932,6 +932,12 @@ const actions = {
|
||||
data.IsDicom = study.IsDicom
|
||||
data.PreviewImageCount = 0
|
||||
data.IsCriticalSequence = study.IsCriticalSequence
|
||||
data.PatientSex = study.PatientSex
|
||||
data.PatientWeight = study.PatientWeight
|
||||
data.RadionuclideHalfLife = study.RadionuclideHalfLife
|
||||
data.RadionuclideTotalDose = study.RadionuclideTotalDose
|
||||
data.RadiopharmaceuticalStartTime = study.RadiopharmaceuticalStartTime
|
||||
data.AcquisitionTime = study.AcquisitionTime
|
||||
var seriesList = []
|
||||
study.SeriesList.forEach((series, seriesIndex) => {
|
||||
const imageIds = []
|
||||
|
||||
@@ -121,7 +121,7 @@ const actions = {
|
||||
localStorage.setItem('CompanyInfo', JSON.stringify(response.Result.CompanyInfo))
|
||||
const data = response.Result
|
||||
commit('SET_ROLES', data.BasicInfo.AccountList)
|
||||
if (data.BasicInfo.IsFirstAdd || data.BasicInfo.LoginState === 1) {
|
||||
if (data.BasicInfo.IsFirstAdd || data.BasicInfo.LoginState === 1 || data.BasicInfo.IsNeedResetPwd) {
|
||||
try {
|
||||
zzSessionStorage.setItem('userId', data.BasicInfo.Id)
|
||||
commit('SET_TOKEN', data.JWTStr)
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
@import "./variables.module.scss";
|
||||
@import "./mixin.scss";
|
||||
@import "./transition.scss";
|
||||
@import "./element-ui.scss";
|
||||
@import "./sidebar.scss";
|
||||
@use "./variables.module.scss";
|
||||
@use "./mixin.scss";
|
||||
@use "./transition.scss";
|
||||
@use "./element-ui.scss";
|
||||
@use "./sidebar.scss";
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
|
||||
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
// font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
||||
// "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial,
|
||||
@@ -205,139 +206,143 @@ body .el-table th.gutter {
|
||||
.el-descriptions {
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
color: #303133
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-descriptions__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-descriptions__title {
|
||||
font-size: 16px;
|
||||
font-weight: 700
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.el-descriptions__body {
|
||||
color: #606266;
|
||||
background-color: #fff
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
table-layout: fixed
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell {
|
||||
box-sizing: border-box;
|
||||
text-align: left;
|
||||
font-weight: 400;
|
||||
line-height: 1.5
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-left {
|
||||
text-align: left
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center {
|
||||
text-align: center
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right {
|
||||
text-align: right
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.el-descriptions .is-bordered {
|
||||
table-layout: auto
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
.el-descriptions .is-bordered .el-descriptions-item__cell {
|
||||
border: 1px solid #ebeef5;
|
||||
padding: 12px 10px
|
||||
padding: 12px 10px;
|
||||
}
|
||||
|
||||
.el-descriptions :not(.is-bordered) .el-descriptions-item__cell {
|
||||
padding-bottom: 12px
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.el-descriptions--medium.is-bordered .el-descriptions-item__cell {
|
||||
padding: 10px
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.el-descriptions--medium:not(.is-bordered) .el-descriptions-item__cell {
|
||||
padding-bottom: 10px
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.el-descriptions--small {
|
||||
font-size: 12px
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-descriptions--small.is-bordered .el-descriptions-item__cell {
|
||||
padding: 8px 10px
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.el-descriptions--small:not(.is-bordered) .el-descriptions-item__cell {
|
||||
padding-bottom: 8px
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.el-descriptions--mini {
|
||||
font-size: 12px
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-descriptions--mini.is-bordered .el-descriptions-item__cell {
|
||||
padding: 6px 10px
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.el-descriptions--mini:not(.is-bordered) .el-descriptions-item__cell {
|
||||
padding-bottom: 6px
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.el-descriptions-item {
|
||||
vertical-align: top
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.el-descriptions-item__container {
|
||||
display: flex
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.el-descriptions-item__container .el-descriptions-item__content,
|
||||
.el-descriptions-item__container .el-descriptions-item__label {
|
||||
display: inline-flex;
|
||||
align-items: baseline
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.el-descriptions-item__container .el-descriptions-item__content {
|
||||
flex: 1
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.el-descriptions-item__label.has-colon:after {
|
||||
content: ":";
|
||||
position: relative;
|
||||
top: -.5px
|
||||
top: -0.5px;
|
||||
}
|
||||
|
||||
.el-descriptions-item__label.is-bordered-label {
|
||||
font-weight: 700;
|
||||
color: #909399;
|
||||
background: #fafafa
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.el-descriptions-item__label:not(.is-bordered-label) {
|
||||
margin-right: 10px
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.el-descriptions-item__content {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.feedBack-box {
|
||||
.el-dialog__wrapper {
|
||||
z-index: 3999 !important;
|
||||
}
|
||||
|
||||
.el-popper {
|
||||
z-index: 4000 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.feedBack-select-box {
|
||||
@@ -350,7 +355,7 @@ body .el-table th.gutter {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
background: #000;
|
||||
z-index: 3999;
|
||||
}
|
||||
@@ -371,4 +376,8 @@ body .el-table th.gutter {
|
||||
height: 20px !important;
|
||||
vertical-align: -0.4em !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mobile_confirm {
|
||||
width: 200px;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import defaultSettings from '@/settings'
|
||||
|
||||
const title = defaultSettings.title || 'EIC lmaging Trial Management System'
|
||||
const title = defaultSettings.title || 'HASC 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;
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function isNMReconstructable(imageSubType) {
|
||||
return imageSubType === 'RECON TOMO' || imageSubType === 'RECON GATED TOMO';
|
||||
}
|
||||
@@ -1,25 +1,123 @@
|
||||
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
|
||||
import * as cornerstoneWADOImageLoader from "cornerstone-wado-image-loader";
|
||||
import store from "@/store";
|
||||
import { getPTClinicalDataForInstance } from "@/utils/ptClinicalDataCache";
|
||||
import {
|
||||
getImageTypeSubItemFromDataset,
|
||||
extractOrientationFromDataset,
|
||||
extractPositionFromDataset,
|
||||
extractSpacingFromDataset,
|
||||
extractSliceThicknessFromDataset,
|
||||
} from "./extractPositioningFromDataset";
|
||||
|
||||
function toNumber(val) {
|
||||
if (val === undefined || val === null || val === "") return null;
|
||||
const n = typeof val === "number" ? val : parseFloat(val);
|
||||
return Number.isFinite(n) ? n : null;
|
||||
}
|
||||
|
||||
function normalizeDicomTime(value) {
|
||||
if (value === undefined || value === null || value === "") return null;
|
||||
const num = toNumber(value);
|
||||
if (num != null) {
|
||||
return String(Math.floor(num)).padStart(6, "0");
|
||||
}
|
||||
if (typeof value !== "string") return null;
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return null;
|
||||
const plain = trimmed.replace(/:/g, "");
|
||||
const parts = plain.split(".");
|
||||
const main = parts[0];
|
||||
const fractional = parts[1];
|
||||
if (!/^\d+$/.test(main)) {
|
||||
return trimmed;
|
||||
}
|
||||
const normalizedMain = main.padStart(6, "0");
|
||||
return fractional ? `${normalizedMain}.${fractional}` : normalizedMain;
|
||||
}
|
||||
|
||||
function getPTClinicalOverrideFromImageId(imageId) {
|
||||
try {
|
||||
const qIndex = imageId.indexOf("?");
|
||||
if (qIndex === -1) return null;
|
||||
const params = new URLSearchParams(imageId.slice(qIndex + 1));
|
||||
const visitTaskId = params.get("visitTaskId");
|
||||
const idx = params.get("idx");
|
||||
|
||||
// 场景1:trials/dicoms,imageId 带 visitTaskId + idx,优先使用列表中的最新 study 值
|
||||
if (visitTaskId && idx) {
|
||||
const parts = idx.split("|");
|
||||
const studyIndex = toNumber(parts[0]);
|
||||
if (Number.isInteger(studyIndex) && studyIndex >= 0) {
|
||||
const visitTaskList = store.state.reading.visitTaskList;
|
||||
if (Array.isArray(visitTaskList)) {
|
||||
const visitTaskInfo = visitTaskList.find(
|
||||
(v) => v && String(v.VisitTaskId) === visitTaskId
|
||||
);
|
||||
const study = visitTaskInfo?.StudyList?.[studyIndex];
|
||||
if (
|
||||
study &&
|
||||
!(
|
||||
study.PatientWeight == null &&
|
||||
study.RadionuclideTotalDose == null &&
|
||||
study.RadionuclideHalfLife == null &&
|
||||
study.RadiopharmaceuticalStartTime == null &&
|
||||
study.AcquisitionTime == null &&
|
||||
study.PatientSex == null
|
||||
)
|
||||
) {
|
||||
return study;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 场景2:src/components/Dicom,imageId 仅带 instanceId,回退到实例缓存
|
||||
const instanceId = params.get("instanceId");
|
||||
if (instanceId) {
|
||||
const cached = getPTClinicalDataForInstance(instanceId);
|
||||
if (cached) return cached;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function parseImageId(imageId) {
|
||||
// build a url by parsing out the url scheme and frame index from the imageId
|
||||
const firstColonIndex = imageId.indexOf(':');
|
||||
|
||||
let url = imageId.substring(firstColonIndex + 1);
|
||||
const frameIndex = url.indexOf('frame=');
|
||||
|
||||
// 兼容 frame 参数不在最后的情况:只移除 frame 参数本身,保留 instanceId/visitTaskId/idx 等其余 query
|
||||
const firstColonIndex = imageId.indexOf(":");
|
||||
const scheme = imageId.substr(0, firstColonIndex);
|
||||
const urlPart = imageId.substring(firstColonIndex + 1);
|
||||
let url = urlPart;
|
||||
let frame;
|
||||
const qIndex = urlPart.indexOf("?");
|
||||
if (qIndex !== -1) {
|
||||
const base = urlPart.slice(0, qIndex);
|
||||
const query = urlPart.slice(qIndex + 1);
|
||||
const parts = query.split("&").filter(Boolean);
|
||||
const preservedParts = [];
|
||||
|
||||
if (frameIndex !== -1) {
|
||||
const frameStr = url.substr(frameIndex + 6);
|
||||
parts.forEach((part) => {
|
||||
const eqIndex = part.indexOf("=");
|
||||
const key = eqIndex === -1 ? part : part.slice(0, eqIndex);
|
||||
const value = eqIndex === -1 ? "" : part.slice(eqIndex + 1);
|
||||
|
||||
frame = parseInt(frameStr, 10);
|
||||
url = url.substr(0, frameIndex - 1);
|
||||
if (key === "frame") {
|
||||
const n = value !== "" ? parseInt(value, 10) : NaN;
|
||||
if (Number.isFinite(n)) {
|
||||
frame = n;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 保留原始 query 片段,避免 URLSearchParams 把 | 编码成 %7C 导致 dataSetCache key 对不上
|
||||
preservedParts.push(part);
|
||||
});
|
||||
|
||||
url = preservedParts.length ? `${base}?${preservedParts.join("&")}` : base;
|
||||
}
|
||||
|
||||
return {
|
||||
scheme: imageId.substr(0, firstColonIndex),
|
||||
url,
|
||||
frame,
|
||||
};
|
||||
return { scheme, url, frame };
|
||||
}
|
||||
function getNumberValues(dataSet, tag, minimumLength) {
|
||||
const values = [];
|
||||
@@ -28,7 +126,7 @@ function getNumberValues(dataSet, tag, minimumLength) {
|
||||
if (!valueAsString) {
|
||||
return;
|
||||
}
|
||||
const split = valueAsString.split('\\');
|
||||
const split = valueAsString.split("\\");
|
||||
|
||||
if (minimumLength && split.length < minimumLength) {
|
||||
return;
|
||||
@@ -67,28 +165,31 @@ function getLutData(lutDataSet, tag, lutDescriptor) {
|
||||
return lut;
|
||||
}
|
||||
function populateSmallestLargestPixelValues(dataSet, imagePixelModule) {
|
||||
const pixelRepresentation = dataSet.uint16('x00280103');
|
||||
const pixelRepresentation = dataSet.uint16("x00280103");
|
||||
if (pixelRepresentation === 0) {
|
||||
imagePixelModule.smallestPixelValue = dataSet.uint16('x00280106');
|
||||
imagePixelModule.largestPixelValue = dataSet.uint16('x00280107');
|
||||
imagePixelModule.smallestPixelValue = dataSet.uint16("x00280106");
|
||||
imagePixelModule.largestPixelValue = dataSet.uint16("x00280107");
|
||||
} else {
|
||||
imagePixelModule.smallestPixelValue = dataSet.int16('x00280106');
|
||||
imagePixelModule.largestPixelValue = dataSet.int16('x00280107');
|
||||
imagePixelModule.smallestPixelValue = dataSet.int16("x00280106");
|
||||
imagePixelModule.largestPixelValue = dataSet.int16("x00280107");
|
||||
}
|
||||
imagePixelModule.largestPixelValue = imagePixelModule.largestPixelValue === 0 ? undefined : imagePixelModule.largestPixelValue;
|
||||
imagePixelModule.largestPixelValue =
|
||||
imagePixelModule.largestPixelValue === 0
|
||||
? undefined
|
||||
: imagePixelModule.largestPixelValue;
|
||||
}
|
||||
function populatePaletteColorLut(dataSet, imagePixelModule) {
|
||||
imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor(
|
||||
dataSet,
|
||||
'x00281101'
|
||||
"x00281101"
|
||||
);
|
||||
imagePixelModule.greenPaletteColorLookupTableDescriptor = getLutDescriptor(
|
||||
dataSet,
|
||||
'x00281102'
|
||||
"x00281102"
|
||||
);
|
||||
imagePixelModule.bluePaletteColorLookupTableDescriptor = getLutDescriptor(
|
||||
dataSet,
|
||||
'x00281103'
|
||||
"x00281103"
|
||||
);
|
||||
|
||||
// The first Palette Color Lookup Table Descriptor value is the number of entries in the lookup table.
|
||||
@@ -127,33 +228,196 @@ function populatePaletteColorLut(dataSet, imagePixelModule) {
|
||||
|
||||
imagePixelModule.redPaletteColorLookupTableData = getLutData(
|
||||
dataSet,
|
||||
'x00281201',
|
||||
"x00281201",
|
||||
imagePixelModule.redPaletteColorLookupTableDescriptor
|
||||
);
|
||||
imagePixelModule.greenPaletteColorLookupTableData = getLutData(
|
||||
dataSet,
|
||||
'x00281202',
|
||||
"x00281202",
|
||||
imagePixelModule.greenPaletteColorLookupTableDescriptor
|
||||
);
|
||||
imagePixelModule.bluePaletteColorLookupTableData = getLutData(
|
||||
dataSet,
|
||||
'x00281203',
|
||||
"x00281203",
|
||||
imagePixelModule.bluePaletteColorLookupTableDescriptor
|
||||
);
|
||||
}
|
||||
|
||||
function getSpacingBetweenSlices(dataSet) {
|
||||
if (dataSet?.elements?.x00180088) {
|
||||
return dataSet.floatString("x00180088");
|
||||
}
|
||||
const pixelMeasuresSequence = dataSet?.elements?.x00289110;
|
||||
if (
|
||||
pixelMeasuresSequence?.items?.length &&
|
||||
pixelMeasuresSequence.items[0]?.dataSet?.elements?.x00180088
|
||||
) {
|
||||
return pixelMeasuresSequence.items[0].dataSet.floatString("x00180088");
|
||||
}
|
||||
}
|
||||
function metaDataProvider(type, imageId) {
|
||||
const parsedImageId = parseImageId(imageId);
|
||||
const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(parsedImageId.url);
|
||||
const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(
|
||||
parsedImageId.url
|
||||
);
|
||||
|
||||
if (!dataSet) {
|
||||
return;
|
||||
}
|
||||
if (type === 'imagePlaneModule') {
|
||||
const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6);
|
||||
const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
|
||||
const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
|
||||
const imagePixelSpacing = getNumberValues(dataSet, 'x00181164', 2);
|
||||
const estimatedRadiographicMagnificationFactor = getNumberValues(dataSet, 'x00181114', 2);
|
||||
const ptOverride = getPTClinicalOverrideFromImageId(imageId);
|
||||
if (type === "generalSeriesModule") {
|
||||
const { dicomParser } = cornerstoneWADOImageLoader.external || {};
|
||||
const overrideTime = normalizeDicomTime(ptOverride?.AcquisitionTime);
|
||||
const seriesTimeRaw =
|
||||
overrideTime ||
|
||||
dataSet.string("x00080031") ||
|
||||
dataSet.string("x00080032") ||
|
||||
"";
|
||||
const acquisitionTimeRaw =
|
||||
overrideTime ||
|
||||
dataSet.string("x00080032") ||
|
||||
dataSet.string("x00080031") ||
|
||||
"";
|
||||
return {
|
||||
modality: dataSet.string("x00080060"),
|
||||
seriesInstanceUID: dataSet.string("x0020000e"),
|
||||
seriesNumber: dataSet.intString("x00200011"),
|
||||
studyInstanceUID: dataSet.string("x0020000d"),
|
||||
seriesDate: dicomParser.parseDA(dataSet.string("x00080021")),
|
||||
// 2D SUV 计算读取的是 seriesTime,这里同步使用用户录入采集时间
|
||||
// seriesTime: dicomParser.parseTM(String(seriesTimeRaw)),
|
||||
seriesTime: dicomParser.parseTM(dataSet.string('x00080031') || ''),
|
||||
acquisitionDate: dicomParser.parseDA(dataSet.string("x00080022") || ""),
|
||||
acquisitionTime: dicomParser.parseTM(String(acquisitionTimeRaw)),
|
||||
};
|
||||
}
|
||||
if (type === "patientStudyModule") {
|
||||
const weightOverride = ptOverride?.PatientWeight;
|
||||
const weight =
|
||||
weightOverride
|
||||
? toNumber(weightOverride)
|
||||
: dataSet.floatString("x00101030");
|
||||
return {
|
||||
patientAge: dataSet.intString("x00101010"),
|
||||
patientSize: dataSet.floatString("x00101020"),
|
||||
patientWeight: weight,
|
||||
};
|
||||
}
|
||||
|
||||
if (type === "petIsotopeModule") {
|
||||
const { dicomParser } = cornerstoneWADOImageLoader.external || {};
|
||||
const radiopharmaceuticalInfo = dataSet.elements.x00540016;
|
||||
|
||||
if (radiopharmaceuticalInfo === undefined) {
|
||||
return;
|
||||
}
|
||||
const firstRadiopharmaceuticalInfoDataSet =
|
||||
radiopharmaceuticalInfo.items[0].dataSet;
|
||||
|
||||
const startTimeRaw =
|
||||
firstRadiopharmaceuticalInfoDataSet.string("x00181072") || "";
|
||||
const totalDoseRaw =
|
||||
firstRadiopharmaceuticalInfoDataSet.floatString("x00181074");
|
||||
const halfLifeRaw =
|
||||
firstRadiopharmaceuticalInfoDataSet.floatString("x00181075");
|
||||
let startTimeValue = normalizeDicomTime(
|
||||
ptOverride?.RadiopharmaceuticalStartTime
|
||||
);
|
||||
if (!startTimeValue && startTimeRaw) {
|
||||
startTimeValue = normalizeDicomTime(startTimeRaw) || startTimeRaw;
|
||||
}
|
||||
const radiopharmaceuticalStartTime = dicomParser.parseTM(
|
||||
String(startTimeValue)
|
||||
);
|
||||
const overrideTotalDose =
|
||||
ptOverride?.RadionuclideTotalDose != null &&
|
||||
ptOverride.RadionuclideTotalDose !== ""
|
||||
? toNumber(ptOverride.RadionuclideTotalDose)
|
||||
: null;
|
||||
const overrideHalfLife =
|
||||
ptOverride?.RadionuclideHalfLife != null &&
|
||||
ptOverride.RadionuclideHalfLife !== ""
|
||||
? toNumber(ptOverride.RadionuclideHalfLife)
|
||||
: null;
|
||||
const radionuclideTotalDose =
|
||||
overrideTotalDose != null ? overrideTotalDose : toNumber(totalDoseRaw);
|
||||
const radionuclideHalfLife =
|
||||
overrideHalfLife != null ? overrideHalfLife : toNumber(halfLifeRaw);
|
||||
return {
|
||||
radiopharmaceuticalInfo: {
|
||||
radiopharmaceuticalStartTime,
|
||||
radionuclideTotalDose,
|
||||
radionuclideHalfLife,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (type === "imagePlaneModule") {
|
||||
// const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6);
|
||||
// const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
|
||||
// const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
|
||||
const imagePixelSpacing = getNumberValues(dataSet, "x00181164", 2);
|
||||
const frameIndex =
|
||||
parsedImageId.frame !== undefined ? parsedImageId.frame - 1 : undefined;
|
||||
const imageOrientationPatient = extractOrientationFromDataset(
|
||||
dataSet,
|
||||
frameIndex
|
||||
);
|
||||
let imagePositionPatient = extractPositionFromDataset(dataSet, frameIndex);
|
||||
const pixelSpacing = extractSpacingFromDataset(dataSet, frameIndex);
|
||||
const sliceThickness = extractSliceThicknessFromDataset(
|
||||
dataSet,
|
||||
frameIndex
|
||||
);
|
||||
|
||||
const modality = dataSet.string("x00080060");
|
||||
if (
|
||||
modality &&
|
||||
modality.includes("NM") &&
|
||||
parsedImageId.frame !== undefined &&
|
||||
parsedImageId.frame > 1
|
||||
) {
|
||||
const spacingBetweenSlices = getSpacingBetweenSlices(dataSet);
|
||||
const step =
|
||||
spacingBetweenSlices !== undefined
|
||||
? spacingBetweenSlices
|
||||
: sliceThickness;
|
||||
if (
|
||||
imageOrientationPatient &&
|
||||
imagePositionPatient &&
|
||||
step !== undefined &&
|
||||
frameIndex !== undefined
|
||||
) {
|
||||
const rowCosines = [
|
||||
parseFloat(imageOrientationPatient[0]),
|
||||
parseFloat(imageOrientationPatient[1]),
|
||||
parseFloat(imageOrientationPatient[2]),
|
||||
];
|
||||
const columnCosines = [
|
||||
parseFloat(imageOrientationPatient[3]),
|
||||
parseFloat(imageOrientationPatient[4]),
|
||||
parseFloat(imageOrientationPatient[5]),
|
||||
];
|
||||
const normal = [
|
||||
rowCosines[1] * columnCosines[2] - rowCosines[2] * columnCosines[1],
|
||||
rowCosines[2] * columnCosines[0] - rowCosines[0] * columnCosines[2],
|
||||
rowCosines[0] * columnCosines[1] - rowCosines[1] * columnCosines[0],
|
||||
];
|
||||
|
||||
const offset = frameIndex * parseFloat(step);
|
||||
|
||||
imagePositionPatient = [
|
||||
parseFloat(imagePositionPatient[0]) + normal[0] * offset,
|
||||
parseFloat(imagePositionPatient[1]) + normal[1] * offset,
|
||||
parseFloat(imagePositionPatient[2]) + normal[2] * offset,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
const estimatedRadiographicMagnificationFactor = getNumberValues(
|
||||
dataSet,
|
||||
"x00181114",
|
||||
2
|
||||
);
|
||||
let columnPixelSpacing = null;
|
||||
|
||||
let rowPixelSpacing = null;
|
||||
@@ -162,8 +426,10 @@ function metaDataProvider(type, imageId) {
|
||||
rowPixelSpacing = pixelSpacing[0];
|
||||
columnPixelSpacing = pixelSpacing[1];
|
||||
} else if (imagePixelSpacing && estimatedRadiographicMagnificationFactor) {
|
||||
rowPixelSpacing = imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0];
|
||||
columnPixelSpacing = imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1];
|
||||
rowPixelSpacing =
|
||||
imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0];
|
||||
columnPixelSpacing =
|
||||
imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1];
|
||||
} else if (imagePixelSpacing && !estimatedRadiographicMagnificationFactor) {
|
||||
rowPixelSpacing = imagePixelSpacing[0];
|
||||
columnPixelSpacing = imagePixelSpacing[1];
|
||||
@@ -187,43 +453,48 @@ function metaDataProvider(type, imageId) {
|
||||
}
|
||||
|
||||
return {
|
||||
frameOfReferenceUID: dataSet.string('x00200052'),
|
||||
rows: dataSet.uint16('x00280010'),
|
||||
columns: dataSet.uint16('x00280011'),
|
||||
frameOfReferenceUID: dataSet.string("x00200052"),
|
||||
rows: dataSet.uint16("x00280010"),
|
||||
columns: dataSet.uint16("x00280011"),
|
||||
imageOrientationPatient,
|
||||
rowCosines,
|
||||
columnCosines,
|
||||
imagePositionPatient,
|
||||
sliceThickness: dataSet.floatString('x00180050'),
|
||||
sliceLocation: dataSet.floatString('x00201041'),
|
||||
sliceThickness,
|
||||
sliceLocation: dataSet.floatString("x00201041"),
|
||||
pixelSpacing,
|
||||
rowPixelSpacing,
|
||||
columnPixelSpacing,
|
||||
};
|
||||
}
|
||||
if (type === 'imagePixelModule') {
|
||||
if (type === "imagePixelModule") {
|
||||
const imagePixelModule = {
|
||||
samplesPerPixel: dataSet.uint16('x00280002'),
|
||||
photometricInterpretation: dataSet.string('x00280004'),
|
||||
rows: dataSet.uint16('x00280010'),
|
||||
columns: dataSet.uint16('x00280011'),
|
||||
bitsAllocated: dataSet.uint16('x00280100'),
|
||||
bitsStored: dataSet.uint16('x00280101'),
|
||||
highBit: dataSet.uint16('x00280102'),
|
||||
pixelRepresentation: dataSet.uint16('x00280103'),
|
||||
planarConfiguration: dataSet.uint16('x00280006'),
|
||||
pixelAspectRatio: dataSet.string('x00280034'),
|
||||
samplesPerPixel: dataSet.uint16("x00280002"),
|
||||
photometricInterpretation: dataSet.string("x00280004"),
|
||||
rows: dataSet.uint16("x00280010"),
|
||||
columns: dataSet.uint16("x00280011"),
|
||||
bitsAllocated: dataSet.uint16("x00280100"),
|
||||
bitsStored: dataSet.uint16("x00280101"),
|
||||
highBit: dataSet.uint16("x00280102"),
|
||||
pixelRepresentation: dataSet.uint16("x00280103"),
|
||||
planarConfiguration: dataSet.uint16("x00280006"),
|
||||
pixelAspectRatio: dataSet.string("x00280034"),
|
||||
};
|
||||
populateSmallestLargestPixelValues(dataSet, imagePixelModule);
|
||||
|
||||
if (
|
||||
imagePixelModule.photometricInterpretation === 'PALETTE COLOR' &&
|
||||
imagePixelModule.photometricInterpretation === "PALETTE COLOR" &&
|
||||
dataSet.elements.x00281101
|
||||
) {
|
||||
populatePaletteColorLut(dataSet, imagePixelModule);
|
||||
}
|
||||
return imagePixelModule;
|
||||
}
|
||||
// if (type === "multiframeModule") {
|
||||
// return {
|
||||
// NumberOfFrames: dataSet.uint16("x00280008") || dataSet.string("x00280008")
|
||||
// };
|
||||
// }
|
||||
// if (type === 'imagePixelModule') {
|
||||
// return {
|
||||
// samplesPerPixel: dataSet.uint16('x00280002'),
|
||||
@@ -249,4 +520,4 @@ function metaDataProvider(type, imageId) {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
export default metaDataProvider;
|
||||
export default metaDataProvider;
|
||||
|
||||
@@ -5,6 +5,7 @@ const stream = require('stream')
|
||||
import Vue from 'vue'
|
||||
import { customerHttp, OSSclose } from "@/utils/multipartUpload/oss"
|
||||
import { exist, AWSclose } from "@/utils/multipartUpload/aws"
|
||||
import { addOrUpdateFileUploadRecord } from '@/api/file'
|
||||
const { GetObjectStoreToken } = require('../api/user.js')
|
||||
const {
|
||||
S3Client,
|
||||
@@ -22,7 +23,6 @@ async function ossGenerateSTS() {
|
||||
res = await GetObjectStoreToken()
|
||||
localStorage.setItem('stsToken', JSON.stringify(res))
|
||||
}
|
||||
|
||||
// res.Result.ObjectStoreUse = 'AWS';
|
||||
Vue.prototype.OSSclientConfig = { ...res.Result[res.Result.ObjectStoreUse] }
|
||||
Vue.prototype.OSSclientConfig.ObjectStoreUse = res.Result.ObjectStoreUse;
|
||||
@@ -34,7 +34,8 @@ async function ossGenerateSTS() {
|
||||
Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000
|
||||
let OSSclient = new OSS(Vue.prototype.OSSclientConfig)
|
||||
Vue.prototype.OSSclient = {
|
||||
put: async function (objectName, object) {
|
||||
put: async function (objectName, object, fileInfo = {}) {
|
||||
|
||||
OSSclient = await RefreshClient(OSSclient)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
@@ -52,6 +53,20 @@ async function ossGenerateSTS() {
|
||||
}
|
||||
let res = await OSSclient.put(objectName, object)
|
||||
if (res && res.url) {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const trialId = urlParams.get('trialId')
|
||||
if (Object.keys(fileInfo).length !== 0) {
|
||||
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
|
||||
let params = Object.assign({path: objectName}, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
const fileName = objectName.split('/').pop()
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
let params = { trialId, path: objectName, fileName, fileType }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
resolve({
|
||||
name: objectName,
|
||||
url: res.url
|
||||
@@ -65,7 +80,7 @@ async function ossGenerateSTS() {
|
||||
}
|
||||
})
|
||||
},
|
||||
multipartUpload: async (data, progress) => {
|
||||
multipartUpload: async (data, progress, fileInfo = {}) => {
|
||||
OSSclient = await RefreshClient(OSSclient)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
@@ -95,6 +110,21 @@ async function ossGenerateSTS() {
|
||||
}
|
||||
let res = await customerHttp(OSSclient, data, progress);
|
||||
if (res) {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const trialId = urlParams.get('trialId')
|
||||
if (Object.keys(fileInfo).length !== 0) {
|
||||
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
|
||||
let params = Object.assign({path: data.path}, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
const fileName = data.path.split('/').pop()
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
let params = { trialId, path: data.path, fileName, fileType }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
|
||||
resolve({
|
||||
name: data.path,
|
||||
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name)
|
||||
@@ -169,17 +199,17 @@ async function ossGenerateSTS() {
|
||||
}
|
||||
});
|
||||
Vue.prototype.OSSclient = {
|
||||
put: async function (objectName, object) {
|
||||
put: async function (objectName, object, fileInfo = {}) {
|
||||
let data = {
|
||||
file: object,
|
||||
path: objectName
|
||||
}
|
||||
aws = await RefreshClient(aws);
|
||||
return uploadAWS(aws, data, () => { });
|
||||
return uploadAWS(aws, data, () => { }, fileInfo);
|
||||
},
|
||||
multipartUpload: async (data, progress) => {
|
||||
multipartUpload: async (data, progress, fileInfo = {}) => {
|
||||
aws = await RefreshClient(aws);
|
||||
return uploadAWS(aws, data, progress);
|
||||
return uploadAWS(aws, data, progress, fileInfo);
|
||||
},
|
||||
close: () => {
|
||||
AWSclose();
|
||||
@@ -189,7 +219,7 @@ async function ossGenerateSTS() {
|
||||
return
|
||||
}
|
||||
// AWS上传函数
|
||||
function uploadAWS(aws, data, progress) {
|
||||
function uploadAWS(aws, data, progress, fileInfo) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const { file, path } = data;
|
||||
@@ -211,6 +241,21 @@ function uploadAWS(aws, data, progress) {
|
||||
data.path = data.path.replace(`/${bucketName}/`, '');
|
||||
await exist(aws, bucketName, data, progress, (path, status) => {
|
||||
if (status === 'success') {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
|
||||
const trialId = urlParams.get('trialId')
|
||||
if (Object.keys(fileInfo).length !== 0) {
|
||||
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
|
||||
let params = Object.assign({path: decodeUtf8(curPath)}, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
const fileName = decodeUtf8(curPath).split('/').pop()
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
let params = { trialId, path: decodeUtf8(curPath), fileName, fileType }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
resolve({
|
||||
name: decodeUtf8(curPath),
|
||||
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(curPath)
|
||||
@@ -320,5 +365,37 @@ function isCredentialsExpired(credentials) {
|
||||
return expireDate.getTime() - now.getTime() <= 300000;
|
||||
|
||||
}
|
||||
function mimeTypeToExt(mimeType) {
|
||||
const map = {
|
||||
// 图片
|
||||
'image/jpeg': 'jpg',
|
||||
'image/jpg': 'jpg',
|
||||
'image/png': 'png',
|
||||
'image/gif': 'gif',
|
||||
'image/webp': 'webp',
|
||||
'image/svg+xml': 'svg',
|
||||
'image/bmp': 'bmp',
|
||||
|
||||
// 文档
|
||||
'application/dicom': 'dcm',
|
||||
'application/pdf': 'pdf',
|
||||
'application/msword': 'doc',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
||||
'application/vnd.ms-excel': 'xls',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
||||
'application/vnd.ms-powerpoint': 'ppt',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
|
||||
'text/plain': 'txt',
|
||||
// 音频/视频
|
||||
'audio/mpeg': 'mp3',
|
||||
'audio/wav': 'wav',
|
||||
'video/mp4': 'mp4',
|
||||
'video/mpeg': 'mpeg',
|
||||
// 压缩包
|
||||
'application/zip': 'zip',
|
||||
'application/x-rar-compressed': 'rar',
|
||||
'application/x-7z-compressed': '7z',
|
||||
};
|
||||
return map[mimeType] || ''; // 找不到返回空字符串
|
||||
}
|
||||
export const OSSclient = ossGenerateSTS
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// PT 临床数据缓存:用于统一 SUV 口径(优先接口,缺失则回退 DICOM 元数据)
|
||||
const instanceIdToClinicalData = new Map()
|
||||
|
||||
function normalizeId(id) {
|
||||
if (id === undefined || id === null) return null
|
||||
const s = String(id).trim()
|
||||
return s ? s : null
|
||||
}
|
||||
|
||||
export function setPTClinicalDataForInstance(instanceId, clinicalData) {
|
||||
const key = normalizeId(instanceId)
|
||||
if (!key) return
|
||||
if (!clinicalData || typeof clinicalData !== 'object') return
|
||||
instanceIdToClinicalData.set(key, { ...clinicalData })
|
||||
}
|
||||
|
||||
export function getPTClinicalDataForInstance(instanceId) {
|
||||
const key = normalizeId(instanceId)
|
||||
if (!key) return null
|
||||
return instanceIdToClinicalData.get(key) || null
|
||||
}
|
||||
|
||||
export function deletePTClinicalDataForInstance(instanceId) {
|
||||
const key = normalizeId(instanceId)
|
||||
if (!key) return
|
||||
instanceIdToClinicalData.delete(key)
|
||||
}
|
||||
|
||||
export function clearPTClinicalDataCache() {
|
||||
instanceIdToClinicalData.clear()
|
||||
}
|
||||
@@ -28,7 +28,7 @@ async function executeTask() {
|
||||
task.callback({ success: true, res: result })
|
||||
|
||||
}).catch((error) => {
|
||||
task.callback({ success: true, err: error })
|
||||
task.callback({ success: false, err: error })
|
||||
})
|
||||
})
|
||||
// let starLoadTime = performance.now()
|
||||
|
||||
@@ -21,6 +21,16 @@ var path
|
||||
|
||||
service.interceptors.request.use(
|
||||
async config => {
|
||||
if (config.url.includes("/Dictionary/getBasicDataSelect")) {
|
||||
let query = router && router.app && router.app._route && router.app._route.query
|
||||
if (query.trialId) {
|
||||
let str = config.url.split("?")
|
||||
config.url = `${str[0]}?TrialId=${query.trialId}`
|
||||
if (str[1]) {
|
||||
config.url += `&${str[1]}`
|
||||
}
|
||||
}
|
||||
}
|
||||
path = router && router.app && router.app._route && router.app._route.path
|
||||
config.headers['Content-Type'] = 'application/json;charset=UTF-8'
|
||||
// config.baseURL = process.env.NODE_ENV === 'prod' ? "https://api.irc.extimaging.com" : '/api'
|
||||
|
||||
@@ -52,18 +52,22 @@ function getScreen() {
|
||||
})
|
||||
|
||||
}
|
||||
export async function openWindow(url, name, Skip = false) {
|
||||
export async function openWindow(url, name, Skip = false, noreferrer = false) {
|
||||
// 判断浏览器是否兼容
|
||||
// 高版本的谷歌,edge不支持跨屏,需要降低浏览器版本86.0版
|
||||
let fulls = ''
|
||||
if (noreferrer) {
|
||||
fulls = 'noopener,noreferrer'
|
||||
}
|
||||
if (!window.getScreens && !window.getScreenDetails) {
|
||||
console.log('你的浏览器版本不支持多屏展示功能!');
|
||||
return window.open(url, name);
|
||||
return window.open(url, name, fulls);
|
||||
}
|
||||
let permission = await getPermission()
|
||||
if (!permission) {
|
||||
// alert('使用多屏功能请先进行授权')
|
||||
if (Skip) {
|
||||
return window.open(url, name);
|
||||
return window.open(url, name, fulls);
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -72,14 +76,13 @@ export async function openWindow(url, name, Skip = false) {
|
||||
// 判断是否2个屏幕
|
||||
if (multiScreen.length < 2) {
|
||||
console.log('请接入多个显示屏!');
|
||||
return window.open(url, name);
|
||||
return window.open(url, name, fulls);
|
||||
}
|
||||
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},`
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
const WHITELIST = ['/', "/curriculumVitae", 'researchDetail_m', '/researchForm', '/ReviewersResearch', '/login', '/error', '/resetpassword', '/recompose', '/email-recompose', '/trialStats', '/showdicom', '/imagesShare', '/audit', '/preview', '/researchLogin', '/researchLogin_m', '/blindResumeInfo', '/trialsResume', '/joinVerify', '/showNoneDicoms', '/noneDicomReading', '/clinicalData', '/readingDicoms', '/readingPage', '/visitDicomReview', '/visitNondicomReview', '/globalReview', '/adReview', '/oncologyReview', '/nonedicoms']
|
||||
const WHITELIST = ['/', "/curriculumVitae", 'researchDetail_m', '/researchForm', '/ReviewersResearch', '/login', '/link_expired', '/error', '/resetpassword', '/recompose', '/email-recompose', '/trialStats', '/showdicom', '/imagesShare', '/audit', '/preview', '/researchLogin', '/researchLogin_m', '/blindResumeInfo', '/trialsResume', '/joinVerify', '/showNoneDicoms', '/noneDicomReading', '/clinicalData', '/readingDicoms', '/readingPage', '/visitDicomReview', '/visitNondicomReview', '/globalReview', '/adReview', '/oncologyReview', '/nonedicoms']
|
||||
export default WHITELIST
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="dashboard">
|
||||
<div class="dashboard-header">
|
||||
<h1>
|
||||
<a href="#" @click="handleTitleClick">GRR Real-Time IRC Information</a>
|
||||
<a href="#" @click="handleTitleClick">GRR Real-Time HASC Information</a>
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
<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 worldMap from 'echarts-map/json/world.json';
|
||||
import { fontSize } from 'utils/fontsize'
|
||||
echarts.registerMap('world', worldMap);
|
||||
export default {
|
||||
props: {
|
||||
area: { type: String, default: '' },
|
||||
@@ -14,7 +15,7 @@ export default {
|
||||
watch: {
|
||||
area() {
|
||||
const that = this
|
||||
this.$nextTick(function() {
|
||||
this.$nextTick(function () {
|
||||
that.myChart.resize()
|
||||
})
|
||||
}
|
||||
@@ -56,7 +57,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]
|
||||
@@ -76,8 +77,8 @@ export default {
|
||||
}
|
||||
return res
|
||||
}
|
||||
var series = []
|
||||
;[['Shanghai', BJData]].forEach(function(item, i) {
|
||||
var series = [];
|
||||
[['Shanghai', BJData]].forEach(function (item, i) {
|
||||
series.push(
|
||||
{
|
||||
type: 'lines',
|
||||
@@ -125,11 +126,11 @@ export default {
|
||||
}
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: function(val) {
|
||||
symbolSize: function (val) {
|
||||
return fontSize(0.08) // 圆环大小
|
||||
},
|
||||
|
||||
data: item[1].map(function(dataItem) {
|
||||
data: item[1].map(function (dataItem) {
|
||||
return {
|
||||
name: dataItem[0].name,
|
||||
value: geoCoordMap[dataItem[0].name]
|
||||
@@ -161,7 +162,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 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<div class="dashboard-header">
|
||||
<h1>Extimaging Real-Time IRC Information</h1>
|
||||
<!-- <h1>Extimaging Real-Time HASC Information</h1> -->
|
||||
<div>
|
||||
<span>{{ currentTime }}</span>
|
||||
</div>
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
<div
|
||||
v-for="(instance, idx) in item.instanceInfoList"
|
||||
:key="instance.InstanceUid"
|
||||
class="frame_content"
|
||||
class="frame_content"
|
||||
:class="{ 'frame_content_active': activeInstanceUid === instance.InstanceUid }"
|
||||
:style="{'margin-bottom':idx<item.instanceInfoList.length-1? '5px':'0px'}"
|
||||
@click="showMultiFrames(item, index, instance)"
|
||||
>
|
||||
@@ -136,7 +137,8 @@ export default {
|
||||
studyTitle: '',
|
||||
seriesCount: 0,
|
||||
seriesList: [],
|
||||
currentSeriesIndex: -1
|
||||
currentSeriesIndex: -1,
|
||||
activeInstanceUid: null
|
||||
}
|
||||
},
|
||||
|
||||
@@ -231,6 +233,7 @@ export default {
|
||||
},
|
||||
showMultiFrames(series, seriesIndex, instanceInfo) {
|
||||
this.currentSeriesIndex = seriesIndex
|
||||
this.activeInstanceUid = instanceInfo.InstanceUid
|
||||
const imageIds = []
|
||||
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
||||
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
||||
@@ -252,6 +255,7 @@ export default {
|
||||
showSeriesImage(seriesIndex) {
|
||||
// if (seriesIndex === this.currentSeriesIndex) return;
|
||||
this.currentSeriesIndex = seriesIndex
|
||||
this.activeInstanceUid = null
|
||||
this.$refs.dicomViewer.loadImageStack(this.seriesList[seriesIndex])
|
||||
},
|
||||
closeDialog() {
|
||||
@@ -429,4 +433,8 @@ export default {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
.frame_content_active {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<div class="frame_list">
|
||||
<div v-for="(instance, idx) in item.instanceInfoList" :key="instance.Id"
|
||||
class="frame_content"
|
||||
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
:style="{ 'margin-bottom': idx < item.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||
@click="showMultiFrames(item, index, instance)">
|
||||
<div>
|
||||
@@ -72,17 +73,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;"
|
||||
@click="popperClick(seriesList, item)" />
|
||||
@click.stop="popperClick(seriesList, item)" />
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="item.instanceCount" style="padding: 1px;">
|
||||
<div v-if="item.instanceCount" style="padding: 1px;">
|
||||
{{ item.modality }}: {{ item.instanceCount }} image
|
||||
</div>
|
||||
<div v-show="!item.keySeries && item.sliceThickness" style="padding: 1px;">
|
||||
<div v-if="!item.keySeries && item.sliceThickness" style="padding: 1px;">
|
||||
T: {{ parseFloat(item.sliceThickness).toFixed(2) }}
|
||||
</div>
|
||||
<div v-show="!item.keySeries && item.description"
|
||||
<div v-if="!item.keySeries && item.description"
|
||||
style="width: 120px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;padding: 1x;">
|
||||
{{ item.description }}
|
||||
</div>
|
||||
@@ -123,12 +124,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="viewerContent">
|
||||
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" />
|
||||
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" :loading.sync="loading"
|
||||
:modality="modality" :Comparison.sync="isComparison" @loadStudy="loadStudy" />
|
||||
</div>
|
||||
<!-- <div class="viewerRightSidePanel">
|
||||
<dicom-tools />
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -202,7 +203,9 @@ export default {
|
||||
isFromCRCUpload: false,
|
||||
isReading: null,
|
||||
activeSeriesId: null,
|
||||
isPacs: false
|
||||
isPacs: false,
|
||||
isComparison: false,
|
||||
activeInstanceId: null
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
@@ -307,7 +310,7 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
async loadStudy() {
|
||||
async loadStudy(seriesId = null) {
|
||||
let params = {}
|
||||
if (this.isPacs) {
|
||||
params.IsPacs = true
|
||||
@@ -327,7 +330,7 @@ export default {
|
||||
isReading = `?IsPacs=true`
|
||||
}
|
||||
const url = `/series/list/${this.studyId}${isReading}`
|
||||
this.getSeriesList(url)
|
||||
this.getSeriesList(url, seriesId)
|
||||
}
|
||||
},
|
||||
async loadPatientStudy() {
|
||||
@@ -392,7 +395,7 @@ export default {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
async getSeriesList(url) {
|
||||
async getSeriesList(url, seriesId = null) {
|
||||
try {
|
||||
const data = await getSeriesList(url)
|
||||
if (data.IsSuccess) {
|
||||
@@ -431,12 +434,12 @@ export default {
|
||||
isDeleted: item.IsDeleted,
|
||||
previewImageUrl: item.ImageResizePath ? this.OSSclientConfig.basePath + item.ImageResizePath : `/api/series/preview/${item.Id}`,
|
||||
instanceCount: item.InstanceCount,
|
||||
prefetchInstanceCount: 0,
|
||||
prefetchInstanceCount: seriesId ? item.InstanceInfoList.length * 100 : 0,
|
||||
hasLabel: item.HasLabel,
|
||||
keySeries: item.KeySeries,
|
||||
tpCode: this.tpCode,
|
||||
loadStatus: false,
|
||||
imageloadedArr: [],
|
||||
imageloadedArr: seriesId ? imageIds : [],
|
||||
isExistMutiFrames: item.IsExistMutiFrames,
|
||||
isShowPopper: false,
|
||||
subjectCode: item.SubjectCode,
|
||||
@@ -446,8 +449,14 @@ export default {
|
||||
this.seriesList = seriesList
|
||||
if (this.seriesList.length > 0) {
|
||||
this.loadAllImages()
|
||||
this.$refs.dicomViewer.loadImageStack(this.seriesList[0], this.labels[this.tpCode])
|
||||
this.firstInstanceId = this.seriesList[0].imageIds[0]
|
||||
let index = 0;
|
||||
if (seriesId) {
|
||||
index = this.seriesList.findIndex(item => item.seriesId === seriesId)
|
||||
this.refreshImage(this.seriesList[index])
|
||||
}
|
||||
this.$refs.dicomViewer.loadImageStack(this.seriesList[index], this.labels[this.tpCode])
|
||||
this.firstInstanceId = this.seriesList[index].imageIds[0]
|
||||
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -527,7 +536,9 @@ export default {
|
||||
}
|
||||
},
|
||||
showSeriesImage(e, seriesIndex, series) {
|
||||
if (this.isComparison) return false
|
||||
this.activeSeriesId = series.seriesId
|
||||
this.activeInstanceId = null
|
||||
workSpeedclose(true)
|
||||
// if (seriesIndex === this.currentSeriesIndex) return
|
||||
const element = e.currentTarget
|
||||
@@ -576,6 +587,7 @@ export default {
|
||||
},
|
||||
showMultiFrames(series, seriesIndex, instanceInfo) {
|
||||
this.currentSeriesIndex = seriesIndex
|
||||
this.activeInstanceId = instanceInfo.Id
|
||||
const imageIds = []
|
||||
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
||||
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
||||
@@ -587,6 +599,7 @@ export default {
|
||||
const seriesInfo = {
|
||||
trialId: series.trialId,
|
||||
subjectVisitId: series.subjectVisitId,
|
||||
instanceInfoList: series.instanceInfoList,
|
||||
studyId: series.studyId,
|
||||
imageIds: imageIds,
|
||||
seriesId: series.seriesId,
|
||||
@@ -920,6 +933,7 @@ export default {
|
||||
}
|
||||
if (this.visitTaskId === params.visitTaskId) {
|
||||
const seriesIndex = params.seriesIndex
|
||||
if (!this.seriesList[seriesIndex]) return false
|
||||
var prefetchInstanceCount = this.seriesList[seriesIndex].prefetchInstanceCount
|
||||
var instanceCount = this.seriesList[seriesIndex].instanceCount
|
||||
if (!this.activeSeriesId) {
|
||||
@@ -965,8 +979,8 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.imageBox {
|
||||
<style lang="scss">
|
||||
.viewerContainer .imageBox {
|
||||
position: relative;
|
||||
|
||||
i {
|
||||
@@ -1183,6 +1197,10 @@ export default {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
.frame_content_active {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
|
||||
/* .viewerRightSidePanel {
|
||||
width: 300px;
|
||||
|
||||
@@ -19,25 +19,26 @@
|
||||
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`"
|
||||
:name="`${study.StudyId}`">
|
||||
<template slot="title">
|
||||
|
||||
<div class="text-desc">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
<div class="collapse-title-wrapper">
|
||||
<div class="text-desc" v-if="IsReadingTaskViewInOrder !== 0">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
{{ study.Description }}
|
||||
</div> -->
|
||||
<el-tooltip v-show="study.Description" class="item" effect="dark" :content="study.Description"
|
||||
<!-- <el-tooltip v-show="study.Description" class="item" effect="dark" :content="study.Description"
|
||||
placement="bottom">
|
||||
<div v-show="study.Description"
|
||||
<div v-if="study.Description"
|
||||
style="width: 50px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;padding: 1x;">
|
||||
{{ study.Description }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div v-show="study.SeriesCount" class="text-desc">
|
||||
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
||||
</el-tooltip> -->
|
||||
<div v-if="study.SeriesCount" class="text-desc collapse-title-extra">
|
||||
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-show="study.Description" class="text-desc" style="background-color: #1f1f1f;">
|
||||
<div v-if="study.Description" class="text-desc" style="background-color: #1f1f1f;">
|
||||
{{ study.Description }}
|
||||
</div>
|
||||
<div v-for="(series, i) in study.SeriesList" :key="i"
|
||||
@@ -65,6 +66,7 @@
|
||||
<div class="frame_list">
|
||||
<div v-for="(instance, idx) in series.instanceInfoList" :key="instance.Id"
|
||||
class="frame_content"
|
||||
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
:style="{ 'margin-bottom': idx < series.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||
@click="showMultiFrames(index, series, i, instance)">
|
||||
<!-- <div>
|
||||
@@ -97,12 +99,12 @@
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-connection"
|
||||
style="font-size: 15px;cursor: pointer;"
|
||||
@click="popperClick(studyList, series)" />
|
||||
@click.stop="popperClick(studyList, series)" />
|
||||
</el-popover>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-show="series.InstanceCount" style="padding: 1px;">
|
||||
<div v-show="series.instanceCount" style="padding: 1px;">
|
||||
{{ series.modality }}: {{ series.instanceCount }} image
|
||||
</div>
|
||||
<div v-show="series.sliceThickness" style="padding: 1px;">
|
||||
@@ -153,113 +155,111 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-show="!visitTaskId" :label="$t('trials:dicom-show:relatedVisit')" name="relation-study"
|
||||
class="pane-relation-wrapper">
|
||||
<el-tab-pane v-show="!visitTaskId" v-if="IsReadingTaskViewInOrder >= 2"
|
||||
:label="$t('trials:dicom-show:relatedVisit')" name="relation-study" class="pane-relation-wrapper">
|
||||
<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 class="text-desc">
|
||||
<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="collapse-title-wrapper">
|
||||
<div class="text-desc" v-if="IsReadingTaskViewInOrder !== 0">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
{{ study.Description }}
|
||||
</div> -->
|
||||
{{ study.Description }}
|
||||
</div> -->
|
||||
|
||||
<div v-show="study.SeriesCount" class="text-desc">
|
||||
<div v-show="study.SeriesCount" class="text-desc collapse-title-extra">
|
||||
{{ 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>
|
||||
</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"
|
||||
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
: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>
|
||||
@@ -330,7 +330,9 @@ export default {
|
||||
isFromCRCUpload: false,
|
||||
visitTaskId: null,
|
||||
page: '',
|
||||
activeSeriesId: null
|
||||
activeSeriesId: null,
|
||||
activeInstanceId: null,
|
||||
IsReadingTaskViewInOrder: 2
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -349,20 +351,22 @@ export default {
|
||||
this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload
|
||||
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
|
||||
this.page = this.$route.query.page
|
||||
if (this.$router.currentRoute.query.IsReadingTaskViewInOrder) {
|
||||
this.IsReadingTaskViewInOrder = Number(this.$router.currentRoute.query.IsReadingTaskViewInOrder)
|
||||
}
|
||||
console.log(this.IsReadingTaskViewInOrder)
|
||||
this.beforeUnloadHandler = () => {
|
||||
cornerstone.imageCache.purgeCache()
|
||||
requestPoolManager.resetRequestPool()
|
||||
}
|
||||
// cornerstone.events.addEventListener('cornerstoneimageloaded', this.cornerstoneImageLoaded)
|
||||
this.getStudiesInfo()
|
||||
cornerstone.events.addEventListener('cornerstoneimageloadprogress', this.cornerstoneimageloadprogress)
|
||||
window.addEventListener('beforeunload', e => {
|
||||
cornerstone.imageCache.purgeCache()
|
||||
requestPoolManager.resetRequestPool()
|
||||
})
|
||||
window.addEventListener('beforeunload', this.beforeUnloadHandler)
|
||||
},
|
||||
beforeDestroy() {
|
||||
requestPoolManager.stopTaskTimer()
|
||||
window.removeEventListener('beforeunload', e => {
|
||||
cornerstone.imageCache.purgeCache()
|
||||
requestPoolManager.resetRequestPool()
|
||||
})
|
||||
window.removeEventListener('beforeunload', this.beforeUnloadHandler)
|
||||
workSpeedclose(true)
|
||||
},
|
||||
methods: {
|
||||
@@ -492,14 +496,17 @@ export default {
|
||||
data.SeriesList = seriesList
|
||||
this.studyList.push(data)
|
||||
})
|
||||
if (this.studyList.length > 0) {
|
||||
this.$refs.dicomViewer.loadImageStack(this.studyList[0].SeriesList[0])
|
||||
const imageId = this.studyList[0].SeriesList[0].imageIds[0]
|
||||
const firstStudy = this.studyList.find(study => Array.isArray(study.SeriesList) && study.SeriesList.length > 0)
|
||||
if (firstStudy) {
|
||||
const firstSeries = firstStudy.SeriesList[0]
|
||||
if (!Array.isArray(firstSeries.imageIds) || firstSeries.imageIds.length === 0) return
|
||||
this.$refs.dicomViewer.loadImageStack(firstSeries)
|
||||
const imageId = firstSeries.imageIds[0]
|
||||
let instanceId = imageId.split('/')[imageId.split('/').length - 1]
|
||||
instanceId = instanceId.split('.')[0]
|
||||
this.firstInstanceId = instanceId
|
||||
this.activeNames = [this.studyList[0].StudyId]
|
||||
this.loadImages(this.studyList[0].SeriesList[0], 0)
|
||||
this.activeNames = [firstStudy.StudyId]
|
||||
this.loadImages(firstSeries, 0)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -524,6 +531,7 @@ export default {
|
||||
},
|
||||
showSeriesImage(e, studyIndex, seriesIndex, series) {
|
||||
this.activeSeriesId = series.seriesId
|
||||
this.activeInstanceId = null
|
||||
workSpeedclose(true)
|
||||
const element = e.currentTarget
|
||||
const elements = document.querySelectorAll('[series-type]')
|
||||
@@ -565,6 +573,7 @@ export default {
|
||||
},
|
||||
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
||||
this.currentSeriesIndex = seriesIndex
|
||||
this.activeInstanceId = instanceInfo.Id
|
||||
const imageIds = []
|
||||
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
||||
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
||||
@@ -576,6 +585,7 @@ export default {
|
||||
const seriesInfo = {
|
||||
trialId: series.trialId,
|
||||
subjectVisitId: series.subjectVisitId,
|
||||
instanceInfoList: series.instanceInfoList,
|
||||
studyId: series.studyId,
|
||||
imageIds: imageIds,
|
||||
seriesId: series.seriesId,
|
||||
@@ -601,7 +611,11 @@ export default {
|
||||
}
|
||||
if (!isAddToTakPool) {
|
||||
var priority = parseInt(new Date().getTime())
|
||||
if (series.isExistMutiFrames) {
|
||||
if (series.isExistMutiFrames && imageIds.length > 1) {
|
||||
imageIds.map(imageId => {
|
||||
this.imageList.push({ imageId, seriesId: series.seriesId, priority })
|
||||
})
|
||||
} else if (series.isExistMutiFrames) {
|
||||
series.instanceInfoList.map(image => {
|
||||
this.imageList.push({ imageId: image.ImageId, seriesId: series.seriesId, priority })
|
||||
})
|
||||
@@ -883,6 +897,7 @@ export default {
|
||||
},
|
||||
showRelationSeriesImage(e, series, studyIndex, index) {
|
||||
this.activeSeriesId = series.seriesId
|
||||
this.activeInstanceId = null
|
||||
workSpeedclose(true)
|
||||
this.currentRelationIndex = index
|
||||
const element = e.currentTarget
|
||||
@@ -940,7 +955,7 @@ export default {
|
||||
if (this.imageList.length > 0) {
|
||||
requestPoolManager.startTaskTimer()
|
||||
this.imageList.map(image => {
|
||||
requestPoolManager.loadAndCacheImagePlus(image.imageId, image.seriesId, image.priority)
|
||||
requestPoolManager.loadAndCacheImagePlus(image.imageId, image.seriesId, image.priority).catch(() => { })
|
||||
})
|
||||
requestPoolManager.sortTaskPool()
|
||||
this.imageList = []
|
||||
@@ -1012,7 +1027,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.imageBox {
|
||||
.viewerContainer .imageBox {
|
||||
position: relative;
|
||||
|
||||
i {
|
||||
@@ -1102,6 +1117,7 @@ export default {
|
||||
padding: 0;
|
||||
margin-right: 2px;
|
||||
color: #D0D0D0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@@ -1110,6 +1126,8 @@ export default {
|
||||
word-break: break-all;
|
||||
display: table;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
border: 1px solid #3e3f3a;
|
||||
}
|
||||
|
||||
@@ -1138,14 +1156,20 @@ export default {
|
||||
.viewerContainer .viewerLeftSidePanel .viewernavigatorwrapper {
|
||||
display: flex;
|
||||
width: 220px;
|
||||
/* height: 84px; */
|
||||
min-height: 85px;
|
||||
padding: 1px 2px 1px 2px;
|
||||
margin: 2px 0 1px 1px;
|
||||
align-items: flex-start;
|
||||
/* border-radius: 2px;
|
||||
border: 1px solid #404040; */
|
||||
|
||||
}
|
||||
|
||||
.viewerContainer .viewerLeftSidePanel .viewernavigatorwrapper .imageBox {
|
||||
align-self: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.viewerContainer .viewernavigatorwrapper .el-progress__text {
|
||||
display: none;
|
||||
}
|
||||
@@ -1168,9 +1192,19 @@ export default {
|
||||
/* width: 120px;
|
||||
height: 80px; */
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 3px 1px 3px 4px;
|
||||
vertical-align: top;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.viewerContainer .viewerLeftSidePanel .viewernavitextwrapper>div {
|
||||
max-width: 100%;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.viewerContainer .viewerLeftSidePanel .viewerlabelwrapper {
|
||||
@@ -1200,12 +1234,24 @@ export default {
|
||||
|
||||
.viewerContainer .el-collapse {
|
||||
border: none;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.viewerContainer .el-collapse-item {
|
||||
background-color: #585453 !important;
|
||||
color: #ddd;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.viewerContainer .el-collapse-item__wrap {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.viewerContainer .el-collapse-item__content {
|
||||
@@ -1218,9 +1264,42 @@ export default {
|
||||
background-color: #585453 !important;
|
||||
color: #ddd;
|
||||
border-bottom-color: #5a5a5a;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
padding-left: 5px;
|
||||
height: 40px;
|
||||
height: auto;
|
||||
min-height: 30px;
|
||||
line-height: 20px;
|
||||
align-items: flex-start;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.viewerContainer .collapse-title-wrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
column-gap: 6px;
|
||||
row-gap: 2px;
|
||||
line-height: 16px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.viewerContainer .collapse-title-wrapper .text-desc {
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.viewerContainer .collapse-title-wrapper .collapse-title-extra {
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.instance_frame_wrapper {
|
||||
@@ -1264,6 +1343,11 @@ export default {
|
||||
background-color: #213a54;
|
||||
}
|
||||
|
||||
.frame_content_active {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
|
||||
/* .viewerRightSidePanel {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictionary:signature:form:DocLanguageType')" prop="DocLanguageType">
|
||||
<el-select v-model="form.DocLanguageType" style="width: 100%">
|
||||
<el-option v-for="item of $d.DocLanguageType" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictionary:signature:form:NeedConfirmedUserTypeIdList')"
|
||||
prop="NeedConfirmedUserTypeIdList">
|
||||
<el-select v-model="form.NeedConfirmedUserTypeIdList" style="width: 100%" multiple>
|
||||
@@ -83,6 +88,7 @@ export default {
|
||||
DocUserSignType: 0,
|
||||
CurrentStaffTrainDays: 1,
|
||||
NewStaffTrainDays: 14,
|
||||
DocLanguageType: null
|
||||
},
|
||||
rules: {
|
||||
FileTypeId: [
|
||||
@@ -92,6 +98,13 @@ export default {
|
||||
trigger: ['blur'],
|
||||
},
|
||||
],
|
||||
DocLanguageType: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur'],
|
||||
},
|
||||
],
|
||||
SignViewMinimumMinutes: [
|
||||
{
|
||||
required: true,
|
||||
@@ -143,6 +156,9 @@ export default {
|
||||
this.form.DocUserSignType = this.data.DocUserSignType
|
||||
this.form.CurrentStaffTrainDays = this.data.CurrentStaffTrainDays
|
||||
this.form.NewStaffTrainDays = this.data.NewStaffTrainDays
|
||||
this.form.DocLanguageType = this.data.DocLanguageType
|
||||
} else {
|
||||
this.form.DocLanguageType = this.$i18n.locale !== 'zh' ? 1 : 0
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
<el-form-item :label="$t('dictionary:signature:search:Name')">
|
||||
<el-input v-model="searchData.Name" style="width: 130px" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictionary:signature:search:DocLanguageType')">
|
||||
<el-select v-model="searchData.DocLanguageType" style="width: 150px" clearable>
|
||||
<el-option v-for="item of $d.DocLanguageType" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictionary:signature:table:NeedConfirmedUserTypes')">
|
||||
<el-select v-model="searchData.UserTypeId" style="width: 150px" clearable>
|
||||
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName"
|
||||
@@ -90,6 +95,12 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="DocLanguageType" :label="$t('dictionary:signature:table:DocLanguageType')"
|
||||
show-overflow-tooltip sortable="custom" min-width="120px">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ $fd('DocLanguageType', scope.row.DocLanguageType) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="SignViewMinimumMinutes" :label="$t('dictionary:signature:table:SignViewMinimumMinutes')"
|
||||
show-overflow-tooltip sortable="custom" min-width="200px" />
|
||||
<el-table-column prop="CurrentStaffTrainDays" :label="$t('dictionary:signature:table:CurrentStaffTrainDays')"
|
||||
@@ -161,7 +172,7 @@
|
||||
<!-- 新增/编辑 -->
|
||||
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title"
|
||||
width="600px" custom-class="base-dialog-wrapper">
|
||||
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
|
||||
<TemplateForm :data="currentRow" @closeDialog="closeDialog" v-if="editVisible" @getList="getList" />
|
||||
</el-dialog>
|
||||
<!--附件列表-->
|
||||
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
|
||||
@@ -200,6 +211,7 @@ const searchDataDefault = () => {
|
||||
IsDeleted: null,
|
||||
DocUserSignType: null,
|
||||
UserTypeId: null,
|
||||
DocLanguageType: null,
|
||||
Name: '',
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
|
||||
@@ -26,11 +26,19 @@
|
||||
<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="$t('audit:label:moduleType')" show-overflow-tooltip align="left" min-width="230px" />
|
||||
<el-table-column v-if="language === 'en'" prop="ModuleTypeValue" :label="$t('audit:label:moduleType')" show-overflow-tooltip align="left" min-width="230px">
|
||||
</el-table-column>
|
||||
<el-table-column v-else prop="ModuleTypeValueCN" :label="$t('audit:label:moduleType')" show-overflow-tooltip align="left" min-width="230px">
|
||||
</el-table-column>
|
||||
<!-- 操作名称 -->
|
||||
<el-table-column prop="Description" :label="$t('audit:label:desc')" :show-overflow-tooltip="true" min-width="200px">
|
||||
<el-table-column v-if="language === 'en'" 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>
|
||||
<span>{{ scope.row.Description }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-else prop="DescriptionCN" :label="$t('audit:label:desc')" :show-overflow-tooltip="true" min-width="200px">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.DescriptionCN }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 其他 -->
|
||||
@@ -61,17 +69,20 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 标识 -->
|
||||
<el-table-column prop="Identification" :label="$t('audit:label:identification')" :show-overflow-tooltip="true" min-width="200px" />
|
||||
<el-table-column prop="Identification" :label="$t('audit:label:identification')" :show-overflow-tooltip="true" min-width="120px" />
|
||||
<!-- 操作类型 -->
|
||||
<el-table-column prop="OptTypeValueCN" :label="$t('audit:label:optType')" show-overflow-tooltip width="100px" />
|
||||
<el-table-column v-if="language === 'en'" prop="OptTypeValue" :label="$t('audit:label:optType')" show-overflow-tooltip min-width="110px" />
|
||||
<el-table-column v-else prop="OptTypeValueCN" :label="$t('audit:label:optType')" show-overflow-tooltip min-width="110px" />
|
||||
<!-- 对象类型 -->
|
||||
<el-table-column prop="ObjectTypeValueCN" :label="$t('audit:label:objectType')" show-overflow-tooltip min-width="100px" />
|
||||
<el-table-column v-if="language === 'en'" prop="ObjectTypeValue" :label="$t('audit:label:objectType')" show-overflow-tooltip width="100px" />
|
||||
<el-table-column v-else 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 v-if="language === 'en'" prop="ChildrenTypeValue" :label="$t('audit:label:dataType')" show-overflow-tooltip min-width="100px" />
|
||||
<el-table-column v-else 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 prop="Sort" :label="$t('audit:label:sort')" min-width="100" show-overflow-tooltip />
|
||||
<!-- 启用 -->
|
||||
<el-table-column :label="$t('audit:label:isEnable')" align="center" prop="CreateTime" min-width="80">
|
||||
<el-table-column :label="$t('audit:label:isEnable')" align="center" prop="CreateTime" min-width="90">
|
||||
<!-- 启用/禁用 -->
|
||||
<template slot-scope="scope">
|
||||
<!-- <el-tag v-if="scope.row.IsEnable" size="success">启用</el-tag>
|
||||
@@ -81,7 +92,7 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('common:action:action')" 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" width="290" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<!-- 上移 -->
|
||||
<el-button
|
||||
@@ -659,7 +670,7 @@ import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
import Sortable from 'sortablejs'
|
||||
import BaseModel from "@/components/BaseModel";
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'CheckConfig',
|
||||
dicts: ['OptType', 'ObjectType', 'ModuleType', 'ChildrenType'],
|
||||
@@ -715,6 +726,9 @@ export default {
|
||||
this.getList();
|
||||
this.getDictionaryCodeList();
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['language'])
|
||||
},
|
||||
methods: {
|
||||
querySearch(queryString, cb) {
|
||||
var DictionaryCodeList = this.DictionaryCodeList;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<box-content>
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form :inline="true" class="base-search-form" @submit.native.prevent="">
|
||||
<!-- CRO Name -->
|
||||
<el-form-item :label="$t('institutions:cros:label:croName')">
|
||||
<el-input v-model="searchData.CROName" style="width: 100px" />
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="siteForm"
|
||||
v-loading="loading"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
class="demo-ruleForm"
|
||||
size="small"
|
||||
label-width="150px"
|
||||
>
|
||||
<el-form ref="siteForm" v-loading="loading" :model="form" :rules="rules" class="demo-ruleForm" size="small"
|
||||
label-width="150px">
|
||||
<div class="base-dialog-body">
|
||||
<!-- Site Code -->
|
||||
<el-form-item :label="$t('institutions:sites:label:siteCode')" v-if="form.Id" prop="SiteCode">
|
||||
@@ -15,17 +8,11 @@
|
||||
</el-form-item>
|
||||
|
||||
<!-- 中心名称 -->
|
||||
<el-form-item
|
||||
:label="$t('institutions:sites:label:siteName')"
|
||||
prop="SiteName"
|
||||
>
|
||||
<el-form-item :label="$t('institutions:sites:label:siteName')" prop="SiteName">
|
||||
<el-input v-model="form.SiteName" />
|
||||
</el-form-item>
|
||||
<!-- 中心名称(CN) -->
|
||||
<el-form-item
|
||||
:label="$t('institutions:sites:label:siteNameCN')"
|
||||
prop="SiteNameCN"
|
||||
>
|
||||
<el-form-item :label="$t('institutions:sites:label:siteNameCN')" prop="SiteNameCN">
|
||||
<el-input v-model="form.SiteNameCN" />
|
||||
</el-form-item>
|
||||
<!-- Alias Name -->
|
||||
@@ -38,7 +25,9 @@
|
||||
</el-form-item> -->
|
||||
<!-- Country -->
|
||||
<el-form-item :label="$t('institutions:sites:label:country')" prop="Country">
|
||||
<el-input v-model="form.Country" />
|
||||
<el-select v-model="form.Country" style="width: 100%">
|
||||
<el-option v-for="item of $d.SiteCountry" :key="item.id" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- City -->
|
||||
<el-form-item :label="$t('institutions:sites:label:city')" prop="City">
|
||||
@@ -50,17 +39,8 @@
|
||||
</el-form-item>
|
||||
<!-- Affiliated Hospital -->
|
||||
<el-form-item :label="$t('institutions:sites:label:affiliatedHospital')">
|
||||
<el-select
|
||||
v-model="form.HospitalId"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in hospitalList"
|
||||
:key="item.Id"
|
||||
:label="item.HospitalName"
|
||||
:value="item.Id"
|
||||
/>
|
||||
<el-select v-model="form.HospitalId" clearable style="width: 100%">
|
||||
<el-option v-for="item in hospitalList" :key="item.Id" :label="item.HospitalName" :value="item.Id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- Director Name -->
|
||||
@@ -82,20 +62,10 @@
|
||||
</div>
|
||||
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
|
||||
<el-form-item>
|
||||
<el-button
|
||||
:disabled="btnLoading"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="handleCancel"
|
||||
>{{ $t('common:button:cancel') }}</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:loading="btnLoading"
|
||||
@click="handleSave"
|
||||
>{{ $t('common:button:save') }}</el-button
|
||||
>
|
||||
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancel">{{
|
||||
$t('common:button:cancel') }}</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">{{ $t('common:button:save')
|
||||
}}</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<box-content>
|
||||
<div class="search">
|
||||
<el-form :inline="true" class="base-search-form">
|
||||
<el-form :inline="true" class="base-search-form" @submit.native.prevent="">
|
||||
<!-- Sponsor Name -->
|
||||
<el-form-item :label="$t('institutions:sponsors:label:sponsorName')">
|
||||
<el-input v-model="searchData.SponsorName" style="width: 100px" />
|
||||
|
||||
@@ -37,7 +37,7 @@ export default {
|
||||
// console.log(type, No);
|
||||
if (type !== "Chrome" && type !== "Edge") {
|
||||
this.tip = this.$t("browser:tip:changeBorwser");
|
||||
this.getSystemInfo()
|
||||
// this.getSystemInfo()
|
||||
return (this.visible = true);
|
||||
}
|
||||
let res = await this.getInfo();
|
||||
@@ -53,10 +53,10 @@ export default {
|
||||
this.tip += "、";
|
||||
}
|
||||
});
|
||||
this.getSystemInfo()
|
||||
// this.getSystemInfo()
|
||||
return (this.visible = true);
|
||||
}
|
||||
this.getSystemInfo()
|
||||
// this.getSystemInfo()
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<el-input v-model="password.UserType" disabled />
|
||||
</el-form-item> -->
|
||||
<!-- 用户名 -->
|
||||
<el-form-item :label="$t('recompose:form:userName')" prop="NewUserName">
|
||||
<el-form-item class="my_new_pwd" :label="$t('recompose:form:userName')" prop="NewUserName">
|
||||
<el-input v-model="password.NewUserName" :disabled="isUpdate" />
|
||||
</el-form-item>
|
||||
<!-- 新密码 -->
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
callback(
|
||||
lang === 'zh'
|
||||
? new Error(
|
||||
'1)新建账号,用户名字符长度最小为4个字符,最大为16个字符,只可使用字母、数字、下划线;'
|
||||
'新建账号,用户名字符长度最小为4个字符,最大为16个字符,只可使用字母、数字、下划线;'
|
||||
)
|
||||
: new Error(
|
||||
'For a new account, the username must have:1) At least 4 characters;2) At most 16 characters;3)Only letters, numbers, and underscores are allowed.'
|
||||
|
||||
@@ -4,122 +4,57 @@
|
||||
<el-form :inline="true">
|
||||
<!--项目编号/实验名称-->
|
||||
<el-form-item :label="$t('feedBack:search:trials')" v-if="level > 8">
|
||||
<el-input
|
||||
v-model="searchData.TrialKeyInfo"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
></el-input>
|
||||
<el-input v-model="searchData.TrialKeyInfo" clearable style="width: 150px"></el-input>
|
||||
</el-form-item>
|
||||
<!--中心-->
|
||||
<el-form-item :label="$t('feedBack:search:site')" v-if="level > 7">
|
||||
<el-input
|
||||
v-model="searchData.TrialSiteCode"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
></el-input>
|
||||
<el-input v-model="searchData.TrialSiteCode" clearable style="width: 150px"></el-input>
|
||||
</el-form-item>
|
||||
<!--受试者访视-->
|
||||
<el-form-item
|
||||
:label="$t('feedBack:search:subjectVisit')"
|
||||
v-if="level > 7"
|
||||
>
|
||||
<el-input
|
||||
v-model="searchData.SubejctAndVisitKeyInfo"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
></el-input>
|
||||
<el-form-item :label="$t('feedBack:search:subjectVisit')" v-if="level > 7">
|
||||
<el-input v-model="searchData.SubejctAndVisitKeyInfo" clearable style="width: 150px"></el-input>
|
||||
</el-form-item>
|
||||
<!--角色-->
|
||||
<el-form-item :label="$t('feedBack:search:role')" v-if="level > 7">
|
||||
<el-select
|
||||
v-model="searchData.UserTypeEnum"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
popper-class="feedBack-select-box"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of UserTypeOptins"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
<el-select v-model="searchData.UserTypeEnum" clearable style="width: 150px"
|
||||
popper-class="feedBack-select-box">
|
||||
<el-option v-for="item of UserTypeOptins" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!--反馈人-->
|
||||
<el-form-item :label="$t('feedBack:search:user')" v-if="level > 7">
|
||||
<el-input
|
||||
v-model="searchData.FeedBackUserKeyInfo"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
></el-input>
|
||||
<el-input v-model="searchData.FeedBackUserKeyInfo" clearable style="width: 150px"></el-input>
|
||||
</el-form-item>
|
||||
<!--问题类型-->
|
||||
<el-form-item :label="$t('feedBack:search:questionType')">
|
||||
<el-select
|
||||
v-model="searchData.QuestionType"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
popper-class="feedBack-select-box"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of QuestionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
<el-select v-model="searchData.QuestionType" clearable style="width: 150px"
|
||||
popper-class="feedBack-select-box">
|
||||
<el-option v-for="item of QuestionTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!--问题描述-->
|
||||
<el-form-item :label="$t('feedBack:search:description')">
|
||||
<el-input
|
||||
v-model="searchData.QuestionDescription"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
></el-input>
|
||||
<el-input v-model="searchData.QuestionDescription" clearable style="width: 150px"></el-input>
|
||||
</el-form-item>
|
||||
<!--状态-->
|
||||
<el-form-item :label="$t('feedBack:search:status')" v-if="level > 7">
|
||||
<el-select
|
||||
v-model="searchData.State"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
popper-class="feedBack-select-box"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of $d.FeedBackStatus"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
<el-select v-model="searchData.State" clearable style="width: 150px" popper-class="feedBack-select-box">
|
||||
<el-option v-for="item of $d.FeedBackStatus" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!--反馈日期-->
|
||||
<el-form-item :label="$t('feedBack:search:time')">
|
||||
<el-date-picker
|
||||
v-model="datetimerange"
|
||||
type="datetimerange"
|
||||
:default-time="['00:00:00', '23:59:59']"
|
||||
:start-placeholder="$t('feedBack:search:beginTime')"
|
||||
:end-placeholder="$t('feedBack:search:endTime')"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="handleDatetimeChange"
|
||||
style="width: 250px"
|
||||
popper-class="feedBack-select-box"
|
||||
/>
|
||||
<el-date-picker v-model="datetimerange" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
|
||||
:start-placeholder="$t('feedBack:search:beginTime')" :end-placeholder="$t('feedBack:search:endTime')"
|
||||
value-format="yyyy-MM-dd HH:mm:ss" @change="handleDatetimeChange" style="width: 250px"
|
||||
popper-class="feedBack-select-box" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList"
|
||||
>
|
||||
<el-button type="primary" icon="el-icon-search" @click="getList">
|
||||
{{ $t('common:button:search') }}
|
||||
</el-button>
|
||||
<!-- 重置 -->
|
||||
<el-button
|
||||
icon="el-icon-refresh-left"
|
||||
@click="handleReset"
|
||||
>
|
||||
<el-button icon="el-icon-refresh-left" @click="handleReset">
|
||||
{{ $t('common:button:reset') }}
|
||||
</el-button>
|
||||
<!-- <el-button
|
||||
@@ -131,97 +66,32 @@
|
||||
{{ $t("common:button:export") }}
|
||||
</el-button> -->
|
||||
</el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="resolve"
|
||||
style="float: right"
|
||||
v-if="level > 7"
|
||||
:disabled="tableSelectData.length <= 0"
|
||||
>
|
||||
<el-button type="primary" @click="resolve" style="float: right" v-if="level > 7"
|
||||
:disabled="tableSelectData.length <= 0">
|
||||
{{ $t('feedBack:button:resolve') }}
|
||||
</el-button>
|
||||
</el-form>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
v-adaptive="{ bottomOffset: 45 }"
|
||||
height="100"
|
||||
:data="list"
|
||||
class="table"
|
||||
@selection-change="handleSelectChange"
|
||||
@sort-change="handleSortByColumn"
|
||||
:default-sort="{ prop: 'CreateTime', order: 'descending' }"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
align="center"
|
||||
width="45"
|
||||
v-if="level > 7"
|
||||
:selectable="handleSelectTable"
|
||||
/>
|
||||
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 45 }" height="100" :data="list" class="table"
|
||||
@selection-change="handleSelectChange" @sort-change="handleSortByColumn"
|
||||
:default-sort="{ prop: 'CreateTime', order: 'descending' }">
|
||||
<el-table-column type="selection" align="center" width="45" v-if="level > 7" :selectable="handleSelectTable" />
|
||||
<el-table-column type="index" width="50" />
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:trialCode')"
|
||||
prop="TrialCode"
|
||||
min-width="100"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 8"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:study')"
|
||||
prop="ExperimentName"
|
||||
min-width="140"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 8"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:siteCode')"
|
||||
prop="TrialSiteCode"
|
||||
min-width="100"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:SubjectCode')"
|
||||
prop="SubjectCode"
|
||||
min-width="120"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:subjectVisit')"
|
||||
prop="SubjectVisitName"
|
||||
min-width="120"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:role')"
|
||||
prop="FeedBackUserName"
|
||||
min-width="100"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:user')"
|
||||
prop="FeedBackFullName"
|
||||
min-width="140"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:questionType')"
|
||||
prop="QuestionType"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
>
|
||||
<el-table-column :label="$t('feedBack:form:trialCode')" prop="TrialCode" min-width="100" show-overflow-tooltip
|
||||
sortable="custom" v-if="level > 8" />
|
||||
<el-table-column :label="$t('feedBack:form:study')" prop="ExperimentName" min-width="140" show-overflow-tooltip
|
||||
sortable="custom" v-if="level > 8" />
|
||||
<el-table-column :label="$t('feedBack:form:siteCode')" prop="TrialSiteCode" min-width="100"
|
||||
show-overflow-tooltip sortable="custom" v-if="level > 7" />
|
||||
<el-table-column :label="$t('feedBack:form:SubjectCode')" prop="SubjectCode" min-width="120"
|
||||
show-overflow-tooltip sortable="custom" v-if="level > 7" />
|
||||
<el-table-column :label="$t('feedBack:form:subjectVisit')" prop="SubjectVisitName" min-width="120"
|
||||
show-overflow-tooltip sortable="custom" v-if="level > 7" />
|
||||
<el-table-column :label="$t('feedBack:form:role')" prop="FeedBackUserName" min-width="100" show-overflow-tooltip
|
||||
sortable="custom" v-if="level > 7" />
|
||||
<el-table-column :label="$t('feedBack:form:user')" prop="FeedBackFullName" min-width="140" show-overflow-tooltip
|
||||
sortable="custom" v-if="level > 7" />
|
||||
<el-table-column :label="$t('feedBack:form:questionType')" prop="QuestionType" min-width="180"
|
||||
show-overflow-tooltip sortable="custom">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
QuestionTypeOptions.filter(
|
||||
@@ -230,49 +100,22 @@
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:description')"
|
||||
prop="QuestionDescription"
|
||||
min-width="200"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:time')"
|
||||
prop="CreateTime"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:status')"
|
||||
prop="State"
|
||||
min-width="120"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
>
|
||||
<el-table-column :label="$t('feedBack:form:description')" prop="QuestionDescription" min-width="200"
|
||||
show-overflow-tooltip sortable="custom" />
|
||||
<el-table-column :label="$t('feedBack:form:time')" prop="CreateTime" min-width="180" show-overflow-tooltip
|
||||
sortable="custom" />
|
||||
<el-table-column :label="$t('feedBack:form:status')" prop="State" min-width="120" show-overflow-tooltip
|
||||
sortable="custom" v-if="level > 7">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="['danger', 'success'][scope.row.State]">{{
|
||||
<el-tag :type="['danger', 'success', 'danger'][scope.row.State]">{{
|
||||
$fd('FeedBackStatus', scope.row.State)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('feedBack:form:uploadTime')"
|
||||
prop="UpdateTime"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
v-if="level > 7"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('common:action:action')"
|
||||
fixed="right"
|
||||
prop="UserTypeShortName"
|
||||
width="100"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<el-table-column :label="$t('feedBack:form:uploadTime')" prop="UpdateTime" min-width="180" show-overflow-tooltip
|
||||
sortable="custom" v-if="level > 7" />
|
||||
<el-table-column :label="$t('common:action:action')" fixed="right" prop="UserTypeShortName" width="100"
|
||||
show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="getDetail(scope.row)">
|
||||
{{ $t('common:button:view') }}
|
||||
@@ -281,12 +124,8 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination" style="text-align: right; margin-top: 5px">
|
||||
<pagination
|
||||
:total="total"
|
||||
:page.sync="searchData.PageIndex"
|
||||
:limit.sync="searchData.PageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<pagination :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
|
||||
@pagination="getList" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -434,7 +273,7 @@ export default {
|
||||
}
|
||||
},
|
||||
// 导出
|
||||
report() {},
|
||||
report() { },
|
||||
// 表格选择
|
||||
handleSelectChange(selection) {
|
||||
// console.log(selection, "handleSelectChange");
|
||||
@@ -472,31 +311,37 @@ export default {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 0;
|
||||
flex-grow: 4;
|
||||
|
||||
// border-right: 1px solid #ccc;
|
||||
.filter-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.data-table {
|
||||
flex: 1;
|
||||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 0;
|
||||
flex-grow: 6;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.selected-row {
|
||||
background-color: cadetblue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
<template>
|
||||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404" style="display: flex;align-items: center;flex-wrap: wrap;justify-content: center;">
|
||||
<div class="pic-404">
|
||||
<!-- <img class="pic-404__parent" src="@/assets/login-bg.png" alt="404"> -->
|
||||
<svg-icon icon-class="login-bg" style="width: 100%; height: 100%" />
|
||||
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops" style="color: #428bca">{{ $t('trials:researchForm:title:IsExpired') }}!</div>
|
||||
<!-- <div class="bullshit__headline">{{ $t('trials:researchForm:title:IsExpired') }}</div> -->
|
||||
<!-- <div class="bullshit__return-home" style="background: #428bca" @click="$router.push({ path: '/login' })">{{
|
||||
$t('common:title:goHome') }}</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
|
||||
...mapGetters([
|
||||
'asyncRoutes',
|
||||
'routes',
|
||||
'language'
|
||||
]),
|
||||
},
|
||||
mounted() {
|
||||
let lang = this.$route.query.lang
|
||||
if (!lang) {
|
||||
const language = navigator.language
|
||||
lang = 'en'
|
||||
if (language.includes("zh")) {
|
||||
lang = 'zh'
|
||||
}
|
||||
}
|
||||
this.$i18n.locale = lang
|
||||
this.setLanguage(lang)
|
||||
this.$updateDictionary()
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setLanguage: 'lang/setLanguage' }),
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wscn-http404-container {
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 0 50px;
|
||||
overflow: hidden;
|
||||
|
||||
.pic-404 {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
margin-right: 10px;
|
||||
|
||||
&__parent {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__child {
|
||||
position: absolute;
|
||||
|
||||
&.left {
|
||||
width: 80px;
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
animation-name: cloudLeft;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
&.mid {
|
||||
width: 46px;
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
animation-name: cloudMid;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
&.right {
|
||||
width: 62px;
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
animation-name: cloudRight;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
@keyframes cloudLeft {
|
||||
0% {
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
20% {
|
||||
top: 33px;
|
||||
left: 188px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80% {
|
||||
top: 81px;
|
||||
left: 92px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 97px;
|
||||
left: 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes cloudMid {
|
||||
0% {
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
20% {
|
||||
top: 40px;
|
||||
left: 360px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
70% {
|
||||
top: 130px;
|
||||
left: 180px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 160px;
|
||||
left: 120px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes cloudRight {
|
||||
0% {
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
20% {
|
||||
top: 120px;
|
||||
left: 460px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80% {
|
||||
top: 180px;
|
||||
left: 340px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 200px;
|
||||
left: 300px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bullshit {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 300px;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
|
||||
&__oops {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 40px;
|
||||
color: #1482f0;
|
||||
opacity: 0;
|
||||
margin-bottom: 20px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__headline {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
margin-bottom: 10px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.1s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
color: grey;
|
||||
opacity: 0;
|
||||
margin-bottom: 30px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
&__return-home {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 110px;
|
||||
height: 36px;
|
||||
background: #1482f0;
|
||||
border-radius: 100px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
opacity: 0;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,28 +5,27 @@
|
||||
</div>
|
||||
<div class="login-body">
|
||||
<div class="login-l">
|
||||
<div class="login-logo">
|
||||
<!-- <div class="login-logo">
|
||||
<img v-if="language === 'zh'" src="@/assets/zzlogo2.png" alt="" />
|
||||
<img v-else-if="NODE_ENV === 'usa'" src="@/assets/zzlogo-usa.png" alt="" class="usa-logo" />
|
||||
<img v-else src="@/assets/zzlogo4.png" alt="" />
|
||||
</div>
|
||||
<img v-else src="@/assets/zzlogo2.png" alt="" />
|
||||
</div> -->
|
||||
<div :class="{
|
||||
'login-image': true,
|
||||
'login-image-usa': true,
|
||||
}">
|
||||
<svg-icon icon-class="login-bg" style="width: 90%; height: 90%" />
|
||||
<!-- <img src="@/assets/login-bg.png" v-else /> -->
|
||||
<!-- <svg-icon icon-class="login-bg" style="width: 90%; height: 90%" /> -->
|
||||
<img src="@/assets/login-bg.png" style=" height: 80%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-r">
|
||||
<div class="title-container">
|
||||
<!-- IRC Management System -->
|
||||
<!-- HASC Management System -->
|
||||
<div v-if="NODE_ENV === 'usa'">
|
||||
<svg-icon icon-class="login-logo" style="width: 300px; height: 94px" />
|
||||
</div>
|
||||
<div class="title" v-else>
|
||||
<img src="@/assets/system.png" alt=""
|
||||
:style="{ width: isEN ? '180px' : '200px', height: isEN ? '60px' : '65px' }" />
|
||||
<img src="@/assets/system.png" alt="" :style="{ height: isEN ? '50px' : '55px' }" />
|
||||
<div :style="`font-size:${isEN ? '28px' : '35px'}`">{{ $t('login:title:system') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -111,17 +110,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="language === 'zh'" class="login-footer">
|
||||
<span>Copyright © {{ new Date().getFullYear() }} 上海展影医疗科技有限公司
|
||||
<span>Copyright © {{ new Date().getFullYear() }} 上海禾安枢信息科技有限公司
|
||||
版权所有</span>
|
||||
<span> | </span>
|
||||
<a target="_blank" href="https://beian.miit.gov.cn/">
|
||||
<!-- <a target="_blank" href="https://beian.miit.gov.cn/">
|
||||
<span> 沪ICP备2021037850-2 </span>
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=31011002005859">
|
||||
<img src="@/assets/filing.png" />
|
||||
<span>沪公网安备 31011002005859号</span>
|
||||
</a>
|
||||
</a> -->
|
||||
<a @click="openAbout">
|
||||
<span style="color: #428bca">关于</span>
|
||||
</a>
|
||||
@@ -152,27 +151,32 @@
|
||||
<!-- {{ $t('login:title:system_title_about') }} -->
|
||||
<svg-icon icon-class="login-logo" style="width: 250px; height: 71px" />
|
||||
</p>
|
||||
<p style="margin-bottom: 0px" v-else>{{ $t('login:title:system') }}</p>
|
||||
<div style="margin-bottom: 0px" v-else>
|
||||
<!-- {{ $t('login:title:system_title_about') }} -->
|
||||
<img src="@/assets/system.png" alt=""
|
||||
:style="{ width: isEN ? '180px' : '200px', height: isEN ? '60px' : '65px' }" />
|
||||
<p style="margin-bottom: 0px">{{ $t('login:title:system') }}</p>
|
||||
</div>
|
||||
<p style="margin-bottom: 20px; margin-top: 0">
|
||||
V{{ $version.IsEnv_US ? $version.Version_US : $version.Version }}
|
||||
</p>
|
||||
<p style="margin-bottom: 20px" v-if="language === 'zh'">
|
||||
Copyright © {{ new Date().getFullYear() }} 上海展影医疗科技有限公司
|
||||
Copyright © {{ new Date().getFullYear() }} 上海禾安枢信息科技有限公司
|
||||
版权所有
|
||||
</p>
|
||||
<p style="margin-bottom: 20px" v-else-if="NODE_ENV === 'usa'">
|
||||
© {{ new Date().getFullYear() }} Elevate Imaging Inc.
|
||||
</p>
|
||||
<p style="margin-bottom: 20px" v-else>
|
||||
<!-- <p style="margin-bottom: 20px" v-else>
|
||||
Copyright © {{ new Date().getFullYear() }} Shanghai Extensive Imaging
|
||||
Inc.
|
||||
</p>
|
||||
<div style="margin-bottom: 20px" v-if="NODE_ENV === 'usa'">
|
||||
</p> -->
|
||||
<!-- <div style="margin-bottom: 20px" v-if="NODE_ENV === 'usa'">
|
||||
<img style="width: 180px" src="@/assets/zzlogo-usa.png" alt="" />
|
||||
</div>
|
||||
<div style="margin-bottom: 20px" v-else>
|
||||
<img style="width: 180px" src="@/assets/zzlogo2.png" alt="" />
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" size="mini" @click="aboutVisible = false">
|
||||
@@ -369,6 +373,15 @@ export default {
|
||||
})
|
||||
}, 500)
|
||||
return
|
||||
} else if (res.BasicInfo.IsNeedResetPwd) {
|
||||
// 当前用户管理员重置密码,请先修改密码之后再次登录
|
||||
this.$message.success(this.$t('login:message:login5'))
|
||||
setTimeout(() => {
|
||||
this.$router.push({
|
||||
path: `/user-recompose?UserId=${res.BasicInfo.IdentityUserId}&Email=${res.BasicInfo.EMail}&UserName=${res.BasicInfo.UserName}&lang=${this.$i18n.locale}&access_token=${res.JWTStr}&isUpdate=1`,
|
||||
})
|
||||
}, 500)
|
||||
return
|
||||
} else if (res.BasicInfo.NeedChangePassWord) {
|
||||
// 请先修改密码后再登录!
|
||||
this.$alert(
|
||||
|
||||
@@ -153,7 +153,8 @@ export default {
|
||||
isAudit: false,
|
||||
|
||||
activeNames: [],
|
||||
Asc: false
|
||||
Asc: false,
|
||||
IsReadingTaskViewInOrder: 2
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@@ -165,6 +166,9 @@ export default {
|
||||
store.dispatch('user/setToken', this.$router.currentRoute.query.TokenKey)
|
||||
changeURLStatic('TokenKey', '')
|
||||
}
|
||||
if (this.$router.currentRoute.query.IsReadingTaskViewInOrder) {
|
||||
this.IsReadingTaskViewInOrder = Number(this.$router.currentRoute.query.IsReadingTaskViewInOrder)
|
||||
}
|
||||
this.subjectVisitId = this.$router.currentRoute.query.subjectVisitId
|
||||
this.studyId = this.$router.currentRoute.query.studyId
|
||||
this.getNoneDicomList()
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
<template>
|
||||
<div v-loading="loading" class="none-dicom-study-wrapper">
|
||||
<div class="study-info">
|
||||
<div style="cursor: pointer;" @click.stop="sortFile">
|
||||
<i :class="['el-icon-caret-top', asc === false ? '' : 'icon_check']"
|
||||
style="display: block;margin-bottom: -5px;"></i>
|
||||
<i :class="['el-icon-caret-bottom', asc === true ? '' : 'icon_check']"
|
||||
style="display: block; margin-top: -5px;"></i>
|
||||
</div>
|
||||
<div>{{ $t('trials:none-dicom-show:fileList') }} </div>
|
||||
</div>
|
||||
<div class="ps" ref="studyBox_ps">
|
||||
<el-collapse v-model="activeNames">
|
||||
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.Id}`" :name="`${study.Id}`">
|
||||
<template slot="title">
|
||||
<div class="dicom-desc">
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||
<span :title="study.CodeView">{{ study.CodeView }}</span>
|
||||
<span v-if="otherInfo && otherInfo.IsShowStudyName" :title="study.StudyName" style="margin-left: 5px;">
|
||||
{{ study.StudyName }}
|
||||
</span>
|
||||
</div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||
<span :title="study.BodyPart">{{ getBodyPart(study.BodyPart, study.BodyPartForEditOther) }}</span>
|
||||
<span style="margin-left: 5px;" :title="study.Modality">{{ study.Modality }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="file-list-container">
|
||||
<div v-for="(k, i) in study.NoneDicomStudyFileList" :key="i" style="position:relative;margin-top:1px;"
|
||||
@click="selectFile(study, index, i, k)" :ref="`noneDicomRef_${index}_${i}`">
|
||||
<div :class="{ 'file-active': index === activeStudyIndex && i === activeFileIndex }" class="file-wrapper">
|
||||
<div class="file-main">
|
||||
<div class="file-image">
|
||||
<el-image
|
||||
v-if="k.FileType === 'image/jpeg' || k.FileType === 'image/jpg' || k.FileType === 'image/bmp' || k.FileType === 'image/png'"
|
||||
style="width: 100%;height: 100%;"
|
||||
:src="`${OSSclientConfig.basePath}${k.Path}?x-oss-process=image/resize,w_50,h_50/format,png`"
|
||||
fit="contain" crossorigin="anonymous" />
|
||||
<el-image v-else-if="k.FileType === 'application/pdf'" style="width: 100%;height: 100%;" :src="pdf"
|
||||
fit="contain" crossorigin="anonymous" />
|
||||
<el-image v-else-if="
|
||||
!!~k.FileType.indexOf('mp4')
|
||||
" style="width: 100%; height: 100%" :src="mp4" fit="contain" crossorigin="anonymous" />
|
||||
</div>
|
||||
<div class="file-text" :title="k.FileName">
|
||||
{{ k.FileName }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isQcCheck" class="switchBox">
|
||||
<div class="item">
|
||||
<span>{{ $t('trials:audit:table:isReading') }}</span>
|
||||
<el-switch v-model="k.IsReading" :disabled="k.IsDeleted || isAudit"
|
||||
:active-text="$fd('YesOrNo', true)" :inactive-text="$fd('YesOrNo', false)"
|
||||
@change="changeReadingStatus($event, study, k)" />
|
||||
</div>
|
||||
<div class="item">
|
||||
<span>{{ $t('trials:audit:table:isDelete') }}</span>
|
||||
<el-switch v-model="k.IsDeleted" :disabled="isAudit" :active-text="$fd('YesOrNo', true)"
|
||||
:inactive-text="$fd('YesOrNo', false)" @change="changeDeleteStatus($event, study, k)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getNoneDicomStudyList, setNodicomStudyState } from '@/api/trials'
|
||||
import FileNameSorter from "@/utils/customSort"
|
||||
import pdf from '@/assets/pdf.png'
|
||||
import mp4 from '@/assets/mp4.png'
|
||||
export default {
|
||||
name: 'StudyList',
|
||||
props: {
|
||||
visitTaskInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
isComparison: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
activeNames: [],
|
||||
activeStudyId: '',
|
||||
activeFileId: '',
|
||||
activeStudyIndex: -1,
|
||||
activeFileIndex: -1,
|
||||
studyList: [],
|
||||
pdf,
|
||||
mp4,
|
||||
BodyPart: {},
|
||||
subjectVisitId: '',
|
||||
studyId: '',
|
||||
otherInfo: null,
|
||||
criterionType: null,
|
||||
isQcCheck: false,
|
||||
isAudit: false,
|
||||
asc: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.subjectVisitId = this.$route.query.subjectVisitId
|
||||
this.studyId = this.$route.query.studyId
|
||||
this.isQcCheck = !!this.$route.query.isQcCheck
|
||||
this.getNoneDicoms()
|
||||
|
||||
// this.$nextTick(() => {
|
||||
// this.activeStudy(this.studyList[0].Id)
|
||||
// })
|
||||
this.BodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
|
||||
},
|
||||
methods: {
|
||||
scrollActiveFileIntoView() {
|
||||
this.$nextTick(() => {
|
||||
const refKey = `noneDicomRef_${this.activeStudyIndex}_${this.activeFileIndex}`
|
||||
const targetRef = this.$refs[refKey]
|
||||
const element = Array.isArray(targetRef) ? targetRef[0] : targetRef
|
||||
if (!element) return
|
||||
this.scrollElementToVisible(element)
|
||||
})
|
||||
},
|
||||
scrollElementToVisible(element, options = {}) {
|
||||
const container = this.$refs['studyBox_ps']
|
||||
if (!container || !element) return
|
||||
const elementTop = element.offsetTop
|
||||
const elementBottom = elementTop + element.offsetHeight
|
||||
const visibleTop = container.scrollTop
|
||||
const visibleBottom = visibleTop + container.clientHeight
|
||||
if (elementTop >= visibleTop && elementBottom <= visibleBottom) return
|
||||
const offset = options.offset != null
|
||||
? options.offset
|
||||
: Math.max((container.clientHeight - element.offsetHeight) / 2, 0)
|
||||
const targetPosition = Math.max(elementTop - offset, 0)
|
||||
container.scrollTo({
|
||||
top: targetPosition,
|
||||
behavior: options.behavior || 'smooth'
|
||||
})
|
||||
},
|
||||
async getNoneDicoms() {
|
||||
const loading = this.$loading({ fullscreen: true })
|
||||
try {
|
||||
let res = await getNoneDicomStudyList(
|
||||
this.subjectVisitId,
|
||||
this.studyId,
|
||||
false,
|
||||
this.$route.query.visitTaskId,
|
||||
!!this.$route.query.isReading,
|
||||
this.$route.query.isImageSegmentLabel,
|
||||
)
|
||||
this.studyList = res.Result
|
||||
this.studyList.forEach(study => {
|
||||
if (study.NoneDicomStudyFileList && study.NoneDicomStudyFileList.length > 0) {
|
||||
study.NoneDicomStudyFileList.forEach(file => {
|
||||
if (file.Path.includes('.MaskNoneDicom_')) {
|
||||
file.IsBeMark = true
|
||||
} else {
|
||||
file.IsBeMark = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
this.otherInfo = res.OtherInfo
|
||||
this.isAudit = res.OtherInfo.AuditState * 1 > 6
|
||||
const studyIndex = this.studyList.findIndex((item) => {
|
||||
return item.NoneDicomStudyFileList.length > 0
|
||||
})
|
||||
if (studyIndex > -1) {
|
||||
this.selectFile(this.studyList[studyIndex], studyIndex, 0)
|
||||
let studyId = this.studyList[studyIndex].Id
|
||||
this.activeNames = [studyId]
|
||||
}
|
||||
if (this.criterionType === 19 || this.criterionType === 20) {
|
||||
this.sortFile()
|
||||
}
|
||||
loading.close()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
loading.close()
|
||||
}
|
||||
|
||||
},
|
||||
selected() {
|
||||
|
||||
},
|
||||
sortFile() {
|
||||
this.asc = !this.asc
|
||||
this.studyList.forEach(study => {
|
||||
if (study.NoneDicomStudyFileList.length > 0) {
|
||||
study.NoneDicomStudyFileList = FileNameSorter.sortFileNames(study.NoneDicomStudyFileList, {
|
||||
direction: this.asc ? 'asc' : 'desc',
|
||||
key: 'FileName'
|
||||
})
|
||||
}
|
||||
})
|
||||
this.activeStudyIndex = this.studyList.findIndex(item => item.Id === this.activeStudyId)
|
||||
if (this.activeStudyIndex === -1) return
|
||||
this.activeFileIndex = this.studyList[this.activeStudyIndex].NoneDicomStudyFileList.findIndex(item => item.Id === this.activeFileId)
|
||||
},
|
||||
changeReadingStatus(callback, row, file) {
|
||||
let statusStr = ''
|
||||
if (callback) {
|
||||
statusStr = this.$t('trials:audit:label:setSeriesReading')
|
||||
file.IsReading = false
|
||||
} else {
|
||||
statusStr = this.$t('trials:audit:label:setSeriesNotReading')
|
||||
file.IsReading = true
|
||||
}
|
||||
let message = this.$t('trials:audit:message:changeSeriesStatus').replace('xxx', statusStr)
|
||||
message = message.replace('yyy', this.$fd('YesOrNo', !file.IsReading))
|
||||
this.$confirm(message, {
|
||||
distinguishCancelAndClose: true,
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
const state = file.IsReading ? 1 : 2
|
||||
this.loading = true
|
||||
const params = {
|
||||
SubjectVisitId: row.SubjectVisitId,
|
||||
NoneDicomStudyId: row.Id,
|
||||
State: state,
|
||||
NoneDicomStudyFileId: file.Id,
|
||||
}
|
||||
return setNodicomStudyState(params)
|
||||
.then((res) => {
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
file.IsReading = !file.IsReading
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
.catch(() => { })
|
||||
},
|
||||
changeDeleteStatus(callback, row, file) {
|
||||
let statusStr = ''
|
||||
if (callback) {
|
||||
statusStr = this.$t('trials:audit:label:setSeriesDeleted')
|
||||
file.IsDeleted = false
|
||||
} else {
|
||||
statusStr = this.$t('trials:audit:label:setSeriesNotDelete')
|
||||
file.IsDeleted = true
|
||||
}
|
||||
let message = this.$t('trials:audit:message:changeSeriesStatus').replace('xxx', statusStr)
|
||||
message = message.replace('yyy', this.$fd('YesOrNo', !file.IsDeleted))
|
||||
this.$confirm(message, {
|
||||
distinguishCancelAndClose: true,
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
const state = file.IsDeleted ? 5 : 4
|
||||
this.loading = true
|
||||
const params = {
|
||||
SubjectVisitId: row.SubjectVisitId,
|
||||
NoneDicomStudyId: row.Id,
|
||||
State: state,
|
||||
NoneDicomStudyFileId: file.Id,
|
||||
}
|
||||
return setNodicomStudyState(params)
|
||||
.then((res) => {
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
file.IsDeleted = !file.IsDeleted
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
.catch(() => { })
|
||||
},
|
||||
getBodyPart(bodyPart, other) {
|
||||
if (!bodyPart && !other) return ''
|
||||
var separator = ','
|
||||
if (bodyPart.indexOf('|') > -1) {
|
||||
separator = '|'
|
||||
} else if (bodyPart.indexOf(',') > -1) {
|
||||
separator = ','
|
||||
} else if (bodyPart.indexOf(',') > -1) {
|
||||
separator = ','
|
||||
}
|
||||
var arr = bodyPart.split(separator)
|
||||
var newArr = arr.map((i) => {
|
||||
return this.$fd('Bodypart', i.trim(), 'Code', this.BodyPart, 'Name')
|
||||
})
|
||||
if (other) {
|
||||
newArr.push(other)
|
||||
}
|
||||
newArr = newArr.filter(Boolean)
|
||||
return newArr.join(' | ')
|
||||
},
|
||||
// 切换文件
|
||||
selectFile(study, studyIndex, fileIndex, isReset = false) {
|
||||
if (this.isComparison) return false
|
||||
this.activeStudyIndex = studyIndex
|
||||
this.activeFileIndex = fileIndex
|
||||
this.activeStudyId = study.Id
|
||||
const fileList = study.NoneDicomStudyFileList
|
||||
this.activeFileId = fileList[fileIndex].Id
|
||||
this.$emit('selectFile', { fileInfo: fileList[fileIndex], fileList, visitTaskInfo: this.visitTaskInfo, studyId: study.Id, isReset })
|
||||
this.scrollActiveFileIntoView()
|
||||
},
|
||||
activeImage(obj) {
|
||||
if (!obj || this.studyList.length === 0) return
|
||||
const study = this.studyList.find(i => i.Id === obj.studyId)
|
||||
const studyIndex = this.studyList.findIndex(i => i.Id === obj.studyId)
|
||||
if (studyIndex === -1) return
|
||||
this.activeStudy(`${obj.studyId}`)
|
||||
this.activeStudyIndex = studyIndex
|
||||
this.activeStudyId = obj.studyId
|
||||
const fileList = this.studyList[studyIndex].NoneDicomStudyFileList || []
|
||||
const fileIndex = fileList.findIndex(f => f.Path === obj.path)
|
||||
if (fileIndex === -1) return
|
||||
this.activeFileIndex = fileIndex
|
||||
this.activeFileId = fileList[fileIndex].Id
|
||||
this.selectFile(study, studyIndex, fileIndex)
|
||||
this.scrollActiveFileIntoView()
|
||||
},
|
||||
replaceImage(obj) {
|
||||
if (!obj || this.studyList.length === 0) return
|
||||
const study = this.studyList.find(i => i.Id === obj.studyId)
|
||||
const studyIndex = this.studyList.findIndex(i => i.Id === obj.studyId)
|
||||
if (studyIndex === -1) return
|
||||
this.activeStudy(`${obj.studyId}`)
|
||||
this.activeStudyIndex = studyIndex
|
||||
this.activeStudyId = obj.studyId
|
||||
const fileList = this.studyList[studyIndex].NoneDicomStudyFileList || []
|
||||
const fileIndex = fileList.findIndex(f => f.Path === obj.path)
|
||||
const file = fileList.find(f => f.Path === obj.path)
|
||||
if (fileIndex === -1) return
|
||||
this.activeFileIndex = fileIndex
|
||||
this.activeFileId = fileList[fileIndex].Id
|
||||
file.Path = obj.file.Path
|
||||
file.FullFilePath = obj.file.Path
|
||||
file.IsBeMark = obj.IsBeMark
|
||||
this.selectFile(study, studyIndex, fileIndex, true)
|
||||
},
|
||||
activeStudy(id) {
|
||||
const studyId = `${id}`
|
||||
if (this.activeNames.indexOf(studyId) > -1) return
|
||||
this.activeNames.push(studyId)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.none-dicom-study-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.study-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #ddd;
|
||||
background-color: #4c4c4c;
|
||||
line-height: 40px;
|
||||
user-select: none;
|
||||
}
|
||||
.icon_check {
|
||||
color: #409EFF;
|
||||
}
|
||||
.dicom-desc {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
color: #d0d0d0;
|
||||
padding: 2px 8px 2px 2px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ps {
|
||||
flex: 1;
|
||||
overflow-anchor: none;
|
||||
touch-action: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.file-active {
|
||||
// background: #16477b;
|
||||
background-color: #183553 !important;
|
||||
border: 1px solid #23527b !important;
|
||||
}
|
||||
|
||||
::v-deep .el-progress__text {
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
}
|
||||
::v-deep .el-switch__label {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.file-list-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
.file-wrapper {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
cursor: pointer;
|
||||
background-color: #3a3a3a;
|
||||
|
||||
// color: #ddd;
|
||||
// white-space: nowrap;
|
||||
// overflow: hidden;
|
||||
// text-overflow: ellipsis;
|
||||
.file-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.el-progress__text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-progress-bar {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.file-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.file-text {
|
||||
flex: 1;
|
||||
padding-left: 5px;
|
||||
color: #ddd;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.switchBox {
|
||||
width: 100%;
|
||||
margin-top: 6px;
|
||||
color: #ddd;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-collapse {
|
||||
border: none;
|
||||
|
||||
.el-collapse-item {
|
||||
background-color: #000 !important;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.el-collapse-item__content {
|
||||
padding-bottom: 0px;
|
||||
background-color: #000 !important;
|
||||
}
|
||||
|
||||
.el-collapse-item__header {
|
||||
background-color: #353535 !important;
|
||||
color: #ddd;
|
||||
border-bottom-color: #5a5a5a;
|
||||
padding-left: 5px;
|
||||
height: 60px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
::v-deep .el-progress-bar__inner {
|
||||
transition: width 0s ease;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="read-page-container">
|
||||
<!-- 检查列表 -->
|
||||
<div class="left-panel">
|
||||
<div class="study-info">
|
||||
<study-list ref="studyList" :isComparison="isComparison" @selectFile="selectFile" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图像 -->
|
||||
<div class="middle-panel">
|
||||
|
||||
<file-viewer ref="fileViewer" :isComparison.sync="isComparison" @toggleImage="toggleImage"
|
||||
@selectFile="selectFile" @replaceImage="replaceImage" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import store from '@/store'
|
||||
import { changeURLStatic } from '@/utils/history.js'
|
||||
import StudyList from './components/study-list'
|
||||
import FileViewer from './components/file-viewer'
|
||||
export default {
|
||||
name: 'NoneDicoms',
|
||||
components: {
|
||||
StudyList,
|
||||
FileViewer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isComparison: false
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.$route.query.TokenKey) {
|
||||
store.dispatch('user/setToken', this.$route.query.TokenKey)
|
||||
changeURLStatic('TokenKey', '')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleImage(obj) {
|
||||
this.$refs['studyList'].activeImage(obj)
|
||||
},
|
||||
selectFile(obj) {
|
||||
if (obj.fileInfo && obj.fileList && obj.studyId) {
|
||||
this.$refs['fileViewer'].setActiveCanvasImages(obj)
|
||||
return
|
||||
}
|
||||
},
|
||||
replaceImage(obj) {
|
||||
this.$refs['studyList'].replaceImage(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.read-page-container {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
background-color: #444;
|
||||
padding: 5px;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
display: flex;
|
||||
width: 230px;
|
||||
border: 1px solid #727272;
|
||||
color: #fff;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.study-info {
|
||||
width: 100%;
|
||||
border-left: 1px solid #727272;
|
||||
}
|
||||
}
|
||||
|
||||
.middle-panel {
|
||||
flex: 1;
|
||||
border: 1px solid #727272;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
// .right-panel {
|
||||
// width: 400px;
|
||||
// border: 1px solid #727272;
|
||||
// padding: 0 10px;
|
||||
// overflow-y: auto;
|
||||
|
||||
// .text-info {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: space-between;
|
||||
// color: #ddd;
|
||||
// }
|
||||
// }
|
||||
|
||||
::v-deep .dialog-container {
|
||||
margin-top: 50px !important;
|
||||
width: 75%;
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
::v-deep .el-dialog__body {
|
||||
padding: 20px 20px 0 20px;
|
||||
height: calc(100% - 70px);
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.full-dialog-container {
|
||||
::v-deep .is-fullscreen .el-dialog__body {
|
||||
height: calc(100% - 70px);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -25,19 +25,10 @@
|
||||
<div class="login_content">
|
||||
<div class="form-label-width">
|
||||
<el-form-item :label="$t('trials:researchForm:form:siteName')" prop="TrialSiteId">
|
||||
<el-select
|
||||
v-model="form.TrialSiteId"
|
||||
filterable
|
||||
style="width:100%;"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory"
|
||||
@change="handleSiteChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item,index) of siteOptions"
|
||||
:key="index"
|
||||
:label="item.TrialSiteAliasName"
|
||||
:value="item.TrialSiteId"
|
||||
/>
|
||||
<el-select v-model="form.TrialSiteId" filterable style="width:100%;"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" @change="handleSiteChange">
|
||||
<el-option v-for="(item, index) of siteOptions" :key="index" :label="item.TrialSiteAliasName"
|
||||
:value="item.TrialSiteId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 中心编号 -->
|
||||
@@ -49,74 +40,149 @@
|
||||
<el-input v-model="form.UserName" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 联系电话 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:contactorPhone')"
|
||||
prop="Phone"
|
||||
>
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorPhone')" prop="Phone">
|
||||
<el-input v-model="form.Phone" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 联系邮箱 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')">
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')" prop="Email">
|
||||
<el-input v-model="form.Email" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('trials:researchForm:form:CommonUploadRecordId')
|
||||
" v-if="IsSupportUploadFile" class="file">
|
||||
<el-input v-model="form.SiteSurveyFile.FileName" type="textarea" :autosize="{ minRows: 1, maxRows: 3 }"
|
||||
style="margin-right: 5px;" disabled />
|
||||
<div class="upload" v-if="!(!(state === 0 && userTypeEnumInt === 0) || isHistory)">
|
||||
<input accept=".pdf,.docx,.doc" type="file" name="uploadFolder" class="select-file" title=""
|
||||
@change="beginScanFiles($event)" />
|
||||
<div class="btn-select">
|
||||
{{ $t('dictionary:template:basicData:button:selectFile') }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <el-button type="primary" @click="viewManualFile"
|
||||
:disabled="!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path">{{
|
||||
$t('trials:researchForm:form:preview') }}</el-button> -->
|
||||
<el-button type="primary" @click="downLoad"
|
||||
:disabled="!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path">{{
|
||||
$t('trials:researchForm:form:download') }}</el-button>
|
||||
</el-form-item>
|
||||
<!-- 平均刻盘周期(天) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('AverageEngravingCycle')" :label="$t('trials:researchForm:form:engravingCycle')">
|
||||
<el-input-number v-model="form.AverageEngravingCycle" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" controls-position="right" :min="0" style="width:100%;" />
|
||||
<el-form-item v-if="!notShowFieldList.includes('AverageEngravingCycle')"
|
||||
:label="$t('trials:researchForm:form:engravingCycle')">
|
||||
<el-input-number v-model="form.AverageEngravingCycle"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" controls-position="right" :min="0"
|
||||
style="width:100%;" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<!-- MRI-PDFF 是否为本中心该适应症的常规诊疗检查项目? -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsRoutineMRIPDEE')"
|
||||
:label="$t('trials:researchForm:form:IsRoutineMRIPDEE')" prop="IsRoutineMRIPDEE">
|
||||
<el-radio-group v-model="form.IsRoutineMRIPDEE"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsRoutineMRIPDEE${item.value}`" :label="item.value">{{
|
||||
item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- MRI-PDFF 检查的检测周期(含单次检查时长、预约等待时长等) -->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('MRIPDFFScanTime') || !notShowFieldList.includes('MRIPDFFLeadTime') || !notShowFieldList.includes('MRIPDFFOther')"
|
||||
:label="$t('trials:researchForm:form:IsMRIPDFF')">
|
||||
</el-form-item>
|
||||
<!-- 单次检查时长(分钟) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('MRIPDFFScanTime')"
|
||||
:label="$t('trials:researchForm:form:MRIPDFFScanTime')">
|
||||
<el-input-number v-model="form.MRIPDFFScanTime"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<!-- 平均预约等待时长(天) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('MRIPDFFLeadTime')"
|
||||
:label="$t('trials:researchForm:form:MRIPDFFLeadTime')">
|
||||
<el-input-number v-model="form.MRIPDFFLeadTime"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<!-- 特殊情况备注-->
|
||||
<el-form-item v-if="!notShowFieldList.includes('MRIPDFFOther')"
|
||||
:label="$t('trials:researchForm:form:MRIPDFFOther')">
|
||||
<el-input v-model="form.MRIPDFFOther" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" />
|
||||
</el-form-item>
|
||||
<!-- 如已选择研究者评估,项目是否会授权影像科老师参与本试验?如不单独授权,是否可在试验中保持 1-2 名固定技师操作?-->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('IsAuthorizeRadiologistsParticipate') || !notShowFieldList.includes('AssignFixedTechnologists')"
|
||||
:label="$t('trials:researchForm:form:IsAuthorize')" prop="IsAuthorize">
|
||||
<el-radio-group v-model="form.IsAuthorize" :disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)"
|
||||
@input="handleIsAuthorizeInput">
|
||||
<el-radio label="IsAuthorizeRadiologistsParticipate">{{
|
||||
$t('trials:researchForm:form:IsAuthorizeRadiologistsParticipate') }}</el-radio>
|
||||
<el-radio label="AssignFixedTechnologists">{{
|
||||
$t('trials:researchForm:form:AssignFixedTechnologists') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 请确认参与本项目影像采集的影像技师具备对应的资质(如:“技师证”,对应设备的“大型设备上岗证”) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsConfirmImagingTechnologist')" :label="$t('trials:researchForm:form:isQualified')">
|
||||
<el-radio-group v-model="form.IsConfirmImagingTechnologist" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio
|
||||
v-for="item of $d.YesOrNo"
|
||||
:key="`IsConfirmImagingTechnologist${item.value}`"
|
||||
:label="item.value"
|
||||
>{{ item.label }}</el-radio>
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsConfirmImagingTechnologist')"
|
||||
:label="$t('trials:researchForm:form:isQualified')" prop="IsConfirmImagingTechnologist">
|
||||
<el-radio-group v-model="form.IsConfirmImagingTechnologist"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsConfirmImagingTechnologist${item.value}`"
|
||||
:label="item.value">{{ item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 原因 -->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('NotConfirmReson') && form.IsConfirmImagingTechnologist === false"
|
||||
:label="$t('trials:researchForm:form:notQualifiedReason')"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.NotConfirmReson"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4}"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory"
|
||||
/>
|
||||
:label="$t('trials:researchForm:form:notQualifiedReason')" prop="NotConfirmReson">
|
||||
<el-input v-model="form.NotConfirmReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 研究单位疗效评估人员类型 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('EfficacyEvaluatorType')" :label="$t('trials:researchForm:form:staffType')">
|
||||
<el-radio-group v-model="form.EfficacyEvaluatorType" :disabled="!(state === 0 && userTypeEnumInt === 0)|| isHistory">
|
||||
<el-radio v-for="item of $d.EfficacyEvaluatorType" :key="`EfficacyEvaluatorType${item.value}`" :label="item.value">{{ item.label }}</el-radio>
|
||||
<el-form-item v-if="!notShowFieldList.includes('EfficacyEvaluatorType')"
|
||||
:label="$t('trials:researchForm:form:staffType')">
|
||||
<el-radio-group v-model="form.EfficacyEvaluatorType"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.EfficacyEvaluatorType" :key="`EfficacyEvaluatorType${item.value}`"
|
||||
:label="item.value">{{ item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 是否严格按照研究单位影像手册参数完成图像采集 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsFollowStudyParameters')">
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsFollowStudyParameters')" prop="IsFollowStudyParameters">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:isFollowStudyParam')" />
|
||||
<el-radio-group v-model="form.IsFollowStudyParameters" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsFollowStudyParameters${item.value}`" :label="item.value">{{ item.label }}</el-radio>
|
||||
<el-radio-group v-model="form.IsFollowStudyParameters"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsFollowStudyParameters${item.value}`" :label="item.value">{{
|
||||
item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button type="primary" size="small" style="margin-left: 5px;" @click="viewManual">
|
||||
{{ $t('trials:researchForm:button:viewManual') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<!-- 不能严格按照研究单位影像手册参数采集图像原因 -->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('NotFollowReson') && !form.IsFollowStudyParameters"
|
||||
>
|
||||
<el-form-item v-if="!notShowFieldList.includes('NotFollowReson') && !form.IsFollowStudyParameters"
|
||||
prop="NotFollowReson">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:notFollowStudyParam')" />
|
||||
<el-input
|
||||
v-model="form.NotFollowReson"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4}"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory"
|
||||
/>
|
||||
<el-input v-model="form.NotFollowReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 是否严格按照影像手册参数完成刻盘 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('ISStrictManualBurnFlag')" prop="ISStrictManualBurnFlag">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:ISStrictManualBurnFlag')" />
|
||||
<el-radio-group v-model="form.ISStrictManualBurnFlag"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" style="margin-right: 10px;">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`ISStrictManualBurnFlag${item.value}`" :label="item.value">{{
|
||||
item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 不能严格按照影像手册参数完成刻盘原因 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('NotStrictManualBurnFlagReason') && !form.ISStrictManualBurnFlag"
|
||||
prop="NotStrictManualBurnFlagReason">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:NotStrictManualBurnFlagReason')" />
|
||||
<el-input v-model="form.NotStrictManualBurnFlagReason" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getTrialSiteSelect } from '@/api/trials'
|
||||
import { getTrialSiteSelect, getTrialDocumentList, addOrUpdateCommonUploadRecord } from '@/api/trials'
|
||||
import { addOrUpdateTrialSiteSurvey } from '@/api/research'
|
||||
export default {
|
||||
name: 'ResearchBasicInfo',
|
||||
@@ -124,7 +190,15 @@ export default {
|
||||
isHistory: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
IsOnlyUploadFile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
IsSupportUploadFile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
var checkPhone = (rule, value, callback) => {
|
||||
@@ -156,16 +230,51 @@ export default {
|
||||
Phone: '', // 联系人电话
|
||||
Email: '', // 联系人邮箱
|
||||
AverageEngravingCycle: '',
|
||||
IsRoutineMRIPDEE: '',
|
||||
MRIPDFFScanTime: '',
|
||||
MRIPDFFLeadTime: '',
|
||||
MRIPDFFOther: '',
|
||||
IsAuthorize: '',
|
||||
IsAuthorizeRadiologistsParticipate: '',
|
||||
AssignFixedTechnologists: '',
|
||||
ISStrictManualBurnFlag: '',
|
||||
NotStrictManualBurnFlagReason: '',
|
||||
IsConfirmImagingTechnologist: '',
|
||||
NotConfirmReson: '',
|
||||
EfficacyEvaluatorType: '',
|
||||
IsFollowStudyParameters: '',
|
||||
NotFollowReson: ''
|
||||
NotFollowReson: '',
|
||||
CommonUploadRecordId: null,
|
||||
SiteSurveyFile: []
|
||||
},
|
||||
rules: {
|
||||
TrialSiteId: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
IsRoutineMRIPDEE: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
IsAuthorize: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
ISStrictManualBurnFlag: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
IsFollowStudyParameters: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
IsConfirmImagingTechnologist: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
NotConfirmReson: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
NotFollowReson: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
NotStrictManualBurnFlagReason: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
UserName: [
|
||||
{ required: true, validator: (rule, value, callback) => { !value ? callback(new Error(this.$t('trials:researchForm:formRule:specify'))) : callback() }, trigger: 'blur' },
|
||||
{ min: 0, max: 50, message: this.$t('trials:researchForm:formRule:maxLength'), trigger: ['blur', 'change'] }
|
||||
@@ -186,14 +295,173 @@ export default {
|
||||
state: null,
|
||||
userTypeEnumInt: zzSessionStorage.getItem('userTypeEnumInt') * 1,
|
||||
isShow: false,
|
||||
notShowFieldList: []
|
||||
notShowFieldList: [],
|
||||
perview_visible: false,
|
||||
ExternalList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async beginScanFiles(e) {
|
||||
try {
|
||||
let file = e.target.files[0]
|
||||
let name = file.name
|
||||
if (!this.checkFileSuffix(name)) return this.$message.warning(this.$t("trials:researchRecord:ImageManual:message:checkFileSuffix"))
|
||||
this.loading = true
|
||||
file = await this.fileToBlob(file)
|
||||
let scope = this
|
||||
var index = name.lastIndexOf('.')
|
||||
var type = name.substring(index + 1, name.length)
|
||||
let res = await this.OSSclient.put(
|
||||
`/${this.$route.query.trialId}/InspectionUpload/SiteSurvey/${this.form.TrialSiteId}/${scope.getGuid(Date.now() + '_' + name.split('.')[0])}.${type}`,
|
||||
file
|
||||
)
|
||||
let data = {
|
||||
Path: this.$getObjectName(res.url),
|
||||
FileName: name,
|
||||
FileSize: file.size,
|
||||
FileType: type
|
||||
|
||||
}
|
||||
res = await addOrUpdateCommonUploadRecord(data)
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.form.CommonUploadRecordId = res.Result
|
||||
data.Id = res.Result
|
||||
this.form.SiteSurveyFile = data
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
checkFileSuffix(fileName) {
|
||||
var index = fileName.lastIndexOf('.')
|
||||
var suffix = fileName.substring(index + 1, fileName.length)
|
||||
if ('.pdf'.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1 && '.docx'.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1 && '.doc'.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
handleIsAuthorizeInput(label) {
|
||||
this.form.IsAuthorizeRadiologistsParticipate = false
|
||||
this.form.AssignFixedTechnologists = false
|
||||
this.form[label] = true
|
||||
},
|
||||
async viewManualFile() {
|
||||
if (!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path) return this.$message.warning(this.$t("trials:researchForm:message:notFile"))
|
||||
this.$preview({
|
||||
path: this.form.SiteSurveyFile.Path,
|
||||
type: this.form.SiteSurveyFile.FileType,
|
||||
title: this.form.SiteSurveyFile.Path.FileName,
|
||||
})
|
||||
},
|
||||
async downLoad() {
|
||||
if (!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path) return this.$message.warning(this.$t("trials:researchForm:message:notFile"))
|
||||
let link = document.createElement('a')
|
||||
link.href = this.OSSclientConfig.basePath + this.form.SiteSurveyFile.Path;
|
||||
link.target = '_blank'
|
||||
link.download = this.form.SiteSurveyFile.FileName
|
||||
link.style.display = 'none'
|
||||
document.body.append(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
link = null
|
||||
},
|
||||
async viewManual() {
|
||||
try {
|
||||
let data = {
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
TrialId: this.$route.query.trialId,
|
||||
IsPublish: true,
|
||||
FileTypeCode: 4,
|
||||
IsDeleted: false
|
||||
}
|
||||
let res = await getTrialDocumentList(data)
|
||||
if (res.IsSuccess) {
|
||||
const { CurrentPageData } = res.Result
|
||||
if (CurrentPageData.length <= 0) return this.$message.warning(this.$t("trials:researchRecord:ImageManual:message:noImageManual"))
|
||||
this.ExternalList = []
|
||||
CurrentPageData.forEach(item => {
|
||||
let obj = {
|
||||
FilePath: item.Path,
|
||||
FileFormat: 'pdf',
|
||||
Name: item.Name
|
||||
}
|
||||
this.ExternalList.push(obj)
|
||||
});
|
||||
// this.perview_visible = true
|
||||
this.ExternalList.forEach(item => {
|
||||
let link = document.createElement('a')
|
||||
link.href = this.OSSclientConfig.basePath + item.FilePath;
|
||||
link.target = '_blank'
|
||||
link.download = item.Name
|
||||
link.style.display = 'none'
|
||||
document.body.append(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
link = null
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
// 保存基本信息
|
||||
handleSave(isAutoCommit) {
|
||||
return new Promise(async(resolve) => {
|
||||
handleSave(isAutoCommit, isCheck = false) {
|
||||
return new Promise(async (resolve) => {
|
||||
isCheck = false
|
||||
try {
|
||||
if (this.IsOnlyUploadFile && !isCheck) {
|
||||
if (!this.form.UserName) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notUserName"))
|
||||
return resolve(false)
|
||||
}
|
||||
if (!this.form.Phone) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notPhone"))
|
||||
return resolve(false)
|
||||
}
|
||||
if (!this.form.CommonUploadRecordId) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notCommonUploadRecordId"))
|
||||
return resolve(false)
|
||||
}
|
||||
this.btnLoading = true
|
||||
const param = {
|
||||
id: this.form.Id,
|
||||
trialId: this.$route.query.trialId,
|
||||
trialSiteId: this.form.TrialSiteId,
|
||||
userName: this.form.UserName,
|
||||
phone: this.form.Phone,
|
||||
email: this.form.Email,
|
||||
averageEngravingCycle: this.form.AverageEngravingCycle,
|
||||
IsRoutineMRIPDEE: this.form.IsRoutineMRIPDEE,
|
||||
MRIPDFFScanTime: this.form.MRIPDFFScanTime,
|
||||
MRIPDFFLeadTime: this.form.MRIPDFFLeadTime,
|
||||
MRIPDFFOther: this.form.MRIPDFFOther,
|
||||
IsAuthorizeRadiologistsParticipate: this.form.IsAuthorizeRadiologistsParticipate,
|
||||
AssignFixedTechnologists: this.form.AssignFixedTechnologists,
|
||||
ISStrictManualBurnFlag: this.form.ISStrictManualBurnFlag,
|
||||
NotStrictManualBurnFlagReason: this.form.NotStrictManualBurnFlagReason,
|
||||
isConfirmImagingTechnologist: this.form.IsConfirmImagingTechnologist,
|
||||
notConfirmReson: this.form.NotConfirmReson,
|
||||
efficacyEvaluatorType: this.form.EfficacyEvaluatorType,
|
||||
isFollowStudyParameters: this.form.IsFollowStudyParameters,
|
||||
notFollowReson: this.form.NotFollowReson,
|
||||
CommonUploadRecordId: this.form.CommonUploadRecordId
|
||||
}
|
||||
addOrUpdateTrialSiteSurvey(param).then(res => {
|
||||
this.btnLoading = false
|
||||
if (res.IsSuccess && !isAutoCommit) {
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
}
|
||||
resolve(true)
|
||||
}).catch(() => {
|
||||
this.btnLoading = false
|
||||
reject(false)
|
||||
})
|
||||
return resolve(true)
|
||||
}
|
||||
const valid = await this.$refs['researchBSForm'].validate()
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
@@ -205,11 +473,20 @@ export default {
|
||||
phone: this.form.Phone,
|
||||
email: this.form.Email,
|
||||
averageEngravingCycle: this.form.AverageEngravingCycle,
|
||||
IsRoutineMRIPDEE: this.form.IsRoutineMRIPDEE,
|
||||
MRIPDFFScanTime: this.form.MRIPDFFScanTime,
|
||||
MRIPDFFLeadTime: this.form.MRIPDFFLeadTime,
|
||||
MRIPDFFOther: this.form.MRIPDFFOther,
|
||||
IsAuthorizeRadiologistsParticipate: this.form.IsAuthorizeRadiologistsParticipate,
|
||||
AssignFixedTechnologists: this.form.AssignFixedTechnologists,
|
||||
ISStrictManualBurnFlag: this.form.ISStrictManualBurnFlag,
|
||||
NotStrictManualBurnFlagReason: this.form.NotStrictManualBurnFlagReason,
|
||||
isConfirmImagingTechnologist: this.form.IsConfirmImagingTechnologist,
|
||||
notConfirmReson: this.form.NotConfirmReson,
|
||||
efficacyEvaluatorType: this.form.EfficacyEvaluatorType,
|
||||
isFollowStudyParameters: this.form.IsFollowStudyParameters,
|
||||
notFollowReson: this.form.NotFollowReson
|
||||
notFollowReson: this.form.NotFollowReson,
|
||||
CommonUploadRecordId: this.form.CommonUploadRecordId
|
||||
}
|
||||
const res = await addOrUpdateTrialSiteSurvey(param)
|
||||
this.loading = false
|
||||
@@ -232,7 +509,7 @@ export default {
|
||||
// 初始化
|
||||
async initForm(trialInfo, trialSiteSurvey, notShowFieldList) {
|
||||
// 获取项目下的site
|
||||
const { Result } = await getTrialSiteSelect(this.$route.query.trialId)
|
||||
const { Result } = await getTrialSiteSelect(this.$route.query.trialId, { IgnoreDisable: true })
|
||||
this.siteOptions = Result
|
||||
this.form.Id = trialSiteSurvey.Id
|
||||
this.form.Sponsor = trialInfo.Sponsor // 申办方
|
||||
@@ -246,7 +523,20 @@ export default {
|
||||
this.form.UserName = trialSiteSurvey.UserName // 联系人
|
||||
this.form.Phone = trialSiteSurvey.Phone // 联系人电话
|
||||
this.form.Email = trialSiteSurvey.Email // 联系人邮箱
|
||||
this.form.CommonUploadRecordId = trialSiteSurvey.CommonUploadRecordId
|
||||
this.form.SiteSurveyFile = trialSiteSurvey.SiteSurveyFile || {}
|
||||
this.form.fileStr = this.form.SiteSurveyFile.FileName
|
||||
this.form.AverageEngravingCycle = trialSiteSurvey.AverageEngravingCycle
|
||||
this.form.IsRoutineMRIPDEE = trialSiteSurvey.IsRoutineMRIPDEE
|
||||
this.form.MRIPDFFScanTime = trialSiteSurvey.MRIPDFFScanTime
|
||||
this.form.MRIPDFFLeadTime = trialSiteSurvey.MRIPDFFLeadTime
|
||||
this.form.MRIPDFFOther = trialSiteSurvey.MRIPDFFOther
|
||||
this.form.IsAuthorizeRadiologistsParticipate = trialSiteSurvey.IsAuthorizeRadiologistsParticipate
|
||||
this.form.AssignFixedTechnologists = trialSiteSurvey.AssignFixedTechnologists
|
||||
if (this.form.IsAuthorizeRadiologistsParticipate) this.form.IsAuthorize = 'IsAuthorizeRadiologistsParticipate'
|
||||
if (this.form.AssignFixedTechnologists) this.form.IsAuthorize = 'AssignFixedTechnologists'
|
||||
this.form.ISStrictManualBurnFlag = trialSiteSurvey.ISStrictManualBurnFlag
|
||||
this.form.NotStrictManualBurnFlagReason = trialSiteSurvey.NotStrictManualBurnFlagReason
|
||||
this.form.IsConfirmImagingTechnologist = trialSiteSurvey.IsConfirmImagingTechnologist
|
||||
this.form.NotConfirmReson = trialSiteSurvey.NotConfirmReson
|
||||
this.form.EfficacyEvaluatorType = trialSiteSurvey.EfficacyEvaluatorType
|
||||
@@ -267,51 +557,109 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.research_bs_content{
|
||||
.research_bs_content {
|
||||
|
||||
.basic_content{
|
||||
.basic_content {
|
||||
padding: 0 20px;
|
||||
background: #fff;
|
||||
|
||||
}
|
||||
.login_content{
|
||||
|
||||
.login_content {
|
||||
padding: 5px 20px;
|
||||
margin-top: 5px;
|
||||
background: #fff;
|
||||
::v-deep.el-form-item {
|
||||
|
||||
::v-deep .el-form-item {
|
||||
padding-bottom: 20px;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
.code_content{
|
||||
display:flex;
|
||||
|
||||
.code_content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
.el-input{
|
||||
|
||||
.el-input {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.form-label-width{
|
||||
::v-deep.el-form-item__label{
|
||||
|
||||
.form-label-width {
|
||||
::v-deep .el-form-item__label {
|
||||
width: 140px;
|
||||
}
|
||||
::v-deep.el-form-item__content{
|
||||
|
||||
::v-deep .el-form-item__content {
|
||||
margin-left: 140px;
|
||||
}
|
||||
}
|
||||
.submit_content{
|
||||
|
||||
.submit_content {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
::v-deep.el-form-item {
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 0px;
|
||||
padding-top: 5px;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
.el-form-item__content{
|
||||
|
||||
.el-form-item__content {
|
||||
color: #82848a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.upload {
|
||||
display: inline-block;
|
||||
height: 36px;
|
||||
width: 90px;
|
||||
padding: 0 10px;
|
||||
line-height: 23px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
background: #428bca;
|
||||
border-color: #428bca;
|
||||
color: #fff;
|
||||
margin-right: 5px;
|
||||
|
||||
.select-file {
|
||||
height: 36px;
|
||||
width: 90px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.btn-select {
|
||||
//给显示在页面上的按钮写样式
|
||||
// width: 70px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
pointer-events: none; //pointer-events:none用来控制该标签的点击穿透事件
|
||||
}
|
||||
}
|
||||
|
||||
.file {
|
||||
::v-deep .el-form-item__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,59 +1,107 @@
|
||||
<template>
|
||||
<div
|
||||
v-loading="loading"
|
||||
class="equipment_form_content"
|
||||
>
|
||||
<el-form
|
||||
ref="equipmentForm"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-position="left"
|
||||
>
|
||||
<div v-loading="loading" class="equipment_form_content">
|
||||
<el-form ref="equipmentForm" :model="form" :rules="rules" label-position="left">
|
||||
<!-- 扫描设备 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:equipment')" prop="EquipmentTypeId">
|
||||
<el-select
|
||||
v-model="form.EquipmentTypeId"
|
||||
style="width:100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of $d.SiteSurvey_ScanEquipmentType"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:equipment')" prop="EquipmentTypeEnum"
|
||||
v-if="EquipmentControlFieldList.includes('EquipmentTypeEnum')">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-select v-model="form.EquipmentTypeEnum" style="width:100%" @change="form.OtherEquipmentType = null">
|
||||
<el-option v-for="item of $d.SiteSurvey_ScanEquipmentType" :key="item.id" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
<el-input placeholder="" v-model="form.OtherEquipmentType" style="margin-left: 10px;"
|
||||
v-if="form.EquipmentTypeEnum == '-1'" clearable>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 扫描参数 -->
|
||||
<el-form-item v-if="isShowParameters" :label="$t('trials:equiptResearch:form:param')">
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:param')"
|
||||
v-if="EquipmentControlFieldList.includes('Parameters')" prop="Parameters">
|
||||
<el-input v-model="form.Parameters" />
|
||||
</el-form-item>
|
||||
<!-- 扫描仪器制造商名称 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:manufacturer')">
|
||||
<el-input v-model="form.ManufacturerName" />
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:manufacturer')"
|
||||
v-if="EquipmentControlFieldList.includes('ManufacturerType')" prop="ManufacturerType">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-select v-model="form.ManufacturerType" style="width:100%" @change="form.ManufacturerName = null">
|
||||
<el-option v-for="item of $d.ManufacturerType" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<el-input placeholder="" v-model="form.ManufacturerName" style="margin-left: 10px;"
|
||||
v-if="form.ManufacturerType == '-1'" clearable>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 扫描仪型号 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:model')">
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:model')"
|
||||
v-if="EquipmentControlFieldList.includes('ScannerType')" prop="ScannerType">
|
||||
<el-input v-model="form.ScannerType" />
|
||||
</el-form-item>
|
||||
<!-- 磁场强度 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:MagneticFieldStrengthType')"
|
||||
v-if="EquipmentControlFieldList.includes('MagneticFieldStrengthType')" prop="MagneticFieldStrengthType">
|
||||
<el-select v-model="form.MagneticFieldStrengthType" style="width:100%">
|
||||
<el-option v-for="item of $d.MagneticFieldStrengthType" :key="item.id" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 体部线圈通道数 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:BodyCoilChannelCount')"
|
||||
v-if="EquipmentControlFieldList.includes('BodyCoilChannelCount')" prop="BodyCoilChannelCount">
|
||||
<el-select v-model="form.BodyCoilChannelCount" style="width:100%">
|
||||
<el-option v-for="item of $d.BodyCoilChannelCount" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 是否具备专用的PDFF脂肪定量序列(CSE-MRI序列) -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:HasDedicatedPdfFatQuantificationSequence')"
|
||||
v-if="EquipmentControlFieldList.includes('HasDedicatedPdfFatQuantificationSequence')"
|
||||
prop="HasDedicatedPdfFatQuantificationSequence">
|
||||
<el-select v-model="form.HasDedicatedPdfFatQuantificationSequence" style="width:100%"
|
||||
@change="form.PdfFatQuantificationSequenceType = null, form.OtherSequenceSpecification = null">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- PDFF脂肪定量序列 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:PdfFatQuantificationSequenceType')"
|
||||
prop="PdfFatQuantificationSequenceType"
|
||||
v-if="form.HasDedicatedPdfFatQuantificationSequence && EquipmentControlFieldList.includes('PdfFatQuantificationSequenceType')">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-select v-model="form.PdfFatQuantificationSequenceType" style="width:100%"
|
||||
@change="form.OtherSequenceSpecification = null">
|
||||
<el-option v-for="item of $d.PdfFatQuantificationSequenceType" :key="item.id" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
<el-input placeholder="" v-model="form.OtherSequenceSpecification" style="margin-left: 10px;"
|
||||
v-if="form.PdfFatQuantificationSequenceType == '-1'" clearable>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 是否包含 T2/R2 校正(用于铁沉积校正) -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:HasT2R2Correction')" prop="HasT2R2Correction"
|
||||
v-if="EquipmentControlFieldList.includes('HasT2R2Correction')">
|
||||
<el-select v-model="form.HasT2R2Correction" style="width:100%">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 是否可完整导出 PDFF 参数图及全部原始 DICOM 数据 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:CanFullyExportPdfParameterMapsAndRawDicom')"
|
||||
prop="CanFullyExportPdfParameterMapsAndRawDicom"
|
||||
v-if="EquipmentControlFieldList.includes('CanFullyExportPdfParameterMapsAndRawDicom')">
|
||||
<el-select v-model="form.CanFullyExportPdfParameterMapsAndRawDicom" style="width:100%">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 备注 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:remark')">
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:remark')" prop="Note"
|
||||
v-if="EquipmentControlFieldList.includes('Note')">
|
||||
<el-input v-model="form.Note" />
|
||||
</el-form-item>
|
||||
<div style="text-align: center;padding:20px 0px;">
|
||||
<!-- 取消 -->
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
@click="handleCancel"
|
||||
>
|
||||
<el-button size="large" type="primary" @click="handleCancel">
|
||||
{{ $t("common:button:cancel") }}
|
||||
</el-button>
|
||||
<!-- 保存 -->
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
@click="handleSave"
|
||||
>
|
||||
<el-button size="large" type="primary" @click="handleSave">
|
||||
{{ $t("common:button:save") }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -76,29 +124,96 @@ export default {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isShowParameters: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
EquipmentControlFieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
Id: '',
|
||||
EquipmentTypeId: '',
|
||||
Parameters: '',
|
||||
ManufacturerName: '',
|
||||
ScannerType: '',
|
||||
Note: '',
|
||||
EquipmentTypeEnum: null,
|
||||
OtherEquipmentType: null,
|
||||
Parameters: null,
|
||||
Note: null,
|
||||
ManufacturerType: null,
|
||||
ManufacturerName: null,
|
||||
ScannerType: null,
|
||||
MagneticFieldStrengthType: null,
|
||||
BodyCoilChannelCount: null,
|
||||
HasDedicatedPdfFatQuantificationSequence: null,
|
||||
PdfFatQuantificationSequenceType: null,
|
||||
OtherSequenceSpecification: null,
|
||||
HasT2R2Correction: null,
|
||||
CanFullyExportPdfParameterMapsAndRawDicom: null,
|
||||
TrialSiteSurveyId: ''
|
||||
},
|
||||
rules: {
|
||||
EquipmentTypeId: [
|
||||
EquipmentTypeEnum: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.form.EquipmentTypeEnum === -1 && !this.form.OtherEquipmentType) {
|
||||
callback(this.$t('common:ruleMessage:specify'));
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||
},
|
||||
],
|
||||
Parameters: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
// Note: [
|
||||
// { required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] }
|
||||
// ],
|
||||
ManufacturerType: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.form.ManufacturerType === -1 && !this.form.ManufacturerName) {
|
||||
callback(this.$t('common:ruleMessage:specify'));
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||
},
|
||||
],
|
||||
ScannerType: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
MagneticFieldStrengthType: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
]
|
||||
],
|
||||
BodyCoilChannelCount: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
HasDedicatedPdfFatQuantificationSequence: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
PdfFatQuantificationSequenceType: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.form.PdfFatQuantificationSequenceType === -1 && !this.form.OtherSequenceSpecification) {
|
||||
callback(this.$t('common:ruleMessage:specify'));
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||
},
|
||||
],
|
||||
HasT2R2Correction: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
CanFullyExportPdfParameterMapsAndRawDicom: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
},
|
||||
loading: false,
|
||||
dictionaryList: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -154,13 +269,15 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.equipment_form_content{
|
||||
.equipment_form_content {
|
||||
padding: 0 10px;
|
||||
::v-deep.el-form-item {
|
||||
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 0px;
|
||||
padding: 5px 0 20px 0;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
.el-form-item__content{
|
||||
|
||||
.el-form-item__content {
|
||||
color: #82848a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,18 +13,22 @@
|
||||
<i class="el-icon-receiving" />
|
||||
</div>
|
||||
<div class="p_info">
|
||||
<div
|
||||
class="p_info_basic"
|
||||
:style="{maxWidth:w+'px','white-space': 'nowrap',
|
||||
overflow: 'hidden',
|
||||
'text-overflow': 'ellipsis'}"
|
||||
>
|
||||
<div class="p_text">{{ item.EquipmentType }}</div>
|
||||
<div v-if="isShowParameters" class="p_text" style="margin-left:10px">{{ item.Parameters }}</div>
|
||||
<div class="p_text" style="margin-left:10px">{{ item.ManufacturerName }}</div>
|
||||
<div class="p_info_basic" :style="{
|
||||
maxWidth: w + 'px', 'white-space': 'nowrap',
|
||||
overflow: 'hidden',
|
||||
'text-overflow': 'ellipsis'
|
||||
}">
|
||||
<div class="p_text" v-if="EquipmentControlFieldList.includes('EquipmentTypeEnum')">
|
||||
{{ item.OtherEquipmentType ? item.OtherEquipmentType :
|
||||
$fd('SiteSurvey_ScanEquipmentType', item.EquipmentTypeEnum) }}</div>
|
||||
<div v-if="EquipmentControlFieldList.includes('Parameters')" class="p_text" style="margin-left:10px">{{
|
||||
item.Parameters }}</div>
|
||||
<div class="p_text" style="margin-left:10px" v-if="EquipmentControlFieldList.includes('ManufacturerType')">{{
|
||||
item.ManufacturerName ? item.ManufacturerName : $fd('ManufacturerType',
|
||||
item.ManufacturerType) }}</div>
|
||||
</div>
|
||||
<div class="p_text">{{ item.ScannerType }}</div>
|
||||
<div class="p_text">{{ item.Note }}</div>
|
||||
<div class="p_text" v-if="EquipmentControlFieldList.includes('ScannerType')">{{ item.ScannerType }}</div>
|
||||
<div class="p_text" v-if="EquipmentControlFieldList.includes('Note')">{{ item.Note }}</div>
|
||||
</div>
|
||||
<div v-if="state === 0 && userTypeEnumInt === 0 && !isHistory" class="p_func">
|
||||
<el-button type="text" @click="handleEdit(item)">
|
||||
@@ -36,19 +40,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加/编辑设备信息 -->
|
||||
<el-drawer
|
||||
:title="title"
|
||||
:visible.sync="formVisible"
|
||||
direction="btt"
|
||||
size="70%"
|
||||
>
|
||||
<EquipmentForm
|
||||
v-if="formVisible"
|
||||
:equipment-info="equipmentInfo"
|
||||
:is-show-parameters="isShowParameters"
|
||||
@getList="getList"
|
||||
@close="close"
|
||||
/>
|
||||
<el-drawer :title="title" :visible.sync="formVisible" direction="btt" size="70%">
|
||||
<EquipmentForm v-if="formVisible" :equipment-info="equipmentInfo"
|
||||
:EquipmentControlFieldList="EquipmentControlFieldList" @getList="getList" @close="close" />
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -81,7 +75,7 @@ export default {
|
||||
state: null,
|
||||
trialSiteSurveyId: '',
|
||||
trialId: '',
|
||||
isShowParameters: false
|
||||
EquipmentControlFieldList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -142,8 +136,11 @@ export default {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
initList(TrialSiteEquipmentSurveyList, trialSiteSurvey, isShowParameters) {
|
||||
this.isShowParameters = isShowParameters
|
||||
initList(TrialSiteEquipmentSurveyList, trialSiteSurvey, EquipmentControlFieldList) {
|
||||
this.EquipmentControlFieldList = []
|
||||
EquipmentControlFieldList.forEach(item => {
|
||||
this.EquipmentControlFieldList.push(item.FiledName)
|
||||
})
|
||||
this.list = TrialSiteEquipmentSurveyList
|
||||
this.state = trialSiteSurvey.State
|
||||
this.$forceUpdate()
|
||||
@@ -157,63 +154,70 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.equipments_content{
|
||||
.equipments_content {
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
.title{
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.equipment_info{
|
||||
|
||||
.equipment_info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
border-top: 1px solid #f5f7fa;
|
||||
.p_icon{
|
||||
|
||||
.p_icon {
|
||||
width: 70px;
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.p_info{
|
||||
|
||||
.p_info {
|
||||
position: relative;
|
||||
flex:1;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
// border-right: 1px solid #f5f7fa;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.p_info:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 0;
|
||||
height: 50px;
|
||||
width: 1px;
|
||||
background-color: #f5f7fa;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 0;
|
||||
height: 50px;
|
||||
width: 1px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.p_info_basic{
|
||||
|
||||
.p_info_basic {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
.p_text{
|
||||
|
||||
.p_text {
|
||||
line-height: 25px;
|
||||
color: #82848a;
|
||||
}
|
||||
.p_func{
|
||||
|
||||
.p_func {
|
||||
width: 80px;
|
||||
padding: 0 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||