commit
8d4ba686e8
|
|
@ -7,6 +7,7 @@
|
||||||
"": {
|
"": {
|
||||||
"name": "EICS",
|
"name": "EICS",
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.726.1",
|
"@aws-sdk/client-s3": "3.726.1",
|
||||||
"@cornerstonejs/adapters": "^4.19.2",
|
"@cornerstonejs/adapters": "^4.19.2",
|
||||||
|
|
@ -33,6 +34,7 @@
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"dicomedit": "^0.1.0",
|
"dicomedit": "^0.1.0",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
|
"echarts-map": "^3.0.1",
|
||||||
"element-ui": "^2.15.14",
|
"element-ui": "^2.15.14",
|
||||||
"exceljs": "^4.4.0",
|
"exceljs": "^4.4.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
|
@ -88,6 +90,7 @@
|
||||||
"html-webpack-plugin": "^5.6.3",
|
"html-webpack-plugin": "^5.6.3",
|
||||||
"mini-css-extract-plugin": "^2.9.2",
|
"mini-css-extract-plugin": "^2.9.2",
|
||||||
"node-polyfill-webpack-plugin": "^4.0.0",
|
"node-polyfill-webpack-plugin": "^4.0.0",
|
||||||
|
"patch-package": "^8.0.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"sass": "^1.63.2",
|
"sass": "^1.63.2",
|
||||||
|
|
@ -2747,9 +2750,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@cornerstonejs/adapters": {
|
"node_modules/@cornerstonejs/adapters": {
|
||||||
"version": "4.21.7",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@cornerstonejs/adapters/-/adapters-4.21.7.tgz",
|
"resolved": "https://registry.npmmirror.com/@cornerstonejs/adapters/-/adapters-4.19.2.tgz",
|
||||||
"integrity": "sha512-a9lGNlcLuuk81c8H2F4rotrMxTf9EGursSVIdz7n0cQ8nJmebSZTmp5FWGLDadRxh9pIxMeC52JTcDVd3JR9MQ==",
|
"integrity": "sha512-alzqHxQvz+nxTV4FPuyvcI/+IvZ0P/PFkMTJ2N9Jc/toJ+xPfuRL2daT9ddgMp9sR5qlMh/wD3A+xw+OyN7HPw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime-corejs2": "7.26.10",
|
"@babel/runtime-corejs2": "7.26.10",
|
||||||
|
|
@ -2759,8 +2762,8 @@
|
||||||
"ndarray": "1.0.19"
|
"ndarray": "1.0.19"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "4.21.7",
|
"@cornerstonejs/core": "4.19.2",
|
||||||
"@cornerstonejs/tools": "4.21.7"
|
"@cornerstonejs/tools": "4.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cornerstonejs/adapters/node_modules/dcmjs": {
|
"node_modules/@cornerstonejs/adapters/node_modules/dcmjs": {
|
||||||
|
|
@ -2824,9 +2827,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cornerstonejs/core": {
|
"node_modules/@cornerstonejs/core": {
|
||||||
"version": "4.21.7",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@cornerstonejs/core/-/core-4.21.7.tgz",
|
"resolved": "https://registry.npmmirror.com/@cornerstonejs/core/-/core-4.19.2.tgz",
|
||||||
"integrity": "sha512-wZkALM/P6TTODtbSeOOZvzWKXjyMRKtsyWJ6NL61BveIlNxATpBbrAIj0dqLVasdF45XcJO5Qn4TiSO/kgKRGA==",
|
"integrity": "sha512-T/nezzLhlQyS82FHsd129n7nKml2uCQjqOIls8P+S1bd/IUQSTnOZ9rnLFkfSVAvnuVyPiCz2f5t5wp/UZuZMQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kitware/vtk.js": "34.15.1",
|
"@kitware/vtk.js": "34.15.1",
|
||||||
|
|
@ -2840,9 +2843,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cornerstonejs/dicom-image-loader": {
|
"node_modules/@cornerstonejs/dicom-image-loader": {
|
||||||
"version": "4.21.7",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-4.21.7.tgz",
|
"resolved": "https://registry.npmmirror.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-4.19.2.tgz",
|
||||||
"integrity": "sha512-wtfKs/U+FM2M7HHiNTFJwujs8TEU2rBz03Fx4Bc//vpktasUN9bqLl/eQ/9zfmz8Cdi12BewVpORd7l4nUmhtQ==",
|
"integrity": "sha512-zHUQtw77saGanh2QpiJID9hY4ueO/kjNHXNTFl6P2DA00V9bWCK8nS6giDTkLEpWz7WrhHQsxTGNnQUqU+wUYQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cornerstonejs/codec-charls": "1.2.3",
|
"@cornerstonejs/codec-charls": "1.2.3",
|
||||||
|
|
@ -2856,28 +2859,28 @@
|
||||||
"uuid": "9.0.1"
|
"uuid": "9.0.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "4.21.7",
|
"@cornerstonejs/core": "4.19.2",
|
||||||
"dicom-parser": "1.8.21"
|
"dicom-parser": "1.8.21"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cornerstonejs/polymorphic-segmentation": {
|
"node_modules/@cornerstonejs/polymorphic-segmentation": {
|
||||||
"version": "4.21.7",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-4.21.7.tgz",
|
"resolved": "https://registry.npmmirror.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-4.19.2.tgz",
|
||||||
"integrity": "sha512-4qxVMY0LJ+ffJfbzvzFOwe6j1p93pawwMEVcWRZkipE0pgtlW1SWlBvePCNb25yps6GUxNFPEmdUn5x/Lw77VQ==",
|
"integrity": "sha512-A3V6ZOJbrwmoPr/DlMTOpQhSqAlWgng/LyIHYt0FXFuGCvW8NI2bhNqQ4t4vq8UoEoE7qgdCZUCC8KYkODUilQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@icr/polyseg-wasm": "0.4.0"
|
"@icr/polyseg-wasm": "0.4.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "4.21.7",
|
"@cornerstonejs/core": "4.19.2",
|
||||||
"@cornerstonejs/tools": "4.21.7",
|
"@cornerstonejs/tools": "4.19.2",
|
||||||
"@kitware/vtk.js": "34.15.1"
|
"@kitware/vtk.js": "34.15.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cornerstonejs/tools": {
|
"node_modules/@cornerstonejs/tools": {
|
||||||
"version": "4.21.7",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@cornerstonejs/tools/-/tools-4.21.7.tgz",
|
"resolved": "https://registry.npmmirror.com/@cornerstonejs/tools/-/tools-4.19.2.tgz",
|
||||||
"integrity": "sha512-p8bWrEKdjeNzzZfN5NI6Wh7tiZyI3/lXqrdLlY+BCD1YRUdv+rybhyrg0JhpodJYEGrS4/wrkhCApOp9j9Evdg==",
|
"integrity": "sha512-8eas92LIhc4Pa0t5RK72JLNZPgePGj+k2Vk3803D97jUrid/pob8q3E7ILBivqLUqPWbVj5fErR/jsZJ08eYtg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/offscreencanvas": "2019.7.3",
|
"@types/offscreencanvas": "2019.7.3",
|
||||||
|
|
@ -2889,7 +2892,7 @@
|
||||||
"url": "https://ohif.org/donate"
|
"url": "https://ohif.org/donate"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "4.21.7",
|
"@cornerstonejs/core": "4.19.2",
|
||||||
"@kitware/vtk.js": "34.15.1",
|
"@kitware/vtk.js": "34.15.1",
|
||||||
"@types/d3-array": "3.2.1",
|
"@types/d3-array": "3.2.1",
|
||||||
"@types/d3-interpolate": "3.0.4",
|
"@types/d3-interpolate": "3.0.4",
|
||||||
|
|
@ -5919,6 +5922,13 @@
|
||||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/@yarnpkg/lockfile": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
"node_modules/@zxing/text-encoding": {
|
"node_modules/@zxing/text-encoding": {
|
||||||
"version": "0.9.0",
|
"version": "0.9.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
|
||||||
|
|
@ -10503,6 +10513,23 @@
|
||||||
"zrender": "6.0.0"
|
"zrender": "6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/echarts-map": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/echarts-map/-/echarts-map-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-ZsfP4U75v9p2sdSCP4Fqhh8O43EglFwjeV/FbaIfeDn6G1MEvbp3CF0XRNAVhwoTfBK0zILuGcpcwcWq6z8CYw==",
|
||||||
|
"dependencies": {
|
||||||
|
"echarts": "~3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/echarts-map/node_modules/echarts": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-8Hvaa+hOUAYaFAgQjRISWN/2LKZ4g66nE33dHNjG8wT3S/SU7m2ENJ2+96mEkLQN5m9VvQKhmjCMqiky3J/png==",
|
||||||
|
"deprecated": "deprecated",
|
||||||
|
"dependencies": {
|
||||||
|
"zrenderjs": "~3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/echarts/node_modules/tslib": {
|
"node_modules/echarts/node_modules/tslib": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
|
|
@ -11942,6 +11969,16 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/find-yarn-workspace-root": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"micromatch": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/flat": {
|
"node_modules/flat": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz",
|
||||||
|
|
@ -14214,12 +14251,39 @@
|
||||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/json-stable-stringify": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.8",
|
||||||
|
"call-bound": "^1.0.4",
|
||||||
|
"isarray": "^2.0.5",
|
||||||
|
"jsonify": "^0.0.1",
|
||||||
|
"object-keys": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/json-stable-stringify-without-jsonify": {
|
"node_modules/json-stable-stringify-without-jsonify": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
||||||
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
|
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/json-stable-stringify/node_modules/isarray": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/json-stream": {
|
"node_modules/json-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/json-stream/-/json-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/json-stream/-/json-stream-1.0.0.tgz",
|
||||||
|
|
@ -14251,6 +14315,16 @@
|
||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonify": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/jsonify/-/jsonify-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Public Domain",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jstoxml": {
|
"node_modules/jstoxml": {
|
||||||
"version": "2.2.9",
|
"version": "2.2.9",
|
||||||
"resolved": "https://registry.npmmirror.com/jstoxml/-/jstoxml-2.2.9.tgz",
|
"resolved": "https://registry.npmmirror.com/jstoxml/-/jstoxml-2.2.9.tgz",
|
||||||
|
|
@ -14323,6 +14397,16 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/klaw-sync": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.1.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/klona": {
|
"node_modules/klona": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz",
|
||||||
|
|
@ -16733,6 +16817,140 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/patch-package": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/patch-package/-/patch-package-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@yarnpkg/lockfile": "^1.1.0",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"ci-info": "^3.7.0",
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"find-yarn-workspace-root": "^2.0.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"json-stable-stringify": "^1.0.2",
|
||||||
|
"klaw-sync": "^6.0.0",
|
||||||
|
"minimist": "^1.2.6",
|
||||||
|
"open": "^7.4.2",
|
||||||
|
"semver": "^7.5.3",
|
||||||
|
"slash": "^2.0.0",
|
||||||
|
"tmp": "^0.2.4",
|
||||||
|
"yaml": "^2.2.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"patch-package": "index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14",
|
||||||
|
"npm": ">5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/ci-info": {
|
||||||
|
"version": "3.9.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-3.9.0.tgz",
|
||||||
|
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/sibiraj-s"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/fs-extra": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/open": {
|
||||||
|
"version": "7.4.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/open/-/open-7.4.2.tgz",
|
||||||
|
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-docker": "^2.0.0",
|
||||||
|
"is-wsl": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/semver": {
|
||||||
|
"version": "7.8.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.0.tgz",
|
||||||
|
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/slash": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/slash/-/slash-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/yaml": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz",
|
||||||
|
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"yaml": "bin.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/eemeli"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/path-browserify": {
|
"node_modules/path-browserify": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||||
|
|
@ -23587,6 +23805,12 @@
|
||||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/zrenderjs": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/zrenderjs/-/zrenderjs-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-+WsvUsqButmQXmdFENN4AJFbiNMf+9j0xKupRQoAxuxiFHU4y142X/i3O/Q6GGJ4YwXh8YbBNsWxkbCAxB3C/A==",
|
||||||
|
"license": "BSD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"build:usa": "vue-cli-service build --mode usa",
|
"build:usa": "vue-cli-service build --mode usa",
|
||||||
"build:usa_prod": "vue-cli-service build --mode usa_prod",
|
"build:usa_prod": "vue-cli-service build --mode usa_prod",
|
||||||
"pre": "vue-cli-service build --mode pre",
|
"pre": "vue-cli-service build --mode pre",
|
||||||
|
"postinstall": "patch-package",
|
||||||
"i18n": "npm run i18n:zh && npm run i18n:en",
|
"i18n": "npm run i18n:zh && npm run i18n:en",
|
||||||
"i18n:zh": "node i18nGenerate.js lang=zh keyCol=5 valCol=6",
|
"i18n:zh": "node i18nGenerate.js lang=zh keyCol=5 valCol=6",
|
||||||
"i18n:en": "node i18nGenerate.js lang=en keyCol=5 valCol=7"
|
"i18n:en": "node i18nGenerate.js lang=en keyCol=5 valCol=7"
|
||||||
|
|
@ -40,6 +41,7 @@
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"dicomedit": "^0.1.0",
|
"dicomedit": "^0.1.0",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
|
"echarts-map": "^3.0.1",
|
||||||
"element-ui": "^2.15.14",
|
"element-ui": "^2.15.14",
|
||||||
"exceljs": "^4.4.0",
|
"exceljs": "^4.4.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
|
@ -95,6 +97,7 @@
|
||||||
"html-webpack-plugin": "^5.6.3",
|
"html-webpack-plugin": "^5.6.3",
|
||||||
"mini-css-extract-plugin": "^2.9.2",
|
"mini-css-extract-plugin": "^2.9.2",
|
||||||
"node-polyfill-webpack-plugin": "^4.0.0",
|
"node-polyfill-webpack-plugin": "^4.0.0",
|
||||||
|
"patch-package": "^8.0.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"sass": "^1.63.2",
|
"sass": "^1.63.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
|
||||||
|
}
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
num = e.data
|
num = e.data
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/config.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
|
||||||
59
src/App.vue
59
src/App.vue
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app" style="position: relative">
|
<div id="app" style="position: relative" :class="{ mask: isLock }">
|
||||||
<router-view />
|
<router-view />
|
||||||
<div v-show="show" v-if="$route.matched.length > 0" v-adaptive @click="openI18n" style="
|
<div v-show="show" v-if="$route.matched.length > 0" v-adaptive @click="openI18n" style="
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
" size="mini"></el-input>
|
" size="mini"></el-input>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</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">
|
<template slot-scope="scope">
|
||||||
<el-select v-model="scope.row.State" clearable filterable size="mini">
|
<el-select v-model="scope.row.State" clearable filterable size="mini">
|
||||||
<el-option v-for="item of $d.InternationalizationKeyState"
|
<el-option v-for="item of $d.InternationalizationKeyState"
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
<feedBack v-if="$route.matched.length > 0" />
|
<feedBack v-if="$route.matched.length > 0" />
|
||||||
<timeTag />
|
<timeTag v-if="config.timeZone" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -97,6 +97,7 @@ import feedBack from '@/views/trials/trials-layout/components/feedBack'
|
||||||
import timeTag from '@/components/timeTag'
|
import timeTag from '@/components/timeTag'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import i18n from './lang'
|
import i18n from './lang'
|
||||||
|
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -112,11 +113,17 @@ export default {
|
||||||
arr: [],
|
arr: [],
|
||||||
il8nExternal: false,
|
il8nExternal: false,
|
||||||
State: null,
|
State: null,
|
||||||
|
config: window.config,
|
||||||
|
isLock: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.show = process.env.VUE_APP_OSS_PATH === '/test/dist'
|
this.show = process.env.VUE_APP_OSS_PATH === '/test/dist'
|
||||||
Vue.prototype.$openI18n = this.openI18n
|
Vue.prototype.$openI18n = this.openI18n
|
||||||
|
// this.getIsLock()
|
||||||
|
// DicomEvent.$on("isLock", (isLock) => {
|
||||||
|
// this.isLock = isLock
|
||||||
|
// })
|
||||||
},
|
},
|
||||||
// watch: {
|
// watch: {
|
||||||
// '$route.query': {
|
// '$route.query': {
|
||||||
|
|
@ -148,17 +155,30 @@ export default {
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
methods: {
|
methods: {
|
||||||
|
getIsLock() {
|
||||||
|
if (zzSessionStorage.getItem('isLock') === 'true') {
|
||||||
|
this.isLock = true
|
||||||
|
} else {
|
||||||
|
this.isLock = false
|
||||||
|
}
|
||||||
|
},
|
||||||
// 排序
|
// 排序
|
||||||
handleSortByColumn(column) {
|
handleSortByColumn(column) {
|
||||||
if (column.order === 'ascending') {
|
const { prop, order } = column
|
||||||
this.tableData.sort((a, b) =>
|
if (!prop || !order) {
|
||||||
a[column.prop].localeCompare(b[column.prop])
|
this.tableData = [...this.tableData]
|
||||||
)
|
return
|
||||||
} else {
|
|
||||||
this.tableData.sort((a, b) =>
|
|
||||||
b[column.prop].localeCompare(a[column.prop])
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
handleStateChange() {
|
||||||
this.tableData.forEach((item) => {
|
this.tableData.forEach((item) => {
|
||||||
|
|
@ -300,6 +320,23 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.mask {
|
||||||
|
position: relative;
|
||||||
|
filter: blur(2px);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mask::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
background: rgba(255, 253, 253, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
$light_gray: #606266;
|
$light_gray: #606266;
|
||||||
|
|
||||||
.el-tooltip__popper {
|
.el-tooltip__popper {
|
||||||
|
|
|
||||||
|
|
@ -391,3 +391,35 @@ export function getReSendEmail(data) {
|
||||||
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -432,3 +432,19 @@ export function studyUndoMaskImage(data) {
|
||||||
data
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -4467,3 +4467,11 @@ export function updateReadModuleClinicalData(data) {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTrialUnreadVisitList(params) {
|
||||||
|
return request({
|
||||||
|
url: `/DownloadAndUpload/getTrialUnreadVisitList`,
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
<div>Series #{{ dicomInfo.series }}</div>
|
<div>Series #{{ dicomInfo.series }}</div>
|
||||||
<div>Image #{{ dicomInfo.frame }}</div>
|
<div>Image #{{ dicomInfo.frame }}</div>
|
||||||
<div>{{ dicomInfo.modality }}</div>
|
<div>{{ dicomInfo.modality }}</div>
|
||||||
|
<div v-if="isComparison" style="font-size: 30px;color: #428bca;">{{ tip }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="dicomInfo.series" class="info-image">
|
<div v-show="dicomInfo.series" class="info-image">
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
|
|
@ -100,6 +101,7 @@ cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)')
|
||||||
// cornerstoneTools.init({ showSVGCursors: true })
|
// cornerstoneTools.init({ showSVGCursors: true })
|
||||||
cornerstoneTools.init()
|
cornerstoneTools.init()
|
||||||
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
|
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
|
||||||
|
console.log(cornerstoneTools, 'cornerstoneTools')
|
||||||
import DicomTags from './DicomTags'
|
import DicomTags from './DicomTags'
|
||||||
export default {
|
export default {
|
||||||
name: 'DicomCanvas',
|
name: 'DicomCanvas',
|
||||||
|
|
@ -109,6 +111,12 @@ export default {
|
||||||
return `${this.$store.state.trials.downloadSize}, NS: ${this.$store.state.trials.downloadTip}`
|
return `${this.$store.state.trials.downloadSize}, NS: ${this.$store.state.trials.downloadTip}`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
isComparison: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|
@ -166,6 +174,7 @@ export default {
|
||||||
orientationMarkers: [],
|
orientationMarkers: [],
|
||||||
originalMarkers: [],
|
originalMarkers: [],
|
||||||
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') },
|
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') },
|
||||||
|
tip: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -200,8 +209,12 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
loadImageStack(dicomSeries) {
|
loadImageStack(dicomSeries, text = '') {
|
||||||
|
this.tip = text
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
if (!dicomSeries || !Array.isArray(dicomSeries.imageIds) || dicomSeries.imageIds.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.series = dicomSeries
|
this.series = dicomSeries
|
||||||
this.stack.seriesId = dicomSeries.seriesId
|
this.stack.seriesId = dicomSeries.seriesId
|
||||||
this.stack.seriesNumber = dicomSeries.seriesNumber
|
this.stack.seriesNumber = dicomSeries.seriesNumber
|
||||||
|
|
@ -304,7 +317,7 @@ export default {
|
||||||
cornerstoneTools.addToolForElement(element, Note_RectangleRoiTool, {
|
cornerstoneTools.addToolForElement(element, Note_RectangleRoiTool, {
|
||||||
configuration: {
|
configuration: {
|
||||||
color: '#f00',
|
color: '#f00',
|
||||||
lineWidth: 0.5,
|
lineWidth: 2,
|
||||||
drawHandles: false,
|
drawHandles: false,
|
||||||
fillColor: 'rgba(0, 0, 0, 1)',
|
fillColor: 'rgba(0, 0, 0, 1)',
|
||||||
},
|
},
|
||||||
|
|
@ -378,17 +391,20 @@ export default {
|
||||||
// var instanceId = image.imageId.split('/')[image.imageId.split('/').length - 1]
|
// var instanceId = image.imageId.split('/')[image.imageId.split('/').length - 1]
|
||||||
// instanceId = instanceId.split('.')[0]
|
// instanceId = instanceId.split('.')[0]
|
||||||
// this.stack.instanceId = instanceId
|
// this.stack.instanceId = instanceId
|
||||||
this.height =
|
this.height = this.getStackHeightPercent()
|
||||||
(this.stack.currentImageIdIndex * 100) /
|
|
||||||
(this.stack.imageIds.length - 1)
|
|
||||||
this.resetWwwc()
|
this.resetWwwc()
|
||||||
},
|
},
|
||||||
onNewImage(e) {
|
onNewImage(e) {
|
||||||
e.detail.enabledElement.options = {}
|
e.detail.enabledElement.options = {}
|
||||||
var data = e.detail.image.data
|
var data = e.detail.image.data
|
||||||
this.dicomInfo.hospital = data.string('x00080080')
|
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 => item.ImageId === e.detail.image.imageId)
|
||||||
this.dicomInfo.IsMasked = instanceInfo.IsMasked
|
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('x00100020')
|
||||||
this.dicomInfo.pid = data.string('x00120040')
|
this.dicomInfo.pid = data.string('x00120040')
|
||||||
this.dicomInfo.name = data.string('x00100010')
|
this.dicomInfo.name = data.string('x00100010')
|
||||||
|
|
@ -421,10 +437,14 @@ export default {
|
||||||
this.stack.currentImageIdIndex = newImageIdIndex
|
this.stack.currentImageIdIndex = newImageIdIndex
|
||||||
this.stack.imageIdIndex = newImageIdIndex
|
this.stack.imageIdIndex = newImageIdIndex
|
||||||
this.series.imageIdIndex = newImageIdIndex
|
this.series.imageIdIndex = newImageIdIndex
|
||||||
this.height =
|
this.height = this.getStackHeightPercent()
|
||||||
(this.stack.currentImageIdIndex * 100) /
|
},
|
||||||
(this.stack.imageIds.length - 1)
|
getStackHeightPercent() {
|
||||||
this.resetWwwc()
|
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) {
|
stackScrollCallback(e) {
|
||||||
const { detail } = e
|
const { detail } = e
|
||||||
|
|
@ -435,9 +455,7 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.stack.currentImageIdIndex = e.detail.newImageIdIndex
|
this.stack.currentImageIdIndex = e.detail.newImageIdIndex
|
||||||
this.height =
|
this.height = this.getStackHeightPercent()
|
||||||
(this.stack.currentImageIdIndex * 100) /
|
|
||||||
(this.stack.imageIds.length - 1)
|
|
||||||
// var priority = new Date(new Date().setHours(23, 59, 59, 999)).getTime()
|
// var priority = new Date(new Date().setHours(23, 59, 59, 999)).getTime()
|
||||||
|
|
||||||
// requestPoolManager.loadAndCacheImagePlus(this.stack.imageIds[this.stack.currentImageIdIndex], this.stack.seriesId, priority)
|
// requestPoolManager.loadAndCacheImagePlus(this.stack.imageIds[this.stack.currentImageIdIndex], this.stack.seriesId, priority)
|
||||||
|
|
@ -731,6 +749,7 @@ export default {
|
||||||
var viewport = cornerstone.getViewport(this.canvas)
|
var viewport = cornerstone.getViewport(this.canvas)
|
||||||
// viewport.invert = false
|
// viewport.invert = false
|
||||||
var image = cornerstone.getImage(this.canvas)
|
var image = cornerstone.getImage(this.canvas)
|
||||||
|
if (!viewport || !image) return
|
||||||
viewport.voi.windowWidth = image.windowWidth
|
viewport.voi.windowWidth = image.windowWidth
|
||||||
viewport.voi.windowCenter = image.windowCenter
|
viewport.voi.windowCenter = image.windowCenter
|
||||||
cornerstone.setViewport(this.canvas, viewport)
|
cornerstone.setViewport(this.canvas, viewport)
|
||||||
|
|
@ -942,6 +961,16 @@ export default {
|
||||||
|
|
||||||
// this.reloadImage(this.canvas, 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) {
|
setToolActive(toolName) {
|
||||||
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
|
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
|
||||||
mouseButtonMask: 1,
|
mouseButtonMask: 1,
|
||||||
|
|
|
||||||
|
|
@ -3,45 +3,47 @@
|
||||||
<div ref="dicomViewer" class="dicom-viewer">
|
<div ref="dicomViewer" class="dicom-viewer">
|
||||||
<!-- <div v-for="i in layoutRow" :key="i" class="dicom-row" :style="{height: rowHeight}">
|
<!-- <div v-for="i in layoutRow" :key="i" class="dicom-row" :style="{height: rowHeight}">
|
||||||
<div v-for="j in layoutCol" :key="j" class="dicom-item" oncontextmenu="return false">
|
<div v-for="j in layoutCol" :key="j" class="dicom-item" oncontextmenu="return false">
|
||||||
<dicom-canvas ref="dicomCanvas" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>-->
|
</div>-->
|
||||||
<div class="Anonymous" v-if="isAnonymous">
|
<div class="Anonymous" v-if="isAnonymous">
|
||||||
<div
|
<div
|
||||||
:class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' && !isComparison, isNoted: isComparison }"
|
:class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' && !isComparison, isNoted: isComparison }"
|
||||||
@click="setToolActive($event, 'Note_RectangleRoi')">{{
|
@click="setToolActive($event, 'Note_RectangleRoi', true)">{{
|
||||||
$t('DicomViewer:anonymous:Note_RectangleRoi') }}</div>
|
$t('DicomViewer:anonymous:Note_RectangleRoi') }}</div>
|
||||||
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' && !isComparison, isNoted: isComparison }"
|
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' && !isComparison, isNoted: isComparison }"
|
||||||
@click="setToolActive($event, 'Eraser')">{{
|
@click="setToolActive($event, 'Eraser', true)">{{
|
||||||
$t('DicomViewer:anonymous:Eraser') }}
|
$t('DicomViewer:anonymous:Eraser') }}
|
||||||
</div>
|
</div>
|
||||||
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(false)">{{
|
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(false)">{{
|
||||||
$t('DicomViewer:anonymous:Application') }}</div>
|
$t('DicomViewer:anonymous:Application') }}</div>
|
||||||
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(true)">{{
|
<div :class="{ btn: true, isNoted: isComparison }" v-if="!isMultiple" @click="anonymousImage(true)">{{
|
||||||
$t('DicomViewer:anonymous:ApplicationAll') }}</div>
|
$t('DicomViewer:anonymous:ApplicationAll') }}</div>
|
||||||
<!-- <div class="btn">刷新图像</div> -->
|
<!-- <div class="btn">刷新图像</div> -->
|
||||||
<div class="btn" v-if="!isComparison" @click="comparison(true)">{{
|
<div class="btn" v-if="!isComparison" @click="comparison(true)">{{
|
||||||
$t('DicomViewer:anonymous:Comparison') }}</div>
|
$t('DicomViewer:anonymous:Comparison') }}</div>
|
||||||
<div class="btn" v-else @click="comparison(false)">{{
|
<div class="btn" v-else @click="comparison(false)">{{
|
||||||
$t('DicomViewer:anonymous:Exit') }}</div>
|
$t('DicomViewer:anonymous:Exit') }}</div>
|
||||||
<div :class="{ btn: true, isNoted: isComparison }" @click="recovery(false)">{{
|
<div :class="{ btn: true }" @click="recovery(false)">{{
|
||||||
$t('DicomViewer:anonymous:Recovery') }}</div>
|
$t('DicomViewer:anonymous:Recovery') }}</div>
|
||||||
|
<div :class="{ btn: true }" @click="recovery(true)">{{
|
||||||
|
$t('DicomViewer:anonymous:RecoveryAll') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }">
|
<div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }">
|
||||||
<div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item"
|
<div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas0' }" data-index="0" @click="activateDicomCanvas(0)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas0' }" data-index="0" @click="activateDicomCanvas(0)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas0" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas0" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow >= 1 && layoutCol >= 2" class="dicom-item"
|
<div v-show="layoutRow >= 1 && layoutCol >= 2" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas1' }" data-index="1" @click="activateDicomCanvas(1)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas1' }" data-index="1" @click="activateDicomCanvas(1)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas1" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas1" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow >= 1 && layoutCol >= 3" class="dicom-item"
|
<div v-show="layoutRow >= 1 && layoutCol >= 3" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas2' }" data-index="2" @click="activateDicomCanvas(2)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas2' }" data-index="2" @click="activateDicomCanvas(2)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas2" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas2" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -49,17 +51,17 @@
|
||||||
<div v-show="layoutRow >= 2 && layoutCol >= 1" class="dicom-item"
|
<div v-show="layoutRow >= 2 && layoutCol >= 1" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas3' }" data-index="3" @click="activateDicomCanvas(3)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas3' }" data-index="3" @click="activateDicomCanvas(3)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas3" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas3" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow >= 2 && layoutCol >= 2" class="dicom-item"
|
<div v-show="layoutRow >= 2 && layoutCol >= 2" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas4' }" data-index="4" @click="activateDicomCanvas(4)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas4' }" data-index="4" @click="activateDicomCanvas(4)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas4" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas4" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow >= 2 && layoutCol >= 3" class="dicom-item"
|
<div v-show="layoutRow >= 2 && layoutCol >= 3" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas5' }" data-index="5" @click="activateDicomCanvas(5)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas5' }" data-index="5" @click="activateDicomCanvas(5)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas5" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas5" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -67,17 +69,17 @@
|
||||||
<div v-show="layoutRow == 3 && layoutCol >= 1" class="dicom-item"
|
<div v-show="layoutRow == 3 && layoutCol >= 1" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas6' }" data-index="6" @click="activateDicomCanvas(6)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas6' }" data-index="6" @click="activateDicomCanvas(6)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas6" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas6" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow == 3 && layoutCol >= 2" class="dicom-item"
|
<div v-show="layoutRow == 3 && layoutCol >= 2" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas7' }" data-index="7" @click="activateDicomCanvas(7)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas7' }" data-index="7" @click="activateDicomCanvas(7)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas7" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas7" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="layoutRow == 3 && layoutCol >= 3" class="dicom-item"
|
<div v-show="layoutRow == 3 && layoutCol >= 3" class="dicom-item"
|
||||||
:class="{ 'activeItem': activeItem == 'dicomCanvas8' }" data-index="8" @click="activateDicomCanvas(8)"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas8' }" data-index="8" @click="activateDicomCanvas(8)"
|
||||||
@dblclick="setFullScreen($event)">
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas8" style="width:100%;height:100%" />
|
<dicom-canvas :isComparison="isComparison" ref="dicomCanvas8" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -99,8 +101,10 @@
|
||||||
<option value="3x2">3x2</option>
|
<option value="3x2">3x2</option>
|
||||||
<option value="3x3">3x3</option>
|
<option value="3x3">3x3</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="btnBox" v-if="hasAnonymous" @click="openAnonymous">{{ $t('DicomViewer:anonymous:PixelAnonymity')
|
<div :class="{ btnBox: true, activeBtnBox: isAnonymous }" v-if="hasAnonymous && hasPermi(['role:iqc'])"
|
||||||
}}
|
@click="openAnonymous">{{
|
||||||
|
$t('DicomViewer:anonymous:PixelAnonymity')
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -299,7 +303,8 @@
|
||||||
v-if="type === 'Study' && modality && ['PT、CT', 'CT、PT', 'PET-CT'].includes(modality)">
|
v-if="type === 'Study' && modality && ['PT、CT', 'CT、PT', 'PET-CT'].includes(modality)">
|
||||||
<div class="sideTool-title">{{ $t('trials:tab:patientData') }}</div>
|
<div class="sideTool-title">{{ $t('trials:tab:patientData') }}</div>
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<el-form ref="patientForm" size="mini" :model="formData" :rules="rules" label-width="150" v-loading="formLoading">
|
<el-form ref="patientForm" size="mini" :model="formData" :rules="rules" label-width="150"
|
||||||
|
v-loading="formLoading">
|
||||||
<!-- 性别 -->
|
<!-- 性别 -->
|
||||||
<el-form-item :label="$t('trials:ptData:label:patientSex')" prop="PatientSex">
|
<el-form-item :label="$t('trials:ptData:label:patientSex')" prop="PatientSex">
|
||||||
<el-select v-model="formData.PatientSex" :placeholder="$t('common:ruleMessage:select')"
|
<el-select v-model="formData.PatientSex" :placeholder="$t('common:ruleMessage:select')"
|
||||||
|
|
@ -323,15 +328,17 @@
|
||||||
<el-input v-model.number="formData.RadionuclideHalfLife" :placeholder="$t('trials:halfLife:eg')"
|
<el-input v-model.number="formData.RadionuclideHalfLife" :placeholder="$t('trials:halfLife:eg')"
|
||||||
style="width: 100%" :disabled="!isEdit"></el-input>
|
style="width: 100%" :disabled="!isEdit"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 注射时间(s) Unix 秒 或 相对秒-->
|
<!-- 注射时间 HHMMSS-->
|
||||||
<el-form-item :label="$t('trials:ptData:label:injectTime')" prop="RadiopharmaceuticalStartTime">
|
<el-form-item :label="$t('trials:ptData:label:injectTime')" prop="RadiopharmaceuticalStartTime">
|
||||||
<el-input v-model.number="formData.RadiopharmaceuticalStartTime" :placeholder="$t('trials:injectTime:eg')"
|
<el-input v-model.trim="formData.RadiopharmaceuticalStartTime" :placeholder="$t('trials:injectTime:eg')"
|
||||||
style="width: 100%" @input="computeTimeRelation" :disabled="!isEdit"></el-input>
|
@blur="handleTimeBlur('RadiopharmaceuticalStartTime')" maxlength="6" style="width: 100%"
|
||||||
|
@input="computeTimeRelation" :disabled="!isEdit"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 成像时间(s) Unix 秒 或 相对秒-->
|
<!-- 成像时间 HHMMSS-->
|
||||||
<el-form-item :label="$t('trials:ptData:label:acquisitionTime')" prop="AcquisitionTime">
|
<el-form-item :label="$t('trials:ptData:label:acquisitionTime')" prop="AcquisitionTime">
|
||||||
<el-input v-model.number="formData.AcquisitionTime" :placeholder="$t('trials:injectTime:eg')"
|
<el-input v-model.trim="formData.AcquisitionTime" @blur="handleTimeBlur('AcquisitionTime')" maxlength="6"
|
||||||
style="width: 100%" @input="computeTimeRelation" :disabled="!isEdit"></el-input>
|
:placeholder="$t('trials:injectTime:eg')" style="width: 100%" @input="computeTimeRelation"
|
||||||
|
:disabled="!isEdit"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 时间一致性检查 -->
|
<!-- 时间一致性检查 -->
|
||||||
<!-- <el-form-item :label="$t('trials:ptData:label:timeCheck')">
|
<!-- <el-form-item :label="$t('trials:ptData:label:timeCheck')">
|
||||||
|
|
@ -401,7 +408,7 @@ export default {
|
||||||
handler(v) {
|
handler(v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
if (this.type === 'Study' && ['PT、CT', 'CT、PT', 'PET-CT'].includes(v)) {
|
if (this.type === 'Study' && ['PT、CT', 'CT、PT', 'PET-CT'].includes(v)) {
|
||||||
this.$nextTick(()=>{
|
this.$nextTick(() => {
|
||||||
this.getPatientInfo()
|
this.getPatientInfo()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -443,8 +450,8 @@ export default {
|
||||||
PatientWeight: null,
|
PatientWeight: null,
|
||||||
RadionuclideTotalDose: null,
|
RadionuclideTotalDose: null,
|
||||||
RadionuclideHalfLife: null,
|
RadionuclideHalfLife: null,
|
||||||
RadiopharmaceuticalStartTime: null,
|
RadiopharmaceuticalStartTime: '',
|
||||||
AcquisitionTime: null,
|
AcquisitionTime: '',
|
||||||
TimeCheck: ''
|
TimeCheck: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
|
|
@ -465,11 +472,11 @@ export default {
|
||||||
],
|
],
|
||||||
RadiopharmaceuticalStartTime: [
|
RadiopharmaceuticalStartTime: [
|
||||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
{ type: 'number', message: this.$t('trials:ptData:ruleMessage:number2'), trigger: 'blur' }//请输入数字
|
{ validator: this.validateDicomTime, trigger: 'blur' }
|
||||||
],
|
],
|
||||||
AcquisitionTime: [
|
AcquisitionTime: [
|
||||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
{ type: 'number', message: this.$t('trials:ptData:ruleMessage:number2'), trigger: 'blur' },//请输入数字
|
{ validator: this.validateDicomTime, trigger: 'blur' },
|
||||||
// 自定义校验:确保成像时间不早于注射时间
|
// 自定义校验:确保成像时间不早于注射时间
|
||||||
{ validator: this.validateTime, trigger: 'blur' }
|
{ validator: this.validateTime, trigger: 'blur' }
|
||||||
]
|
]
|
||||||
|
|
@ -479,6 +486,11 @@ export default {
|
||||||
isEdit: 0
|
isEdit: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isMultiple() {
|
||||||
|
return this.series?.instanceInfoList[0]?.NumberOfFrames > 1
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
|
let type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
|
||||||
this.hasAnonymous = type === 'Study'
|
this.hasAnonymous = type === 'Study'
|
||||||
|
|
@ -492,16 +504,14 @@ export default {
|
||||||
this.colormapsList = cornerstone.colors.getColormapsList()
|
this.colormapsList = cornerstone.colors.getColormapsList()
|
||||||
this.currentDicomCanvas = this.$refs['dicomCanvas0']
|
this.currentDicomCanvas = this.$refs['dicomCanvas0']
|
||||||
this.type = this.$route.query.type
|
this.type = this.$route.query.type
|
||||||
this.isEdit = parseInt(this.$route.query.showDelete)
|
this.isEdit = parseInt(this.$route.query.showDelete) || parseInt(this.$route.query.showEdit)
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
clearPTClinicalDataCache()
|
clearPTClinicalDataCache()
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
comparison(f) {
|
setToolsPassive() {
|
||||||
this.isComparison = f
|
|
||||||
this.$emit("update:Comparison", f)
|
|
||||||
const elements = document.querySelectorAll('.dicom-item')
|
const elements = document.querySelectorAll('.dicom-item')
|
||||||
const scope = this
|
const scope = this
|
||||||
Array.from(elements).forEach((element, index) => {
|
Array.from(elements).forEach((element, index) => {
|
||||||
|
|
@ -510,12 +520,21 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
scope.activeTool = null
|
scope.activeTool = null
|
||||||
if (this.isComparison) {
|
},
|
||||||
|
comparison(f) {
|
||||||
|
this.setToolsPassive()
|
||||||
|
if (f) {
|
||||||
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(obj => {
|
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(obj => {
|
||||||
let { image } = obj
|
let { image } = obj
|
||||||
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
|
let instanceInfo = this.series.instanceInfoList.find(item => {
|
||||||
|
let s1 = item.ImageId.split("?")[0]
|
||||||
|
let s2 = image.imageId.split("?")[0]
|
||||||
|
return s1 === s2
|
||||||
|
})
|
||||||
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
|
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
|
||||||
this.changeLayout('1x2')
|
this.changeLayout('1x2')
|
||||||
|
this.isComparison = f
|
||||||
|
this.$emit("update:Comparison", f)
|
||||||
let serie = {}
|
let serie = {}
|
||||||
Object.keys(this.series).forEach(key => {
|
Object.keys(this.series).forEach(key => {
|
||||||
if (key !== 'instanceInfoList' && key !== 'imageIds') {
|
if (key !== 'instanceInfoList' && key !== 'imageIds') {
|
||||||
|
|
@ -531,8 +550,6 @@ export default {
|
||||||
})
|
})
|
||||||
info0.ImageId = imageId
|
info0.ImageId = imageId
|
||||||
info1.ImageId = newImageId
|
info1.ImageId = newImageId
|
||||||
console.log(info0)
|
|
||||||
console.log(info1)
|
|
||||||
let dicomCanvas0_info = Object.assign({
|
let dicomCanvas0_info = Object.assign({
|
||||||
instanceInfoList: [
|
instanceInfoList: [
|
||||||
info0
|
info0
|
||||||
|
|
@ -545,23 +562,30 @@ export default {
|
||||||
],
|
],
|
||||||
imageIds: [newImageId]
|
imageIds: [newImageId]
|
||||||
}, serie)
|
}, serie)
|
||||||
console.log(dicomCanvas0_info, 'dicomCanvas0_info')
|
this.$refs[`dicomCanvas0`].loadImageStack(dicomCanvas0_info, this.$t('DicomViewer:anonymous:after'))
|
||||||
console.log(dicomCanvas1_info, 'dicomCanvas0_info')
|
this.$refs[`dicomCanvas1`].loadImageStack(dicomCanvas1_info, this.$t('DicomViewer:anonymous:before'))
|
||||||
this.$refs[`dicomCanvas0`].loadImageStack(dicomCanvas0_info)
|
|
||||||
this.$refs[`dicomCanvas1`].loadImageStack(dicomCanvas1_info)
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
this.isComparison = f
|
||||||
|
this.$emit("update:Comparison", f)
|
||||||
this.changeLayout('1x1')
|
this.changeLayout('1x1')
|
||||||
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
|
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
recovery(isAll = false) {
|
recovery(isAll = false) {
|
||||||
if (this.isComparison) return false
|
// if (this.isComparison) return false
|
||||||
|
if (this.isAnonymous) {
|
||||||
|
this.comparison(false)
|
||||||
|
}
|
||||||
|
this.setToolsPassive()
|
||||||
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
|
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
|
||||||
let { image } = obj
|
let { image } = obj
|
||||||
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
|
let instanceInfo = this.series.instanceInfoList.find(item => {
|
||||||
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
|
let s1 = item.ImageId.split("?")[0]
|
||||||
|
let s2 = image.imageId.split("?")[0]
|
||||||
|
return s1 === s2
|
||||||
|
})
|
||||||
|
if ((!instanceInfo.IsMasked && !isAll) || (isAll && this.series.instanceInfoList.every(item => !item.IsMasked))) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
|
||||||
let data = {
|
let data = {
|
||||||
// SeriesId: this.series.seriesId,
|
// SeriesId: this.series.seriesId,
|
||||||
instanceIdList: [instanceInfo.Id]
|
instanceIdList: [instanceInfo.Id]
|
||||||
|
|
@ -573,6 +597,11 @@ export default {
|
||||||
let res = await this.studyUndoMaskImage(data)
|
let res = await this.studyUndoMaskImage(data)
|
||||||
if (!res) return false
|
if (!res) return false
|
||||||
this.$emit("update:loading", true)
|
this.$emit("update:loading", true)
|
||||||
|
let isMultiple = false
|
||||||
|
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1 && isAll === false) {
|
||||||
|
isAll = true;
|
||||||
|
isMultiple = true;
|
||||||
|
}
|
||||||
if (!isAll) {
|
if (!isAll) {
|
||||||
let strs = image.imageId.split("?")
|
let strs = image.imageId.split("?")
|
||||||
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
|
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
|
||||||
|
|
@ -587,30 +616,23 @@ export default {
|
||||||
this.series.imageIds.splice(index, 1, newImageId)
|
this.series.imageIds.splice(index, 1, newImageId)
|
||||||
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
|
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
|
||||||
} else {
|
} else {
|
||||||
let arr = []
|
|
||||||
this.series.instanceInfoList.forEach(item => {
|
|
||||||
let strs = item.ImageId.split("?")
|
|
||||||
let info = res.find(i => item.Id === i.Id)
|
|
||||||
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${info.Path}?${strs[1]}`
|
|
||||||
item.ImageId = newImageId
|
|
||||||
item.IsMasked = false
|
|
||||||
arr.push(newImageId)
|
|
||||||
})
|
|
||||||
this.series.imageIds = arr
|
|
||||||
console.log(this.series, 'this.series')
|
|
||||||
// this.loadImageStack(this.series)
|
|
||||||
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
|
|
||||||
}
|
}
|
||||||
|
this.$emit('loadStudy', this.series.seriesId)
|
||||||
this.$emit("update:loading", false)
|
this.$emit("update:loading", false)
|
||||||
this.$emit('loadStudy', false)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
anonymousImage(isAll = false) {
|
anonymousImage(isAll = false) {
|
||||||
if (this.isComparison) return false
|
if (this.isComparison) return false
|
||||||
|
this.setToolsPassive()
|
||||||
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
|
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
|
||||||
let { toolInfo, image } = obj
|
let { toolInfo, image } = obj
|
||||||
if (!toolInfo || toolInfo.data.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:notMark"))
|
if (!toolInfo || toolInfo.data.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:notMark"))
|
||||||
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
|
let instanceInfo = this.series.instanceInfoList.find(item => {
|
||||||
|
let s1 = item.ImageId.split("?")[0]
|
||||||
|
let s2 = image.imageId.split("?")[0]
|
||||||
|
return s1 === s2
|
||||||
|
})
|
||||||
let data = {
|
let data = {
|
||||||
// SeriesId: this.series.seriesId,
|
// SeriesId: this.series.seriesId,
|
||||||
instanceIdList: [instanceInfo.Id],
|
instanceIdList: [instanceInfo.Id],
|
||||||
|
|
@ -641,8 +663,13 @@ export default {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
let res = await this.studyMaskImage(data)
|
let res = await this.studyMaskImage(data)
|
||||||
if (!res) return false
|
if (!res || res.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:studyMaskImageFail"))
|
||||||
this.$emit("update:loading", true)
|
this.$emit("update:loading", true)
|
||||||
|
let isMultiple = false
|
||||||
|
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1 && isAll === false) {
|
||||||
|
isAll = true;
|
||||||
|
isMultiple = true;
|
||||||
|
}
|
||||||
if (!isAll) {
|
if (!isAll) {
|
||||||
let strs = image.imageId.split("?")
|
let strs = image.imageId.split("?")
|
||||||
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
|
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
|
||||||
|
|
@ -657,22 +684,13 @@ export default {
|
||||||
this.series.imageIds.splice(index, 1, newImageId)
|
this.series.imageIds.splice(index, 1, newImageId)
|
||||||
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
|
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
|
||||||
} else {
|
} else {
|
||||||
let arr = []
|
|
||||||
this.series.instanceInfoList.forEach(item => {
|
|
||||||
let strs = item.ImageId.split("?")
|
|
||||||
let info = res.find(i => item.Id === i.Id)
|
|
||||||
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${info.Path}?${strs[1]}`
|
|
||||||
item.ImageId = newImageId
|
|
||||||
item.IsMasked = true
|
|
||||||
arr.push(newImageId)
|
|
||||||
})
|
|
||||||
this.series.imageIds = arr
|
|
||||||
console.log(this.series, 'this.series')
|
|
||||||
// this.loadImageStack(this.series)
|
|
||||||
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
|
|
||||||
}
|
}
|
||||||
this.$emit("update:loading", false)
|
this.$refs[`dicomCanvas0`].removeNote_RectangleRoi()
|
||||||
this.$emit('loadStudy', false)
|
setTimeout(() => {
|
||||||
|
this.$emit('loadStudy', this.series.seriesId)
|
||||||
|
this.$emit("update:loading", false)
|
||||||
|
}, 500)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
openAnonymous() {
|
openAnonymous() {
|
||||||
|
|
@ -839,8 +857,25 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setToolActive(e, toolName) {
|
setToolActive(e, toolName, isNotSetClassName = false) {
|
||||||
const elements = document.querySelectorAll('.dicom-item')
|
const elements = document.querySelectorAll('.dicom-item')
|
||||||
|
if (isNotSetClassName) {
|
||||||
|
const scope = this
|
||||||
|
if (scope.activeTool) {
|
||||||
|
Array.from(elements).forEach((element, index) => {
|
||||||
|
if (element.style.display !== 'none') {
|
||||||
|
scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (scope.activeTool === toolName) return scope.activeTool = null
|
||||||
|
scope.activeTool = toolName
|
||||||
|
return Array.from(elements).forEach((element, index) => {
|
||||||
|
if (element.style.display !== 'none') {
|
||||||
|
scope.$refs[`dicomCanvas${index}`].setToolActive(toolName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
if (e.currentTarget.classList.contains('activeTool')) {
|
if (e.currentTarget.classList.contains('activeTool')) {
|
||||||
e.currentTarget.classList.remove('activeTool')
|
e.currentTarget.classList.remove('activeTool')
|
||||||
const scope = this
|
const scope = this
|
||||||
|
|
@ -995,12 +1030,68 @@ export default {
|
||||||
// 时间一致性校验
|
// 时间一致性校验
|
||||||
validateTime(rule, value, callback) {
|
validateTime(rule, value, callback) {
|
||||||
const { RadiopharmaceuticalStartTime } = this.formData
|
const { RadiopharmaceuticalStartTime } = this.formData
|
||||||
if (value && RadiopharmaceuticalStartTime !== null && value < RadiopharmaceuticalStartTime) {
|
const acquireSeconds = this.timeToSeconds(value)
|
||||||
|
const startSeconds = this.timeToSeconds(RadiopharmaceuticalStartTime)
|
||||||
|
if (acquireSeconds !== null && startSeconds !== null && acquireSeconds < startSeconds) {
|
||||||
callback(new Error(this.$t('trials:ptData:ruleMessage:number3')))//成像时间不能早于注射时间
|
callback(new Error(this.$t('trials:ptData:ruleMessage:number3')))//成像时间不能早于注射时间
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
validateDicomTime(rule, value, callback) {
|
||||||
|
if (value === undefined || value === null || value === '') {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const raw = String(value).trim()
|
||||||
|
if (!/^\d{1,6}$/.test(raw)) {
|
||||||
|
callback(new Error(this.$t('trials:ptData:ruleMessage:number2')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const normalized = this.normalizeClinicalTime(raw)
|
||||||
|
if (!this.isValidDicomTime(normalized)) {
|
||||||
|
callback(new Error(this.$t('trials:ptData:ruleMessage:number4')))//请输入有效时间(HHMMSS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
normalizeClinicalTime(value) {
|
||||||
|
if (value === undefined || value === null || value === '') return ''
|
||||||
|
const digits = String(value).trim().replace(/[^\d]/g, '')
|
||||||
|
if (!digits) return ''
|
||||||
|
return digits.slice(0, 6).padStart(6, '0')
|
||||||
|
},
|
||||||
|
isValidDicomTime(value) {
|
||||||
|
if (!/^\d{6}$/.test(String(value || ''))) return false
|
||||||
|
const normalized = String(value)
|
||||||
|
const hh = Number(normalized.slice(0, 2))
|
||||||
|
const mm = Number(normalized.slice(2, 4))
|
||||||
|
const ss = Number(normalized.slice(4, 6))
|
||||||
|
return hh >= 0 && hh <= 23 && mm >= 0 && mm <= 59 && ss >= 0 && ss <= 59
|
||||||
|
},
|
||||||
|
timeToSeconds(value) {
|
||||||
|
const normalized = this.normalizeClinicalTime(value)
|
||||||
|
if (!this.isValidDicomTime(normalized)) return null
|
||||||
|
const hh = Number(normalized.slice(0, 2))
|
||||||
|
const mm = Number(normalized.slice(2, 4))
|
||||||
|
const ss = Number(normalized.slice(4, 6))
|
||||||
|
return hh * 3600 + mm * 60 + ss
|
||||||
|
},
|
||||||
|
handleTimeBlur(field) {
|
||||||
|
const value = this.formData[field]
|
||||||
|
if (value === undefined || value === null || value === '') return
|
||||||
|
this.formData[field] = this.normalizeClinicalTime(value)
|
||||||
|
this.computeTimeRelation()
|
||||||
|
},
|
||||||
|
normalizeTimeFields() {
|
||||||
|
this.formData.RadiopharmaceuticalStartTime = this.normalizeClinicalTime(
|
||||||
|
this.formData.RadiopharmaceuticalStartTime
|
||||||
|
)
|
||||||
|
this.formData.AcquisitionTime = this.normalizeClinicalTime(
|
||||||
|
this.formData.AcquisitionTime
|
||||||
|
)
|
||||||
|
this.computeTimeRelation()
|
||||||
|
},
|
||||||
computeTimeRelation() {
|
computeTimeRelation() {
|
||||||
const startTime = this.formData.RadiopharmaceuticalStartTime
|
const startTime = this.formData.RadiopharmaceuticalStartTime
|
||||||
const acquireTime = this.formData.AcquisitionTime
|
const acquireTime = this.formData.AcquisitionTime
|
||||||
|
|
@ -1010,7 +1101,14 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startTime <= acquireTime) {
|
const startSeconds = this.timeToSeconds(startTime)
|
||||||
|
const acquireSeconds = this.timeToSeconds(acquireTime)
|
||||||
|
if (startSeconds === null || acquireSeconds === null) {
|
||||||
|
this.formData.TimeCheck = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startSeconds <= acquireSeconds) {
|
||||||
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val1') //注射时间 ≤ 成像时间
|
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val1') //注射时间 ≤ 成像时间
|
||||||
} else {
|
} else {
|
||||||
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val2') //注射时间 > 成像时间
|
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val2') //注射时间 > 成像时间
|
||||||
|
|
@ -1020,22 +1118,22 @@ export default {
|
||||||
try {
|
try {
|
||||||
this.formLoading = true
|
this.formLoading = true
|
||||||
let studyId = this.$route.query.studyId
|
let studyId = this.$route.query.studyId
|
||||||
let res = await getPatientInfo({studyId: studyId})
|
let res = await getPatientInfo({ studyId: studyId })
|
||||||
this.formData = {
|
this.formData = {
|
||||||
Id: res.Result.Id || '',
|
Id: res.Result.Id || '',
|
||||||
PatientSex: res.Result.PatientSex || '',
|
PatientSex: res.Result.PatientSex || '',
|
||||||
PatientWeight: parseFloat(res.Result.PatientWeight) || null,
|
PatientWeight: parseFloat(res.Result.PatientWeight) || null,
|
||||||
RadionuclideTotalDose: parseFloat(res.Result.RadionuclideTotalDose) || null,
|
RadionuclideTotalDose: parseFloat(res.Result.RadionuclideTotalDose) || null,
|
||||||
RadionuclideHalfLife: parseFloat(res.Result.RadionuclideHalfLife) || null,
|
RadionuclideHalfLife: parseFloat(res.Result.RadionuclideHalfLife) || null,
|
||||||
RadiopharmaceuticalStartTime: parseFloat(res.Result.RadiopharmaceuticalStartTime) || '',
|
RadiopharmaceuticalStartTime: this.normalizeClinicalTime(res.Result.RadiopharmaceuticalStartTime),
|
||||||
AcquisitionTime: parseFloat(res.Result.AcquisitionTime) || '',
|
AcquisitionTime: this.normalizeClinicalTime(res.Result.AcquisitionTime),
|
||||||
TimeCheck: ''
|
TimeCheck: ''
|
||||||
}
|
}
|
||||||
this.computeTimeRelation()
|
this.computeTimeRelation()
|
||||||
// 缓存 PT 临床数据:用于 2D SUV 计算时优先使用接口/人工录入值
|
// 缓存 PT 临床数据:用于 2D SUV 计算时优先使用接口/人工录入值
|
||||||
this.cachePtClinicalDataToInstances()
|
this.cachePtClinicalDataToInstances()
|
||||||
this.formLoading = false
|
this.formLoading = false
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
this.formLoading = false
|
this.formLoading = false
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
@ -1118,6 +1216,7 @@ export default {
|
||||||
try {
|
try {
|
||||||
let valid = await this.$refs.patientForm.validate()
|
let valid = await this.$refs.patientForm.validate()
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
|
this.normalizeTimeFields()
|
||||||
this.formLoading = true
|
this.formLoading = true
|
||||||
let res = await editPatientInfo(this.formData)
|
let res = await editPatientInfo(this.formData)
|
||||||
this.formLoading = false
|
this.formLoading = false
|
||||||
|
|
@ -1149,31 +1248,35 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
z-index: 9999;
|
z-index: 2000;
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
width: 15%;
|
width: 12%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: rgba(255, 255, 255, .3);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border: 1px solid rgba(255, 255, 255, .7);
|
color: #428bca;
|
||||||
|
background: #ecf3fa;
|
||||||
&:hover {
|
border-color: #b3d1ea;
|
||||||
background-color: rgba(255, 255, 255, .5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.activeBtn {
|
.activeBtn {
|
||||||
background-color: rgba(255, 255, 255, .5);
|
background: #428bca;
|
||||||
|
border-color: #428bca;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.isNoted {
|
// &:hover {
|
||||||
cursor: not-allowed;
|
// background-color: rgba(255, 255, 255, .5);
|
||||||
}
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.isNoted {
|
||||||
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -1225,13 +1328,21 @@ export default {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: rgba(255, 255, 255, .3);
|
color: #428bca;
|
||||||
|
background: #ecf3fa;
|
||||||
|
border-color: #b3d1ea;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border: 1px solid rgba(255, 255, 255, .7);
|
border: 1px solid rgba(255, 255, 255, .7);
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dicom-tools .activeBtnBox {
|
||||||
|
background: #428bca;
|
||||||
|
border-color: #428bca;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dicom-row {
|
.dicom-wrapper .dicom-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ export default {
|
||||||
// document.cookie = 'TrialId=' + this.$route.query.trialId + ';path=/'
|
// document.cookie = 'TrialId=' + this.$route.query.trialId + ';path=/'
|
||||||
},
|
},
|
||||||
trialId(v) {
|
trialId(v) {
|
||||||
|
if (!this.$route.query.trialId) return
|
||||||
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
||||||
var total = res.OtherInfo.NeedSignCount
|
var total = res.OtherInfo.NeedSignCount
|
||||||
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
||||||
|
|
@ -100,15 +101,17 @@ export default {
|
||||||
if (~url.indexOf('?')) {
|
if (~url.indexOf('?')) {
|
||||||
query = url.split('?')[1]
|
query = url.split('?')[1]
|
||||||
}
|
}
|
||||||
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
if (this.$route.query.trialId) {
|
||||||
var total = res.OtherInfo.NeedSignCount
|
getUserDocumentList({ TrialId: this.$route.query.trialId }).then(async res => {
|
||||||
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
var total = res.OtherInfo.NeedSignCount
|
||||||
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
|
var TrialStatusStr = res.OtherInfo.TrialStatusStr
|
||||||
this.TrialStatusStr = TrialStatusStr
|
this.IsAdditionalAssessment = res.OtherInfo.IsAdditionalAssessment
|
||||||
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
|
this.TrialStatusStr = TrialStatusStr
|
||||||
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
|
await store.dispatch('user/setTotalNeedSignTrialDocCount', total)
|
||||||
this.TrialConfig = res.OtherInfo.TrialConfig
|
await store.dispatch('user/setTrialStatusStr', TrialStatusStr)
|
||||||
})
|
this.TrialConfig = res.OtherInfo.TrialConfig
|
||||||
|
})
|
||||||
|
}
|
||||||
this.selectedTab()
|
this.selectedTab()
|
||||||
this.getTrialList()
|
this.getTrialList()
|
||||||
var firstGoIn = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children[0]
|
var firstGoIn = this.trialsRouter.children.find(v => { return v.name === 'TrialsPanel' }).children[0]
|
||||||
|
|
@ -132,6 +135,9 @@ export default {
|
||||||
let chartList = [
|
let chartList = [
|
||||||
'/trials/trials-panel/trial-summary/report-forms'
|
'/trials/trials-panel/trial-summary/report-forms'
|
||||||
]
|
]
|
||||||
|
let dataSyncList = [
|
||||||
|
`/trials/trials-panel/trial-summary/data-sync`
|
||||||
|
]
|
||||||
var qualityList = [
|
var qualityList = [
|
||||||
'/trials/trials-panel/visit/crc-question',
|
'/trials/trials-panel/visit/crc-question',
|
||||||
'/trials/trials-panel/visit/qc-check',
|
'/trials/trials-panel/visit/qc-check',
|
||||||
|
|
@ -147,6 +153,9 @@ export default {
|
||||||
'/trials/trials-panel/trial-summary/image-inspect',
|
'/trials/trials-panel/trial-summary/image-inspect',
|
||||||
'/trials/trials-panel/trial-summary/push-record',
|
'/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'])) {
|
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
|
isShow = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,13 +85,14 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<!--type !== 'detail'-->
|
<!--type !== 'detail'-->
|
||||||
<div slot="footer" v-if="level >= 8 || isImgfail">
|
<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') }}
|
{{ $t('feedBack:button:cancel') }}
|
||||||
</el-button>
|
</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') }}
|
{{ $t('feedBack:button:save') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ export default {
|
||||||
zIndex: 9,
|
zIndex: 9,
|
||||||
chart: null,
|
chart: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
key: 'readingChart'
|
key: 'readingChart',
|
||||||
|
isInteger: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -101,12 +102,13 @@ export default {
|
||||||
let res = await getReportsChartData(params)
|
let res = await getReportsChartData(params)
|
||||||
this.loading = false
|
this.loading = false
|
||||||
if (res.IsSuccess) {
|
if (res.IsSuccess) {
|
||||||
|
this.isInteger = res.Result.Type === 'number' && res.Result.ValueType === 0
|
||||||
let LatestScanDateList = res.Result.LatestScanDateList.map(item => item.split(" ")[0])
|
let LatestScanDateList = res.Result.LatestScanDateList.map(item => item.split(" ")[0])
|
||||||
let obj = {
|
let obj = {
|
||||||
title: QuestionName,
|
title: QuestionName,
|
||||||
xAxisData: LatestScanDateList || [],
|
xAxisData: LatestScanDateList || [],
|
||||||
series: [],
|
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,
|
visitName: res.Result.VisitTaskNameList,
|
||||||
min: null,
|
min: null,
|
||||||
max: null
|
max: null
|
||||||
|
|
@ -123,43 +125,6 @@ export default {
|
||||||
type: 'line'
|
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)
|
this.initChart(obj)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -236,6 +201,9 @@ export default {
|
||||||
},
|
},
|
||||||
series: obj.series
|
series: obj.series
|
||||||
};
|
};
|
||||||
|
if (this.isInteger) {
|
||||||
|
option.yAxis.minInterval = 1
|
||||||
|
}
|
||||||
// 4. 使用配置项渲染图表
|
// 4. 使用配置项渲染图表
|
||||||
this.chart.setOption(option);
|
this.chart.setOption(option);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -12,33 +12,16 @@
|
||||||
<!--受试者-->
|
<!--受试者-->
|
||||||
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" sortable />
|
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" sortable />
|
||||||
<!--访视名称-->
|
<!--访视名称-->
|
||||||
<el-table-column
|
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" v-if="IsImageSegment" sortable />
|
||||||
prop="VisitName"
|
|
||||||
:label="$t('download:table:VisitName')"
|
|
||||||
v-if="IsImageSegment"
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<!--任务名称-->
|
<!--任务名称-->
|
||||||
<el-table-column
|
<el-table-column prop="TaskBlindName" :label="$t('upload:dicom:table:taskBlindName')" v-else sortable />
|
||||||
prop="TaskBlindName"
|
|
||||||
:label="$t('upload:dicom:table:taskBlindName')"
|
|
||||||
v-else
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<!--原始检查数-->
|
<!--原始检查数-->
|
||||||
<el-table-column
|
<el-table-column prop="OrginalStudyList" :label="$t('upload:dicom:table:orginalStudyListNum')">
|
||||||
prop="OrginalStudyList"
|
|
||||||
:label="$t('upload:dicom:table:orginalStudyListNum')"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button v-if="
|
||||||
v-if="
|
|
||||||
scope.row.OrginalStudyList &&
|
scope.row.OrginalStudyList &&
|
||||||
scope.row.OrginalStudyList.length >= 1
|
scope.row.OrginalStudyList.length >= 1
|
||||||
"
|
" type="text" @click="handleOpenDialog(scope.row, 'OrginalStudyList')">
|
||||||
type="text"
|
|
||||||
@click="handleOpenDialog(scope.row, 'OrginalStudyList')"
|
|
||||||
>
|
|
||||||
<span>{{ scope.row.OrginalStudyList.length }}</span>
|
<span>{{ scope.row.OrginalStudyList.length }}</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<span v-else>0</span>
|
<span v-else>0</span>
|
||||||
|
|
@ -47,13 +30,9 @@
|
||||||
<!--后处理检查数-->
|
<!--后处理检查数-->
|
||||||
<el-table-column prop="UploadStudyList" :label="$t('upload:dicom:table:uploadStudyListNum')">
|
<el-table-column prop="UploadStudyList" :label="$t('upload:dicom:table:uploadStudyListNum')">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button v-if="
|
||||||
v-if="
|
|
||||||
scope.row.UploadStudyList && scope.row.UploadStudyList.length >= 1
|
scope.row.UploadStudyList && scope.row.UploadStudyList.length >= 1
|
||||||
"
|
" type="text" @click="handleOpenDialog(scope.row, 'UploadStudyList', true)">
|
||||||
type="text"
|
|
||||||
@click="handleOpenDialog(scope.row, 'UploadStudyList', true)"
|
|
||||||
>
|
|
||||||
<span>{{ scope.row.UploadStudyList.length }}</span>
|
<span>{{ scope.row.UploadStudyList.length }}</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<span v-else>0</span>
|
<span v-else>0</span>
|
||||||
|
|
@ -63,57 +42,27 @@
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<div class="btnBox">
|
<div class="btnBox">
|
||||||
<!--上传--->
|
<!--上传--->
|
||||||
<form
|
<form id="inputForm" :ref="`uploadForm_${scope.row.Id}`" enctype="multipart/form-data" v-if="!forbid">
|
||||||
id="inputForm"
|
|
||||||
:ref="`uploadForm_${scope.row.Id}`"
|
|
||||||
enctype="multipart/form-data"
|
|
||||||
v-if="!forbid"
|
|
||||||
>
|
|
||||||
<div class="form-group" style="margin-right: 10px">
|
<div class="form-group" style="margin-right: 10px">
|
||||||
<div :id="`directoryInputWrapper_${scope.row.Id}`" class="btn btn-link file-input">
|
<div :id="`directoryInputWrapper_${scope.row.Id}`" class="btn btn-link file-input">
|
||||||
<el-button
|
<el-button circle icon="el-icon-upload2" :disabled="btnLoading" :loading="btnLoading"
|
||||||
circle
|
:title="$t('upload:dicom:button:upload')" />
|
||||||
icon="el-icon-upload2"
|
<input :title="$t('upload:dicom:button:upload')" type="file" :name="`file_${scope.row.VisitTaskId}`"
|
||||||
:disabled="btnLoading"
|
:ref="`pathClear_${scope.row.VisitTaskId}`" :disabled="btnLoading" webkitdirectory multiple @change="
|
||||||
:loading="btnLoading"
|
|
||||||
:title="$t('upload:dicom:button:upload')"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
:title="$t('upload:dicom:button:upload')"
|
|
||||||
type="file"
|
|
||||||
:name="`file_${scope.row.VisitTaskId}`"
|
|
||||||
:ref="`pathClear_${scope.row.VisitTaskId}`"
|
|
||||||
:disabled="btnLoading"
|
|
||||||
webkitdirectory
|
|
||||||
multiple
|
|
||||||
@change="
|
|
||||||
($event) => beginScanFiles($event, scope.row.VisitTaskId)
|
($event) => beginScanFiles($event, scope.row.VisitTaskId)
|
||||||
"
|
" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<!--预览--->
|
<!--预览--->
|
||||||
<el-button
|
<el-button circle icon="el-icon-view" :disabled="!scope.row.UploadStudyList ||
|
||||||
circle
|
|
||||||
icon="el-icon-view"
|
|
||||||
:disabled="!scope.row.UploadStudyList ||
|
|
||||||
scope.row.UploadStudyList.length <= 0
|
scope.row.UploadStudyList.length <= 0
|
||||||
"
|
" @click.stop="handleViewReadingImages(scope.row)" :title="$t('upload:dicom:button:preview')" />
|
||||||
@click.stop="handleViewReadingImages(scope.row)"
|
|
||||||
:title="$t('upload:dicom:button:preview')"
|
|
||||||
/>
|
|
||||||
<!--删除--->
|
<!--删除--->
|
||||||
<el-button
|
<el-button circle :disabled="!scope.row.UploadStudyList ||
|
||||||
circle
|
|
||||||
:disabled="!scope.row.UploadStudyList ||
|
|
||||||
scope.row.UploadStudyList.length <= 0 ||
|
scope.row.UploadStudyList.length <= 0 ||
|
||||||
scope.row.ReadingTaskState === 2
|
scope.row.ReadingTaskState === 2
|
||||||
"
|
" icon="el-icon-delete" :title="$t('upload:dicom:button:delete')" @click.stop="remove(scope.row)" />
|
||||||
icon="el-icon-delete"
|
|
||||||
:title="$t('upload:dicom:button:delete')"
|
|
||||||
@click.stop="remove(scope.row)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -125,36 +74,18 @@
|
||||||
<form id="inputForm" ref="uploadForm" enctype="multipart/form-data">
|
<form id="inputForm" ref="uploadForm" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div id="directoryInputWrapper" class="btn btn-link file-input">
|
<div id="directoryInputWrapper" class="btn btn-link file-input">
|
||||||
<el-button
|
<el-button type="primary" :disabled="btnLoading" :loading="btnLoading" size="mini">{{
|
||||||
type="primary"
|
$t('upload:dicom:button:batchUpload') }}</el-button>
|
||||||
:disabled="btnLoading"
|
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title
|
||||||
:loading="btnLoading"
|
@change="beginScanFiles($event)" />
|
||||||
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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--上传列表-->
|
<!--上传列表-->
|
||||||
<el-table
|
<el-table ref="dicomFilesTable" v-adaptive="{ bottomOffset: 80 }" height="100" :data="uploadQueues"
|
||||||
ref="dicomFilesTable"
|
class="dicomFiles-table" @selection-change="handleSelectionChange">
|
||||||
v-adaptive="{ bottomOffset: 80 }"
|
|
||||||
height="100"
|
|
||||||
:data="uploadQueues"
|
|
||||||
class="dicomFiles-table"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
>
|
|
||||||
<el-table-column type="index" width="40" />
|
<el-table-column type="index" width="40" />
|
||||||
<el-table-column min-width="200" show-overflow-tooltip>
|
<el-table-column min-width="200" show-overflow-tooltip>
|
||||||
<template slot="header">
|
<template slot="header">
|
||||||
|
|
@ -180,9 +111,8 @@
|
||||||
<span v-else style="color: #f44336">N/A</span>
|
<span v-else style="color: #f44336">N/A</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-block; margin-right: 2px">
|
<div style="display: inline-block; margin-right: 2px">
|
||||||
<span
|
<span v-if="scope.row.dicomInfo.modality.length > 0">{{ scope.row.dicomInfo.modality.join('、')
|
||||||
v-if="scope.row.dicomInfo.modality.length > 0"
|
}},</span>
|
||||||
>{{ scope.row.dicomInfo.modality.join('、') }},</span>
|
|
||||||
<span v-else style="color: #f44336">N/A,</span>
|
<span v-else style="color: #f44336">N/A,</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-block; margin-right: 2px">
|
<div style="display: inline-block; margin-right: 2px">
|
||||||
|
|
@ -228,162 +158,123 @@
|
||||||
<span v-if="scope.row.dicomInfo.patientId">
|
<span v-if="scope.row.dicomInfo.patientId">
|
||||||
<span style="font-weight: 500">PID:</span>
|
<span style="font-weight: 500">PID:</span>
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientId }}
|
scope.row.dicomInfo.patientId }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else style="color: #f44336">N/A</span>
|
<span v-else style="color: #f44336">N/A</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span :class="[scope.row.dicomInfo.patientName ? '' : 'colorOfRed']">
|
<span :class="[scope.row.dicomInfo.patientName ? '' : 'colorOfRed']">
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientName
|
scope.row.dicomInfo.patientName
|
||||||
? scope.row.dicomInfo.patientName
|
? scope.row.dicomInfo.patientName
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span :class="[scope.row.dicomInfo.patientSex ? '' : 'colorOfRed']">
|
<span :class="[scope.row.dicomInfo.patientSex ? '' : 'colorOfRed']">
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientSex
|
scope.row.dicomInfo.patientSex
|
||||||
? scope.row.dicomInfo.patientSex
|
? scope.row.dicomInfo.patientSex
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}},
|
}},
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span :class="[scope.row.dicomInfo.patientAge ? '' : 'colorOfRed']">
|
<span :class="[scope.row.dicomInfo.patientAge ? '' : 'colorOfRed']">
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientAge
|
scope.row.dicomInfo.patientAge
|
||||||
? scope.row.dicomInfo.patientAge
|
? scope.row.dicomInfo.patientAge
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}},
|
}},
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span :class="[
|
||||||
:class="[
|
|
||||||
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
|
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientBirthDate
|
scope.row.dicomInfo.patientBirthDate
|
||||||
? scope.row.dicomInfo.patientBirthDate
|
? scope.row.dicomInfo.patientBirthDate
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column :label="$t('trials:uploadDicomList:table:failedFileCount')" min-width="150"
|
||||||
:label="$t('trials:uploadDicomList:table:failedFileCount')"
|
show-overflow-tooltip>
|
||||||
min-width="150"
|
|
||||||
show-overflow-tooltip
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-progress
|
<el-progress color="#409eff" :percentage="(
|
||||||
color="#409eff"
|
|
||||||
:percentage="(
|
|
||||||
(scope.row.dicomInfo.uploadFileSize * 100) /
|
(scope.row.dicomInfo.uploadFileSize * 100) /
|
||||||
(scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1)
|
(scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1)
|
||||||
).toFixed(2) * 1
|
).toFixed(2) * 1
|
||||||
"
|
" />
|
||||||
/>
|
|
||||||
<span>
|
<span>
|
||||||
{{ $t('trials:uploadDicomList:table:uploadNow')
|
{{ $t('trials:uploadDicomList:table:uploadNow')
|
||||||
}}{{ scope.row.dicomInfo.failedFileCount }}/{{
|
}}{{ scope.row.dicomInfo.failedFileCount }}/{{
|
||||||
scope.row.dicomInfo.fileCount
|
scope.row.dicomInfo.fileCount
|
||||||
}}
|
}}
|
||||||
({{
|
({{
|
||||||
(scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(3)
|
(scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(3)
|
||||||
}}MB/{{
|
}}MB/{{
|
||||||
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3)
|
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3)
|
||||||
}}MB)
|
}}MB)
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column :label="$t('trials:uploadDicomList:table:status')" min-width="140" show-overflow-tooltip>
|
||||||
:label="$t('trials:uploadDicomList:table:status')"
|
|
||||||
min-width="140"
|
|
||||||
show-overflow-tooltip
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span
|
<span v-if="
|
||||||
v-if="
|
|
||||||
!scope.row.dicomInfo.failedFileCount &&
|
!scope.row.dicomInfo.failedFileCount &&
|
||||||
!scope.row.dicomInfo.isInit
|
!scope.row.dicomInfo.isInit
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status1') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status1') }}</span>
|
<span style="color: #409eff" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #409eff"
|
|
||||||
v-else-if="
|
|
||||||
!scope.row.dicomInfo.failedFileCount &&
|
!scope.row.dicomInfo.failedFileCount &&
|
||||||
scope.row.dicomInfo.isInit &&
|
scope.row.dicomInfo.isInit &&
|
||||||
btnLoading
|
btnLoading
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
<span style="color: #409eff" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #409eff"
|
|
||||||
v-else-if="
|
|
||||||
scope.row.dicomInfo.failedFileCount <
|
scope.row.dicomInfo.failedFileCount <
|
||||||
scope.row.dicomInfo.fileCount && !scope.row.uploadState.record
|
scope.row.dicomInfo.fileCount && !scope.row.uploadState.record
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
<span style="color: #2cc368" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #2cc368"
|
|
||||||
v-else-if="
|
|
||||||
scope.row.dicomInfo.failedFileCount ===
|
scope.row.dicomInfo.failedFileCount ===
|
||||||
scope.row.dicomInfo.fileCount
|
scope.row.dicomInfo.fileCount
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status3') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status3') }}</span>
|
<span style="color: #f66" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #f66"
|
|
||||||
v-else-if="
|
|
||||||
scope.row.uploadState.record &&
|
scope.row.uploadState.record &&
|
||||||
scope.row.uploadState.record.fileCount === 0
|
scope.row.uploadState.record.fileCount === 0
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status5') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status5') }}</span>
|
|
||||||
<span style="color: #f66" v-else>
|
<span style="color: #f66" v-else>
|
||||||
{{
|
{{
|
||||||
$t('trials:uploadDicomList:table:Failed')
|
$t('trials:uploadDicomList:table:Failed')
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column :label="$t('trials:uploadDicomList:table:record')" min-width="140" show-overflow-tooltip>
|
||||||
:label="$t('trials:uploadDicomList:table:record')"
|
|
||||||
min-width="140"
|
|
||||||
show-overflow-tooltip
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tooltip placement="top" v-if="scope.row.uploadState.record">
|
<el-tooltip placement="top" v-if="scope.row.uploadState.record">
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
<div style="max-height: 500px; overflow-y: auto">
|
<div style="max-height: 500px; overflow-y: auto">
|
||||||
{{ $t('trials:uploadDicomList:table:Existed') }}:
|
{{ $t('trials:uploadDicomList:table:Existed') }}:
|
||||||
<div v-if="scope.row.uploadState.record.Existed.length">
|
<div v-if="scope.row.uploadState.record.Existed.length">
|
||||||
<div
|
<div v-for="item of scope.row.uploadState.record.Existed" :key="item"
|
||||||
v-for="item of scope.row.uploadState.record.Existed"
|
style="font-size: 12px; color: #baa72a">{{ item }}</div>
|
||||||
:key="item"
|
|
||||||
style="font-size: 12px; color: #baa72a"
|
|
||||||
>{{ item }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> </div>
|
<div v-else> </div>
|
||||||
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
|
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
|
||||||
<div v-if="scope.row.uploadState.record.Uploaded.length">
|
<div v-if="scope.row.uploadState.record.Uploaded.length">
|
||||||
<div
|
<div v-for="item of scope.row.uploadState.record.Uploaded" :key="item"
|
||||||
v-for="item of scope.row.uploadState.record.Uploaded"
|
style="font-size: 12px; color: #24b837">{{ item }}</div>
|
||||||
:key="item"
|
|
||||||
style="font-size: 12px; color: #24b837"
|
|
||||||
>{{ item }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> </div>
|
<div v-else> </div>
|
||||||
<br />
|
<br />
|
||||||
{{ $t('trials:uploadDicomList:table:Failed') }}:
|
{{ $t('trials:uploadDicomList:table:Failed') }}:
|
||||||
<div v-if="scope.row.uploadState.record.Failed.length">
|
<div v-if="scope.row.uploadState.record.Failed.length">
|
||||||
<div
|
<div v-for="item of scope.row.uploadState.record.Failed" :key="item"
|
||||||
v-for="item of scope.row.uploadState.record.Failed"
|
style="font-size: 12px; color: #f66">{{ item }}</div>
|
||||||
:key="item"
|
|
||||||
style="font-size: 12px; color: #f66"
|
|
||||||
>{{ item }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> </div>
|
<div v-else> </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -391,19 +282,19 @@
|
||||||
<el-button size="mini" style="cursor: pointer">
|
<el-button size="mini" style="cursor: pointer">
|
||||||
<span style="font-size: 12px; color: #baa72a">
|
<span style="font-size: 12px; color: #baa72a">
|
||||||
{{
|
{{
|
||||||
scope.row.uploadState.record.Existed.length
|
scope.row.uploadState.record.Existed.length
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
/
|
/
|
||||||
<span style="font-size: 12px; color: #24b837">
|
<span style="font-size: 12px; color: #24b837">
|
||||||
{{
|
{{
|
||||||
scope.row.uploadState.record.Uploaded.length
|
scope.row.uploadState.record.Uploaded.length
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
/
|
/
|
||||||
<span style="font-size: 12px; color: #f66">
|
<span style="font-size: 12px; color: #f66">
|
||||||
{{
|
{{
|
||||||
scope.row.uploadState.record.Failed.length
|
scope.row.uploadState.record.Failed.length
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -411,18 +302,9 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<study-view
|
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :IsDicom="true" :bodyPart="bodyPart"
|
||||||
v-if="model_cfg.visible"
|
:subjectVisitId="openSubjectVisitId" :modelList="modelList" :isUpload="openIsUpload"
|
||||||
:model_cfg="model_cfg"
|
:visitTaskId="openVisitTaskId" :TrialModality="TrialModality" @getList="getList" />
|
||||||
:IsDicom="true"
|
|
||||||
:bodyPart="bodyPart"
|
|
||||||
:subjectVisitId="openSubjectVisitId"
|
|
||||||
:modelList="modelList"
|
|
||||||
:isUpload="openIsUpload"
|
|
||||||
:visitTaskId="openVisitTaskId"
|
|
||||||
:TrialModality="TrialModality"
|
|
||||||
@getList="getList"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -666,9 +548,8 @@ export default {
|
||||||
this.openIsUpload = isUpload
|
this.openIsUpload = isUpload
|
||||||
this.openSubjectVisitId = item.SubjectVisitId || item.SourceSubjectVisitId
|
this.openSubjectVisitId = item.SubjectVisitId || item.SourceSubjectVisitId
|
||||||
this.openVisitTaskId = item.VisitTaskId
|
this.openVisitTaskId = item.VisitTaskId
|
||||||
this.model_cfg.title = `${item.SubjectCode || ''} > ${
|
this.model_cfg.title = `${item.SubjectCode || ''} > ${this.IsImageSegment ? item.VisitName : item.TaskBlindName
|
||||||
this.IsImageSegment ? item.VisitName : item.TaskBlindName
|
}`
|
||||||
}`
|
|
||||||
this.modelList = item[list]
|
this.modelList = item[list]
|
||||||
this.model_cfg.visible = true
|
this.model_cfg.visible = true
|
||||||
},
|
},
|
||||||
|
|
@ -801,7 +682,7 @@ export default {
|
||||||
var validFilesCount = 0
|
var validFilesCount = 0
|
||||||
scope.uploadQueues = []
|
scope.uploadQueues = []
|
||||||
for (var i = 0; i < checkFiles.length; ++i) {
|
for (var i = 0; i < checkFiles.length; ++i) {
|
||||||
;(function (index) {
|
; (function (index) {
|
||||||
p = p.then(function () {
|
p = p.then(function () {
|
||||||
if (
|
if (
|
||||||
checkFiles[index].name.toUpperCase().indexOf('DICOMDIR') === -1
|
checkFiles[index].name.toUpperCase().indexOf('DICOMDIR') === -1
|
||||||
|
|
@ -1249,6 +1130,7 @@ export default {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
try {
|
try {
|
||||||
let subjectVisitId = null
|
let subjectVisitId = null
|
||||||
|
let dicomInfo = {}
|
||||||
if (scope.VisitTaskId) {
|
if (scope.VisitTaskId) {
|
||||||
scope.StudyInstanceUidList.forEach((item) => {
|
scope.StudyInstanceUidList.forEach((item) => {
|
||||||
if (item.VisitTaskId === scope.VisitTaskId) {
|
if (item.VisitTaskId === scope.VisitTaskId) {
|
||||||
|
|
@ -1278,7 +1160,7 @@ export default {
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
scope.uploadQueues[index].dicomInfo.failedFileCount = 0
|
scope.uploadQueues[index].dicomInfo.failedFileCount = 0
|
||||||
scope.$set(scope.uploadQueues[index].dicomInfo, 'isInit', true)
|
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 seriesNum = scope.uploadQueues[index].seriesList.length
|
||||||
let fileNum = scope.uploadQueues[index].fileList.length
|
let fileNum = scope.uploadQueues[index].fileList.length
|
||||||
let seriesList = scope.uploadQueues[index].seriesList
|
let seriesList = scope.uploadQueues[index].seriesList
|
||||||
|
|
@ -1324,8 +1206,8 @@ export default {
|
||||||
institutionName: dicomInfo.institutionName,
|
institutionName: dicomInfo.institutionName,
|
||||||
patientId: dicomInfo.patientId,
|
patientId: dicomInfo.patientId,
|
||||||
patientName: '',
|
patientName: '',
|
||||||
patientAge: '',
|
patientAge: dicomInfo.patientAge,
|
||||||
patientSex: dicomInfo.patientSex,
|
patientSex: config?.DicomStoreInfo.SubjectSex || dicomInfo.patientSex,
|
||||||
accessionNumber: dicomInfo.accNumber,
|
accessionNumber: dicomInfo.accNumber,
|
||||||
patientBirthDate: '',
|
patientBirthDate: '',
|
||||||
acquisitionTime: dicomInfo.acquisitionTime,
|
acquisitionTime: dicomInfo.acquisitionTime,
|
||||||
|
|
@ -1409,27 +1291,23 @@ export default {
|
||||||
dicomInfo.failedFileCount++
|
dicomInfo.failedFileCount++
|
||||||
Record.FileCount++
|
Record.FileCount++
|
||||||
} else {
|
} else {
|
||||||
let path = `/${params.trialId}/Image/${
|
let path = `/${params.trialId}/Image/${params.subjectId
|
||||||
params.subjectId
|
}/${params.subjectVisitId}/${dicomInfo.visitTaskId
|
||||||
}/${params.subjectVisitId}/${
|
}/${scope.getGuid(
|
||||||
dicomInfo.visitTaskId
|
dicomInfo.studyUid +
|
||||||
}/${scope.getGuid(
|
|
||||||
dicomInfo.studyUid +
|
|
||||||
v.seriesUid +
|
v.seriesUid +
|
||||||
o.instanceUid +
|
o.instanceUid +
|
||||||
params.trialId
|
params.trialId
|
||||||
)}`
|
)}`
|
||||||
if (scope.IsImageSegment) {
|
if (scope.IsImageSegment) {
|
||||||
path = `/${params.trialId}/Image/${
|
path = `/${params.trialId}/Image/${params.subjectId
|
||||||
params.subjectId
|
}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId
|
||||||
}/${params.subjectVisitId}/AnnotationImage/${
|
}/${scope.getGuid(
|
||||||
dicomInfo.visitTaskId
|
dicomInfo.studyUid +
|
||||||
}/${scope.getGuid(
|
|
||||||
dicomInfo.studyUid +
|
|
||||||
v.seriesUid +
|
v.seriesUid +
|
||||||
o.instanceUid +
|
o.instanceUid +
|
||||||
params.trialId
|
params.trialId
|
||||||
)}`
|
)}`
|
||||||
}
|
}
|
||||||
if (scope.isClose) return
|
if (scope.isClose) return
|
||||||
let res = await dcmUpload(
|
let res = await dcmUpload(
|
||||||
|
|
@ -1759,11 +1637,9 @@ export default {
|
||||||
var token = getToken()
|
var token = getToken()
|
||||||
let trialId = this.$route.query.trialId
|
let trialId = this.$route.query.trialId
|
||||||
const routeData = this.$router.resolve({
|
const routeData = this.$router.resolve({
|
||||||
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${
|
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${this.IsImageSegment ? 'undefined' : row.VisitTaskId
|
||||||
this.IsImageSegment ? 'undefined' : row.VisitTaskId
|
}&subjectVisitId=${row.SourceSubjectVisitId
|
||||||
}&subjectVisitId=${
|
}&isReading=1&TokenKey=${token}`,
|
||||||
row.SourceSubjectVisitId
|
|
||||||
}&isReading=1&TokenKey=${token}`,
|
|
||||||
})
|
})
|
||||||
this.open = window.open(routeData.href, '_blank')
|
this.open = window.open(routeData.href, '_blank')
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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 |
300
src/main.js
300
src/main.js
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
import Vue from 'vue'
|
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 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||||
// import { createVersionPolling } from "@/utils/version-polling.esm.js";
|
// import { createVersionPolling } from "@/utils/version-polling.esm.js";
|
||||||
import ElementUI, { MessageBox } from 'element-ui'
|
import ElementUI, { MessageBox } from 'element-ui'
|
||||||
|
|
@ -451,6 +452,7 @@ async function VueInit() {
|
||||||
isOpen = false
|
isOpen = false
|
||||||
isLock = null
|
isLock = null
|
||||||
zzSessionStorage.removeItem('isLock')
|
zzSessionStorage.removeItem('isLock')
|
||||||
|
// DicomEvent.$emit('isLock', false)
|
||||||
router.push("/login")
|
router.push("/login")
|
||||||
}).then(() => {
|
}).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!', {
|
// _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!', {
|
||||||
|
|
@ -462,160 +464,166 @@ async function VueInit() {
|
||||||
})
|
})
|
||||||
|
|
||||||
} : () => { }, process.env.VUE_APP_LOGOUT_FOR_TIME,
|
} : () => { }, process.env.VUE_APP_LOGOUT_FOR_TIME,
|
||||||
eval(process.env.VUE_APP_LOCK_FOR_PERMISSION) ? () => {
|
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)) {
|
var lang = zzSessionStorage.getItem('lang') ? zzSessionStorage.getItem('lang') : 'zh'
|
||||||
count = 0;
|
if (_vm.$store.state.trials.unlock || WHITELIST.includes(_vm.$route.path)) {
|
||||||
localStorage.setItem('count', '0')
|
count = 0;
|
||||||
if (_vm.$route.path === '/login') {
|
localStorage.setItem('count', '0')
|
||||||
zzSessionStorage.removeItem('lastWorkbench')
|
if (_vm.$route.path === '/login') {
|
||||||
zzSessionStorage.removeItem('isLock')
|
zzSessionStorage.removeItem('lastWorkbench')
|
||||||
isLock = null
|
zzSessionStorage.removeItem('isLock')
|
||||||
}
|
// DicomEvent.$emit('isLock', false)
|
||||||
return
|
isLock = null
|
||||||
}
|
|
||||||
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'))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
return
|
||||||
message: h('div', {}, [
|
}
|
||||||
h('el-form', {
|
if (isOpen) {
|
||||||
props: { labelWidth: "80px" }
|
return
|
||||||
}, [
|
}
|
||||||
h('el-form-item', {
|
isOpen = true
|
||||||
props: { label: _vm.$t("env:lock:msgBox:form:username") },
|
zzSessionStorage.setItem('isLock', 'true')
|
||||||
}, [
|
// DicomEvent.$emit('isLock', true)
|
||||||
h('input', {
|
_vm.$msgbox({
|
||||||
props: {
|
title: _vm.$t("env:lock:msgBox:title"),
|
||||||
value: _vm.unlock.my_username
|
confirmButtonText: _vm.$t("env:lock:msgBox:confirmButtonText"),
|
||||||
},
|
showClose: false,
|
||||||
attrs: {
|
beforeClose: (action, instance, done) => {
|
||||||
id: 'my_username',
|
if (action === 'confirm') {
|
||||||
class: 'el-input__inner',
|
if (!_vm.unlock.my_username) {
|
||||||
autocomplete: 'new-password'
|
_vm.$message.warning(_vm.$t("env:lock:msgBox:iupUser"))
|
||||||
},
|
return
|
||||||
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;"
|
|
||||||
}
|
}
|
||||||
}, [
|
if (!_vm.unlock.my_password) {
|
||||||
h('input', {
|
_vm.$message.warning(_vm.$t("env:lock:msgBox:inpPassword"))
|
||||||
props: {
|
return
|
||||||
value: _vm.unlock.my_password
|
}
|
||||||
},
|
var my_username = zzSessionStorage.getItem('my_username')
|
||||||
ref: "unlock_my_password_input",
|
var my_password = zzSessionStorage.getItem('my_password')
|
||||||
attrs: {
|
let my_userid = zzSessionStorage.getItem('userId')
|
||||||
id: 'my_password',
|
let my_EMail = zzSessionStorage.getItem('my_EMail') || ''
|
||||||
class: 'el-input__inner',
|
if (md5(_vm.unlock.my_password) === my_password && (my_username === _vm.unlock.my_username || my_EMail.toUpperCase() === _vm.unlock.my_username.toUpperCase())) {
|
||||||
type: _vm.unlock.view ? 'text' : 'password',
|
resetReadingRestTime().then(() => {
|
||||||
autocomplete: 'new-password',
|
})
|
||||||
style: "padding-right:25px"
|
const closeLock = (_vm) => {
|
||||||
},
|
_vm.$message.success(_vm.$t("env:lock:msgBox:lockSuccess"))
|
||||||
on: {
|
_vm.unlock = {
|
||||||
change: (event) => {
|
my_username: null,
|
||||||
_vm.unlock.my_password = event.target.value
|
my_password: null,
|
||||||
},
|
view: false
|
||||||
input: (event) => {
|
|
||||||
_vm.unlock.my_password = event.target.value
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}),
|
// if (eval(process.env.VUE_APP_LOCK_FOR_PERMISSION_MFA)) {
|
||||||
h('i', {
|
// sendMFAEmail({ UserId: my_userid, MfaType: 1 }).then((res) => {
|
||||||
attrs: {
|
// done();
|
||||||
id: 'my_password_view',
|
// Vue.prototype.$MFA({
|
||||||
class: "el-icon-view",
|
// status: "lock",
|
||||||
style: "cursor: pointer;position: absolute;top:35%;right:10px"
|
// UserId: my_userid,
|
||||||
},
|
// EMail: res.Result,
|
||||||
on: {
|
// username: my_username,
|
||||||
click: (event) => {
|
// callBack: () => {
|
||||||
_vm.unlock.view = !_vm.unlock.view
|
// closeLock(_vm)
|
||||||
if (_vm.unlock.view) {
|
// },
|
||||||
_vm.$refs['unlock_my_password_input'].type = "text"
|
// })
|
||||||
} else {
|
// })
|
||||||
_vm.$refs['unlock_my_password_input'].type = "password"
|
// } 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()
|
VueInit()
|
||||||
// createVersionPolling({
|
// createVersionPolling({
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ function getQuestions(questions) {
|
||||||
answerObj.angle = angle
|
answerObj.angle = angle
|
||||||
answerObj.saveTypeEnum = isNaN(parseFloat(angle)) ? 1 : 2
|
answerObj.saveTypeEnum = isNaN(parseFloat(angle)) ? 1 : 2
|
||||||
}
|
}
|
||||||
} else if (criterionType === 21) {
|
} else if (criterionType === 21 || criterionType === 22) {
|
||||||
// MRI-PDFF
|
// MRI-PDFF
|
||||||
let isMeasurable = getQuestionAnswer(item.TableQuestions.Questions, 1105, answerObj)
|
let isMeasurable = getQuestionAnswer(item.TableQuestions.Questions, 1105, answerObj)
|
||||||
answerObj.isMeasurable = isMeasurable
|
answerObj.isMeasurable = isMeasurable
|
||||||
|
|
|
||||||
|
|
@ -383,7 +383,7 @@ function mimeTypeToExt(mimeType) {
|
||||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
||||||
'application/vnd.ms-excel': 'xls',
|
'application/vnd.ms-excel': 'xls',
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
||||||
'application/vnd.ms-powerpoint': '.ppt',
|
'application/vnd.ms-powerpoint': 'ppt',
|
||||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
|
||||||
'text/plain': 'txt',
|
'text/plain': 'txt',
|
||||||
// 音频/视频
|
// 音频/视频
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ async function executeTask() {
|
||||||
task.callback({ success: true, res: result })
|
task.callback({ success: true, res: result })
|
||||||
|
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
task.callback({ success: true, err: error })
|
task.callback({ success: false, err: error })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
// let starLoadTime = performance.now()
|
// let starLoadTime = performance.now()
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
// import 'modules/echarts/map/js/world.js'
|
import worldMap from 'echarts-map/json/world.json';
|
||||||
import { fontSize } from 'utils/fontsize'
|
import { fontSize } from 'utils/fontsize'
|
||||||
|
echarts.registerMap('world', worldMap);
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
area: { type: String, default: '' },
|
area: { type: String, default: '' },
|
||||||
|
|
@ -76,68 +77,68 @@ export default {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
var series = []
|
var series = [];
|
||||||
;[['Shanghai', BJData]].forEach(function (item, i) {
|
[['Shanghai', BJData]].forEach(function (item, i) {
|
||||||
series.push(
|
series.push(
|
||||||
{
|
{
|
||||||
type: 'lines',
|
type: 'lines',
|
||||||
zlevel: 1,
|
zlevel: 1,
|
||||||
effect: {
|
effect: {
|
||||||
show: true,
|
show: true,
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
period: 6,
|
period: 6,
|
||||||
trailLength: 0.7,
|
trailLength: 0.7,
|
||||||
symbolSize: fontSize(0.05)
|
symbolSize: fontSize(0.05)
|
||||||
},
|
},
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
normal: {
|
normal: {
|
||||||
width: fontSize(0.03),
|
width: fontSize(0.03),
|
||||||
color: '#9ae5fc',
|
color: '#9ae5fc',
|
||||||
opacity: 0.02,
|
opacity: 0.02,
|
||||||
curveness: -0.2
|
curveness: -0.2
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
data: convertData(item[1])
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
data: convertData(item[1])
|
||||||
type: 'effectScatter',
|
},
|
||||||
coordinateSystem: 'geo',
|
|
||||||
zlevel: 3,
|
|
||||||
rippleEffect: {
|
|
||||||
// 涟漪特效
|
|
||||||
period: 5, // 动画时间,值越小速度越快
|
|
||||||
brushType: 'fill', // 波纹绘制方式 stroke, fill
|
|
||||||
scale: 5 // 波纹圆环最大限制,值越大波纹越大
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
normal: {
|
|
||||||
show: true,
|
|
||||||
color: '#fce630',
|
|
||||||
position: 'right', // 显示位置
|
|
||||||
offset: [10, 0], // 偏移设置
|
|
||||||
fontSize: fontSize(0.16),
|
|
||||||
formatter: '{b}' // 圆环显示文字
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
show: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
symbol: 'circle',
|
|
||||||
symbolSize: function (val) {
|
|
||||||
return fontSize(0.08) // 圆环大小
|
|
||||||
},
|
|
||||||
|
|
||||||
data: item[1].map(function (dataItem) {
|
{
|
||||||
return {
|
type: 'effectScatter',
|
||||||
name: dataItem[0].name,
|
coordinateSystem: 'geo',
|
||||||
value: geoCoordMap[dataItem[0].name]
|
zlevel: 3,
|
||||||
}
|
rippleEffect: {
|
||||||
})
|
// 涟漪特效
|
||||||
}
|
period: 5, // 动画时间,值越小速度越快
|
||||||
)
|
brushType: 'fill', // 波纹绘制方式 stroke, fill
|
||||||
})
|
scale: 5 // 波纹圆环最大限制,值越大波纹越大
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
color: '#fce630',
|
||||||
|
position: 'right', // 显示位置
|
||||||
|
offset: [10, 0], // 偏移设置
|
||||||
|
fontSize: fontSize(0.16),
|
||||||
|
formatter: '{b}' // 圆环显示文字
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: function (val) {
|
||||||
|
return fontSize(0.08) // 圆环大小
|
||||||
|
},
|
||||||
|
|
||||||
|
data: item[1].map(function (dataItem) {
|
||||||
|
return {
|
||||||
|
name: dataItem[0].name,
|
||||||
|
value: geoCoordMap[dataItem[0].name]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
var option = {
|
var option = {
|
||||||
// backgroundColor: '#fff',
|
// backgroundColor: '#fff',
|
||||||
title: {
|
title: {
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
v-for="(instance, idx) in item.instanceInfoList"
|
v-for="(instance, idx) in item.instanceInfoList"
|
||||||
:key="instance.InstanceUid"
|
: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'}"
|
:style="{'margin-bottom':idx<item.instanceInfoList.length-1? '5px':'0px'}"
|
||||||
@click="showMultiFrames(item, index, instance)"
|
@click="showMultiFrames(item, index, instance)"
|
||||||
>
|
>
|
||||||
|
|
@ -136,7 +137,8 @@ export default {
|
||||||
studyTitle: '',
|
studyTitle: '',
|
||||||
seriesCount: 0,
|
seriesCount: 0,
|
||||||
seriesList: [],
|
seriesList: [],
|
||||||
currentSeriesIndex: -1
|
currentSeriesIndex: -1,
|
||||||
|
activeInstanceUid: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -231,6 +233,7 @@ export default {
|
||||||
},
|
},
|
||||||
showMultiFrames(series, seriesIndex, instanceInfo) {
|
showMultiFrames(series, seriesIndex, instanceInfo) {
|
||||||
this.currentSeriesIndex = seriesIndex
|
this.currentSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceUid = instanceInfo.InstanceUid
|
||||||
const imageIds = []
|
const imageIds = []
|
||||||
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
||||||
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
||||||
|
|
@ -252,6 +255,7 @@ export default {
|
||||||
showSeriesImage(seriesIndex) {
|
showSeriesImage(seriesIndex) {
|
||||||
// if (seriesIndex === this.currentSeriesIndex) return;
|
// if (seriesIndex === this.currentSeriesIndex) return;
|
||||||
this.currentSeriesIndex = seriesIndex
|
this.currentSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceUid = null
|
||||||
this.$refs.dicomViewer.loadImageStack(this.seriesList[seriesIndex])
|
this.$refs.dicomViewer.loadImageStack(this.seriesList[seriesIndex])
|
||||||
},
|
},
|
||||||
closeDialog() {
|
closeDialog() {
|
||||||
|
|
@ -429,4 +433,8 @@ export default {
|
||||||
border-color: #213a54 !important;
|
border-color: #213a54 !important;
|
||||||
background-color: #213a54;
|
background-color: #213a54;
|
||||||
}
|
}
|
||||||
|
.frame_content_active {
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@
|
||||||
<div class="frame_list">
|
<div class="frame_list">
|
||||||
<div v-for="(instance, idx) in item.instanceInfoList" :key="instance.Id"
|
<div v-for="(instance, idx) in item.instanceInfoList" :key="instance.Id"
|
||||||
class="frame_content"
|
class="frame_content"
|
||||||
|
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||||
:style="{ 'margin-bottom': idx < item.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
:style="{ 'margin-bottom': idx < item.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||||
@click="showMultiFrames(item, index, instance)">
|
@click="showMultiFrames(item, index, instance)">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -72,17 +73,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;"
|
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;"
|
||||||
@click="popperClick(seriesList, item)" />
|
@click.stop="popperClick(seriesList, item)" />
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="item.instanceCount" style="padding: 1px;">
|
<div v-if="item.instanceCount" style="padding: 1px;">
|
||||||
{{ item.modality }}: {{ item.instanceCount }} image
|
{{ item.modality }}: {{ item.instanceCount }} image
|
||||||
</div>
|
</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) }}
|
T: {{ parseFloat(item.sliceThickness).toFixed(2) }}
|
||||||
</div>
|
</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;">
|
style="width: 120px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;padding: 1x;">
|
||||||
{{ item.description }}
|
{{ item.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -203,7 +204,8 @@ export default {
|
||||||
isReading: null,
|
isReading: null,
|
||||||
activeSeriesId: null,
|
activeSeriesId: null,
|
||||||
isPacs: false,
|
isPacs: false,
|
||||||
isComparison: false
|
isComparison: false,
|
||||||
|
activeInstanceId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
|
|
@ -308,7 +310,7 @@ export default {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async loadStudy(isJump = true) {
|
async loadStudy(seriesId = null) {
|
||||||
let params = {}
|
let params = {}
|
||||||
if (this.isPacs) {
|
if (this.isPacs) {
|
||||||
params.IsPacs = true
|
params.IsPacs = true
|
||||||
|
|
@ -328,7 +330,7 @@ export default {
|
||||||
isReading = `?IsPacs=true`
|
isReading = `?IsPacs=true`
|
||||||
}
|
}
|
||||||
const url = `/series/list/${this.studyId}${isReading}`
|
const url = `/series/list/${this.studyId}${isReading}`
|
||||||
this.getSeriesList(url, isJump)
|
this.getSeriesList(url, seriesId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loadPatientStudy() {
|
async loadPatientStudy() {
|
||||||
|
|
@ -393,7 +395,7 @@ export default {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getSeriesList(url, isJump = true) {
|
async getSeriesList(url, seriesId = null) {
|
||||||
try {
|
try {
|
||||||
const data = await getSeriesList(url)
|
const data = await getSeriesList(url)
|
||||||
if (data.IsSuccess) {
|
if (data.IsSuccess) {
|
||||||
|
|
@ -432,12 +434,12 @@ export default {
|
||||||
isDeleted: item.IsDeleted,
|
isDeleted: item.IsDeleted,
|
||||||
previewImageUrl: item.ImageResizePath ? this.OSSclientConfig.basePath + item.ImageResizePath : `/api/series/preview/${item.Id}`,
|
previewImageUrl: item.ImageResizePath ? this.OSSclientConfig.basePath + item.ImageResizePath : `/api/series/preview/${item.Id}`,
|
||||||
instanceCount: item.InstanceCount,
|
instanceCount: item.InstanceCount,
|
||||||
prefetchInstanceCount: !isJump ? item.InstanceInfoList.length * 100 : 0,
|
prefetchInstanceCount: seriesId ? item.InstanceInfoList.length * 100 : 0,
|
||||||
hasLabel: item.HasLabel,
|
hasLabel: item.HasLabel,
|
||||||
keySeries: item.KeySeries,
|
keySeries: item.KeySeries,
|
||||||
tpCode: this.tpCode,
|
tpCode: this.tpCode,
|
||||||
loadStatus: false,
|
loadStatus: false,
|
||||||
imageloadedArr: [],
|
imageloadedArr: seriesId ? imageIds : [],
|
||||||
isExistMutiFrames: item.IsExistMutiFrames,
|
isExistMutiFrames: item.IsExistMutiFrames,
|
||||||
isShowPopper: false,
|
isShowPopper: false,
|
||||||
subjectCode: item.SubjectCode,
|
subjectCode: item.SubjectCode,
|
||||||
|
|
@ -447,10 +449,13 @@ export default {
|
||||||
this.seriesList = seriesList
|
this.seriesList = seriesList
|
||||||
if (this.seriesList.length > 0) {
|
if (this.seriesList.length > 0) {
|
||||||
this.loadAllImages()
|
this.loadAllImages()
|
||||||
if (isJump) {
|
let index = 0;
|
||||||
this.$refs.dicomViewer.loadImageStack(this.seriesList[0], this.labels[this.tpCode])
|
if (seriesId) {
|
||||||
this.firstInstanceId = this.seriesList[0].imageIds[0]
|
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]
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -531,8 +536,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showSeriesImage(e, seriesIndex, series) {
|
showSeriesImage(e, seriesIndex, series) {
|
||||||
if (!isComparison) return false
|
if (this.isComparison) return false
|
||||||
this.activeSeriesId = series.seriesId
|
this.activeSeriesId = series.seriesId
|
||||||
|
this.activeInstanceId = null
|
||||||
workSpeedclose(true)
|
workSpeedclose(true)
|
||||||
// if (seriesIndex === this.currentSeriesIndex) return
|
// if (seriesIndex === this.currentSeriesIndex) return
|
||||||
const element = e.currentTarget
|
const element = e.currentTarget
|
||||||
|
|
@ -581,6 +587,7 @@ export default {
|
||||||
},
|
},
|
||||||
showMultiFrames(series, seriesIndex, instanceInfo) {
|
showMultiFrames(series, seriesIndex, instanceInfo) {
|
||||||
this.currentSeriesIndex = seriesIndex
|
this.currentSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceId = instanceInfo.Id
|
||||||
const imageIds = []
|
const imageIds = []
|
||||||
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
||||||
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
||||||
|
|
@ -592,6 +599,7 @@ export default {
|
||||||
const seriesInfo = {
|
const seriesInfo = {
|
||||||
trialId: series.trialId,
|
trialId: series.trialId,
|
||||||
subjectVisitId: series.subjectVisitId,
|
subjectVisitId: series.subjectVisitId,
|
||||||
|
instanceInfoList: series.instanceInfoList,
|
||||||
studyId: series.studyId,
|
studyId: series.studyId,
|
||||||
imageIds: imageIds,
|
imageIds: imageIds,
|
||||||
seriesId: series.seriesId,
|
seriesId: series.seriesId,
|
||||||
|
|
@ -1189,6 +1197,10 @@ export default {
|
||||||
border-color: #213a54 !important;
|
border-color: #213a54 !important;
|
||||||
background-color: #213a54;
|
background-color: #213a54;
|
||||||
}
|
}
|
||||||
|
.frame_content_active {
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
|
|
||||||
/* .viewerRightSidePanel {
|
/* .viewerRightSidePanel {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
|
||||||
|
|
@ -19,25 +19,26 @@
|
||||||
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`"
|
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`"
|
||||||
:name="`${study.StudyId}`">
|
:name="`${study.StudyId}`">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
|
<div class="collapse-title-wrapper">
|
||||||
<div class="text-desc">
|
<div class="text-desc">
|
||||||
{{ study.StudyCode }}
|
{{ study.StudyCode }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <div v-show="study.Description" class="text-desc">
|
<!-- <div v-show="study.Description" class="text-desc">
|
||||||
{{ study.Description }}
|
{{ study.Description }}
|
||||||
</div> -->
|
</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">
|
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;">
|
style="width: 50px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;padding: 1x;">
|
||||||
{{ study.Description }}
|
{{ study.Description }}
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip> -->
|
||||||
<div v-show="study.SeriesCount" class="text-desc">
|
<div v-if="study.SeriesCount" class="text-desc collapse-title-extra">
|
||||||
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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 }}
|
{{ study.Description }}
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(series, i) in study.SeriesList" :key="i"
|
<div v-for="(series, i) in study.SeriesList" :key="i"
|
||||||
|
|
@ -65,6 +66,7 @@
|
||||||
<div class="frame_list">
|
<div class="frame_list">
|
||||||
<div v-for="(instance, idx) in series.instanceInfoList" :key="instance.Id"
|
<div v-for="(instance, idx) in series.instanceInfoList" :key="instance.Id"
|
||||||
class="frame_content"
|
class="frame_content"
|
||||||
|
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||||
:style="{ 'margin-bottom': idx < series.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
:style="{ 'margin-bottom': idx < series.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||||
@click="showMultiFrames(index, series, i, instance)">
|
@click="showMultiFrames(index, series, i, instance)">
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
|
|
@ -97,12 +99,12 @@
|
||||||
</div>
|
</div>
|
||||||
<i slot="reference" class="el-icon-connection"
|
<i slot="reference" class="el-icon-connection"
|
||||||
style="font-size: 15px;cursor: pointer;"
|
style="font-size: 15px;cursor: pointer;"
|
||||||
@click="popperClick(studyList, series)" />
|
@click.stop="popperClick(studyList, series)" />
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div v-show="series.InstanceCount" style="padding: 1px;">
|
<div v-show="series.instanceCount" style="padding: 1px;">
|
||||||
{{ series.modality }}: {{ series.instanceCount }} image
|
{{ series.modality }}: {{ series.instanceCount }} image
|
||||||
</div>
|
</div>
|
||||||
<div v-show="series.sliceThickness" style="padding: 1px;">
|
<div v-show="series.sliceThickness" style="padding: 1px;">
|
||||||
|
|
@ -166,16 +168,17 @@
|
||||||
<el-collapse-item :key="`${study.StudyId}`" :name="`${study.StudyId}`"
|
<el-collapse-item :key="`${study.StudyId}`" :name="`${study.StudyId}`"
|
||||||
v-if="study.VisitName === item.VisitName">
|
v-if="study.VisitName === item.VisitName">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
|
<div class="collapse-title-wrapper">
|
||||||
<div class="text-desc">
|
<div class="text-desc">
|
||||||
{{ study.StudyCode }}
|
{{ study.StudyCode }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <div v-show="study.Description" class="text-desc">
|
<!-- <div v-show="study.Description" class="text-desc">
|
||||||
{{ study.Description }}
|
{{ study.Description }}
|
||||||
</div> -->
|
</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
|
{{ study.Modalities }} : {{ study.SeriesCount }} Series
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-show="study.Description" class="text-desc" style="background-color: #1f1f1f;">
|
<div v-show="study.Description" class="text-desc" style="background-color: #1f1f1f;">
|
||||||
|
|
@ -207,6 +210,7 @@
|
||||||
<div class="frame_list">
|
<div class="frame_list">
|
||||||
<div v-for="(instance, idx) in seriesItem.instanceInfoList"
|
<div v-for="(instance, idx) in seriesItem.instanceInfoList"
|
||||||
:key="instance.Id" class="frame_content"
|
:key="instance.Id" class="frame_content"
|
||||||
|
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||||
:style="{ 'margin-bottom': idx < seriesItem.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
:style="{ 'margin-bottom': idx < seriesItem.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||||
@click="showMultiFrames(studyIndex, seriesItem, index, instance)">
|
@click="showMultiFrames(studyIndex, seriesItem, index, instance)">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -327,7 +331,8 @@ export default {
|
||||||
isFromCRCUpload: false,
|
isFromCRCUpload: false,
|
||||||
visitTaskId: null,
|
visitTaskId: null,
|
||||||
page: '',
|
page: '',
|
||||||
activeSeriesId: null
|
activeSeriesId: null,
|
||||||
|
activeInstanceId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -346,20 +351,18 @@ export default {
|
||||||
this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload
|
this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload
|
||||||
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
|
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
|
||||||
this.page = this.$route.query.page
|
this.page = this.$route.query.page
|
||||||
|
this.beforeUnloadHandler = () => {
|
||||||
|
cornerstone.imageCache.purgeCache()
|
||||||
|
requestPoolManager.resetRequestPool()
|
||||||
|
}
|
||||||
// cornerstone.events.addEventListener('cornerstoneimageloaded', this.cornerstoneImageLoaded)
|
// cornerstone.events.addEventListener('cornerstoneimageloaded', this.cornerstoneImageLoaded)
|
||||||
this.getStudiesInfo()
|
this.getStudiesInfo()
|
||||||
cornerstone.events.addEventListener('cornerstoneimageloadprogress', this.cornerstoneimageloadprogress)
|
cornerstone.events.addEventListener('cornerstoneimageloadprogress', this.cornerstoneimageloadprogress)
|
||||||
window.addEventListener('beforeunload', e => {
|
window.addEventListener('beforeunload', this.beforeUnloadHandler)
|
||||||
cornerstone.imageCache.purgeCache()
|
|
||||||
requestPoolManager.resetRequestPool()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
requestPoolManager.stopTaskTimer()
|
requestPoolManager.stopTaskTimer()
|
||||||
window.removeEventListener('beforeunload', e => {
|
window.removeEventListener('beforeunload', this.beforeUnloadHandler)
|
||||||
cornerstone.imageCache.purgeCache()
|
|
||||||
requestPoolManager.resetRequestPool()
|
|
||||||
})
|
|
||||||
workSpeedclose(true)
|
workSpeedclose(true)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -489,14 +492,17 @@ export default {
|
||||||
data.SeriesList = seriesList
|
data.SeriesList = seriesList
|
||||||
this.studyList.push(data)
|
this.studyList.push(data)
|
||||||
})
|
})
|
||||||
if (this.studyList.length > 0) {
|
const firstStudy = this.studyList.find(study => Array.isArray(study.SeriesList) && study.SeriesList.length > 0)
|
||||||
this.$refs.dicomViewer.loadImageStack(this.studyList[0].SeriesList[0])
|
if (firstStudy) {
|
||||||
const imageId = this.studyList[0].SeriesList[0].imageIds[0]
|
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]
|
let instanceId = imageId.split('/')[imageId.split('/').length - 1]
|
||||||
instanceId = instanceId.split('.')[0]
|
instanceId = instanceId.split('.')[0]
|
||||||
this.firstInstanceId = instanceId
|
this.firstInstanceId = instanceId
|
||||||
this.activeNames = [this.studyList[0].StudyId]
|
this.activeNames = [firstStudy.StudyId]
|
||||||
this.loadImages(this.studyList[0].SeriesList[0], 0)
|
this.loadImages(firstSeries, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -521,6 +527,7 @@ export default {
|
||||||
},
|
},
|
||||||
showSeriesImage(e, studyIndex, seriesIndex, series) {
|
showSeriesImage(e, studyIndex, seriesIndex, series) {
|
||||||
this.activeSeriesId = series.seriesId
|
this.activeSeriesId = series.seriesId
|
||||||
|
this.activeInstanceId = null
|
||||||
workSpeedclose(true)
|
workSpeedclose(true)
|
||||||
const element = e.currentTarget
|
const element = e.currentTarget
|
||||||
const elements = document.querySelectorAll('[series-type]')
|
const elements = document.querySelectorAll('[series-type]')
|
||||||
|
|
@ -562,6 +569,7 @@ export default {
|
||||||
},
|
},
|
||||||
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
||||||
this.currentSeriesIndex = seriesIndex
|
this.currentSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceId = instanceInfo.Id
|
||||||
const imageIds = []
|
const imageIds = []
|
||||||
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
|
||||||
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
|
||||||
|
|
@ -573,6 +581,7 @@ export default {
|
||||||
const seriesInfo = {
|
const seriesInfo = {
|
||||||
trialId: series.trialId,
|
trialId: series.trialId,
|
||||||
subjectVisitId: series.subjectVisitId,
|
subjectVisitId: series.subjectVisitId,
|
||||||
|
instanceInfoList: series.instanceInfoList,
|
||||||
studyId: series.studyId,
|
studyId: series.studyId,
|
||||||
imageIds: imageIds,
|
imageIds: imageIds,
|
||||||
seriesId: series.seriesId,
|
seriesId: series.seriesId,
|
||||||
|
|
@ -598,7 +607,11 @@ export default {
|
||||||
}
|
}
|
||||||
if (!isAddToTakPool) {
|
if (!isAddToTakPool) {
|
||||||
var priority = parseInt(new Date().getTime())
|
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 => {
|
series.instanceInfoList.map(image => {
|
||||||
this.imageList.push({ imageId: image.ImageId, seriesId: series.seriesId, priority })
|
this.imageList.push({ imageId: image.ImageId, seriesId: series.seriesId, priority })
|
||||||
})
|
})
|
||||||
|
|
@ -880,6 +893,7 @@ export default {
|
||||||
},
|
},
|
||||||
showRelationSeriesImage(e, series, studyIndex, index) {
|
showRelationSeriesImage(e, series, studyIndex, index) {
|
||||||
this.activeSeriesId = series.seriesId
|
this.activeSeriesId = series.seriesId
|
||||||
|
this.activeInstanceId = null
|
||||||
workSpeedclose(true)
|
workSpeedclose(true)
|
||||||
this.currentRelationIndex = index
|
this.currentRelationIndex = index
|
||||||
const element = e.currentTarget
|
const element = e.currentTarget
|
||||||
|
|
@ -937,7 +951,7 @@ export default {
|
||||||
if (this.imageList.length > 0) {
|
if (this.imageList.length > 0) {
|
||||||
requestPoolManager.startTaskTimer()
|
requestPoolManager.startTaskTimer()
|
||||||
this.imageList.map(image => {
|
this.imageList.map(image => {
|
||||||
requestPoolManager.loadAndCacheImagePlus(image.imageId, image.seriesId, image.priority)
|
requestPoolManager.loadAndCacheImagePlus(image.imageId, image.seriesId, image.priority).catch(() => {})
|
||||||
})
|
})
|
||||||
requestPoolManager.sortTaskPool()
|
requestPoolManager.sortTaskPool()
|
||||||
this.imageList = []
|
this.imageList = []
|
||||||
|
|
@ -1099,6 +1113,7 @@ export default {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
color: #D0D0D0;
|
color: #D0D0D0;
|
||||||
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1107,6 +1122,8 @@ export default {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
display: table;
|
display: table;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-x: hidden;
|
||||||
border: 1px solid #3e3f3a;
|
border: 1px solid #3e3f3a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1135,14 +1152,20 @@ export default {
|
||||||
.viewerContainer .viewerLeftSidePanel .viewernavigatorwrapper {
|
.viewerContainer .viewerLeftSidePanel .viewernavigatorwrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 220px;
|
width: 220px;
|
||||||
/* height: 84px; */
|
min-height: 85px;
|
||||||
padding: 1px 2px 1px 2px;
|
padding: 1px 2px 1px 2px;
|
||||||
margin: 2px 0 1px 1px;
|
margin: 2px 0 1px 1px;
|
||||||
|
align-items: flex-start;
|
||||||
/* border-radius: 2px;
|
/* border-radius: 2px;
|
||||||
border: 1px solid #404040; */
|
border: 1px solid #404040; */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.viewerContainer .viewerLeftSidePanel .viewernavigatorwrapper .imageBox {
|
||||||
|
align-self: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.viewerContainer .viewernavigatorwrapper .el-progress__text {
|
.viewerContainer .viewernavigatorwrapper .el-progress__text {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -1165,9 +1188,19 @@ export default {
|
||||||
/* width: 120px;
|
/* width: 120px;
|
||||||
height: 80px; */
|
height: 80px; */
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
padding: 3px 1px 3px 4px;
|
padding: 3px 1px 3px 4px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
font-size: 12px;
|
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 {
|
.viewerContainer .viewerLeftSidePanel .viewerlabelwrapper {
|
||||||
|
|
@ -1197,12 +1230,24 @@ export default {
|
||||||
|
|
||||||
.viewerContainer .el-collapse {
|
.viewerContainer .el-collapse {
|
||||||
border: none;
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewerContainer .el-collapse-item {
|
.viewerContainer .el-collapse-item {
|
||||||
background-color: #585453 !important;
|
background-color: #585453 !important;
|
||||||
color: #ddd;
|
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 {
|
.viewerContainer .el-collapse-item__content {
|
||||||
|
|
@ -1215,9 +1260,42 @@ export default {
|
||||||
background-color: #585453 !important;
|
background-color: #585453 !important;
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
border-bottom-color: #5a5a5a;
|
border-bottom-color: #5a5a5a;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
height: 40px;
|
height: auto;
|
||||||
|
min-height: 30px;
|
||||||
line-height: 20px;
|
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 {
|
.instance_frame_wrapper {
|
||||||
|
|
@ -1260,6 +1338,10 @@ export default {
|
||||||
border-color: #213a54 !important;
|
border-color: #213a54 !important;
|
||||||
background-color: #213a54;
|
background-color: #213a54;
|
||||||
}
|
}
|
||||||
|
.frame_content_active {
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
|
|
||||||
/* .viewerRightSidePanel {
|
/* .viewerRightSidePanel {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,11 @@
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</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')"
|
<el-form-item :label="$t('dictionary:signature:form:NeedConfirmedUserTypeIdList')"
|
||||||
prop="NeedConfirmedUserTypeIdList">
|
prop="NeedConfirmedUserTypeIdList">
|
||||||
<el-select v-model="form.NeedConfirmedUserTypeIdList" style="width: 100%" multiple>
|
<el-select v-model="form.NeedConfirmedUserTypeIdList" style="width: 100%" multiple>
|
||||||
|
|
@ -83,6 +88,7 @@ export default {
|
||||||
DocUserSignType: 0,
|
DocUserSignType: 0,
|
||||||
CurrentStaffTrainDays: 1,
|
CurrentStaffTrainDays: 1,
|
||||||
NewStaffTrainDays: 14,
|
NewStaffTrainDays: 14,
|
||||||
|
DocLanguageType: null
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
FileTypeId: [
|
FileTypeId: [
|
||||||
|
|
@ -92,6 +98,13 @@ export default {
|
||||||
trigger: ['blur'],
|
trigger: ['blur'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
DocLanguageType: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('common:ruleMessage:select'),
|
||||||
|
trigger: ['blur'],
|
||||||
|
},
|
||||||
|
],
|
||||||
SignViewMinimumMinutes: [
|
SignViewMinimumMinutes: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -143,6 +156,9 @@ export default {
|
||||||
this.form.DocUserSignType = this.data.DocUserSignType
|
this.form.DocUserSignType = this.data.DocUserSignType
|
||||||
this.form.CurrentStaffTrainDays = this.data.CurrentStaffTrainDays
|
this.form.CurrentStaffTrainDays = this.data.CurrentStaffTrainDays
|
||||||
this.form.NewStaffTrainDays = this.data.NewStaffTrainDays
|
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
|
this.loading = false
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,11 @@
|
||||||
<el-form-item :label="$t('dictionary:signature:search:Name')">
|
<el-form-item :label="$t('dictionary:signature:search:Name')">
|
||||||
<el-input v-model="searchData.Name" style="width: 130px" clearable />
|
<el-input v-model="searchData.Name" style="width: 130px" clearable />
|
||||||
</el-form-item>
|
</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-form-item :label="$t('dictionary:signature:table:NeedConfirmedUserTypes')">
|
||||||
<el-select v-model="searchData.UserTypeId" style="width: 150px" clearable>
|
<el-select v-model="searchData.UserTypeId" style="width: 150px" clearable>
|
||||||
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName"
|
<el-option v-for="item of userTypeOptions" :key="item.Id" :label="item.UserTypeShortName"
|
||||||
|
|
@ -90,6 +95,12 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</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')"
|
<el-table-column prop="SignViewMinimumMinutes" :label="$t('dictionary:signature:table:SignViewMinimumMinutes')"
|
||||||
show-overflow-tooltip sortable="custom" min-width="200px" />
|
show-overflow-tooltip sortable="custom" min-width="200px" />
|
||||||
<el-table-column prop="CurrentStaffTrainDays" :label="$t('dictionary:signature:table:CurrentStaffTrainDays')"
|
<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"
|
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title"
|
||||||
width="600px" custom-class="base-dialog-wrapper">
|
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>
|
</el-dialog>
|
||||||
<!--附件列表-->
|
<!--附件列表-->
|
||||||
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
|
<attachmentList v-if="config.visible" :config="config" :rowData="currentRow" :SystemDocumentId="SystemDocumentId"
|
||||||
|
|
@ -200,6 +211,7 @@ const searchDataDefault = () => {
|
||||||
IsDeleted: null,
|
IsDeleted: null,
|
||||||
DocUserSignType: null,
|
DocUserSignType: null,
|
||||||
UserTypeId: null,
|
UserTypeId: null,
|
||||||
|
DocLanguageType: null,
|
||||||
Name: '',
|
Name: '',
|
||||||
PageIndex: 1,
|
PageIndex: 1,
|
||||||
PageSize: 20,
|
PageSize: 20,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form
|
<el-form ref="siteForm" v-loading="loading" :model="form" :rules="rules" class="demo-ruleForm" size="small"
|
||||||
ref="siteForm"
|
label-width="150px">
|
||||||
v-loading="loading"
|
|
||||||
:model="form"
|
|
||||||
:rules="rules"
|
|
||||||
class="demo-ruleForm"
|
|
||||||
size="small"
|
|
||||||
label-width="150px"
|
|
||||||
>
|
|
||||||
<div class="base-dialog-body">
|
<div class="base-dialog-body">
|
||||||
<!-- Site Code -->
|
<!-- Site Code -->
|
||||||
<el-form-item :label="$t('institutions:sites:label:siteCode')" v-if="form.Id" prop="SiteCode">
|
<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>
|
||||||
|
|
||||||
<!-- 中心名称 -->
|
<!-- 中心名称 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('institutions:sites:label:siteName')" prop="SiteName">
|
||||||
:label="$t('institutions:sites:label:siteName')"
|
|
||||||
prop="SiteName"
|
|
||||||
>
|
|
||||||
<el-input v-model="form.SiteName" />
|
<el-input v-model="form.SiteName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 中心名称(CN) -->
|
<!-- 中心名称(CN) -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('institutions:sites:label:siteNameCN')" prop="SiteNameCN">
|
||||||
:label="$t('institutions:sites:label:siteNameCN')"
|
|
||||||
prop="SiteNameCN"
|
|
||||||
>
|
|
||||||
<el-input v-model="form.SiteNameCN" />
|
<el-input v-model="form.SiteNameCN" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- Alias Name -->
|
<!-- Alias Name -->
|
||||||
|
|
@ -38,7 +25,9 @@
|
||||||
</el-form-item> -->
|
</el-form-item> -->
|
||||||
<!-- Country -->
|
<!-- Country -->
|
||||||
<el-form-item :label="$t('institutions:sites:label:country')" prop="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>
|
</el-form-item>
|
||||||
<!-- City -->
|
<!-- City -->
|
||||||
<el-form-item :label="$t('institutions:sites:label:city')" prop="City">
|
<el-form-item :label="$t('institutions:sites:label:city')" prop="City">
|
||||||
|
|
@ -50,17 +39,8 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- Affiliated Hospital -->
|
<!-- Affiliated Hospital -->
|
||||||
<el-form-item :label="$t('institutions:sites:label:affiliatedHospital')">
|
<el-form-item :label="$t('institutions:sites:label:affiliatedHospital')">
|
||||||
<el-select
|
<el-select v-model="form.HospitalId" clearable style="width: 100%">
|
||||||
v-model="form.HospitalId"
|
<el-option v-for="item in hospitalList" :key="item.Id" :label="item.HospitalName" :value="item.Id" />
|
||||||
clearable
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in hospitalList"
|
|
||||||
:key="item.Id"
|
|
||||||
:label="item.HospitalName"
|
|
||||||
:value="item.Id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- Director Name -->
|
<!-- Director Name -->
|
||||||
|
|
@ -82,20 +62,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
|
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button
|
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancel">{{
|
||||||
:disabled="btnLoading"
|
$t('common:button:cancel') }}</el-button>
|
||||||
size="small"
|
<el-button size="small" type="primary" :loading="btnLoading" @click="handleSave">{{ $t('common:button:save')
|
||||||
type="primary"
|
}}</el-button>
|
||||||
@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>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<el-input v-model="password.UserType" disabled />
|
<el-input v-model="password.UserType" disabled />
|
||||||
</el-form-item> -->
|
</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-input v-model="password.NewUserName" :disabled="isUpdate" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 新密码 -->
|
<!-- 新密码 -->
|
||||||
|
|
@ -77,7 +77,7 @@ export default {
|
||||||
callback(
|
callback(
|
||||||
lang === 'zh'
|
lang === 'zh'
|
||||||
? new Error(
|
? new Error(
|
||||||
'1)新建账号,用户名字符长度最小为4个字符,最大为16个字符,只可使用字母、数字、下划线;'
|
'新建账号,用户名字符长度最小为4个字符,最大为16个字符,只可使用字母、数字、下划线;'
|
||||||
)
|
)
|
||||||
: new Error(
|
: 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.'
|
'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.'
|
||||||
|
|
|
||||||
|
|
@ -150,12 +150,12 @@
|
||||||
<!-- {{ $t('login:title:system_title_about') }} -->
|
<!-- {{ $t('login:title:system_title_about') }} -->
|
||||||
<svg-icon icon-class="login-logo" style="width: 250px; height: 71px" />
|
<svg-icon icon-class="login-logo" style="width: 250px; height: 71px" />
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0px" v-else>
|
<div style="margin-bottom: 0px" v-else>
|
||||||
<!-- {{ $t('login:title:system_title_about') }} -->
|
<!-- {{ $t('login:title:system_title_about') }} -->
|
||||||
<img src="@/assets/system.png" alt=""
|
<img src="@/assets/system.png" alt=""
|
||||||
:style="{ width: isEN ? '180px' : '200px', height: isEN ? '60px' : '65px' }">
|
:style="{ width: isEN ? '180px' : '200px', height: isEN ? '60px' : '65px' }" />
|
||||||
<p style="margin-bottom: 0px">{{ $t('login:title:system') }}</p>
|
<p style="margin-bottom: 0px">{{ $t('login:title:system') }}</p>
|
||||||
</p>
|
</div>
|
||||||
<p style="margin-bottom: 20px; margin-top: 0">
|
<p style="margin-bottom: 20px; margin-top: 0">
|
||||||
V{{ $version.IsEnv_US ? $version.Version_US : $version.Version }}
|
V{{ $version.IsEnv_US ? $version.Version_US : $version.Version }}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,52 @@
|
||||||
<el-input-number v-model="form.AverageEngravingCycle"
|
<el-input-number v-model="form.AverageEngravingCycle"
|
||||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" controls-position="right" :min="0" />
|
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" controls-position="right" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<!-- 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')"
|
<el-form-item v-if="!notShowFieldList.includes('IsConfirmImagingTechnologist')"
|
||||||
:label="$t('trials:researchForm:form:isQualified')">
|
:label="$t('trials:researchForm:form:isQualified')" prop="IsConfirmImagingTechnologist">
|
||||||
<el-radio-group v-model="form.IsConfirmImagingTechnologist"
|
<el-radio-group v-model="form.IsConfirmImagingTechnologist"
|
||||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsConfirmImagingTechnologist${item.value}`" :label="item.value">{{
|
<el-radio v-for="item of $d.YesOrNo" :key="`IsConfirmImagingTechnologist${item.value}`" :label="item.value">{{
|
||||||
|
|
@ -60,7 +103,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 原因 -->
|
<!-- 原因 -->
|
||||||
<el-form-item v-if="!notShowFieldList.includes('NotConfirmReson') && form.IsConfirmImagingTechnologist === false"
|
<el-form-item v-if="!notShowFieldList.includes('NotConfirmReson') && form.IsConfirmImagingTechnologist === false"
|
||||||
:label="$t('trials:researchForm:form:notQualifiedReason')">
|
:label="$t('trials:researchForm:form:notQualifiedReason')" prop="NotConfirmReson">
|
||||||
<el-input v-model="form.NotConfirmReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
<el-input v-model="form.NotConfirmReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -74,7 +117,7 @@
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</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')" />
|
<span slot="label" v-html="$t('trials:researchForm:form:isFollowStudyParam')" />
|
||||||
<el-radio-group v-model="form.IsFollowStudyParameters"
|
<el-radio-group v-model="form.IsFollowStudyParameters"
|
||||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" style="margin-right: 10px;">
|
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" style="margin-right: 10px;">
|
||||||
|
|
@ -86,11 +129,28 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</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')" />
|
<span slot="label" v-html="$t('trials:researchForm:form:notFollowStudyParam')" />
|
||||||
<el-input v-model="form.NotFollowReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
<el-input v-model="form.NotFollowReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||||
</el-form-item>
|
</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>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<!-- 保存 -->
|
<!-- 保存 -->
|
||||||
<el-button v-if="state === 0 && userTypeEnumInt === 0 && !isHistory" type="primary" :loading="btnLoading"
|
<el-button v-if="state === 0 && userTypeEnumInt === 0 && !isHistory" type="primary" :loading="btnLoading"
|
||||||
|
|
@ -152,6 +212,15 @@ export default {
|
||||||
Phone: '', // 联系人电话
|
Phone: '', // 联系人电话
|
||||||
Email: '', // 联系人邮箱
|
Email: '', // 联系人邮箱
|
||||||
AverageEngravingCycle: '',
|
AverageEngravingCycle: '',
|
||||||
|
IsRoutineMRIPDEE: '',
|
||||||
|
MRIPDFFScanTime: '',
|
||||||
|
MRIPDFFLeadTime: '',
|
||||||
|
MRIPDFFOther: '',
|
||||||
|
IsAuthorize: '',
|
||||||
|
IsAuthorizeRadiologistsParticipate: '',
|
||||||
|
AssignFixedTechnologists: '',
|
||||||
|
ISStrictManualBurnFlag: '',
|
||||||
|
NotStrictManualBurnFlagReason: '',
|
||||||
IsConfirmImagingTechnologist: '',
|
IsConfirmImagingTechnologist: '',
|
||||||
NotConfirmReson: '',
|
NotConfirmReson: '',
|
||||||
EfficacyEvaluatorType: '',
|
EfficacyEvaluatorType: '',
|
||||||
|
|
@ -162,6 +231,30 @@ export default {
|
||||||
TrialSiteId: [
|
TrialSiteId: [
|
||||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
{ 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: [
|
UserName: [
|
||||||
{ required: true, validator: (rule, value, callback) => { !value ? callback(new Error(this.$t('trials:researchForm:formRule:specify'))) : callback() }, trigger: 'blur' },
|
{ 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'] }
|
{ min: 0, max: 50, message: this.$t('trials:researchForm:formRule:maxLength'), trigger: ['blur', 'change'] }
|
||||||
|
|
@ -188,6 +281,11 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleIsAuthorizeInput(label) {
|
||||||
|
this.form.IsAuthorizeRadiologistsParticipate = false
|
||||||
|
this.form.AssignFixedTechnologists = false
|
||||||
|
this.form[label] = true
|
||||||
|
},
|
||||||
async viewManual() {
|
async viewManual() {
|
||||||
try {
|
try {
|
||||||
let data = {
|
let data = {
|
||||||
|
|
@ -231,6 +329,14 @@ export default {
|
||||||
phone: this.form.Phone,
|
phone: this.form.Phone,
|
||||||
email: this.form.Email,
|
email: this.form.Email,
|
||||||
averageEngravingCycle: this.form.AverageEngravingCycle,
|
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,
|
isConfirmImagingTechnologist: this.form.IsConfirmImagingTechnologist,
|
||||||
notConfirmReson: this.form.NotConfirmReson,
|
notConfirmReson: this.form.NotConfirmReson,
|
||||||
efficacyEvaluatorType: this.form.EfficacyEvaluatorType,
|
efficacyEvaluatorType: this.form.EfficacyEvaluatorType,
|
||||||
|
|
@ -275,6 +381,16 @@ export default {
|
||||||
this.form.Phone = trialSiteSurvey.Phone // 联系人电话
|
this.form.Phone = trialSiteSurvey.Phone // 联系人电话
|
||||||
this.form.Email = trialSiteSurvey.Email // 联系人邮箱
|
this.form.Email = trialSiteSurvey.Email // 联系人邮箱
|
||||||
this.form.AverageEngravingCycle = trialSiteSurvey.AverageEngravingCycle
|
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.IsConfirmImagingTechnologist = trialSiteSurvey.IsConfirmImagingTechnologist
|
||||||
this.form.NotConfirmReson = trialSiteSurvey.NotConfirmReson
|
this.form.NotConfirmReson = trialSiteSurvey.NotConfirmReson
|
||||||
this.form.EfficacyEvaluatorType = trialSiteSurvey.EfficacyEvaluatorType
|
this.form.EfficacyEvaluatorType = trialSiteSurvey.EfficacyEvaluatorType
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,98 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="equipmentForm" :model="form" :rules="rules" label-width="150px">
|
<el-form ref="equipmentForm" :model="form" :rules="rules" label-width="380px">
|
||||||
<div class="base-dialog-body">
|
<div class="base-dialog-body">
|
||||||
<!-- 扫描设备 -->
|
<!-- 扫描设备 -->
|
||||||
<el-form-item :label="$t('trials:equiptResearch:form:equipment')" prop="EquipmentTypeId">
|
<el-form-item :label="$t('trials:equiptResearch:form:equipment')" prop="EquipmentTypeEnum"
|
||||||
<el-select
|
v-if="EquipmentControlFieldList.includes('EquipmentTypeEnum')">
|
||||||
v-model="form.EquipmentTypeId"
|
<div style="display: flex;align-items: center;">
|
||||||
style="width:100%"
|
<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"
|
||||||
<!-- <el-option
|
:value="item.value" />
|
||||||
v-for="item of dictionaryList.SiteSurvey_ScanEquipmentType"
|
</el-select>
|
||||||
:key="item.Id"
|
<el-input placeholder="" v-model="form.OtherEquipmentType" style="margin-left: 10px;"
|
||||||
:label="item.Value"
|
v-if="form.EquipmentTypeEnum == '-1'" clearable>
|
||||||
:value="item.Id"
|
</el-input>
|
||||||
/> -->
|
</div>
|
||||||
<el-option
|
|
||||||
v-for="item of $d.SiteSurvey_ScanEquipmentType"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</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-input v-model="form.Parameters" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 扫描仪器制造商名称 -->
|
<!-- 扫描仪器制造商名称 -->
|
||||||
<el-form-item :label="$t('trials:equiptResearch:form:manufacturer')">
|
<el-form-item :label="$t('trials:equiptResearch:form:manufacturer')"
|
||||||
<el-input v-model="form.ManufacturerName" />
|
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>
|
||||||
<!-- 扫描仪型号 -->
|
<!-- 扫描仪型号 -->
|
||||||
<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-input v-model="form.ScannerType" />
|
||||||
</el-form-item>
|
</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-input v-model="form.Note" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -69,26 +127,94 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
isShowParameters: {
|
EquipmentControlFieldList: {
|
||||||
type: Boolean,
|
type: Array,
|
||||||
default: false
|
default: () => {
|
||||||
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
Id: '',
|
Id: '',
|
||||||
EquipmentTypeId: '',
|
EquipmentTypeEnum: null,
|
||||||
Parameters: '',
|
OtherEquipmentType: null,
|
||||||
ManufacturerName: '',
|
Parameters: null,
|
||||||
ScannerType: '',
|
Note: null,
|
||||||
Note: '',
|
ManufacturerType: null,
|
||||||
|
ManufacturerName: null,
|
||||||
|
ScannerType: null,
|
||||||
|
MagneticFieldStrengthType: null,
|
||||||
|
BodyCoilChannelCount: null,
|
||||||
|
HasDedicatedPdfFatQuantificationSequence: null,
|
||||||
|
PdfFatQuantificationSequenceType: null,
|
||||||
|
OtherSequenceSpecification: null,
|
||||||
|
HasT2R2Correction: null,
|
||||||
|
CanFullyExportPdfParameterMapsAndRawDicom: null,
|
||||||
TrialSiteSurveyId: ''
|
TrialSiteSurveyId: ''
|
||||||
},
|
},
|
||||||
rules: {
|
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'] }
|
{ 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'] }
|
||||||
|
],
|
||||||
},
|
},
|
||||||
btnLoading: false,
|
btnLoading: false,
|
||||||
dictionaryList: {}
|
dictionaryList: {}
|
||||||
|
|
|
||||||
|
|
@ -2,63 +2,88 @@
|
||||||
<div class="equipment-wrapper">
|
<div class="equipment-wrapper">
|
||||||
<div class="header-wrapper">
|
<div class="header-wrapper">
|
||||||
<!-- 新增 -->
|
<!-- 新增 -->
|
||||||
<el-button
|
<el-button v-if="state === 0 && userTypeEnumInt === 0 && !isHistory && EquipmentControlFieldList.length > 0"
|
||||||
v-if="state === 0 && userTypeEnumInt === 0 && !isHistory"
|
size="small" type="primary" @click="handleAdd">
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
@click="handleAdd"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:add') }}
|
{{ $t('common:button:add') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table v-loading="loading" :data="list" border style="width: 100%">
|
||||||
v-loading="loading"
|
|
||||||
:data="list"
|
|
||||||
border
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<!-- 扫描设备 -->
|
<!-- 扫描设备 -->
|
||||||
<el-table-column
|
<el-table-column v-if="EquipmentControlFieldList.includes('EquipmentTypeEnum')" prop="EquipmentTypeEnum"
|
||||||
prop="EquipmentType"
|
:label="$t('trials:equiptResearch:form:equipment')" min-width="120" show-overflow-tooltip>
|
||||||
:label="$t('trials:equiptResearch:form:equipment')"
|
<template slot-scope="scope">
|
||||||
min-width="120"
|
{{ scope.row.OtherEquipmentType ? scope.row.OtherEquipmentType :
|
||||||
show-overflow-tooltip
|
$fd('SiteSurvey_ScanEquipmentType', scope.row.EquipmentTypeEnum) }}
|
||||||
/>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<!-- 扫描参数 -->
|
<!-- 扫描参数 -->
|
||||||
<el-table-column
|
<el-table-column v-if="EquipmentControlFieldList.includes('Parameters')" prop="Parameters"
|
||||||
v-if="isShowParameters"
|
:label="$t('trials:equiptResearch:form:param')" min-width="100" show-overflow-tooltip />
|
||||||
prop="Parameters"
|
|
||||||
:label="$t('trials:equiptResearch:form:param')"
|
|
||||||
min-width="100"
|
|
||||||
show-overflow-tooltip
|
|
||||||
/>
|
|
||||||
<!-- 扫描仪器制造商名称 -->
|
<!-- 扫描仪器制造商名称 -->
|
||||||
<el-table-column
|
<el-table-column v-if="EquipmentControlFieldList.includes('ManufacturerType')" min-width="120"
|
||||||
min-width="120"
|
prop="ManufacturerType" :label="$t('trials:equiptResearch:form:manufacturer')" show-overflow-tooltip>
|
||||||
prop="ManufacturerName"
|
<template slot-scope="scope">
|
||||||
:label="$t('trials:equiptResearch:form:manufacturer')"
|
{{ scope.row.ManufacturerName ? scope.row.ManufacturerName : $fd('ManufacturerType',
|
||||||
show-overflow-tooltip
|
scope.row.ManufacturerType) }}
|
||||||
/>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<!-- 扫描仪型号 -->
|
<!-- 扫描仪型号 -->
|
||||||
<el-table-column
|
<el-table-column v-if="EquipmentControlFieldList.includes('ScannerType')" min-width="120" prop="ScannerType"
|
||||||
min-width="120"
|
:label="$t('trials:equiptResearch:form:model')" show-overflow-tooltip />
|
||||||
prop="ScannerType"
|
<!-- 磁场强度 -->
|
||||||
:label="$t('trials:equiptResearch:form:model')"
|
<el-table-column v-if="EquipmentControlFieldList.includes('MagneticFieldStrengthType')" min-width="120"
|
||||||
show-overflow-tooltip
|
prop="MagneticFieldStrengthType" :label="$t('trials:equiptResearch:form:MagneticFieldStrengthType')"
|
||||||
/>
|
show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ $fd('MagneticFieldStrengthType', scope.row.MagneticFieldStrengthType) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 体部线圈通道数 -->
|
||||||
|
<el-table-column v-if="EquipmentControlFieldList.includes('BodyCoilChannelCount')" min-width="120"
|
||||||
|
prop="BodyCoilChannelCount" :label="$t('trials:equiptResearch:form:BodyCoilChannelCount')"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ $fd('BodyCoilChannelCount', scope.row.BodyCoilChannelCount) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 是否具备专用的PDFF脂肪定量序列(CSE-MRI序列) -->
|
||||||
|
<el-table-column v-if="EquipmentControlFieldList.includes('HasDedicatedPdfFatQuantificationSequence')"
|
||||||
|
min-width="120" prop="HasDedicatedPdfFatQuantificationSequence"
|
||||||
|
:label="$t('trials:equiptResearch:form:HasDedicatedPdfFatQuantificationSequence')" show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ $fd('YesOrNo', scope.row.HasDedicatedPdfFatQuantificationSequence) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 专用的PDFF脂肪定量序列类型 -->
|
||||||
|
<el-table-column v-if="EquipmentControlFieldList.includes('PdfFatQuantificationSequenceType')" min-width="120"
|
||||||
|
prop="PdfFatQuantificationSequenceType"
|
||||||
|
:label="$t('trials:equiptResearch:form:PdfFatQuantificationSequenceType')" show-overflow-tooltip><template
|
||||||
|
slot-scope="scope">
|
||||||
|
{{ scope.row.OtherSequenceSpecification ? scope.row.OtherSequenceSpecification :
|
||||||
|
$fd('PdfFatQuantificationSequenceType', scope.row.PdfFatQuantificationSequenceType) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 是否包含 T2/R2 校正(用于铁沉积校正) -->
|
||||||
|
<el-table-column v-if="EquipmentControlFieldList.includes('HasT2R2Correction')" min-width="120"
|
||||||
|
prop="HasT2R2Correction" :label="$t('trials:equiptResearch:form:HasT2R2Correction')" show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ $fd('YesOrNo', scope.row.HasT2R2Correction) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 是否可完整导出 PDFF 参数图及全部原始 DICOM 数据 -->
|
||||||
|
<el-table-column v-if="EquipmentControlFieldList.includes('CanFullyExportPdfParameterMapsAndRawDicom')"
|
||||||
|
prop="CanFullyExportPdfParameterMapsAndRawDicom"
|
||||||
|
:label="$t('trials:equiptResearch:form:CanFullyExportPdfParameterMapsAndRawDicom')" min-width="120"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ $fd('YesOrNo', scope.row.CanFullyExportPdfParameterMapsAndRawDicom) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<!-- 备注 -->
|
<!-- 备注 -->
|
||||||
<el-table-column
|
<el-table-column v-if="EquipmentControlFieldList.includes('Note')" min-width="120" prop="Note"
|
||||||
min-width="120"
|
:label="$t('trials:equiptResearch:form:precautions')" show-overflow-tooltip />
|
||||||
prop="Note"
|
<el-table-column v-if="state === 0 && userTypeEnumInt === 0 && !isHistory" fixed="right"
|
||||||
:label="$t('trials:equiptResearch:form:precautions')"
|
:label="$t('common:action:action')" width="100">
|
||||||
show-overflow-tooltip
|
|
||||||
/>
|
|
||||||
<el-table-column
|
|
||||||
v-if="state === 0 && userTypeEnumInt === 0 && !isHistory"
|
|
||||||
fixed="right"
|
|
||||||
:label="$t('common:action:action')"
|
|
||||||
width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 编辑 -->
|
<!-- 编辑 -->
|
||||||
<el-button type="text" size="small" @click="handleEdit(scope.row)">
|
<el-button type="text" size="small" @click="handleEdit(scope.row)">
|
||||||
|
|
@ -73,16 +98,10 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 新增/编辑人员信息 -->
|
<!-- 新增/编辑人员信息 -->
|
||||||
<el-dialog
|
<el-dialog v-if="editVisible" :visible.sync="editVisible" :close-on-click-modal="false" :title="title" width="800px"
|
||||||
v-if="editVisible"
|
custom-class="base-dialog-wrapper" :append-to-body="userTypeEnumInt !== 0">
|
||||||
:visible.sync="editVisible"
|
<EquipmentForm :data="rowData" :trial-site-survey-equipment-type="trialSiteSurveyEquipmentType"
|
||||||
:close-on-click-modal="false"
|
:EquipmentControlFieldList="EquipmentControlFieldList" @getList="getList" @close="closeDialog" />
|
||||||
:title="title"
|
|
||||||
width="600px"
|
|
||||||
custom-class="base-dialog-wrapper"
|
|
||||||
:append-to-body="userTypeEnumInt !== 0"
|
|
||||||
>
|
|
||||||
<EquipmentForm :data="rowData" :trial-site-survey-equipment-type="trialSiteSurveyEquipmentType" :is-show-parameters="isShowParameters" @getList="getList" @close="closeDialog" />
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -115,7 +134,7 @@ export default {
|
||||||
state: null,
|
state: null,
|
||||||
trialSiteSurveyId: '',
|
trialSiteSurveyId: '',
|
||||||
trialId: '',
|
trialId: '',
|
||||||
isShowParameters: false
|
EquipmentControlFieldList: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -160,10 +179,14 @@ export default {
|
||||||
this.$message.success(this.$t('trials:equiptResearch:message:delSuccessfully'))
|
this.$message.success(this.$t('trials:equiptResearch:message:delSuccessfully'))
|
||||||
}
|
}
|
||||||
}).catch(() => { this.loading = false })
|
}).catch(() => { this.loading = false })
|
||||||
}).catch(() => {})
|
}).catch(() => { })
|
||||||
},
|
},
|
||||||
initList(TrialSiteEquipmentSurveyList, trialSiteSurvey, isShowParameters) {
|
initList(TrialSiteEquipmentSurveyList, trialSiteSurvey, EquipmentControlFieldList) {
|
||||||
this.isShowParameters = isShowParameters
|
this.EquipmentControlFieldList = []
|
||||||
|
EquipmentControlFieldList.forEach(item => {
|
||||||
|
this.EquipmentControlFieldList.push(item.FiledName)
|
||||||
|
})
|
||||||
|
console.log(this.EquipmentControlFieldList, 'this.EquipmentControlFieldList')
|
||||||
this.list = TrialSiteEquipmentSurveyList
|
this.list = TrialSiteEquipmentSurveyList
|
||||||
this.state = trialSiteSurvey.State
|
this.state = trialSiteSurvey.State
|
||||||
this.$forceUpdate()
|
this.$forceUpdate()
|
||||||
|
|
@ -176,8 +199,8 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.equipment-wrapper{
|
.equipment-wrapper {
|
||||||
.header-wrapper{
|
.header-wrapper {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ export default {
|
||||||
this.$refs['historicalParticipant'].initList(historicalArr, res.Result.TrialSiteSurvey)
|
this.$refs['historicalParticipant'].initList(historicalArr, res.Result.TrialSiteSurvey)
|
||||||
this.$refs['researchParticipants'].initList(newArr, res.Result.TrialSiteSurvey)
|
this.$refs['researchParticipants'].initList(newArr, res.Result.TrialSiteSurvey)
|
||||||
// this.$refs['researchParticipants'].initList(res.Result.TrialSiteUserSurveyList, res.Result.TrialSiteSurvey)
|
// this.$refs['researchParticipants'].initList(res.Result.TrialSiteUserSurveyList, res.Result.TrialSiteSurvey)
|
||||||
this.$refs['researchEquipments'].initList(res.Result.TrialSiteEquipmentSurveyList, res.Result.TrialSiteSurvey, !(res.Result.SiteSurveyFiledConfig && res.Result.SiteSurveyFiledConfig.ModifyFiledList.length > 0))
|
this.$refs['researchEquipments'].initList(res.Result.TrialSiteEquipmentSurveyList, res.Result.TrialSiteSurvey, res.Result.SiteSurveyFiledConfig.EquipmentControlFieldList)
|
||||||
this.isExistIncorrect = res.Result.TrialSiteUserSurveyList.every(item => item.IsCorrect === false)
|
this.isExistIncorrect = res.Result.TrialSiteUserSurveyList.every(item => item.IsCorrect === false)
|
||||||
}
|
}
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<!-- <TopLang style="position: fixed;top: 40px;right: 40px" /> -->
|
<!-- <TopLang style="position: fixed;top: 40px;right: 40px" /> -->
|
||||||
<div style="display: flex;justify-content: space-between;" v-if="!isPreview">
|
<div style="display: flex;justify-content: space-between;" v-if="!isPreview">
|
||||||
<div>{{ $t('trials:researchForm:title:researchSurveyStatus') }} <el-tag>{{ $fd('ResearchRecord', state)
|
<div>{{ $t('trials:researchForm:title:researchSurveyStatus') }} <el-tag>{{ $fd('ResearchRecord', state)
|
||||||
}}</el-tag></div>
|
}}</el-tag></div>
|
||||||
<div>
|
<div>
|
||||||
<!-- 提交 -->
|
<!-- 提交 -->
|
||||||
<el-button v-if="(state === 0 && userTypeEnumInt === 0)" type="primary" size="small"
|
<el-button v-if="(state === 0 && userTypeEnumInt === 0)" type="primary" size="small"
|
||||||
|
|
@ -209,7 +209,7 @@ export default {
|
||||||
|
|
||||||
this.$refs['historicalParticipant'].initList(historicalArr, res.Result.TrialSiteSurvey)
|
this.$refs['historicalParticipant'].initList(historicalArr, res.Result.TrialSiteSurvey)
|
||||||
this.$refs['researchParticipants'].initList(newArr, res.Result.TrialSiteSurvey)
|
this.$refs['researchParticipants'].initList(newArr, res.Result.TrialSiteSurvey)
|
||||||
this.$refs['researchEquipments'].initList(res.Result.TrialSiteEquipmentSurveyList, res.Result.TrialSiteSurvey, !(res.Result.SiteSurveyFiledConfig && res.Result.SiteSurveyFiledConfig.ModifyFiledList.length > 0))
|
this.$refs['researchEquipments'].initList(res.Result.TrialSiteEquipmentSurveyList, res.Result.TrialSiteSurvey, res.Result.SiteSurveyFiledConfig.EquipmentControlFieldList)
|
||||||
this.isExistIncorrect = res.Result.TrialSiteUserSurveyList.every(item => item.IsCorrect === false)
|
this.isExistIncorrect = res.Result.TrialSiteUserSurveyList.every(item => item.IsCorrect === false)
|
||||||
}
|
}
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<h2 style="text-align:center;">
|
<h2 style="text-align:center;">
|
||||||
<!-- 中心调研表 -->
|
<!-- 中心调研表 -->
|
||||||
{{ $t('trials:researchForm:title:question') }}
|
{{ $t('trials:researchForm:title:question') }}
|
||||||
<!-- <TopLang style="position: fixed;top: 40px;right: 40px" /> -->
|
<TopLang style="position: fixed;top: 40px;right: 40px" />
|
||||||
</h2>
|
</h2>
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="resetForm" v-loading="loading" :model="form" label-width="150px" style="width:80%;margin:0 auto;"
|
<el-form ref="resetForm" v-loading="loading" :model="form" label-width="150px" style="width:80%;margin:0 auto;"
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
import { changeURLStatic } from '@/utils/history.js'
|
||||||
export default {
|
export default {
|
||||||
name: 'TopLang',
|
name: 'TopLang',
|
||||||
|
|
||||||
|
|
@ -44,7 +44,8 @@ export default {
|
||||||
this.$i18n.locale = lang
|
this.$i18n.locale = lang
|
||||||
this.setLanguage(lang)
|
this.setLanguage(lang)
|
||||||
this.$updateDictionary()
|
this.$updateDictionary()
|
||||||
// window.location.reload()
|
changeURLStatic('lang', lang)
|
||||||
|
window.location.reload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,423 @@
|
||||||
|
<template>
|
||||||
|
<div class="systemConfig" v-loading="loading">
|
||||||
|
<div ref="leftContainer" class="left" style="padding: 20px;">
|
||||||
|
<el-form :inline="true" :model="form" :rules="rules" ref="systemConfigForm"
|
||||||
|
style="display: flex;align-items: center;justify-content: space-between;flex-wrap: wrap;">
|
||||||
|
<h3>{{ $t("system:config:BasicSystemConfig") }}</h3>
|
||||||
|
<el-form-item :label="$t('system:config:QcRiskControl')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.QCRiskControl" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OpenUserComplexPassword')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.OpenUserComplexPassword" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OpenSignDocumentBeforeWork')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.OpenSignDocumentBeforeWork" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OpenTrialRelationDelete')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.OpenTrialRelationDelete" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OpenLoginLimit')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.OpenLoginLimit" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:LoginMaxFailCount')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.LoginMaxFailCount">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.LoginMaxFailCount" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:LoginFailLockMinutes')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.LoginFailLockMinutes">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.LoginFailLockMinutes" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:AutoLoginOutMinutes')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.AutoLoginOutMinutes">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.AutoLoginOutMinutes" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OpenLoginMFA')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.OpenLoginMFA" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:ContinuousReadingTimeMin')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.ContinuousReadingTimeMin">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.ContinuousReadingTimeMin" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:ReadingRestTimeMin')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.ReadingRestTimeMin">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.ReadingRestTimeMin" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:IsNeedChangePassWord')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.IsNeedChangePassWord" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:ChangePassWordDays')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.ChangePassWordDays">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.ChangePassWordDays" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:TemplateType')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.TemplateType">
|
||||||
|
<el-select v-model="form.BasicSystemConfig.TemplateType" placeholder="">
|
||||||
|
<el-option v-for="item in $d.SysTemplateType" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:ThirdPdfUrl')" style="width: 45%;" prop="BasicSystemConfig.ThirdPdfUrl">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.ThirdPdfUrl" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:UserMFAVerifyMinutes')" style="width: 45%;"
|
||||||
|
prop="BasicSystemConfig.UserMFAVerifyMinutes">
|
||||||
|
<el-input v-model="form.BasicSystemConfig.UserMFAVerifyMinutes" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<h3>{{ $t("system:config:SystemEmailSendConfig") }}</h3>
|
||||||
|
<el-form-item :label="$t('system:config:Host')" style="width: 45%;" prop="SystemEmailSendConfig.Host">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.Host" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:Port')" style="width: 45%;" prop="SystemEmailSendConfig.Port">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.Port" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:Imap')" style="width: 45%;" prop="SystemEmailSendConfig.Imap">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.Imap" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:ImapPort')" style="width: 45%;" prop="SystemEmailSendConfig.ImapPort">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.ImapPort" clearable type="number" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:FromEmail')" style="width: 45%;" prop="SystemEmailSendConfig.FromEmail">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.FromEmail" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:FromName')" style="width: 45%;" prop="SystemEmailSendConfig.FromName">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.FromName" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:AuthorizationCode')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.AuthorizationCode">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.AuthorizationCode" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:SiteUrl')" style="width: 45%;" prop="SystemEmailSendConfig.SiteUrl">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.SiteUrl" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:SystemShortName')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.SystemShortName">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.SystemShortName" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OrganizationName')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.OrganizationName">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.OrganizationName" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:OrganizationNameCN')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.OrganizationNameCN">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.OrganizationNameCN" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:PlatformName')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.PlatformName">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.PlatformName" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:PlatformNameCN')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.PlatformNameCN">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.PlatformNameCN" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:CompanyName')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.CompanyName">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.CompanyName" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:CompanyNameCN')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.CompanyNameCN">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.CompanyNameCN" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:CompanyShortName')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.CompanyShortName">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.CompanyShortName" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:CompanyShortNameCN')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.CompanyShortNameCN">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.CompanyShortNameCN" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:IsEnv_US')" style="width: 45%;">
|
||||||
|
<el-select v-model="form.SystemEmailSendConfig.IsEnv_US" placeholder="">
|
||||||
|
<el-option v-for="item in $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:config:EmailRegexStr')" style="width: 45%;"
|
||||||
|
prop="SystemEmailSendConfig.EmailRegexStr">
|
||||||
|
<el-input v-model="form.SystemEmailSendConfig.EmailRegexStr" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item style="width: 100%;text-align: right;">
|
||||||
|
<el-button type="primary" size="small" @click="handleSave">
|
||||||
|
{{ $t('common:button:save') }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { getSystemBasicConfigInfo, getEmailConfigInfo, updateSystemBasicConfig, updateSystemEmailConfig } from '@/api/admin'
|
||||||
|
export default {
|
||||||
|
name: "systemConfig",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
rules: {
|
||||||
|
'BasicSystemConfig.LoginMaxFailCount': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.LoginFailLockMinutes': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.AutoLoginOutMinutes': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.ContinuousReadingTimeMin': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.ReadingRestTimeMin': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.ChangePassWordDays': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.TemplateType': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.UserMFAVerifyMinutes': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'BasicSystemConfig.ThirdPdfUrl': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
|
||||||
|
'SystemEmailSendConfig.Host': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.Port': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.Imap': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.ImapPort': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
|
{ type: 'number', message: this.$t('systemConfig:ruleMessage:mustNumber'), trigger: 'blur' },
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.FromEmail': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.FromName': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.AuthorizationCode': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.SiteUrl': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.SystemShortName': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.OrganizationName': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.OrganizationNameCN': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.PlatformName': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.PlatformNameCN': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.CompanyName': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.CompanyNameCN': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.CompanyShortName': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.CompanyShortNameCN': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'SystemEmailSendConfig.EmailRegexStr': [
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
// 启用质控风险控制功能
|
||||||
|
"QCRiskControl": true,
|
||||||
|
// 打开用户复杂密码
|
||||||
|
"OpenUserComplexPassword": false,
|
||||||
|
// 是否在开始工作前强制签署电子知情同意书
|
||||||
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
// 是否打开项目关联删除
|
||||||
|
"OpenTrialRelationDelete": false,
|
||||||
|
//是否启用登录失败次数限制(防暴力破解)
|
||||||
|
"OpenLoginLimit": false,
|
||||||
|
// 连续登录失败多少次后触发锁定
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
//触发锁定后账号锁定时长(分钟)
|
||||||
|
"LoginFailLockMinutes": 1,
|
||||||
|
//无操作自动登出的超时时间(分钟)
|
||||||
|
"AutoLoginOutMinutes": 10,
|
||||||
|
// 是否启用多因子登录认证(MFA)
|
||||||
|
"OpenLoginMFA": false,
|
||||||
|
// 连续阅片的最长工作时间(分钟),超时后强制休息
|
||||||
|
"ContinuousReadingTimeMin": 120,
|
||||||
|
//强制休息时长(分钟)
|
||||||
|
"ReadingRestTimeMin": 10,
|
||||||
|
// 是否强制用户定期修改密码
|
||||||
|
"IsNeedChangePassWord": true,
|
||||||
|
// 密码有效期(天),到期后必须修改
|
||||||
|
"ChangePassWordDays": 90,
|
||||||
|
//模板类型1Elevate(LiLi)2Extensive(展影)
|
||||||
|
"TemplateType": 2,
|
||||||
|
// 转换PDF服务配置
|
||||||
|
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf",
|
||||||
|
//MFA免验证发送天数
|
||||||
|
"UserMFAVerifyMinutes": 1440
|
||||||
|
},
|
||||||
|
// 邮件服务配置(用于系统通知、找回密码、错误报警等'
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
//企业邮箱sMTP服务器地址
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
//SMTP端口
|
||||||
|
"Port": 465,
|
||||||
|
"Imap": "imap.qiye.aliyun.com",
|
||||||
|
"ImapPort": 993,
|
||||||
|
// 发件人邮箱地址
|
||||||
|
"FromEmail": "test@extimaging.com",
|
||||||
|
// 发件人显示名称
|
||||||
|
"FromName": "Test IRC Imaging System",
|
||||||
|
//SMTP授权码
|
||||||
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
|
//系统对外访问地址
|
||||||
|
"SiteUrl": "http://irc.test.extimaging.com/login",
|
||||||
|
//系统简称-致性核查使用
|
||||||
|
"SystemShortName": "IRC",
|
||||||
|
// 组织英文名称-添加用户默认值
|
||||||
|
"OrganizationName": "ExtImaging",
|
||||||
|
// 组织中文名称
|
||||||
|
"OrganizationNameCN": "ExtImaging",
|
||||||
|
"PlatformName": "EICS",
|
||||||
|
"PlatformNameCN": "展影云平台",
|
||||||
|
//公司英文全称
|
||||||
|
"CompanyName": "Extensive Imaging",
|
||||||
|
// 公司中文全称,
|
||||||
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
|
//公司英文简称
|
||||||
|
"CompanyShortName": "Extensive Imaging",
|
||||||
|
//公司中文简称
|
||||||
|
"CompanyShortNameCN": "展影医疗",
|
||||||
|
// 是否为国际版环境 方便前端区分,用于区分1i1li还是irc 做一些事情"
|
||||||
|
"IsEnv_US": false,
|
||||||
|
// 邮箱格式校验正则表达式
|
||||||
|
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
||||||
|
//后端周期性邮件默认语言
|
||||||
|
// "CronEmailDefaultCulture": "zh-CN"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getInfo()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSave() {
|
||||||
|
this.loading = true
|
||||||
|
Promise.all([this.updateSystemBasicConfig(), this.updateSystemEmailConfig()]).then(res => {
|
||||||
|
this.loading = false
|
||||||
|
this.getInfo()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getInfo() {
|
||||||
|
this.loading = true
|
||||||
|
Promise.all([this.getSystemBasicConfigInfo(), this.getEmailConfigInfo()]).then(res => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async updateSystemBasicConfig() {
|
||||||
|
try {
|
||||||
|
let validate = await this.$refs.systemConfigForm.validate()
|
||||||
|
if (!validate) return false
|
||||||
|
let data = {}
|
||||||
|
Object.keys(this.form.BasicSystemConfig).forEach(key => {
|
||||||
|
data[key] = this.form.BasicSystemConfig[key]
|
||||||
|
})
|
||||||
|
let res = await updateSystemBasicConfig(data)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async updateSystemEmailConfig() {
|
||||||
|
try {
|
||||||
|
let validate = await this.$refs.systemConfigForm.validate()
|
||||||
|
if (!validate) return false
|
||||||
|
let data = {}
|
||||||
|
Object.keys(this.form.SystemEmailSendConfig).forEach(key => {
|
||||||
|
data[key] = this.form.SystemEmailSendConfig[key]
|
||||||
|
})
|
||||||
|
let res = await updateSystemEmailConfig(data)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getSystemBasicConfigInfo() {
|
||||||
|
try {
|
||||||
|
let res = await getSystemBasicConfigInfo()
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
Object.keys(this.form.BasicSystemConfig).forEach(key => {
|
||||||
|
this.form.BasicSystemConfig[key] = res.Result[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.loading = false
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getEmailConfigInfo() {
|
||||||
|
try {
|
||||||
|
let res = await getEmailConfigInfo()
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
Object.keys(this.form.SystemEmailSendConfig).forEach(key => {
|
||||||
|
this.form.SystemEmailSendConfig[key] = res.Result[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.loading = false
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.systemConfig {
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,42 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form
|
<el-form ref="userForm" size="small" :model="user" :rules="userFormRules" label-width="150px" style="width: 800px">
|
||||||
ref="userForm"
|
|
||||||
size="small"
|
|
||||||
:model="user"
|
|
||||||
:rules="userFormRules"
|
|
||||||
label-width="150px"
|
|
||||||
style="width: 800px"
|
|
||||||
>
|
|
||||||
<el-card class="Basic" shadow="never" size="small">
|
<el-card class="Basic" shadow="never" size="small">
|
||||||
<div slot="header" class="clearfix">
|
<div slot="header" class="clearfix">
|
||||||
<span>{{ $t('system:userlist:title:Information') }}</span>
|
<span>{{ $t('system:userlist:title:Information') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form-item
|
<el-form-item v-if="user.UserCode" :label="$t('system:userlist:table:S/N')" prop="UserCode">
|
||||||
v-if="user.UserCode"
|
|
||||||
:label="$t('system:userlist:table:S/N')"
|
|
||||||
prop="UserCode"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.UserCode" disabled />
|
<el-input v-model="user.UserCode" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:UserName')" class="my_new_pwd" prop="UserName">
|
||||||
:label="$t('system:userlist:table:UserName')"
|
|
||||||
class="my_new_pwd"
|
|
||||||
prop="UserName"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.UserName" />
|
<el-input v-model="user.UserName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:LastName')" prop="LastName">
|
||||||
:label="$t('system:userlist:table:LastName')"
|
|
||||||
prop="LastName"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.LastName" />
|
<el-input v-model="user.LastName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:FirstName')" prop="FirstName">
|
||||||
:label="$t('system:userlist:table:FirstName')"
|
|
||||||
prop="FirstName"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.FirstName" />
|
<el-input v-model="user.FirstName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- <el-form-item :label="$t('system:userlist:table:Gender')" prop="Sex" style="margin-right:40px;">
|
<!-- <el-form-item :label="$t('system:userlist:table:Gender')" prop="Sex" style="margin-right:40px;">
|
||||||
|
|
@ -51,105 +30,52 @@
|
||||||
<el-form-item :label="$t('system:userlist:table:Phone')" prop="Phone">
|
<el-form-item :label="$t('system:userlist:table:Phone')" prop="Phone">
|
||||||
<el-input v-model="user.Phone" />
|
<el-input v-model="user.Phone" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="type == 1" :label="$t('system:userlist:table:Disable')">
|
||||||
v-if="type == 1"
|
<el-switch v-model="user.Status" :active-value="1" :inactive-value="0" />
|
||||||
:label="$t('system:userlist:table:Disable')"
|
|
||||||
>
|
|
||||||
<el-switch
|
|
||||||
v-model="user.Status"
|
|
||||||
:active-value="1"
|
|
||||||
:inactive-value="0"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('system:userlist:table:IsTestUser')">
|
<el-form-item :label="$t('system:userlist:table:IsTestUser')">
|
||||||
<el-radio-group v-model="user.IsTestUser">
|
<el-radio-group v-model="user.IsTestUser">
|
||||||
<el-radio
|
<el-radio v-for="item of $d.YesOrNo" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
|
||||||
v-for="item of $d.YesOrNo"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.value"
|
|
||||||
>{{ item.label }}</el-radio
|
|
||||||
>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:UserWorkLanguage')" prop="UserWorkLanguage">
|
||||||
:label="$t('system:userlist:table:UserType')"
|
<el-select v-model="user.UserWorkLanguage" style="width: 100%">
|
||||||
prop="Roles"
|
<el-option v-for="item of $d.UserWorkLanguage" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
v-if="type === 0"
|
</el-select>
|
||||||
>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('system:userlist:table:UserType')" prop="Roles" v-if="type === 0">
|
||||||
<div style="display: flex; align-items: center">
|
<div style="display: flex; align-items: center">
|
||||||
<el-select
|
<el-select ref="userType" v-model="user.Roles" size="small" placeholder="Please select" multiple
|
||||||
ref="userType"
|
style="width: 100%" :disabled="user.CanEditUserType === false || type === 1" @change="handleChange">
|
||||||
v-model="user.Roles"
|
|
||||||
size="small"
|
|
||||||
placeholder="Please select"
|
|
||||||
multiple
|
|
||||||
style="width: 100%"
|
|
||||||
:disabled="user.CanEditUserType === false || type === 1"
|
|
||||||
@change="handleChange"
|
|
||||||
>
|
|
||||||
<template v-for="userType of userTypeOptions">
|
<template v-for="userType of userTypeOptions">
|
||||||
<el-option
|
<el-option v-if="![4, 6, 20].includes(userType.UserTypeEnum)" :key="userType.Id"
|
||||||
v-if="![4, 6, 20].includes(userType.UserTypeEnum)"
|
:label="userType.UserType" :value="userType.Id" />
|
||||||
:key="userType.Id"
|
|
||||||
:label="userType.UserType"
|
|
||||||
:value="userType.Id"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:UserType')" prop="userTypeId" v-else>
|
||||||
:label="$t('system:userlist:table:UserType')"
|
|
||||||
prop="userTypeId"
|
|
||||||
v-else
|
|
||||||
>
|
|
||||||
<div style="display: flex; align-items: center">
|
<div style="display: flex; align-items: center">
|
||||||
<el-select
|
<el-select ref="userType" v-model="Roles" size="small" placeholder="Please select" multiple
|
||||||
ref="userType"
|
style="width: 100%" :disabled="user.CanEditUserType === false || type === 1" @change="handleChange">
|
||||||
v-model="Roles"
|
|
||||||
size="small"
|
|
||||||
placeholder="Please select"
|
|
||||||
multiple
|
|
||||||
style="width: 100%"
|
|
||||||
:disabled="user.CanEditUserType === false || type === 1"
|
|
||||||
@change="handleChange"
|
|
||||||
>
|
|
||||||
<template v-for="userType of userTypeOptions">
|
<template v-for="userType of userTypeOptions">
|
||||||
<el-option
|
<el-option v-if="![4, 6, 20].includes(userType.UserTypeEnum)" :key="userType.Id"
|
||||||
v-if="![4, 6, 20].includes(userType.UserTypeEnum)"
|
:label="userType.UserType" :value="userType.Id" />
|
||||||
:key="userType.Id"
|
|
||||||
:label="userType.UserType"
|
|
||||||
:value="userType.Id"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button
|
<el-button type="primary" size="small" style="margin-left: 5px" v-if="type === 1" @click.stop="openRoleList">
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
style="margin-left: 5px"
|
|
||||||
v-if="type === 1"
|
|
||||||
@click.stop="openRoleList"
|
|
||||||
>
|
|
||||||
{{ $t('system:userlist:button:roles') }}
|
{{ $t('system:userlist:button:roles') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card
|
<el-card class="Affiliation" shadow="never" style="margin-top: 10px" size="small">
|
||||||
class="Affiliation"
|
|
||||||
shadow="never"
|
|
||||||
style="margin-top: 10px"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<div slot="header" class="clearfix">
|
<div slot="header" class="clearfix">
|
||||||
<span>{{ $t('system:userlist:title:Affiliation') }}</span>
|
<span>{{ $t('system:userlist:title:Affiliation') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form-item prop="IsZhiZhun">
|
<el-form-item prop="IsZhiZhun">
|
||||||
<el-radio-group
|
<el-radio-group v-model="user.IsZhiZhun" @change="OrgnizationTypeChanged">
|
||||||
v-model="user.IsZhiZhun"
|
|
||||||
@change="OrgnizationTypeChanged"
|
|
||||||
>
|
|
||||||
<el-radio :label="true">{{
|
<el-radio :label="true">{{
|
||||||
$t('system:userlist:title:Internal')
|
$t('system:userlist:title:Internal')
|
||||||
}}</el-radio>
|
}}</el-radio>
|
||||||
|
|
@ -158,43 +84,22 @@
|
||||||
}}</el-radio>
|
}}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-show="user.IsZhiZhun === false" :label="$t('system:userlist:table:OrganizationName')">
|
||||||
v-show="user.IsZhiZhun === false"
|
|
||||||
:label="$t('system:userlist:table:OrganizationName')"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.OrganizationName" />
|
<el-input v-model="user.OrganizationName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:Department')" prop="DepartmentName">
|
||||||
:label="$t('system:userlist:table:Department')"
|
|
||||||
prop="DepartmentName"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.DepartmentName" />
|
<el-input v-model="user.DepartmentName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item :label="$t('system:userlist:table:Position')" prop="PositionName">
|
||||||
:label="$t('system:userlist:table:Position')"
|
|
||||||
prop="PositionName"
|
|
||||||
>
|
|
||||||
<el-input v-model="user.PositionName" />
|
<el-input v-model="user.PositionName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button
|
<el-button type="primary" size="small" :disabled="isDisabled" style="margin: 10px 15px" @click="handleSave">{{
|
||||||
type="primary"
|
$t('common:button:save') }}</el-button>
|
||||||
size="small"
|
|
||||||
:disabled="isDisabled"
|
|
||||||
style="margin: 10px 15px"
|
|
||||||
@click="handleSave"
|
|
||||||
>{{ $t('common:button:save') }}</el-button
|
|
||||||
>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<roleList
|
<roleList v-if="visible" :visible.sync="visible" :userId="userId" :list="userRoleList"
|
||||||
v-if="visible"
|
:userTypeOptions="userTypeOptions" @getRoleList="getRoleList" />
|
||||||
:visible.sync="visible"
|
|
||||||
:userId="userId"
|
|
||||||
:list="userRoleList"
|
|
||||||
:userTypeOptions="userTypeOptions"
|
|
||||||
@getRoleList="getRoleList"
|
|
||||||
/>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -365,11 +270,11 @@ export default {
|
||||||
callback(
|
callback(
|
||||||
lang === 'zh'
|
lang === 'zh'
|
||||||
? new Error(
|
? new Error(
|
||||||
'1)新建账号,用户名字符长度最小为4个字符,最大为16个字符,只可使用字母、数字、下划线;'
|
'新建账号,用户名字符长度最小为4个字符,最大为16个字符,只可使用字母、数字、下划线;'
|
||||||
)
|
)
|
||||||
: new Error(
|
: 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.'
|
'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.'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback()
|
||||||
|
|
@ -379,6 +284,7 @@ export default {
|
||||||
userRoleList: [],
|
userRoleList: [],
|
||||||
Roles: [],
|
Roles: [],
|
||||||
user: {
|
user: {
|
||||||
|
UserWorkLanguage: null,
|
||||||
Roles: [],
|
Roles: [],
|
||||||
UserRoleList: [],
|
UserRoleList: [],
|
||||||
UserName: '',
|
UserName: '',
|
||||||
|
|
@ -399,6 +305,13 @@ export default {
|
||||||
UserName: [
|
UserName: [
|
||||||
{ required: true, validator: validatePassword, trigger: 'blur' },
|
{ required: true, validator: validatePassword, trigger: 'blur' },
|
||||||
],
|
],
|
||||||
|
UserWorkLanguage: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please Select',
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
],
|
||||||
Roles: [
|
Roles: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,42 @@
|
||||||
<template>
|
<template>
|
||||||
<box-content>
|
<box-content>
|
||||||
<div class="search" style="position: relative">
|
<div class="search" style="position: relative">
|
||||||
<SearchForm
|
<SearchForm :that="this" :search-data="searchData" :search-form="searchForm" :search-handle="searchHandle"
|
||||||
:that="this"
|
@search="handleSearch" @reset="handleReset" @new="handleAddUser" />
|
||||||
:search-data="searchData"
|
|
||||||
:search-form="searchForm"
|
|
||||||
:search-handle="searchHandle"
|
|
||||||
@search="handleSearch"
|
|
||||||
@reset="handleReset"
|
|
||||||
@new="handleAddUser"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<base-table
|
<base-table v-loading="loading" :columns="columns" :list="users" :search-data="searchData" :total="total"
|
||||||
v-loading="loading"
|
@getList="getList" @editCb="handleEditUser" @sendCb="addNewUserSendEmail" @deleteCb="handleDeleteUser"
|
||||||
:columns="columns"
|
@sortByColumn="sortByColumn">
|
||||||
:list="users"
|
|
||||||
:search-data="searchData"
|
|
||||||
:total="total"
|
|
||||||
@getList="getList"
|
|
||||||
@editCb="handleEditUser"
|
|
||||||
@sendCb="addNewUserSendEmail"
|
|
||||||
@deleteCb="handleDeleteUser"
|
|
||||||
@sortByColumn="sortByColumn"
|
|
||||||
>
|
|
||||||
<!-- 选择自定义slot -->
|
<!-- 选择自定义slot -->
|
||||||
<template slot="tip-slot" slot-scope="{ scope }">
|
<template slot="tip-slot" slot-scope="{ scope }">
|
||||||
<i
|
<i v-if="
|
||||||
v-if="
|
diffTime(scope.row.LastLoginTime) >= 90 &&
|
||||||
diffTime(scope.row.LastLoginTime) >= 90 &&
|
diffTime(scope.row.LastChangePassWordTime) >= 90
|
||||||
diffTime(scope.row.LastChangePassWordTime) >= 90
|
" class="el-icon-warning" style="color: #f56c6c"
|
||||||
"
|
:title="$t('system:userlist:tip:overTimeAndoverTimePassWord')" />
|
||||||
class="el-icon-warning"
|
<i v-else-if="diffTime(scope.row.LastLoginTime) >= 90" class="el-icon-warning" style="color: #f56c6c"
|
||||||
style="color: #f56c6c"
|
:title="$t('system:userlist:tip:overTime')" />
|
||||||
:title="$t('system:userlist:tip:overTimeAndoverTimePassWord')"
|
<i v-else-if="diffTime(scope.row.LastChangePassWordTime) >= 90" class="el-icon-warning" style="color: #f56c6c"
|
||||||
/>
|
:title="$t('system:userlist:tip:overTimePassWord')" />
|
||||||
<i
|
|
||||||
v-else-if="diffTime(scope.row.LastLoginTime) >= 90"
|
|
||||||
class="el-icon-warning"
|
|
||||||
style="color: #f56c6c"
|
|
||||||
:title="$t('system:userlist:tip:overTime')"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else-if="diffTime(scope.row.LastChangePassWordTime) >= 90"
|
|
||||||
class="el-icon-warning"
|
|
||||||
style="color: #f56c6c"
|
|
||||||
:title="$t('system:userlist:tip:overTimePassWord')"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template slot="genderSlot" slot-scope="{ scope }">
|
<template slot="genderSlot" slot-scope="{ scope }">
|
||||||
{{ scope.row.Sex ? 'Male' : 'Female' }}
|
{{ scope.row.Sex ? 'Male' : 'Female' }}
|
||||||
</template>
|
</template>
|
||||||
|
<template slot="UserWorkLanguageSlot" slot-scope="{ scope }">
|
||||||
|
{{ $fd('UserWorkLanguage', scope.row.UserWorkLanguage) }}
|
||||||
|
</template>
|
||||||
<template slot="UserTypeSlot" slot-scope="{ scope }">
|
<template slot="UserTypeSlot" slot-scope="{ scope }">
|
||||||
{{
|
{{
|
||||||
Array.isArray(scope.row.UserRoleList) &&
|
Array.isArray(scope.row.UserRoleList) &&
|
||||||
scope.row.UserRoleList.length > 0
|
scope.row.UserRoleList.length > 0
|
||||||
? scope.row.UserRoleList.filter((item) => !item.IsUserRoleDisabled)
|
? scope.row.UserRoleList.filter((item) => !item.IsUserRoleDisabled)
|
||||||
.map((item) => item.UserTypeShortName)
|
.map((item) => item.UserTypeShortName)
|
||||||
.join(', ')
|
.join(', ')
|
||||||
: ''
|
: ''
|
||||||
}}
|
}}
|
||||||
</template>
|
</template>
|
||||||
<template slot="roleSlot" slot-scope="{ scope }">
|
<template slot="roleSlot" slot-scope="{ scope }">
|
||||||
{{ scope.row.RoleNameList.map((role) => role.RoleName).join(', ') }}
|
{{scope.row.RoleNameList.map((role) => role.RoleName).join(', ')}}
|
||||||
</template>
|
</template>
|
||||||
<template slot="isZhiZhunSlot" slot-scope="{ scope }">
|
<template slot="isZhiZhunSlot" slot-scope="{ scope }">
|
||||||
{{
|
{{
|
||||||
|
|
@ -155,6 +130,14 @@ export default {
|
||||||
sortable: 'custom',
|
sortable: 'custom',
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// prop: 'UserWorkLanguage',
|
||||||
|
label: this.$t('system:userlist:table:UserWorkLanguage'),
|
||||||
|
minWidth: 120,
|
||||||
|
slot: 'UserWorkLanguageSlot',
|
||||||
|
sortable: 'custom',
|
||||||
|
showOverflowTooltip: true,
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// prop: 'Sex',
|
// prop: 'Sex',
|
||||||
// label: this.$t('system:userlist:table:Gender'),
|
// label: this.$t('system:userlist:table:Gender'),
|
||||||
|
|
@ -287,6 +270,15 @@ export default {
|
||||||
width: '120px',
|
width: '120px',
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'Select',
|
||||||
|
label: this.$t('system:userlist:label:UserWorkLanguage'),
|
||||||
|
prop: 'UserWorkLanguage',
|
||||||
|
width: '100px',
|
||||||
|
options: [], // 下拉选项
|
||||||
|
props: { label: 'label', value: 'value' }, // 下拉选项配置信息,必填
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'Input',
|
type: 'Input',
|
||||||
label: this.$t('system:userlist:label:Phone'),
|
label: this.$t('system:userlist:label:Phone'),
|
||||||
|
|
@ -476,8 +468,10 @@ export default {
|
||||||
// 获取用户类型下拉选项信息
|
// 获取用户类型下拉选项信息
|
||||||
async getInfo() {
|
async getInfo() {
|
||||||
const res = await getUserTypeList()
|
const res = await getUserTypeList()
|
||||||
const index = this.findItemIndex('UserType')
|
let index = this.findItemIndex('UserType')
|
||||||
this.$set(this.searchForm[index], 'options', res.Result)
|
this.$set(this.searchForm[index], 'options', res.Result)
|
||||||
|
index = this.findItemIndex('UserWorkLanguage')
|
||||||
|
this.$set(this.searchForm[index], 'options', this.$d.UserWorkLanguage)
|
||||||
},
|
},
|
||||||
handleAddUser() {
|
handleAddUser() {
|
||||||
this.$router.push({ path: '/system/user/add' })
|
this.$router.push({ path: '/system/user/add' })
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,145 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- <label>行数: </label>
|
<el-input v-model="input" placeholder="" clearable></el-input>
|
||||||
<input v-model.number="rows" type="number" min="1" max="3" />
|
<el-input v-model="pageIndex" placeholder="" clearable></el-input>
|
||||||
<label>列数: </label>
|
<el-input v-model="pageSize" placeholder="" clearable></el-input>
|
||||||
<input v-model.number="cols" type="number" min="1" max="3" /> -->
|
<el-button type="primary" size="small" :disabled="!input" @click.stop="getTrialUnreadVisitList">下载</el-button>
|
||||||
<GridLayout :rows="rows" :cols="cols" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import GridLayout from './GridLayout.vue';
|
import { downLoadFile } from '@/utils/stream.js'
|
||||||
|
import { getTrialUnreadVisitList, getExportSubjectVisitImageList } from '@/api/trials'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
// components: {
|
||||||
GridLayout,
|
// GridLayout,
|
||||||
},
|
// },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
rows: 2,
|
input: '08deab4a-f842-a7a4-0242-0a0001000000',
|
||||||
cols: 2,
|
pageIndex: 1,
|
||||||
|
pageSize: 250
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
async getTrialUnreadVisitList() {
|
||||||
|
let params = {
|
||||||
|
TrialId: this.input,
|
||||||
|
PageIndex: this.pageIndex,
|
||||||
|
PageSize: this.pageSize,
|
||||||
|
}
|
||||||
|
let res = await getTrialUnreadVisitList(params)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
let arr = res.Result
|
||||||
|
this.LoopDownload(arr, 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async LoopDownload(arr, index) {
|
||||||
|
if (index >= arr.length) return false
|
||||||
|
let res = await this.handleExportImage(false, true, arr[index])
|
||||||
|
console.log(res, arr[index], 'res')
|
||||||
|
index++
|
||||||
|
this.LoopDownload(arr, index)
|
||||||
|
},
|
||||||
|
async handleExportImage(IsKeyImage = false, IsExportReading = false, SubjectVisitId) {
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
TrialId: this.input,
|
||||||
|
IsKeyImage,
|
||||||
|
IsExportReading
|
||||||
|
}
|
||||||
|
data.SubjectVisitIdList = [SubjectVisitId]
|
||||||
|
// if (!IsKeyImage) {
|
||||||
|
// let confirm = await this.$confirm(this.$t('trials:imageSummary:confirm:space').replace('xxx', this.image_size.CheckImageSize))
|
||||||
|
// if (!confirm) return false
|
||||||
|
// }
|
||||||
|
let res = await getExportSubjectVisitImageList(data)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
return this.downLoad(IsKeyImage, res.Result, IsExportReading)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} catch (err) {
|
||||||
|
return false
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 下载
|
||||||
|
async downLoad(IsKeyImage = false, row, IsExportReading = false) {
|
||||||
|
try {
|
||||||
|
let { files, name } = this.formatDownloadFile(IsKeyImage, row, IsExportReading)
|
||||||
|
return await downLoadFile(files, name, 'zip')
|
||||||
|
// }
|
||||||
|
} catch (err) {
|
||||||
|
return false
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 格式化下载文件路径
|
||||||
|
formatDownloadFile(IsKeyImage = false, row, IsExportReading = false) {
|
||||||
|
let files = [],
|
||||||
|
name = `${this.$route.query.researchProgramNo}_${this.$t('trials:imageSummary:downloadname:dicom')}_${Date.now()}.zip`;
|
||||||
|
if (IsExportReading) {
|
||||||
|
name = `${row.VisitList[0].SubjectCode}_${row.VisitList[0].VisitName}.zip`;
|
||||||
|
}
|
||||||
|
if (!IsKeyImage) {
|
||||||
|
//中心ID/受试者ID/访视名/Study ID_Study Date_Modality/文件
|
||||||
|
row.VisitList.forEach(visit => {
|
||||||
|
if (visit.StudyList && visit.StudyList.length > 0) {
|
||||||
|
visit.StudyList.forEach(study => {
|
||||||
|
let arr = []
|
||||||
|
study.SeriesList.forEach(item => {
|
||||||
|
if (!arr.includes(item.Modality)) {
|
||||||
|
arr.push(item.Modality)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let str = arr.join('_')
|
||||||
|
let time = study.StudyTime.split(' ')[0]
|
||||||
|
if (study.StudyDIRPath && !study.dirHas) {
|
||||||
|
study.dirHas = true
|
||||||
|
let obj = {
|
||||||
|
name: `${study.StudyCode}_${time}_${str}/DICOMDIR`,
|
||||||
|
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
|
||||||
|
}
|
||||||
|
files.push(obj)
|
||||||
|
}
|
||||||
|
if (study.SeriesList && study.SeriesList.length > 0) {
|
||||||
|
study.SeriesList.forEach(serie => {
|
||||||
|
|
||||||
|
if (serie.InstanceList && serie.InstanceList.length > 0) {
|
||||||
|
serie.InstanceList.forEach(instance => {
|
||||||
|
let instanceArr = instance.Path.split("/")
|
||||||
|
let fileName = instance.FileName || instanceArr[instanceArr.length - 1]
|
||||||
|
let obj = {
|
||||||
|
name: `${study.StudyCode}_${time}_${str}/IMAGE/${fileName}`,
|
||||||
|
url: this.OSSclientConfig.basePath + instance.Path,
|
||||||
|
IsEncapsulated: instance.IsEncapsulated
|
||||||
|
}
|
||||||
|
files.push(obj)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (visit.NoneDicomStudyList && visit.NoneDicomStudyList.length > 0) {
|
||||||
|
visit.NoneDicomStudyList.forEach(noneDicomStudy => {
|
||||||
|
if (noneDicomStudy.FileList && noneDicomStudy.FileList.length > 0) {
|
||||||
|
noneDicomStudy.FileList.forEach(file => {
|
||||||
|
let time = noneDicomStudy.ImageDate.split(' ')[0]
|
||||||
|
let obj = {
|
||||||
|
name: `${noneDicomStudy.StudyCode}_${time}_${noneDicomStudy.Modality}/${file.FileName}`,
|
||||||
|
url: this.OSSclientConfig.basePath + file.Path,
|
||||||
|
}
|
||||||
|
files.push(obj)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { files, name }
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -5,77 +5,42 @@
|
||||||
<!-- 用户基本信息 -->
|
<!-- 用户基本信息 -->
|
||||||
{{ $t("trials:trials-myinfo:title:basicInfo") }}
|
{{ $t("trials:trials-myinfo:title:basicInfo") }}
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form ref="userForm" label-position="right" :model="user" :rules="userFormRules" label-width="120px">
|
||||||
ref="userForm"
|
|
||||||
label-position="right"
|
|
||||||
:model="user"
|
|
||||||
:rules="userFormRules"
|
|
||||||
label-width="120px"
|
|
||||||
>
|
|
||||||
<el-form-item v-if="user.Code" label="ID: " prop="Code">
|
<el-form-item v-if="user.Code" label="ID: " prop="Code">
|
||||||
<el-input v-model="user.Code" disabled />
|
<el-input v-model="user.Code" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 姓 -->
|
<!-- 姓 -->
|
||||||
<el-form-item
|
<el-form-item :disabled="user.UserTypeEnum === 8" :label="$t('trials:trials-myinfo:form:surname')"
|
||||||
:disabled="user.UserTypeEnum === 8"
|
prop="LastName">
|
||||||
:label="$t('trials:trials-myinfo:form:surname')"
|
<el-input v-model="user.LastName" :placeholder="$t('trials:trials-myinfo:form:surname')" />
|
||||||
prop="LastName"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="user.LastName"
|
|
||||||
:placeholder="$t('trials:trials-myinfo:form:surname')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 名 -->
|
<!-- 名 -->
|
||||||
<el-form-item
|
<el-form-item :disabled="user.UserTypeEnum === 8" :label="$t('trials:trials-myinfo:form:givenname')"
|
||||||
:disabled="user.UserTypeEnum === 8"
|
prop="FirstName">
|
||||||
:label="$t('trials:trials-myinfo:form:givenname')"
|
<el-input v-model="user.FirstName" :placeholder="$t('trials:trials-myinfo:form:givenname')" />
|
||||||
prop="FirstName"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="user.FirstName"
|
|
||||||
:placeholder="$t('trials:trials-myinfo:form:givenname')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 单位 -->
|
<!-- 单位 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:trials-myinfo:form:organization')" prop="OrganizationName">
|
||||||
:label="$t('trials:trials-myinfo:form:organization')"
|
<el-input :disabled="user.IsZhiZhun" v-model="user.OrganizationName"
|
||||||
prop="OrganizationName"
|
:placeholder="$t('trials:trials-myinfo:form:organization')" />
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
:disabled="user.IsZhiZhun"
|
|
||||||
v-model="user.OrganizationName"
|
|
||||||
:placeholder="$t('trials:trials-myinfo:form:organization')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 部门 -->
|
<!-- 部门 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:trials-myinfo:form:department')" prop="DepartmentName">
|
||||||
:label="$t('trials:trials-myinfo:form:department')"
|
<el-input v-model="user.DepartmentName" :placeholder="$t('trials:trials-myinfo:form:organization')" />
|
||||||
prop="DepartmentName"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="user.DepartmentName"
|
|
||||||
:placeholder="$t('trials:trials-myinfo:form:organization')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 职位 -->
|
<!-- 职位 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:trials-myinfo:form:position')" prop="PositionName">
|
||||||
:label="$t('trials:trials-myinfo:form:position')"
|
<el-input v-model="user.PositionName" :placeholder="$t('trials:trials-myinfo:form:position')" />
|
||||||
prop="PositionName"
|
</el-form-item>
|
||||||
>
|
<!-- 工作语言 -->
|
||||||
<el-input
|
<el-form-item :label="$t('trials:trials-myinfo:form:UserWorkLanguage')" prop="UserWorkLanguage">
|
||||||
v-model="user.PositionName"
|
<el-select v-model="user.UserWorkLanguage" style="width: 100%">
|
||||||
:placeholder="$t('trials:trials-myinfo:form:position')"
|
<el-option v-for="item of $d.UserWorkLanguage" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
/>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<!-- 保存 -->
|
<!-- 保存 -->
|
||||||
<el-button
|
<el-button class="trial-info-btn" type="primary" size="small" @click="handleSave">
|
||||||
class="trial-info-btn"
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
@click="handleSave"
|
|
||||||
>
|
|
||||||
{{ $t("trials:trials-myinfo:button:save") }}
|
{{ $t("trials:trials-myinfo:button:save") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -102,6 +67,13 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userFormRules: {
|
userFormRules: {
|
||||||
|
UserWorkLanguage: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t("common:ruleMessage:select"),
|
||||||
|
trigger: ["blur", "change"],
|
||||||
|
},
|
||||||
|
],
|
||||||
UserName: [
|
UserName: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
|
|
||||||
|
|
@ -27,23 +27,110 @@
|
||||||
<span v-html="$t('trials:researchForm:form:isFollowStudyParam')"></span>
|
<span v-html="$t('trials:researchForm:form:isFollowStudyParam')"></span>
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="form.IsRoutineMRIPDEE">
|
||||||
|
<span v-html="$t('trials:researchForm:form:IsRoutineMRIPDEE')"></span>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="form.IsMRIPDFF" @change="(val) => handleChange(val, 'IsMRIPDFF')">
|
||||||
|
<span v-html="$t('trials:researchForm:form:IsMRIPDFF')"></span>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="form.IsAuthorize" @change="(val) => handleChange(val, 'IsAuthorize')">
|
||||||
|
<span v-html="$t('trials:researchForm:form:IsAuthorize')"></span>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="form.ISStrictManualBurnFlag"
|
||||||
|
@change="(val) => handleChange(val, 'ISStrictManualBurnFlag')">
|
||||||
|
<span v-html="$t('trials:researchForm:form:ISStrictManualBurnFlag')"></span>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div style="margin-bottom: 20px;font-weight: bold;">
|
<div style="margin-bottom: 20px;font-weight: bold;">
|
||||||
{{ $t("trials:researchRecord:ImageManual:TableConfiguration") }}
|
{{ $t("trials:researchRecord:ImageManual:TableConfiguration") }}
|
||||||
</div>
|
</div>
|
||||||
<el-form size="small" :model="form" style="width:80%">
|
<el-form size="small" :model="form" style="width:80%">
|
||||||
<el-form-item :label="$t('trials:researchRecord:ImageManual:Equipment')">
|
<el-form-item :label="$t('trials:researchRecord:ImageManual:Equipment')">
|
||||||
<el-radio-group v-model="form.IsCloseEquipmentSurvey">
|
<el-radio-group v-model="form.IsCloseEquipmentSurvey" @input="handleInput">
|
||||||
<el-radio :label="item.value" v-for="item in $d.YesOrNo" :key="item.id">{{ item.label
|
<el-radio :label="item.value" v-for="item in $d.YesOrNo" :key="item.id">{{ item.label
|
||||||
}}</el-radio>
|
}}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
<div style="margin-bottom: 20px;font-weight: bold;">
|
||||||
|
{{ $t("trials:researchRecord:ImageManual:EquipmentConfig") }}
|
||||||
|
</div>
|
||||||
|
<el-form size="small" :model="EquipmentForm" style="width:80%" v-if="form.IsCloseEquipmentSurvey">
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.EquipmentTypeEnum">
|
||||||
|
{{ $t('trials:researchForm:form:EquipmentTypeEnum') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.Parameters">
|
||||||
|
{{ $t('trials:researchForm:form:Parameters') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.ManufacturerType">
|
||||||
|
{{ $t('trials:researchForm:form:ManufacturerType') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.ScannerType">
|
||||||
|
{{ $t('trials:researchForm:form:ScannerType') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.MagneticFieldStrengthType">
|
||||||
|
{{ $t('trials:researchForm:form:MagneticFieldStrengthType') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.BodyCoilChannelCount">
|
||||||
|
{{ $t('trials:researchForm:form:BodyCoilChannelCount') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.HasDedicatedPdfFatQuantificationSequence"
|
||||||
|
@change="EquipmentForm.PdfFatQuantificationSequenceType = false">
|
||||||
|
{{ $t('trials:researchForm:form:HasDedicatedPdfFatQuantificationSequence') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="EquipmentForm.HasDedicatedPdfFatQuantificationSequence">
|
||||||
|
<el-checkbox v-model="EquipmentForm.PdfFatQuantificationSequenceType">
|
||||||
|
{{ $t('trials:researchForm:form:PdfFatQuantificationSequenceType') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.HasT2R2Correction">
|
||||||
|
{{ $t('trials:researchForm:form:HasT2R2Correction') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.CanFullyExportPdfParameterMapsAndRawDicom">
|
||||||
|
{{ $t('trials:researchForm:form:CanFullyExportPdfParameterMapsAndRawDicom') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="EquipmentForm.Note">
|
||||||
|
{{ $t('trials:researchForm:form:Note') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
<div style="margin-bottom: 20px;font-weight: bold;">
|
<div style="margin-bottom: 20px;font-weight: bold;">
|
||||||
{{ $t("trials:researchRecord:ImageManual:Precautions") }}
|
{{ $t("trials:researchRecord:ImageManual:Precautions") }}
|
||||||
</div>
|
</div>
|
||||||
<el-input type="textarea" :autosize="{ minRows: 4, maxRows: 99 }" placeholder=""
|
<el-input type="textarea" :autosize="{ minRows: 4, maxRows: 99 }" placeholder=""
|
||||||
v-model="form.ReplaceContent" @input="handleInput" style="width: 70%;" />
|
v-model="form.ReplaceContentCN" style="width: 70%;" />
|
||||||
|
<div style="margin: 20px 0;font-weight: bold;">
|
||||||
|
{{ $t("trials:researchRecord:ImageManual:PrecautionsUS") }}
|
||||||
|
</div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4, maxRows: 99 }" placeholder=""
|
||||||
|
v-model="form.ReplaceContent" style="width: 70%;" />
|
||||||
<div style="text-align: right;margin: 20px;" class="btnBox">
|
<div style="text-align: right;margin: 20px;" class="btnBox">
|
||||||
<el-button type="primary" :loading="loading" size="small" @click="handleSave">
|
<el-button type="primary" :loading="loading" size="small" @click="handleSave">
|
||||||
{{ $t('common:button:save') }}
|
{{ $t('common:button:save') }}
|
||||||
|
|
@ -80,7 +167,30 @@ export default {
|
||||||
ReplaceContentCN: '',
|
ReplaceContentCN: '',
|
||||||
IsOpenLostVistRead: false,
|
IsOpenLostVistRead: false,
|
||||||
IsSupportQCDownloadImage: false,
|
IsSupportQCDownloadImage: false,
|
||||||
IsCloseEquipmentSurvey: true
|
IsCloseEquipmentSurvey: true,
|
||||||
|
IsRoutineMRIPDEE: false,
|
||||||
|
IsMRIPDFF: false,
|
||||||
|
MRIPDFFScanTime: false,
|
||||||
|
MRIPDFFLeadTime: false,
|
||||||
|
MRIPDFFOther: false,
|
||||||
|
IsAuthorize: false,
|
||||||
|
IsAuthorizeRadiologistsParticipate: false,
|
||||||
|
AssignFixedTechnologists: false,
|
||||||
|
ISStrictManualBurnFlag: false,
|
||||||
|
NotStrictManualBurnFlagReason: false
|
||||||
|
},
|
||||||
|
EquipmentForm: {
|
||||||
|
Parameters: false,
|
||||||
|
Note: false,
|
||||||
|
EquipmentTypeEnum: false,
|
||||||
|
ManufacturerType: false,
|
||||||
|
ScannerType: false,
|
||||||
|
MagneticFieldStrengthType: false,
|
||||||
|
BodyCoilChannelCount: false,
|
||||||
|
HasDedicatedPdfFatQuantificationSequence: false,
|
||||||
|
PdfFatQuantificationSequenceType: false,
|
||||||
|
HasT2R2Correction: false,
|
||||||
|
CanFullyExportPdfParameterMapsAndRawDicom: false,
|
||||||
},
|
},
|
||||||
obj: {
|
obj: {
|
||||||
AverageEngravingCycle: false,
|
AverageEngravingCycle: false,
|
||||||
|
|
@ -89,6 +199,14 @@ export default {
|
||||||
EfficacyEvaluatorType: false,
|
EfficacyEvaluatorType: false,
|
||||||
IsFollowStudyParameters: false,
|
IsFollowStudyParameters: false,
|
||||||
NotFollowReson: false,
|
NotFollowReson: false,
|
||||||
|
IsRoutineMRIPDEE: false,
|
||||||
|
MRIPDFFScanTime: false,
|
||||||
|
MRIPDFFLeadTime: false,
|
||||||
|
MRIPDFFOther: false,
|
||||||
|
IsAuthorizeRadiologistsParticipate: false,
|
||||||
|
AssignFixedTechnologists: false,
|
||||||
|
ISStrictManualBurnFlag: false,
|
||||||
|
NotStrictManualBurnFlagReason: false,
|
||||||
},
|
},
|
||||||
loading: false
|
loading: false
|
||||||
}
|
}
|
||||||
|
|
@ -100,9 +218,21 @@ export default {
|
||||||
handleChange(val, key) {
|
handleChange(val, key) {
|
||||||
if (key === 'IsConfirmImagingTechnologist') this.form.NotConfirmReson = val
|
if (key === 'IsConfirmImagingTechnologist') this.form.NotConfirmReson = val
|
||||||
if (key === 'IsFollowStudyParameters') this.form.NotFollowReson = val
|
if (key === 'IsFollowStudyParameters') this.form.NotFollowReson = val
|
||||||
|
if (key === 'IsMRIPDFF') {
|
||||||
|
this.form.MRIPDFFScanTime = val
|
||||||
|
this.form.MRIPDFFLeadTime = val
|
||||||
|
this.form.MRIPDFFOther = val
|
||||||
|
}
|
||||||
|
if (key === 'IsAuthorize') {
|
||||||
|
this.form.IsAuthorizeRadiologistsParticipate = val
|
||||||
|
this.form.AssignFixedTechnologists = val
|
||||||
|
}
|
||||||
|
if (key === 'ISStrictManualBurnFlag') this.form.NotStrictManualBurnFlagReason = val
|
||||||
},
|
},
|
||||||
handleInput(val) {
|
handleInput(val) {
|
||||||
this.form.ReplaceContentCN = val
|
Object.keys(this.EquipmentForm).forEach(key => {
|
||||||
|
this.EquipmentForm[key] = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async getInfo() {
|
async getInfo() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -115,12 +245,22 @@ export default {
|
||||||
this.form[key] = true
|
this.form[key] = true
|
||||||
if (key === 'ReplaceContent' || key === 'ReplaceContentCN') this.form[key] = ''
|
if (key === 'ReplaceContent' || key === 'ReplaceContentCN') this.form[key] = ''
|
||||||
})
|
})
|
||||||
|
Object.keys(this.EquipmentForm).forEach(key => {
|
||||||
|
this.EquipmentForm[key] = false
|
||||||
|
})
|
||||||
|
res.Result.EquipmentControlFieldList.forEach(item => {
|
||||||
|
if (this.EquipmentForm.hasOwnProperty(item.FiledName)) {
|
||||||
|
this.EquipmentForm[item.FiledName] = true
|
||||||
|
}
|
||||||
|
})
|
||||||
this.form.IsOpenLostVistRead = res.Result.IsOpenLostVistRead
|
this.form.IsOpenLostVistRead = res.Result.IsOpenLostVistRead
|
||||||
this.form.IsSupportQCDownloadImage = res.Result.IsSupportQCDownloadImage
|
this.form.IsSupportQCDownloadImage = res.Result.IsSupportQCDownloadImage
|
||||||
this.form.IsCloseEquipmentSurvey = !res.Result.IsCloseEquipmentSurvey
|
this.form.IsCloseEquipmentSurvey = !res.Result.IsCloseEquipmentSurvey
|
||||||
if (Array.isArray(res.Result.NotShowFieldList) && res.Result.NotShowFieldList.length > 0) {
|
if (Array.isArray(res.Result.NotShowFieldList) && res.Result.NotShowFieldList.length > 0) {
|
||||||
res.Result.NotShowFieldList.forEach(key => {
|
res.Result.NotShowFieldList.forEach(key => {
|
||||||
this.form[key] = false
|
this.form[key] = false
|
||||||
|
if (['MRIPDFFScanTime', 'MRIPDFFLeadTime', 'MRIPDFFOther'].includes(key)) this.form.IsMRIPDFF = false
|
||||||
|
if (['IsAuthorizeRadiologistsParticipate', 'AssignFixedTechnologists'].includes(key)) this.form.IsAuthorize = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (Array.isArray(res.Result.ModifyFiledList) && res.Result.ModifyFiledList.length > 0) {
|
if (Array.isArray(res.Result.ModifyFiledList) && res.Result.ModifyFiledList.length > 0) {
|
||||||
|
|
@ -128,8 +268,15 @@ export default {
|
||||||
this.form.ReplaceContentCN = res.Result.ModifyFiledList[0].ReplaceContentCN.split('<p>').join('').split('</p>').filter(item => isNaN(item)).join("\n")
|
this.form.ReplaceContentCN = res.Result.ModifyFiledList[0].ReplaceContentCN.split('<p>').join('').split('</p>').filter(item => isNaN(item)).join("\n")
|
||||||
} else {
|
} else {
|
||||||
let arr = [this.$t('trials:equiptResearch:form:item1'), this.$t('trials:equiptResearch:form:item2'), this.$t('trials:equiptResearch:form:item3'), this.$t('trials:equiptResearch:form:item4')]
|
let arr = [this.$t('trials:equiptResearch:form:item1'), this.$t('trials:equiptResearch:form:item2'), this.$t('trials:equiptResearch:form:item3'), this.$t('trials:equiptResearch:form:item4')]
|
||||||
this.form.ReplaceContent = arr.join("\n")
|
let arr2 = [this.$t('trials:equiptResearch:form:item5'), this.$t('trials:equiptResearch:form:item6'), this.$t('trials:equiptResearch:form:item7'), this.$t('trials:equiptResearch:form:item8')]
|
||||||
this.form.ReplaceContentCN = arr.join("\n")
|
if (this.$i18n.locale !== 'zh') {
|
||||||
|
this.form.ReplaceContentCN = arr2.join("\n")
|
||||||
|
this.form.ReplaceContent = arr.join("\n")
|
||||||
|
} else {
|
||||||
|
this.form.ReplaceContentCN = arr.join("\n")
|
||||||
|
this.form.ReplaceContent = arr2.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -168,7 +315,8 @@ export default {
|
||||||
IsSupportQCDownloadImage: this.form.IsSupportQCDownloadImage,
|
IsSupportQCDownloadImage: this.form.IsSupportQCDownloadImage,
|
||||||
IsCloseEquipmentSurvey: !this.form.IsCloseEquipmentSurvey,
|
IsCloseEquipmentSurvey: !this.form.IsCloseEquipmentSurvey,
|
||||||
ModifyFiledList: [],
|
ModifyFiledList: [],
|
||||||
NotShowFieldList: []
|
NotShowFieldList: [],
|
||||||
|
EquipmentControlFieldList: []
|
||||||
}
|
}
|
||||||
Object.keys(this.obj).forEach(key => {
|
Object.keys(this.obj).forEach(key => {
|
||||||
if (!this.form[key]) data.NotShowFieldList.push(key)
|
if (!this.form[key]) data.NotShowFieldList.push(key)
|
||||||
|
|
@ -187,6 +335,16 @@ export default {
|
||||||
ReplaceContentCN: ReplaceContentCN,
|
ReplaceContentCN: ReplaceContentCN,
|
||||||
}
|
}
|
||||||
data.ModifyFiledList.push(obj)
|
data.ModifyFiledList.push(obj)
|
||||||
|
Object.keys(this.EquipmentForm).forEach((key, index) => {
|
||||||
|
if (this.EquipmentForm[key]) {
|
||||||
|
let obj = {
|
||||||
|
FiledName: key,
|
||||||
|
IsView: true,
|
||||||
|
ShowOrder: index,
|
||||||
|
}
|
||||||
|
data.EquipmentControlFieldList.push(obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
this.loading = true
|
this.loading = true
|
||||||
let res = await updateTrialExtralConfig(param, data)
|
let res = await updateTrialExtralConfig(param, data)
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ import BidirectionalTool from '@/views/trials/trials-panel/reading/dicoms/tools/
|
||||||
import ArrowAnnotateTool from '@/views/trials/trials-panel/reading/dicoms/tools/ArrowAnnotate/ArrowAnnotateTool'
|
import ArrowAnnotateTool from '@/views/trials/trials-panel/reading/dicoms/tools/ArrowAnnotate/ArrowAnnotateTool'
|
||||||
import RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/RectangleRoiTool'
|
import RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/RectangleRoi/RectangleRoiTool'
|
||||||
import ProbeTool from '@/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool'
|
import ProbeTool from '@/views/trials/trials-panel/reading/dicoms/tools/Probe/ProbeTool'
|
||||||
|
import FixedCircleRoiTool from '@/views/trials/trials-panel/reading/dicoms/tools/FixedCircleRoi/FixedCircleRoiTool'
|
||||||
// import OrientationMarkersTool from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/OrientationMarkersTool'
|
// import OrientationMarkersTool from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/OrientationMarkersTool'
|
||||||
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
|
import ScaleOverlayTool from '@/views/trials/trials-panel/reading/dicoms/tools/ScaleOverlay/ScaleOverlayTool'
|
||||||
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
||||||
|
|
@ -260,7 +261,7 @@ export default {
|
||||||
series: '',
|
series: '',
|
||||||
ToolStateManager: null,
|
ToolStateManager: null,
|
||||||
renderedMeasured: [],
|
renderedMeasured: [],
|
||||||
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe'],
|
measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate', 'RectangleRoi', 'Probe', 'FixedCircleRoi'],
|
||||||
measureData: [],
|
measureData: [],
|
||||||
selectedLesion: null,
|
selectedLesion: null,
|
||||||
activeTool: 0, // 0:enable 1:passive 2:active
|
activeTool: 0, // 0:enable 1:passive 2:active
|
||||||
|
|
@ -584,6 +585,13 @@ export default {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
|
} else if (this.CriterionType === 22 && this.activeToolName === 'Probe' && this.readingTaskState < 2) {
|
||||||
|
if (!(e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME1' || e.detail.image.imageFrame.photometricInterpretation === 'MONOCHROME2')) {
|
||||||
|
this.$alert(this.$t('trials:MRIPDFF:message:message5'))
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pointNearTool(e) {
|
pointNearTool(e) {
|
||||||
|
|
@ -593,7 +601,9 @@ export default {
|
||||||
var toolType = this.measuredTools[m]
|
var toolType = this.measuredTools[m]
|
||||||
const toolState = ToolStateManager.getImageIdToolState(image.imageId, toolType)
|
const toolState = ToolStateManager.getImageIdToolState(image.imageId, toolType)
|
||||||
if (toolState) {
|
if (toolState) {
|
||||||
var toolObj = new cornerstoneTools[`${toolType}Tool`]()
|
const toolClass = this.getToolClassByType(toolType)
|
||||||
|
if (!toolClass) continue
|
||||||
|
var toolObj = new toolClass()
|
||||||
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||||
if (i > -1 && this.disabledMarks.length > 0 && this.disabledMarks.indexOf(toolState.data[i].remark) > -1) {
|
if (i > -1 && this.disabledMarks.length > 0 && this.disabledMarks.indexOf(toolState.data[i].remark) > -1) {
|
||||||
return true
|
return true
|
||||||
|
|
@ -783,7 +793,9 @@ export default {
|
||||||
var toolType = this.measuredTools[m]
|
var toolType = this.measuredTools[m]
|
||||||
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
||||||
if (toolState) {
|
if (toolState) {
|
||||||
var toolObj = new cornerstoneTools[`${toolType}Tool`]()
|
const toolClass = this.getToolClassByType(toolType)
|
||||||
|
if (!toolClass) continue
|
||||||
|
var toolObj = new toolClass()
|
||||||
|
|
||||||
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
|
|
@ -1019,7 +1031,9 @@ export default {
|
||||||
var toolType = this.measuredTools[t]
|
var toolType = this.measuredTools[t]
|
||||||
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
const toolState = ToolStateManager.getImageIdToolState(e.detail.image.imageId, toolType)
|
||||||
if (!toolState) continue
|
if (!toolState) continue
|
||||||
var toolObj = new cornerstoneTools[`${toolType}Tool`]()
|
const toolClass = this.getToolClassByType(toolType)
|
||||||
|
if (!toolClass) continue
|
||||||
|
var toolObj = new toolClass()
|
||||||
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
var i = toolState.data.findIndex(data => toolObj.pointNearTool(element, data, currentPoints.canvas, 'mouse'))
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
var idx = this.measureData.findIndex(item => item.MeasureData && item.MeasureData.data && item.MeasureData.data.uuid === toolState.data[i].uuid)
|
var idx = this.measureData.findIndex(item => item.MeasureData && item.MeasureData.data && item.MeasureData.data.uuid === toolState.data[i].uuid)
|
||||||
|
|
@ -1046,7 +1060,7 @@ export default {
|
||||||
measureData.wc = Math.round(viewport.voi.windowCenter)
|
measureData.wc = Math.round(viewport.voi.windowCenter)
|
||||||
measureData.data.active = false
|
measureData.data.active = false
|
||||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||||
if (criterionType === 21) {
|
if (criterionType === 21 || criterionType === 22) {
|
||||||
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
||||||
}
|
}
|
||||||
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
||||||
|
|
@ -1057,6 +1071,15 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getToolClassByType(toolType) {
|
||||||
|
if (toolType === 'Length') return LengthTool
|
||||||
|
if (toolType === 'Bidirectional') return BidirectionalTool
|
||||||
|
if (toolType === 'ArrowAnnotate') return ArrowAnnotateTool
|
||||||
|
if (toolType === 'RectangleRoi') return RectangleRoiTool
|
||||||
|
if (toolType === 'Probe') return ProbeTool
|
||||||
|
if (toolType === 'FixedCircleRoi') return FixedCircleRoiTool
|
||||||
|
return cornerstoneTools[`${toolType}Tool`]
|
||||||
|
},
|
||||||
loadImageStack(dicomSeries) {
|
loadImageStack(dicomSeries) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.isInitWwwc = true
|
this.isInitWwwc = true
|
||||||
|
|
@ -1169,8 +1192,22 @@ export default {
|
||||||
// Add the tool
|
// Add the tool
|
||||||
const toolName = toolBtn.getAttribute('data-tool')
|
const toolName = toolBtn.getAttribute('data-tool')
|
||||||
const apiTool = cornerstoneTools[`${toolName}Tool`]
|
const apiTool = cornerstoneTools[`${toolName}Tool`]
|
||||||
if (apiTool) {
|
let toolClass = apiTool
|
||||||
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, apiTool)
|
if (toolName === 'Length') {
|
||||||
|
toolClass = LengthTool
|
||||||
|
} else if (toolName === 'Bidirectional') {
|
||||||
|
toolClass = BidirectionalTool
|
||||||
|
} else if (toolName === 'ArrowAnnotate') {
|
||||||
|
toolClass = ArrowAnnotateTool
|
||||||
|
} else if (toolName === 'RectangleRoi') {
|
||||||
|
toolClass = RectangleRoiTool
|
||||||
|
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) {
|
||||||
|
toolClass = ProbeTool
|
||||||
|
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 22)) {
|
||||||
|
toolClass = FixedCircleRoiTool
|
||||||
|
}
|
||||||
|
if (toolClass) {
|
||||||
|
const toolAlreadyAddedToElement = cornerstoneTools.getToolForElement(element, toolClass)
|
||||||
|
|
||||||
if (!toolAlreadyAddedToElement) {
|
if (!toolAlreadyAddedToElement) {
|
||||||
if (toolName === 'Length') {
|
if (toolName === 'Length') {
|
||||||
|
|
@ -1183,8 +1220,10 @@ export default {
|
||||||
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
||||||
} else if (toolName === 'RectangleRoi') {
|
} else if (toolName === 'RectangleRoi') {
|
||||||
cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
||||||
} else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 21) {
|
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) {
|
||||||
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
||||||
|
} else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 22) {
|
||||||
|
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 12, unit: 'mm', handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
||||||
} else {
|
} else {
|
||||||
cornerstoneTools.addToolForElement(element, apiTool)
|
cornerstoneTools.addToolForElement(element, apiTool)
|
||||||
}
|
}
|
||||||
|
|
@ -1528,7 +1567,7 @@ export default {
|
||||||
measureData.wc = Math.round(viewport.voi.windowCenter)
|
measureData.wc = Math.round(viewport.voi.windowCenter)
|
||||||
measureData.data.active = false
|
measureData.data.active = false
|
||||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||||
if (criterionType === 21) {
|
if (criterionType === 21 || criterionType === 22) {
|
||||||
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
measureData.tableQuestionId = this.measureData[idx].TableQuestionId
|
||||||
}
|
}
|
||||||
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
this.$emit('modifyMeasureData', { measureData, questionInfo })
|
||||||
|
|
@ -1982,7 +2021,8 @@ export default {
|
||||||
'CobbAngle',
|
'CobbAngle',
|
||||||
'Angle',
|
'Angle',
|
||||||
'Bidirectional',
|
'Bidirectional',
|
||||||
'FreehandRoi'
|
'FreehandRoi',
|
||||||
|
'FixedCircleRoi'
|
||||||
]
|
]
|
||||||
for (let i = 0; i < toolROITypes.length; i++) {
|
for (let i = 0; i < toolROITypes.length; i++) {
|
||||||
const toolROIType = toolROITypes[i]
|
const toolROIType = toolROITypes[i]
|
||||||
|
|
|
||||||
|
|
@ -492,6 +492,10 @@
|
||||||
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
||||||
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
||||||
@handleReadingChart="handleReadingChart" />
|
@handleReadingChart="handleReadingChart" />
|
||||||
|
<MRIPDFFAdvance v-else-if="CriterionType === 22" ref="measurementList"
|
||||||
|
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
||||||
|
:is-show="isShow" :is-reading-show-subject-info="isReadingShowSubjectInfo"
|
||||||
|
@handleReadingChart="handleReadingChart" />
|
||||||
<h2 v-else style="color:#ddd">
|
<h2 v-else style="color:#ddd">
|
||||||
Developing...
|
Developing...
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -689,6 +693,7 @@ import LuganoWithoutPETQuestionList from './LuganoWithoutPET/QuestionList'
|
||||||
import IVUSList from './IVUS/QuestionList'
|
import IVUSList from './IVUS/QuestionList'
|
||||||
import OCTList from './OCT/QuestionList'
|
import OCTList from './OCT/QuestionList'
|
||||||
import MRIPDFF from './MRIPDFF/QuestionList'
|
import MRIPDFF from './MRIPDFF/QuestionList'
|
||||||
|
import MRIPDFFAdvance from './MRIPDFFAdvance/QuestionList'
|
||||||
import CustomWwwcForm from './CustomWwwcForm'
|
import CustomWwwcForm from './CustomWwwcForm'
|
||||||
import Manuals from './Manuals'
|
import Manuals from './Manuals'
|
||||||
import Hotkeys from './Hotkeys'
|
import Hotkeys from './Hotkeys'
|
||||||
|
|
@ -725,6 +730,7 @@ export default {
|
||||||
IVUSList,
|
IVUSList,
|
||||||
OCTList,
|
OCTList,
|
||||||
MRIPDFF,
|
MRIPDFF,
|
||||||
|
MRIPDFFAdvance,
|
||||||
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
||||||
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
||||||
SignForm
|
SignForm
|
||||||
|
|
@ -1012,6 +1018,10 @@ export default {
|
||||||
this.measuredTools = [{
|
this.measuredTools = [{
|
||||||
toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: ''
|
toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: ''
|
||||||
}]
|
}]
|
||||||
|
} else if (this.CriterionType === 22) {
|
||||||
|
this.measuredTools = [{
|
||||||
|
toolName: 'Probe', text: this.$t('trials:reading:button:circle'), icon: 'oval', isDisabled: false, disabledReason: ''
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
this.rotateList[0] = '1'
|
this.rotateList[0] = '1'
|
||||||
this.colorList[0] = ''
|
this.colorList[0] = ''
|
||||||
|
|
@ -1041,30 +1051,23 @@ export default {
|
||||||
console.log('getMeasureData')
|
console.log('getMeasureData')
|
||||||
})
|
})
|
||||||
DicomEvent.$on('getScreenshots', async (measuredData, callback) => {
|
DicomEvent.$on('getScreenshots', async (measuredData, callback) => {
|
||||||
if (this.currentDicomCanvasIndex > -1) {
|
if (this.currentDicomCanvasIndex <= -1 || typeof callback !== 'function') return
|
||||||
|
const shouldRelocate = this.shouldRelocateBeforeScreenshot(measuredData)
|
||||||
|
if (shouldRelocate) {
|
||||||
await this.imageLocation(measuredData)
|
await this.imageLocation(measuredData)
|
||||||
if (!measuredData.isMarked) {
|
|
||||||
callback()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setTimeout(async () => {
|
|
||||||
// var base64Str = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getScreenshots()
|
|
||||||
const divForDownloadViewport = document.querySelector(
|
|
||||||
`div[data-canvas-uid="dicomCanvas${this.currentDicomCanvasIndex}"]`
|
|
||||||
)
|
|
||||||
var canvas = await html2canvas(divForDownloadViewport)
|
|
||||||
var base64Str = canvas.toDataURL('image/png', 1)
|
|
||||||
console.log('getScreenshots')
|
|
||||||
callback(base64Str)
|
|
||||||
}, 50)
|
|
||||||
}
|
}
|
||||||
|
if (!measuredData || !measuredData.isMarked) {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const base64Str = await this.captureActiveViewportScreenshot()
|
||||||
|
callback(base64Str)
|
||||||
})
|
})
|
||||||
DicomEvent.$on('imageLocation', async (measuredData) => {
|
DicomEvent.$on('imageLocation', async (measuredData) => {
|
||||||
return new Promise(async resolve => {
|
return new Promise(async resolve => {
|
||||||
if (!measuredData) return
|
if (!measuredData) return
|
||||||
await this.imageLocation(measuredData)
|
|
||||||
|
|
||||||
console.log('imageLocation')
|
await this.imageLocation(measuredData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1126,7 +1129,12 @@ export default {
|
||||||
DicomEvent.$on('addAnnotation', async obj => {
|
DicomEvent.$on('addAnnotation', async obj => {
|
||||||
this.tmpData = Object.assign({}, obj.question)
|
this.tmpData = Object.assign({}, obj.question)
|
||||||
// await this.imageLocation(obj.locateInfo)
|
// await this.imageLocation(obj.locateInfo)
|
||||||
this.setToolActive('Probe', true, null, 'tableQuestion')
|
if (this.CriterionType === 21) {
|
||||||
|
this.setToolActive('Probe', true, null, 'tableQuestion')
|
||||||
|
} else if (this.CriterionType === 22) {
|
||||||
|
this.setToolActive('Probe', true, null, 'tableQuestion')
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
window.addEventListener('beforeunload', () => {
|
window.addEventListener('beforeunload', () => {
|
||||||
if (this.petctWindow) {
|
if (this.petctWindow) {
|
||||||
|
|
@ -1695,6 +1703,43 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
shouldRelocateBeforeScreenshot(measuredData) {
|
||||||
|
if (!measuredData) return false
|
||||||
|
const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0]
|
||||||
|
if (!currentCanvas || !currentCanvas.stack) return true
|
||||||
|
const currentStack = currentCanvas.stack
|
||||||
|
if (currentStack.visitTaskId !== measuredData.visitTaskId) return true
|
||||||
|
|
||||||
|
// 当前序列与病灶目标序列一致时,避免重复 imageLocation 引发的重载等待
|
||||||
|
const targetSeries = this.getSeriesInfoByMark(measuredData.visitTaskId, measuredData)
|
||||||
|
if (!targetSeries) return false
|
||||||
|
if (currentStack.seriesId !== targetSeries.seriesId) return true
|
||||||
|
if (typeof targetSeries.imageIdIndex === 'number' &&
|
||||||
|
targetSeries.imageIdIndex !== currentStack.currentImageIdIndex) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
async captureActiveViewportScreenshot() {
|
||||||
|
// const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0]
|
||||||
|
await this.$nextTick()
|
||||||
|
const divForDownloadViewport = document.querySelector(
|
||||||
|
`div[data-canvas-uid="dicomCanvas${this.currentDicomCanvasIndex}"]`
|
||||||
|
)
|
||||||
|
if (divForDownloadViewport) {
|
||||||
|
try {
|
||||||
|
const canvas = await html2canvas(divForDownloadViewport, {
|
||||||
|
logging: false,
|
||||||
|
useCORS: true,
|
||||||
|
scale: 1
|
||||||
|
})
|
||||||
|
return canvas.toDataURL('image/png')
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
setToolToTarget(obj) {
|
setToolToTarget(obj) {
|
||||||
if (obj.readingTaskState < 2 && obj.markTool && !obj.isMarked) {
|
if (obj.readingTaskState < 2 && obj.markTool && !obj.isMarked) {
|
||||||
if (this.activeTool) {
|
if (this.activeTool) {
|
||||||
|
|
@ -2160,7 +2205,7 @@ export default {
|
||||||
},
|
},
|
||||||
// 添加标记
|
// 添加标记
|
||||||
setMeasureData(data) {
|
setMeasureData(data) {
|
||||||
if (this.CriterionType === 21) {
|
if (this.CriterionType === 21 || this.CriterionType === 22) {
|
||||||
if (this.tmpData) {
|
if (this.tmpData) {
|
||||||
data.tableQuestionId = this.tmpData.Id
|
data.tableQuestionId = this.tmpData.Id
|
||||||
data.tableQuestionMark = this.tmpData.QuestionMark
|
data.tableQuestionMark = this.tmpData.QuestionMark
|
||||||
|
|
@ -2174,7 +2219,7 @@ export default {
|
||||||
},
|
},
|
||||||
// 修改标记
|
// 修改标记
|
||||||
modifyMeasureData(data) {
|
modifyMeasureData(data) {
|
||||||
if (this.CriterionType === 21 && data.measureData.tableQuestionId) {
|
if ((this.CriterionType === 21 || this.CriterionType === 22) && data.measureData.tableQuestionId) {
|
||||||
this.$refs['measurementList'].modifyMeasuredData(data)
|
this.$refs['measurementList'].modifyMeasuredData(data)
|
||||||
} else {
|
} else {
|
||||||
this.$refs['measurementList'].modifyMeasuredData(data)
|
this.$refs['measurementList'].modifyMeasuredData(data)
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="isFusion" class="item" effect="dark" :content="$t('trials:reading:button:crosshairsPosition')" placement="bottom">
|
||||||
|
<div class="tool-wrapper">
|
||||||
|
<div class="icon" :class="[activeTool === 'FusionJumpToPointTool' ? 'tool_active' : '']"
|
||||||
|
@click.prevent="setFusionJumpToolActive">
|
||||||
|
<svg-icon icon-class="position" class="svg-icon" />
|
||||||
|
</div>
|
||||||
|
<div class="text">{{ $t('trials:reading:button:crosshairsPosition') }}</div>
|
||||||
|
</div>
|
||||||
|
</el-tooltip>
|
||||||
<!-- 椭圆oval -->
|
<!-- 椭圆oval -->
|
||||||
<template v-for="tool in measuredTools">
|
<template v-for="tool in measuredTools">
|
||||||
<el-tooltip v-if="isCurrentTask && readingTaskState !== 2" :key="tool.toolName" class="item" effect="dark"
|
<el-tooltip v-if="isCurrentTask && readingTaskState !== 2" :key="tool.toolName" class="item" effect="dark"
|
||||||
|
|
@ -140,7 +149,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- 伪彩 -->
|
<!-- 伪彩 -->
|
||||||
<colorMap v-show="isFusion" ref="colorMap" :unit="fusionOverlayModality === 'NM' ? 'counts' : 'g/ml'"
|
<colorMap v-show="isFusion" ref="colorMap" :unit="fusionOverlayModality === 'NM' ? '' : 'g/ml'"
|
||||||
:modality="fusionOverlayModality" @setColorMap="setColorMap" @voiChange="voiChange" />
|
:modality="fusionOverlayModality" @setColorMap="setColorMap" @voiChange="voiChange" />
|
||||||
|
|
||||||
<!-- 截屏 -->
|
<!-- 截屏 -->
|
||||||
|
|
@ -294,6 +303,7 @@ const {
|
||||||
CrosshairsTool,
|
CrosshairsTool,
|
||||||
TrackballRotateTool,
|
TrackballRotateTool,
|
||||||
ProbeTool,
|
ProbeTool,
|
||||||
|
MIPJumpToClickTool,
|
||||||
ScaleOverlayTool,
|
ScaleOverlayTool,
|
||||||
utilities,
|
utilities,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
|
@ -431,7 +441,8 @@ export default {
|
||||||
lineWidth: 2,
|
lineWidth: 2,
|
||||||
lineLength: 20,
|
lineLength: 20,
|
||||||
centerHoleSize: 20,
|
centerHoleSize: 20,
|
||||||
}
|
},
|
||||||
|
fusionJumpEnabled: false
|
||||||
// initFirstAnnotation:false
|
// initFirstAnnotation:false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -458,9 +469,6 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
document.documentElement.style.userSelect = 'none'
|
document.documentElement.style.userSelect = 'none'
|
||||||
window.addEventListener('message', this.receiveMsg)
|
window.addEventListener('message', this.receiveMsg)
|
||||||
|
|
||||||
console.log(cornerstoneTools)
|
|
||||||
console.log(cornerstone3D)
|
|
||||||
this.$i18n.locale = this.$route.query.lang
|
this.$i18n.locale = this.$route.query.lang
|
||||||
this.setLanguage(this.$route.query.lang)
|
this.setLanguage(this.$route.query.lang)
|
||||||
this.readingTaskState = parseInt(this.$route.query.readingTaskState)
|
this.readingTaskState = parseInt(this.$route.query.readingTaskState)
|
||||||
|
|
@ -841,6 +849,9 @@ export default {
|
||||||
const { detail } = e
|
const { detail } = e
|
||||||
const { annotation } = detail
|
const { annotation } = detail
|
||||||
const { metadata } = annotation
|
const { metadata } = annotation
|
||||||
|
if (!metadata || metadata.toolName === FusionJumpToPointTool.toolName) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const measureData = {}
|
const measureData = {}
|
||||||
measureData.frame = 0
|
measureData.frame = 0
|
||||||
measureData.data = annotation
|
measureData.data = annotation
|
||||||
|
|
@ -858,6 +869,9 @@ export default {
|
||||||
const { detail } = e
|
const { detail } = e
|
||||||
const { annotation } = detail
|
const { annotation } = detail
|
||||||
const { metadata, data } = annotation
|
const { metadata, data } = annotation
|
||||||
|
if (!metadata || metadata.toolName === FusionJumpToPointTool.toolName) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// var i = this.initAnnotations.findIndex(i => i.orderMark === data.remark && !i.isInit)
|
// var i = this.initAnnotations.findIndex(i => i.orderMark === data.remark && !i.isInit)
|
||||||
// if (i > -1) {
|
// if (i > -1) {
|
||||||
// console.log(data.remark)
|
// console.log(data.remark)
|
||||||
|
|
@ -982,6 +996,7 @@ export default {
|
||||||
cornerstoneTools.addTool(ZoomTool)
|
cornerstoneTools.addTool(ZoomTool)
|
||||||
cornerstoneTools.addTool(StackScrollTool)
|
cornerstoneTools.addTool(StackScrollTool)
|
||||||
cornerstoneTools.addTool(FusionJumpToPointTool)
|
cornerstoneTools.addTool(FusionJumpToPointTool)
|
||||||
|
cornerstoneTools.addTool(MIPJumpToClickTool)
|
||||||
cornerstoneTools.addTool(VolumeRotateTool)
|
cornerstoneTools.addTool(VolumeRotateTool)
|
||||||
cornerstoneTools.addTool(EllipticalROITool)
|
cornerstoneTools.addTool(EllipticalROITool)
|
||||||
cornerstoneTools.addTool(CircleROITool)
|
cornerstoneTools.addTool(CircleROITool)
|
||||||
|
|
@ -1081,13 +1096,7 @@ export default {
|
||||||
true // overwrite
|
true // overwrite
|
||||||
)
|
)
|
||||||
toolGroup.setToolEnabled(ScaleOverlayTool.toolName)
|
toolGroup.setToolEnabled(ScaleOverlayTool.toolName)
|
||||||
toolGroup.setToolActive(FusionJumpToPointTool.toolName, {
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Primary // Left Click
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
// toolGroup.setToolConfiguration(OrientationMarkerTool.toolName, {
|
// toolGroup.setToolConfiguration(OrientationMarkerTool.toolName, {
|
||||||
// orientationWidget: {
|
// orientationWidget: {
|
||||||
// enabled: true,
|
// enabled: true,
|
||||||
|
|
@ -1139,23 +1148,29 @@ export default {
|
||||||
mipToolGroup.setToolActive(VolumeRotateTool.toolName, {
|
mipToolGroup.setToolActive(VolumeRotateTool.toolName, {
|
||||||
bindings: [{ mouseButton: MouseBindings.Wheel }],
|
bindings: [{ mouseButton: MouseBindings.Wheel }],
|
||||||
});
|
});
|
||||||
|
mipToolGroup.addTool(PanTool.toolName)
|
||||||
|
mipToolGroup.addTool(ZoomTool.toolName)
|
||||||
|
mipToolGroup.setToolActive(PanTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Auxiliary }]
|
||||||
|
})
|
||||||
|
mipToolGroup.setToolActive(ZoomTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Secondary }]
|
||||||
|
})
|
||||||
mipToolGroup.addTool(FusionJumpToPointTool.toolName, this.getFusionJumpToolConfiguration())
|
mipToolGroup.addTool(FusionJumpToPointTool.toolName, this.getFusionJumpToolConfiguration())
|
||||||
|
mipToolGroup.addTool(MIPJumpToClickTool.toolName, {
|
||||||
|
targetViewportIds: this.getFusionJumpToolConfiguration().targetViewportIds
|
||||||
|
})
|
||||||
|
|
||||||
// Set the initial state of the tools, here we set one tool active on left click.
|
// Set the initial state of the tools, here we set one tool active on left click.
|
||||||
// This means left click will draw that tool.
|
// This means left click will draw that tool.
|
||||||
mipToolGroup.setToolActive(FusionJumpToPointTool.toolName, {
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Primary // Left ClickR
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
// As the Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
|
// As the Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
|
||||||
// hook instead of mouse buttons, it does not need to assign any mouse button.
|
// hook instead of mouse buttons, it does not need to assign any mouse button.
|
||||||
// mipToolGroup.setToolActive('VolumeRotateMouseWheel')
|
// mipToolGroup.setToolActive('VolumeRotateMouseWheel')
|
||||||
// mipToolGroup.addTool(OrientationMarkerTool.toolName)
|
// mipToolGroup.addTool(OrientationMarkerTool.toolName)
|
||||||
// mipToolGroup.setToolActive(OrientationMarkerTool.toolName)
|
// mipToolGroup.setToolActive(OrientationMarkerTool.toolName)
|
||||||
mipToolGroup.addViewport(viewportIds.PETMIP.CORONAL, renderingEngineId)
|
mipToolGroup.addViewport(viewportIds.PETMIP.CORONAL, renderingEngineId)
|
||||||
|
this.setFusionMipClickEnabled(!this.fusionJumpEnabled && this.isFusion)
|
||||||
},
|
},
|
||||||
getFusionJumpToolConfiguration() {
|
getFusionJumpToolConfiguration() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -1188,6 +1203,7 @@ export default {
|
||||||
return colors[viewportId] || '#0000ff'
|
return colors[viewportId] || '#0000ff'
|
||||||
},
|
},
|
||||||
handleFusionSlicePointChange({ viewportId, worldPoint }) {
|
handleFusionSlicePointChange({ viewportId, worldPoint }) {
|
||||||
|
if (!this.fusionJumpEnabled) return
|
||||||
if (!this.isFusion) return
|
if (!this.isFusion) return
|
||||||
if (!viewportId || !Array.isArray(worldPoint) || worldPoint.length < 3) return
|
if (!viewportId || !Array.isArray(worldPoint) || worldPoint.length < 3) return
|
||||||
if (viewportId === viewportIds.PETMIP.CORONAL) return
|
if (viewportId === viewportIds.PETMIP.CORONAL) return
|
||||||
|
|
@ -1207,10 +1223,11 @@ export default {
|
||||||
let instance = null
|
let instance = null
|
||||||
for (const toolGroupId of toolGroupCandidates) {
|
for (const toolGroupId of toolGroupCandidates) {
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
instance = toolGroup?.getToolInstance(FusionJumpToPointTool.toolName)
|
if (!toolGroup || !toolGroup.getToolInstance) continue
|
||||||
if (instance?.setPoint) break
|
instance = toolGroup.getToolInstance(FusionJumpToPointTool.toolName)
|
||||||
|
if (instance && instance.setPoint) break
|
||||||
}
|
}
|
||||||
if (!instance?.setPoint) return
|
if (!instance || !instance.setPoint) return
|
||||||
|
|
||||||
instance.setPoint(worldPoint, viewportId, renderEngine.id, {
|
instance.setPoint(worldPoint, viewportId, renderEngine.id, {
|
||||||
jumpToTargetViewports: false,
|
jumpToTargetViewports: false,
|
||||||
|
|
@ -1218,16 +1235,18 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
dispatchFusionCenterPoint(retryCount = 0) {
|
dispatchFusionCenterPoint(retryCount = 0) {
|
||||||
|
if (!this.fusionJumpEnabled) return
|
||||||
const renderEngine = getRenderingEngine(renderingEngineId)
|
const renderEngine = getRenderingEngine(renderingEngineId)
|
||||||
if (!renderEngine) return
|
if (!renderEngine) return
|
||||||
const toolGroupCandidates = [fusionToolGroupId, mipToolGroupUID, ptToolGroupId, ctToolGroupId]
|
const toolGroupCandidates = [fusionToolGroupId, mipToolGroupUID, ptToolGroupId, ctToolGroupId]
|
||||||
let instance = null
|
let instance = null
|
||||||
for (const toolGroupId of toolGroupCandidates) {
|
for (const toolGroupId of toolGroupCandidates) {
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
instance = toolGroup?.getToolInstance?.(FusionJumpToPointTool.toolName)
|
if (!toolGroup || !toolGroup.getToolInstance) continue
|
||||||
if (instance?.setPoint) break
|
instance = toolGroup.getToolInstance(FusionJumpToPointTool.toolName)
|
||||||
|
if (instance && instance.setPoint) break
|
||||||
}
|
}
|
||||||
if (!instance?.setPoint) {
|
if (!instance || !instance.setPoint) {
|
||||||
if (retryCount < 10) {
|
if (retryCount < 10) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.dispatchFusionCenterPoint(retryCount + 1)
|
this.dispatchFusionCenterPoint(retryCount + 1)
|
||||||
|
|
@ -1240,14 +1259,17 @@ export default {
|
||||||
for (const viewportId of candidates) {
|
for (const viewportId of candidates) {
|
||||||
const viewport = renderEngine.getViewport(viewportId)
|
const viewport = renderEngine.getViewport(viewportId)
|
||||||
if (!viewport) continue
|
if (!viewport) continue
|
||||||
const width = viewport.element?.clientWidth
|
const width = viewport.element ? viewport.element.clientWidth : null
|
||||||
const height = viewport.element?.clientHeight
|
const height = viewport.element ? viewport.element.clientHeight : null
|
||||||
let worldPoint = null
|
let worldPoint = null
|
||||||
if (width && height && viewport.canvasToWorld) {
|
if (width && height && viewport.canvasToWorld) {
|
||||||
worldPoint = viewport.canvasToWorld([width / 2, height / 2])
|
worldPoint = viewport.canvasToWorld([width / 2, height / 2])
|
||||||
}
|
}
|
||||||
if ((!worldPoint || worldPoint.length < 3) && viewport.getCamera) {
|
if ((!worldPoint || worldPoint.length < 3) && viewport.getCamera) {
|
||||||
worldPoint = viewport.getCamera()?.focalPoint
|
const camera = viewport.getCamera()
|
||||||
|
if (camera && camera.focalPoint) {
|
||||||
|
worldPoint = camera.focalPoint
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!worldPoint || worldPoint.length < 3) continue
|
if (!worldPoint || worldPoint.length < 3) continue
|
||||||
instance.setPoint(worldPoint, viewportId, renderEngine.id, {
|
instance.setPoint(worldPoint, viewportId, renderEngine.id, {
|
||||||
|
|
@ -1262,6 +1284,80 @@ export default {
|
||||||
}, 120)
|
}, 120)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setFusionJumpToolActive() {
|
||||||
|
if (this.activeTool === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionJumpEnabled(false)
|
||||||
|
this.activeTool = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.activeTool) {
|
||||||
|
this.setToolMode('passive', this.activeTool)
|
||||||
|
}
|
||||||
|
this.setFusionJumpEnabled(true)
|
||||||
|
this.activeTool = FusionJumpToPointTool.toolName
|
||||||
|
},
|
||||||
|
setFusionMipClickEnabled(enabled) {
|
||||||
|
const toolGroup = ToolGroupManager.getToolGroup(mipToolGroupUID)
|
||||||
|
if (!toolGroup || !toolGroup.hasTool(MIPJumpToClickTool.toolName)) return
|
||||||
|
if (enabled && this.isFusion) {
|
||||||
|
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
toolGroup.setToolDisabled(MIPJumpToClickTool.toolName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setFusionJumpEnabled(enabled) {
|
||||||
|
this.fusionJumpEnabled = !!enabled
|
||||||
|
const toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId, mipToolGroupUID]
|
||||||
|
if (enabled) {
|
||||||
|
this.setFusionMipClickEnabled(false)
|
||||||
|
toolGroupIds.forEach((toolGroupId) => {
|
||||||
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
|
if (!toolGroup || !toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
|
||||||
|
toolGroup.setToolActive(FusionJumpToPointTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.dispatchFusionCenterPoint()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.setFusionMipClickEnabled(this.isFusion)
|
||||||
|
toolGroupIds.forEach((toolGroupId) => {
|
||||||
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
|
if (!toolGroup || !toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
|
||||||
|
toolGroup.setToolDisabled(FusionJumpToPointTool.toolName)
|
||||||
|
})
|
||||||
|
this.clearFusionJumpToPointAnnotations()
|
||||||
|
},
|
||||||
|
clearFusionJumpToPointAnnotations() {
|
||||||
|
const annotations = cornerstoneTools.annotation.state.getAllAnnotations() || []
|
||||||
|
const removeList = []
|
||||||
|
for (let i = 0; i < annotations.length; i++) {
|
||||||
|
const item = annotations[i]
|
||||||
|
if (!item || !item.metadata) continue
|
||||||
|
if (item.metadata.toolName !== FusionJumpToPointTool.toolName) continue
|
||||||
|
removeList.push(item)
|
||||||
|
}
|
||||||
|
if (!removeList.length) return
|
||||||
|
removeList.forEach(i => {
|
||||||
|
cornerstoneTools.annotation.state.removeAnnotation(i.annotationUID)
|
||||||
|
})
|
||||||
|
const renderEngine = getRenderingEngine(renderingEngineId)
|
||||||
|
if (!renderEngine) return
|
||||||
|
const viewportIdsToRender = [
|
||||||
|
viewportIds.CT.AXIAL,
|
||||||
|
viewportIds.PT.AXIAL,
|
||||||
|
viewportIds.FUSION.AXIAL,
|
||||||
|
viewportIds.PETMIP.CORONAL
|
||||||
|
]
|
||||||
|
viewportIdsToRender.forEach(viewportId => {
|
||||||
|
const viewport = renderEngine.getViewport(viewportId)
|
||||||
|
if (viewport && viewport.render) {
|
||||||
|
viewport.render()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
getTextLines(data, targetId) {
|
getTextLines(data, targetId) {
|
||||||
const cachedVolumeStats = data.cachedStats[targetId]
|
const cachedVolumeStats = data.cachedStats[targetId]
|
||||||
const {
|
const {
|
||||||
|
|
@ -1324,14 +1420,22 @@ export default {
|
||||||
},
|
},
|
||||||
// 设置测量工具启用(不会对输入作出反应)
|
// 设置测量工具启用(不会对输入作出反应)
|
||||||
setBasicToolActive(toolName) {
|
setBasicToolActive(toolName) {
|
||||||
var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId]
|
var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId, mipToolGroupUID]
|
||||||
|
if (toolName !== FusionJumpToPointTool.toolName && this.fusionJumpEnabled) {
|
||||||
|
this.setFusionJumpEnabled(false)
|
||||||
|
}
|
||||||
toolGroupIds.forEach((toolGroupId) => {
|
toolGroupIds.forEach((toolGroupId) => {
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
|
if (!toolGroup || !toolGroup.hasTool(toolName)) return
|
||||||
if (this.activeTool === toolName) {
|
if (this.activeTool === toolName) {
|
||||||
toolGroup.setToolPassive(toolName)
|
if (toolGroup.hasTool(toolName)) {
|
||||||
|
toolGroup.setToolPassive(toolName)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.activeTool) {
|
if (this.activeTool) {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
if (toolGroup.hasTool(this.activeTool)) {
|
||||||
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var bindings = []
|
var bindings = []
|
||||||
if (toolName === 'Pan') {
|
if (toolName === 'Pan') {
|
||||||
|
|
@ -1414,9 +1518,10 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setToolMode(mode, toolName) {
|
setToolMode(mode, toolName) {
|
||||||
var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId]
|
var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId, mipToolGroupUID]
|
||||||
toolGroupIds.forEach((toolGroupId) => {
|
toolGroupIds.forEach((toolGroupId) => {
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
|
if (!toolGroup || !toolGroup.hasTool(toolName)) return
|
||||||
toolGroup.setToolPassive(toolName)
|
toolGroup.setToolPassive(toolName)
|
||||||
if (mode === 'enabled') {
|
if (mode === 'enabled') {
|
||||||
toolGroup.setToolEnabled(toolName)
|
toolGroup.setToolEnabled(toolName)
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,13 @@ export default {
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getQuestionFormRef(refName) {
|
||||||
|
const ref = this.$refs[refName]
|
||||||
|
if (!ref) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return Array.isArray(ref) ? ref[0] : ref
|
||||||
|
},
|
||||||
handleReadingChart(e) {
|
handleReadingChart(e) {
|
||||||
this.$emit('handleReadingChart', e)
|
this.$emit('handleReadingChart', e)
|
||||||
},
|
},
|
||||||
|
|
@ -191,7 +198,8 @@ export default {
|
||||||
this.tableQuestions.forEach(item => {
|
this.tableQuestions.forEach(item => {
|
||||||
item.TableQuestions.Answers.forEach(i => {
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
var refName = `${item.Id}_${i.RowIndex}`
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
this.$refs[refName] && this.$refs[refName][0].initForm(isRerender)
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
questionFormRef && questionFormRef.initForm(isRerender)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -271,7 +279,8 @@ export default {
|
||||||
this.tableQuestions.forEach(item => {
|
this.tableQuestions.forEach(item => {
|
||||||
item.TableQuestions.Answers.forEach(i => {
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
var refName = `${item.Id}_${i.RowIndex}`
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
this.$refs[refName] && this.$refs[refName][0].initForm()
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
questionFormRef && questionFormRef.initForm()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -379,7 +388,8 @@ export default {
|
||||||
this.tableQuestions.forEach(item => {
|
this.tableQuestions.forEach(item => {
|
||||||
item.TableQuestions.Answers.forEach(i => {
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
var refName = `${item.Id}_${i.RowIndex}`
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
this.$refs[refName] && this.$refs[refName][0].initForm()
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
questionFormRef && questionFormRef.initForm()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -391,7 +401,8 @@ export default {
|
||||||
var rowIndex = String(this.unSaveTargets[0].rowIndex)
|
var rowIndex = String(this.unSaveTargets[0].rowIndex)
|
||||||
var questionId = this.unSaveTargets[0].questionId
|
var questionId = this.unSaveTargets[0].questionId
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
if (rowIndex === this.activeItem.activeRowIndex && questionId === this.activeItem.activeCollapseId && !this.$refs[refName][0].questionForm.OtherMeasureData) {
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
if (rowIndex === this.activeItem.activeRowIndex && questionId === this.activeItem.activeCollapseId && questionFormRef && !questionFormRef.questionForm.OtherMeasureData) {
|
||||||
if (toolName === 'CircleROI') {
|
if (toolName === 'CircleROI') {
|
||||||
return { isCanActiveTool: true, reason: '' }
|
return { isCanActiveTool: true, reason: '' }
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -522,7 +533,8 @@ export default {
|
||||||
if (item.TableQuestions && item.TableQuestions.Answers) {
|
if (item.TableQuestions && item.TableQuestions.Answers) {
|
||||||
item.TableQuestions.Answers.map(t => {
|
item.TableQuestions.Answers.map(t => {
|
||||||
const refName = `${item.Id}_${t.RowIndex}`
|
const refName = `${item.Id}_${t.RowIndex}`
|
||||||
if (this.$refs[refName] && this.$refs[refName][0] && this.$refs[refName][0].questionForm.saveTypeEnum !== 2) {
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
if (questionFormRef && questionFormRef.questionForm.saveTypeEnum !== 2) {
|
||||||
var lessionName = this.getLesionName(item.OrderMark, t.RowIndex)
|
var lessionName = this.getLesionName(item.OrderMark, t.RowIndex)
|
||||||
arr.push({ lessionName: lessionName, rowIndex: t.RowIndex, questionId: item.Id })
|
arr.push({ lessionName: lessionName, rowIndex: t.RowIndex, questionId: item.Id })
|
||||||
}
|
}
|
||||||
|
|
@ -552,11 +564,15 @@ export default {
|
||||||
this.activeItem.activeCollapseId = arr[0]
|
this.activeItem.activeCollapseId = arr[0]
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
if (this.$refs[refName][0].questionForm.IsDicomReading !== false) {
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
var markTool = 'CircleROI'
|
if (!questionFormRef) {
|
||||||
var isMarked = !!this.$refs[refName][0].questionForm.OtherMeasureData
|
return
|
||||||
}
|
}
|
||||||
FusionEvent.$emit('imageLocation', { otherMeasureData: this.$refs[refName][0].questionForm.OtherMeasureData, markTool, isMarked })
|
if (questionFormRef.questionForm.IsDicomReading !== false) {
|
||||||
|
var markTool = 'CircleROI'
|
||||||
|
var isMarked = !!questionFormRef.questionForm.OtherMeasureData
|
||||||
|
}
|
||||||
|
FusionEvent.$emit('imageLocation', { otherMeasureData: questionFormRef.questionForm.OtherMeasureData, markTool, isMarked })
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.activeItem.activeRowIndex = null
|
this.activeItem.activeRowIndex = null
|
||||||
|
|
@ -576,7 +592,10 @@ export default {
|
||||||
},
|
},
|
||||||
collapseRightClick(e, obj, activeCollapseId, activeRowIndex) {
|
collapseRightClick(e, obj, activeCollapseId, activeRowIndex) {
|
||||||
const refName = `${activeCollapseId}_${activeRowIndex}`
|
const refName = `${activeCollapseId}_${activeRowIndex}`
|
||||||
FusionEvent.$emit('imageLocation', { otherMeasureData: this.$refs[refName][0].questionForm.OtherMeasureData })
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
if (questionFormRef) {
|
||||||
|
FusionEvent.$emit('imageLocation', { otherMeasureData: questionFormRef.questionForm.OtherMeasureData })
|
||||||
|
}
|
||||||
|
|
||||||
e.stopImmediatePropagation()
|
e.stopImmediatePropagation()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
@ -621,8 +640,12 @@ export default {
|
||||||
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
if (!questionFormRef) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (deleteInfo) {
|
if (deleteInfo) {
|
||||||
this.$refs[refName][0].setDeleteInfo(deleteInfo)
|
questionFormRef.setDeleteInfo(deleteInfo)
|
||||||
}
|
}
|
||||||
if (questionsObj.otherMeasureData) {
|
if (questionsObj.otherMeasureData) {
|
||||||
const measureData = {}
|
const measureData = {}
|
||||||
|
|
@ -631,7 +654,7 @@ export default {
|
||||||
measureData.type = questionsObj.otherMeasureData.metadata.toolName
|
measureData.type = questionsObj.otherMeasureData.metadata.toolName
|
||||||
measureData.suvMax = questionsObj.suvMax
|
measureData.suvMax = questionsObj.suvMax
|
||||||
|
|
||||||
this.$refs[refName][0].setMeasureData(measureData)
|
questionFormRef.setMeasureData(measureData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -719,21 +742,28 @@ export default {
|
||||||
this.activeItem.activeRowIndex = String(measureObj.questionInfo.RowIndex)
|
this.activeItem.activeRowIndex = String(measureObj.questionInfo.RowIndex)
|
||||||
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
if (this.$refs[refName]) {
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
this.$refs[refName][0].setMeasureData(measureObj.measureData)
|
if (questionFormRef) {
|
||||||
|
questionFormRef.setMeasureData(measureObj.measureData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearMeasuredData() {
|
clearMeasuredData() {
|
||||||
if (this.activeItem.activeCollapseId && this.activeItem.activeRowIndex && this.activeName) {
|
if (this.activeItem.activeCollapseId && this.activeItem.activeRowIndex && this.activeName) {
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
this.$refs[refName][0].clearMeasurement()
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
if (questionFormRef) {
|
||||||
|
questionFormRef.clearMeasurement()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setOutsideMeasuredData(annotation) {
|
setOutsideMeasuredData(annotation) {
|
||||||
if (this.activeItem.activeCollapseId && this.activeItem.activeRowIndex && this.activeName) {
|
if (this.activeItem.activeCollapseId && this.activeItem.activeRowIndex && this.activeName) {
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
this.$refs[refName][0].setOutsideMeasuredData(annotation)
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
|
if (questionFormRef) {
|
||||||
|
questionFormRef.setOutsideMeasuredData(annotation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 设置测量数据
|
// 设置测量数据
|
||||||
|
|
@ -779,8 +809,22 @@ export default {
|
||||||
// 判断是否存在测量数据
|
// 判断是否存在测量数据
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
if (!this.$refs[refName][0].questionForm.OtherMeasureData) {
|
const questionFormRef = this.getQuestionFormRef(refName)
|
||||||
this.$refs[refName][0].setMeasureData(measureData)
|
if (!questionFormRef) {
|
||||||
|
if (this.isBaseLineTask) {
|
||||||
|
var idx = this.tableQuestions.findIndex(item => item.LesionType === 0)
|
||||||
|
if (this.tableQuestions[idx].TableQuestions.Answers.length < this.tableQuestions[idx].MaxQuestionCount && (measureData.type === 'CircleROI')) {
|
||||||
|
this.createTTarget(measureData)
|
||||||
|
} else {
|
||||||
|
this.createNTTarget(measureData)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.createNLTarget(measureData)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!questionFormRef.questionForm.OtherMeasureData) {
|
||||||
|
questionFormRef.setMeasureData(measureData)
|
||||||
} else {
|
} else {
|
||||||
if (this.isBaseLineTask) {
|
if (this.isBaseLineTask) {
|
||||||
var idx = this.tableQuestions.findIndex(item => item.LesionType === 0)
|
var idx = this.tableQuestions.findIndex(item => item.LesionType === 0)
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
{{ markers.left }}
|
{{ markers.left }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="presetName" class="color_bar">
|
<div v-if="presetName" class="color_bar">
|
||||||
<canvas id="colorBar_Canvas" />
|
<canvas ref="colorBarCanvas" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="index === 4" id="rotateBar" ref="rotateBar" class="rotate_slider_box" @click.stop="clickRotate($event)">
|
<div v-if="index === 4" id="rotateBar" ref="rotateBar" class="rotate_slider_box" @click.stop="clickRotate($event)">
|
||||||
<div id="rotateSlider" :style="{left: rotateBarLeft + 'px'}" class="box" @click.stop.prevent="() => {return}" @mousedown.stop="rotateBarMousedown($event)" />
|
<div id="rotateSlider" :style="{left: rotateBarLeft + 'px'}" class="box" @click.stop.prevent="() => {return}" @mousedown.stop="rotateBarMousedown($event)" />
|
||||||
|
|
@ -162,6 +162,10 @@ export default {
|
||||||
default() {
|
default() {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
rgbPresetName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -203,6 +207,16 @@ export default {
|
||||||
handler(v) {
|
handler(v) {
|
||||||
console.log('activeIndex ', v)
|
console.log('activeIndex ', v)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
rgbPresetName: {
|
||||||
|
immediate: true,
|
||||||
|
handler(v) {
|
||||||
|
this.presetName = v || ''
|
||||||
|
if (!this.presetName) return
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.renderColorBar(this.presetName)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -574,7 +588,8 @@ export default {
|
||||||
colorMap = getColormap(presetName)
|
colorMap = getColormap(presetName)
|
||||||
}
|
}
|
||||||
const rgbPoints = colorMap.RGBPoints
|
const rgbPoints = colorMap.RGBPoints
|
||||||
const canvas = document.getElementById('colorBar_Canvas')
|
const canvas = this.$refs.colorBarCanvas
|
||||||
|
if (!canvas) return
|
||||||
const ctx = canvas.getContext('2d')
|
const ctx = canvas.getContext('2d')
|
||||||
const canvasWidth = 160
|
const canvasWidth = 160
|
||||||
const canvasHeight = 5
|
const canvasHeight = 5
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-loading="loading">
|
<div v-loading="loading">
|
||||||
<div class="base-dialog-body" style="height:380px;overflow-y: auto;">
|
<div class="base-dialog-body" style="height:420px;overflow-y: auto;">
|
||||||
<div class="hot-keys-container">
|
<div class="hot-keys-container">
|
||||||
<div v-for="(item, index) in hotKeyList" :key="`${item.tag}_${index}`" class="wrapper">
|
<div v-for="(item, index) in hotKeyList" :key="`${item.tag}_${index}`" class="wrapper">
|
||||||
<template>
|
<template>
|
||||||
|
|
|
||||||
|
|
@ -832,7 +832,7 @@ export default {
|
||||||
|
|
||||||
::v-deep .el-button--mini,
|
::v-deep .el-button--mini,
|
||||||
.el-button--mini.is-round {
|
.el-button--mini.is-round {
|
||||||
padding: 7px 10px;
|
padding: 7px 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .el-input-group__append,
|
::v-deep .el-input-group__append,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,689 @@
|
||||||
|
<template>
|
||||||
|
<el-form v-if="isRender" ref="measurementForm" v-loading="loading" :model="questionForm" size="mini"
|
||||||
|
class="measurement-form">
|
||||||
|
<div class="base-dialog-body">
|
||||||
|
<div style="display: flex;justify-content: space-between;">
|
||||||
|
<h3 v-if="questionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
|
||||||
|
{{ lesionName }}
|
||||||
|
</h3>
|
||||||
|
<!-- 关闭 -->
|
||||||
|
<div>
|
||||||
|
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="handleClose" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item v-for="qs in questions" v-show="qs.ShowQuestion !== 2" :key="qs.Id" :label="`${qs.QuestionName}`"
|
||||||
|
:prop="qs.Id" :rules="[
|
||||||
|
{
|
||||||
|
required: (qs.IsRequired === 0 || (qs.IsRequired === 1 && qs.RelevanceId && (String(questionForm[qs.RelevanceId]) === qs.RelevanceValue)) || (qs.QuestionMark === 6 && questionForm.IsCanEditPosition === true) || (questionForm.IsCanEditPosition && qs.QuestionMark === 10)) && qs.Type !== 'group' && qs.Type !== 'summary',
|
||||||
|
message: ['radio', 'select', 'checkbox'].includes(qs.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||||
|
},
|
||||||
|
]" style="flex-wrap: wrap">
|
||||||
|
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<template
|
||||||
|
v-if="(qs.Type === 'input' || qs.Type === 'number') && (qs.QuestionMark === 1104)">
|
||||||
|
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;">
|
||||||
|
<el-input v-model="questionForm[qs.Id]" disabled style="width: 100px;">
|
||||||
|
<template v-if="qs.Unit" slot="append">
|
||||||
|
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<!-- 测量 -->
|
||||||
|
<el-button
|
||||||
|
v-if="questionForm[isMeasurableId] && parseInt(questionForm[isMeasurableId]) === 1 && !questionForm.MeasureData && readingTaskState !== 2"
|
||||||
|
size="mini" type="text" @click="addAnnotation(qs)">
|
||||||
|
{{ $t('trials:MRIPDFF:button:measure') }}
|
||||||
|
</el-button>
|
||||||
|
<!-- 清除标记 -->
|
||||||
|
<!-- <el-button v-if="getAnnotationStatus(qs) && readingTaskState !== 2" size="mini" type="text"
|
||||||
|
style="margin-left: 0px" @click="removeAnnotation(qs)">
|
||||||
|
{{ $t('trials:MRIPDFF:button:clear') }}
|
||||||
|
</el-button> -->
|
||||||
|
<el-button v-if="questionForm.MeasureData && readingTaskState !== 2" size="mini" type="text" @click="handleDeleteMeasureData">
|
||||||
|
{{ $t('trials:reading:button:removeMark') }}
|
||||||
|
</el-button>
|
||||||
|
<!-- 返回 -->
|
||||||
|
<!-- <el-button v-if="questionForm[qs.Id]" size="mini" type="text" style="margin-left: 0px"
|
||||||
|
@click="locateAnnotation(qs)">
|
||||||
|
{{ $t('trials:MRIPDFF:button:return') }}
|
||||||
|
</el-button> -->
|
||||||
|
<!-- 保存 -->
|
||||||
|
<!-- <el-button
|
||||||
|
v-if="questionForm[isMeasurableId] && parseInt(questionForm[isMeasurableId]) === 1 && questionForm[qs.Id] && readingTaskState !== 2"
|
||||||
|
size="mini" type="text" style="margin-left: 0px" @click="saveAnnotation(qs)">
|
||||||
|
<el-tooltip v-if="getAnnotationSaveEnum(qs) === 0" class="item" effect="dark"
|
||||||
|
:content="$t('trials:reading:button:unsaved')" placement="bottom">
|
||||||
|
<i class="el-icon-warning" style="color:red" />
|
||||||
|
</el-tooltip>
|
||||||
|
{{ $t('common:button:save') }}
|
||||||
|
</el-button> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="qs.Type === 'input' || qs.Type === 'number'">
|
||||||
|
<div style="display: flex;justify-content: space-between;">
|
||||||
|
<el-input v-model="questionForm[qs.Id]" :disabled="!isCurrentTask || readingTaskState >= 2"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="(qs.QuestionMark === 0 || qs.QuestionMark === 1) && qs.Unit" slot="append">
|
||||||
|
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<svg-icon v-if="qs.ShowChartTypeEnum > 0" icon-class="readingChart" class="svg-icon svg-readingChart"
|
||||||
|
@click.stop="(e) => handleReadingChart({
|
||||||
|
e,
|
||||||
|
data: {
|
||||||
|
TableQuestionId: qs.Id,
|
||||||
|
RowIndex: questionForm.RowIndex,
|
||||||
|
QuestionName: qs.QuestionName
|
||||||
|
}
|
||||||
|
})" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 多行文本输入框 -->
|
||||||
|
<el-input v-else-if="qs.Type === 'textarea'" v-model="questionForm[qs.Id]" type="textarea"
|
||||||
|
:autosize="{ minRows: 2, maxRows: 4 }" :disabled="!isCurrentTask || readingTaskState >= 2"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })" />
|
||||||
|
<!-- 下拉框 -->
|
||||||
|
|
||||||
|
<el-select v-else-if="qs.Type === 'select'" v-model="questionForm[qs.Id]" filterable
|
||||||
|
:placeholder="$t('common:placeholder:select')"
|
||||||
|
:disabled="!isCurrentTask || readingTaskState >= 2 || qs.QuestionMark === 1106"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="qs.TableQuestionType === 1">
|
||||||
|
<el-option v-for="item in organList" :key="item.Id" :label="item[qs.DataTableColumn]"
|
||||||
|
:value="item[qs.DataTableColumn]" />
|
||||||
|
</template>
|
||||||
|
<template v-else-if="qs.DictionaryCode">
|
||||||
|
<el-option v-for="item of $d[qs.DictionaryCode]" :key="item.id" :value="item.value" :label="item.label" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-option v-for="val in qs.TypeValue.split('|')" :key="val" :label="val" :value="val" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</el-select>
|
||||||
|
<!-- 单选 -->
|
||||||
|
<el-radio-group v-else-if="qs.Type === 'radio'" v-model="questionForm[qs.Id]"
|
||||||
|
:disabled="!isCurrentTask || readingTaskState >= 2 || (qs.QuestionMark === 1105 && isDisabledMeasurableRadio)"
|
||||||
|
@change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="qs.DictionaryCode.length > 0">
|
||||||
|
<el-radio v-for="item in $d[qs.DictionaryCode]" :key="item.id" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="qs.options.length > 0">
|
||||||
|
<el-radio v-for="val in qs.options.split('|')" :key="val" :label="val">
|
||||||
|
{{ val }}
|
||||||
|
</el-radio>
|
||||||
|
</template>
|
||||||
|
</el-radio-group>
|
||||||
|
<div style="display: flex;justify-content: space-between;" v-else-if="qs.Type === 'calculation'">
|
||||||
|
<!-- 自动计算 -->
|
||||||
|
<el-input v-model="questionForm[qs.Id]" disabled @change="((val) => { formItemChange(val, qs) })">
|
||||||
|
<template v-if="qs.Unit" slot="append">
|
||||||
|
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<svg-icon v-if="qs.ShowChartTypeEnum > 0" icon-class="readingChart" class="svg-icon svg-readingChart"
|
||||||
|
@click.stop="(e) => handleReadingChart({
|
||||||
|
e,
|
||||||
|
data: {
|
||||||
|
TableQuestionId: qs.Id,
|
||||||
|
RowIndex: questionForm.RowIndex,
|
||||||
|
QuestionName: qs.QuestionName
|
||||||
|
}
|
||||||
|
})" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isCurrentTask && readingTaskState < 2" class="base-dialog-footer"
|
||||||
|
style="text-align:right;margin-top:10px;">
|
||||||
|
<!-- 清除标记 -->
|
||||||
|
<!-- <el-button v-if="questionForm.MeasureData" size="mini" @click="handleDeleteMeasureData">
|
||||||
|
{{ $t('trials:reading:button:removeMark') }}
|
||||||
|
</el-button> -->
|
||||||
|
<!-- 保存 -->
|
||||||
|
<el-button size="mini" @click="handleSave">
|
||||||
|
{{ $t('common:button:save') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
// import { submitTableQuestion } from '@/api/trials'
|
||||||
|
import { saveTableQuestionMark, submitTaskRowInfo, deleteTableQuestionMark, deleteSingleTableQuestionMark } from '@/api/reading'
|
||||||
|
import DicomEvent from './../DicomEvent'
|
||||||
|
import store from '@/store'
|
||||||
|
import * as cornerstone from 'cornerstone-core'
|
||||||
|
export default {
|
||||||
|
name: 'MeasurementForm',
|
||||||
|
props: {
|
||||||
|
questions: {
|
||||||
|
type: Array,
|
||||||
|
default() { return [] }
|
||||||
|
},
|
||||||
|
answers: {
|
||||||
|
type: Object,
|
||||||
|
default() { return {} }
|
||||||
|
},
|
||||||
|
lesionType: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
visitTaskId: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
parentQsId: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isCurrentTask: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
readingTaskState: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isBaseLineTask: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
orderMark: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
questionName: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
rowIndex: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tableQuestions: {
|
||||||
|
type: Array,
|
||||||
|
default() { return [] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
questionForm: {},
|
||||||
|
loading: false,
|
||||||
|
trialId: '',
|
||||||
|
originalQuestionForm: {},
|
||||||
|
isRender: false,
|
||||||
|
lesionName: '',
|
||||||
|
lesionMark: '',
|
||||||
|
activeQuestionId: '',
|
||||||
|
activeQuestionMark: '',
|
||||||
|
digitPlaces: 2,
|
||||||
|
isMeasurableId: '',
|
||||||
|
isDisabledMeasurableRadio: false,
|
||||||
|
liverSeg: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.trialId = this.$route.query.trialId
|
||||||
|
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||||
|
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||||
|
this.initForm()
|
||||||
|
DicomEvent.$on('handleImageQualityAbnormal', () => {
|
||||||
|
this.setState()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
DicomEvent.$off('handleImageQualityAbnormal')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleReadingChart(e) {
|
||||||
|
this.$emit('handleReadingChart', e)
|
||||||
|
},
|
||||||
|
async initForm() {
|
||||||
|
this.isRender = false
|
||||||
|
this.isMeasurableId = this.getQuestionId(1105)
|
||||||
|
this.isDisabledMeasurableRadio = false
|
||||||
|
// const loading = this.$loading({ fullscreen: true })
|
||||||
|
this.questions.forEach(item => {
|
||||||
|
if (this.answers.hasOwnProperty(item.Id)) {
|
||||||
|
let val = this.answers[item.Id]
|
||||||
|
if (item.DictionaryCode) {
|
||||||
|
val = isNaN(parseInt(this.answers[item.Id])) ? this.answers[item.Id] : parseInt(this.answers[item.Id])
|
||||||
|
}
|
||||||
|
this.$set(this.questionForm, item.Id, val)
|
||||||
|
} else {
|
||||||
|
this.$set(this.questionForm, item.Id, '')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$set(this.questionForm, 'MeasureData', this.answers.MeasureData ? JSON.parse(this.answers.MeasureData) : '')
|
||||||
|
this.$set(this.questionForm, 'RowIndex', this.answers.RowIndex ? this.answers.RowIndex : '')
|
||||||
|
this.$set(this.questionForm, 'RowId', this.answers.RowId ? this.answers.RowId : '')
|
||||||
|
this.toolType = this.questionForm.MeasureData ? this.questionForm.MeasureData.type : ''
|
||||||
|
this.currentMarkTool = this.questionForm.MeasureData ? this.questionForm.MeasureData.type : this.answers.MarkTool
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
const mean = this.getQuestionVal(1104)
|
||||||
|
if (this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
if (this.answers.MeasureData) {
|
||||||
|
if (!isNaN(parseInt(isMeasurable)) && parseInt(isMeasurable) === 1 ) {
|
||||||
|
this.isDisabledMeasurableRadio = true
|
||||||
|
} else if (!isNaN(parseInt(isMeasurable)) && parseInt(this.questionForm[this.isMeasurableId]) === 0) {
|
||||||
|
// 如果存在标记且是否可测量为否,则将是否可测量更改为是
|
||||||
|
this.$set(this.questionForm, this.isMeasurableId, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// saveTypeEnum 0:未保存过(新建病灶);1:已保存,信息不完整(随访初始化病灶/分裂病灶,通过状态判断);2:已保存,信息完整
|
||||||
|
if (this.questionForm.saveTypeEnum !== 1 && this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', parseInt(isMeasurable) === 1 && isNaN(parseFloat(mean)) ? 1 : 2)
|
||||||
|
}
|
||||||
|
this.lesionName = this.getLesionInfo(this.orderMark, this.rowIndex)
|
||||||
|
this.lesionMark = this.getLesionName(this.orderMark, this.questionForm.RowIndex)
|
||||||
|
this.originalQuestionForm = { ...this.questionForm }
|
||||||
|
|
||||||
|
|
||||||
|
const seg = this.getQuestionVal(1106)
|
||||||
|
this.liverSeg = this.$fd('LiverSegmentation', seg)
|
||||||
|
if (this.questionForm.saveTypeEnum === 1 && this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
this.setQuestions()
|
||||||
|
}
|
||||||
|
this.isRender = true
|
||||||
|
// loading.close()
|
||||||
|
},
|
||||||
|
// getLesionName(orderMark) {
|
||||||
|
// // 根据肝脏分段枚举和第一次(或第二次或第三次)测量问题标识定义标记名称
|
||||||
|
// // I II III IV V VI VII VIII
|
||||||
|
// // L-I-01 L-I-02 L-I-03
|
||||||
|
// // L-II-01 L-II-02 L-II-03
|
||||||
|
// const segArr = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII']
|
||||||
|
// let lessionName = ''
|
||||||
|
// const segmentId = this.getQuestionId(1106)
|
||||||
|
// let segmentVal = this.answers[segmentId]
|
||||||
|
// segmentVal = segmentVal ? parseInt(segmentVal) : null
|
||||||
|
// if (segmentVal) {
|
||||||
|
|
||||||
|
// lessionName = `${orderMark}-${segArr[segmentVal - 1]}`
|
||||||
|
// }
|
||||||
|
// return lessionName
|
||||||
|
// },
|
||||||
|
getLesionName(orderMark, rowIndex) {
|
||||||
|
var lessionName = ''
|
||||||
|
var rowIndexArr = rowIndex.split('.')
|
||||||
|
var x = parseInt(rowIndexArr[0])
|
||||||
|
var y = parseInt(rowIndexArr[1])
|
||||||
|
if (y > 0) {
|
||||||
|
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
|
||||||
|
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
|
||||||
|
} else {
|
||||||
|
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return lessionName
|
||||||
|
},
|
||||||
|
getLesionInfo(orderMark, rowIndex) {
|
||||||
|
var arr = []
|
||||||
|
var lessionName = ''
|
||||||
|
var rowIndexArr = rowIndex.split('.')
|
||||||
|
var x = parseInt(rowIndexArr[0])
|
||||||
|
var y = parseInt(rowIndexArr[1])
|
||||||
|
if (y > 0) {
|
||||||
|
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
|
||||||
|
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
|
||||||
|
arr.push(lessionName)
|
||||||
|
} else {
|
||||||
|
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
|
||||||
|
arr.push(lessionName)
|
||||||
|
}
|
||||||
|
return arr.join(' ')
|
||||||
|
},
|
||||||
|
getQuestionId(questionMark) {
|
||||||
|
var idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
|
||||||
|
if (idx > -1) {
|
||||||
|
return this.questions[idx].Id
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async formItemChange(v, qs) {
|
||||||
|
// 维护平均值、是否可测量等信息
|
||||||
|
// 1101 -- 第一次测量 1102 -- 第二次测量 1103 -- 第三次测量 1107 -- 第四次测量
|
||||||
|
// 1104 -- MRI-PDFF 1105 -- 是否可测量
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
if (qs.QuestionMark === 1105) {
|
||||||
|
const meanId = this.getQuestionId(1104)
|
||||||
|
if (!v) {
|
||||||
|
this.$set(this.questionForm, meanId, 'NE')
|
||||||
|
} else {
|
||||||
|
this.$set(this.questionForm, meanId, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setQuestions()
|
||||||
|
},
|
||||||
|
setMeasureData(measureData, isInit = false) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (!measureData) {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
let data = {}
|
||||||
|
// 创建标记
|
||||||
|
if (!measureData.data.remark) {
|
||||||
|
// 维护标记信息
|
||||||
|
measureData.data.remark = this.getLesionName(this.orderMark, this.questionForm.RowIndex)
|
||||||
|
}
|
||||||
|
// const val = measureData.data.cachedStats.mean / 10
|
||||||
|
let val = parseFloat(measureData?.data?.cachedStats?.mean)
|
||||||
|
if (isNaN(val)) {
|
||||||
|
resolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// let imagePixelModule = cornerstone.metaData.get('imagePixelModule', measureData.imageId)
|
||||||
|
if (measureData.largestPixelValue >= 500) {
|
||||||
|
val = val / 10
|
||||||
|
}
|
||||||
|
this.$set(this.questionForm, measureData.tableQuestionId, val.toFixed(this.digitPlaces))
|
||||||
|
data = {
|
||||||
|
Id: '',
|
||||||
|
IsDicomReading: true,
|
||||||
|
StudyId: measureData.studyId,
|
||||||
|
InstanceId: measureData.instanceId,
|
||||||
|
SeriesId: measureData.seriesId,
|
||||||
|
MeasureData: measureData,
|
||||||
|
QuestionId: this.parentQsId,
|
||||||
|
RowIndex: this.questionForm.RowIndex,
|
||||||
|
RowId: this.questionForm.RowId,
|
||||||
|
VisitTaskId: this.visitTaskId,
|
||||||
|
NumberOfFrames: isNaN(parseInt(measureData.frame)) ? 0 : measureData.frame,
|
||||||
|
frame: isNaN(parseInt(measureData.frame)) ? 0 : measureData.frame,
|
||||||
|
OrderMarkName: measureData.data.remark
|
||||||
|
}
|
||||||
|
store.dispatch('reading/addMeasuredData', { visitTaskId: this.visitTaskId, data: data })
|
||||||
|
DicomEvent.$emit('refreshStudyListMeasureData')
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
|
||||||
|
if (!isNaN(parseInt(isMeasurable)) && parseInt(isMeasurable) === 1) {
|
||||||
|
this.isDisabledMeasurableRadio = true
|
||||||
|
}
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
this.$set(this.questionForm, 'MeasureData', measureData)
|
||||||
|
this.setQuestions()
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addAnnotation(qs) {
|
||||||
|
const orderMarkName = this.getLesionName(this.orderMark, this.questionForm.RowIndex)
|
||||||
|
this.activeQuestionId = qs.Id
|
||||||
|
this.activeQuestionMark = qs.QuestionMark
|
||||||
|
DicomEvent.$emit('addAnnotation', { question: qs, locateInfo: { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: orderMarkName, lesionType: null, markTool: 'Probe', readingTaskState: this.readingTaskState, isMarked: true } })
|
||||||
|
},
|
||||||
|
setQuestions() {
|
||||||
|
const mean = this.getQuestionVal(1104)
|
||||||
|
const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
this.$emit('resetQuestions', { mean, isMeasurable, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
|
||||||
|
},
|
||||||
|
returnFloat(num) {
|
||||||
|
if (num) return
|
||||||
|
var value = Math.round(parseFloat(num) * 100) / 100
|
||||||
|
var s = value.toString().split('.')
|
||||||
|
if (s.length === 1) {
|
||||||
|
value = value.toString() + '.00'
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (s.length > 1) {
|
||||||
|
if (s[1].length < 2) {
|
||||||
|
value = value.toString() + '0'
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getQuestionVal(questionMark) {
|
||||||
|
const idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
|
||||||
|
if (idx > -1) {
|
||||||
|
const questionId = this.questions[idx].Id
|
||||||
|
const answer = this.questionForm[questionId]
|
||||||
|
if (isNaN(parseFloat(answer))) {
|
||||||
|
return answer
|
||||||
|
} else {
|
||||||
|
return parseFloat(answer)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async uploadScreenshots(fileName, file) {
|
||||||
|
try {
|
||||||
|
file = this.convertBase64ToBlob(file)
|
||||||
|
var trialId = this.$route.query.trialId
|
||||||
|
var subjectId = this.$route.query.trialId
|
||||||
|
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
|
||||||
|
return { isSuccess: true, result: result }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return { isSuccess: false, result: e }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
convertBase64ToBlob(imageEditorBase64) {
|
||||||
|
var base64Arr = imageEditorBase64.split(',')
|
||||||
|
var imgtype = ''
|
||||||
|
var base64String = ''
|
||||||
|
if (base64Arr.length > 1) {
|
||||||
|
// 如果是图片base64,去掉头信息
|
||||||
|
base64String = base64Arr[1]
|
||||||
|
imgtype = base64Arr[0].substring(
|
||||||
|
base64Arr[0].indexOf(':') + 1,
|
||||||
|
base64Arr[0].indexOf(';')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 将base64解码
|
||||||
|
var bytes = atob(base64String)
|
||||||
|
// var bytes = base64;
|
||||||
|
var bytesCode = new ArrayBuffer(bytes.length)
|
||||||
|
// 转换为类型化数组
|
||||||
|
var byteArray = new Uint8Array(bytesCode)
|
||||||
|
|
||||||
|
// 将base64转换为ascii码
|
||||||
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
|
byteArray[i] = bytes.charCodeAt(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成Blob对象(文件对象)
|
||||||
|
return new Blob([bytesCode], { type: imgtype })
|
||||||
|
},
|
||||||
|
// async handleDeleteMeasureData() {
|
||||||
|
// // 是否确认清除标记?
|
||||||
|
// const confirm = await this.$confirm(
|
||||||
|
// this.$t('trials:reading:warnning:msg47'),
|
||||||
|
// {
|
||||||
|
// type: 'warning',
|
||||||
|
// distinguishCancelAndClose: true
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// if (confirm !== 'confirm') return
|
||||||
|
// // 重置MRI-PDFF
|
||||||
|
// var mripdffId = this.getQuestionId(1104)
|
||||||
|
// this.$set(this.questionForm, mripdffId, '')
|
||||||
|
// if (this.questionForm.RowId) {
|
||||||
|
// this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
// } else {
|
||||||
|
// this.$set(this.questionForm, 'saveTypeEnum', 0)
|
||||||
|
// }
|
||||||
|
// await store.dispatch('reading/removeMeasuredData', { visitTaskId: this.visitTaskId, measureData: this.questionForm.MeasureData, questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex })
|
||||||
|
// DicomEvent.$emit('getMeasureData')
|
||||||
|
|
||||||
|
// if (!this.questionForm.IsDicomReading) {
|
||||||
|
// DicomEvent.$emit('removeNoneDicomMeasureData', this.questionForm.MeasureData)
|
||||||
|
// }
|
||||||
|
// this.$set(this.questionForm, 'IsDicomReading', true)
|
||||||
|
|
||||||
|
// this.$set(this.questionForm, 'MeasureData', '')
|
||||||
|
|
||||||
|
|
||||||
|
// const mean = this.getQuestionVal(1104)
|
||||||
|
// const isMeasurable = this.getQuestionVal(1105)
|
||||||
|
// this.$emit('resetQuestions', { mean, isMeasurable, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
|
||||||
|
|
||||||
|
// DicomEvent.$emit('refreshStudyListMeasureData')
|
||||||
|
// },
|
||||||
|
|
||||||
|
async handleDeleteMeasureData() {
|
||||||
|
// 是否确认清除标记?
|
||||||
|
const confirm = await this.$confirm(
|
||||||
|
this.$t('trials:reading:warnning:msg47'),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
distinguishCancelAndClose: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (confirm !== 'confirm') return
|
||||||
|
let isMeasurable = this.getQuestionVal(1105)
|
||||||
|
// 重置MRI-PDFF
|
||||||
|
let mripdffId = this.getQuestionId(1104)
|
||||||
|
this.$set(this.questionForm, mripdffId, '')
|
||||||
|
if (this.questionForm.RowId) {
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 1)
|
||||||
|
} else {
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 0)
|
||||||
|
}
|
||||||
|
await store.dispatch('reading/removeMeasuredData', { visitTaskId: this.visitTaskId, measureData: this.questionForm.MeasureData, questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex })
|
||||||
|
DicomEvent.$emit('getMeasureData')
|
||||||
|
|
||||||
|
this.$set(this.questionForm, 'MeasureData', '')
|
||||||
|
this.isDisabledMeasurableRadio = false
|
||||||
|
let anwsers = Object.assign({}, this.questionForm)
|
||||||
|
this.$emit('resetQuestions', { mean: '', isMeasurable, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: anwsers })
|
||||||
|
DicomEvent.$emit('refreshStudyListMeasureData')
|
||||||
|
},
|
||||||
|
async handleSave() {
|
||||||
|
try {
|
||||||
|
const valid = await this.$refs.measurementForm.validate()
|
||||||
|
if (!valid) return
|
||||||
|
const loading = this.$loading({ fullscreen: true })
|
||||||
|
let measureData = this.questionForm.MeasureData
|
||||||
|
if (parseInt(this.questionForm[this.isMeasurableId]) === 0 && measureData) {
|
||||||
|
await deleteTableQuestionMark({ rowId: this.questionForm.RowId }, 11)
|
||||||
|
}
|
||||||
|
DicomEvent.$emit('getScreenshots', { questionId: this.parentQsId, rowIndex: this.questionForm.RowIndex, visitTaskId: this.visitTaskId, lesionName: this.lesionMark, lesionType: this.lesionType, isMarked: !!measureData }, async val => {
|
||||||
|
try {
|
||||||
|
let picturePath = ''
|
||||||
|
if (val && measureData) {
|
||||||
|
let pictureObj = await this.uploadScreenshots(`${new Date().getTime()}`, val)
|
||||||
|
|
||||||
|
picturePath = pictureObj.isSuccess ? this.$getObjectName(pictureObj.result.url) : ''
|
||||||
|
}
|
||||||
|
let answers = []
|
||||||
|
let reg = new RegExp(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/)
|
||||||
|
for (const k in this.questionForm) {
|
||||||
|
if (reg.test(k)) {
|
||||||
|
if (answers.findIndex(i => i.tableQuestionId === k) === -1) {
|
||||||
|
answers.push({ tableQuestionId: k, answer: this.questionForm[k] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
questionId: this.parentQsId,
|
||||||
|
rowId: this.questionForm.RowId,
|
||||||
|
rowIndex: this.answers.RowIndex,
|
||||||
|
visitTaskId: this.visitTaskId,
|
||||||
|
trialId: this.trialId,
|
||||||
|
measureData: measureData ? JSON.stringify(measureData) : '',
|
||||||
|
answerList: answers,
|
||||||
|
isDicomReading: true,
|
||||||
|
studyId: measureData ? this.questionForm.MeasureData.studyId : '',
|
||||||
|
seriesId: measureData ? this.questionForm.MeasureData.seriesId : '',
|
||||||
|
instanceId: measureData ? this.questionForm.MeasureData.instanceId : '',
|
||||||
|
numberOfFrames: measureData && !isNaN(parseInt(this.questionForm.MeasureData.frame)) ? parseInt(this.questionForm.MeasureData.frame) : 0,
|
||||||
|
picturePath: picturePath,
|
||||||
|
markTool: measureData ? measureData.type : ''
|
||||||
|
}
|
||||||
|
const res = await submitTaskRowInfo(params, 13)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
// 保存成功!
|
||||||
|
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||||
|
this.currentMarkTool = measureData ? measureData.type : ''
|
||||||
|
this.$set(this.questionForm, 'saveTypeEnum', 2)
|
||||||
|
this.originalQuestionForm = { ...this.questionForm }
|
||||||
|
this.$set(this.questionForm, 'RowId', res.Result.RowId)
|
||||||
|
this.setQuestions()
|
||||||
|
this.$emit('close')
|
||||||
|
DicomEvent.$emit('getReportInfo', true)
|
||||||
|
DicomEvent.$emit('setMeasuredToolsPassive')
|
||||||
|
// await store.dispatch('reading/refreshMeasuredData', this.visitTaskId)
|
||||||
|
// DicomEvent.$emit('getMeasureData')
|
||||||
|
this.$emit('getReadingQuestionAndAnswer')
|
||||||
|
}
|
||||||
|
loading.close()
|
||||||
|
} catch(e) {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleClose() {
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
setState() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.isCurrentTask && this.readingTaskState < 2) {
|
||||||
|
// 是否要将是否可测量设置为否?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.measurement-form {
|
||||||
|
::v-deep .el-form-item__label {
|
||||||
|
color: #c3c3c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-input .el-input__inner {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #ddd;
|
||||||
|
border: 1px solid #5e5e5e;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item__content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-input.is-disabled .el-input__inner {
|
||||||
|
background-color: #646464a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-select.is-disabled .el-input__inner {
|
||||||
|
background-color: #646464a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-button--mini,
|
||||||
|
.el-button--mini.is-round {
|
||||||
|
padding: 7px 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-input-group__append,
|
||||||
|
.el-input-group__prepend {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__content .el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-width1 {
|
||||||
|
width: calc(100% - 60px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-width2 {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,622 @@
|
||||||
|
<template>
|
||||||
|
<div class="measurement-wrapper">
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="basic-info">
|
||||||
|
<h3 v-if="isReadingShowSubjectInfo">
|
||||||
|
<span v-if="subjectCode">{{ subjectCode }} </span>
|
||||||
|
<span style="margin-left:5px;">{{ taskBlindName }}</span>
|
||||||
|
</h3>
|
||||||
|
<div v-if="readingTaskState < 2">
|
||||||
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')"
|
||||||
|
placement="bottom">
|
||||||
|
<i class="el-icon-refresh-left" @click="resetMeasuredData" />
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 非测量问题 -->
|
||||||
|
<div class="lesions">
|
||||||
|
<Questions ref="ecrf" :groupClassify="1" :question-form-change-state="questionFormChangeState"
|
||||||
|
:question-form-change-num="questionFormChangeNum" @handleReadingChart="handleReadingChart" />
|
||||||
|
</div>
|
||||||
|
<!-- 测量问题 -->
|
||||||
|
<template>
|
||||||
|
<div v-for="(qs, index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper">
|
||||||
|
<h4 v-if="qs.Type === 'group'" style="color: #ddd;padding: 5px 0px;margin: 0;">
|
||||||
|
{{ language === 'en' ? qs.GroupEnName : qs.GroupName }}
|
||||||
|
</h4>
|
||||||
|
<div class="lesion_list">
|
||||||
|
<div v-for="item in qs.Childrens" v-show="!(isBaseLineTask && item.LesionType === 2)" :key="item.Id">
|
||||||
|
<div v-if="item.Type === 'table'" class="flex-row" style="margin:3px 0;">
|
||||||
|
<div class="title">{{ item.QuestionName }}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="color: #ddd;text-align: left;padding: 5px 10px;border-bottom: 1px solid #5a5a5a; font-size: 15px;">
|
||||||
|
<el-row>
|
||||||
|
<!-- 分段 -->
|
||||||
|
<el-col :span="14">{{ $t('trials:MRIPDFF:label:col1') }}</el-col>
|
||||||
|
<!-- 是否可测量 -->
|
||||||
|
<!-- <el-col :span="7">{{$t('trials:MRIPDFF:label:col2')}}</el-col> -->
|
||||||
|
<!-- 平均值 -->
|
||||||
|
<el-col :span="7">{{ $t('trials:MRIPDFF:label:col3') }}</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-collapse v-if="item.Type === 'table' && item.TableQuestions" v-model="activeName" accordion
|
||||||
|
@change="handleCollapseChange">
|
||||||
|
<el-collapse-item v-for="(q, i) in item.TableQuestions.Answers" :key="`${item.Id}_${q.RowIndex}`"
|
||||||
|
:name="`${item.Id}_${q.RowIndex}`"
|
||||||
|
@contextmenu.prevent.native="collapseRightClick($event, q, item.Id, q.RowIndex)">
|
||||||
|
<template slot="title">
|
||||||
|
<div style="width:300px;position: relative;"
|
||||||
|
:style="{ color: (activeName === item.Id + q.RowIndex ? '#ffeb3b' : '#fff') }">
|
||||||
|
|
||||||
|
{{ getLesionName(item.TableQuestions.Questions, q) }}
|
||||||
|
<!-- 未保存 -->
|
||||||
|
<el-tooltip
|
||||||
|
v-if="readingTaskState < 2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) === 0"
|
||||||
|
class="item" effect="dark" :content="$t('trials:reading:button:unsaved')" placement="bottom">
|
||||||
|
<i class="el-icon-warning" style="color:red" />
|
||||||
|
</el-tooltip>
|
||||||
|
<!-- 信息不完整 -->
|
||||||
|
<el-tooltip
|
||||||
|
v-if="readingTaskState < 2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) === 1"
|
||||||
|
class="item" effect="dark" :content="$t('trials:reading:button:incompleteInfor')"
|
||||||
|
placement="bottom">
|
||||||
|
<i class="el-icon-warning" style="color:#ff9800" />
|
||||||
|
</el-tooltip>
|
||||||
|
<div style="position: absolute;right: 0px;top: 2px;">
|
||||||
|
<!-- white-space: nowrap;overflow: hidden;text-overflow: ellipsis; -->
|
||||||
|
<div style="font-size: 13px;width:110px;height: 30px;">
|
||||||
|
<!-- <div style="display: inline-block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width:95px">
|
||||||
|
{{ $fd('ReadingYesOrNo', parseInt(item.TableQuestions.Answers[i].isMeasurable)) }}
|
||||||
|
</div> -->
|
||||||
|
<div
|
||||||
|
style="display: inline-block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width:50px">
|
||||||
|
{{ isNaN(parseFloat(item.TableQuestions.Answers[i].mean)) ?
|
||||||
|
item.TableQuestions.Answers[i].mean : `${item.TableQuestions.Answers[i].mean}%` }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<QuestionForm :ref="`${item.Id}_${q.RowIndex}`" :questions="item.TableQuestions.Questions"
|
||||||
|
:answers="item.TableQuestions.Answers[i]" :lesion-type="item.LesionType"
|
||||||
|
:order-mark="item.OrderMark" :table-questions="tableQuestions" :row-index="String(q.RowIndex)"
|
||||||
|
:question-name="item.QuestionName" :parent-qs-id="item.Id" :visit-task-id="visitTaskId"
|
||||||
|
:is-current-task="isCurrentTask" :reading-task-state="readingTaskState"
|
||||||
|
:is-base-line-task="isBaseLineTask" @getReadingQuestionAndAnswer="getReadingQuestionAndAnswer"
|
||||||
|
@resetQuestions="resetQuestions" @close="close" @handleReadingChart="handleReadingChart" />
|
||||||
|
</el-collapse-item>
|
||||||
|
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { resetReadingTask } from '@/api/reading'
|
||||||
|
import DicomEvent from './../DicomEvent'
|
||||||
|
import store from '@/store'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
import Questions from './../Questions'
|
||||||
|
import QuestionForm from './QuestionForm'
|
||||||
|
export default {
|
||||||
|
name: 'MeasurementList',
|
||||||
|
components: {
|
||||||
|
Questions,
|
||||||
|
QuestionForm
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
isShow: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isReadingShowSubjectInfo: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
questionFormChangeState: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
questionFormChangeNum: {
|
||||||
|
type: Number,
|
||||||
|
default() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
questions: [],
|
||||||
|
activeName: '',
|
||||||
|
activeItem: {
|
||||||
|
activeRowIndex: null,
|
||||||
|
activeCollapseId: null
|
||||||
|
},
|
||||||
|
visitTaskId: '',
|
||||||
|
isCurrentTask: false,
|
||||||
|
loading: false,
|
||||||
|
unSaveTargets: [],
|
||||||
|
temporaryLesions: [],
|
||||||
|
readingTaskState: 2,
|
||||||
|
isBaseLineTask: false,
|
||||||
|
taskBlindName: '',
|
||||||
|
tableQuestions: [],
|
||||||
|
isFirstRender: false,
|
||||||
|
CriterionType: null,
|
||||||
|
subjectCode: '',
|
||||||
|
liverSegmentId: '',
|
||||||
|
liverSegmentDicCode: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['visitTaskList', 'language', 'lastCanvasTaskId', 'currentReadingTaskState'])
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
lastCanvasTaskId: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val) {
|
||||||
|
this.initList()
|
||||||
|
}
|
||||||
|
console.log('lastCanvasTaskId', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentReadingTaskState: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val) {
|
||||||
|
this.readingTaskState = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// this.subjectCode = this.$router.currentRoute.query.subjectCode
|
||||||
|
this.subjectCode = localStorage.getItem('subjectCode')
|
||||||
|
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||||
|
DicomEvent.$on('setCollapseActive', measureData => {
|
||||||
|
this.setCollapseActive(measureData)
|
||||||
|
console.log('setCollapseActive')
|
||||||
|
})
|
||||||
|
DicomEvent.$on('getAllUnSaveLesions', (callback) => {
|
||||||
|
var list = this.getAllUnSaveLesions()
|
||||||
|
callback(list)
|
||||||
|
console.log('getAllUnSaveLesions')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
DicomEvent.$off('setCollapseActive')
|
||||||
|
DicomEvent.$off('getUnSaveTarget')
|
||||||
|
DicomEvent.$off('getAllUnSaveLesions')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleReadingChart(e) {
|
||||||
|
this.$emit('handleReadingChart', e)
|
||||||
|
},
|
||||||
|
async initList() {
|
||||||
|
var i = this.visitTaskList.findIndex(i => i.VisitTaskId === this.lastCanvasTaskId)
|
||||||
|
if (i > -1) {
|
||||||
|
this.visitTaskId = this.visitTaskList[i].VisitTaskId
|
||||||
|
this.taskBlindName = this.visitTaskList[i].TaskBlindName
|
||||||
|
this.readingTaskState = this.visitTaskList[i].ReadingTaskState
|
||||||
|
this.isBaseLineTask = this.visitTaskList[i].IsBaseLineTask
|
||||||
|
this.isCurrentTask = this.visitTaskList[i].IsCurrentTask
|
||||||
|
this.activeName = ''
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
if (!this.visitTaskList[i].IsInit) {
|
||||||
|
var loading = this.$loading({ fullscreen: true })
|
||||||
|
var triald = this.trialId = this.$router.currentRoute.query.trialId
|
||||||
|
if (!this.visitTaskList[i].measureDataInit) {
|
||||||
|
await store.dispatch('reading/getMeasuredData', this.visitTaskList[i].VisitTaskId)
|
||||||
|
}
|
||||||
|
if (!this.visitTaskList[i].studyListInit) {
|
||||||
|
await store.dispatch('reading/getStudyInfo', { trialId: triald, subjectVisitId: this.visitTaskList[i].VisitId, visitTaskId: this.visitTaskList[i].VisitTaskId, taskBlindName: this.visitTaskList[i].TaskBlindName })
|
||||||
|
}
|
||||||
|
if (!this.visitTaskList[i].readingQuestionsInit) {
|
||||||
|
await store.dispatch('reading/getReadingQuestionAndAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
|
||||||
|
}
|
||||||
|
if (!this.visitTaskList[i].questionsInit) {
|
||||||
|
await store.dispatch('reading/getDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
|
||||||
|
}
|
||||||
|
|
||||||
|
await store.dispatch('reading/setStatus', { visitTaskId: this.visitTaskList[i].VisitTaskId })
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
this.questions = this.visitTaskList[i].ReadingQuestions
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs['ecrf'].getQuestions(this.visitTaskId)
|
||||||
|
this.getTableQuestions()
|
||||||
|
this.tableQuestions.forEach(item => {
|
||||||
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
|
this.$refs[refName] && this.$refs[refName][0].initForm()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async resetQuestions(obj) {
|
||||||
|
this.setQuestions(this.questions, obj)
|
||||||
|
await store.dispatch('reading/setReadingQuestionAndAnswer', { questions: this.questions, visitTaskId: this.visitTaskId })
|
||||||
|
|
||||||
|
this.getTableQuestions()
|
||||||
|
},
|
||||||
|
setQuestions(questions, obj) {
|
||||||
|
questions.forEach(item => {
|
||||||
|
if (item.Type === 'table' && item.Id === obj.questionId) {
|
||||||
|
var idx = item.TableQuestions.Answers.findIndex(i => i.RowIndex === obj.rowIndex)
|
||||||
|
item.TableQuestions.Answers[idx].isMeasurable = obj.isMeasurable
|
||||||
|
item.TableQuestions.Answers[idx].mean = obj.mean
|
||||||
|
item.TableQuestions.Answers[idx].saveTypeEnum = obj.saveTypeEnum
|
||||||
|
|
||||||
|
for (const i in obj.anwsers) {
|
||||||
|
if (i === 'MeasureData' && obj.anwsers[i]) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
item.TableQuestions.Answers[idx][i] = String(obj.anwsers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.setQuestions(item.Childrens, obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getQuestions(questions) {
|
||||||
|
questions.forEach(item => {
|
||||||
|
if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
|
||||||
|
item.TableQuestions.Answers.forEach(answerObj => {
|
||||||
|
let isMeasurable = this.getQuestionAnswer(item.TableQuestions.Questions, 1105, answerObj)
|
||||||
|
this.$set(answerObj, 'isMeasurable', isMeasurable)
|
||||||
|
this.$set(answerObj, 'mean', this.getQuestionAnswer(item.TableQuestions.Questions, 1104, answerObj))
|
||||||
|
if (answerObj.RowId) {
|
||||||
|
this.$set(answerObj, 'saveTypeEnum', isNaN(parseInt(isMeasurable)) ? 1 : 2)
|
||||||
|
} else {
|
||||||
|
this.$set(answerObj, 'saveTypeEnum', 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.getQuestions(item.Childrens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return questions
|
||||||
|
},
|
||||||
|
getTableQuestions() {
|
||||||
|
this.tableQuestions = []
|
||||||
|
this.questions.map(item => {
|
||||||
|
if (item.Type === 'table') {
|
||||||
|
this.tableQuestions.push(item)
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.getTableQuestionsChild(item.Childrens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getTableQuestionsChild(obj) {
|
||||||
|
obj.map(item => {
|
||||||
|
if (item.Type === 'table') {
|
||||||
|
this.tableQuestions.push(item)
|
||||||
|
}
|
||||||
|
if (item.Childrens.length > 0) {
|
||||||
|
this.getTableQuestionsChild(item.Childrens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshReadingQuestionAndAnswer(type) {
|
||||||
|
if (type === 0) {
|
||||||
|
// 删除
|
||||||
|
this.activeName = ''
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getReadingQuestionAndAnswer(this.visitTaskId)
|
||||||
|
},
|
||||||
|
getReadingQuestionAndAnswer(showLoading = true) {
|
||||||
|
return new Promise(async resolve => {
|
||||||
|
try {
|
||||||
|
let loading = null
|
||||||
|
if (showLoading) {
|
||||||
|
loading = this.$loading({ fullscreen: true })
|
||||||
|
}
|
||||||
|
await store.dispatch('reading/refreshReadingQuestionAndAnswer', { trialId: this.$router.currentRoute.query.trialId, visitTaskId: this.visitTaskId }).then(() => {
|
||||||
|
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||||
|
if (idx > -1) {
|
||||||
|
if (this.visitTaskList[idx].ReadingQuestions.length > 0) {
|
||||||
|
this.questions = this.visitTaskList[idx].ReadingQuestions
|
||||||
|
}
|
||||||
|
this.readingTaskState = this.visitTaskList[idx].ReadingTaskState
|
||||||
|
this.isBaseLineTask = this.visitTaskList[idx].IsBaseLineTask
|
||||||
|
this.isCurrentTask = this.visitTaskList[idx].IsCurrentTask
|
||||||
|
}
|
||||||
|
this.getTableQuestions()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.tableQuestions.forEach(item => {
|
||||||
|
item.TableQuestions.Answers.forEach(i => {
|
||||||
|
var refName = `${item.Id}_${i.RowIndex}`
|
||||||
|
this.$refs[refName] && this.$refs[refName][0].initForm()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await store.dispatch('reading/refreshMeasuredData', this.visitTaskId)
|
||||||
|
DicomEvent.$emit('getMeasureData')
|
||||||
|
|
||||||
|
loading ? loading.close() : ''
|
||||||
|
resolve()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
loading ? loading.close() : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getQuestionAnswer(questions, questionMark, answers) {
|
||||||
|
var idx = questions.findIndex(i => i.QuestionMark === questionMark)
|
||||||
|
if (idx > -1) {
|
||||||
|
var questionId = questions[idx].Id
|
||||||
|
return answers[questionId]
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isCanActiveTool(toolName) {
|
||||||
|
return { isCanActiveTool: true, reason: '' }
|
||||||
|
},
|
||||||
|
|
||||||
|
checkToolCanActive(toolName) {
|
||||||
|
return { isCanActiveTool: true, reason: '' }
|
||||||
|
},
|
||||||
|
|
||||||
|
getLesionName(questions, q) {
|
||||||
|
let liverSegmentStr = ''
|
||||||
|
if (!this.liverSegmentId) {
|
||||||
|
let i = questions.findIndex(i => i.QuestionMark === 1106)
|
||||||
|
if (i === -1) return
|
||||||
|
this.liverSegmentId = questions[i].Id
|
||||||
|
this.liverSegmentDicCode = questions[i].DictionaryCode
|
||||||
|
}
|
||||||
|
if (q && q[this.liverSegmentId]) {
|
||||||
|
liverSegmentStr = this.$fd(this.liverSegmentDicCode, parseInt(q[this.liverSegmentId]))
|
||||||
|
}
|
||||||
|
return liverSegmentStr
|
||||||
|
},
|
||||||
|
handleCollapseChange(val) {
|
||||||
|
if (this.activeName) {
|
||||||
|
var arr = this.activeName.split('_')
|
||||||
|
this.activeItem.activeRowIndex = arr[1]
|
||||||
|
this.activeItem.activeCollapseId = arr[0]
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
if (this.$refs[refName][0].questionForm.IsDicomReading !== false) {
|
||||||
|
var markTool = this.$refs[refName][0].currentMarkTool
|
||||||
|
var readingTaskState = this.readingTaskState
|
||||||
|
var isMarked = !!this.$refs[refName][0].questionForm.MeasureData
|
||||||
|
DicomEvent.$emit('imageLocation', { questionId: this.activeItem.activeCollapseId, rowIndex: this.activeItem.activeRowIndex, visitTaskId: this.visitTaskId, lesionName: this.$refs[refName][0].lesionMark, lesionType: this.$refs[refName][0].lesionType, markTool, readingTaskState, isMarked })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collapseRightClick(e, obj, activeCollapseId, activeRowIndex) {
|
||||||
|
if (obj.IsDicomReading !== false) {
|
||||||
|
const refName = `${activeCollapseId}_${activeRowIndex}`
|
||||||
|
DicomEvent.$emit('imageLocation', { questionId: activeCollapseId, rowIndex: activeRowIndex, visitTaskId: this.visitTaskId, lesionName: this.$refs[refName][0].lesionMark, lesionType: this.$refs[refName][0].lesionType })
|
||||||
|
}
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
setCollapseActive(measureData) {
|
||||||
|
if (measureData) {
|
||||||
|
if (this.activeItem.activeRowIndex === measureData.RowIndex && this.activeItem.activeCollapseId === measureData.QuestionId) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
this.activeItem.activeCollapseId = measureData.QuestionId
|
||||||
|
this.activeItem.activeRowIndex = measureData.RowIndex
|
||||||
|
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifyMeasuredData(measureObj) {
|
||||||
|
if (measureObj.questionInfo) {
|
||||||
|
this.activeItem.activeCollapseId = measureObj.questionInfo.QuestionId
|
||||||
|
this.activeItem.activeRowIndex = String(measureObj.questionInfo.RowIndex)
|
||||||
|
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
this.$refs[refName][0].setMeasureData(measureObj.measureData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 设置测量数据
|
||||||
|
setMeasuredData(measureData) {
|
||||||
|
if (this.activeItem.activeCollapseId) {
|
||||||
|
// 判断是否存在测量数据
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const refName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
|
||||||
|
if (!this.$refs[refName][0].questionForm.MeasureData || (this.$refs[refName][0].questionForm && this.$refs[refName][0].questionForm.MeasureData && measureData.data.uuid === this.$refs[refName][0].questionForm.MeasureData.data.uuid)) {
|
||||||
|
this.$refs[refName][0].setMeasureData(measureData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async close(questionsObj) {
|
||||||
|
if (questionsObj) {
|
||||||
|
this.getReadingQuestionAndAnswer(questionsObj.visitTaskId)
|
||||||
|
}
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
this.activeName = ''
|
||||||
|
},
|
||||||
|
getECRFQuestions(obj) {
|
||||||
|
this.$refs['ecrf'].getQuestions(obj.visitTaskId)
|
||||||
|
},
|
||||||
|
async resetMeasuredData() {
|
||||||
|
const confirm = await this.$confirm(
|
||||||
|
this.$t('trials:dicomReading:message:confirmReset1'),
|
||||||
|
this.$t('trials:dicomReading:message:confirmReset2'),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
distinguishCancelAndClose: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (confirm !== 'confirm') return
|
||||||
|
const loading = this.$loading({ fullscreen: true })
|
||||||
|
try {
|
||||||
|
const res = await resetReadingTask({ visitTaskId: this.visitTaskId })
|
||||||
|
this.loading = false
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
// 刷新标注、表单、报告页信息
|
||||||
|
this.activeName = ''
|
||||||
|
this.activeItem.activeRowIndex = null
|
||||||
|
this.activeItem.activeCollapseId = null
|
||||||
|
await this.getReadingQuestionAndAnswer(this.visitTaskId)
|
||||||
|
const triald = this.$router.currentRoute.query.trialId
|
||||||
|
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskId })
|
||||||
|
this.$refs['ecrf'].getQuestions(this.visitTaskId, true)
|
||||||
|
DicomEvent.$emit('getMeasureData')
|
||||||
|
DicomEvent.$emit('getReportInfo', true)
|
||||||
|
DicomEvent.$emit('refreshStudyListMeasureData')
|
||||||
|
}
|
||||||
|
loading.close()
|
||||||
|
} catch (e) {
|
||||||
|
loading.close()
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAllUnSaveLesions() {
|
||||||
|
var arr = []
|
||||||
|
this.tableQuestions.map(item => {
|
||||||
|
if (item.TableQuestions && item.TableQuestions.Answers) {
|
||||||
|
item.TableQuestions.Answers.map(t => {
|
||||||
|
const refName = `${item.Id}_${t.RowIndex}`
|
||||||
|
if (this.$refs[refName] && this.$refs[refName][0] && this.$refs[refName][0].questionForm.saveTypeEnum !== 2) {
|
||||||
|
var lessionName = this.$refs[refName][0].liverSeg
|
||||||
|
arr.push({ lessionName: lessionName, rowIndex: t.RowIndex, questionId: item.Id })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.measurement-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
// overflow: hidden;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.basic-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #ddd;
|
||||||
|
padding: 5px 0px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
padding: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 15px;
|
||||||
|
border: 1px solid #938b8b;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon:hover {
|
||||||
|
background-color: #607d8b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #424242;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesion_list {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse {
|
||||||
|
border-bottom: none;
|
||||||
|
border-top: none;
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item {
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #ddd;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__header {
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #ddd;
|
||||||
|
border-bottom-color: #5a5a5a;
|
||||||
|
padding-left: 5px;
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__wrap {
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__content {
|
||||||
|
width: 260px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
// border: 1px solid #ffeb3b;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
z-index: 1;
|
||||||
|
color: #ddd;
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -17,52 +17,53 @@
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="dicom-desc"
|
class="dicom-desc"
|
||||||
style="width: 135px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;"
|
style="white-space: normal;"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;" v-if="!study.StudyName">
|
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
|
||||||
<span style="margin-left: 5px;">{{ study.Modalities }} ({{ study.SeriesCount }})</span>
|
<span v-if="taskInfo && taskInfo.IsShowStudyName && study.StudyName" :title="study.StudyName">
|
||||||
</div>
|
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;" v-else>
|
|
||||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
|
||||||
<span v-if="taskInfo && taskInfo.IsShowStudyName" :title="study.StudyName" style="margin: 0 5px">
|
|
||||||
{{study.StudyName}}
|
{{study.StudyName}}
|
||||||
</span>
|
</span>
|
||||||
<div>{{ study.Modalities }} ({{ study.SeriesCount }})</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;" :title="study.Description">{{ study.Description }}</div>
|
<div>
|
||||||
<div class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
<span class="study-meta-line" :title="study.Modalities">
|
||||||
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
<span class="study-code" :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||||
<h4>{{ $t('trials:ptData:title') }}</h4>
|
<span class="study-modality">{{ study.Modalities }}({{ study.SeriesCount }})</span>
|
||||||
<div class="patient-info-row">
|
<span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
||||||
<label>{{ $t('trials:ptData:label:patientSex') }}</label>
|
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
||||||
<span>{{ study.PatientSex }}</span>
|
<h4>{{ $t('trials:ptData:title') }}</h4>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:patientSex') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:patientWeight') }}</label>
|
<span>{{ study.PatientSex }}</span>
|
||||||
<span>{{ study.PatientWeight }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:patientWeight') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:totalDose') }}</label>
|
<span>{{ study.PatientWeight }}</span>
|
||||||
<span>{{ study.RadionuclideTotalDose }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:totalDose') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:halfLife') }}</label>
|
<span>{{ study.RadionuclideTotalDose }}</span>
|
||||||
<span>{{ study.RadionuclideHalfLife }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:halfLife') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:injectTime') }}</label>
|
<span>{{ study.RadionuclideHalfLife }}</span>
|
||||||
<span>{{ study.RadiopharmaceuticalStartTime }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:injectTime') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:acquisitionTime') }}</label>
|
<span>{{ study.RadiopharmaceuticalStartTime }}</span>
|
||||||
<span>{{ study.AcquisitionTime }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<i slot="reference" class="el-icon-document"
|
<label>{{ $t('trials:ptData:label:acquisitionTime') }}</label>
|
||||||
style="font-size: 15px;cursor: pointer;color: #f5f7fa;" />
|
<span>{{ study.AcquisitionTime }}</span>
|
||||||
</el-popover>
|
</div>
|
||||||
|
<i slot="reference" class="el-icon-document"
|
||||||
|
style="font-size: 15px;cursor: pointer;color: #f5f7fa;" />
|
||||||
|
</el-popover>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="study.Description" class="study-desc-text" :title="study.Description">{{ study.Description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -111,6 +112,7 @@
|
||||||
v-for="(instance, idx) in series.instanceInfoList"
|
v-for="(instance, idx) in series.instanceInfoList"
|
||||||
:key="instance.Id"
|
:key="instance.Id"
|
||||||
class="frame_content"
|
class="frame_content"
|
||||||
|
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||||
:style="{'margin-bottom':idx<series.instanceInfoList.length-1? '5px':'0px'}"
|
:style="{'margin-bottom':idx<series.instanceInfoList.length-1? '5px':'0px'}"
|
||||||
@click.stop="showMultiFrames(index,series, i, instance)"
|
@click.stop="showMultiFrames(index,series, i, instance)"
|
||||||
>
|
>
|
||||||
|
|
@ -246,7 +248,8 @@ export default {
|
||||||
srInfo: {},
|
srInfo: {},
|
||||||
digitPlaces: 2,
|
digitPlaces: 2,
|
||||||
visitTaskIdx: -1,
|
visitTaskIdx: -1,
|
||||||
taskInfo: null
|
taskInfo: null,
|
||||||
|
activeInstanceId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -697,6 +700,7 @@ export default {
|
||||||
},
|
},
|
||||||
showSeriesImage(studyIndex, seriesIndex, series) {
|
showSeriesImage(studyIndex, seriesIndex, series) {
|
||||||
if (series.isDicom) {
|
if (series.isDicom) {
|
||||||
|
this.activeInstanceId = null
|
||||||
if (series.modality === 'SR') {
|
if (series.modality === 'SR') {
|
||||||
this.studyIndex = studyIndex
|
this.studyIndex = studyIndex
|
||||||
this.seriesIndex = seriesIndex
|
this.seriesIndex = seriesIndex
|
||||||
|
|
@ -756,6 +760,7 @@ export default {
|
||||||
},
|
},
|
||||||
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
||||||
this.currentSeriesIndex = seriesIndex
|
this.currentSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceId = instanceInfo.Id
|
||||||
var idx = this.visitTaskIdx
|
var idx = this.visitTaskIdx
|
||||||
const imageIds = []
|
const imageIds = []
|
||||||
if (instanceInfo.KeyFramesList.length > 0) {
|
if (instanceInfo.KeyFramesList.length > 0) {
|
||||||
|
|
@ -973,6 +978,35 @@ export default {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #d0d0d0;
|
color: #d0d0d0;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
white-space: normal;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.study-meta-line {
|
||||||
|
// display: grid;
|
||||||
|
// grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
// align-items: start;
|
||||||
|
// gap: 6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.study-meta-main {
|
||||||
|
display: block;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: normal;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.study-code,
|
||||||
|
.study-modality {
|
||||||
|
white-space: normal;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
.study-desc-text {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ps {
|
.ps {
|
||||||
|
|
@ -1068,8 +1102,17 @@ export default {
|
||||||
background-color: #000!important;
|
background-color: #000!important;
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
border-bottom-color:#5a5a5a;
|
border-bottom-color:#5a5a5a;
|
||||||
padding-left: 5px;
|
padding-left: 1px;
|
||||||
height: 40px;
|
min-height: 40px;
|
||||||
|
height: auto;
|
||||||
|
line-height: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
.el-collapse-item__arrow{
|
||||||
|
align-self: flex-start;
|
||||||
|
margin-top: 2px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1138,11 +1181,17 @@ export default {
|
||||||
border-color: #213a54 !important;
|
border-color: #213a54 !important;
|
||||||
background-color: #213a54;
|
background-color: #213a54;
|
||||||
}
|
}
|
||||||
|
.frame_content_active {
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.patient-info {
|
.patient-info {
|
||||||
// display: inline-block;
|
display: inline-flex;
|
||||||
text-align: right;
|
align-items: center;
|
||||||
|
line-height: 1;
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
.patient-info-popper {
|
.patient-info-popper {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@
|
||||||
v-for="(instance, idx) in series.instanceInfoList"
|
v-for="(instance, idx) in series.instanceInfoList"
|
||||||
:key="instance.Id"
|
:key="instance.Id"
|
||||||
class="frame_content"
|
class="frame_content"
|
||||||
|
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||||
:style="{'margin-bottom':idx<series.instanceInfoList.length-1? '5px':'0px'}"
|
:style="{'margin-bottom':idx<series.instanceInfoList.length-1? '5px':'0px'}"
|
||||||
@click.stop="showMultiFrames(index,series, i, instance)"
|
@click.stop="showMultiFrames(index,series, i, instance)"
|
||||||
>
|
>
|
||||||
|
|
@ -221,7 +222,8 @@ export default {
|
||||||
srInfo: {},
|
srInfo: {},
|
||||||
digitPlaces: 2,
|
digitPlaces: 2,
|
||||||
visitTaskIdx: -1,
|
visitTaskIdx: -1,
|
||||||
taskInfo: null
|
taskInfo: null,
|
||||||
|
activeInstanceId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -641,6 +643,7 @@ export default {
|
||||||
},
|
},
|
||||||
showSeriesImage(studyIndex, seriesIndex, series) {
|
showSeriesImage(studyIndex, seriesIndex, series) {
|
||||||
if (series.isDicom) {
|
if (series.isDicom) {
|
||||||
|
this.activeInstanceId = null
|
||||||
if (series.modality === 'SR') {
|
if (series.modality === 'SR') {
|
||||||
this.studyIndex = studyIndex
|
this.studyIndex = studyIndex
|
||||||
this.seriesIndex = seriesIndex
|
this.seriesIndex = seriesIndex
|
||||||
|
|
@ -699,6 +702,7 @@ export default {
|
||||||
},
|
},
|
||||||
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
showMultiFrames(studyIndex, series, seriesIndex, instanceInfo) {
|
||||||
this.currentSeriesIndex = seriesIndex
|
this.currentSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceId = instanceInfo.Id
|
||||||
var idx = this.visitTaskIdx
|
var idx = this.visitTaskIdx
|
||||||
this.studyIndex = studyIndex
|
this.studyIndex = studyIndex
|
||||||
this.seriesIndex = seriesIndex
|
this.seriesIndex = seriesIndex
|
||||||
|
|
@ -1042,4 +1046,8 @@ export default {
|
||||||
border-color: #213a54 !important;
|
border-color: #213a54 !important;
|
||||||
background-color: #213a54;
|
background-color: #213a54;
|
||||||
}
|
}
|
||||||
|
.frame_content_active {
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import createNewMeasurement from './createNewMeasurement'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class BidirectionalTool extends cornerstoneTools.BidirectionalTool {
|
export default class BidirectionalTool extends cornerstoneTools.BidirectionalTool {
|
||||||
constructor(props) {
|
constructor(props = {}) {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
name: 'Bidirectional',
|
name: 'Bidirectional',
|
||||||
configuration: {
|
configuration: {
|
||||||
|
|
@ -25,7 +25,8 @@ export default class BidirectionalTool extends cornerstoneTools.BidirectionalToo
|
||||||
|
|
||||||
super(props, defaultProps)
|
super(props, defaultProps)
|
||||||
this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 50)
|
this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 50)
|
||||||
this.digits = isNaN(parseInt(props.configuration.digits)) ? 2 : props.configuration.digits
|
const digits = props?.configuration?.digits
|
||||||
|
this.digits = isNaN(parseInt(digits)) ? 2 : digits
|
||||||
this.createNewMeasurement = createNewMeasurement.bind(this)
|
this.createNewMeasurement = createNewMeasurement.bind(this)
|
||||||
this.renderToolData = renderToolData.bind(this)
|
this.renderToolData = renderToolData.bind(this)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,347 @@
|
||||||
|
import * as cornerstoneTools from 'cornerstone-tools'
|
||||||
|
import * as cornerstone from 'cornerstone-core'
|
||||||
|
import getCircleCoords from '../CircleRoi/getCircleCoords'
|
||||||
|
const EVENTS = cornerstoneTools.EVENTS
|
||||||
|
const getPixelSpacing = cornerstoneTools.importInternal('util/getPixelSpacing')
|
||||||
|
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
|
||||||
|
const external = cornerstoneTools.external
|
||||||
|
const getToolState = cornerstoneTools.getToolState
|
||||||
|
const toolStyle = cornerstoneTools.toolStyle
|
||||||
|
const toolColors = cornerstoneTools.toolColors
|
||||||
|
const getModule = cornerstoneTools.getModule
|
||||||
|
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
|
||||||
|
const draw = cornerstoneTools.import('drawing/draw')
|
||||||
|
const setShadow = cornerstoneTools.import('drawing/setShadow')
|
||||||
|
const drawCircle = cornerstoneTools.import('drawing/drawCircle')
|
||||||
|
const drawHandles = cornerstoneTools.import('drawing/drawHandles')
|
||||||
|
const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox')
|
||||||
|
const getROITextBoxCoords = cornerstoneTools.import('util/getROITextBoxCoords')
|
||||||
|
const numbersWithCommas = cornerstoneTools.import('util/numbersWithCommas')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @class FixedCircleRoiTool
|
||||||
|
* @memberof Tools.Annotation
|
||||||
|
* @classdesc Tool for drawing circular regions of interest with a fixed radius, and measuring
|
||||||
|
* the statistics of the enclosed pixels.
|
||||||
|
* @extends Tools.Annotation.CircleRoiTool
|
||||||
|
*/
|
||||||
|
export default class FixedCircleRoiTool extends cornerstoneTools.CircleRoiTool {
|
||||||
|
constructor(props = {}) {
|
||||||
|
const defaultProps = {
|
||||||
|
name: 'FixedCircleRoi',
|
||||||
|
configuration: {
|
||||||
|
radius: 10, // Default radius in units (mm by default)
|
||||||
|
unit: 'mm', // 'mm' or 'px'
|
||||||
|
centerPointRadius: 0,
|
||||||
|
renderDashed: false,
|
||||||
|
drawHandlesOnHover: false,
|
||||||
|
handleRadius: 0,
|
||||||
|
digits: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
super(props, defaultProps);
|
||||||
|
|
||||||
|
// Explicitly set name to ensure it is defined
|
||||||
|
this.name = 'FixedCircleRoi';
|
||||||
|
|
||||||
|
// Manually merge configuration to ensure props override defaults
|
||||||
|
if (props && props.configuration) {
|
||||||
|
this.configuration = Object.assign(
|
||||||
|
{},
|
||||||
|
this.configuration || defaultProps.configuration,
|
||||||
|
props.configuration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewMeasurement(eventData) {
|
||||||
|
const measurementData = super.createNewMeasurement(eventData);
|
||||||
|
|
||||||
|
if (!measurementData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { image } = eventData;
|
||||||
|
// Fallback if configuration is missing
|
||||||
|
if (!this.configuration) {
|
||||||
|
console.warn(
|
||||||
|
'FixedCircleRoiTool: configuration missing, using defaults'
|
||||||
|
);
|
||||||
|
this.configuration = { radius: 10, unit: 'mm' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = this.configuration;
|
||||||
|
let radiusPixels = config.radius;
|
||||||
|
|
||||||
|
if (config.unit === 'mm') {
|
||||||
|
const pixelSpacing = getPixelSpacing(image);
|
||||||
|
console.log(
|
||||||
|
'FixedCircleRoiTool: PixelSpacing retrieved:',
|
||||||
|
pixelSpacing
|
||||||
|
);
|
||||||
|
|
||||||
|
const { colPixelSpacing } = pixelSpacing;
|
||||||
|
|
||||||
|
if (colPixelSpacing && colPixelSpacing > 0) {
|
||||||
|
radiusPixels = config.radius / colPixelSpacing;
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
'FixedCircleRoiTool: Invalid pixel spacing, treating radius as pixels'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure radiusPixels is a valid number
|
||||||
|
if (isNaN(radiusPixels)) {
|
||||||
|
console.warn(
|
||||||
|
'FixedCircleRoiTool: radiusPixels is NaN, defaulting to 10px'
|
||||||
|
);
|
||||||
|
radiusPixels = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set end handle position based on calculated radius pixels
|
||||||
|
measurementData.handles.end.x =
|
||||||
|
measurementData.handles.start.x + radiusPixels;
|
||||||
|
measurementData.handles.end.y = measurementData.handles.start.y;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'FixedCircleRoiTool created measurement:',
|
||||||
|
JSON.parse(JSON.stringify(measurementData))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Invalidate to trigger stats calculation
|
||||||
|
measurementData.invalidated = true;
|
||||||
|
|
||||||
|
return measurementData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrite the addNewMeasurement method to prevent the default behavior
|
||||||
|
* of resizing the circle on mouse drag immediately after creation.
|
||||||
|
*/
|
||||||
|
addNewMeasurement(evt, interactionType) {
|
||||||
|
const eventData = evt.detail;
|
||||||
|
if (
|
||||||
|
!eventData ||
|
||||||
|
!eventData.currentPoints ||
|
||||||
|
!eventData.currentPoints.image
|
||||||
|
) {
|
||||||
|
console.warn(
|
||||||
|
'FixedCircleRoiTool: Invalid eventData supplied to addNewMeasurement'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = eventData.element;
|
||||||
|
|
||||||
|
// 1. Create the measurement data (which already has the fixed radius)
|
||||||
|
const measurementData = this.createNewMeasurement(eventData);
|
||||||
|
|
||||||
|
if (!measurementData) return;
|
||||||
|
|
||||||
|
// 2. Add it to the tool state
|
||||||
|
cornerstoneTools.addToolState(element, this.name, measurementData);
|
||||||
|
|
||||||
|
// 3. Ensure stats are available for completion listeners (e.g. mean value consumers).
|
||||||
|
if (!measurementData.cachedStats && eventData.image) {
|
||||||
|
this.updateCachedStats(eventData.image, element, measurementData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Update the image to show the new annotation
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
|
||||||
|
// 5. Manually emit completion event since we bypass default drag-finish flow.
|
||||||
|
triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
|
||||||
|
toolName: this.name,
|
||||||
|
element,
|
||||||
|
measurementData,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 6. Do NOT attach mouse/touch event listeners for resizing.
|
||||||
|
// The circle is created with fixed size and placed immediately.
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSelectedCallback(evt, measurementData, handle, interactionType = 'mouse') {
|
||||||
|
// Lock circle radius by preventing start/end handle drag.
|
||||||
|
if (measurementData && measurementData.handles) {
|
||||||
|
const { start, end } = measurementData.handles
|
||||||
|
if (handle === start || handle === end) {
|
||||||
|
evt.stopImmediatePropagation?.()
|
||||||
|
evt.preventDefault?.()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.handleSelectedCallback(evt, measurementData, handle, interactionType)
|
||||||
|
}
|
||||||
|
|
||||||
|
pointNearTool(element, data, coords, interactionType = 'mouse') {
|
||||||
|
const isNearDefault = super.pointNearTool(element, data, coords, interactionType)
|
||||||
|
if (isNearDefault) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (!data || !data.handles || !data.handles.start || !data.handles.end) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const centerCanvas = external.cornerstone.pixelToCanvas(element, data.handles.start)
|
||||||
|
const edgeCanvas = external.cornerstone.pixelToCanvas(element, data.handles.end)
|
||||||
|
const radius = external.cornerstoneMath.point.distance(centerCanvas, edgeCanvas)
|
||||||
|
const distanceToCenter = external.cornerstoneMath.point.distance(centerCanvas, coords)
|
||||||
|
|
||||||
|
return distanceToCenter <= radius
|
||||||
|
}
|
||||||
|
|
||||||
|
renderToolData(evt) {
|
||||||
|
const toolData = getToolState(evt.currentTarget, this.name)
|
||||||
|
|
||||||
|
if (!toolData) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDistance = external.cornerstoneMath.point.distance
|
||||||
|
const eventData = evt.detail
|
||||||
|
const { image, element, canvasContext } = eventData
|
||||||
|
const lineWidth = toolStyle.getToolWidth()
|
||||||
|
const {
|
||||||
|
handleRadius,
|
||||||
|
drawHandlesOnHover,
|
||||||
|
hideHandlesIfMoving,
|
||||||
|
renderDashed,
|
||||||
|
centerPointRadius,
|
||||||
|
} = this.configuration
|
||||||
|
const newContext = getNewContext(canvasContext.canvas)
|
||||||
|
const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image)
|
||||||
|
const lineDash = getModule('globalConfiguration').configuration.lineDash
|
||||||
|
|
||||||
|
const seriesModule =
|
||||||
|
external.cornerstone.metaData.get('generalSeriesModule', image.imageId) ||
|
||||||
|
{}
|
||||||
|
const modality = seriesModule.modality
|
||||||
|
const hasPixelSpacing = rowPixelSpacing && colPixelSpacing
|
||||||
|
|
||||||
|
draw(newContext, context => {
|
||||||
|
for (let i = 0; i < toolData.data.length; i++) {
|
||||||
|
const data = toolData.data[i]
|
||||||
|
|
||||||
|
if (data.visible === false) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const color = toolColors.getColorIfActive(data)
|
||||||
|
const handleOptions = {
|
||||||
|
color,
|
||||||
|
handleRadius,
|
||||||
|
drawHandlesIfActive: drawHandlesOnHover,
|
||||||
|
hideHandlesIfMoving,
|
||||||
|
}
|
||||||
|
|
||||||
|
setShadow(context, this.configuration)
|
||||||
|
|
||||||
|
const startCanvas = external.cornerstone.pixelToCanvas(
|
||||||
|
element,
|
||||||
|
data.handles.start
|
||||||
|
)
|
||||||
|
const endCanvas = external.cornerstone.pixelToCanvas(
|
||||||
|
element,
|
||||||
|
data.handles.end
|
||||||
|
)
|
||||||
|
const radius = getDistance(startCanvas, endCanvas)
|
||||||
|
|
||||||
|
const circleOptions = { color }
|
||||||
|
if (renderDashed) {
|
||||||
|
circleOptions.lineDash = lineDash
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCircle(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
data.handles.start,
|
||||||
|
radius,
|
||||||
|
circleOptions,
|
||||||
|
'pixel'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (centerPointRadius && radius > 3 * centerPointRadius) {
|
||||||
|
drawCircle(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
data.handles.start,
|
||||||
|
centerPointRadius,
|
||||||
|
circleOptions,
|
||||||
|
'pixel'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.handles) {
|
||||||
|
data.handles.start.drawnIndependently = true
|
||||||
|
data.handles.end.drawnIndependently = true
|
||||||
|
}
|
||||||
|
drawHandles(context, eventData, data.handles, handleOptions)
|
||||||
|
|
||||||
|
if (data.invalidated === true) {
|
||||||
|
if (data.cachedStats) {
|
||||||
|
this.throttledUpdateCachedStats(image, element, data)
|
||||||
|
} else {
|
||||||
|
this.updateCachedStats(image, element, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.handles.textBox.hasMoved) {
|
||||||
|
const defaultCoords = getROITextBoxCoords(
|
||||||
|
eventData.viewport,
|
||||||
|
data.handles
|
||||||
|
)
|
||||||
|
Object.assign(data.handles.textBox, defaultCoords)
|
||||||
|
}
|
||||||
|
|
||||||
|
const textBoxContent = []
|
||||||
|
console.log(data)
|
||||||
|
if (data.remark) {
|
||||||
|
textBoxContent.push(data.remark)
|
||||||
|
}
|
||||||
|
|
||||||
|
const digits = this.configuration.digits || 1
|
||||||
|
if (!image.color && data.cachedStats && Number.isFinite(data.cachedStats.mean)) {
|
||||||
|
const unit = modality === 'CT' && this.configuration.showHounsfieldUnits !== false ? 'HU' : ''
|
||||||
|
const meanText = numbersWithCommas(data.cachedStats.mean.toFixed(digits))
|
||||||
|
textBoxContent.push(unit ? `Mean: ${meanText} ${unit}` : `Mean: ${meanText}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!textBoxContent.length) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const textBoxAnchorPoints = handles =>
|
||||||
|
findTextBoxAnchorPoints(handles.start, handles.end)
|
||||||
|
|
||||||
|
drawLinkedTextBox(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
data.handles.textBox,
|
||||||
|
textBoxContent,
|
||||||
|
data.handles,
|
||||||
|
textBoxAnchorPoints,
|
||||||
|
color,
|
||||||
|
lineWidth,
|
||||||
|
20,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
data.unit = modality === 'CT' && this.configuration.showHounsfieldUnits !== false ? 'HU' : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findTextBoxAnchorPoints(startHandle, endHandle) {
|
||||||
|
const { left, top, width, height } = getCircleCoords(startHandle, endHandle)
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ x: left + width / 2, y: top },
|
||||||
|
{ x: left, y: top + height / 2 },
|
||||||
|
{ x: left + width / 2, y: top + height },
|
||||||
|
{ x: left + width, y: top + height / 2 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import * as cornerstoneTools from 'cornerstone-tools'
|
import * as cornerstoneTools from 'cornerstone-tools'
|
||||||
|
const EVENTS = cornerstoneTools.EVENTS
|
||||||
|
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
|
||||||
const external = cornerstoneTools.external
|
const external = cornerstoneTools.external
|
||||||
// State
|
// State
|
||||||
const getToolState = cornerstoneTools.getToolState
|
const getToolState = cornerstoneTools.getToolState
|
||||||
|
|
@ -87,7 +89,7 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
visible: true,
|
visible: true,
|
||||||
active: true,
|
active: false,
|
||||||
color: undefined,
|
color: undefined,
|
||||||
invalidated: true,
|
invalidated: true,
|
||||||
handles: {
|
handles: {
|
||||||
|
|
@ -100,8 +102,8 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool {
|
||||||
end: {
|
end: {
|
||||||
x: eventData.currentPoints.image.x,
|
x: eventData.currentPoints.image.x,
|
||||||
y: eventData.currentPoints.image.y,
|
y: eventData.currentPoints.image.y,
|
||||||
highlight: true,
|
highlight: false,
|
||||||
active: true,
|
active: false,
|
||||||
radius: 0
|
radius: 0
|
||||||
},
|
},
|
||||||
// textBox: {
|
// textBox: {
|
||||||
|
|
@ -125,6 +127,41 @@ export default class ProbeTool extends cornerstoneTools.ProbeTool {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addNewMeasurement(evt, interactionType) {
|
||||||
|
const eventData = evt.detail
|
||||||
|
if (!eventData || !eventData.currentPoints || !eventData.currentPoints.image) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { element, image } = eventData
|
||||||
|
const measurementData = this.createNewMeasurement(eventData)
|
||||||
|
|
||||||
|
if (!measurementData) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click-to-place and finish immediately; avoid default drag listeners.
|
||||||
|
measurementData.active = false
|
||||||
|
if (measurementData.handles && measurementData.handles.end) {
|
||||||
|
measurementData.handles.end.active = false
|
||||||
|
measurementData.handles.end.highlight = false
|
||||||
|
}
|
||||||
|
|
||||||
|
cornerstoneTools.addToolState(element, this.name, measurementData)
|
||||||
|
|
||||||
|
if (!measurementData.cachedStats && image) {
|
||||||
|
this.updateCachedStats(image, element, measurementData)
|
||||||
|
}
|
||||||
|
|
||||||
|
external.cornerstone.updateImage(element)
|
||||||
|
|
||||||
|
triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
|
||||||
|
toolName: this.name,
|
||||||
|
element,
|
||||||
|
measurementData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -564,17 +564,18 @@ export default {
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||||
if (!viewport) return
|
if (!viewport) return
|
||||||
|
let index = this.series.SliceIndex
|
||||||
if (forceFitToWindow) {
|
if (forceFitToWindow) {
|
||||||
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
||||||
viewport.render()
|
viewport.render()
|
||||||
|
this.setFullScreen(index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
||||||
const canvas = viewport.getCanvas() || this.element.querySelector('canvas')
|
const canvas = viewport.getCanvas() || this.element.querySelector('canvas')
|
||||||
const imageData = viewport.getImageData()?.imageData
|
const imageData = viewport.getImageData()?.imageData
|
||||||
const dimensions = imageData?.getDimensions?.()
|
const dimensions = imageData?.getDimensions()
|
||||||
const imageWidth = dimensions?.[0]
|
const imageWidth = dimensions?.[0]
|
||||||
const imageHeight = dimensions?.[1]
|
const imageHeight = dimensions?.[1]
|
||||||
const canvasWidth = canvas?.clientWidth
|
const canvasWidth = canvas?.clientWidth
|
||||||
|
|
@ -582,16 +583,17 @@ export default {
|
||||||
|
|
||||||
if (!imageWidth || !imageHeight || !canvasWidth || !canvasHeight) {
|
if (!imageWidth || !imageHeight || !canvasWidth || !canvasHeight) {
|
||||||
viewport.render()
|
viewport.render()
|
||||||
|
this.setFullScreen(index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const fitScale = Math.min(canvasWidth / imageWidth, canvasHeight / imageHeight)
|
const fitScale = Math.min(canvasWidth / imageWidth, canvasHeight / imageHeight)
|
||||||
if (fitScale > 0) {
|
if (fitScale > 0) {
|
||||||
// zoom=1 通常是 fit-to-window,这里换算为图像接近 1:1 像素显示
|
|
||||||
viewport.setZoom(1 / fitScale)
|
viewport.setZoom(1 / fitScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewport.render()
|
viewport.render()
|
||||||
|
this.setFullScreen(index)
|
||||||
},
|
},
|
||||||
voiChange(v) {
|
voiChange(v) {
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||||
|
|
@ -656,13 +658,12 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
viewport.render()
|
viewport.render()
|
||||||
if (this.series.Modality === 'PT') {
|
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
// viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
||||||
viewport.resetProperties()
|
// viewport.resetProperties()
|
||||||
viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
|
viewport.setProperties({ voiRange: { upper: 5, lower: 0 }, invert: true }, this.volumeId)
|
||||||
viewport.render()
|
viewport.render()
|
||||||
renderingEngine.render()
|
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, null, this.actionConfiguration, this.segmentationId, this.segmentIndex)
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, null, this.actionConfiguration, this.segmentationId, this.segmentIndex)
|
||||||
|
|
@ -701,7 +702,7 @@ export default {
|
||||||
ijk[2] = viewport.getCurrentImageIdIndex()
|
ijk[2] = viewport.getCurrentImageIdIndex()
|
||||||
let modalityUnit
|
let modalityUnit
|
||||||
if (modality === 'US') {
|
if (modality === 'US') {
|
||||||
const calibratedResults = cornerstoneTools.utilities.getCalibratedProbeUnitsAndValue(image, [ijk])
|
const calibratedResults = cornerstoneTools.utilities.getCalibratedProbeUnitsAndValue(data, [ijk])
|
||||||
const hasEnhancedRegionValues = calibratedResults.values.every(
|
const hasEnhancedRegionValues = calibratedResults.values.every(
|
||||||
(value) => value !== null
|
(value) => value !== null
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,21 @@
|
||||||
<div :style="{ top: sliderInfo.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
|
<div :style="{ top: sliderInfo.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
|
||||||
@mousedown.stop="sliderMousedown($event)" />
|
@mousedown.stop="sliderMousedown($event)" />
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="annotationContextMenu.visible"
|
||||||
|
ref="annotation-context-menu"
|
||||||
|
class="annotation-context-menu"
|
||||||
|
:style="{ left: `${annotationContextMenu.x}px`, top: `${annotationContextMenu.y}px` }"
|
||||||
|
@mousedown.stop
|
||||||
|
@mouseup.stop
|
||||||
|
@click.stop
|
||||||
|
@contextmenu.prevent
|
||||||
|
>
|
||||||
|
<div class="annotation-context-menu__item" @click.stop="copyCircleAnnotation()">
|
||||||
|
<!-- 复制 -->
|
||||||
|
{{ $t('trials:reading:menu:copy') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -98,7 +113,7 @@ import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
|
||||||
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
|
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
|
||||||
|
|
||||||
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
|
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
|
||||||
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
|
import setCtTransferFunctionForVolumeActor, { setCtMappingRange } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
|
||||||
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
|
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
|
||||||
import {
|
import {
|
||||||
setMipTransferFunctionForVolumeActor,
|
setMipTransferFunctionForVolumeActor,
|
||||||
|
|
@ -108,6 +123,15 @@ import setNmFusionColorMapTransferFunctionForVolumeActor from './helpers/setNmFu
|
||||||
const { BlendModes, OrientationAxis } = Enums;
|
const { BlendModes, OrientationAxis } = Enums;
|
||||||
const { getColormap } = csUtils.colormap;
|
const { getColormap } = csUtils.colormap;
|
||||||
import { vec3, mat4 } from 'gl-matrix'
|
import { vec3, mat4 } from 'gl-matrix'
|
||||||
|
const DEFAULT_COLOR_MAP_UPPER = 6
|
||||||
|
|
||||||
|
function getVoiValue(value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return Number(value[0])
|
||||||
|
}
|
||||||
|
return Number(value)
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ImageViewport',
|
name: 'ImageViewport',
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -180,7 +204,13 @@ export default {
|
||||||
Colorbar: null,
|
Colorbar: null,
|
||||||
fusionOpacity: 0.95,
|
fusionOpacity: 0.95,
|
||||||
topFusionVolumeActor: null,
|
topFusionVolumeActor: null,
|
||||||
currentVoiUpper: null
|
currentVoiUpper: null,
|
||||||
|
annotationContextMenu: {
|
||||||
|
visible: false,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
annotation: null,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -200,7 +230,7 @@ export default {
|
||||||
renderingEngine.resize(true, false)
|
renderingEngine.resize(true, false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.element.oncontextmenu = (e) => e.preventDefault()
|
this.element.oncontextmenu = this.handleElementContextMenu
|
||||||
// resizeObserver.observe(this.element)
|
// resizeObserver.observe(this.element)
|
||||||
this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage)
|
this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage)
|
||||||
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
|
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
|
||||||
|
|
@ -213,9 +243,303 @@ export default {
|
||||||
})
|
})
|
||||||
document.addEventListener('mouseup', this.handleDocumentMouseUp)
|
document.addEventListener('mouseup', this.handleDocumentMouseUp)
|
||||||
document.addEventListener('mousemove', this.handleDocumentMouseMove)
|
document.addEventListener('mousemove', this.handleDocumentMouseMove)
|
||||||
|
document.addEventListener('mousedown', this.handleDocumentMouseDown)
|
||||||
// console.log(cornerstoneTools)
|
// console.log(cornerstoneTools)
|
||||||
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
|
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
|
||||||
},
|
},
|
||||||
|
getViewportInstance() {
|
||||||
|
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||||
|
return renderingEngine?.getViewport(this.viewportId)
|
||||||
|
},
|
||||||
|
hideAnnotationContextMenu() {
|
||||||
|
if (!this.annotationContextMenu.visible) return
|
||||||
|
this.annotationContextMenu.visible = false
|
||||||
|
this.annotationContextMenu.annotation = null
|
||||||
|
},
|
||||||
|
handleDocumentMouseDown(e) {
|
||||||
|
const menu = this.$refs['annotation-context-menu']
|
||||||
|
if (menu && menu.contains(e.target)) return
|
||||||
|
this.hideAnnotationContextMenu()
|
||||||
|
},
|
||||||
|
handleElementContextMenu(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
if (this.series.Modality !== 'NM') return false
|
||||||
|
const annotation = this.getCircleAnnotationFromContextMenuEvent(e)
|
||||||
|
if (!annotation) {
|
||||||
|
this.hideAnnotationContextMenu()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cornerstoneTools.annotation.locking.isAnnotationLocked(annotation.annotationUID)) {
|
||||||
|
this.hideAnnotationContextMenu()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('activeViewport', this.viewportIndex)
|
||||||
|
|
||||||
|
const { x, y } = this.getContextMenuPosition(e)
|
||||||
|
this.annotationContextMenu.visible = true
|
||||||
|
this.annotationContextMenu.x = x
|
||||||
|
this.annotationContextMenu.y = y
|
||||||
|
this.annotationContextMenu.annotation = annotation
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
getContextMenuPosition(e) {
|
||||||
|
const rect = this.element?.getBoundingClientRect?.()
|
||||||
|
if (!rect) {
|
||||||
|
return { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuWidth = 128
|
||||||
|
const menuHeight = 40
|
||||||
|
const padding = 8
|
||||||
|
const maxX = Math.max(padding, rect.width - menuWidth - padding)
|
||||||
|
const maxY = Math.max(padding, rect.height - menuHeight - padding)
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: Math.min(Math.max(e.clientX - rect.left, padding), maxX),
|
||||||
|
y: Math.min(Math.max(e.clientY - rect.top, padding), maxY),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getCircleAnnotationFromContextMenuEvent(e) {
|
||||||
|
const viewport = this.getViewportInstance()
|
||||||
|
if (!viewport || !this.element) return null
|
||||||
|
|
||||||
|
const rect = this.element.getBoundingClientRect()
|
||||||
|
const canvasPoint = [e.clientX - rect.left, e.clientY - rect.top]
|
||||||
|
const currentVisitTaskId = this.series?.TaskInfo?.VisitTaskId
|
||||||
|
const toolNames = ['CircleROI'] //FixedRadiusCircleROI看后期是不是要补充
|
||||||
|
const candidates = []
|
||||||
|
|
||||||
|
toolNames.forEach((toolName) => {
|
||||||
|
const annotations = cornerstoneTools.annotation.state.getAnnotations(toolName, this.element) || []
|
||||||
|
annotations.forEach((annotation) => {
|
||||||
|
if (!annotation?.data?.handles?.points?.length) return
|
||||||
|
if (currentVisitTaskId && annotation.visitTaskId && annotation.visitTaskId !== currentVisitTaskId) return
|
||||||
|
|
||||||
|
const hitInfo = this.getCircleAnnotationHitInfo(annotation, canvasPoint, viewport)
|
||||||
|
if (!hitInfo.hit || hitInfo.score === null) return
|
||||||
|
|
||||||
|
candidates.push({
|
||||||
|
annotation,
|
||||||
|
score: hitInfo.score,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!candidates.length) return null
|
||||||
|
|
||||||
|
candidates.sort((a, b) => a.score - b.score)
|
||||||
|
return candidates[0].annotation
|
||||||
|
},
|
||||||
|
getCircleAnnotationHitInfo(annotation, canvasPoint, viewport) {
|
||||||
|
const points = annotation?.data?.handles?.points || []
|
||||||
|
if (points.length < 2) {
|
||||||
|
return { hit: false, score: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
const centerCanvas = viewport.worldToCanvas(points[0]) // 圆心
|
||||||
|
const edgeCanvas = viewport.worldToCanvas(points[1]) // 边缘点
|
||||||
|
const radius = this.distanceToPoint(centerCanvas, edgeCanvas)
|
||||||
|
if (radius <= 0) {
|
||||||
|
return { hit: false, score: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
const dx = canvasPoint[0] - centerCanvas[0]
|
||||||
|
const dy = canvasPoint[1] - centerCanvas[1]
|
||||||
|
const distance = (dx * dx + dy * dy) / (radius * radius)
|
||||||
|
const hit = distance <= 1.2
|
||||||
|
|
||||||
|
return {
|
||||||
|
hit,
|
||||||
|
score: hit ? distance : null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createCopiedCachedStats(sourceCachedStats = {}) {
|
||||||
|
const cloned = JSON.parse(JSON.stringify(sourceCachedStats || {}))
|
||||||
|
const keys = Object.keys(cloned)
|
||||||
|
|
||||||
|
if (!keys.length) {
|
||||||
|
const fallbackKey = this.isFusion ? (this.ptVolumeId || this.volumeId) : this.volumeId
|
||||||
|
if (fallbackKey) {
|
||||||
|
cloned[fallbackKey] = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(cloned).forEach((key) => {
|
||||||
|
cloned[key] = {
|
||||||
|
...cloned[key],
|
||||||
|
area: null,
|
||||||
|
count: null,
|
||||||
|
isEmptyArea: null,
|
||||||
|
max: null,
|
||||||
|
mean: null,
|
||||||
|
min: null,
|
||||||
|
perimeter: null,
|
||||||
|
pointsInShape: null,
|
||||||
|
radius: null,
|
||||||
|
statsArray: [],
|
||||||
|
stdDev: null,
|
||||||
|
total: null,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return cloned
|
||||||
|
},
|
||||||
|
getCopySide(sourceCenterCanvas, radius) {
|
||||||
|
const canvasWidth = this.element.clientWidth || 0
|
||||||
|
const padding = Math.max(radius * 0.5, 8)
|
||||||
|
const requiredSpace = Math.max(radius * 2.1, 16) + padding // 放置新标注所需要的空间
|
||||||
|
const leftSpace = sourceCenterCanvas[0] - padding
|
||||||
|
const rightSpace = canvasWidth - sourceCenterCanvas[0] - padding
|
||||||
|
|
||||||
|
const canPlaceLeft = leftSpace >= requiredSpace
|
||||||
|
const canPlaceRight = rightSpace >= requiredSpace
|
||||||
|
|
||||||
|
if (canPlaceLeft && canPlaceRight) {
|
||||||
|
return rightSpace >= leftSpace ? 'right' : 'left'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canPlaceRight) {
|
||||||
|
return 'right'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canPlaceLeft) {
|
||||||
|
return 'left'
|
||||||
|
}
|
||||||
|
|
||||||
|
return rightSpace >= leftSpace ? 'right' : 'left'
|
||||||
|
},
|
||||||
|
buildCopiedCircleAnnotation(sourceAnnotation, side) {
|
||||||
|
const viewport = this.getViewportInstance()
|
||||||
|
if (!viewport) return null
|
||||||
|
|
||||||
|
const points = sourceAnnotation.data.handles.points || []
|
||||||
|
if (points.length < 2) return null
|
||||||
|
|
||||||
|
const sourceCenterCanvas = viewport.worldToCanvas(points[0])
|
||||||
|
const sourceEdgeCanvas = viewport.worldToCanvas(points[1])
|
||||||
|
|
||||||
|
const radiusVector = [
|
||||||
|
sourceEdgeCanvas[0] - sourceCenterCanvas[0],
|
||||||
|
sourceEdgeCanvas[1] - sourceCenterCanvas[1],
|
||||||
|
]
|
||||||
|
const radius = this.distanceToPoint(sourceCenterCanvas, sourceEdgeCanvas)
|
||||||
|
if (radius <= 0) return null
|
||||||
|
|
||||||
|
const offsetDirection = side === 'left' ? -1 : 1
|
||||||
|
const offsetDistance = Math.max(radius * 2.1, 16)
|
||||||
|
const padding = Math.max(radius * 0.5, 8)
|
||||||
|
const canvasWidth = this.element?.clientWidth || 0
|
||||||
|
const canvasHeight = this.element?.clientHeight || 0
|
||||||
|
const targetCenterCanvas = [
|
||||||
|
sourceCenterCanvas[0] + offsetDirection * offsetDistance,
|
||||||
|
sourceCenterCanvas[1],
|
||||||
|
]
|
||||||
|
|
||||||
|
if (canvasWidth > 0) {
|
||||||
|
targetCenterCanvas[0] = Math.min(Math.max(targetCenterCanvas[0], padding), canvasWidth - padding)
|
||||||
|
}
|
||||||
|
if (canvasHeight > 0) {
|
||||||
|
targetCenterCanvas[1] = Math.min(Math.max(targetCenterCanvas[1], padding), canvasHeight - padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetEdgeCanvas = [
|
||||||
|
targetCenterCanvas[0] + radiusVector[0],
|
||||||
|
targetCenterCanvas[1] + radiusVector[1],
|
||||||
|
]
|
||||||
|
const centerWorld = viewport.canvasToWorld(targetCenterCanvas)
|
||||||
|
const edgeWorld = viewport.canvasToWorld(targetEdgeCanvas)
|
||||||
|
const camera = viewport.getCamera()
|
||||||
|
|
||||||
|
return {
|
||||||
|
highlighted: true,
|
||||||
|
invalidated: true,
|
||||||
|
metadata: {
|
||||||
|
toolName: sourceAnnotation.metadata?.toolName || 'CircleROI',
|
||||||
|
viewPlaneNormal: [...(camera?.viewPlaneNormal || sourceAnnotation.metadata?.viewPlaneNormal || [])],
|
||||||
|
viewUp: [...(camera?.viewUp || sourceAnnotation.metadata?.viewUp || [])],
|
||||||
|
FrameOfReferenceUID: viewport.getFrameOfReferenceUID(),
|
||||||
|
referencedImageId: sourceAnnotation.metadata?.referencedImageId || viewport.getCurrentImageId?.(),
|
||||||
|
...viewport.getViewReference({ points: [centerWorld] }),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
label: '',
|
||||||
|
handles: {
|
||||||
|
textBox: {
|
||||||
|
hasMoved: false,
|
||||||
|
worldPosition: [0, 0, 0],
|
||||||
|
worldBoundingBox: {
|
||||||
|
topLeft: [0, 0, 0],
|
||||||
|
topRight: [0, 0, 0],
|
||||||
|
bottomLeft: [0, 0, 0],
|
||||||
|
bottomRight: [0, 0, 0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
points: [[...centerWorld], [...edgeWorld]],
|
||||||
|
activeHandleIndex: null,
|
||||||
|
},
|
||||||
|
cachedStats: this.createCopiedCachedStats(sourceAnnotation.data?.cachedStats),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
copyCircleAnnotation(side) {
|
||||||
|
const sourceAnnotation = this.annotationContextMenu.annotation
|
||||||
|
this.hideAnnotationContextMenu()
|
||||||
|
|
||||||
|
if (!sourceAnnotation || !this.element) return
|
||||||
|
|
||||||
|
let targetSide = side
|
||||||
|
if (!targetSide) {
|
||||||
|
const viewport = this.getViewportInstance()
|
||||||
|
const points = sourceAnnotation.data.handles.points || []
|
||||||
|
if (!viewport || points.length < 2) return
|
||||||
|
|
||||||
|
const sourceCenterCanvas = viewport.worldToCanvas(points[0])
|
||||||
|
const sourceEdgeCanvas = viewport.worldToCanvas(points[1])
|
||||||
|
if (
|
||||||
|
!Array.isArray(sourceCenterCanvas) ||sourceCenterCanvas.length < 2 || !Array.isArray(sourceEdgeCanvas) || sourceEdgeCanvas.length < 2
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const radius = this.distanceToPoint(sourceCenterCanvas, sourceEdgeCanvas)
|
||||||
|
if (radius <= 0) return
|
||||||
|
|
||||||
|
targetSide = this.getCopySide(sourceCenterCanvas, radius)
|
||||||
|
}
|
||||||
|
|
||||||
|
const annotation = this.buildCopiedCircleAnnotation(sourceAnnotation, targetSide)
|
||||||
|
if (!annotation) return
|
||||||
|
|
||||||
|
cornerstoneTools.annotation.state.addAnnotation(annotation, this.element)
|
||||||
|
|
||||||
|
const viewportIdsToRender = cornerstoneTools.utilities.viewportFilters.getViewportIdsWithToolToRender(
|
||||||
|
this.element,
|
||||||
|
annotation.metadata.toolName
|
||||||
|
)
|
||||||
|
cornerstoneTools.utilities.triggerAnnotationRenderForViewportIds(viewportIdsToRender)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
cornerstoneTools.annotation.state.triggerAnnotationCompleted(annotation)
|
||||||
|
}, 0)
|
||||||
|
},
|
||||||
|
distanceToPoint(p1, p2) {
|
||||||
|
return Math.sqrt(this.distanceToPointSquared(p1, p2))
|
||||||
|
},
|
||||||
|
distanceToPointSquared(p1, p2) {
|
||||||
|
if (p1.length !== p2.length) {
|
||||||
|
throw Error('Both points should have the same dimensionality')
|
||||||
|
}
|
||||||
|
const [x1, y1, z1 = 0] = p1
|
||||||
|
const [x2, y2, z2 = 0] = p2
|
||||||
|
const dx = x2 - x1
|
||||||
|
const dy = y2 - y1
|
||||||
|
const dz = z2 - z1
|
||||||
|
|
||||||
|
return dx * dx + dy * dy + dz * dz
|
||||||
|
},
|
||||||
handleDocumentMouseUp(e) {
|
handleDocumentMouseUp(e) {
|
||||||
this.sliderMouseup(e)
|
this.sliderMouseup(e)
|
||||||
if (this.isMip) {
|
if (this.isMip) {
|
||||||
|
|
@ -254,8 +578,10 @@ export default {
|
||||||
|
|
||||||
if (properties && properties.voiRange) {
|
if (properties && properties.voiRange) {
|
||||||
var { lower, upper } = properties.voiRange
|
var { lower, upper } = properties.voiRange
|
||||||
const windowWidth = upper - lower
|
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
|
||||||
const windowCenter = (upper + lower) / 2
|
lower,
|
||||||
|
upper
|
||||||
|
)
|
||||||
this.defaultWindowLevel.windowWidth = windowWidth
|
this.defaultWindowLevel.windowWidth = windowWidth
|
||||||
this.defaultWindowLevel.windowCenter = windowCenter
|
this.defaultWindowLevel.windowCenter = windowCenter
|
||||||
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
|
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
|
||||||
|
|
@ -588,8 +914,27 @@ export default {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getInitialWindowLevelFromVolumeId(volumeId) {
|
||||||
|
if (!volumeId) return null
|
||||||
|
const volume = cache.getVolume(volumeId)
|
||||||
|
const imageId = volume?.imageIds?.[0]
|
||||||
|
if (!imageId) return null
|
||||||
|
|
||||||
|
const voiLutModule = metaData.get('voiLutModule', imageId)
|
||||||
|
const windowCenter = getVoiValue(voiLutModule?.windowCenter)
|
||||||
|
const windowWidth = getVoiValue(voiLutModule?.windowWidth)
|
||||||
|
|
||||||
|
if (windowWidth <= 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
windowCenter,
|
||||||
|
windowWidth,
|
||||||
|
}
|
||||||
|
},
|
||||||
getFusionVolumes() {
|
getFusionVolumes() {
|
||||||
const ctVolumeId = this.ctSeries?.SeriesInstanceUid
|
const ctVolumeId = this.ctSeries.SeriesInstanceUid
|
||||||
const ptFusionVolumeId = this.ptVolumeId
|
const ptFusionVolumeId = this.ptVolumeId
|
||||||
if (!ctVolumeId || !ptFusionVolumeId) {
|
if (!ctVolumeId || !ptFusionVolumeId) {
|
||||||
return []
|
return []
|
||||||
|
|
@ -598,6 +943,10 @@ export default {
|
||||||
const ctEntry = {
|
const ctEntry = {
|
||||||
volumeId: ctVolumeId,
|
volumeId: ctVolumeId,
|
||||||
callback: (r) => {
|
callback: (r) => {
|
||||||
|
const ctWindowLevel = this.getInitialWindowLevelFromVolumeId(ctVolumeId)
|
||||||
|
if (ctWindowLevel) {
|
||||||
|
setCtMappingRange(ctWindowLevel.windowWidth, ctWindowLevel.windowCenter)
|
||||||
|
}
|
||||||
setCtTransferFunctionForVolumeActor({ ...r, volumeId: ctVolumeId })
|
setCtTransferFunctionForVolumeActor({ ...r, volumeId: ctVolumeId })
|
||||||
if (this.fusionCtOnTop) {
|
if (this.fusionCtOnTop) {
|
||||||
this.topFusionVolumeActor = r.volumeActor
|
this.topFusionVolumeActor = r.volumeActor
|
||||||
|
|
@ -656,13 +1005,13 @@ export default {
|
||||||
async applyFusionRenderOrder() {
|
async applyFusionRenderOrder() {
|
||||||
if (!this.isFusion) return
|
if (!this.isFusion) return
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||||
const viewport = renderingEngine?.getViewport?.(this.viewportId)
|
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||||
if (!viewport) return
|
if (!viewport) return
|
||||||
|
|
||||||
const volumes = this.getFusionVolumes()
|
const volumes = this.getFusionVolumes()
|
||||||
if (!volumes.length) return
|
if (!volumes.length) return
|
||||||
|
|
||||||
const camera = viewport.getCamera?.()
|
const camera = viewport.getCamera()
|
||||||
|
|
||||||
const savedVoiUpper = this.currentVoiUpper
|
const savedVoiUpper = this.currentVoiUpper
|
||||||
|
|
||||||
|
|
@ -694,6 +1043,7 @@ export default {
|
||||||
if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex });
|
if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex });
|
||||||
this.volumeId = data.SeriesInstanceUid
|
this.volumeId = data.SeriesInstanceUid
|
||||||
this.ptVolumeId = null
|
this.ptVolumeId = null
|
||||||
|
this.currentVoiUpper = null
|
||||||
this.series = {}
|
this.series = {}
|
||||||
this.topFusionVolumeActor = null
|
this.topFusionVolumeActor = null
|
||||||
let { isFusion, isMip, colorMap } = option
|
let { isFusion, isMip, colorMap } = option
|
||||||
|
|
@ -705,6 +1055,7 @@ export default {
|
||||||
this.renderColorBar(this.presetName)
|
this.renderColorBar(this.presetName)
|
||||||
})
|
})
|
||||||
this.ptVolumeId = `fusion_${this.volumeId}`
|
this.ptVolumeId = `fusion_${this.volumeId}`
|
||||||
|
this.currentVoiUpper = DEFAULT_COLOR_MAP_UPPER
|
||||||
let { ct, data } = obj
|
let { ct, data } = obj
|
||||||
this.series = { ...data }
|
this.series = { ...data }
|
||||||
this.ctSeries = { ...ct }
|
this.ctSeries = { ...ct }
|
||||||
|
|
@ -715,6 +1066,7 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.series = { ...data }
|
this.series = { ...data }
|
||||||
if (this.isMip) {
|
if (this.isMip) {
|
||||||
|
this.currentVoiUpper = DEFAULT_COLOR_MAP_UPPER
|
||||||
let volume = cache.getVolume(this.volumeId)
|
let volume = cache.getVolume(this.volumeId)
|
||||||
const ptVolumeDimensions = volume.dimensions
|
const ptVolumeDimensions = volume.dimensions
|
||||||
const slabThickness = Math.sqrt(
|
const slabThickness = Math.sqrt(
|
||||||
|
|
@ -747,9 +1099,14 @@ export default {
|
||||||
.setVolumes([{
|
.setVolumes([{
|
||||||
volumeId: this.volumeId, callback: (r) => {
|
volumeId: this.volumeId, callback: (r) => {
|
||||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||||
|
this.currentVoiUpper = DEFAULT_COLOR_MAP_UPPER
|
||||||
// setPetColorMapTransferFunctionForVolumeActor(r, true)
|
// setPetColorMapTransferFunctionForVolumeActor(r, true)
|
||||||
setPetTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
setPetTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
||||||
} else {
|
} else {
|
||||||
|
const ctWindowLevel = this.getInitialWindowLevelFromVolumeId(this.volumeId)
|
||||||
|
if (ctWindowLevel) {
|
||||||
|
setCtMappingRange(ctWindowLevel.windowWidth, ctWindowLevel.windowCenter)
|
||||||
|
}
|
||||||
setCtTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
setCtTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -758,7 +1115,9 @@ export default {
|
||||||
|
|
||||||
}
|
}
|
||||||
viewport.render()
|
viewport.render()
|
||||||
this.voiChange(this.currentVoiUpper)
|
if (this.currentVoiUpper > 0) {
|
||||||
|
this.voiChange(this.currentVoiUpper)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
@ -788,7 +1147,7 @@ export default {
|
||||||
ijk[2] = viewport.getCurrentImageIdIndex()
|
ijk[2] = viewport.getCurrentImageIdIndex()
|
||||||
let modalityUnit
|
let modalityUnit
|
||||||
if (modality === 'US') {
|
if (modality === 'US') {
|
||||||
const calibratedResults = cornerstoneTools.utilities.getCalibratedProbeUnitsAndValue(image, [ijk])
|
const calibratedResults = cornerstoneTools.utilities.getCalibratedProbeUnitsAndValue(data, [ijk])
|
||||||
const hasEnhancedRegionValues = calibratedResults.values.every(
|
const hasEnhancedRegionValues = calibratedResults.values.every(
|
||||||
(value) => value !== null
|
(value) => value !== null
|
||||||
)
|
)
|
||||||
|
|
@ -982,8 +1341,13 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
this.hideAnnotationContextMenu()
|
||||||
|
if (this.element) {
|
||||||
|
this.element.oncontextmenu = null
|
||||||
|
}
|
||||||
document.removeEventListener('mouseup', this.handleDocumentMouseUp)
|
document.removeEventListener('mouseup', this.handleDocumentMouseUp)
|
||||||
document.removeEventListener('mousemove', this.handleDocumentMouseMove)
|
document.removeEventListener('mousemove', this.handleDocumentMouseMove)
|
||||||
|
document.removeEventListener('mousedown', this.handleDocumentMouseDown)
|
||||||
this.series = null
|
this.series = null
|
||||||
this.topFusionVolumeActor = null
|
this.topFusionVolumeActor = null
|
||||||
},
|
},
|
||||||
|
|
@ -1001,6 +1365,30 @@ export default {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
|
|
||||||
|
.annotation-context-menu {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 30;
|
||||||
|
min-width: 120px;
|
||||||
|
padding: 4px 0;
|
||||||
|
background: rgba(24, 24, 24, 0.96);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ddd;
|
||||||
|
line-height: 1.2;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.opacity-slider-wrapper {
|
.opacity-slider-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,12 @@
|
||||||
@click.prevent="openFusion">
|
@click.prevent="openFusion">
|
||||||
<svg-icon icon-class="fusion" class="svg-icon" />
|
<svg-icon icon-class="fusion" class="svg-icon" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isFusion"
|
||||||
|
:class="['tool-item', activeTool === 'FusionJumpToPointTool' ? 'tool-item-active' : '']"
|
||||||
|
:title="$t('trials:reading:button:crosshairsPosition')"
|
||||||
|
@click.prevent="setToolActive('FusionJumpToPointTool')">
|
||||||
|
<svg-icon icon-class="position" class="svg-icon" />
|
||||||
|
</div>
|
||||||
<div v-for="tool in tools" :key="tool.toolName"
|
<div v-for="tool in tools" :key="tool.toolName"
|
||||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']"
|
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']"
|
||||||
:style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }"
|
:style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }"
|
||||||
|
|
@ -576,9 +582,11 @@ import FusionForm from './FusionForm.vue'
|
||||||
import SegmentForm from './SegmentForm.vue'
|
import SegmentForm from './SegmentForm.vue'
|
||||||
import colorMap from './colorMap.vue'
|
import colorMap from './colorMap.vue'
|
||||||
import RectangleROITool from './tools/RectangleROITool'
|
import RectangleROITool from './tools/RectangleROITool'
|
||||||
|
import CircleROITool from './tools/CircleROITool'
|
||||||
import ScaleOverlayTool from './tools/ScaleOverlayTool'
|
import ScaleOverlayTool from './tools/ScaleOverlayTool'
|
||||||
import SegmentBidirectionalTool from './tools/SegmentBidirectionalTool'
|
import SegmentBidirectionalTool from './tools/SegmentBidirectionalTool'
|
||||||
import FusionJumpToPointTool from './tools/FusionJumpToPointTool'
|
import FusionJumpToPointTool from './tools/FusionJumpToPointTool'
|
||||||
|
import MIPJumpToClickTool from './tools/MIPJumpToClickTool'
|
||||||
import { setPTClinicalDataForInstance, clearPTClinicalDataCache } from '@/utils/ptClinicalDataCache'
|
import { setPTClinicalDataForInstance, clearPTClinicalDataCache } from '@/utils/ptClinicalDataCache'
|
||||||
import FixedRadiusCircleROITool from './tools/FixedRadiusCircleROITool'
|
import FixedRadiusCircleROITool from './tools/FixedRadiusCircleROITool'
|
||||||
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
|
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
|
||||||
|
|
@ -590,6 +598,8 @@ import md5 from 'js-md5'
|
||||||
const { visibility } = annotation
|
const { visibility } = annotation
|
||||||
const { ViewportType, Events } = Enums
|
const { ViewportType, Events } = Enums
|
||||||
const renderingEngineId = 'myRenderingEngine'
|
const renderingEngineId = 'myRenderingEngine'
|
||||||
|
const DEFAULT_FUSION_COLOR_MAP_RANGE = 40
|
||||||
|
const DEFAULT_FUSION_COLOR_MAP_UPPER = 6
|
||||||
const {
|
const {
|
||||||
ToolGroupManager,
|
ToolGroupManager,
|
||||||
Enums: csToolsEnums,
|
Enums: csToolsEnums,
|
||||||
|
|
@ -608,7 +618,6 @@ const {
|
||||||
ArrowAnnotateTool,
|
ArrowAnnotateTool,
|
||||||
// RectangleROITool,
|
// RectangleROITool,
|
||||||
PlanarFreehandROITool,
|
PlanarFreehandROITool,
|
||||||
CircleROITool,
|
|
||||||
AngleTool,
|
AngleTool,
|
||||||
CobbAngleTool,
|
CobbAngleTool,
|
||||||
EraserTool,
|
EraserTool,
|
||||||
|
|
@ -647,7 +656,7 @@ const newStyles = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
annotation.config.style.setDefaultToolStyles(newStyles)
|
annotation.config.style.setDefaultToolStyles(newStyles)
|
||||||
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
const { MouseBindings, Events: toolsEvents, ChangeTypes } = csToolsEnums
|
||||||
export default {
|
export default {
|
||||||
name: 'ReadPage',
|
name: 'ReadPage',
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -968,7 +977,6 @@ export default {
|
||||||
this.tools = getCustomizeStandardsTools(this.taskInfo.ReadingToolList)
|
this.tools = getCustomizeStandardsTools(this.taskInfo.ReadingToolList)
|
||||||
const toolNames = this.tools.map(i => i.toolName)
|
const toolNames = this.tools.map(i => i.toolName)
|
||||||
this.customizeStandards = config.customizeStandards.filter(item => !toolNames.includes(item.toolName))
|
this.customizeStandards = config.customizeStandards.filter(item => !toolNames.includes(item.toolName))
|
||||||
console.log(this.customizeStandards, 'this.customizeStandards')
|
|
||||||
} else {
|
} else {
|
||||||
this.tools = getTools(this.criterionType)
|
this.tools = getTools(this.criterionType)
|
||||||
}
|
}
|
||||||
|
|
@ -1052,7 +1060,6 @@ export default {
|
||||||
let imageId = imageIds[0]
|
let imageId = imageIds[0]
|
||||||
const imagePixelModule = metaData.get('imagePixelModule', imageId);
|
const imagePixelModule = metaData.get('imagePixelModule', imageId);
|
||||||
const photometricInterpretation = imagePixelModule?.photometricInterpretation;
|
const photometricInterpretation = imagePixelModule?.photometricInterpretation;
|
||||||
console.log(photometricInterpretation, 'photometricInterpretation')
|
|
||||||
if (photometricInterpretation && photometricInterpretation !== 'MONOCHROME1' && photometricInterpretation !== 'MONOCHROME2') return this.$confirm(this.$t('trials:histogram:confirm:photometricInterpretationNotSupported'))
|
if (photometricInterpretation && photometricInterpretation !== 'MONOCHROME1' && photometricInterpretation !== 'MONOCHROME2') return this.$confirm(this.$t('trials:histogram:confirm:photometricInterpretationNotSupported'))
|
||||||
this.histogramVisible = true
|
this.histogramVisible = true
|
||||||
this.setToolsPassive()
|
this.setToolsPassive()
|
||||||
|
|
@ -1553,6 +1560,7 @@ export default {
|
||||||
cornerstoneTools.addTool(AngleTool)
|
cornerstoneTools.addTool(AngleTool)
|
||||||
cornerstoneTools.addTool(CobbAngleTool)
|
cornerstoneTools.addTool(CobbAngleTool)
|
||||||
cornerstoneTools.addTool(FusionJumpToPointTool)
|
cornerstoneTools.addTool(FusionJumpToPointTool)
|
||||||
|
cornerstoneTools.addTool(MIPJumpToClickTool)
|
||||||
cornerstoneTools.addTool(VolumeRotateTool)
|
cornerstoneTools.addTool(VolumeRotateTool)
|
||||||
cornerstoneTools.addTool(CrosshairsTool)
|
cornerstoneTools.addTool(CrosshairsTool)
|
||||||
cornerstoneTools.addTool(LabelMapEditWithContourTool)
|
cornerstoneTools.addTool(LabelMapEditWithContourTool)
|
||||||
|
|
@ -1721,6 +1729,10 @@ export default {
|
||||||
})
|
})
|
||||||
if (viewportId === 'viewport-fusion-3') {
|
if (viewportId === 'viewport-fusion-3') {
|
||||||
toolGroup.addTool(VolumeRotateTool.toolName)
|
toolGroup.addTool(VolumeRotateTool.toolName)
|
||||||
|
toolGroup.addTool(MIPJumpToClickTool.toolName, {
|
||||||
|
targetViewportIds: ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3', 'viewport-fusion-hidden-sag'],
|
||||||
|
sourceViewportIds: ['viewport-fusion-3'],
|
||||||
|
})
|
||||||
toolGroup.addTool(FusionJumpToPointTool.toolName, {
|
toolGroup.addTool(FusionJumpToPointTool.toolName, {
|
||||||
targetViewportIds: ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3', 'viewport-fusion-hidden-sag'],
|
targetViewportIds: ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3', 'viewport-fusion-hidden-sag'],
|
||||||
useBrightestPoint: true,
|
useBrightestPoint: true,
|
||||||
|
|
@ -1736,6 +1748,10 @@ export default {
|
||||||
mipViewportIds: ['viewport-fusion-3'],
|
mipViewportIds: ['viewport-fusion-3'],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
|
})
|
||||||
|
|
||||||
toolGroup.setToolActive(VolumeRotateTool.toolName, {
|
toolGroup.setToolActive(VolumeRotateTool.toolName, {
|
||||||
bindings: [
|
bindings: [
|
||||||
{
|
{
|
||||||
|
|
@ -1933,12 +1949,6 @@ export default {
|
||||||
// this.toolModeChanged
|
// this.toolModeChanged
|
||||||
// )
|
// )
|
||||||
},
|
},
|
||||||
toolModeChanged(e) {
|
|
||||||
console.log(e)
|
|
||||||
const arr = cornerstoneTools.annotation.state.getAllAnnotations()
|
|
||||||
// if (arr)
|
|
||||||
console.log(arr)
|
|
||||||
},
|
|
||||||
annotationAddedListener(e) {
|
annotationAddedListener(e) {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -1951,7 +1961,8 @@ export default {
|
||||||
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
|
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
|
||||||
if (this.readingTaskState === 2) return
|
if (this.readingTaskState === 2) return
|
||||||
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
||||||
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
|
let viewportIndex = this.isFusion ? 2 : this.activeViewportIndex
|
||||||
|
const series = this.$refs[`${this.viewportKey}-${viewportIndex}`][0].series
|
||||||
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
||||||
const referencedImageId = annotation.metadata.referencedImageId
|
const referencedImageId = annotation.metadata.referencedImageId
|
||||||
const params = this.getInstanceInfo(referencedImageId)
|
const params = this.getInstanceInfo(referencedImageId)
|
||||||
|
|
@ -1972,12 +1983,13 @@ export default {
|
||||||
},
|
},
|
||||||
annotationModifiedListener(e) {
|
annotationModifiedListener(e) {
|
||||||
console.log('Modified')
|
console.log('Modified')
|
||||||
const { annotation } = e.detail
|
const { annotation, changeType } = e.detail
|
||||||
|
const isStatsUpdated = changeType === ChangeTypes.StatsUpdated
|
||||||
if (!annotation) return
|
if (!annotation) return
|
||||||
if (annotation.metadata.toolName === FusionJumpToPointTool.toolName) return
|
if (annotation.metadata.toolName === FusionJumpToPointTool.toolName) return
|
||||||
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
|
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
|
||||||
if (this.readingTaskState === 2) return
|
if (this.readingTaskState === 2) return
|
||||||
if (!annotation.highlighted) return
|
if (!annotation.highlighted && !isStatsUpdated) return
|
||||||
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
||||||
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
|
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
|
||||||
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
||||||
|
|
@ -2019,6 +2031,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async customAnnotationCompletedListener(e) {
|
async customAnnotationCompletedListener(e) {
|
||||||
|
console.log('completed')
|
||||||
const { annotation } = e.detail
|
const { annotation } = e.detail
|
||||||
if (!annotation) return
|
if (!annotation) return
|
||||||
if (annotation.metadata.toolName === FusionJumpToPointTool.toolName) return
|
if (annotation.metadata.toolName === FusionJumpToPointTool.toolName) return
|
||||||
|
|
@ -2031,10 +2044,10 @@ export default {
|
||||||
}
|
}
|
||||||
if (annotation.metadata.segmentationId) return
|
if (annotation.metadata.segmentationId) return
|
||||||
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
||||||
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
|
let viewportIndex = this.isFusion ? 2 : this.activeViewportIndex
|
||||||
|
const series = this.$refs[`${this.viewportKey}-${viewportIndex}`][0].series
|
||||||
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
||||||
const referencedImageId = annotation.metadata.referencedImageId
|
const referencedImageId = annotation.metadata.referencedImageId
|
||||||
console.log(annotation, 'annotation')
|
|
||||||
const params = this.getInstanceInfo(referencedImageId)
|
const params = this.getInstanceInfo(referencedImageId)
|
||||||
annotation.visitTaskId = series.TaskInfo.VisitTaskId
|
annotation.visitTaskId = series.TaskInfo.VisitTaskId
|
||||||
annotation.studyId = series.StudyId
|
annotation.studyId = series.StudyId
|
||||||
|
|
@ -2108,7 +2121,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
customAnnotationModifiedListener(e) {
|
customAnnotationModifiedListener(e) {
|
||||||
const { annotation } = e.detail
|
console.log('modified')
|
||||||
|
const { annotation, changeType } = e.detail
|
||||||
|
const isStatsUpdated = changeType === ChangeTypes.StatsUpdated
|
||||||
if (!annotation) return
|
if (!annotation) return
|
||||||
if (annotation.metadata.toolName === FusionJumpToPointTool.toolName) return
|
if (annotation.metadata.toolName === FusionJumpToPointTool.toolName) return
|
||||||
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
|
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
|
||||||
|
|
@ -2210,7 +2225,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contentMouseup(e) {
|
contentMouseup(e) {
|
||||||
console.log('contentMouseup')
|
|
||||||
if (this.$refs.Segmentations) {
|
if (this.$refs.Segmentations) {
|
||||||
this.$refs.Segmentations.contentMouseup()
|
this.$refs.Segmentations.contentMouseup()
|
||||||
}
|
}
|
||||||
|
|
@ -2482,12 +2496,14 @@ export default {
|
||||||
getCircleROIToolTextLines(data, targetId) {
|
getCircleROIToolTextLines(data, targetId) {
|
||||||
const cachedVolumeStats = data.cachedStats[targetId]
|
const cachedVolumeStats = data.cachedStats[targetId]
|
||||||
const {
|
const {
|
||||||
|
Modality,
|
||||||
radius,
|
radius,
|
||||||
radiusUnit,
|
radiusUnit,
|
||||||
area,
|
area,
|
||||||
mean,
|
mean,
|
||||||
stdDev,
|
stdDev,
|
||||||
max,
|
max,
|
||||||
|
total,
|
||||||
isEmptyArea,
|
isEmptyArea,
|
||||||
areaUnit,
|
areaUnit,
|
||||||
modalityUnit
|
modalityUnit
|
||||||
|
|
@ -2512,12 +2528,16 @@ export default {
|
||||||
textLines.push(areaLine)
|
textLines.push(areaLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (total !== undefined && total !== null && Modality === 'NM') {
|
||||||
|
textLines.push(`Total: ${this.formatStatSum(total)}`)
|
||||||
|
}
|
||||||
|
|
||||||
if (mean) {
|
if (mean) {
|
||||||
textLines.push(`Mean: ${this.reRound(mean, this.digitPlaces)} ${modalityUnit}`)
|
textLines.push(`Mean: ${this.reRound(mean, this.digitPlaces)} ${modalityUnit}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max) {
|
if (max) {
|
||||||
textLines.push(`Max: ${this.reRound(max, this.digitPlaces)} ${modalityUnit}`)
|
textLines.push(`Max: ${this.reRound(max, Modality === 'NM' ? 0 : this.digitPlaces)} ${modalityUnit}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdDev) {
|
if (stdDev) {
|
||||||
|
|
@ -2615,6 +2635,16 @@ export default {
|
||||||
}
|
}
|
||||||
return this.processSingle(result, finalPrecision)
|
return this.processSingle(result, finalPrecision)
|
||||||
},
|
},
|
||||||
|
formatStatSum(value) {
|
||||||
|
const num = Number(value)
|
||||||
|
if (!Number.isFinite(num)) return value
|
||||||
|
|
||||||
|
if (Math.abs(num - Math.round(num)) < 1e-6) {
|
||||||
|
return String(Math.round(num))
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.reRound(num, this.digitPlaces)
|
||||||
|
},
|
||||||
processSingle(str, precision) {
|
processSingle(str, precision) {
|
||||||
const num = parseFloat(str)
|
const num = parseFloat(str)
|
||||||
if (isNaN(num)) return 'NaN'
|
if (isNaN(num)) return 'NaN'
|
||||||
|
|
@ -2645,37 +2675,78 @@ export default {
|
||||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||||
if (!renderingEngine) return
|
if (!renderingEngine) return
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
||||||
const instance = toolGroup?.getToolInstance(FusionJumpToPointTool.toolName)
|
if (!toolGroup) return
|
||||||
if (!instance?.setPoint) return
|
const instance = toolGroup.getToolInstance(FusionJumpToPointTool.toolName)
|
||||||
|
if (!instance || !instance.setPoint) return
|
||||||
|
|
||||||
instance.setPoint(worldPoint, viewportId, renderingEngine.id, {
|
instance.setPoint(worldPoint, viewportId, renderingEngine.id, {
|
||||||
jumpToTargetViewports: false,
|
jumpToTargetViewports: false,
|
||||||
dispatchEvent: false,
|
dispatchEvent: false,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setFusionMipJumpEnabled(enabled) {
|
setFusionMipClickEnabled(enabled) {
|
||||||
if (!this.isFusion) return
|
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
||||||
if (!toolGroup || !toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
|
if (!toolGroup || !toolGroup.hasTool(MIPJumpToClickTool.toolName)) return
|
||||||
|
if (enabled && this.isFusion) {
|
||||||
|
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
toolGroup.setToolDisabled(MIPJumpToClickTool.toolName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setFusionMipJumpEnabled(enabled) {
|
||||||
|
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
||||||
|
if (!toolGroup) return
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
this.setFusionMipClickEnabled(false)
|
||||||
|
if (!toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
|
||||||
|
if (!this.isFusion) return
|
||||||
toolGroup.setToolActive(FusionJumpToPointTool.toolName, {
|
toolGroup.setToolActive(FusionJumpToPointTool.toolName, {
|
||||||
bindings: [{ mouseButton: MouseBindings.Primary }]
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
})
|
})
|
||||||
this.dispatchFusionCenterPoint()
|
this.dispatchFusionCenterPoint()
|
||||||
} else {
|
} else {
|
||||||
|
this.setFusionMipClickEnabled(this.isFusion)
|
||||||
|
if (!toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
|
||||||
toolGroup.setToolDisabled(FusionJumpToPointTool.toolName)
|
toolGroup.setToolDisabled(FusionJumpToPointTool.toolName)
|
||||||
|
this.clearFusionJumpToPointAnnotations()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
clearFusionJumpToPointAnnotations() {
|
||||||
|
const annotations = cornerstoneTools.annotation.state.getAllAnnotations() || []
|
||||||
|
const removeList = []
|
||||||
|
for (let i = 0; i < annotations.length; i++) {
|
||||||
|
const item = annotations[i]
|
||||||
|
if (!item || !item.metadata) continue
|
||||||
|
if (item.metadata.toolName !== FusionJumpToPointTool.toolName) continue
|
||||||
|
removeList.push(item)
|
||||||
|
}
|
||||||
|
if (!removeList.length) return
|
||||||
|
removeList.forEach(i => {
|
||||||
|
cornerstoneTools.annotation.state.removeAnnotation(i.annotationUID)
|
||||||
|
})
|
||||||
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||||
|
if (!renderingEngine) return
|
||||||
|
const viewportIds = ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3', 'viewport-fusion-hidden-sag']
|
||||||
|
viewportIds.forEach(viewportId => {
|
||||||
|
const viewport = renderingEngine.getViewport(viewportId)
|
||||||
|
if (viewport && viewport.render) {
|
||||||
|
viewport.render()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
dispatchFusionCenterPoint(retryCount = 0) {
|
dispatchFusionCenterPoint(retryCount = 0) {
|
||||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||||
if (!renderingEngine) return
|
if (!renderingEngine) return
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
|
||||||
const instance = toolGroup?.getToolInstance?.(FusionJumpToPointTool.toolName)
|
if (!toolGroup || !toolGroup.getToolInstance) return
|
||||||
if (!instance?.setPoint) return
|
const instance = toolGroup.getToolInstance(FusionJumpToPointTool.toolName)
|
||||||
|
if (!instance || !instance.setPoint) return
|
||||||
const candidates = ['viewport-fusion-2', 'viewport-fusion-1', 'viewport-fusion-0']
|
const candidates = ['viewport-fusion-2', 'viewport-fusion-1', 'viewport-fusion-0']
|
||||||
for (const viewportId of candidates) {
|
for (const viewportId of candidates) {
|
||||||
const viewport = renderingEngine.getViewport(viewportId)
|
const viewport = renderingEngine.getViewport(viewportId)
|
||||||
if (!viewport?.canvasToWorld || !viewport?.element) continue
|
if (!viewport || !viewport.canvasToWorld || !viewport.element) continue
|
||||||
const width = viewport.element.clientWidth
|
const width = viewport.element.clientWidth
|
||||||
const height = viewport.element.clientHeight
|
const height = viewport.element.clientHeight
|
||||||
let worldPoint = null
|
let worldPoint = null
|
||||||
|
|
@ -2683,7 +2754,10 @@ export default {
|
||||||
worldPoint = viewport.canvasToWorld([width / 2, height / 2])
|
worldPoint = viewport.canvasToWorld([width / 2, height / 2])
|
||||||
}
|
}
|
||||||
if ((!worldPoint || worldPoint.length < 3) && viewport.getCamera) {
|
if ((!worldPoint || worldPoint.length < 3) && viewport.getCamera) {
|
||||||
worldPoint = viewport.getCamera()?.focalPoint
|
const camera = viewport.getCamera()
|
||||||
|
if (camera && camera.focalPoint) {
|
||||||
|
worldPoint = camera.focalPoint
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!worldPoint || worldPoint.length < 3) continue
|
if (!worldPoint || worldPoint.length < 3) continue
|
||||||
instance.setPoint(worldPoint, viewportId, renderingEngine.id, {
|
instance.setPoint(worldPoint, viewportId, renderingEngine.id, {
|
||||||
|
|
@ -2724,6 +2798,8 @@ export default {
|
||||||
}
|
}
|
||||||
this.setFusionMipJumpEnabled(true)
|
this.setFusionMipJumpEnabled(true)
|
||||||
// this.setFusionMipRotateEnabled(true)
|
// this.setFusionMipRotateEnabled(true)
|
||||||
|
} else if (toolName === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
|
|
@ -2736,31 +2812,37 @@ export default {
|
||||||
}
|
}
|
||||||
this.setFusionMipJumpEnabled(true)
|
this.setFusionMipJumpEnabled(true)
|
||||||
// this.setFusionMipRotateEnabled(true)
|
// this.setFusionMipRotateEnabled(true)
|
||||||
|
} else if (this.activeTool === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toolGroup.setToolActive(toolName, {
|
if (toolName === FusionJumpToPointTool.toolName) {
|
||||||
bindings: [{ mouseButton: MouseBindings.Primary }]
|
this.setFusionMipJumpEnabled(true)
|
||||||
})
|
} else {
|
||||||
if (toolName === CrosshairsTool.toolName) {
|
toolGroup.setToolActive(toolName, {
|
||||||
if (this.isFusion) {
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
// const instance = toolGroup.getToolInstance?.(CrosshairsTool.toolName)
|
})
|
||||||
// if (instance && !instance.__fusionSameForPatched) {
|
if (toolName === CrosshairsTool.toolName) {
|
||||||
// instance.__fusionSameForPatched = true
|
if (this.isFusion) {
|
||||||
// const original = instance._checkIfViewportsRenderingSameScene?.bind(instance)
|
// const instance = toolGroup.getToolInstance?.(CrosshairsTool.toolName)
|
||||||
// instance._checkIfViewportsRenderingSameScene = (viewport, otherViewport) => {
|
// if (instance && !instance.__fusionSameForPatched) {
|
||||||
// try {
|
// instance.__fusionSameForPatched = true
|
||||||
// const a = viewport?.getFrameOfReferenceUID?.()
|
// const original = instance._checkIfViewportsRenderingSameScene?.bind(instance)
|
||||||
// const b = otherViewport?.getFrameOfReferenceUID?.()
|
// instance._checkIfViewportsRenderingSameScene = (viewport, otherViewport) => {
|
||||||
// if (a && b && a === b) return true
|
// try {
|
||||||
// } catch (e) { }
|
// const a = viewport?.getFrameOfReferenceUID?.()
|
||||||
// return original ? original(viewport, otherViewport) : true
|
// const b = otherViewport?.getFrameOfReferenceUID?.()
|
||||||
// }
|
// if (a && b && a === b) return true
|
||||||
// }
|
// } catch (e) { }
|
||||||
|
// return original ? original(viewport, otherViewport) : true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
|
// this.setFusionMipRotateEnabled(false)
|
||||||
}
|
}
|
||||||
this.setFusionMipJumpEnabled(false)
|
|
||||||
// this.setFusionMipRotateEnabled(false)
|
|
||||||
}
|
}
|
||||||
this.activeTool = toolName
|
this.activeTool = toolName
|
||||||
}
|
}
|
||||||
|
|
@ -2807,6 +2889,8 @@ export default {
|
||||||
if (toolGroup.hasTool(this.activeTool)) {
|
if (toolGroup.hasTool(this.activeTool)) {
|
||||||
toolGroup.setToolDisabled(this.activeTool)
|
toolGroup.setToolDisabled(this.activeTool)
|
||||||
}
|
}
|
||||||
|
} else if (toolName === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
|
|
@ -2817,6 +2901,8 @@ export default {
|
||||||
if (toolGroup.hasTool(this.activeTool)) {
|
if (toolGroup.hasTool(this.activeTool)) {
|
||||||
toolGroup.setToolDisabled(this.activeTool)
|
toolGroup.setToolDisabled(this.activeTool)
|
||||||
}
|
}
|
||||||
|
} else if (this.activeTool === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
|
|
@ -2844,6 +2930,8 @@ export default {
|
||||||
if (toolGroup.hasTool(this.activeTool)) {
|
if (toolGroup.hasTool(this.activeTool)) {
|
||||||
toolGroup.setToolDisabled(this.activeTool)
|
toolGroup.setToolDisabled(this.activeTool)
|
||||||
}
|
}
|
||||||
|
} else if (this.activeTool === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
|
|
@ -2866,6 +2954,8 @@ export default {
|
||||||
if (toolGroup.hasTool(this.activeTool)) {
|
if (toolGroup.hasTool(this.activeTool)) {
|
||||||
toolGroup.setToolDisabled(this.activeTool)
|
toolGroup.setToolDisabled(this.activeTool)
|
||||||
}
|
}
|
||||||
|
} else if (this.activeTool === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
|
|
@ -2898,6 +2988,8 @@ export default {
|
||||||
if (toolGroup.hasTool(this.activeTool)) {
|
if (toolGroup.hasTool(this.activeTool)) {
|
||||||
toolGroup.setToolDisabled(this.activeTool)
|
toolGroup.setToolDisabled(this.activeTool)
|
||||||
}
|
}
|
||||||
|
} else if (this.activeTool === FusionJumpToPointTool.toolName) {
|
||||||
|
this.setFusionMipJumpEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
toolGroup.setToolPassive(this.activeTool)
|
toolGroup.setToolPassive(this.activeTool)
|
||||||
}
|
}
|
||||||
|
|
@ -3031,7 +3123,7 @@ export default {
|
||||||
this.resetCrosshairsAnnotationsForViewports(fusionAllViewportIds)
|
this.resetCrosshairsAnnotationsForViewports(fusionAllViewportIds)
|
||||||
renderingEngine.render()
|
renderingEngine.render()
|
||||||
this.dispatchFusionCenterPoint()
|
this.dispatchFusionCenterPoint()
|
||||||
if (this.fusionOverlayModality === 'NM' && Number.isFinite(this.fusionOverlayDefaultUpper) && Number.isFinite(this.fusionOverlayDefaultRange)) {
|
if (Number.isFinite(this.fusionOverlayDefaultUpper) && Number.isFinite(this.fusionOverlayDefaultRange)) {
|
||||||
this.lastUpper = null
|
this.lastUpper = null
|
||||||
this.hasFusionUpperInitialized = false
|
this.hasFusionUpperInitialized = false
|
||||||
if (this.$refs.colorMap) {
|
if (this.$refs.colorMap) {
|
||||||
|
|
@ -3052,7 +3144,6 @@ export default {
|
||||||
if (this.readingTool !== 3) {
|
if (this.readingTool !== 3) {
|
||||||
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true, resetRotation: true })
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true, resetRotation: true })
|
||||||
}
|
}
|
||||||
viewport.resetProperties()
|
|
||||||
if (this.isMPR) {
|
if (this.isMPR) {
|
||||||
let volume = cache.getVolume(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId)
|
let volume = cache.getVolume(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId)
|
||||||
const voi = metaData.get('voiLutModule', volume._imageIds[Math.ceil((volume._imageIds.length - 1) / 2)])
|
const voi = metaData.get('voiLutModule', volume._imageIds[Math.ceil((volume._imageIds.length - 1) / 2)])
|
||||||
|
|
@ -3068,9 +3159,12 @@ export default {
|
||||||
|
|
||||||
return this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
|
return this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
|
||||||
}
|
}
|
||||||
|
// viewport.resetProperties()
|
||||||
this.setToolsPassive()
|
this.setToolsPassive()
|
||||||
if (this.readingTool === 3 && this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.Modality === 'PT') {
|
if (this.readingTool === 3 && this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.Modality === 'PT') {
|
||||||
viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
|
viewport.setProperties({ voiRange: { upper: 5, lower: 0 }, invert: true }, this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId)
|
||||||
|
} else {
|
||||||
|
viewport.resetProperties()
|
||||||
}
|
}
|
||||||
viewport.render()
|
viewport.render()
|
||||||
// renderingEngine.render()
|
// renderingEngine.render()
|
||||||
|
|
@ -3324,6 +3418,7 @@ export default {
|
||||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(true)
|
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(true)
|
||||||
} else if (shortcutKeyEnum === 15) {
|
} else if (shortcutKeyEnum === 15) {
|
||||||
// 截图
|
// 截图
|
||||||
|
this.saveImage()
|
||||||
} else if (shortcutKeyEnum === 16) {
|
} else if (shortcutKeyEnum === 16) {
|
||||||
// 反色
|
// 反色
|
||||||
this.toggleInvert()
|
this.toggleInvert()
|
||||||
|
|
@ -3360,6 +3455,23 @@ export default {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
async saveImage() {
|
||||||
|
const divForDownloadViewport = document.querySelector(
|
||||||
|
`div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
|
||||||
|
)
|
||||||
|
let series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
|
||||||
|
const canvas = await html2canvas(divForDownloadViewport)
|
||||||
|
const base64Str = canvas.toDataURL('image/png', 1)
|
||||||
|
let file = this.convertBase64ToBlob(base64Str)
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.download = `${series.SeriesInstanceUid}.png`
|
||||||
|
const blobUrl = URL.createObjectURL(file)
|
||||||
|
a.href = blobUrl
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click()
|
||||||
|
a.remove()
|
||||||
|
URL.revokeObjectURL(blobUrl)
|
||||||
|
},
|
||||||
// 重置热键信息
|
// 重置热键信息
|
||||||
resetHotkeyList(arr) {
|
resetHotkeyList(arr) {
|
||||||
this.hotKeyList = []
|
this.hotKeyList = []
|
||||||
|
|
@ -3373,6 +3485,7 @@ export default {
|
||||||
},
|
},
|
||||||
// 重置视口
|
// 重置视口
|
||||||
resetRenderingEngine(viewportId = null, i) {
|
resetRenderingEngine(viewportId = null, i) {
|
||||||
|
if (viewportId.includes('MPR') && !this.isMPR) return false
|
||||||
if (this.timer[viewportId]) {
|
if (this.timer[viewportId]) {
|
||||||
clearInterval(this.timer[viewportId])
|
clearInterval(this.timer[viewportId])
|
||||||
this.timer[viewportId] = null
|
this.timer[viewportId] = null
|
||||||
|
|
@ -3404,7 +3517,9 @@ export default {
|
||||||
},
|
},
|
||||||
// 切换全屏
|
// 切换全屏
|
||||||
async toggleFullScreen(e, index) {
|
async toggleFullScreen(e, index) {
|
||||||
|
if (!this.isMPR && !this.isFusion && this.cells.length <= 1) return false
|
||||||
if (this.isDelay && (this.readingTool === 3 || this.isMPR)) return false
|
if (this.isDelay && (this.readingTool === 3 || this.isMPR)) return false
|
||||||
|
if (this.readingTool === 3 && this.isMPR) return false
|
||||||
if (this.readingTool === 3) {
|
if (this.readingTool === 3) {
|
||||||
let res = await this.changeScreenSave()
|
let res = await this.changeScreenSave()
|
||||||
if (!res) return false
|
if (!res) return false
|
||||||
|
|
@ -3469,6 +3584,7 @@ export default {
|
||||||
this.sLoading = false
|
this.sLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.$refs[this.activeTaskId][0].setSeriesActive(0, 0)
|
||||||
// this.setToolsPassive()
|
// this.setToolsPassive()
|
||||||
},
|
},
|
||||||
async toggleTaskByViewport(obj) {
|
async toggleTaskByViewport(obj) {
|
||||||
|
|
@ -3598,8 +3714,14 @@ export default {
|
||||||
DicomEvent.$emit('SegmentationLoading', `${this.viewportKey}-${this.activeViewportIndex}`)
|
DicomEvent.$emit('SegmentationLoading', `${this.viewportKey}-${this.activeViewportIndex}`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (this.activeTool !== CrosshairsTool.toolName) {
|
if (this.activeTool && this.activeTool !== CrosshairsTool.toolName && this.activeTool !== FusionJumpToPointTool.toolName) {
|
||||||
this.setToolsPassive()
|
const toolGroupId = this.getActiveToolGroupId()
|
||||||
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
|
if (toolGroup && toolGroup.hasTool(this.activeTool)) {
|
||||||
|
toolGroup.setToolActive(this.activeTool, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getRelatedSeries(visitTaskInfo, baselineSeries) {
|
getRelatedSeries(visitTaskInfo, baselineSeries) {
|
||||||
|
|
@ -3724,6 +3846,9 @@ export default {
|
||||||
if (i === -1) return
|
if (i === -1) return
|
||||||
const studyList = this.visitTaskList[i].StudyList
|
const studyList = this.visitTaskList[i].StudyList
|
||||||
let series = null
|
let series = null
|
||||||
|
if (this.isFusion) {
|
||||||
|
this.activeViewportIndex = 2
|
||||||
|
}
|
||||||
let curSeriesId = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.Id
|
let curSeriesId = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.Id
|
||||||
if (obj.segment) {
|
if (obj.segment) {
|
||||||
let study = studyList.find(item => item.StudyId === obj.segmentGroup.StudyId)
|
let study = studyList.find(item => item.StudyId === obj.segmentGroup.StudyId)
|
||||||
|
|
@ -3962,7 +4087,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setToolToTarget(obj) {
|
setToolToTarget(obj) {
|
||||||
console.log('setToolToTarget')
|
|
||||||
if (obj.visitTaskId === this.taskInfo.VisitTaskId && this.readingTaskState !== 2 && obj.markTool && !obj.isMarked) {
|
if (obj.visitTaskId === this.taskInfo.VisitTaskId && this.readingTaskState !== 2 && obj.markTool && !obj.isMarked) {
|
||||||
const toolName = obj.markTool
|
const toolName = obj.markTool
|
||||||
if (this.activeTool) {
|
if (this.activeTool) {
|
||||||
|
|
@ -4244,6 +4368,7 @@ export default {
|
||||||
if (!res) return false
|
if (!res) return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.fullScreenIndex = null
|
||||||
if (!data) {
|
if (!data) {
|
||||||
let { imageOrientationPatient, imagePositionPatient } = this.$refs[`viewport-${this.activeViewportIndex}`][0].imageInfo
|
let { imageOrientationPatient, imagePositionPatient } = this.$refs[`viewport-${this.activeViewportIndex}`][0].imageInfo
|
||||||
if (!imageOrientationPatient || !imagePositionPatient || imagePositionPatient.length <= 0 || imageOrientationPatient.length <= 0) return this.$confirm(this.$t('trials:reading:confirm:imageNotMPR'), this.$t('system:menu:confirm:title:warning'), {
|
if (!imageOrientationPatient || !imagePositionPatient || imagePositionPatient.length <= 0 || imageOrientationPatient.length <= 0) return this.$confirm(this.$t('trials:reading:confirm:imageNotMPR'), this.$t('system:menu:confirm:title:warning'), {
|
||||||
|
|
@ -4310,9 +4435,6 @@ export default {
|
||||||
this.$refs[`viewport-1`][0].setSeriesInfo(pt)
|
this.$refs[`viewport-1`][0].setSeriesInfo(pt)
|
||||||
this.$refs[`viewport-2`][0].setSeriesInfo(pt)
|
this.$refs[`viewport-2`][0].setSeriesInfo(pt)
|
||||||
this.$refs[`viewport-3`][0].setSeriesInfo(pt)
|
this.$refs[`viewport-3`][0].setSeriesInfo(pt)
|
||||||
this.$nextTick(() => {
|
|
||||||
this.setFusionMipJumpEnabled(true)
|
|
||||||
})
|
|
||||||
// this.resetAnnotation = false
|
// this.resetAnnotation = false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -4349,29 +4471,18 @@ export default {
|
||||||
await this.initFusionHiddenSagViewport(pt)
|
await this.initFusionHiddenSagViewport(pt)
|
||||||
// this.resetAnnotation = false
|
// this.resetAnnotation = false
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
this.setFusionMipJumpEnabled(this.activeTool === FusionJumpToPointTool.toolName)
|
||||||
|
const defaultRange = this.getFusionDefaultColorMapRange(pt)
|
||||||
|
const defaultUpper = this.getFusionDefaultColorMapUpper(defaultRange)
|
||||||
this.$refs[`colorMap`].init()
|
this.$refs[`colorMap`].init()
|
||||||
if (this.fusionOverlayModality === 'NM') {
|
this.fusionOverlayDefaultRange = defaultRange
|
||||||
const imageIds = this.sortImageIdsByImagePositionPatient(pt.ImageIds)
|
this.fusionOverlayDefaultUpper = defaultUpper
|
||||||
const imageId = imageIds?.[0]
|
this.lastUpper = null
|
||||||
const voiLutModule = imageId ? metaData.get('voiLutModule', imageId) : null
|
this.hasFusionUpperInitialized = false
|
||||||
const rawWidth = Array.isArray(voiLutModule?.windowWidth) ? voiLutModule.windowWidth[0] : voiLutModule?.windowWidth
|
this.$refs.colorMap.range = defaultRange
|
||||||
const nmMax = Number(rawWidth)
|
this.$refs.colorMap.upper = defaultUpper
|
||||||
if (Number.isFinite(nmMax) && nmMax > 0) {
|
this.$refs.colorMap.upperRangeChange(defaultRange)
|
||||||
const halfMax = Math.round(nmMax * 0.5)
|
this.voiChange(defaultUpper)
|
||||||
this.fusionOverlayDefaultRange = Math.round(nmMax)
|
|
||||||
this.fusionOverlayDefaultUpper = halfMax
|
|
||||||
this.lastUpper = null
|
|
||||||
this.hasFusionUpperInitialized = false
|
|
||||||
this.$refs.colorMap.range = Math.round(nmMax)
|
|
||||||
this.$refs.colorMap.upper = halfMax
|
|
||||||
this.$refs.colorMap.upperRangeChange(Math.round(nmMax))
|
|
||||||
this.voiChange(halfMax)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.fusionOverlayDefaultRange = null
|
|
||||||
this.fusionOverlayDefaultUpper = null
|
|
||||||
}
|
|
||||||
this.setFusionMipJumpEnabled(true)
|
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
|
@ -4455,6 +4566,41 @@ export default {
|
||||||
pairs.sort((a, b) => b.distance - a.distance);
|
pairs.sort((a, b) => b.distance - a.distance);
|
||||||
return pairs.map((p) => p.imageId);
|
return pairs.map((p) => p.imageId);
|
||||||
},
|
},
|
||||||
|
getFusionDefaultColorMapRange(series) {
|
||||||
|
if (this.fusionOverlayModality !== 'NM') {
|
||||||
|
return DEFAULT_FUSION_COLOR_MAP_RANGE
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageIds = this.sortImageIdsByImagePositionPatient(series?.ImageIds || [])
|
||||||
|
const imageId = imageIds?.[0]
|
||||||
|
if (!imageId) {
|
||||||
|
return DEFAULT_FUSION_COLOR_MAP_RANGE
|
||||||
|
}
|
||||||
|
|
||||||
|
const voiLutModule = metaData.get('voiLutModule', imageId)
|
||||||
|
const rawWidth = Array.isArray(voiLutModule?.windowWidth)
|
||||||
|
? voiLutModule.windowWidth[0]
|
||||||
|
: voiLutModule?.windowWidth
|
||||||
|
const windowWidth = Math.round(Number(rawWidth))
|
||||||
|
|
||||||
|
if (!Number.isFinite(windowWidth) || windowWidth <= 0) {
|
||||||
|
return DEFAULT_FUSION_COLOR_MAP_RANGE
|
||||||
|
}
|
||||||
|
|
||||||
|
return windowWidth
|
||||||
|
},
|
||||||
|
getFusionDefaultColorMapUpper(range) {
|
||||||
|
if (this.fusionOverlayModality !== 'NM') {
|
||||||
|
return DEFAULT_FUSION_COLOR_MAP_UPPER
|
||||||
|
}
|
||||||
|
|
||||||
|
const safeRange = Number(range)
|
||||||
|
if (!Number.isFinite(safeRange) || safeRange <= 0) {
|
||||||
|
return DEFAULT_FUSION_COLOR_MAP_UPPER
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.round(safeRange * 0.5)
|
||||||
|
},
|
||||||
upperRangeChange(upper) {
|
upperRangeChange(upper) {
|
||||||
if (!this.hasFusionUpperInitialized) {
|
if (!this.hasFusionUpperInitialized) {
|
||||||
if (!upper) return
|
if (!upper) return
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ export default {
|
||||||
}
|
}
|
||||||
if (this.visitInfo.operateStateEnum === 22) {
|
if (this.visitInfo.operateStateEnum === 22) {
|
||||||
let o = {}
|
let o = {}
|
||||||
if (this.isTableQuestion) {
|
if (this.visitInfo.isTableQuestion) {
|
||||||
o.TableQuestionId = this.visitInfo.operateQuestionId
|
o.TableQuestionId = this.visitInfo.operateQuestionId
|
||||||
o.RowId = this.visitInfo.operateRowId
|
o.RowId = this.visitInfo.operateRowId
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,19 @@
|
||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="ConfigBox">
|
<div class="ConfigBox">
|
||||||
|
<div class="EraserConfig"
|
||||||
|
v-if="activeTool === 'CircularEraser' || activeTool === 'CircularBrush' || ThresholdTools.includes(activeTool)">
|
||||||
|
<span>{{ $t('trials:reading:Segmentations:title:EraserConfigSection') }}</span>
|
||||||
|
<el-select v-model="sliderMax" placeholder="" size="small" @change="handleSliderChange">
|
||||||
|
<el-option v-for="item in sliderSection" :key="item.id" :label="item.label"
|
||||||
|
:value="item.max">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
<div class="EraserConfig"
|
<div class="EraserConfig"
|
||||||
v-if="activeTool === 'CircularEraser' || activeTool === 'CircularBrush' || ThresholdTools.includes(activeTool)">
|
v-if="activeTool === 'CircularEraser' || activeTool === 'CircularBrush' || ThresholdTools.includes(activeTool)">
|
||||||
<span>{{ $t('trials:reading:Segmentations:title:EraserConfig') }}</span>
|
<span>{{ $t('trials:reading:Segmentations:title:EraserConfig') }}</span>
|
||||||
<el-slider v-model="brushSize" show-input :step="1" :max="100" input-size="mini"
|
<el-slider v-model="brushSize" show-input :step="sliderStep" :max="sliderMax" input-size="mini"
|
||||||
:show-input-controls="false" />
|
:show-input-controls="false" />
|
||||||
</div>
|
</div>
|
||||||
<div class="EraserConfig" v-if="ThresholdTools.includes(activeTool)">
|
<div class="EraserConfig" v-if="ThresholdTools.includes(activeTool)">
|
||||||
|
|
@ -95,15 +104,16 @@
|
||||||
<span>{{ $t('trials:reading:Segmentations:title:Show:Fill&Outline') }}</span>
|
<span>{{ $t('trials:reading:Segmentations:title:Show:Fill&Outline') }}</span>
|
||||||
<div style="display: flex;">
|
<div style="display: flex;">
|
||||||
<div :class="['tool-item', SegmentConfig.renderOutline && SegmentConfig.renderFill ? 'tool-item-active' : '']"
|
<div :class="['tool-item', SegmentConfig.renderOutline && SegmentConfig.renderFill ? 'tool-item-active' : '']"
|
||||||
:title="$t('trials:dicom-show:Eraser')" @click.stop="changeSegmentConfig(true, true)">
|
:title="$t('trials:dicom-show:fill_outline')"
|
||||||
|
@click.stop="changeSegmentConfig(true, true)">
|
||||||
<svg-icon icon-class="fill_outline" class="svg-icon" />
|
<svg-icon icon-class="fill_outline" class="svg-icon" />
|
||||||
</div>
|
</div>
|
||||||
<div :class="['tool-item', SegmentConfig.renderOutline && !SegmentConfig.renderFill ? 'tool-item-active' : '']"
|
<div :class="['tool-item', SegmentConfig.renderOutline && !SegmentConfig.renderFill ? 'tool-item-active' : '']"
|
||||||
:title="$t('trials:dicom-show:Eraser')" @click.stop="changeSegmentConfig(true, false)">
|
:title="$t('trials:dicom-show:outline')" @click.stop="changeSegmentConfig(true, false)">
|
||||||
<svg-icon icon-class="outline" class="svg-icon" />
|
<svg-icon icon-class="outline" class="svg-icon" />
|
||||||
</div>
|
</div>
|
||||||
<div :class="['tool-item', !SegmentConfig.renderOutline && SegmentConfig.renderFill ? 'tool-item-active' : '']"
|
<div :class="['tool-item', !SegmentConfig.renderOutline && SegmentConfig.renderFill ? 'tool-item-active' : '']"
|
||||||
:title="$t('trials:dicom-show:Eraser')" @click.stop="changeSegmentConfig(false, true)">
|
:title="$t('trials:dicom-show:fill')" @click.stop="changeSegmentConfig(false, true)">
|
||||||
<svg-icon icon-class="fill" class="svg-icon" />
|
<svg-icon icon-class="fill" class="svg-icon" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -127,7 +137,7 @@
|
||||||
</el-switch>
|
</el-switch>
|
||||||
<span style="margin-left: 5px;">{{
|
<span style="margin-left: 5px;">{{
|
||||||
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
|
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="segmentList.length > 0">
|
<template v-if="segmentList.length > 0">
|
||||||
|
|
@ -145,6 +155,9 @@
|
||||||
<div class="SegmentGroupBtn" @click.stop="exportSegmentGroup">
|
<div class="SegmentGroupBtn" @click.stop="exportSegmentGroup">
|
||||||
{{ $t('trials:reading:Segmentations:button:exportSegmentGroup') }}
|
{{ $t('trials:reading:Segmentations:button:exportSegmentGroup') }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="SegmentGroupBtn" @click.stop="recoverySegmentGroup">
|
||||||
|
{{ $t('trials:reading:Segmentations:button:recoverySegmentGroup') }}
|
||||||
|
</div>
|
||||||
<div class="SegmentGroupBtn" @click.stop="delSegmentGroup">
|
<div class="SegmentGroupBtn" @click.stop="delSegmentGroup">
|
||||||
{{ $t('trials:reading:Segmentations:button:deleteSegmentGroup') }}
|
{{ $t('trials:reading:Segmentations:button:deleteSegmentGroup') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -170,9 +183,9 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="addSegmentBox" @click.stop="addSegment"
|
<div class="addSegmentBox"
|
||||||
style="display: flex;align-items: center;justify-content: space-between;">
|
style="display: flex;align-items: center;justify-content: space-between;">
|
||||||
<span v-if="readingTaskState < 2"><i class="el-icon-plus"></i>
|
<span v-if="readingTaskState < 2" @click.stop="addSegment"><i class="el-icon-plus"></i>
|
||||||
{{ $t('trials:reading:Segmentations:button:addSegment') }}
|
{{ $t('trials:reading:Segmentations:button:addSegment') }}
|
||||||
</span>
|
</span>
|
||||||
<span style="width: 10px;" v-else></span>
|
<span style="width: 10px;" v-else></span>
|
||||||
|
|
@ -228,7 +241,9 @@
|
||||||
<span>{{ k }}</span>
|
<span>{{ k }}</span>
|
||||||
<span v-if="item.stats[k]">{{ JSON.stringify(item.stats[k].value) !== 'null'
|
<span v-if="item.stats[k]">{{ JSON.stringify(item.stats[k].value) !== 'null'
|
||||||
?
|
?
|
||||||
Number(item.stats[k].value).toFixed(2) : null
|
k === 'count' ? Number(item.stats[k].value).toFixed(0) :
|
||||||
|
Number(item.stats[k].value).toFixed(digitPlaces)
|
||||||
|
: null
|
||||||
}}<i>{{ item.stats[k].unit }}</i></span>
|
}}<i>{{ item.stats[k].unit }}</i></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -237,7 +252,15 @@
|
||||||
|
|
||||||
<el-color-picker v-model="item.color" size="mini"
|
<el-color-picker v-model="item.color" size="mini"
|
||||||
@change="(e) => changeColor(e, item)"></el-color-picker>
|
@change="(e) => changeColor(e, item)"></el-color-picker>
|
||||||
<div class="SegmentName">{{ item.SegmentLabel }}</div>
|
<div
|
||||||
|
style="width: 100%;display: flex;align-items: center;justify-content: space-between;">
|
||||||
|
<div class="SegmentName">{{ item.SegmentLabel }}</div>
|
||||||
|
<div v-if="item.stats && item.stats['volume']"
|
||||||
|
style="text-align: left;width: 100px;">{{
|
||||||
|
Number(item.stats['volume'].value).toFixed(digitPlaces) }}{{
|
||||||
|
item.stats['volume'].unit }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="btnBox">
|
<div class="btnBox">
|
||||||
<svg-icon :icon-class="item && !item.view ? 'eye' : 'eye-open'"
|
<svg-icon :icon-class="item && !item.view ? 'eye' : 'eye-open'"
|
||||||
|
|
@ -277,10 +300,39 @@
|
||||||
{{ $t("trials:reading:Segmentations:button:saveAll") }}
|
{{ $t("trials:reading:Segmentations:button:saveAll") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
<el-dialog :visible.sync="visible" :close-on-click-modal="false"
|
||||||
|
:title="$t('trials:reading:Segmentations:recovery')" width="850px">
|
||||||
|
<el-table :data="recoveryList" style="width: 100%;background-color: #1e1e1e;">
|
||||||
|
<!-- <el-table-column type="index" width="50" :label="$t('dictionary:template:globalConfig:order')">
|
||||||
|
</el-table-column> -->
|
||||||
|
<el-table-column property="Version" :label="$t('trials:reading:Segmentations:table:Version')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column property="FileSize" :label="$t('trials:reading:Segmentations:table:FileSize')">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ fileSizeFormatter(scope.row.FileSize) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column property="StartTime" :label="$t('trials:reading:Segmentations:table:StartTime')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column property="CreateTime" :label="$t('trials:reading:Segmentations:table:CreateTime')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('common:action:action')" align="left" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" @click.stop="restoreSegmentationVersion(scope.row)">{{
|
||||||
|
$t('trials:reading:Segmentations:button:recovery')
|
||||||
|
}}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination style="text-align: right;margin-top: 5px;" class="page" :total="total"
|
||||||
|
:page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
|
||||||
|
@pagination="getSegmentationVersionList(segmentationId)" />
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { changeSegmentationSavedStatus, getSegmentationList, addOrUpdateSegmentation, deleteSegmentation, getSegmentList, addOrUpdateSegment, deleteSegment, getSegmentBindingList, saveSegmentBindingAndAnswer, getReadingTableQuestionTrialById, getReadingQuestionTrialById, lockOrUnLockSegment } from '@/api/reading'
|
import { changeSegmentationSavedStatus, getSegmentationList, addOrUpdateSegmentation, deleteSegmentation, getSegmentList, addOrUpdateSegment, deleteSegment, getSegmentBindingList, saveSegmentBindingAndAnswer, getReadingTableQuestionTrialById, getReadingQuestionTrialById, lockOrUnLockSegment, restoreSegmentationVersion, getSegmentationVersionList } from '@/api/reading'
|
||||||
import * as cornerstoneTools from '@cornerstonejs/tools';
|
import * as cornerstoneTools from '@cornerstonejs/tools';
|
||||||
import * as cornerstone from "@cornerstonejs/core";
|
import * as cornerstone from "@cornerstonejs/core";
|
||||||
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||||
|
|
@ -289,6 +341,7 @@ import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
|
||||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||||
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
|
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
|
||||||
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
|
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
|
||||||
|
import Pagination from '@/components/Pagination'
|
||||||
cornerstoneTools.init({ addons: { polySeg } })
|
cornerstoneTools.init({ addons: { polySeg } })
|
||||||
const {
|
const {
|
||||||
ToolGroupManager,
|
ToolGroupManager,
|
||||||
|
|
@ -298,6 +351,7 @@ const {
|
||||||
LabelMapEditWithContourTool,
|
LabelMapEditWithContourTool,
|
||||||
SegmentBidirectionalTool,
|
SegmentBidirectionalTool,
|
||||||
CrosshairsTool,
|
CrosshairsTool,
|
||||||
|
BrushTool,
|
||||||
utilities: CStUtils,
|
utilities: CStUtils,
|
||||||
} = cornerstoneTools;
|
} = cornerstoneTools;
|
||||||
|
|
||||||
|
|
@ -306,8 +360,21 @@ const { segmentation: segmentationUtils } = CStUtils;
|
||||||
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
||||||
// const { downloadDICOMData } = cornerstoneAdapters.helpers;
|
// const { downloadDICOMData } = cornerstoneAdapters.helpers;
|
||||||
const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG;
|
const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG;
|
||||||
|
|
||||||
|
const searchDataDefault = () => {
|
||||||
|
return {
|
||||||
|
SegmentationId: null,
|
||||||
|
PageIndex: 1,
|
||||||
|
PageSize: 20,
|
||||||
|
Asc: false,
|
||||||
|
SortField: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
export default {
|
export default {
|
||||||
name: "Segmentations",
|
name: "Segmentations",
|
||||||
|
components: {
|
||||||
|
Pagination,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
isMPR: {
|
isMPR: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|
@ -386,6 +453,33 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
sliderMax: 50,
|
||||||
|
sliderStep: 1,
|
||||||
|
sliderSection: [{
|
||||||
|
id: `sliderSection1`,
|
||||||
|
max: 5,
|
||||||
|
step: 0.1,
|
||||||
|
label: '0~5mm'
|
||||||
|
}, {
|
||||||
|
id: `sliderSection2`,
|
||||||
|
max: 10,
|
||||||
|
step: 0.1,
|
||||||
|
label: '0~10mm'
|
||||||
|
}, {
|
||||||
|
id: `sliderSection3`,
|
||||||
|
max: 50,
|
||||||
|
step: 1,
|
||||||
|
label: '0~50mm'
|
||||||
|
}, {
|
||||||
|
id: `sliderSection4`,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
label: '0~100mm'
|
||||||
|
}],
|
||||||
|
visible: false,
|
||||||
|
recoveryList: [],
|
||||||
|
searchData: searchDataDefault(),
|
||||||
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
series: {},
|
series: {},
|
||||||
activeNames: ['tools', 'Segment'],
|
activeNames: ['tools', 'Segment'],
|
||||||
|
|
@ -427,7 +521,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.SegmentHight = window.innerHeight > 900 ? window.innerHeight * 0.5 : window.innerHeight * 0.4;
|
this.SegmentHight = window.innerHeight > 900 ? window.innerHeight * 0.45 : window.innerHeight * 0.35;
|
||||||
this.statsKey = getCustomizeStandardsSegmentDicomTools('Labelmap')[0].props.filter(item => item !== 'width' && item !== 'length')
|
this.statsKey = getCustomizeStandardsSegmentDicomTools('Labelmap')[0].props.filter(item => item !== 'width' && item !== 'length')
|
||||||
// console.log(segmentation, 'segmentation')
|
// console.log(segmentation, 'segmentation')
|
||||||
// console.log(annotation, 'annotation')
|
// console.log(annotation, 'annotation')
|
||||||
|
|
@ -517,6 +611,20 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleSliderChange(value) {
|
||||||
|
// console.log(value, 'value')
|
||||||
|
let data = this.sliderSection.find(item => item.max === value)
|
||||||
|
if (data) {
|
||||||
|
this.sliderStep = data.step
|
||||||
|
}
|
||||||
|
if (this.brushSize >= data.max) {
|
||||||
|
this.brushSize = data.max
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fileSizeFormatter(size) {
|
||||||
|
if (!size) return
|
||||||
|
return (size / Math.pow(1024, 2)).toFixed(3) + 'MB'
|
||||||
|
},
|
||||||
showSurface(item) {
|
showSurface(item) {
|
||||||
this.$emit("showSurface", {
|
this.$emit("showSurface", {
|
||||||
segmentationId: item.segmentationId,
|
segmentationId: item.segmentationId,
|
||||||
|
|
@ -650,7 +758,6 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
setToolActive(toolName) {
|
setToolActive(toolName) {
|
||||||
// if (!this.series.TaskInfo || this.series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
|
|
||||||
if (this.segmentList.length <= 0) return false
|
if (this.segmentList.length <= 0) return false
|
||||||
if (this.curSegment.lock) return false
|
if (this.curSegment.lock) return false
|
||||||
if (this.isMPR) return false
|
if (this.isMPR) return false
|
||||||
|
|
@ -676,6 +783,9 @@ export default {
|
||||||
toolGroup.setToolActive(toolName, {
|
toolGroup.setToolActive(toolName, {
|
||||||
bindings: [{ mouseButton: MouseBindings.Primary }]
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
||||||
})
|
})
|
||||||
|
// if (toolName === 'CircularEraser') {
|
||||||
|
// console.log(toolGroup.getToolInstance(toolName))
|
||||||
|
// }
|
||||||
this.$emit('update:activeTool', toolName)
|
this.$emit('update:activeTool', toolName)
|
||||||
this.setBrushSize(toolName)
|
this.setBrushSize(toolName)
|
||||||
if (this.ThresholdTools.includes(toolName)) {
|
if (this.ThresholdTools.includes(toolName)) {
|
||||||
|
|
@ -693,13 +803,8 @@ export default {
|
||||||
for (let j = 0; j < arr.length; j++) {
|
for (let j = 0; j < arr.length; j++) {
|
||||||
let item = arr[j]
|
let item = arr[j]
|
||||||
item.bidirectionalView = view
|
item.bidirectionalView = view
|
||||||
// let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
|
||||||
// item.bidirectionalView = view
|
|
||||||
// if (!bidirectional) continue
|
|
||||||
// annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
|
|
||||||
}
|
}
|
||||||
DicomEvent.$emit('viewBidirectional', arr)
|
DicomEvent.$emit('viewBidirectional', arr)
|
||||||
// this.resetViewport()
|
|
||||||
},
|
},
|
||||||
async jumpBidirectional(item) {
|
async jumpBidirectional(item) {
|
||||||
DicomEvent.$emit('jumpBidirectional', item)
|
DicomEvent.$emit('jumpBidirectional', item)
|
||||||
|
|
@ -741,17 +846,91 @@ export default {
|
||||||
}
|
}
|
||||||
// this.resetViewport()
|
// this.resetViewport()
|
||||||
},
|
},
|
||||||
|
async restoreSegmentationVersion(row) {
|
||||||
|
try {
|
||||||
|
this.popoverId = null
|
||||||
|
let message = this.$t('trials:reading:Segmentations:confirm:CurrentDataIsLoss').replace("xxx", row.Version)
|
||||||
|
let confirm = await this.$confirm(message)
|
||||||
|
if (!confirm) return false
|
||||||
|
let data = {
|
||||||
|
SegmentationId: this.segmentationId,
|
||||||
|
VersionId: row.Id
|
||||||
|
}
|
||||||
|
let res = await restoreSegmentationVersion(data)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId && this.segmentationId === item.metadata.segmentationId && item.metadata.toolName === "SegmentBidirectional");
|
||||||
|
annotations.forEach(item => {
|
||||||
|
annotation.state.removeAnnotation(item.annotationUID)
|
||||||
|
})
|
||||||
|
// 只需要将分割数据清空,分割所需的蒙版volume可以复用不需要清除
|
||||||
|
// 1.清除分割所需的蒙版volume(弃用)
|
||||||
|
// let volume = cache.getVolume(this.segmentationId)
|
||||||
|
// // 1. 销毁 Volume 实例
|
||||||
|
// volume.destroy();
|
||||||
|
// // 2. 从缓存中移除
|
||||||
|
// volume.removeFromCache();
|
||||||
|
// 2.清除分割数据及文件缓存
|
||||||
|
segmentation.removeSegmentation(this.segmentationId)
|
||||||
|
let imageId = null
|
||||||
|
if (this.curSegmentGroup.oldSegUrl) {
|
||||||
|
imageId = `wadouri:${this.OSSclientConfig.basePath}${this.curSegmentGroup.oldSegUrl}`
|
||||||
|
this.curSegmentGroup.oldSegUrl = null
|
||||||
|
} else {
|
||||||
|
imageId = `wadouri:${this.OSSclientConfig.basePath}${this.curSegmentGroup.segUrl}`
|
||||||
|
|
||||||
|
}
|
||||||
|
if (imageId && cache.getImage(imageId)) {
|
||||||
|
cache.removeImageLoadObject(imageId)
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = await this.getSegmentation(this.segmentationId)
|
||||||
|
if (!r) return false
|
||||||
|
this.visible = false
|
||||||
|
this.$message.success(this.$t("trials:reading:Segmentations:message:restoreSuccess"))
|
||||||
|
this.resetViewport()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
DicomEvent.$emit('renderSegmentationBychangeSegmention')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getSegmentationVersionList(segmentationId) {
|
||||||
|
try {
|
||||||
|
this.searchData.SegmentationId = segmentationId || this.segmentationId
|
||||||
|
let res = await getSegmentationVersionList(this.searchData)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
this.recoveryList = res.Result.CurrentPageData
|
||||||
|
// this.visible = true
|
||||||
|
this.total = res.Result.TotalCount
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async recoverySegmentGroup() {
|
||||||
|
try {
|
||||||
|
this.popoverId = null
|
||||||
|
let res = await this.getSegmentationVersionList(this.segmentationId)
|
||||||
|
if (!res) return this.$message.warning(this.$t("trials:reading:Segmentations:message:getSegmentationVersionFail"))
|
||||||
|
this.visible = true
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
selectSegmentGroup(s) {
|
selectSegmentGroup(s) {
|
||||||
// segmentation.activeSegmentation.setActiveSegmentation(`${this.viewportKey}-${this.activeViewportIndex}`, this.segmentationId)
|
|
||||||
this.$emit('setToolsPassive')
|
this.$emit('setToolsPassive')
|
||||||
this.segmentIndex = null;
|
this.segmentIndex = null;
|
||||||
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
|
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.selectSegment(segment)
|
this.selectSegment(segment)
|
||||||
})
|
})
|
||||||
// this.segmentIndex = segment.segmentIndex
|
|
||||||
// this.selectSegment(segment, s ? false : true)
|
|
||||||
// this.readingSegmentByConfig()
|
|
||||||
},
|
},
|
||||||
getSegmentationName(num = 1) {
|
getSegmentationName(num = 1) {
|
||||||
let defaultSegmentationName = this.trialCriterion.DefaultSegmentName.SegmentationName
|
let defaultSegmentationName = this.trialCriterion.DefaultSegmentName.SegmentationName
|
||||||
|
|
@ -812,11 +991,7 @@ export default {
|
||||||
this.segmentList.push(obj);
|
this.segmentList.push(obj);
|
||||||
this.segmentationId = obj.segmentationId;
|
this.segmentationId = obj.segmentationId;
|
||||||
this.segmentIndex = 1
|
this.segmentIndex = 1
|
||||||
// segmentation.segmentIndex.setActiveSegmentIndex(this.segmentationId, 1);
|
|
||||||
// viewportIds.forEach(id => {
|
|
||||||
// segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
|
||||||
// })
|
|
||||||
// this.selectSegmentGroup()
|
|
||||||
},
|
},
|
||||||
async addSegment() {
|
async addSegment() {
|
||||||
if (this.saveLoading) return false
|
if (this.saveLoading) return false
|
||||||
|
|
@ -901,9 +1076,6 @@ export default {
|
||||||
},
|
},
|
||||||
changeColor(e, item) {
|
changeColor(e, item) {
|
||||||
DicomEvent.$emit('changeColor', item)
|
DicomEvent.$emit('changeColor', item)
|
||||||
// this.viewportIds.forEach(id => {
|
|
||||||
// segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
|
|
||||||
// })
|
|
||||||
},
|
},
|
||||||
// 清空所有分割
|
// 清空所有分割
|
||||||
delAllSegment(isChange) {
|
delAllSegment(isChange) {
|
||||||
|
|
@ -948,7 +1120,6 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.segmentationId = null
|
this.segmentationId = null
|
||||||
}
|
}
|
||||||
// this.readingSegmentByConfig()
|
|
||||||
this.resetViewport()
|
this.resetViewport()
|
||||||
this.$emit('resetQuestion')
|
this.$emit('resetQuestion')
|
||||||
},
|
},
|
||||||
|
|
@ -965,7 +1136,6 @@ export default {
|
||||||
if (!res) return false
|
if (!res) return false
|
||||||
segmentation.removeSegment(this.segmentationId, Number(segmentIndex), { setNextSegmentAsActive: false, recordHistory: false })
|
segmentation.removeSegment(this.segmentationId, Number(segmentIndex), { setNextSegmentAsActive: false, recordHistory: false })
|
||||||
segmentation.helpers.clearSegmentValue(this.segmentationId, Number(segmentIndex), { recordHistory: false })
|
segmentation.helpers.clearSegmentValue(this.segmentationId, Number(segmentIndex), { recordHistory: false })
|
||||||
// segmentation.updateSegmentations({ segmentationId: this.segmentationId })
|
|
||||||
let index = this.segmentList[groupIndex].segments.findIndex(item => item.segmentIndex === segmentIndex)
|
let index = this.segmentList[groupIndex].segments.findIndex(item => item.segmentIndex === segmentIndex)
|
||||||
this.segmentList[groupIndex].segments.splice(index, 1)
|
this.segmentList[groupIndex].segments.splice(index, 1)
|
||||||
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId === this.segmentationId && item.metadata.segmentIndex === segmentIndex);
|
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId === this.segmentationId && item.metadata.segmentIndex === segmentIndex);
|
||||||
|
|
@ -997,7 +1167,7 @@ export default {
|
||||||
if (key === 'segmentGroup') {
|
if (key === 'segmentGroup') {
|
||||||
let group = this.segmentList.find(i => i.segmentationId === this.segmentationId)
|
let group = this.segmentList.find(i => i.segmentationId === this.segmentationId)
|
||||||
group.name = name
|
group.name = name
|
||||||
this.addOrUpdateSegmentation({ name, id: group.segmentationId })
|
this.addOrUpdateSegmentation({ name, id: group.segmentationId, url: group.segUrl, size: group.size })
|
||||||
} else {
|
} else {
|
||||||
item.SegmentLabel = name
|
item.SegmentLabel = name
|
||||||
this.addOrUpdateSegment({ name: item.SegmentLabel, color: item.color, segmentIndex: item.segmentIndex, segmentationId: item.segmentationId, segmentJson: JSON.stringify({ stats: item.stats, bidirectional: item.bidirectional }), id: item.id })
|
this.addOrUpdateSegment({ name: item.SegmentLabel, color: item.color, segmentIndex: item.segmentIndex, segmentationId: item.segmentationId, segmentJson: JSON.stringify({ stats: item.stats, bidirectional: item.bidirectional }), id: item.id })
|
||||||
|
|
@ -1331,7 +1501,6 @@ export default {
|
||||||
let { spacing, numFrames } = volume
|
let { spacing, numFrames } = volume
|
||||||
let constant = numFrames * spacing[2] / 100
|
let constant = numFrames * spacing[2] / 100
|
||||||
this.brushThreshold.dynamicRadius = Math.ceil(this.brushSize * constant)
|
this.brushThreshold.dynamicRadius = Math.ceil(this.brushSize * constant)
|
||||||
// console.log(this.brushThreshold.dynamicRadius)
|
|
||||||
},
|
},
|
||||||
setBrushThreshold() {
|
setBrushThreshold() {
|
||||||
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}`
|
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}`
|
||||||
|
|
@ -1518,24 +1687,6 @@ export default {
|
||||||
let segmentList = list ? list : this.segmentList
|
let segmentList = list ? list : this.segmentList
|
||||||
if (segmentList.length <= 0) return false
|
if (segmentList.length <= 0) return false
|
||||||
this.$emit("setToolsPassive")
|
this.$emit("setToolsPassive")
|
||||||
// let questionNeedChange = false;
|
|
||||||
// if (saveSegment) {
|
|
||||||
// for (let i = 0; i < segmentList.length; i++) {
|
|
||||||
// let segmentGroup = segmentList[i]
|
|
||||||
// let data = {
|
|
||||||
// SegmentationId: segmentGroup.segmentationId
|
|
||||||
// }
|
|
||||||
// let res = await this.getSegmentBindingList(data)
|
|
||||||
// if (res && res.length > 0) {
|
|
||||||
// questionNeedChange = true
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (questionNeedChange) {
|
|
||||||
// let confirm = await this.$confirm(this.$t("segment:confirm:questionNeedChange"))
|
|
||||||
// if (!confirm) return false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
this.$emit("update:globalLoading", true)
|
this.$emit("update:globalLoading", true)
|
||||||
this.$emit("update:loadingText", this.$t("segment:loadingText:saveSegmentation"))
|
this.$emit("update:loadingText", this.$t("segment:loadingText:saveSegmentation"))
|
||||||
let IsBeSegment = false
|
let IsBeSegment = false
|
||||||
|
|
@ -1554,13 +1705,15 @@ export default {
|
||||||
}/${this.visitInfo.VisistId}/${this.series.StudyId
|
}/${this.visitInfo.VisistId}/${this.series.StudyId
|
||||||
}/${this.series.Id}/${segmentGroup.name}.dcm`
|
}/${this.series.Id}/${segmentGroup.name}.dcm`
|
||||||
const result = await this.OSSclient.put(path, blob)
|
const result = await this.OSSclient.put(path, blob)
|
||||||
|
segmentGroup.oldSegUrl = segmentGroup.segUrl
|
||||||
segmentGroup.segUrl = this.$getObjectName(result.url)
|
segmentGroup.segUrl = this.$getObjectName(result.url)
|
||||||
DicomEvent.$emit("IsBeSegment", { StudyId: this.series.StudyId, Id: this.series.Id, IsBeSegment: true })
|
DicomEvent.$emit("IsBeSegment", { StudyId: this.series.StudyId, Id: this.series.Id, IsBeSegment: true })
|
||||||
} else {
|
} else {
|
||||||
|
blob = { size: 0 }
|
||||||
segmentGroup.segUrl = null
|
segmentGroup.segUrl = null
|
||||||
}
|
}
|
||||||
|
segmentGroup.size = blob.size
|
||||||
this.addOrUpdateSegmentation({ name: segmentGroup.name, id: segmentGroup.segmentationId, url: segmentGroup.segUrl })
|
this.addOrUpdateSegmentation({ name: segmentGroup.name, id: segmentGroup.segmentationId, url: segmentGroup.segUrl, size: blob.size })
|
||||||
this.changeSegmentationSavedStatus(segmentGroup.segmentationId, saveSegment)
|
this.changeSegmentationSavedStatus(segmentGroup.segmentationId, saveSegment)
|
||||||
if (saveSegment) {
|
if (saveSegment) {
|
||||||
await this.getBidirectionalSaveSegment(segmentList)
|
await this.getBidirectionalSaveSegment(segmentList)
|
||||||
|
|
@ -1687,7 +1840,7 @@ export default {
|
||||||
},
|
},
|
||||||
// 新增或修改分割组
|
// 新增或修改分割组
|
||||||
async addOrUpdateSegmentation(item) {
|
async addOrUpdateSegmentation(item) {
|
||||||
let { name, id, url } = item
|
let { name, id, url, size } = item
|
||||||
try {
|
try {
|
||||||
let data = {
|
let data = {
|
||||||
SegmentationName: name,
|
SegmentationName: name,
|
||||||
|
|
@ -1700,6 +1853,7 @@ export default {
|
||||||
}
|
}
|
||||||
if (url) data.SegUrl = url;
|
if (url) data.SegUrl = url;
|
||||||
if (id) data.Id = id;
|
if (id) data.Id = id;
|
||||||
|
if (size) data.FileSize = size;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
let res = await addOrUpdateSegmentation(data);
|
let res = await addOrUpdateSegmentation(data);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
@ -1711,8 +1865,71 @@ export default {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async getSegmentation(segmentationId) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
SeriesId: this.series.Id,
|
||||||
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
|
PageSize: 9999,
|
||||||
|
PageIndex: 1,
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
let res = await getSegmentationList(data);
|
||||||
|
this.loading = false;
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
// this.segmentList = []
|
||||||
|
// this.segmentationId = null;
|
||||||
|
// this.segmentIndex = null;
|
||||||
|
let list = res.Result.CurrentPageData;
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
let item = list[i]
|
||||||
|
if (item.Id !== segmentationId) continue;
|
||||||
|
let obj = this.segmentList.find(i => i.segmentationId === item.Id)
|
||||||
|
if (!obj) continue;
|
||||||
|
obj.name = item.SegmentationName;
|
||||||
|
obj.segUrl = item.SEGUrl;
|
||||||
|
obj.size = item.FileSize;
|
||||||
|
obj.isSaved = item.IsSaved;
|
||||||
|
obj.segmentationId = item.Id;
|
||||||
|
obj.segments = []
|
||||||
|
if (!this.segmentationId) {
|
||||||
|
this.segmentationId = obj.segmentationId
|
||||||
|
}
|
||||||
|
let segments = await this.getSegmentList(item.Id)
|
||||||
|
segments.forEach((s, index) => {
|
||||||
|
let SegmentJson = s.SegmentJson ? JSON.parse(s.SegmentJson) : {};
|
||||||
|
let o = {
|
||||||
|
segmentIndex: s.SegmentNumber,
|
||||||
|
segmentationId: s.SegmentationId,
|
||||||
|
SegmentLabel: s.SegmentName,
|
||||||
|
color: s.ColorRgb,
|
||||||
|
stats: SegmentJson.stats,
|
||||||
|
bidirectional: SegmentJson.bidirectional,
|
||||||
|
bidirectionalView: true,
|
||||||
|
view: true,
|
||||||
|
lock: s.IsLock,
|
||||||
|
id: s.Id
|
||||||
|
}
|
||||||
|
obj.segments.push(o)
|
||||||
|
|
||||||
|
})
|
||||||
|
this.segmentIndex = obj.segments[0].segmentIndex
|
||||||
|
}
|
||||||
|
this.isloaded = false
|
||||||
|
resolve(true)
|
||||||
|
} else {
|
||||||
|
resolve(false)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
resolve(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
// 获取分割组
|
// 获取分割组
|
||||||
async getSegmentationList(SEGMENT = null) {
|
async getSegmentationList() {
|
||||||
try {
|
try {
|
||||||
this.$emit('setToolsPassive')
|
this.$emit('setToolsPassive')
|
||||||
let data = {
|
let data = {
|
||||||
|
|
@ -1738,6 +1955,7 @@ export default {
|
||||||
name: item.SegmentationName,
|
name: item.SegmentationName,
|
||||||
view: true,
|
view: true,
|
||||||
segUrl: item.SEGUrl,
|
segUrl: item.SEGUrl,
|
||||||
|
size: item.FileSize,
|
||||||
isSaved: item.IsSaved,
|
isSaved: item.IsSaved,
|
||||||
segments: []
|
segments: []
|
||||||
}
|
}
|
||||||
|
|
@ -1997,6 +2215,21 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
::v-deep .el-table th.el-table__cell {
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table tr {
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .hover-row>td.el-table__cell {
|
||||||
|
background-color: #1e1e1e !important;
|
||||||
|
// opacity: 0.5;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.Segmentations {
|
.Segmentations {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -2066,6 +2299,7 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 30px;
|
margin-left: 30px;
|
||||||
|
width: 70%;
|
||||||
|
|
||||||
.serialNum {
|
.serialNum {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -2089,6 +2323,10 @@ export default {
|
||||||
|
|
||||||
.SegmentName {
|
.SegmentName {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
max-width: 120px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,130 +10,124 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ps">
|
<div class="ps">
|
||||||
<el-collapse v-model="activeNames">
|
<el-collapse v-model="activeNames">
|
||||||
<template v-for="(study, index) in studyList">
|
|
||||||
<el-collapse-item :key="`${study.StudyId}`" :name="`${study.StudyId}`" v-if="!study.IsCriticalSequence">
|
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<div v-if="readingTool !== 3 || !study.IsCriticalSequence" class="dicom-desc">
|
<div v-if="!study.IsCriticalSequence" class="dicom-desc">
|
||||||
<template v-if="taskInfo && taskInfo.IsShowStudyName">
|
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
<span v-if="taskInfo && taskInfo.IsShowStudyName && study.StudyName" :title="study.StudyName">
|
||||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
{{ study.StudyName }}
|
||||||
<span v-if="study.StudyName" :title="study.StudyName" style="margin-left: 5px;">{{ study.StudyName
|
</span>
|
||||||
}}</span>
|
</div>
|
||||||
<span v-else :title="study.Modalities" style="margin-left: 5px;">{{ `${study.Modalities}
|
<div>
|
||||||
(${study.SeriesCount})` }}</span>
|
<span class="study-meta-line" :title="study.Modalities">
|
||||||
</div>
|
<span class="study-code" :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||||
<div v-if="study.StudyName" style="text-overflow: ellipsis;overflow: hidden;">
|
<span class="study-modality">{{ `${study.Modalities}(${study.SeriesCount})` }}</span>
|
||||||
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
|
<span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
||||||
</div>
|
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
||||||
</template>
|
<h4>{{ $t('trials:ptData:title') }}</h4>
|
||||||
<template v-else-if="taskInfo && !taskInfo.IsShowStudyName">
|
<div class="patient-info-row">
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
<label>{{ $t('trials:ptData:label:patientSex') }}</label>
|
||||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
<span>{{ study.PatientSex }}</span>
|
||||||
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
</template>
|
<label>{{ $t('trials:ptData:label:patientWeight') }}</label>
|
||||||
<div class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
<span>{{ study.PatientWeight }}</span>
|
||||||
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
</div>
|
||||||
<h4>{{ $t('trials:ptData:title') }}</h4>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:totalDose') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:patientSex') }}</label>
|
<span>{{ study.RadionuclideTotalDose }}</span>
|
||||||
<span>{{ study.PatientSex }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:halfLife') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:patientWeight') }}</label>
|
<span>{{ study.RadionuclideHalfLife }}</span>
|
||||||
<span>{{ study.PatientWeight }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:injectTime') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:totalDose') }}</label>
|
<span>{{ study.RadiopharmaceuticalStartTime }}</span>
|
||||||
<span>{{ study.RadionuclideTotalDose }}</span>
|
</div>
|
||||||
</div>
|
<div class="patient-info-row">
|
||||||
<div class="patient-info-row">
|
<label>{{ $t('trials:ptData:label:acquisitionTime') }}</label>
|
||||||
<label>{{ $t('trials:ptData:label:halfLife') }}</label>
|
<span>{{ study.AcquisitionTime }}</span>
|
||||||
<span>{{ study.RadionuclideHalfLife }}</span>
|
</div>
|
||||||
</div>
|
<i slot="reference" class="el-icon-document"
|
||||||
<div class="patient-info-row">
|
style="font-size: 15px;cursor: pointer;color: #f5f7fa;" />
|
||||||
<label>{{ $t('trials:ptData:label:injectTime') }}</label>
|
</el-popover>
|
||||||
<span>{{ study.RadiopharmaceuticalStartTime }}</span>
|
</span>
|
||||||
</div>
|
</span>
|
||||||
<div class="patient-info-row">
|
</div>
|
||||||
<label>{{ $t('trials:ptData:label:acquisitionTime') }}</label>
|
|
||||||
<span>{{ study.AcquisitionTime }}</span>
|
</div>
|
||||||
</div>
|
<div v-else class="dicom-desc">
|
||||||
<i slot="reference" class="el-icon-document"
|
<!-- 关键序列 -->
|
||||||
style="font-size: 15px;cursor: pointer;color: #f5f7fa;" />
|
{{ $t('trials:reading:title:keySeries') }}
|
||||||
</el-popover>
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="dicom-list-container">
|
||||||
|
<div v-for="(series, i) in study.SeriesList" :key="series.Id" style="position:relative;margin-top:1px;"
|
||||||
|
@click="activeSeries(series, i, index)">
|
||||||
|
<div :class="{ 'series-active': index === activeStudyIndex && i === activeSeriesIndex }"
|
||||||
|
class="series-wrapper">
|
||||||
|
<div class="series-image">
|
||||||
|
<el-image style="width: 100%;height: 100%;"
|
||||||
|
:src="`${OSSclientConfig.basePath}${series.ImageResizePath || series.NoneDicomFileFirstFile}`"
|
||||||
|
fit="fill" crossorigin="anonymous" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="series-text">
|
||||||
</div>
|
<div v-if="series.IsExistMutiFrames && series.InstanceCount > 1"
|
||||||
<div v-else>
|
style="position: absolute;right: 0;top: 0;">
|
||||||
<!-- 关键序列 -->
|
<el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper">
|
||||||
{{ $t('trials:reading:title:keySeries') }}
|
<div class="frame_list">
|
||||||
</div>
|
<div v-for="(instance, idx) in series.InstanceInfoList" :key="instance.Id"
|
||||||
</template>
|
class="frame_content"
|
||||||
<div class="dicom-list-container">
|
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||||
<div v-for="(series, i) in study.SeriesList" :key="series.Id" style="position:relative;margin-top:1px;"
|
:style="{ 'margin-bottom': idx < series.InstanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||||
@click="activeSeries(series, i, index)">
|
@click.stop="showMultiFrames(index, series, i, instance)">
|
||||||
<div :class="{ 'series-active': index === activeStudyIndex && i === activeSeriesIndex }"
|
<div>
|
||||||
class="series-wrapper">
|
<div>{{ instance.InstanceNumber }}</div>
|
||||||
<div class="series-image">
|
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ?
|
||||||
<el-image style="width: 100%;height: 100%;"
|
instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
|
||||||
:src="`${OSSclientConfig.basePath}${series.ImageResizePath || series.NoneDicomFileFirstFile}`"
|
|
||||||
fit="fill" crossorigin="anonymous" />
|
|
||||||
</div>
|
|
||||||
<div class="series-text">
|
|
||||||
<div v-if="series.IsExistMutiFrames && series.InstanceCount > 1"
|
|
||||||
style="position: absolute;right: 0;top: 0;">
|
|
||||||
<el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper">
|
|
||||||
<div class="frame_list">
|
|
||||||
<div v-for="(instance, idx) in series.InstanceInfoList" :key="instance.Id"
|
|
||||||
class="frame_content"
|
|
||||||
:style="{ 'margin-bottom': idx < series.InstanceInfoList.length - 1 ? '5px' : '0px' }"
|
|
||||||
@click.stop="showMultiFrames(index, series, i, instance)">
|
|
||||||
<div>
|
|
||||||
<div>{{ instance.InstanceNumber }}</div>
|
|
||||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ?
|
|
||||||
instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<i slot="reference" class="el-icon-connection"
|
</div>
|
||||||
style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
|
<i slot="reference" class="el-icon-connection"
|
||||||
</el-popover>
|
style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
|
||||||
</div>
|
</el-popover>
|
||||||
<div v-if="!study.IsCriticalSequence" class="text-desc" :title="series.SeriesNumber">
|
</div>
|
||||||
#{{ series.SeriesNumber }}
|
<div v-if="!study.IsCriticalSequence" class="text-desc" :title="series.SeriesNumber">
|
||||||
|
#{{ series.SeriesNumber }}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="series.Description" class="text-desc" :title="series.Description">
|
<div v-if="series.Description" class="text-desc" :title="series.Description">
|
||||||
{{ series.Description }}
|
{{ series.Description }}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="series.SliceThickness && !study.IsCriticalSequence" class="text-desc">
|
<div v-if="series.SliceThickness && !study.IsCriticalSequence" class="text-desc">
|
||||||
T: {{ parseFloat(series.SliceThickness).toFixed(digitPlaces) }}
|
T: {{ parseFloat(series.SliceThickness).toFixed(digitPlaces) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-desc">
|
<div class="text-desc">
|
||||||
<span v-show="series.LoadedImageCount < series.InstanceCount">
|
<span v-show="series.LoadedImageCount < series.InstanceCount">
|
||||||
{{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image
|
{{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image
|
||||||
</span>
|
</span>
|
||||||
<span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{
|
<span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{
|
||||||
series.InstanceCount
|
series.InstanceCount
|
||||||
}} image</span>
|
}} image</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="line-height: 12px;">
|
<div style="line-height: 12px;">
|
||||||
<i v-show="series.IsBeSegment || series.IsBeMark || markedSeriesIds.includes(series.Id)"
|
<i v-show="series.IsBeSegment || series.IsBeMark || markedSeriesIds.includes(series.Id)"
|
||||||
class="el-icon-star-on" style="font-size: 12px;color: #ff5722;" />
|
class="el-icon-star-on" style="font-size: 12px;color: #ff5722;" />
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="series.LoadedImageCount > 0 && series.LoadedImageCount < series.InstanceCount"
|
</div>
|
||||||
style="width: 100%;">
|
<div v-if="series.LoadedImageCount > 0 && series.LoadedImageCount < series.InstanceCount"
|
||||||
<el-progress :percentage="parseInt((series.LoadedImageProgress / series.InstanceCount).toFixed(2))" />
|
style="width: 100%;">
|
||||||
</div>
|
<el-progress :percentage="parseInt((series.LoadedImageProgress / series.InstanceCount).toFixed(2))" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-collapse-item>
|
</div>
|
||||||
</template>
|
</el-collapse-item>
|
||||||
|
|
||||||
|
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -170,7 +164,8 @@ export default {
|
||||||
taskInfo: null,
|
taskInfo: null,
|
||||||
studyList: [],
|
studyList: [],
|
||||||
annotations: [],
|
annotations: [],
|
||||||
digitPlaces: 2
|
digitPlaces: 2,
|
||||||
|
activeInstanceId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -178,6 +173,7 @@ export default {
|
||||||
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||||
this.studyList = this.visitTaskInfo.StudyList
|
this.studyList = this.visitTaskInfo.StudyList
|
||||||
|
console.log(this.studyList)
|
||||||
this.annotations = this.visitTaskInfo.Annotations
|
this.annotations = this.visitTaskInfo.Annotations
|
||||||
if (this.studyList.length === 0) return
|
if (this.studyList.length === 0) return
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|
@ -200,13 +196,15 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
activeSeries(series, seriesIndex, studyIndex) {
|
activeSeries(series, seriesIndex, studyIndex) {
|
||||||
const photometricInterpretation = series?.InstanceInfoList[0]?.PhotometricInterpretation;
|
const photometricInterpretation = series?.InstanceInfoList[0]?.PhotometricInterpretation;
|
||||||
if (!photometricInterpretation || (photometricInterpretation !== 'MONOCHROME1' && photometricInterpretation !== 'MONOCHROME2'))
|
if ((!photometricInterpretation || (photometricInterpretation !== 'MONOCHROME1' && photometricInterpretation !== 'MONOCHROME2')) && this.readingTool === 3)
|
||||||
return this.$confirm(this.$t('trials:histogram:confirm:activeSeriesPhotometricInterpretationNotSupported'))
|
return this.$confirm(this.$t('trials:histogram:confirm:activeSeriesPhotometricInterpretationNotSupported'))
|
||||||
this.$emit('activeSeries', series)
|
this.$emit('activeSeries', series)
|
||||||
this.activeStudyIndex = studyIndex
|
this.activeStudyIndex = studyIndex
|
||||||
this.activeSeriesIndex = seriesIndex
|
this.activeSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceId = null
|
||||||
},
|
},
|
||||||
activeStudy(id) {
|
activeStudy(id) {
|
||||||
|
console.log('activeStudy')
|
||||||
if (this.activeNames.indexOf(id) > -1) return
|
if (this.activeNames.indexOf(id) > -1) return
|
||||||
this.activeNames.push(id)
|
this.activeNames.push(id)
|
||||||
},
|
},
|
||||||
|
|
@ -222,6 +220,7 @@ export default {
|
||||||
let obj = Object.assign({}, series)
|
let obj = Object.assign({}, series)
|
||||||
this.activeStudyIndex = studyIndex
|
this.activeStudyIndex = studyIndex
|
||||||
this.activeSeriesIndex = seriesIndex
|
this.activeSeriesIndex = seriesIndex
|
||||||
|
this.activeInstanceId = instance.Id
|
||||||
let taskId = this.visitTaskInfo.VisitTaskId
|
let taskId = this.visitTaskInfo.VisitTaskId
|
||||||
const nFrames = instance.NumberOfFrames || 0
|
const nFrames = instance.NumberOfFrames || 0
|
||||||
let imageIds = []
|
let imageIds = []
|
||||||
|
|
@ -265,10 +264,10 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.patient-info {
|
// .patient-info {
|
||||||
// display: inline-block;
|
// // display: inline-block;
|
||||||
text-align: right;
|
// // text-align: right;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.patient-info-popper {
|
.patient-info-popper {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -339,9 +338,39 @@ export default {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #d0d0d0;
|
color: #d0d0d0;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
white-space: nowrap;
|
white-space: normal;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
text-overflow: ellipsis;
|
}
|
||||||
|
|
||||||
|
.study-meta-line {
|
||||||
|
// display: grid;
|
||||||
|
// grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
// align-items: start;
|
||||||
|
// gap: 6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.study-meta-main {
|
||||||
|
display: block;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: normal;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.study-code,
|
||||||
|
.study-modality {
|
||||||
|
white-space: normal;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-info {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1;
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ps {
|
.ps {
|
||||||
|
|
@ -426,9 +455,13 @@ export default {
|
||||||
background-color: #000 !important;
|
background-color: #000 !important;
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
border-bottom-color: #5a5a5a;
|
border-bottom-color: #5a5a5a;
|
||||||
padding-left: 5px;
|
padding-left: 1px;
|
||||||
// height: 50px;
|
min-height: 40px;
|
||||||
|
height: auto;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,3 +470,48 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.study-wrapper {
|
||||||
|
.instance_frame_wrapper{
|
||||||
|
min-width: 120px;
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
border: 1px solid #2c2c2c;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.frame_list{
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.instance_frame_wrapper ::-webkit-scrollbar {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
}
|
||||||
|
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #d0d0d0;
|
||||||
|
}
|
||||||
|
.frame_content{
|
||||||
|
height: 50px;
|
||||||
|
padding: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 12px;
|
||||||
|
border: 1px solid #404040;
|
||||||
|
}
|
||||||
|
.frame_content:hover {
|
||||||
|
/* font-weight: bold; */
|
||||||
|
/* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
|
||||||
|
cursor: pointer;
|
||||||
|
/* color: #428bca; */
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
|
.frame_content_active {
|
||||||
|
border-color: #213a54 !important;
|
||||||
|
background-color: #213a54;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,7 @@ export default {
|
||||||
ijk[2] = viewport.getCurrentImageIdIndex()
|
ijk[2] = viewport.getCurrentImageIdIndex()
|
||||||
let modalityUnit
|
let modalityUnit
|
||||||
if (modality === 'US') {
|
if (modality === 'US') {
|
||||||
const calibratedResults = csToolsUtils.getCalibratedProbeUnitsAndValue(image, [ijk])
|
const calibratedResults = csToolsUtils.getCalibratedProbeUnitsAndValue(data, [ijk])
|
||||||
const hasEnhancedRegionValues = calibratedResults.values.every(
|
const hasEnhancedRegionValues = calibratedResults.values.every(
|
||||||
(value) => value !== null
|
(value) => value !== null
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,10 @@
|
||||||
<div v-if="series" class="right-bottom-text">
|
<div v-if="series" class="right-bottom-text">
|
||||||
<div v-show="imageInfo.location">Location: {{
|
<div v-show="imageInfo.location">Location: {{
|
||||||
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
|
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
|
||||||
}}</div>
|
}}</div>
|
||||||
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
|
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
|
||||||
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
|
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
|
||||||
}}</div>
|
}}</div>
|
||||||
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
|
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orientation-top">
|
<div class="orientation-top">
|
||||||
|
|
@ -242,6 +242,10 @@ export default {
|
||||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
|
||||||
resetViewport(this.viewportId)
|
resetViewport(this.viewportId)
|
||||||
})
|
})
|
||||||
|
DicomEvent.$on('renderSegmentationBychangeSegmention', async () => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
|
||||||
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, null, this.actionConfiguration, this.segmentationId, this.segmentIndex)
|
||||||
|
})
|
||||||
DicomEvent.$on('renderSegmentation', async (viewportId) => {
|
DicomEvent.$on('renderSegmentation', async (viewportId) => {
|
||||||
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
if (this.viewportId !== viewportId) return false
|
if (this.viewportId !== viewportId) return false
|
||||||
|
|
@ -595,10 +599,11 @@ export default {
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||||
if (!viewport) return
|
if (!viewport) return
|
||||||
|
let index = this.series.SliceIndex
|
||||||
if (forceFitToWindow) {
|
if (forceFitToWindow) {
|
||||||
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
||||||
viewport.render()
|
viewport.render()
|
||||||
|
this.setFullScreen(index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -613,6 +618,7 @@ export default {
|
||||||
|
|
||||||
if (!imageWidth || !imageHeight || !canvasWidth || !canvasHeight) {
|
if (!imageWidth || !imageHeight || !canvasWidth || !canvasHeight) {
|
||||||
viewport.render()
|
viewport.render()
|
||||||
|
this.setFullScreen(index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -622,6 +628,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewport.render()
|
viewport.render()
|
||||||
|
this.setFullScreen(index)
|
||||||
},
|
},
|
||||||
voiChange(v) {
|
voiChange(v) {
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||||
|
|
@ -703,11 +710,10 @@ export default {
|
||||||
viewport.render()
|
viewport.render()
|
||||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
// viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
||||||
viewport.resetProperties()
|
// viewport.resetProperties()
|
||||||
viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
|
viewport.setProperties({ voiRange: { upper: 5, lower: 0 }, invert: true }, this.volumeId)
|
||||||
viewport.render()
|
viewport.render()
|
||||||
renderingEngine.render()
|
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, data.segment, this.actionConfiguration, this.segmentationId, this.segmentIndex)
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, data.segment, this.actionConfiguration, this.segmentationId, this.segmentIndex)
|
||||||
|
|
@ -742,7 +748,7 @@ export default {
|
||||||
ijk[2] = viewport.getCurrentImageIdIndex()
|
ijk[2] = viewport.getCurrentImageIdIndex()
|
||||||
let modalityUnit
|
let modalityUnit
|
||||||
if (modality === 'US') {
|
if (modality === 'US') {
|
||||||
const calibratedResults = cornerstoneTools.utilities.getCalibratedProbeUnitsAndValue(image, [ijk])
|
const calibratedResults = cornerstoneTools.utilities.getCalibratedProbeUnitsAndValue(data, [ijk])
|
||||||
const hasEnhancedRegionValues = calibratedResults.values.every(
|
const hasEnhancedRegionValues = calibratedResults.values.every(
|
||||||
(value) => value !== null
|
(value) => value !== null
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
style="font-weight: bold;font-size: 14px;margin: 5px 0px;">
|
style="font-weight: bold;font-size: 14px;margin: 5px 0px;">
|
||||||
<div style="display: flex;justify-content: space-between;align-items: center;color:#fff;margin: 10px 0 5px">
|
<div style="display: flex;justify-content: space-between;align-items: center;color:#fff;margin: 10px 0 5px">
|
||||||
<span :title="question.Remark">{{ question.QuestionName }}</span>
|
<span :title="question.Remark">{{ question.QuestionName }}</span>
|
||||||
<el-button size="mini" v-if="readingTaskState < 2 && !question.IsPreinstall" @click="openAddTableCol(question)">
|
<el-button size="mini"
|
||||||
|
v-if="readingTaskState < 2 && !question.IsPreinstall && (question.AddDeleteTypeEnum === 0 || (isBaseline && question.AddDeleteTypeEnum === 1) || (!isBaseline && question.AddDeleteTypeEnum === 2))"
|
||||||
|
@click="openAddTableCol(question)">
|
||||||
{{ $t('common:button:add') }}
|
{{ $t('common:button:add') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -36,14 +38,15 @@
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('common:action:action')" show-overflow-tooltip width="100px"
|
<el-table-column :label="$t('common:action:action')" show-overflow-tooltip width="100px" fixed="right">
|
||||||
v-if="readingTaskState < 2" fixed="right">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="text" size="mini" @click="openAddTableCol(question, scope.$index)">
|
<el-button type="text" size="mini" @click="openAddTableCol(question, scope.$index)">
|
||||||
{{ question.IsPreinstall ? $t('CustomizeQuestionFormItem:button:assessment') : $t('common:button:edit') }}
|
{{ question.IsPreinstall ?
|
||||||
|
$t('CustomizeQuestionFormItem:button:assessment') : readingTaskState >= 2 ? $t('common:button:view') :
|
||||||
|
$t('common:button:edit') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="text" size="mini" :disabled="addOrEdit.visible"
|
<el-button type="text" size="mini" :disabled="addOrEdit.visible"
|
||||||
v-if="(scope.row.IsCurrentTaskAdd === 'True' || !question.IsCopyLesions || isBaseline) && !question.IsPreinstall"
|
v-if="readingTaskState < 2 && (scope.row.IsCurrentTaskAdd === 'True' || !question.IsCopyLesions || isBaseline) && !question.IsPreinstall && (question.AddDeleteTypeEnum === 0 || (isBaseline && question.AddDeleteTypeEnum === 1) || (!isBaseline && question.AddDeleteTypeEnum === 2))"
|
||||||
@click="deleteTableCol(question, scope.$index)">
|
@click="deleteTableCol(question, scope.$index)">
|
||||||
{{ $t('common:button:delete') }}
|
{{ $t('common:button:delete') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -65,7 +68,7 @@
|
||||||
@handleReadingChart="handleReadingChart" />
|
@handleReadingChart="handleReadingChart" />
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
<div slot="footer">
|
<div slot="footer" v-if="readingTaskState < 2">
|
||||||
<el-button size="small" @click="handleCancel">
|
<el-button size="small" @click="handleCancel">
|
||||||
{{ $t('common:button:cancel') }}
|
{{ $t('common:button:cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -647,7 +650,7 @@ export default {
|
||||||
let res = await submitTableQuestion(params)
|
let res = await submitTableQuestion(params)
|
||||||
if (res.IsSuccess) {
|
if (res.IsSuccess) {
|
||||||
this.QuestionsForm.RowId = res.Result.RowId
|
this.QuestionsForm.RowId = res.Result.RowId
|
||||||
obj.rowId = res.Result.RowId
|
// obj.rowId = res.Result.RowId
|
||||||
data.RowId = res.Result.RowId
|
data.RowId = res.Result.RowId
|
||||||
this.AnswersList.push(this.QuestionsForm)
|
this.AnswersList.push(this.QuestionsForm)
|
||||||
this.$emit('setFormItemData', { key: this.question.Id, val: this.AnswersList, question: this.question })
|
this.$emit('setFormItemData', { key: this.question.Id, val: this.AnswersList, question: this.question })
|
||||||
|
|
@ -1375,7 +1378,7 @@ export default {
|
||||||
// 移除问题标记值
|
// 移除问题标记值
|
||||||
this.$set(this.questionForm, obj.question.Id, null)
|
this.$set(this.questionForm, obj.question.Id, null)
|
||||||
}
|
}
|
||||||
if (obj.question.IsTableQuestion && obj.operateStateEnum === 4) {
|
if (obj.question.IsTableQuestion && (obj.operateStateEnum === 4 || obj.operateStateEnum === 24)) {
|
||||||
// 移除表格问题标记
|
// 移除表格问题标记
|
||||||
this.$set(this.QuestionsForm, obj.question.Id, null)
|
this.$set(this.QuestionsForm, obj.question.Id, null)
|
||||||
} else if (obj.question.IsTableQuestion && obj.operateStateEnum === 7 && this.question.Id === obj.question.ParentQsId) {
|
} else if (obj.question.IsTableQuestion && obj.operateStateEnum === 7 && this.question.Id === obj.question.ParentQsId) {
|
||||||
|
|
@ -1464,7 +1467,9 @@ export default {
|
||||||
if (!referencedImageId) return null
|
if (!referencedImageId) return null
|
||||||
const cacheKey = annotation.from || annotation.metadata.volumeId ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}`
|
const cacheKey = annotation.from || annotation.metadata.volumeId ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}`
|
||||||
const points = ['x', 'y', 'z'];
|
const points = ['x', 'y', 'z'];
|
||||||
const cachedStats = annotation.markTool === "ArrowAnnotate" ? annotation.data?.handles?.points[0] : annotation.data?.cachedStats?.[cacheKey]
|
const cachedStats = annotation.markTool === "ArrowAnnotate"
|
||||||
|
? annotation.data?.handles?.points[0]
|
||||||
|
: this.getAnnotationCachedStats(annotation, cacheKey, prop)
|
||||||
const hasProp = cachedStats
|
const hasProp = cachedStats
|
||||||
&& (Object.prototype.hasOwnProperty.call(cachedStats, prop) || cachedStats[points.indexOf(prop)])
|
&& (Object.prototype.hasOwnProperty.call(cachedStats, prop) || cachedStats[points.indexOf(prop)])
|
||||||
if (!hasProp) return null
|
if (!hasProp) return null
|
||||||
|
|
@ -1481,10 +1486,30 @@ export default {
|
||||||
} else if (this.isNoneDicom && value !== null) {
|
} else if (this.isNoneDicom && value !== null) {
|
||||||
value = this.reRound(csUtils.roundNumber(value), this.digitPlaces)
|
value = this.reRound(csUtils.roundNumber(value), this.digitPlaces)
|
||||||
}
|
}
|
||||||
|
if (prop === 'total' && value !== null) {
|
||||||
|
return this.formatStatSum(value)
|
||||||
|
}
|
||||||
return value !== null
|
return value !== null
|
||||||
? parseFloat(value).toFixed(this.digitPlaces)
|
? parseFloat(value).toFixed(this.digitPlaces)
|
||||||
: value
|
: value
|
||||||
},
|
},
|
||||||
|
getAnnotationCachedStats(annotation, cacheKey, prop) {
|
||||||
|
const cachedStatsMap = annotation?.data?.cachedStats || {}
|
||||||
|
const matchedStats = cachedStatsMap[cacheKey]
|
||||||
|
if (prop !== 'total') return matchedStats
|
||||||
|
const nmStats = Object.values(cachedStatsMap).find(item => item?.Modality === 'NM' && item.total !== undefined && item.total !== null)
|
||||||
|
return nmStats || matchedStats
|
||||||
|
},
|
||||||
|
formatStatSum(value) {
|
||||||
|
const num = Number(value)
|
||||||
|
if (!Number.isFinite(num)) return value
|
||||||
|
|
||||||
|
if (Math.abs(num - Math.round(num)) < 1e-6) {
|
||||||
|
return String(Math.round(num))
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.reRound(num, this.digitPlaces)
|
||||||
|
},
|
||||||
reRound(result, finalPrecision) {
|
reRound(result, finalPrecision) {
|
||||||
if (typeof result === 'string' && result.includes(', ')) {
|
if (typeof result === 'string' && result.includes(', ')) {
|
||||||
const numStrs = result.split(', ')
|
const numStrs = result.split(', ')
|
||||||
|
|
|
||||||
|
|
@ -545,7 +545,16 @@ export default {
|
||||||
const { question } = obj
|
const { question } = obj
|
||||||
let confirm = await this.$confirm(this.$t('segment:confirm:sureDelete'))
|
let confirm = await this.$confirm(this.$t('segment:confirm:sureDelete'))
|
||||||
if (!confirm) return false
|
if (!confirm) return false
|
||||||
this.$set(this.questionForm, question.Id, '')
|
if (this.isTableQuestion) {
|
||||||
|
this.questionForm[question.ParentQsId].some((item, index) => {
|
||||||
|
if (item.RowId === question.RowId) {
|
||||||
|
this.$set(this.questionForm[question.ParentQsId][index], question.Id, '')
|
||||||
|
}
|
||||||
|
return item.RowId === question.RowId
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$set(this.questionForm, question.Id, '')
|
||||||
|
}
|
||||||
let o = {
|
let o = {
|
||||||
Answer: '',
|
Answer: '',
|
||||||
SegmentId: null,
|
SegmentId: null,
|
||||||
|
|
@ -1237,7 +1246,9 @@ export default {
|
||||||
if (!referencedImageId) return null
|
if (!referencedImageId) return null
|
||||||
const cacheKey = annotation.from || annotation.metadata.volumeId ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}`
|
const cacheKey = annotation.from || annotation.metadata.volumeId ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}`
|
||||||
const points = ['x', 'y', 'z']
|
const points = ['x', 'y', 'z']
|
||||||
const cachedStats = annotation.markTool === "ArrowAnnotate" ? annotation.data?.handles?.points[0] : annotation.data?.cachedStats?.[cacheKey]
|
const cachedStats = annotation.markTool === "ArrowAnnotate"
|
||||||
|
? annotation.data?.handles?.points[0]
|
||||||
|
: this.getAnnotationCachedStats(annotation, cacheKey, prop)
|
||||||
const hasProp = cachedStats
|
const hasProp = cachedStats
|
||||||
&& (Object.prototype.hasOwnProperty.call(cachedStats, prop) || cachedStats[points.indexOf(prop)])
|
&& (Object.prototype.hasOwnProperty.call(cachedStats, prop) || cachedStats[points.indexOf(prop)])
|
||||||
if (!hasProp) return null
|
if (!hasProp) return null
|
||||||
|
|
@ -1254,10 +1265,30 @@ export default {
|
||||||
} else if (this.isNoneDicom && value !== null) {
|
} else if (this.isNoneDicom && value !== null) {
|
||||||
value = this.reRound(csUtils.roundNumber(value), this.digitPlaces)
|
value = this.reRound(csUtils.roundNumber(value), this.digitPlaces)
|
||||||
}
|
}
|
||||||
|
if (prop === 'total' && value !== null) {
|
||||||
|
return this.formatStatSum(value)
|
||||||
|
}
|
||||||
return value !== null
|
return value !== null
|
||||||
? parseFloat(value).toFixed(this.digitPlaces)
|
? parseFloat(value).toFixed(this.digitPlaces)
|
||||||
: value
|
: value
|
||||||
},
|
},
|
||||||
|
getAnnotationCachedStats(annotation, cacheKey, prop) {
|
||||||
|
const cachedStatsMap = annotation?.data?.cachedStats || {}
|
||||||
|
const matchedStats = cachedStatsMap[cacheKey]
|
||||||
|
if (prop !== 'total') return matchedStats
|
||||||
|
const nmStats = Object.values(cachedStatsMap).find(item => item?.Modality === 'NM' && item.total !== undefined && item.total !== null)
|
||||||
|
return nmStats || matchedStats
|
||||||
|
},
|
||||||
|
formatStatSum(value) {
|
||||||
|
const num = Number(value)
|
||||||
|
if (!Number.isFinite(num)) return value
|
||||||
|
|
||||||
|
if (Math.abs(num - Math.round(num)) < 1e-6) {
|
||||||
|
return String(Math.round(num))
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.reRound(num, this.digitPlaces)
|
||||||
|
},
|
||||||
reRound(result, finalPrecision) {
|
reRound(result, finalPrecision) {
|
||||||
if (typeof result === 'string' && result.includes(', ')) {
|
if (typeof result === 'string' && result.includes(', ')) {
|
||||||
const numStrs = result.split(', ')
|
const numStrs = result.split(', ')
|
||||||
|
|
@ -1555,4 +1586,5 @@ export default {
|
||||||
// min-height:400px;
|
// min-height:400px;
|
||||||
// color: #ddd;
|
// color: #ddd;
|
||||||
|
|
||||||
// }</style>
|
// }
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,15 @@
|
||||||
:class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' || question.Type === 'screenshot' ? 'uploadWrapper' : '']">
|
:class="[question.Type === 'group' ? 'mb' : question.Type === 'upload' || question.Type === 'screenshot' ? 'uploadWrapper' : '']">
|
||||||
<!-- 输入框 -->
|
<!-- 输入框 -->
|
||||||
<el-input v-if="question.Type === 'input'" v-model="questionForm[question.Id]"
|
<el-input v-if="question.Type === 'input'" v-model="questionForm[question.Id]"
|
||||||
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || question.IsPreinstall" />
|
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || question.IsPreinstall || readingTaskState >= 2" />
|
||||||
<!-- 多行文本输入框 -->
|
<!-- 多行文本输入框 -->
|
||||||
<el-input v-if="question.Type === 'textarea'" v-model="questionForm[question.Id]" type="textarea"
|
<el-input v-if="question.Type === 'textarea'" v-model="questionForm[question.Id]" type="textarea"
|
||||||
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || question.IsPreinstall"
|
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || question.IsPreinstall || readingTaskState >= 2"
|
||||||
:autosize="{ minRows: 2, maxRows: 4 }" />
|
:autosize="{ minRows: 2, maxRows: 4 }" />
|
||||||
<!-- 下拉框 -->
|
<!-- 下拉框 -->
|
||||||
<el-select v-if="question.Type === 'select'" v-model="questionForm[question.Id]" clearable
|
<el-select v-if="question.Type === 'select'" v-model="questionForm[question.Id]" clearable
|
||||||
:multiple="question.OptionTypeEnum === 1"
|
:multiple="question.OptionTypeEnum === 1"
|
||||||
:disabled="(question.TableQuestionType === 2 || question.IsPreinstall || question.QuestionGenre === 2) || (question.IsCopy && type === 'edit' && !IsBaseline && questionForm.IsCurrentTaskAdd === 'False')"
|
:disabled="(question.TableQuestionType === 2 || question.IsPreinstall || question.QuestionGenre === 2) || (question.IsCopy && type === 'edit' && !IsBaseline && questionForm.IsCurrentTaskAdd === 'False') || readingTaskState >= 2"
|
||||||
@change="((val) => { formItemChange(val, question) })">
|
@change="((val) => { formItemChange(val, question) })">
|
||||||
<template v-if="question.TableQuestionType === 1">
|
<template v-if="question.TableQuestionType === 1">
|
||||||
<el-option v-for="item in organList" :key="item.Id" :label="item[question.DataTableColumn]"
|
<el-option v-for="item in organList" :key="item.Id" :label="item[question.DataTableColumn]"
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
<!-- 单选 -->
|
<!-- 单选 -->
|
||||||
<el-radio-group v-if="question.Type === 'radio'" v-model="questionForm[question.Id]"
|
<el-radio-group v-if="question.Type === 'radio'" v-model="questionForm[question.Id]"
|
||||||
:disabled="question.TableQuestionType === 2 || question.IsPreinstall || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False')"
|
:disabled="question.TableQuestionType === 2 || question.IsPreinstall || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || readingTaskState >= 2"
|
||||||
@change="((val) => { formItemChange(val, question) })">
|
@change="((val) => { formItemChange(val, question) })">
|
||||||
<template v-if="question.DictionaryCode">
|
<template v-if="question.DictionaryCode">
|
||||||
<el-radio v-for="val in $d[question.DictionaryCode]" :key="val.id" :label="val.value">
|
<el-radio v-for="val in $d[question.DictionaryCode]" :key="val.id" :label="val.value">
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<!-- 复选框 -->
|
<!-- 复选框 -->
|
||||||
<el-checkbox-group v-if="question.Type === 'checkbox'"
|
<el-checkbox-group v-if="question.Type === 'checkbox'"
|
||||||
:disabled="question.TableQuestionType === 2 || question.IsPreinstall || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False')"
|
:disabled="question.TableQuestionType === 2 || question.IsPreinstall || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || readingTaskState >= 2"
|
||||||
v-model="questionForm[question.Id]">
|
v-model="questionForm[question.Id]">
|
||||||
<el-checkbox v-for="val in question.TypeValue.split('|')" :key="val" :label="val">
|
<el-checkbox v-for="val in question.TypeValue.split('|')" :key="val" :label="val">
|
||||||
{{ val }}
|
{{ val }}
|
||||||
|
|
@ -70,12 +70,13 @@
|
||||||
<el-input v-if="question.Type === 'class' && question.ClassifyShowType === 1"
|
<el-input v-if="question.Type === 'class' && question.ClassifyShowType === 1"
|
||||||
v-model="questionForm[question.Id]" />
|
v-model="questionForm[question.Id]" />
|
||||||
<el-select v-if="question.Type === 'class' && question.ClassifyShowType === 2" v-model="questionForm[question.Id]"
|
<el-select v-if="question.Type === 'class' && question.ClassifyShowType === 2" v-model="questionForm[question.Id]"
|
||||||
:disabled="!question.ClassifyEditType || question.IsPreinstall"
|
:disabled="!question.ClassifyEditType || question.IsPreinstall || readingTaskState >= 2"
|
||||||
@change="(val) => { formItemChange(val, question) }">
|
@change="(val) => { formItemChange(val, question) }">
|
||||||
<el-option v-for="val in question.TypeValue.split('|')" :key="val" :label="val.trim()" :value="val.trim()" />
|
<el-option v-for="val in question.TypeValue.split('|')" :key="val" :label="val.trim()" :value="val.trim()" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-radio-group v-if="question.Type === 'class' && question.ClassifyShowType === 3"
|
<el-radio-group v-if="question.Type === 'class' && question.ClassifyShowType === 3"
|
||||||
v-model="questionForm[question.Id]" :disabled="!question.ClassifyEditType || question.IsPreinstall"
|
v-model="questionForm[question.Id]"
|
||||||
|
:disabled="!question.ClassifyEditType || question.IsPreinstall || readingTaskState >= 2"
|
||||||
@change="(val) => { formItemChange(val, question) }">
|
@change="(val) => { formItemChange(val, question) }">
|
||||||
<template v-if="question.DictionaryCode">
|
<template v-if="question.DictionaryCode">
|
||||||
<el-radio v-for="val in $d[question.DictionaryCode]" :key="val.id" :label="val.value">
|
<el-radio v-for="val in $d[question.DictionaryCode]" :key="val.id" :label="val.value">
|
||||||
|
|
@ -114,7 +115,7 @@
|
||||||
@blur="questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
|
@blur="questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
|
||||||
v-model="questionForm[question.Id]"
|
v-model="questionForm[question.Id]"
|
||||||
:title="questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? `${questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].SegmentationName}\n${questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].SegmentName}\n${questionForm[question.Id]}` : question.Remark"
|
:title="questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? `${questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].SegmentationName}\n${questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].SegmentName}\n${questionForm[question.Id]}` : question.Remark"
|
||||||
:disabled="(questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1 || question.IsPreinstall"
|
:disabled="(questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1 || question.IsPreinstall || readingTaskState >= 2"
|
||||||
style="width: 150px;margin-right: 5px;">
|
style="width: 150px;margin-right: 5px;">
|
||||||
<template v-if="question.Unit !== 0" slot="append">
|
<template v-if="question.Unit !== 0" slot="append">
|
||||||
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
|
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
|
||||||
|
|
@ -159,7 +160,7 @@
|
||||||
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
|
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
|
||||||
v-model="questionForm[question.Id]"
|
v-model="questionForm[question.Id]"
|
||||||
:title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : question.Remark"
|
:title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : question.Remark"
|
||||||
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1 || question.IsPreinstall"
|
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1 || question.IsPreinstall || readingTaskState >= 2"
|
||||||
style="width: 150px;margin-right: 5px;">
|
style="width: 150px;margin-right: 5px;">
|
||||||
<template v-if="question.Unit !== 0" slot="append">
|
<template v-if="question.Unit !== 0" slot="append">
|
||||||
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
|
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
|
||||||
|
|
@ -228,7 +229,7 @@
|
||||||
<template v-else-if="question.ValueType === 2" slot="prefix">%</template>
|
<template v-else-if="question.ValueType === 2" slot="prefix">%</template>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-input type="text" v-else-if="question.Type === 'number' && question.DataSource !== 1"
|
<el-input type="text" v-else-if="question.Type === 'number' && question.DataSource !== 1"
|
||||||
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || question.IsPreinstall"
|
:disabled="question.TableQuestionType === 2 || (question.IsCopy && type === 'edit' && !isBaseline && questionForm.IsCurrentTaskAdd === 'False') || question.IsPreinstall || readingTaskState >= 2"
|
||||||
@change="((val) => { formItemNumberChange(val, question) })" @input="numberInput(question.Id)"
|
@change="((val) => { formItemNumberChange(val, question) })" @input="numberInput(question.Id)"
|
||||||
@blur="handleBlur(questionForm[question.Id], questionForm, question.Id)"
|
@blur="handleBlur(questionForm[question.Id], questionForm, question.Id)"
|
||||||
v-model="questionForm[question.Id]">
|
v-model="questionForm[question.Id]">
|
||||||
|
|
@ -237,7 +238,8 @@
|
||||||
question.CustomUnit }}</template>
|
question.CustomUnit }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<el-input type="text" v-else-if="question.Type === 'number' && question.DataSource === 1"
|
<el-input type="text" v-else-if="question.Type === 'number' && question.DataSource === 1"
|
||||||
:disabled="question.DataSource === 1" @input="numberInput(question.Id, true) || question.IsPreinstall"
|
:disabled="question.DataSource === 1"
|
||||||
|
@input="numberInput(question.Id, true) || question.IsPreinstall || readingTaskState >= 2"
|
||||||
@blur="handleCalculationBlur(calculationValue)" v-model="calculationValue">
|
@blur="handleCalculationBlur(calculationValue)" v-model="calculationValue">
|
||||||
<template slot="append" v-if="question.Unit !== 0">{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit)
|
<template slot="append" v-if="question.Unit !== 0">{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit)
|
||||||
:
|
:
|
||||||
|
|
@ -257,8 +259,9 @@
|
||||||
</template>
|
</template>
|
||||||
<!-- 上传图像 -->
|
<!-- 上传图像 -->
|
||||||
<el-upload v-if="question.Type === 'upload' || question.Type === 'screenshot'"
|
<el-upload v-if="question.Type === 'upload' || question.Type === 'screenshot'"
|
||||||
:disabled="readingTaskState === 2 || question.IsPreinstall" action :accept="question.FileType"
|
:disabled="readingTaskState === 2 || question.IsPreinstall || readingTaskState >= 2" action
|
||||||
:limit="question.ImageCount === 0 ? 100 : question.ImageCount" :on-preview="handlePictureCardPreview"
|
:accept="question.FileType" :limit="question.ImageCount === 0 ? 100 : question.ImageCount"
|
||||||
|
:on-preview="handlePictureCardPreview"
|
||||||
:before-upload="(file) => { return handleBeforeUpload(file, question.FileType, question.Type) }"
|
:before-upload="(file) => { return handleBeforeUpload(file, question.FileType, question.Type) }"
|
||||||
:http-request="uploadScreenshot" :on-remove="handleRemove" :file-list="fileList"
|
:http-request="uploadScreenshot" :on-remove="handleRemove" :file-list="fileList"
|
||||||
:class="{ disabled: question.ImageCount === 0 ? false : fileList.length >= question.ImageCount }">
|
:class="{ disabled: question.ImageCount === 0 ? false : fileList.length >= question.ImageCount }">
|
||||||
|
|
@ -416,7 +419,7 @@ export default {
|
||||||
},
|
},
|
||||||
validatorNumberInput(rule, value, callback) {
|
validatorNumberInput(rule, value, callback) {
|
||||||
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
|
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
|
||||||
if (value === '') {
|
if (value === '' || value == null) {
|
||||||
callback();
|
callback();
|
||||||
} else {
|
} else {
|
||||||
if (!reg.test(value)) {
|
if (!reg.test(value)) {
|
||||||
|
|
|
||||||
|
|
@ -226,10 +226,12 @@ async function readingSegmentByConfig(series, visitInfo, viewportId, segmentatio
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
function selectSegmentation(viewportId, segmentationId) {
|
function selectSegmentation(viewportId, segmentationId) {
|
||||||
|
if (!segmentation.state.getSegmentation(segmentationId)) return false
|
||||||
segmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId)
|
segmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId)
|
||||||
}
|
}
|
||||||
function selectSegment(viewportId, segmentationId, segmentIndex) {
|
function selectSegment(viewportId, segmentationId, segmentIndex) {
|
||||||
if (!segmentIndex || !segmentationId) return false
|
if (!segmentIndex || !segmentationId) return false
|
||||||
|
if (!segmentation.state.getSegmentation(segmentationId)) return false
|
||||||
selectSegmentation(viewportId, segmentationId)
|
selectSegmentation(viewportId, segmentationId)
|
||||||
segmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
|
segmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ const config = {
|
||||||
'name': '圆形工具',
|
'name': '圆形工具',
|
||||||
'icon': 'oval',
|
'icon': 'oval',
|
||||||
'toolName': 'CircleROI',
|
'toolName': 'CircleROI',
|
||||||
'props': ['radius', 'area', 'mean', 'max', 'stdDev'],
|
'props': ['radius', 'area', 'mean', 'max', 'stdDev', 'total'],
|
||||||
'i18nKey': 'trials:reading:button:Circle',
|
'i18nKey': 'trials:reading:button:Circle',
|
||||||
'isDisabled': false,
|
'isDisabled': false,
|
||||||
'disabledReason': ''
|
'disabledReason': ''
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
import { EPSILON, utilities as csUtils } from "@cornerstonejs/core"
|
||||||
|
import * as cornerstoneTools from "@cornerstonejs/tools"
|
||||||
|
const { triggerAnnotationModified } = cornerstoneTools.annotation.state
|
||||||
|
|
||||||
|
const { transformWorldToIndex } = csUtils
|
||||||
|
const { BaseTool, Enums, utilities } = cornerstoneTools
|
||||||
|
const { MeasurementType, ChangeTypes } = Enums
|
||||||
|
const { getCanvasCircleCorners } = utilities.math.circle
|
||||||
|
const { pointInEllipse } = utilities.math.ellipse
|
||||||
|
const { getCalibratedLengthUnitsAndScale } = utilities
|
||||||
|
|
||||||
|
class CircleROITool extends cornerstoneTools.CircleROITool {
|
||||||
|
static toolName = "CircleROI"
|
||||||
|
|
||||||
|
constructor(toolProps = {}, defaultToolProps) {
|
||||||
|
super(toolProps, defaultToolProps)
|
||||||
|
|
||||||
|
this._calculateCachedStats = (
|
||||||
|
annotation,
|
||||||
|
viewport,
|
||||||
|
renderingEngine,
|
||||||
|
enabledElement
|
||||||
|
) => {
|
||||||
|
if (!this.configuration.calculateStats) return
|
||||||
|
|
||||||
|
const { data } = annotation
|
||||||
|
const { element } = viewport
|
||||||
|
const wasInvalidated = annotation.invalidated
|
||||||
|
const { points } = data.handles
|
||||||
|
const canvasCoordinates = points.map((point) =>
|
||||||
|
viewport.worldToCanvas(point)
|
||||||
|
)
|
||||||
|
const canvasCenter = canvasCoordinates[0]
|
||||||
|
const canvasTop = canvasCoordinates[1]
|
||||||
|
const [topLeftCanvas, bottomRightCanvas] = getCanvasCircleCorners([
|
||||||
|
canvasCenter,
|
||||||
|
canvasTop
|
||||||
|
])
|
||||||
|
const topLeftWorld = viewport.canvasToWorld(topLeftCanvas)
|
||||||
|
const bottomRightWorld = viewport.canvasToWorld(bottomRightCanvas)
|
||||||
|
const { cachedStats } = data
|
||||||
|
const targetIds = Object.keys(cachedStats)
|
||||||
|
|
||||||
|
for (let i = 0; i < targetIds.length; i++) {
|
||||||
|
const targetId = targetIds[i];
|
||||||
|
const image = this.getTargetImageData(targetId)
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
console.warn("image not found for stats:", targetId)
|
||||||
|
delete cachedStats[targetId]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dimensions, imageData, metadata, voxelManager } = image
|
||||||
|
const handles = points.map((point) => imageData.worldToIndex(point))
|
||||||
|
const calibrate = getCalibratedLengthUnitsAndScale(image, handles)
|
||||||
|
const radius = CircleROITool.calculateLengthInIndex(
|
||||||
|
calibrate,
|
||||||
|
handles.slice(0, 2)
|
||||||
|
)
|
||||||
|
const area = Math.PI * radius * radius
|
||||||
|
const perimeter = 2 * Math.PI * radius
|
||||||
|
const isEmptyArea = radius === 0
|
||||||
|
const { unit, areaUnit } = calibrate
|
||||||
|
const namedArea = {
|
||||||
|
name: "area",
|
||||||
|
value: area,
|
||||||
|
unit: areaUnit,
|
||||||
|
type: MeasurementType.Area,
|
||||||
|
}
|
||||||
|
const namedCircumference = {
|
||||||
|
name: "circumference",
|
||||||
|
value: perimeter,
|
||||||
|
unit,
|
||||||
|
type: MeasurementType.Linear,
|
||||||
|
}
|
||||||
|
const namedRadius = {
|
||||||
|
name: "radius",
|
||||||
|
value: radius,
|
||||||
|
unit,
|
||||||
|
type: MeasurementType.Linear,
|
||||||
|
}
|
||||||
|
const statsArray = [namedArea, namedRadius, namedCircumference]
|
||||||
|
|
||||||
|
cachedStats[targetId] = {
|
||||||
|
Modality: metadata.Modality,
|
||||||
|
area,
|
||||||
|
isEmptyArea,
|
||||||
|
areaUnit,
|
||||||
|
radius,
|
||||||
|
radiusUnit: unit,
|
||||||
|
perimeter,
|
||||||
|
statsArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
const pos1Index = transformWorldToIndex(imageData, topLeftWorld)
|
||||||
|
const pos2Index = transformWorldToIndex(imageData, bottomRightWorld)
|
||||||
|
|
||||||
|
this.isHandleOutsideImage = !BaseTool.isInsideVolume(dimensions, [
|
||||||
|
pos1Index,
|
||||||
|
pos2Index,
|
||||||
|
])
|
||||||
|
if (!this.isHandleOutsideImage) {
|
||||||
|
const iMin = Math.min(pos1Index[0], pos2Index[0])
|
||||||
|
const iMax = Math.max(pos1Index[0], pos2Index[0])
|
||||||
|
const jMin = Math.min(pos1Index[1], pos2Index[1])
|
||||||
|
const jMax = Math.max(pos1Index[1], pos2Index[1])
|
||||||
|
const kMin = Math.min(pos1Index[2], pos2Index[2])
|
||||||
|
const kMax = Math.max(pos1Index[2], pos2Index[2])
|
||||||
|
const boundsIJK = [
|
||||||
|
[iMin, iMax],
|
||||||
|
[jMin, jMax],
|
||||||
|
[kMin, kMax],
|
||||||
|
]
|
||||||
|
const center = points[0];
|
||||||
|
const xRadius = Math.abs(topLeftWorld[0] - bottomRightWorld[0]) / 2
|
||||||
|
const yRadius = Math.abs(topLeftWorld[1] - bottomRightWorld[1]) / 2
|
||||||
|
const zRadius = Math.abs(topLeftWorld[2] - bottomRightWorld[2]) / 2
|
||||||
|
const ellipseObj = {
|
||||||
|
center,
|
||||||
|
xRadius: xRadius < EPSILON / 2 ? 0 : xRadius,
|
||||||
|
yRadius: yRadius < EPSILON / 2 ? 0 : yRadius,
|
||||||
|
zRadius: zRadius < EPSILON / 2 ? 0 : zRadius,
|
||||||
|
}
|
||||||
|
const pixelUnitsOptions = {
|
||||||
|
isPreScaled: utilities.viewport.isViewportPreScaled(
|
||||||
|
viewport,
|
||||||
|
targetId
|
||||||
|
),
|
||||||
|
isSuvScaled: this.isSuvScaled(
|
||||||
|
viewport,
|
||||||
|
targetId,
|
||||||
|
annotation.metadata.referencedImageId
|
||||||
|
),
|
||||||
|
}
|
||||||
|
const modalityUnit = utilities.getPixelValueUnits(
|
||||||
|
metadata.Modality,
|
||||||
|
annotation.metadata.referencedImageId,
|
||||||
|
pixelUnitsOptions
|
||||||
|
)
|
||||||
|
let pointsInShape
|
||||||
|
if (voxelManager) {
|
||||||
|
pointsInShape = voxelManager.forEach(
|
||||||
|
this.configuration.statsCalculator.statsCallback,
|
||||||
|
{
|
||||||
|
isInObject: (pointLPS) =>
|
||||||
|
pointInEllipse(ellipseObj, pointLPS, { fast: true }),
|
||||||
|
boundsIJK,
|
||||||
|
imageData,
|
||||||
|
returnPoints: this.configuration.storePointData,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const stats = this.configuration.statsCalculator.getStatistics()
|
||||||
|
const mean = stats.mean?.value
|
||||||
|
const count = stats.count?.value
|
||||||
|
const total =
|
||||||
|
Array.isArray(mean) && Number.isFinite(count)
|
||||||
|
? mean.map((value) => value * count)
|
||||||
|
: Number.isFinite(mean) && Number.isFinite(count)
|
||||||
|
? mean * count
|
||||||
|
: undefined;
|
||||||
|
cachedStats[targetId] = {
|
||||||
|
...cachedStats[targetId],
|
||||||
|
Modality: metadata.Modality,
|
||||||
|
mean,
|
||||||
|
max: stats.max?.value,
|
||||||
|
min: stats.min?.value,
|
||||||
|
total,
|
||||||
|
count,
|
||||||
|
pointsInShape,
|
||||||
|
stdDev: stats.stdDev?.value,
|
||||||
|
modalityUnit,
|
||||||
|
statsArray: [...statsArray, ...stats.array],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
annotation.invalidated = false
|
||||||
|
if (wasInvalidated) {
|
||||||
|
triggerAnnotationModified(
|
||||||
|
annotation,
|
||||||
|
element,
|
||||||
|
ChangeTypes.StatsUpdated
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedStats
|
||||||
|
}
|
||||||
|
|
||||||
|
this._throttledCalculateCachedStats = utilities.throttle(
|
||||||
|
this._calculateCachedStats,
|
||||||
|
100,
|
||||||
|
{ trailing: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CircleROITool
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { getEnabledElement } from '@cornerstonejs/core'
|
||||||
|
import * as cornerstoneTools from '@cornerstonejs/tools'
|
||||||
|
|
||||||
|
|
||||||
|
class MIPJumpToClickTool extends cornerstoneTools.MIPJumpToClickTool {
|
||||||
|
static toolName = 'MIPJumpToClickTool'
|
||||||
|
|
||||||
|
constructor(toolProps = {}, defaultToolProps) {
|
||||||
|
const mergedDefaultToolProps = defaultToolProps || {
|
||||||
|
supportedInteractionTypes: ['Mouse', 'Touch'],
|
||||||
|
configuration: {
|
||||||
|
targetViewportIds: [],
|
||||||
|
sourceViewportIds: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
super(toolProps, mergedDefaultToolProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseClickCallback(evt) {
|
||||||
|
const { element, viewportId } = evt.detail || {}
|
||||||
|
const enabledElement = element ? getEnabledElement(element) : null
|
||||||
|
const sourceViewportId = viewportId || enabledElement?.viewport?.id || ''
|
||||||
|
const sourceViewportIds = this.configuration?.sourceViewportIds
|
||||||
|
const hasSourceLimit = Array.isArray(sourceViewportIds) && sourceViewportIds.length > 0
|
||||||
|
if (hasSourceLimit && !sourceViewportIds.includes(sourceViewportId)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseClickCallback(evt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MIPJumpToClickTool
|
||||||
|
|
@ -783,8 +783,8 @@
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog v-if="clinicalDataVisible" :title="`${$t('trials:readingPeriod:dialogTitle:clinicalData')}(${rowData.SubjectCode
|
<el-dialog v-if="clinicalDataVisible" :title="`${$t('trials:readingPeriod:dialogTitle:clinicalData')}(${rowData.SubjectCode
|
||||||
}|${rowData.TaskName}|${rowData.TrialReadingCriterionName})`" :visible.sync="clinicalDataVisible"
|
}|${rowData.TaskName}|${rowData.TrialReadingCriterionName})`" :visible.sync="clinicalDataVisible"
|
||||||
:close-on-click-modal="false" append-to-body>
|
:close-on-click-modal="false" append-to-body width="70%">
|
||||||
<ClinicalData :trial-reading-criterion-id="TrialReadingCriterionId" :data="currentData" />
|
<ClinicalData :trial-reading-criterion-id="TrialReadingCriterionId" :data="currentData" :showUpdateStatusBtn="rowData.ReadingCategory === 2 || rowData.ReadingCategory === 5"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog v-if="exportVisible" v-dialogDrag :title="$t('trials:reviewTrack:button:export')"
|
<el-dialog v-if="exportVisible" v-dialogDrag :title="$t('trials:reviewTrack:button:export')"
|
||||||
:visible.sync="exportVisible" :close-on-click-modal="false" width="60%" append-to-body>
|
:visible.sync="exportVisible" :close-on-click-modal="false" width="60%" append-to-body>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,9 @@
|
||||||
<!-- 输入框 -->
|
<!-- 输入框 -->
|
||||||
<div>
|
<div>
|
||||||
<template
|
<template
|
||||||
v-if="!((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)" />
|
v-if="!((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)">
|
||||||
|
<!-- {{ `${questionForm[scope.row.QuestionId] instanceof Array ? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId] : questionForm[scope.row.QuestionId]}` }} -->
|
||||||
|
</template>
|
||||||
<el-input
|
<el-input
|
||||||
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type === 'input' || scope.row.Type === 'textarea') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
|
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type === 'input' || scope.row.Type === 'textarea') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
|
||||||
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
|
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,24 @@
|
||||||
<el-form-item :label="$t('trials:sitesList:table:siteName')">
|
<el-form-item :label="$t('trials:sitesList:table:siteName')">
|
||||||
<el-input v-model="listQuery.TrialSiteName" class="mr" clearable />
|
<el-input v-model="listQuery.TrialSiteName" class="mr" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('trials:sitesList:table:Country')">
|
||||||
|
<el-select v-model="listQuery.Country" clearable class="mr">
|
||||||
|
<el-option v-for="item of $d.SiteCountry" :key="item.id" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<!-- 中心别名 -->
|
<!-- 中心别名 -->
|
||||||
<!-- <el-form-item :label="$t('trials:sitesList:table:siteAliasName')">
|
<!-- <el-form-item :label="$t('trials:sitesList:table:siteAliasName')">
|
||||||
<el-input v-model="listQuery.TrialSiteAliasName" class="mr" clearable />
|
<el-input v-model="listQuery.TrialSiteAliasName" class="mr" clearable />
|
||||||
</el-form-item> -->
|
</el-form-item> -->
|
||||||
<!-- 关键词 -->
|
<!-- 关键词 -->
|
||||||
<el-form-item :label="$t('trials:sitesList:form:keyWord')">
|
<el-form-item :label="$t('trials:sitesList:form:keyWord')">
|
||||||
<el-input
|
<el-input v-model="listQuery.UserKeyInfo" style="width: 200px" class="mr" clearable
|
||||||
v-model="listQuery.UserKeyInfo"
|
:placeholder="$t('trials:sitesList:formPlaceholder:keyWord')" />
|
||||||
style="width: 200px"
|
|
||||||
class="mr"
|
|
||||||
clearable
|
|
||||||
:placeholder="$t('trials:sitesList:formPlaceholder:keyWord')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<el-form-item :label="$t('trials:sitesList:table:status')">
|
<el-form-item :label="$t('trials:sitesList:table:status')">
|
||||||
<el-select v-model="listQuery.IsDeleted" clearable class="mr">
|
<el-select v-model="listQuery.IsDeleted" clearable class="mr">
|
||||||
<el-option
|
<el-option v-for="item of $d.IsSiteDisable" :key="item.label" :label="item.label" :value="item.value" />
|
||||||
v-for="item of $d.IsSiteDisable"
|
|
||||||
:key="item.label"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
|
@ -41,114 +36,61 @@
|
||||||
{{ $t('common:button:search') }}
|
{{ $t('common:button:search') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 重置 -->
|
<!-- 重置 -->
|
||||||
<el-button
|
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
|
||||||
type="primary"
|
|
||||||
icon="el-icon-refresh-left"
|
|
||||||
@click="handleReset"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:reset') }}
|
{{ $t('common:button:reset') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 中心调研 -->
|
<!-- 中心调研 -->
|
||||||
<el-button
|
<el-button v-hasPermi="[
|
||||||
v-hasPermi="[
|
'trials:trials-panel:setting:personnel-manage:questionnaire-record',
|
||||||
'trials:trials-panel:setting:personnel-manage:questionnaire-record',
|
]" type="primary" icon="el-icon-info" @click="handleResearchList">
|
||||||
]"
|
|
||||||
type="primary"
|
|
||||||
icon="el-icon-info"
|
|
||||||
@click="handleResearchList"
|
|
||||||
>
|
|
||||||
{{ $t('trials:sitesList:button:siteResearch') }}
|
{{ $t('trials:sitesList:button:siteResearch') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 添加中心 -->
|
<!-- 添加中心 -->
|
||||||
<el-button
|
<el-button v-hasPermi="[
|
||||||
v-hasPermi="[
|
'trials:trials-panel:setting:personnel-manage:add-site',
|
||||||
'trials:trials-panel:setting:personnel-manage:add-site',
|
]" type="primary" icon="el-icon-plus" @click="handleAdd">
|
||||||
]"
|
|
||||||
type="primary"
|
|
||||||
icon="el-icon-plus"
|
|
||||||
@click="handleAdd"
|
|
||||||
>
|
|
||||||
{{ $t('trials:sitesList:dialogTitle:assignSite') }}
|
{{ $t('trials:sitesList:dialogTitle:assignSite') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button type="primary" icon="el-icon-download" :disabled="list.length === 0"
|
||||||
type="primary"
|
@click="handleResearchListExport">
|
||||||
icon="el-icon-download"
|
|
||||||
:disabled="list.length === 0"
|
|
||||||
@click="handleResearchListExport"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:export') }}
|
{{ $t('common:button:export') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 下载模板 -->
|
<!-- 下载模板 -->
|
||||||
<el-button
|
<el-button type="primary" icon="el-icon-download" v-hasPermi="[
|
||||||
type="primary"
|
'trials:trials-panel:setting:personnel-manage:download',
|
||||||
icon="el-icon-download"
|
]" @click="handleDownload">
|
||||||
v-hasPermi="[
|
|
||||||
'trials:trials-panel:setting:personnel-manage:download',
|
|
||||||
]"
|
|
||||||
@click="handleDownload"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:downloadTpl') }}
|
{{ $t('common:button:downloadTpl') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-hasPermi="['trials:trials-panel:setting:personnel-manage:upload']" type="primary"
|
||||||
v-hasPermi="['trials:trials-panel:setting:personnel-manage:upload']"
|
icon="el-icon-upload2" @click="handleUpload">
|
||||||
type="primary"
|
|
||||||
icon="el-icon-upload2"
|
|
||||||
@click="handleUpload"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:upload') }}
|
{{ $t('common:button:upload') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table v-loading="listLoading" :data="list" stripe @sort-change="handleSortByColumn">
|
||||||
v-loading="listLoading"
|
|
||||||
:data="list"
|
|
||||||
stripe
|
|
||||||
@sort-change="handleSortByColumn"
|
|
||||||
>
|
|
||||||
<el-table-column type="index" width="50" />
|
<el-table-column type="index" width="50" />
|
||||||
<!-- 中心编号 -->
|
<!-- 中心编号 -->
|
||||||
<el-table-column
|
<el-table-column prop="TrialSiteCode" :label="$t('trials:sitesList:table:siteId')" show-overflow-tooltip
|
||||||
prop="TrialSiteCode"
|
sortable="custom" width="120">
|
||||||
:label="$t('trials:sitesList:table:siteId')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable="custom"
|
|
||||||
width="120"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span v-if="!!scope.row.TrialSiteCode">{{
|
<span v-if="!!scope.row.TrialSiteCode">{{
|
||||||
scope.row.TrialSiteCode
|
scope.row.TrialSiteCode
|
||||||
}}</span>
|
}}</span>
|
||||||
<i
|
<i v-else class="el-icon-warning" style="color: #f44336; font-size: 14px" />
|
||||||
v-else
|
|
||||||
class="el-icon-warning"
|
|
||||||
style="color: #f44336; font-size: 14px"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 中心名称 -->
|
<!-- 中心名称 -->
|
||||||
<el-table-column
|
<el-table-column prop="TrialSiteName" :label="$t('trials:sitesList:table:siteName')" show-overflow-tooltip
|
||||||
prop="TrialSiteName"
|
sortable="custom" min-width="120" />
|
||||||
:label="$t('trials:sitesList:table:siteName')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable="custom"
|
|
||||||
min-width="120"
|
|
||||||
/>
|
|
||||||
<!-- 中心别名 -->
|
<!-- 中心别名 -->
|
||||||
<el-table-column
|
<el-table-column prop="TrialSiteAliasName" :label="$t('trials:sitesList:table:siteAliasName')"
|
||||||
prop="TrialSiteAliasName"
|
show-overflow-tooltip sortable="custom" min-width="120" />
|
||||||
:label="$t('trials:sitesList:table:siteAliasName')"
|
<el-table-column prop="Country" :label="$t('trials:sitesList:table:Country')" show-overflow-tooltip
|
||||||
show-overflow-tooltip
|
sortable="custom" min-width="120" />
|
||||||
sortable="custom"
|
|
||||||
min-width="120"
|
|
||||||
/>
|
|
||||||
<!-- 参与者 -->
|
<!-- 参与者 -->
|
||||||
<el-table-column
|
<el-table-column prop="UserNameList" :label="$t('trials:sitesList:table:staff')" show-overflow-tooltip
|
||||||
prop="UserNameList"
|
min-width="100">
|
||||||
:label="$t('trials:sitesList:table:staff')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
min-width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button size="small" type="text" @click="getCrcList(scope.row)">
|
<el-button size="small" type="text" @click="getCrcList(scope.row)">
|
||||||
{{
|
{{
|
||||||
|
|
@ -160,29 +102,14 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- Subjects -->
|
<!-- Subjects -->
|
||||||
<el-table-column
|
<el-table-column prop="SubjectCount" min-width="100" :label="$t('trials:site:table:subjects')"
|
||||||
prop="SubjectCount"
|
show-overflow-tooltip sortable="custom" />
|
||||||
min-width="100"
|
|
||||||
:label="$t('trials:site:table:subjects')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable="custom"
|
|
||||||
/>
|
|
||||||
<!-- Visits -->
|
<!-- Visits -->
|
||||||
<el-table-column
|
<el-table-column prop="VisitCount" min-width="100" :label="$t('trials:site:table:visits')" show-overflow-tooltip
|
||||||
prop="VisitCount"
|
sortable="custom" />
|
||||||
min-width="100"
|
|
||||||
:label="$t('trials:site:table:visits')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable="custom"
|
|
||||||
/>
|
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<el-table-column
|
<el-table-column prop="IsDeleted" :label="$t('trials:sitesList:table:status')" show-overflow-tooltip sortable
|
||||||
prop="IsDeleted"
|
min-width="100">
|
||||||
:label="$t('trials:sitesList:table:status')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
min-width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
|
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
|
||||||
$fd('IsSiteDisable', scope.row.IsDeleted)
|
$fd('IsSiteDisable', scope.row.IsDeleted)
|
||||||
|
|
@ -193,21 +120,11 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- DICOM AE -->
|
<!-- DICOM AE -->
|
||||||
<el-table-column
|
<el-table-column v-if="isPACSConnect" prop="CallingAEList" :label="$t('trials:sitesList:table:AE')"
|
||||||
v-if="isPACSConnect"
|
show-overflow-tooltip sortable min-width="100">
|
||||||
prop="CallingAEList"
|
|
||||||
:label="$t('trials:sitesList:table:AE')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
min-width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button v-if="scope.row.CallingAEList.length > 0" size="small" type="text"
|
||||||
v-if="scope.row.CallingAEList.length > 0"
|
@click="handleConfig(scope.row, 'view')">
|
||||||
size="small"
|
|
||||||
type="text"
|
|
||||||
@click="handleConfig(scope.row, 'view')"
|
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
scope.row.CallingAEList.length > 0
|
scope.row.CallingAEList.length > 0
|
||||||
? scope.row.CallingAEList.join(', ')
|
? scope.row.CallingAEList.join(', ')
|
||||||
|
|
@ -217,63 +134,32 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 授权时间 -->
|
<!-- 授权时间 -->
|
||||||
<el-table-column
|
<el-table-column prop="EnabledTime" :label="$t('trials:sitesList:table:timeAdded')" show-overflow-tooltip sortable
|
||||||
prop="EnabledTime"
|
min-width="150" />
|
||||||
:label="$t('trials:sitesList:table:timeAdded')"
|
<el-table-column v-if="
|
||||||
show-overflow-tooltip
|
hasPermi([
|
||||||
sortable
|
'trials:trials-panel:setting:personnel-manage:edit-site',
|
||||||
min-width="150"
|
'trials:trials-panel:setting:personnel-manage:remove-site',
|
||||||
/>
|
'trials:trials-panel:setting:personnel-manage:edit-dicom',
|
||||||
<el-table-column
|
])
|
||||||
v-if="
|
" :label="$t('common:action:action')" min-width="120">
|
||||||
hasPermi([
|
|
||||||
'trials:trials-panel:setting:personnel-manage:edit-site',
|
|
||||||
'trials:trials-panel:setting:personnel-manage:remove-site',
|
|
||||||
'trials:trials-panel:setting:personnel-manage:edit-dicom',
|
|
||||||
])
|
|
||||||
"
|
|
||||||
:label="$t('common:action:action')"
|
|
||||||
min-width="120"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button circle :title="$t('trials:sitesList:action:assign')" icon="el-icon-user"
|
||||||
circle
|
:disabled="scope.row.IsDeleted" @click="getCrcList(scope.row)" />
|
||||||
:title="$t('trials:sitesList:action:assign')"
|
|
||||||
icon="el-icon-user"
|
|
||||||
:disabled="scope.row.IsDeleted"
|
|
||||||
@click="getCrcList(scope.row)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Edit -->
|
<!-- Edit -->
|
||||||
<el-button
|
<el-button v-hasPermi="[
|
||||||
v-hasPermi="[
|
'trials:trials-panel:setting:personnel-manage:edit-site',
|
||||||
'trials:trials-panel:setting:personnel-manage:edit-site',
|
]" circle :title="$t('common:button:edit')" icon="el-icon-edit-outline" @click="handleEdit(scope.row)" />
|
||||||
]"
|
<el-button v-if="isPACSConnect" circle :title="$t('common:button:config')" icon="el-icon-setting" v-hasPermi="[
|
||||||
circle
|
'trials:trials-panel:setting:personnel-manage:edit-dicom',
|
||||||
:title="$t('common:button:edit')"
|
]" @click="handleConfig(scope.row, 'add')" />
|
||||||
icon="el-icon-edit-outline"
|
|
||||||
@click="handleEdit(scope.row)"
|
|
||||||
/>
|
|
||||||
<el-button
|
|
||||||
v-if="isPACSConnect"
|
|
||||||
circle
|
|
||||||
:title="$t('common:button:config')"
|
|
||||||
icon="el-icon-setting"
|
|
||||||
v-hasPermi="[
|
|
||||||
'trials:trials-panel:setting:personnel-manage:edit-dicom',
|
|
||||||
]"
|
|
||||||
@click="handleConfig(scope.row, 'add')"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="pagination" style="text-align: right">
|
<div class="pagination" style="text-align: right">
|
||||||
<pagination
|
<pagination :total="total" :page.sync="listQuery.PageIndex" :limit.sync="listQuery.PageSize"
|
||||||
:total="total"
|
@pagination="getList" />
|
||||||
:page.sync="listQuery.PageIndex"
|
|
||||||
:limit.sync="listQuery.PageSize"
|
|
||||||
@pagination="getList"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 给site分配crc -->
|
<!-- 给site分配crc -->
|
||||||
|
|
@ -286,67 +172,37 @@
|
||||||
<!-- 修改site信息 -->
|
<!-- 修改site信息 -->
|
||||||
<base-model v-if="edit_model.visible" :config="edit_model">
|
<base-model v-if="edit_model.visible" :config="edit_model">
|
||||||
<template slot="dialog-body">
|
<template slot="dialog-body">
|
||||||
<el-form
|
<el-form ref="editForm" :model="form" label-width="100px" :rules="rules">
|
||||||
ref="editForm"
|
|
||||||
:model="form"
|
|
||||||
label-width="100px"
|
|
||||||
:rules="rules"
|
|
||||||
>
|
|
||||||
<!-- 中心编号 -->
|
<!-- 中心编号 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:sitesList:table:siteId')" prop="TrialSiteCode">
|
||||||
:label="$t('trials:sitesList:table:siteId')"
|
|
||||||
prop="TrialSiteCode"
|
|
||||||
>
|
|
||||||
<el-input v-model="form.TrialSiteCode" />
|
<el-input v-model="form.TrialSiteCode" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 中心名称 -->
|
<!-- 中心名称 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:sitesList:table:siteName')" prop="TrialSiteName">
|
||||||
:label="$t('trials:sitesList:table:siteName')"
|
<el-autocomplete clearable class="inline-input" style="width: 100%" v-model="form.TrialSiteName"
|
||||||
prop="TrialSiteName"
|
:fetch-suggestions="querySearch" @select="handleSelect" placeholder=""
|
||||||
>
|
@change="handleChange"></el-autocomplete>
|
||||||
<el-autocomplete
|
|
||||||
clearable
|
|
||||||
class="inline-input"
|
|
||||||
style="width: 100%"
|
|
||||||
v-model="form.TrialSiteName"
|
|
||||||
:fetch-suggestions="querySearch"
|
|
||||||
@select="handleSelect"
|
|
||||||
placeholder=""
|
|
||||||
@change="handleChange"
|
|
||||||
></el-autocomplete>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 中心别称 -->
|
<!-- 中心别称 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:sitesList:table:siteAliasName')" prop="TrialSiteAliasName">
|
||||||
:label="$t('trials:sitesList:table:siteAliasName')"
|
|
||||||
prop="TrialSiteAliasName"
|
|
||||||
>
|
|
||||||
<el-input v-model="form.TrialSiteAliasName" />
|
<el-input v-model="form.TrialSiteAliasName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('trials:sitesList:table:Country')" prop="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>
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<el-form-item :label="$t('trials:sitesList:table:status')">
|
<el-form-item :label="$t('trials:sitesList:table:status')">
|
||||||
<el-switch
|
<el-switch v-model="form.IsDeleted" :active-value="false" :inactive-value="true" />
|
||||||
v-model="form.IsDeleted"
|
|
||||||
:active-value="false"
|
|
||||||
:inactive-value="true"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
<template slot="dialog-footer">
|
<template slot="dialog-footer">
|
||||||
<el-button
|
<el-button type="primary" size="small" :disabled="saveBtnLoading" @click="edit_model.visible = false">
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
:disabled="saveBtnLoading"
|
|
||||||
@click="edit_model.visible = false"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:cancel') }}
|
{{ $t('common:button:cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button type="primary" size="small" :loading="saveBtnLoading" @click="handleUpdateSiteID">
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
:loading="saveBtnLoading"
|
|
||||||
@click="handleUpdateSiteID"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:save') }}
|
{{ $t('common:button:save') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -357,29 +213,14 @@
|
||||||
<template slot="dialog-body">
|
<template slot="dialog-body">
|
||||||
<span style="margin-right: 5px;">{{ $t('trials:internalStaff:table:status') }}:</span>
|
<span style="margin-right: 5px;">{{ $t('trials:internalStaff:table:status') }}:</span>
|
||||||
<el-radio-group v-model="staffStatus">
|
<el-radio-group v-model="staffStatus">
|
||||||
<el-radio
|
<el-radio v-for="item of $d.IsUserExitTrial" :key="item.label" :label="item.value">{{ item.label }}</el-radio>
|
||||||
v-for="item of $d.IsUserExitTrial"
|
|
||||||
:key="item.label"
|
|
||||||
:label="item.value"
|
|
||||||
>{{ item.label }}</el-radio
|
|
||||||
>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</template>
|
</template>
|
||||||
<template slot="dialog-footer">
|
<template slot="dialog-footer">
|
||||||
<el-button
|
<el-button :disabled="btnLoading" size="small" type="primary" @click="status_model.visible = false">
|
||||||
:disabled="btnLoading"
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
@click="status_model.visible = false"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:cancel') }}
|
{{ $t('common:button:cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button size="small" type="primary" :loading="btnLoading" @click="saveStatus">
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
:loading="btnLoading"
|
|
||||||
@click="saveStatus"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:save') }}
|
{{ $t('common:button:save') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -389,72 +230,34 @@
|
||||||
<base-model v-if="siteOfcrc_model.visible" :config="siteOfcrc_model">
|
<base-model v-if="siteOfcrc_model.visible" :config="siteOfcrc_model">
|
||||||
<template slot="dialog-body">
|
<template slot="dialog-body">
|
||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<el-button
|
<el-button v-hasPermi="[
|
||||||
v-hasPermi="[
|
'trials:trials-panel:setting:personnel-manage:assign-staff',
|
||||||
'trials:trials-panel:setting:personnel-manage:assign-staff',
|
]" type="primary" icon="el-icon-plus" size="small" @click="crc_model.visible = true">
|
||||||
]"
|
|
||||||
type="primary"
|
|
||||||
icon="el-icon-plus"
|
|
||||||
size="small"
|
|
||||||
@click="crc_model.visible = true"
|
|
||||||
>
|
|
||||||
{{ $t('common:button:add') }}
|
{{ $t('common:button:add') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table v-loading="userListLoading" :data="userList" height="400" size="small">
|
||||||
v-loading="userListLoading"
|
|
||||||
:data="userList"
|
|
||||||
height="400"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<!-- 姓名 -->
|
<!-- 姓名 -->
|
||||||
<el-table-column
|
<el-table-column prop="FullName" :label="$t('trials:internalStaff:table:name')" min-width="100"
|
||||||
prop="FullName"
|
show-overflow-tooltip />
|
||||||
:label="$t('trials:internalStaff:table:name')"
|
|
||||||
min-width="100"
|
|
||||||
show-overflow-tooltip
|
|
||||||
/>
|
|
||||||
<!-- 用户名 -->
|
<!-- 用户名 -->
|
||||||
<el-table-column
|
<el-table-column prop="UserName" :label="$t('trials:internalStaff:table:uid')" min-width="100"
|
||||||
prop="UserName"
|
show-overflow-tooltip />
|
||||||
:label="$t('trials:internalStaff:table:uid')"
|
|
||||||
min-width="100"
|
|
||||||
show-overflow-tooltip
|
|
||||||
/>
|
|
||||||
<!-- 用户类型 -->
|
<!-- 用户类型 -->
|
||||||
<el-table-column
|
<el-table-column prop="UserType" :label="$t('trials:internalStaff:table:userType')" min-width="100"
|
||||||
prop="UserType"
|
show-overflow-tooltip />
|
||||||
:label="$t('trials:internalStaff:table:userType')"
|
|
||||||
min-width="100"
|
|
||||||
show-overflow-tooltip
|
|
||||||
/>
|
|
||||||
<!-- 电话 -->
|
<!-- 电话 -->
|
||||||
<el-table-column
|
<el-table-column prop="Phone" :label="$t('trials:internalStaff:table:phone')" show-overflow-tooltip
|
||||||
prop="Phone"
|
min-width="100" />
|
||||||
:label="$t('trials:internalStaff:table:phone')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
min-width="100"
|
|
||||||
/>
|
|
||||||
<!-- 邮箱 -->
|
<!-- 邮箱 -->
|
||||||
<el-table-column
|
<el-table-column prop="EMail" :label="$t('trials:internalStaff:table:email')" show-overflow-tooltip
|
||||||
prop="EMail"
|
min-width="100" />
|
||||||
:label="$t('trials:internalStaff:table:email')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
min-width="100"
|
|
||||||
/>
|
|
||||||
<!-- 单位 -->
|
<!-- 单位 -->
|
||||||
<el-table-column
|
<el-table-column prop="OrganizationName" :label="$t('trials:internalStaff:table:organization')"
|
||||||
prop="OrganizationName"
|
min-width="100" />
|
||||||
:label="$t('trials:internalStaff:table:organization')"
|
|
||||||
min-width="100"
|
|
||||||
/>
|
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<el-table-column
|
<el-table-column prop="IsDeleted" :label="$t('trials:internalStaff:table:status')" show-overflow-tooltip
|
||||||
prop="IsDeleted"
|
min-width="100">
|
||||||
:label="$t('trials:internalStaff:table:status')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
min-width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
|
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
|
||||||
$fd('IsUserExitTrial', scope.row.IsDeleted)
|
$fd('IsUserExitTrial', scope.row.IsDeleted)
|
||||||
|
|
@ -464,37 +267,18 @@
|
||||||
}}</el-tag>
|
}}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column prop="CreateTime" :label="$t('trials:internalStaff:table:authorizationTime')"
|
||||||
prop="CreateTime"
|
show-overflow-tooltip sortable="custom" min-width="210" />
|
||||||
:label="$t('trials:internalStaff:table:authorizationTime')"
|
<el-table-column prop="DeletedTime" :label="$t('trials:internalStaff:table:disableTime')"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip sortable min-width="210" />
|
||||||
sortable="custom"
|
<el-table-column v-hasPermi="[
|
||||||
min-width="210"
|
'trials:trials-panel:setting:personnel-manage:assign-staff',
|
||||||
/>
|
]" :label="$t('common:action:action')" width="100">
|
||||||
<el-table-column
|
|
||||||
prop="DeletedTime"
|
|
||||||
:label="$t('trials:internalStaff:table:disableTime')"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
min-width="210"
|
|
||||||
/>
|
|
||||||
<el-table-column
|
|
||||||
v-hasPermi="[
|
|
||||||
'trials:trials-panel:setting:personnel-manage:assign-staff',
|
|
||||||
]"
|
|
||||||
:label="$t('common:action:action')"
|
|
||||||
width="100"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button v-hasPermi="[
|
||||||
v-hasPermi="[
|
'trials:trials-panel:setting:personnel-manage:assign-staff',
|
||||||
'trials:trials-panel:setting:personnel-manage:assign-staff',
|
]" circle :title="$t('trials:internalStaff:action:status')" icon="el-icon-edit-outline"
|
||||||
]"
|
@click="handleStatus(scope.row)" />
|
||||||
circle
|
|
||||||
:title="$t('trials:internalStaff:action:status')"
|
|
||||||
icon="el-icon-edit-outline"
|
|
||||||
@click="handleStatus(scope.row)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -503,10 +287,7 @@
|
||||||
<!-- 导入 -->
|
<!-- 导入 -->
|
||||||
<base-model v-if="upload_model.visible" :config="upload_model">
|
<base-model v-if="upload_model.visible" :config="upload_model">
|
||||||
<template slot="dialog-body">
|
<template slot="dialog-body">
|
||||||
<UploadExcel
|
<UploadExcel @closeDialog="upload_model.visible = false" @getList="getList" />
|
||||||
@closeDialog="upload_model.visible = false"
|
|
||||||
@getList="getList"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</base-model>
|
</base-model>
|
||||||
<!--dicom AE-->
|
<!--dicom AE-->
|
||||||
|
|
@ -583,6 +364,7 @@ export default {
|
||||||
TrialSiteCode: '',
|
TrialSiteCode: '',
|
||||||
TrialSiteName: '',
|
TrialSiteName: '',
|
||||||
TrialSiteAliasName: '',
|
TrialSiteAliasName: '',
|
||||||
|
Country: '',
|
||||||
IsDeleted: true,
|
IsDeleted: true,
|
||||||
},
|
},
|
||||||
upload_model: {
|
upload_model: {
|
||||||
|
|
@ -634,6 +416,13 @@ export default {
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Country: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('common:ruleMessage:select'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
trialId: '',
|
trialId: '',
|
||||||
TrialSiteSelectList: [],
|
TrialSiteSelectList: [],
|
||||||
|
|
@ -656,10 +445,12 @@ export default {
|
||||||
? item.AliasName
|
? item.AliasName
|
||||||
: item.SiteName
|
: item.SiteName
|
||||||
this.form.SiteId = item.SiteId
|
this.form.SiteId = item.SiteId
|
||||||
|
this.form.Country = item.Country
|
||||||
},
|
},
|
||||||
handleChange(v) {
|
handleChange(v) {
|
||||||
if (v) return
|
if (v) return
|
||||||
this.form.TrialSiteAliasName = ''
|
this.form.TrialSiteAliasName = ''
|
||||||
|
this.form.Country = this.$i18n.locale !== 'zh' ? this.$fd("SiteCountry", 1) : this.$fd("SiteCountry", 0)
|
||||||
},
|
},
|
||||||
querySearch(queryString, cb) {
|
querySearch(queryString, cb) {
|
||||||
var TrialSiteSelectList = this.TrialSiteSelectList
|
var TrialSiteSelectList = this.TrialSiteSelectList
|
||||||
|
|
@ -728,6 +519,7 @@ export default {
|
||||||
this.form[key] = true
|
this.form[key] = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.form.Country = this.$i18n.locale !== 'zh' ? this.$fd("SiteCountry", 1) : this.$fd("SiteCountry", 0)
|
||||||
this.edit_model.visible = true
|
this.edit_model.visible = true
|
||||||
},
|
},
|
||||||
// 给site分配CRC
|
// 给site分配CRC
|
||||||
|
|
@ -764,6 +556,7 @@ export default {
|
||||||
trialSiteCode: this.form.TrialSiteCode,
|
trialSiteCode: this.form.TrialSiteCode,
|
||||||
trialSiteAliasName: this.form.TrialSiteAliasName,
|
trialSiteAliasName: this.form.TrialSiteAliasName,
|
||||||
isDeleted: this.form.IsDeleted,
|
isDeleted: this.form.IsDeleted,
|
||||||
|
Country: this.form.Country,
|
||||||
}
|
}
|
||||||
if (this.edit_model.model_type === 'add') {
|
if (this.edit_model.model_type === 'add') {
|
||||||
addTrialSites([param])
|
addTrialSites([param])
|
||||||
|
|
|
||||||
|
|
@ -318,6 +318,17 @@
|
||||||
]">
|
]">
|
||||||
<el-input-number v-model="form.MaxAnswerLength" :min="0"></el-input-number>
|
<el-input-number v-model="form.MaxAnswerLength" :min="0"></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<!-- 手动增/删记录 -->
|
||||||
|
<el-form-item v-if="form.Type === 'table' || form.Type === 'basicTable'"
|
||||||
|
:label="$t('trials:readingUnit:qsList:title:AddDeleteTypeEnum')" prop="AddDeleteTypeEnum" :rules="[
|
||||||
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }
|
||||||
|
]">
|
||||||
|
<el-radio-group v-model="form.AddDeleteTypeEnum">
|
||||||
|
<el-radio v-for="item of $d.AddDeleteType" :key="item.id" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
<!-- 最大行数 -->
|
<!-- 最大行数 -->
|
||||||
<el-form-item v-if="form.Type === 'table' || form.Type === 'basicTable'"
|
<el-form-item v-if="form.Type === 'table' || form.Type === 'basicTable'"
|
||||||
:label="$t('trials:readingUnit:qsList:title:maxQuestionCount')" prop="MaxQuestionCount" :rules="[
|
:label="$t('trials:readingUnit:qsList:title:maxQuestionCount')" prop="MaxQuestionCount" :rules="[
|
||||||
|
|
@ -765,6 +776,7 @@ export default {
|
||||||
MaxQuestionCount: null,
|
MaxQuestionCount: null,
|
||||||
IsCopyLesions: false,
|
IsCopyLesions: false,
|
||||||
MaxAnswerLength: null,
|
MaxAnswerLength: null,
|
||||||
|
AddDeleteTypeEnum: null,
|
||||||
FileType: [],
|
FileType: [],
|
||||||
DictionaryCode: null,
|
DictionaryCode: null,
|
||||||
GroupId: null,
|
GroupId: null,
|
||||||
|
|
@ -1291,6 +1303,7 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
form.ClassifyEditType = null
|
form.ClassifyEditType = null
|
||||||
}
|
}
|
||||||
|
form.AddDeleteTypeEnum = 0
|
||||||
form.IsRequired = 2
|
form.IsRequired = 2
|
||||||
form.LesionType = null
|
form.LesionType = null
|
||||||
form.ImageCount = 0
|
form.ImageCount = 0
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,31 @@
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<!-- QC质控下载 -->
|
||||||
|
<el-form-item :label="$t('trials:logincCfg:form:IsSupportQCDownloadImage')" prop="IsSupportQCDownloadImage"
|
||||||
|
v-if="showMore">
|
||||||
|
<el-radio-group v-model="form.IsSupportQCDownloadImage" :disabled="form.IsTrialBasicLogicConfirmed && !isEdit">
|
||||||
|
<el-radio v-for="item of $d.YesOrNo" :key="`IsSupportQCDownloadImage${item.value}`" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<!--影像质控风险控制-->
|
||||||
|
<el-form-item :label="$t('trials:processCfg:form:IsImageQualityControl')" prop="IsImageQualityControl">
|
||||||
|
<el-radio-group v-model="form.IsImageQualityControl" :disabled="form.IsTrialBasicLogicConfirmed && !isEdit">
|
||||||
|
<el-radio v-for="item of $d.YesOrNo" :key="item.id" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 失访可读 -->
|
||||||
|
<el-form-item :label="$t('trials:logincCfg:form:IsOpenLostVistRead')" prop="IsOpenLostVistRead " v-if="showMore">
|
||||||
|
<el-radio-group v-model="form.IsOpenLostVistRead" :disabled="form.IsTrialBasicLogicConfirmed && !isEdit">
|
||||||
|
<el-radio v-for="item of $d.YesOrNo" :key="`IsOpenLostVistRead ${item.value}`" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<div :class="{ showMore: true, isCheck: showMore }" @click.stop="showMore = !showMore">
|
<div :class="{ showMore: true, isCheck: showMore }" @click.stop="showMore = !showMore">
|
||||||
<i class="el-icon-arrow-down"></i>
|
<i class="el-icon-arrow-down"></i>
|
||||||
|
|
@ -528,6 +553,9 @@ export default {
|
||||||
StudyUseModalityList: [],
|
StudyUseModalityList: [],
|
||||||
StudyUseStudyNameList: [],
|
StudyUseStudyNameList: [],
|
||||||
IsIQCAutoNextTask: false,
|
IsIQCAutoNextTask: false,
|
||||||
|
IsSupportQCDownloadImage: false,
|
||||||
|
IsImageQualityControl: false,
|
||||||
|
IsOpenLostVistRead: false,
|
||||||
IsIQCAutoTaskDistinguishType: false
|
IsIQCAutoTaskDistinguishType: false
|
||||||
// ClinicalDataSetNames: [],
|
// ClinicalDataSetNames: [],
|
||||||
// ClinicalDataTrialSetIds: [],
|
// ClinicalDataTrialSetIds: [],
|
||||||
|
|
@ -1263,6 +1291,21 @@ export default {
|
||||||
NewVal: this.$fd('YesOrNo', this.form.IsIQCAutoNextTask),
|
NewVal: this.$fd('YesOrNo', this.form.IsIQCAutoNextTask),
|
||||||
OldVal: this.$fd('YesOrNo', this.initialForm.IsIQCAutoNextTask),
|
OldVal: this.$fd('YesOrNo', this.initialForm.IsIQCAutoNextTask),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: this.$t('trials:logincCfg:form:IsSupportQCDownloadImage'),
|
||||||
|
NewVal: this.$fd('YesOrNo', this.form.IsSupportQCDownloadImage),
|
||||||
|
OldVal: this.$fd('YesOrNo', this.initialForm.IsSupportQCDownloadImage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: this.$t('trials:processCfg:form:IsImageQualityControl'), // 影像质控风险控制
|
||||||
|
NewVal: this.$fd('YesOrNo', this.form.IsImageQualityControl),
|
||||||
|
OldVal: this.$fd('YesOrNo', this.initialForm.IsImageQualityControl),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: this.$t('trials:logincCfg:form:IsOpenLostVistRead'),
|
||||||
|
NewVal: this.$fd('YesOrNo', this.form.IsOpenLostVistRead),
|
||||||
|
OldVal: this.$fd('YesOrNo', this.initialForm.IsOpenLostVistRead),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: this.$t('trials:logincCfg:form:IsIQCAutoTaskDistinguishType'),
|
Name: this.$t('trials:logincCfg:form:IsIQCAutoTaskDistinguishType'),
|
||||||
NewVal: this.$fd('YesOrNo', this.form.IsIQCAutoTaskDistinguishType),
|
NewVal: this.$fd('YesOrNo', this.form.IsIQCAutoTaskDistinguishType),
|
||||||
|
|
|
||||||
|
|
@ -62,14 +62,14 @@
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!--影像质控风险控制-->
|
<!--影像质控风险控制-->
|
||||||
<el-form-item :label="$t('trials:processCfg:form:IsImageQualityControl')" prop="IsImageQualityControl"
|
<!-- <el-form-item :label="$t('trials:processCfg:form:IsImageQualityControl')" prop="IsImageQualityControl"
|
||||||
v-if="form.QCProcessEnum > 0">
|
v-if="form.QCProcessEnum > 0">
|
||||||
<el-radio-group v-model="form.IsImageQualityControl" :disabled="form.IsTrialProcessConfirmed && !isEdit">
|
<el-radio-group v-model="form.IsImageQualityControl" :disabled="form.IsTrialProcessConfirmed && !isEdit">
|
||||||
<el-radio v-for="item of $d.YesOrNo" :key="item.id" :label="item.value">
|
<el-radio v-for="item of $d.YesOrNo" :key="item.id" :label="item.value">
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<!-- 一致性核查流程 -->
|
<!-- 一致性核查流程 -->
|
||||||
<el-form-item :label="$t('trials:processCfg:form:conProcess')" prop="IsImageConsistencyVerification">
|
<el-form-item :label="$t('trials:processCfg:form:conProcess')" prop="IsImageConsistencyVerification">
|
||||||
<el-radio-group v-model="form.IsImageConsistencyVerification"
|
<el-radio-group v-model="form.IsImageConsistencyVerification"
|
||||||
|
|
@ -749,7 +749,7 @@ export default {
|
||||||
ClinicalDataTrialSetIds: [],
|
ClinicalDataTrialSetIds: [],
|
||||||
ClinicalDataSetNamesStr: '',
|
ClinicalDataSetNamesStr: '',
|
||||||
QCProcessEnum: null,
|
QCProcessEnum: null,
|
||||||
IsImageQualityControl: false,
|
// IsImageQualityControl: false,
|
||||||
CollectImagesEnum: null,
|
CollectImagesEnum: null,
|
||||||
ImageFormatList: [],
|
ImageFormatList: [],
|
||||||
IsImageConsistencyVerification: null,
|
IsImageConsistencyVerification: null,
|
||||||
|
|
@ -899,8 +899,8 @@ export default {
|
||||||
mounted() { },
|
mounted() { },
|
||||||
methods: {
|
methods: {
|
||||||
QCProcessEnumChange(v) {
|
QCProcessEnumChange(v) {
|
||||||
this.form.IsImageQualityControl = false
|
// this.form.IsImageQualityControl = false
|
||||||
if (v > 0) this.form.IsImageQualityControl = true
|
// if (v > 0) this.form.IsImageQualityControl = true
|
||||||
},
|
},
|
||||||
handlePreview(row) {
|
handlePreview(row) {
|
||||||
this.rowData = { ...row }
|
this.rowData = { ...row }
|
||||||
|
|
@ -1073,11 +1073,11 @@ export default {
|
||||||
NewVal: this.$fd('QCProcessEnum', this.form.QCProcessEnum),
|
NewVal: this.$fd('QCProcessEnum', this.form.QCProcessEnum),
|
||||||
OldVal: this.$fd('QCProcessEnum', this.initialForm.QCProcessEnum),
|
OldVal: this.$fd('QCProcessEnum', this.initialForm.QCProcessEnum),
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
Name: this.$t('trials:processCfg:form:IsImageQualityControl'), // 影像质控风险控制
|
// Name: this.$t('trials:processCfg:form:IsImageQualityControl'), // 影像质控风险控制
|
||||||
NewVal: this.$fd('YesOrNo', this.form.IsImageQualityControl),
|
// NewVal: this.$fd('YesOrNo', this.form.IsImageQualityControl),
|
||||||
OldVal: this.$fd('YesOrNo', this.initialForm.IsImageQualityControl),
|
// OldVal: this.$fd('YesOrNo', this.initialForm.IsImageQualityControl),
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
Name: this.$t('trials:processCfg:form:conProcess'), // 一致性核查流程
|
Name: this.$t('trials:processCfg:form:conProcess'), // 一致性核查流程
|
||||||
NewVal: this.$fd('YesOrNo', this.form.IsImageConsistencyVerification),
|
NewVal: this.$fd('YesOrNo', this.form.IsImageConsistencyVerification),
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ export default {
|
||||||
addReadModule(this.form).then(res => {
|
addReadModule(this.form).then(res => {
|
||||||
this.btnLoading = false
|
this.btnLoading = false
|
||||||
this.$emit('getList')
|
this.$emit('getList')
|
||||||
this.$emit('close', {visitStageId: this.form.VisitStageId})
|
this.$emit('close', {visitStageId: this.form.VisitStageId, expirationVisitNum: this.form.ExpirationVisitNum})
|
||||||
this.form.Name = null
|
this.form.Name = null
|
||||||
this.form.VisitStageId = null
|
this.form.VisitStageId = null
|
||||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@
|
||||||
}}</el-tag>
|
}}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('common:action:action')" width="260">
|
<el-table-column :label="$t('common:action:action')" min-width="200">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 查看 -->
|
<!-- 查看 -->
|
||||||
<el-button circle :disabled="scope.row.ClinicalUploadType === 1 &&
|
<el-button circle :disabled="scope.row.ClinicalUploadType === 1 &&
|
||||||
|
|
@ -145,7 +145,7 @@
|
||||||
" @click="handleDelete(scope.row)" />
|
" @click="handleDelete(scope.row)" />
|
||||||
<!-- 更新 临床数据已签名,阅片状态待阅片 -->
|
<!-- 更新 临床数据已签名,阅片状态待阅片 -->
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['trials:trials-panel:subject:readingPeriod:edit']"
|
v-if="showUpdateStatusBtn && hasPermi(['trials:trials-panel:subject:readingPeriod:edit'])"
|
||||||
circle
|
circle
|
||||||
:title="$t('trials:readingPeriod:cd:action:update')" icon="el-icon-refresh"
|
:title="$t('trials:readingPeriod:cd:action:update')" icon="el-icon-refresh"
|
||||||
:disabled="
|
:disabled="
|
||||||
|
|
@ -296,7 +296,7 @@
|
||||||
" @click="handleDelete(scope.row)" />
|
" @click="handleDelete(scope.row)" />
|
||||||
<!-- 更新 临床数据已签名,阅片状态待阅片 -->
|
<!-- 更新 临床数据已签名,阅片状态待阅片 -->
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['trials:trials-panel:subject:readingPeriod:edit']"
|
v-if="showUpdateStatusBtn && hasPermi(['trials:trials-panel:subject:readingPeriod:edit'])"
|
||||||
circle
|
circle
|
||||||
:title="$t('trials:readingPeriod:cd:action:update')" icon="el-icon-refresh"
|
:title="$t('trials:readingPeriod:cd:action:update')" icon="el-icon-refresh"
|
||||||
:disabled="
|
:disabled="
|
||||||
|
|
@ -354,6 +354,7 @@ import SignForm from '@/views/trials/components/newSignForm'
|
||||||
import const_ from '@/const/sign-code'
|
import const_ from '@/const/sign-code'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
import { downLoadFile } from '@/utils/stream.js'
|
import { downLoadFile } from '@/utils/stream.js'
|
||||||
|
import hasPermi from '../../../../../../directive/permission/hasPermi'
|
||||||
export default {
|
export default {
|
||||||
name: 'ClinicalData',
|
name: 'ClinicalData',
|
||||||
components: { AddOrEditCD, SignForm, Verification },
|
components: { AddOrEditCD, SignForm, Verification },
|
||||||
|
|
@ -373,11 +374,21 @@ export default {
|
||||||
type: {
|
type: {
|
||||||
default: 'readingPeriod',
|
default: 'readingPeriod',
|
||||||
},
|
},
|
||||||
|
showUpdateStatusBtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
clinicalType() {
|
clinicalType() {
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
showUpdateStatusBtn: {
|
||||||
|
immediate: true,
|
||||||
|
handler(v) {
|
||||||
|
console.log(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,7 @@
|
||||||
)}(${currentData.SubjectCode}|${currentData.Name}|${currentData.CriterionName
|
)}(${currentData.SubjectCode}|${currentData.Name}|${currentData.CriterionName
|
||||||
})`" :visible.sync="clinicalDataVisible" :close-on-click-modal="false" append-to-body width="70%">
|
})`" :visible.sync="clinicalDataVisible" :close-on-click-modal="false" append-to-body width="70%">
|
||||||
<ClinicalData :trial-reading-criterion-id="TrialReadingCriterionId" :trial-id="trialId"
|
<ClinicalData :trial-reading-criterion-id="TrialReadingCriterionId" :trial-id="trialId"
|
||||||
:data="currentData" @getList="getList" />
|
:data="currentData" :showUpdateStatusBtn="currentData.ModuleType === 3 || currentData.ModuleType === 5" @getList="getList" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 添加受试者阅片期 -->
|
<!-- 添加受试者阅片期 -->
|
||||||
<el-dialog v-if="subjectPeriod.visible" :title="subjectPeriod.title" :visible.sync="subjectPeriod.visible"
|
<el-dialog v-if="subjectPeriod.visible" :title="subjectPeriod.title" :visible.sync="subjectPeriod.visible"
|
||||||
|
|
@ -540,6 +540,7 @@ export default {
|
||||||
if (res === 'confirm') {
|
if (res === 'confirm') {
|
||||||
this.param.ReadingSetType = 1
|
this.param.ReadingSetType = 1
|
||||||
this.param.VisitStageId = obj.visitStageId
|
this.param.VisitStageId = obj.visitStageId
|
||||||
|
this.param.ExpirationVisitNum = obj.expirationVisitNum
|
||||||
this.subjectPeriod = { visible: true, title: this.$t('trials:readingPeriod:dialogTitle:addSubjectTumorPR') }
|
this.subjectPeriod = { visible: true, title: this.$t('trials:readingPeriod:dialogTitle:addSubjectTumorPR') }
|
||||||
} else {
|
} else {
|
||||||
this.subjectPeriod.visible = true
|
this.subjectPeriod.visible = true
|
||||||
|
|
|
||||||
|
|
@ -90,15 +90,69 @@
|
||||||
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 60 }" height="100" :data="list"
|
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 60 }" height="100" :data="list"
|
||||||
class="table" @sort-change="handleSortByColumn" :default-sort="{ prop: 'CreateTime', order: 'descending' }">
|
class="table" @sort-change="handleSortByColumn" :default-sort="{ prop: 'CreateTime', order: 'descending' }">
|
||||||
<el-table-column type="index" width="50" />
|
<el-table-column type="index" width="50" />
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:subjectCode')" prop="SubjectCode" min-width="90" show-overflow-tooltip sortable="custom"/>
|
<el-table-column
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:visitName')" prop="VisitName" min-width="90" show-overflow-tooltip sortable="custom"/>
|
:label="$t('trials:data-sync:studyList:subjectCode')"
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:studyCode')" prop="StudyCode" min-width="90" show-overflow-tooltip sortable="custom"/>
|
prop="SubjectCode"
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:fileCount')" prop="FileCount" min-width="90" show-overflow-tooltip/>
|
min-width="90"
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:uploadRegion')" prop="UploadRegion" min-width="60" show-overflow-tooltip />
|
show-overflow-tooltip
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:createTime')" prop="CreateTime" min-width="90" show-overflow-tooltip />
|
sortable="custom"
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:targetRegion')" prop="TargetRegion" min-width="60" show-overflow-tooltip />
|
/>
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:syncFinishedTime')" prop="SyncFinishedTime" min-width="90" show-overflow-tooltip/>
|
<el-table-column
|
||||||
<el-table-column :label="$t('trials:data-sync:studyList:isSync')" prop="IsSync" min-width="90" show-overflow-tooltip sortable="custom">
|
:label="$t('trials:data-sync:studyList:visitName')"
|
||||||
|
prop="VisitName"
|
||||||
|
min-width="90"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:studyCode')"
|
||||||
|
prop="StudyCode"
|
||||||
|
min-width="90"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:fileCount')"
|
||||||
|
prop="FileCount"
|
||||||
|
min-width="90"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:uploadRegion')"
|
||||||
|
prop="UploadRegion"
|
||||||
|
min-width="60"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:createTime')"
|
||||||
|
prop="CreateTime"
|
||||||
|
min-width="90"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:targetRegion')"
|
||||||
|
prop="TargetRegion"
|
||||||
|
min-width="60"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:syncFinishedTime')"
|
||||||
|
prop="SyncFinishedTime"
|
||||||
|
min-width="90"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('trials:data-sync:studyList:isSync')"
|
||||||
|
prop="IsSync"
|
||||||
|
min-width="90"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable="custom"
|
||||||
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.IsSync" type="success">
|
<el-tag v-if="scope.row.IsSync" type="success">
|
||||||
{{ $fd('YesOrNo', scope.row.IsSync) }}
|
{{ $fd('YesOrNo', scope.row.IsSync) }}
|
||||||
|
|
@ -178,8 +232,8 @@ const searchDataDefault = () => {
|
||||||
// SyncFinishedEndTime: null,
|
// SyncFinishedEndTime: null,
|
||||||
PageIndex: 1,
|
PageIndex: 1,
|
||||||
PageSize: 20,
|
PageSize: 20,
|
||||||
Asc: true,
|
Asc: false,
|
||||||
SortField: 'StudyCode'
|
SortField: 'CreateTime'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default {
|
export default {
|
||||||
|
|
|
||||||
|
|
@ -64,16 +64,13 @@
|
||||||
<el-table-column :label="$t('trials:data-sync:table:filePath')" prop="Path" min-width="90" show-overflow-tooltip/>
|
<el-table-column :label="$t('trials:data-sync:table:filePath')" prop="Path" min-width="90" show-overflow-tooltip/>
|
||||||
<el-table-column :label="$t('trials:data-sync:table:jobState')" prop="JobState" min-width="90" show-overflow-tooltip sortable="custom">
|
<el-table-column :label="$t('trials:data-sync:table:jobState')" prop="JobState" min-width="90" show-overflow-tooltip sortable="custom">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.JobState === 1" type="infoinf0">
|
<el-tag v-if="scope.row.JobState === 1" type="info">
|
||||||
{{ $fd('JobState', scope.row.JobState) }}
|
|
||||||
</el-tag>
|
|
||||||
<el-tag v-else-if="scope.row.JobState === 1" type="warning">
|
|
||||||
{{ $fd('JobState', scope.row.JobState) }}
|
{{ $fd('JobState', scope.row.JobState) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<el-tag v-else-if="scope.row.JobState === 2" type="success">
|
<el-tag v-else-if="scope.row.JobState === 2" type="success">
|
||||||
{{ $fd('JobState', scope.row.JobState) }}
|
{{ $fd('JobState', scope.row.JobState) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<el-tag v-else-if="scope.row.JobState === 3" type="danger">
|
<el-tag v-else-if="scope.row.JobState === 3" type="danger" :title="scope.row.Msg">
|
||||||
{{ $fd('JobState', scope.row.JobState) }}
|
{{ $fd('JobState', scope.row.JobState) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<el-tag v-else>{{ $fd('JobState', scope.row.JobState) }}</el-tag>
|
<el-tag v-else>{{ $fd('JobState', scope.row.JobState) }}</el-tag>
|
||||||
|
|
@ -136,7 +133,9 @@ export default {
|
||||||
},
|
},
|
||||||
rowInfo: {
|
rowInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -198,7 +197,7 @@ export default {
|
||||||
try {
|
try {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
let params = {
|
let params = {
|
||||||
fileUploadRecordIdList: [row.Id]
|
fileUploadRecordIdList: [row.FileUploadRecordId]
|
||||||
}
|
}
|
||||||
let res = await batchAddSyncFileTask(params)
|
let res = await batchAddSyncFileTask(params)
|
||||||
if (res.IsSuccess) {
|
if (res.IsSuccess) {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export default {
|
||||||
activeTab: 'study',
|
activeTab: 'study',
|
||||||
tabInfo: {
|
tabInfo: {
|
||||||
activeTab: 'file',
|
activeTab: 'file',
|
||||||
currentRow: null
|
currentRow: {}
|
||||||
},
|
},
|
||||||
fileUploadRecordId: '',
|
fileUploadRecordId: '',
|
||||||
path: ''
|
path: ''
|
||||||
|
|
@ -52,7 +52,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openTaskTable(obj) {
|
openTaskTable(obj) {
|
||||||
this.tabInfo.currentRow = obj || null
|
this.tabInfo.currentRow = obj || {}
|
||||||
this.fileUploadRecordId = obj.Id
|
this.fileUploadRecordId = obj.Id
|
||||||
this.path = obj.Path
|
this.path = obj.Path
|
||||||
this.tabInfo.activeTab = 'task'
|
this.tabInfo.activeTab = 'task'
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
<!-- 上传时间 -->
|
<!-- 上传时间 -->
|
||||||
<el-table-column prop="UploadedTime" :label="$t('trials:uploadedDicoms:table:uploadedTime')" sortable
|
<el-table-column prop="UploadedTime" :label="$t('trials:uploadedDicoms:table:uploadedTime')" sortable
|
||||||
min-width="120" show-overflow-tooltip />
|
min-width="120" show-overflow-tooltip />
|
||||||
<el-table-column :label="$t('common:action:action')" min-width="100">
|
<el-table-column :label="$t('common:action:action')" min-width="140">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 预览 -->
|
<!-- 预览 -->
|
||||||
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
|
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
|
||||||
|
|
@ -150,8 +150,8 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!--pet-ct临床数据上传-->
|
<!--pet-ct临床数据上传-->
|
||||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
<el-dialog v-if="petVisible" :close-on-click-modal="false" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" />
|
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="(data.SubmitState * 1 < 2 || (data.SubmitState === 2 && data.IsQCConfirmedReupload)) && hasPermi(['trials:trials-panel:visit:crc-upload:edit'])" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -309,8 +309,14 @@ export default {
|
||||||
// 预览影像
|
// 预览影像
|
||||||
handleViewStudy(row) {
|
handleViewStudy(row) {
|
||||||
var token = getToken()
|
var token = getToken()
|
||||||
|
let path = ''
|
||||||
|
if (this.hasPermi(['trials:trials-panel:visit:crc-upload:edit'])) {
|
||||||
|
path = `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study&showEdit=${(this.data.SubmitState * 1 < 2 || (this.data.SubmitState === 2 && this.data.IsQCConfirmedReupload)) ? 1 : 0}`
|
||||||
|
} else {
|
||||||
|
path = `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study`
|
||||||
|
}
|
||||||
const routeData = this.$router.resolve({
|
const routeData = this.$router.resolve({
|
||||||
path: `/showdicom?studyId=${row.StudyId}&isFromCRCUpload=1&TokenKey=${token}&type=Study`,
|
path: path
|
||||||
})
|
})
|
||||||
var newWindow = window.open(routeData.href, '_blank')
|
var newWindow = window.open(routeData.href, '_blank')
|
||||||
this.$emit('setOpenWindow', newWindow)
|
this.$emit('setOpenWindow', newWindow)
|
||||||
|
|
|
||||||
|
|
@ -7,44 +7,21 @@
|
||||||
<div style="margin: 10px 0">{{ $t('trials:uploadedDicoms:title:dicomUploaded') }}</div>
|
<div style="margin: 10px 0">{{ $t('trials:uploadedDicoms:title:dicomUploaded') }}</div>
|
||||||
<div class="functions" style="text-align: right">
|
<div class="functions" style="text-align: right">
|
||||||
<!-- //批量删除已上传的影像 -->
|
<!-- //批量删除已上传的影像 -->
|
||||||
<el-button
|
<el-button :disabled="deleteArr.length === 0" type="primary" size="small" icon="el-icon-delete"
|
||||||
:disabled="deleteArr.length === 0"
|
@click="handleBatchDelete">{{ $t('trials:uploadedDicoms:action:delete') }}</el-button>
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
icon="el-icon-delete"
|
|
||||||
@click="handleBatchDelete"
|
|
||||||
>{{ $t('trials:uploadedDicoms:action:delete') }}</el-button>
|
|
||||||
<!-- 预览 -->
|
<!-- 预览 -->
|
||||||
<el-button
|
<el-button type="primary" icon="el-icon-view" size="small" :disabled="studyList.length === 0"
|
||||||
type="primary"
|
@click="handlePreviewAllFiles">{{ $t('trials:uploadedDicoms:action:preview') }}</el-button>
|
||||||
icon="el-icon-view"
|
|
||||||
size="small"
|
|
||||||
:disabled="studyList.length === 0"
|
|
||||||
@click="handlePreviewAllFiles"
|
|
||||||
>{{ $t('trials:uploadedDicoms:action:preview') }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table v-loading="studyLoading" :data="studyList" style="width: 100%" :row-class-name="tableRowClassName"
|
||||||
v-loading="studyLoading"
|
max-height="250" @selection-change="handleUploadedSelectionChange"
|
||||||
:data="studyList"
|
:default-sort="{ prop: 'UploadedTime', order: 'ascending' }">
|
||||||
style="width: 100%"
|
|
||||||
:row-class-name="tableRowClassName"
|
|
||||||
max-height="250"
|
|
||||||
@selection-change="handleUploadedSelectionChange"
|
|
||||||
:default-sort="{ prop: 'UploadedTime', order: 'ascending' }"
|
|
||||||
>
|
|
||||||
<el-table-column type="selection" width="55" :selectable="handleSelectable2" />
|
<el-table-column type="selection" width="55" :selectable="handleSelectable2" />
|
||||||
<!-- 检查编号 -->
|
<!-- 检查编号 -->
|
||||||
<el-table-column
|
<el-table-column prop="StudyCode" :label="$t('trials:uploadedDicoms:table:studyId')" min-width="80"
|
||||||
prop="StudyCode"
|
show-overflow-tooltip sortable>
|
||||||
:label="$t('trials:uploadedDicoms:table:studyId')"
|
|
||||||
min-width="80"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tooltip
|
<el-tooltip placement="top" v-if="
|
||||||
placement="top"
|
|
||||||
v-if="
|
|
||||||
(() => {
|
(() => {
|
||||||
var r = false
|
var r = false
|
||||||
if (scope.row.IsHaveUploadFailed) {
|
if (scope.row.IsHaveUploadFailed) {
|
||||||
|
|
@ -60,14 +37,10 @@
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
})()
|
})()
|
||||||
"
|
">
|
||||||
>
|
|
||||||
<div slot="content">{{ $t('trials:uploadDicomList:table:status4') }}</div>
|
<div slot="content">{{ $t('trials:uploadDicomList:table:status4') }}</div>
|
||||||
<span
|
<span class="el-icon-warning" style="color: #cbb024; cursor: pointer"
|
||||||
class="el-icon-warning"
|
v-if="scope.row.IsHaveUploadFailed"></span>
|
||||||
style="color: #cbb024; cursor: pointer"
|
|
||||||
v-if="scope.row.IsHaveUploadFailed"
|
|
||||||
></span>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip placement="top" v-if="!scope.row.IsCompleteClinicalData">
|
<el-tooltip placement="top" v-if="!scope.row.IsCompleteClinicalData">
|
||||||
<div slot="content">{{ $t('trials:crc-upload:confirm:message') }}</div>
|
<div slot="content">{{ $t('trials:crc-upload:confirm:message') }}</div>
|
||||||
|
|
@ -77,115 +50,61 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 检查名称 -->
|
<!-- 检查名称 -->
|
||||||
<el-table-column
|
<el-table-column v-if="relationInfo.IsShowStudyName" prop="StudyName" :label="$t('trials:audit:table:StudyName')"
|
||||||
v-if="relationInfo.IsShowStudyName"
|
sortable />
|
||||||
prop="StudyName"
|
|
||||||
:label="$t('trials:audit:table:StudyName')"
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<!-- 检查类型 -->
|
<!-- 检查类型 -->
|
||||||
<el-table-column prop="ModalityForEdit" :label="$t('trials:audit:table:modality')" sortable />
|
<el-table-column prop="ModalityForEdit" :label="$t('trials:audit:table:modality')" sortable />
|
||||||
<!-- 检查设备 -->
|
<!-- 检查设备 -->
|
||||||
<el-table-column prop="Modalities" :label="$t('trials:audit:table:modality1')" sortable />
|
<el-table-column prop="Modalities" :label="$t('trials:audit:table:modality1')" sortable />
|
||||||
<!-- 检查部位 -->
|
<!-- 检查部位 -->
|
||||||
<el-table-column
|
<el-table-column prop="BodyPartForEdit" :label="$t('trials:uploadedDicoms:table:bodyPart')" min-width="100"
|
||||||
prop="BodyPartForEdit"
|
show-overflow-tooltip sortable>
|
||||||
:label="$t('trials:uploadedDicoms:table:bodyPart')"
|
<template slot-scope="scope">{{ getBodyPart(scope.row.BodyPartForEdit, scope.row.BodyPartForEditOther)
|
||||||
min-width="100"
|
}}</template>
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
slot-scope="scope"
|
|
||||||
>{{ getBodyPart(scope.row.BodyPartForEdit, scope.row.BodyPartForEditOther) }}</template>
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 序列数量 -->
|
<!-- 序列数量 -->
|
||||||
<el-table-column
|
<el-table-column prop="SeriesCount" :label="$t('trials:uploadedDicoms:table:seriesCount')" min-width="100"
|
||||||
prop="SeriesCount"
|
show-overflow-tooltip sortable />
|
||||||
:label="$t('trials:uploadedDicoms:table:seriesCount')"
|
|
||||||
min-width="100"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<!-- 图像数量 -->
|
<!-- 图像数量 -->
|
||||||
<el-table-column
|
<el-table-column prop="InstanceCount" :label="$t('trials:uploadedDicoms:table:instanceCount')" min-width="100"
|
||||||
prop="InstanceCount"
|
show-overflow-tooltip sortable />
|
||||||
:label="$t('trials:uploadedDicoms:table:instanceCount')"
|
|
||||||
min-width="100"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<!-- 检查日期 -->
|
<!-- 检查日期 -->
|
||||||
<el-table-column
|
<el-table-column prop="StudyTime" :label="$t('trials:uploadedDicoms:table:studyDate')" min-width="120"
|
||||||
prop="StudyTime"
|
show-overflow-tooltip sortable>
|
||||||
:label="$t('trials:uploadedDicoms:table:studyDate')"
|
|
||||||
min-width="120"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
{{
|
{{
|
||||||
scope.row.StudyTime
|
scope.row.StudyTime
|
||||||
? moment(scope.row.StudyTime).format('YYYY-MM-DD')
|
? moment(scope.row.StudyTime).format('YYYY-MM-DD')
|
||||||
: ''
|
: ''
|
||||||
}}
|
}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 更新时间 -->
|
<!-- 更新时间 -->
|
||||||
<el-table-column
|
<el-table-column prop="UpdateTime" :label="$t('trials:uploadedDicoms:table:UpdateTime')" min-width="120"
|
||||||
prop="UpdateTime"
|
show-overflow-tooltip sortable />
|
||||||
:label="$t('trials:uploadedDicoms:table:UpdateTime')"
|
|
||||||
min-width="120"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<!-- 上传时间 -->
|
<!-- 上传时间 -->
|
||||||
<el-table-column
|
<el-table-column prop="UploadedTime" :label="$t('trials:uploadedDicoms:table:uploadedTime')" min-width="120"
|
||||||
prop="UploadedTime"
|
show-overflow-tooltip sortable />
|
||||||
:label="$t('trials:uploadedDicoms:table:uploadedTime')"
|
|
||||||
min-width="120"
|
|
||||||
show-overflow-tooltip
|
|
||||||
sortable
|
|
||||||
/>
|
|
||||||
<el-table-column :label="$t('common:action:action')" min-width="260" fixed="right">
|
<el-table-column :label="$t('common:action:action')" min-width="260" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 预览 -->
|
<!-- 预览 -->
|
||||||
<el-button
|
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0"
|
||||||
icon="el-icon-view"
|
:title="$t('trials:uploadedDicoms:action:preview')" circle @click="handleViewStudy(scope.row)" />
|
||||||
:disabled="scope.row.SeriesCount === 0"
|
|
||||||
:title="$t('trials:uploadedDicoms:action:preview')"
|
|
||||||
circle
|
|
||||||
@click="handleViewStudy(scope.row)"
|
|
||||||
/>
|
|
||||||
<!-- 上传临床数据 -->
|
<!-- 上传临床数据 -->
|
||||||
<el-button
|
<el-button icon="el-icon-upload2" v-if="
|
||||||
icon="el-icon-upload2"
|
|
||||||
v-if="
|
|
||||||
['PT、CT', 'CT、PT', 'PET-CT'].includes(scope.row.Modalities) &&
|
['PT、CT', 'CT、PT', 'PET-CT'].includes(scope.row.Modalities) &&
|
||||||
relationInfo.IsHaveStudyClinicalData
|
relationInfo.IsHaveStudyClinicalData
|
||||||
"
|
" :disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
||||||
:disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
:title="$t('trials:workbench:title:UploadClinicalData')" circle @click="handleUploadPetData(scope.row)" />
|
||||||
:title="$t('trials:workbench:title:UploadClinicalData')"
|
|
||||||
circle
|
|
||||||
@click="handleUploadPetData(scope.row)"
|
|
||||||
/>
|
|
||||||
<!-- 编辑 -->
|
<!-- 编辑 -->
|
||||||
<el-button
|
<el-button icon="el-icon-edit-outline" v-hasPermi="['trials:trials-panel:visit:crc-upload:edit']"
|
||||||
icon="el-icon-edit-outline"
|
|
||||||
v-hasPermi="['trials:trials-panel:visit:crc-upload:edit']"
|
|
||||||
:title="$t('common:button:edit')"
|
:title="$t('common:button:edit')"
|
||||||
:disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
:disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
||||||
circle
|
circle @click="handleEditStudy(scope.row)" />
|
||||||
@click="handleEditStudy(scope.row)"
|
|
||||||
/>
|
|
||||||
<!-- 删除 :disabled="scope.row.IsDeleted"-->
|
<!-- 删除 :disabled="scope.row.IsDeleted"-->
|
||||||
<el-button
|
<el-button icon="el-icon-delete" :title="$t('trials:uploadedDicoms:action:delete')" circle
|
||||||
icon="el-icon-delete"
|
|
||||||
:title="$t('trials:uploadedDicoms:action:delete')"
|
|
||||||
circle
|
|
||||||
:disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
:disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
||||||
@click="handleDeleteStudy(scope.row)"
|
@click="handleDeleteStudy(scope.row)" />
|
||||||
/>
|
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- icon="el-icon-toilet-paper"-->
|
<!-- icon="el-icon-toilet-paper"-->
|
||||||
<!-- circle-->
|
<!-- circle-->
|
||||||
|
|
@ -208,31 +127,18 @@
|
||||||
<div id="directoryInputWrapper" class="btn btn-link file-input">
|
<div id="directoryInputWrapper" class="btn btn-link file-input">
|
||||||
<el-button type="primary" :disabled="btnLoading" :loading="btnLoading" size="small">
|
<el-button type="primary" :disabled="btnLoading" :loading="btnLoading" size="small">
|
||||||
{{
|
{{
|
||||||
$t('trials:uploadedDicomsicom:button:selectFolder')
|
$t('trials:uploadedDicomsicom:button:selectFolder')
|
||||||
}}
|
}}
|
||||||
</el-button>
|
</el-button>
|
||||||
<input
|
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title
|
||||||
type="file"
|
@change="beginScanFiles($event)" />
|
||||||
name="file"
|
|
||||||
ref="pathClear"
|
|
||||||
:disabled="btnLoading"
|
|
||||||
webkitdirectory
|
|
||||||
multiple
|
|
||||||
title
|
|
||||||
@change="beginScanFiles($event)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="drag" ref="drag" @dragover="handleDragover" @drop="handleDrop">
|
<div class="drag" ref="drag" @dragover="handleDragover" @drop="handleDrop">
|
||||||
<!-- 文件列表 -->
|
<!-- 文件列表 -->
|
||||||
<el-table
|
<el-table ref="dicomFilesTable" :data="uploadQueues" :row-key="(row) => row.studyIndex"
|
||||||
ref="dicomFilesTable"
|
class="dicomFiles-table" @selection-change="handleSelectionChange">
|
||||||
:data="uploadQueues"
|
|
||||||
:row-key="(row) => row.studyIndex"
|
|
||||||
class="dicomFiles-table"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
>
|
|
||||||
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
|
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
|
||||||
<el-table-column type="index" width="40" />
|
<el-table-column type="index" width="40" />
|
||||||
<el-table-column min-width="200" show-overflow-tooltip>
|
<el-table-column min-width="200" show-overflow-tooltip>
|
||||||
|
|
@ -259,21 +165,16 @@
|
||||||
<span v-else style="color: #f44336">N/A</span>
|
<span v-else style="color: #f44336">N/A</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-block; margin-right: 2px">
|
<div style="display: inline-block; margin-right: 2px">
|
||||||
<span
|
<span v-if="scope.row.dicomInfo.modality.length > 0">{{ scope.row.dicomInfo.modality.join('、')
|
||||||
v-if="scope.row.dicomInfo.modality.length > 0"
|
}},</span>
|
||||||
>{{ scope.row.dicomInfo.modality.join('、') }},</span>
|
|
||||||
<span v-else style="color: #f44336">N/A,</span>
|
<span v-else style="color: #f44336">N/A,</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-block; margin-right: 2px">
|
<div style="display: inline-block; margin-right: 2px">
|
||||||
<span
|
<span v-if="scope.row.seriesList.length">{{ scope.row.seriesList.length }} Series,</span>
|
||||||
v-if="scope.row.seriesList.length"
|
|
||||||
>{{ scope.row.seriesList.length }} Series,</span>
|
|
||||||
<span v-else style="color: #f44336">N/A,</span>
|
<span v-else style="color: #f44336">N/A,</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-block">
|
<div style="display: inline-block">
|
||||||
<span
|
<span v-if="scope.row.fileList.length">{{ scope.row.fileList.length }} Instances</span>
|
||||||
v-if="scope.row.fileList.length"
|
|
||||||
>{{ scope.row.fileList.length }} Instances</span>
|
|
||||||
<span v-else style="color: #f44336">N/A</span>
|
<span v-else style="color: #f44336">N/A</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -284,9 +185,7 @@
|
||||||
<span v-else style="color: #f44336">N/A,</span>
|
<span v-else style="color: #f44336">N/A,</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-block">
|
<div style="display: inline-block">
|
||||||
<span
|
<span v-if="scope.row.dicomInfo.description">{{ scope.row.dicomInfo.description }}</span>
|
||||||
v-if="scope.row.dicomInfo.description"
|
|
||||||
>{{ scope.row.dicomInfo.description }}</span>
|
|
||||||
<span v-else style="color: #f44336">N/A</span>
|
<span v-else style="color: #f44336">N/A</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -306,7 +205,7 @@
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
{{
|
{{
|
||||||
$t('trials:uploadDicomList:table:patientInfo')
|
$t('trials:uploadDicomList:table:patientInfo')
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
@ -317,180 +216,135 @@
|
||||||
<span v-if="scope.row.dicomInfo.patientId">
|
<span v-if="scope.row.dicomInfo.patientId">
|
||||||
<span style="font-weight: 500">PID:</span>
|
<span style="font-weight: 500">PID:</span>
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientId }}
|
scope.row.dicomInfo.patientId }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else style="color: #f44336">N/A</span>
|
<span v-else style="color: #f44336">N/A</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span :class="[
|
||||||
:class="[
|
|
||||||
scope.row.dicomInfo.patientName ? '' : 'colorOfRed',
|
scope.row.dicomInfo.patientName ? '' : 'colorOfRed',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientName
|
scope.row.dicomInfo.patientName
|
||||||
? scope.row.dicomInfo.patientName
|
? scope.row.dicomInfo.patientName
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span :class="[
|
||||||
:class="[
|
|
||||||
scope.row.dicomInfo.patientSex ? '' : 'colorOfRed',
|
scope.row.dicomInfo.patientSex ? '' : 'colorOfRed',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientSex
|
scope.row.dicomInfo.patientSex
|
||||||
? scope.row.dicomInfo.patientSex
|
? scope.row.dicomInfo.patientSex
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}},
|
}},
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span :class="[
|
||||||
:class="[
|
|
||||||
scope.row.dicomInfo.patientAge ? '' : 'colorOfRed',
|
scope.row.dicomInfo.patientAge ? '' : 'colorOfRed',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientAge
|
scope.row.dicomInfo.patientAge
|
||||||
? scope.row.dicomInfo.patientAge
|
? scope.row.dicomInfo.patientAge
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}},
|
}},
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span :class="[
|
||||||
:class="[
|
|
||||||
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
|
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
scope.row.dicomInfo.patientBirthDate
|
scope.row.dicomInfo.patientBirthDate
|
||||||
? scope.row.dicomInfo.patientBirthDate
|
? scope.row.dicomInfo.patientBirthDate
|
||||||
: 'N/A'
|
: 'N/A'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column :label="$t('trials:uploadDicomList:table:failedFileCount')" min-width="150"
|
||||||
:label="$t('trials:uploadDicomList:table:failedFileCount')"
|
show-overflow-tooltip>
|
||||||
min-width="150"
|
|
||||||
show-overflow-tooltip
|
|
||||||
>
|
|
||||||
<!--:percentage="
|
<!--:percentage="
|
||||||
(scope.row.dicomInfo.failedFileCount * 100) /
|
(scope.row.dicomInfo.failedFileCount * 100) /
|
||||||
scope.row.dicomInfo.fileCount
|
scope.row.dicomInfo.fileCount
|
||||||
"
|
"
|
||||||
:show-text="false"--->
|
:show-text="false"--->
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-progress
|
<el-progress color="#409eff" :percentage="(
|
||||||
color="#409eff"
|
|
||||||
:percentage="(
|
|
||||||
(scope.row.dicomInfo.uploadFileSize * 100) /
|
(scope.row.dicomInfo.uploadFileSize * 100) /
|
||||||
(scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1)
|
(scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1)
|
||||||
).toFixed(2) * 1
|
).toFixed(2) * 1
|
||||||
"
|
" />
|
||||||
/>
|
|
||||||
<span>
|
<span>
|
||||||
{{ $t('trials:uploadDicomList:table:uploadNow')
|
{{ $t('trials:uploadDicomList:table:uploadNow')
|
||||||
}}{{ scope.row.dicomInfo.failedFileCount }}/{{
|
}}{{ scope.row.dicomInfo.failedFileCount }}/{{
|
||||||
scope.row.dicomInfo.fileCount
|
scope.row.dicomInfo.fileCount
|
||||||
}}
|
}}
|
||||||
({{
|
({{
|
||||||
(scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(3)
|
(scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(3)
|
||||||
}}MB/{{
|
}}MB/{{
|
||||||
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3)
|
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3)
|
||||||
}}MB)
|
}}MB)
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column :label="$t('trials:uploadDicomList:table:status')" min-width="140" show-overflow-tooltip>
|
||||||
:label="$t('trials:uploadDicomList:table:status')"
|
|
||||||
min-width="140"
|
|
||||||
show-overflow-tooltip
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span
|
<span v-if="
|
||||||
v-if="
|
|
||||||
!scope.row.dicomInfo.failedFileCount &&
|
!scope.row.dicomInfo.failedFileCount &&
|
||||||
!scope.row.dicomInfo.isInit
|
!scope.row.dicomInfo.isInit
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status1') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status1') }}</span>
|
<span style="color: #409eff" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #409eff"
|
|
||||||
v-else-if="
|
|
||||||
!scope.row.dicomInfo.failedFileCount &&
|
!scope.row.dicomInfo.failedFileCount &&
|
||||||
scope.row.dicomInfo.isInit &&
|
scope.row.dicomInfo.isInit &&
|
||||||
btnLoading
|
btnLoading
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
<span style="color: #409eff" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #409eff"
|
|
||||||
v-else-if="
|
|
||||||
scope.row.dicomInfo.failedFileCount <
|
scope.row.dicomInfo.failedFileCount <
|
||||||
scope.row.dicomInfo.fileCount &&
|
scope.row.dicomInfo.fileCount &&
|
||||||
!scope.row.uploadState.record
|
!scope.row.uploadState.record
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status2') }}</span>
|
<span style="color: #2cc368" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #2cc368"
|
|
||||||
v-else-if="
|
|
||||||
scope.row.dicomInfo.failedFileCount ===
|
scope.row.dicomInfo.failedFileCount ===
|
||||||
scope.row.dicomInfo.fileCount
|
scope.row.dicomInfo.fileCount
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status3') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status3') }}</span>
|
<span style="color: #f66" v-else-if="
|
||||||
<span
|
|
||||||
style="color: #f66"
|
|
||||||
v-else-if="
|
|
||||||
scope.row.uploadState.record &&
|
scope.row.uploadState.record &&
|
||||||
scope.row.uploadState.record.fileCount === 0
|
scope.row.uploadState.record.fileCount === 0
|
||||||
"
|
">{{ $t('trials:uploadDicomList:table:status5') }}</span>
|
||||||
>{{ $t('trials:uploadDicomList:table:status5') }}</span>
|
|
||||||
<span style="color: #f66" v-else>
|
<span style="color: #f66" v-else>
|
||||||
{{
|
{{
|
||||||
$t('trials:uploadDicomList:table:Failed')
|
$t('trials:uploadDicomList:table:Failed')
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column :label="$t('trials:uploadDicomList:table:record')" min-width="140" show-overflow-tooltip>
|
||||||
:label="$t('trials:uploadDicomList:table:record')"
|
|
||||||
min-width="140"
|
|
||||||
show-overflow-tooltip
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tooltip placement="top" v-if="scope.row.uploadState.record">
|
<el-tooltip placement="top" v-if="scope.row.uploadState.record">
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
<div style="max-height: 500px; overflow-y: auto">
|
<div style="max-height: 500px; overflow-y: auto">
|
||||||
{{ $t('trials:uploadDicomList:table:Existed') }}:
|
{{ $t('trials:uploadDicomList:table:Existed') }}:
|
||||||
<div v-if="scope.row.uploadState.record.Existed.length">
|
<div v-if="scope.row.uploadState.record.Existed.length">
|
||||||
<div
|
<div v-for="item of scope.row.uploadState.record.Existed" :key="item"
|
||||||
v-for="item of scope.row.uploadState.record.Existed"
|
style="font-size: 12px; color: #baa72a">{{ item }}</div>
|
||||||
:key="item"
|
|
||||||
style="font-size: 12px; color: #baa72a"
|
|
||||||
>{{ item }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> </div>
|
<div v-else> </div>
|
||||||
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
|
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
|
||||||
<div v-if="scope.row.uploadState.record.Uploaded.length">
|
<div v-if="scope.row.uploadState.record.Uploaded.length">
|
||||||
<div
|
<div v-for="item of scope.row.uploadState.record.Uploaded" :key="item"
|
||||||
v-for="item of scope.row.uploadState.record.Uploaded"
|
style="font-size: 12px; color: #24b837">{{ item }}</div>
|
||||||
:key="item"
|
|
||||||
style="font-size: 12px; color: #24b837"
|
|
||||||
>{{ item }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> </div>
|
<div v-else> </div>
|
||||||
<br />
|
<br />
|
||||||
{{ $t('trials:uploadDicomList:table:Failed') }}:
|
{{ $t('trials:uploadDicomList:table:Failed') }}:
|
||||||
<div v-if="scope.row.uploadState.record.Failed.length">
|
<div v-if="scope.row.uploadState.record.Failed.length">
|
||||||
<div
|
<div v-for="item of scope.row.uploadState.record.Failed" :key="item"
|
||||||
v-for="item of scope.row.uploadState.record.Failed"
|
style="font-size: 12px; color: #f66">{{ item }}</div>
|
||||||
:key="item"
|
|
||||||
style="font-size: 12px; color: #f66"
|
|
||||||
>{{ item }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> </div>
|
<div v-else> </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -498,19 +352,19 @@
|
||||||
<el-button size="mini" style="cursor: pointer">
|
<el-button size="mini" style="cursor: pointer">
|
||||||
<span style="font-size: 12px; color: #baa72a">
|
<span style="font-size: 12px; color: #baa72a">
|
||||||
{{
|
{{
|
||||||
scope.row.uploadState.record.Existed.length
|
scope.row.uploadState.record.Existed.length
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
/
|
/
|
||||||
<span style="font-size: 12px; color: #24b837">
|
<span style="font-size: 12px; color: #24b837">
|
||||||
{{
|
{{
|
||||||
scope.row.uploadState.record.Uploaded.length
|
scope.row.uploadState.record.Uploaded.length
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
/
|
/
|
||||||
<span style="font-size: 12px; color: #f66">
|
<span style="font-size: 12px; color: #f66">
|
||||||
{{
|
{{
|
||||||
scope.row.uploadState.record.Failed.length
|
scope.row.uploadState.record.Failed.length
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -521,33 +375,21 @@
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 预览 -->
|
<!-- 预览 -->
|
||||||
<!-- :disabled="scope.row.dicomInfo.failedFileCount < scope.row.dicomInfo.fileCount && scope.row.dicomInfo.failedFileCount !== 0"-->
|
<!-- :disabled="scope.row.dicomInfo.failedFileCount < scope.row.dicomInfo.fileCount && scope.row.dicomInfo.failedFileCount !== 0"-->
|
||||||
<el-button
|
<el-button icon="el-icon-view" circle :disabled="(scope.row.uploadState.stateCode !== '' &&
|
||||||
icon="el-icon-view"
|
|
||||||
circle
|
|
||||||
:disabled="(scope.row.uploadState.stateCode !== '' &&
|
|
||||||
scope.row.dicomInfo.failedFileCount <
|
scope.row.dicomInfo.failedFileCount <
|
||||||
scope.row.dicomInfo.fileCount &&
|
scope.row.dicomInfo.fileCount &&
|
||||||
!scope.row.uploadState.record) ||
|
!scope.row.uploadState.record) ||
|
||||||
btnLoading
|
btnLoading
|
||||||
"
|
" :title="$t('trials:uploadedDicoms:action:preview')" size="small"
|
||||||
:title="$t('trials:uploadedDicoms:action:preview')"
|
@click="handlePreview(scope.row.dicomInfo.studyUid)" />
|
||||||
size="small"
|
|
||||||
@click="handlePreview(scope.row.dicomInfo.studyUid)"
|
|
||||||
/>
|
|
||||||
<!-- 移除 -->
|
<!-- 移除 -->
|
||||||
<el-button
|
<el-button icon="el-icon-delete" circle :title="$t('trials:uploadedDicoms:action:delete')" size="small"
|
||||||
icon="el-icon-delete"
|
|
||||||
circle
|
|
||||||
:title="$t('trials:uploadedDicoms:action:delete')"
|
|
||||||
size="small"
|
|
||||||
:disabled="(scope.row.uploadState.stateCode !== '' &&
|
:disabled="(scope.row.uploadState.stateCode !== '' &&
|
||||||
scope.row.dicomInfo.failedFileCount <
|
scope.row.dicomInfo.failedFileCount <
|
||||||
scope.row.dicomInfo.fileCount &&
|
scope.row.dicomInfo.fileCount &&
|
||||||
!scope.row.uploadState.record) ||
|
!scope.row.uploadState.record) ||
|
||||||
btnLoading
|
btnLoading
|
||||||
"
|
" @click="handleDelete(scope.$index, scope.row)" />
|
||||||
@click="handleDelete(scope.$index, scope.row)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -560,80 +402,41 @@
|
||||||
</el-button>-->
|
</el-button>-->
|
||||||
<span style="margin-right: 10px">
|
<span style="margin-right: 10px">
|
||||||
{{
|
{{
|
||||||
$store.state.trials.uploadTip
|
$store.state.trials.uploadTip
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<!-- 上传 -->
|
<!-- 上传 -->
|
||||||
<el-button
|
<el-button size="small" type="primary" :disabled="selectArr.length == 0 || !isScan" :loading="btnLoading"
|
||||||
size="small"
|
@click="beginUploadQueues">{{ $t('trials:uploadDicomList:button:upload') }}</el-button>
|
||||||
type="primary"
|
|
||||||
:disabled="selectArr.length == 0 || !isScan"
|
|
||||||
:loading="btnLoading"
|
|
||||||
@click="beginUploadQueues"
|
|
||||||
>{{ $t('trials:uploadDicomList:button:upload') }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<!-- pacs上传 -->
|
<!-- pacs上传 -->
|
||||||
<el-tab-pane
|
<el-tab-pane :label="$t('trials:uploadNonDicoms:tab:uploadPacs')" name="pacs" :disabled="btnLoading"
|
||||||
:label="$t('trials:uploadNonDicoms:tab:uploadPacs')"
|
v-if="relationInfo.IsPacsConnectConfiged">
|
||||||
name="pacs"
|
<uploadDicomPacs v-if="uploadActiveName === 'pacs'" ref="dicomPacs" :subjectVisitId="subjectVisitId"
|
||||||
:disabled="btnLoading"
|
:relationInfo="relationInfo" :subjectId="subjectId" @getList="getParentList" @petDataTip="petDataTip" />
|
||||||
v-if="relationInfo.IsPacsConnectConfiged"
|
|
||||||
>
|
|
||||||
<uploadDicomPacs
|
|
||||||
v-if="uploadActiveName === 'pacs'"
|
|
||||||
ref="dicomPacs"
|
|
||||||
:subjectVisitId="subjectVisitId"
|
|
||||||
:relationInfo="relationInfo"
|
|
||||||
:subjectId="subjectId"
|
|
||||||
@getList="getParentList"
|
|
||||||
@petDataTip="petDataTip"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<!-- 预览影像模态框 -->
|
<!-- 预览影像模态框 -->
|
||||||
<el-dialog
|
<el-dialog v-if="previewVisible" :fullscreen="true" :show-close="true" :visible.sync="previewVisible"
|
||||||
v-if="previewVisible"
|
:title="$t('trials:uploadDicoms:title:previewLocalImage')" append-to-body>
|
||||||
:fullscreen="true"
|
|
||||||
:show-close="true"
|
|
||||||
:visible.sync="previewVisible"
|
|
||||||
:title="$t('trials:uploadDicoms:title:previewLocalImage')"
|
|
||||||
append-to-body
|
|
||||||
>
|
|
||||||
<DicomPreview :uid="uid" :studyList="uploadQueues" />
|
<DicomPreview :uid="uid" :studyList="uploadQueues" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!--pet-ct临床数据上传-->
|
<!--pet-ct临床数据上传-->
|
||||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
<el-dialog v-if="petVisible" :show-close="true" :close-on-click-modal="false" :visible.sync="petVisible" append-to-body>
|
||||||
<uploadPetClinicalData
|
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="studyData" :allow-add-or-edit="true"
|
||||||
:subject-visit-id="data.Id"
|
@getStudyInfo="getStudyInfo" />
|
||||||
:data="data"
|
|
||||||
:studyData="studyData"
|
|
||||||
:allow-add-or-edit="true"
|
|
||||||
@getStudyInfo="getStudyInfo"
|
|
||||||
/>
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 校验警告信息模态框 -->
|
<!-- 校验警告信息模态框 -->
|
||||||
<el-dialog
|
<el-dialog v-if="warning_cfg.visible" :visible.sync="warning_cfg.visible" width="500px"
|
||||||
v-if="warning_cfg.visible"
|
:close-on-click-modal="false" append-to-body title="Warning" custom-class="warning-dialog">
|
||||||
:visible.sync="warning_cfg.visible"
|
|
||||||
width="500px"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
append-to-body
|
|
||||||
title="Warning"
|
|
||||||
custom-class="warning-dialog"
|
|
||||||
>
|
|
||||||
<div style="border: 1px solid #e0e0e0; padding: 10px">
|
<div style="border: 1px solid #e0e0e0; padding: 10px">
|
||||||
<!-- Information from DICOM headers not consistent with that of this subject -->
|
<!-- Information from DICOM headers not consistent with that of this subject -->
|
||||||
<div
|
<div style="color: red; font-size: 14px; margin-bottom: 10px">{{
|
||||||
style="color: red; font-size: 14px; margin-bottom: 10px"
|
$t('trials:uploadDicomList:message:informationConsistent') }}:</div>
|
||||||
>{{ $t('trials:uploadDicomList:message:informationConsistent') }}:</div>
|
|
||||||
<div v-for="(item, i) in warningArr" :key="item.index">
|
<div v-for="(item, i) in warningArr" :key="item.index">
|
||||||
<div>{{ `(${i + 1}). ACC: ${item.accNumber}` }}</div>
|
<div>{{ `(${i + 1}). ACC: ${item.accNumber}` }}</div>
|
||||||
<div
|
<div v-for="(warning, index) in item.warnings" :key="index" style="margin: 10px 0px; font-size: 13px">
|
||||||
v-for="(warning, index) in item.warnings"
|
|
||||||
:key="index"
|
|
||||||
style="margin: 10px 0px; font-size: 13px"
|
|
||||||
>
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>{{ warning }}</li>
|
<li>{{ warning }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -641,61 +444,39 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div slot="footer" class="base-modal-footer">
|
<div slot="footer" class="base-modal-footer">
|
||||||
<el-button
|
<el-button size="small" type="primary" @click="handleCancelWarnVisible">{{ $t('common:button:cancel')
|
||||||
size="small"
|
}}</el-button>
|
||||||
type="primary"
|
<el-button size="small" type="primary" @click="handleContinueUpload">{{
|
||||||
@click="handleCancelWarnVisible"
|
$t('trials:uploadDicomList:button:upload')
|
||||||
>{{ $t('common:button:cancel') }}</el-button>
|
}}</el-button>
|
||||||
<el-button
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
@click="handleContinueUpload"
|
|
||||||
>{{ $t('trials:uploadDicomList:button:upload') }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog
|
<el-dialog v-if="editStudyInfoVisible" :title="$t('trials:audit:action:edit')" :visible.sync="editStudyInfoVisible"
|
||||||
v-if="editStudyInfoVisible"
|
:close-on-click-modal="false" append-to-body custom-class="base-dialog-wrapper" width="600px">
|
||||||
:title="$t('trials:audit:action:edit')"
|
<div style="
|
||||||
:visible.sync="editStudyInfoVisible"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
append-to-body
|
|
||||||
custom-class="base-dialog-wrapper"
|
|
||||||
width="600px"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
max-height: 650px;
|
max-height: 650px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
"
|
">
|
||||||
>
|
|
||||||
<el-form ref="studyForm" :model="studyForm" label-width="100px">
|
<el-form ref="studyForm" :model="studyForm" label-width="100px">
|
||||||
<!-- 检查编号 -->
|
<!-- 检查编号 -->
|
||||||
<el-form-item :label="$t('trials:audit:table:studyId')">
|
<el-form-item :label="$t('trials:audit:table:studyId')">
|
||||||
<el-input v-model="studyForm.StudyCode" disabled />
|
<el-input v-model="studyForm.StudyCode" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 检查名称 -->
|
<!-- 检查名称 -->
|
||||||
<el-form-item
|
<el-form-item v-if="relationInfo.IsShowStudyName" :label="$t('trials:audit:table:StudyName')" prop="StudyName"
|
||||||
v-if="relationInfo.IsShowStudyName"
|
|
||||||
:label="$t('trials:audit:table:StudyName')"
|
|
||||||
prop="StudyName"
|
|
||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: $t('common:ruleMessage:specify'),
|
message: $t('common:ruleMessage:specify'),
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
<el-radio-group v-model="studyForm.StudyName">
|
<el-radio-group v-model="studyForm.StudyName">
|
||||||
<template v-for="m in relationInfo.StudyNameList">
|
<template v-for="m in relationInfo.StudyNameList">
|
||||||
<el-radio
|
<el-radio v-if="m.IsChoose" :key="m.Name" :label="isEN ? m.EnName : m.Name"
|
||||||
v-if="m.IsChoose"
|
style="margin-bottom: 15px" />
|
||||||
:key="m.Name"
|
|
||||||
:label="isEN ? m.EnName : m.Name"
|
|
||||||
style="margin-bottom: 15px"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -704,51 +485,33 @@
|
||||||
<el-input v-model="studyForm.Modalities" disabled />
|
<el-input v-model="studyForm.Modalities" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 检查类型 -->
|
<!-- 检查类型 -->
|
||||||
<el-form-item
|
<el-form-item v-else :label="$t('trials:audit:table:modality')" prop="Modalities" :rules="[
|
||||||
v-else
|
|
||||||
:label="$t('trials:audit:table:modality')"
|
|
||||||
prop="Modalities"
|
|
||||||
:rules="[
|
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: $t('common:ruleMessage:specify'),
|
message: $t('common:ruleMessage:specify'),
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
<el-radio-group v-model="studyForm.Modality">
|
<el-radio-group v-model="studyForm.Modality">
|
||||||
<el-radio
|
<el-radio v-for="m in trialModalitys" v-show="m !== ''" :key="m" :label="m" style="margin-bottom: 15px" />
|
||||||
v-for="m in trialModalitys"
|
|
||||||
v-show="m !== ''"
|
|
||||||
:key="m"
|
|
||||||
:label="m"
|
|
||||||
style="margin-bottom: 15px"
|
|
||||||
/>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 检查部位 -->
|
<!-- 检查部位 -->
|
||||||
<el-form-item
|
<el-form-item :label="$t('trials:audit:table:bodyPart')" prop="BodyPartForEdit" :rules="[
|
||||||
:label="$t('trials:audit:table:bodyPart')"
|
|
||||||
prop="BodyPartForEdit"
|
|
||||||
:rules="[
|
|
||||||
{
|
{
|
||||||
required: studyForm.BodyPartForEditOther ? false : true,
|
required: studyForm.BodyPartForEditOther ? false : true,
|
||||||
message: $t('common:ruleMessage:specify'),
|
message: $t('common:ruleMessage:specify'),
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
<el-checkbox-group v-model="studyForm.BodyPartForEdit">
|
<el-checkbox-group v-model="studyForm.BodyPartForEdit">
|
||||||
<el-checkbox v-for="bodyPart in trialBodyPartTypes" :key="bodyPart" :label="bodyPart">
|
<el-checkbox v-for="bodyPart in trialBodyPartTypes" :key="bodyPart" :label="bodyPart">
|
||||||
{{
|
{{
|
||||||
$fd('Bodypart', bodyPart, 'Code', BodyPart, 'Name')
|
$fd('Bodypart', bodyPart, 'Code', BodyPart, 'Name')
|
||||||
}}
|
}}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
<el-input
|
<el-input :placeholder="$t('trials:audit:placeholder:BodyPartForEditOther')"
|
||||||
:placeholder="$t('trials:audit:placeholder:BodyPartForEditOther')"
|
v-model.trim="studyForm.BodyPartForEditOther" style="width:150px;margin-left: 30px;"></el-input>
|
||||||
v-model.trim="studyForm.BodyPartForEditOther"
|
|
||||||
style="width:150px;margin-left: 30px;"
|
|
||||||
></el-input>
|
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 序列数量 -->
|
<!-- 序列数量 -->
|
||||||
|
|
@ -756,38 +519,21 @@
|
||||||
<el-input v-model="studyForm.SeriesCount" disabled />
|
<el-input v-model="studyForm.SeriesCount" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 图像数量 -->
|
<!-- 图像数量 -->
|
||||||
<el-form-item
|
<el-form-item v-if="studyForm.InstanceCount" :label="$t('trials:audit:table:instanceCount')">
|
||||||
v-if="studyForm.InstanceCount"
|
|
||||||
:label="$t('trials:audit:table:instanceCount')"
|
|
||||||
>
|
|
||||||
<el-input v-model="studyForm.InstanceCount" disabled />
|
<el-input v-model="studyForm.InstanceCount" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 检查日期 -->
|
<!-- 检查日期 -->
|
||||||
<el-form-item :label="$t('trials:audit:table:studyDate')">
|
<el-form-item :label="$t('trials:audit:table:studyDate')">
|
||||||
<el-date-picker
|
<el-date-picker v-model="studyForm.StudyTime" disabled type="date" value-format="yyyy-MM-dd"
|
||||||
v-model="studyForm.StudyTime"
|
format="yyyy-MM-dd" style="width: 100%" />
|
||||||
disabled
|
|
||||||
type="date"
|
|
||||||
value-format="yyyy-MM-dd"
|
|
||||||
format="yyyy-MM-dd"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button
|
<el-button :disabled="btnLoading" size="small" type="primary" @click="editStudyInfoVisible = false">{{
|
||||||
:disabled="btnLoading"
|
$t('common:button:cancel') }}</el-button>
|
||||||
size="small"
|
<el-button :loading="btnLoading" size="small" type="primary" @click="handleUpdateStudyInfo">{{
|
||||||
type="primary"
|
$t('common:button:save') }}</el-button>
|
||||||
@click="editStudyInfoVisible = false"
|
|
||||||
>{{ $t('common:button:cancel') }}</el-button>
|
|
||||||
<el-button
|
|
||||||
:loading="btnLoading"
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
@click="handleUpdateStudyInfo"
|
|
||||||
>{{ $t('common:button:save') }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1045,8 +791,14 @@ export default {
|
||||||
// 预览单个检查影像
|
// 预览单个检查影像
|
||||||
handleViewStudy(row) {
|
handleViewStudy(row) {
|
||||||
var token = getToken()
|
var token = getToken()
|
||||||
|
let path = ''
|
||||||
|
if (this.hasPermi(['trials:trials-panel:visit:crc-upload:edit'])) {
|
||||||
|
path = `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study&showEdit=${!(!this.isAfresh && this.data.SubmitState === 2 && this.data.SubmitTime) ? 1 : 0}`
|
||||||
|
} else {
|
||||||
|
path = `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study`
|
||||||
|
}
|
||||||
const routeData = this.$router.resolve({
|
const routeData = this.$router.resolve({
|
||||||
path: `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study`,
|
path: path,
|
||||||
})
|
})
|
||||||
window.open(routeData.href, '_blank')
|
window.open(routeData.href, '_blank')
|
||||||
},
|
},
|
||||||
|
|
@ -1104,7 +856,7 @@ export default {
|
||||||
})
|
})
|
||||||
var validFilesCount = 0
|
var validFilesCount = 0
|
||||||
for (var i = 0; i < files.length; ++i) {
|
for (var i = 0; i < files.length; ++i) {
|
||||||
;(function (index) {
|
; (function (index) {
|
||||||
p = p.then(function () {
|
p = p.then(function () {
|
||||||
if (files[index].name.toUpperCase().indexOf('DICOMDIR') === -1) {
|
if (files[index].name.toUpperCase().indexOf('DICOMDIR') === -1) {
|
||||||
validFilesCount = validFilesCount + 1
|
validFilesCount = validFilesCount + 1
|
||||||
|
|
@ -1618,7 +1370,7 @@ export default {
|
||||||
'trials:uploadDicomList:label:confirm'
|
'trials:uploadDicomList:label:confirm'
|
||||||
),
|
),
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
callback: (action) => {},
|
callback: (action) => { },
|
||||||
})
|
})
|
||||||
this.btnLoading = false
|
this.btnLoading = false
|
||||||
}
|
}
|
||||||
|
|
@ -1755,7 +1507,7 @@ export default {
|
||||||
dicomUploadInProgress({
|
dicomUploadInProgress({
|
||||||
trialId: scope.trialId,
|
trialId: scope.trialId,
|
||||||
studyInstanceUid: dicomInfo.studyUid,
|
studyInstanceUid: dicomInfo.studyUid,
|
||||||
}).then((res) => {})
|
}).then((res) => { })
|
||||||
}, 5000)
|
}, 5000)
|
||||||
scope.myInterval.push(t)
|
scope.myInterval.push(t)
|
||||||
let Record = {
|
let Record = {
|
||||||
|
|
@ -1787,8 +1539,8 @@ export default {
|
||||||
institutionName: dicomInfo.institutionName,
|
institutionName: dicomInfo.institutionName,
|
||||||
patientId: config.DicomStoreInfo.SubjectCode,
|
patientId: config.DicomStoreInfo.SubjectCode,
|
||||||
patientName: '',
|
patientName: '',
|
||||||
patientAge: '',
|
patientAge: dicomInfo.patientAge,
|
||||||
patientSex: config.DicomStoreInfo.SubjectSex,
|
patientSex: config.DicomStoreInfo.SubjectSex || dicomInfo.patientSex,
|
||||||
accessionNumber: dicomInfo.accNumber,
|
accessionNumber: dicomInfo.accNumber,
|
||||||
patientBirthDate: '',
|
patientBirthDate: '',
|
||||||
acquisitionTime: dicomInfo.acquisitionTime,
|
acquisitionTime: dicomInfo.acquisitionTime,
|
||||||
|
|
@ -1872,16 +1624,14 @@ export default {
|
||||||
dicomInfo.failedFileCount++
|
dicomInfo.failedFileCount++
|
||||||
Record.FileCount++
|
Record.FileCount++
|
||||||
} else {
|
} else {
|
||||||
let path = `/${params.trialId}/Image/${
|
let path = `/${params.trialId}/Image/${params.subjectId
|
||||||
params.subjectId
|
}/${params.subjectVisitId}/${dicomInfo.studyUid
|
||||||
}/${params.subjectVisitId}/${
|
}/${scope.getGuid(
|
||||||
dicomInfo.studyUid
|
dicomInfo.studyUid +
|
||||||
}/${scope.getGuid(
|
|
||||||
dicomInfo.studyUid +
|
|
||||||
v.seriesUid +
|
v.seriesUid +
|
||||||
o.instanceUid +
|
o.instanceUid +
|
||||||
params.trialId
|
params.trialId
|
||||||
)}`
|
)}`
|
||||||
if (scope.isClose) return
|
if (scope.isClose) return
|
||||||
console.log(o.file)
|
console.log(o.file)
|
||||||
let res = await dcmUpload(
|
let res = await dcmUpload(
|
||||||
|
|
@ -1902,7 +1652,7 @@ export default {
|
||||||
if (
|
if (
|
||||||
Math.abs(
|
Math.abs(
|
||||||
dicomInfo.uploadFileSize -
|
dicomInfo.uploadFileSize -
|
||||||
dicomInfo.fileSize
|
dicomInfo.fileSize
|
||||||
) < 5000
|
) < 5000
|
||||||
) {
|
) {
|
||||||
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
||||||
|
|
@ -2275,7 +2025,7 @@ export default {
|
||||||
this.studyLoading = true
|
this.studyLoading = true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => { })
|
||||||
},
|
},
|
||||||
// 删除已上传的某个检查
|
// 删除已上传的某个检查
|
||||||
handleDeleteStudy(row) {
|
handleDeleteStudy(row) {
|
||||||
|
|
@ -2306,7 +2056,7 @@ export default {
|
||||||
this.studyLoading = true
|
this.studyLoading = true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => { })
|
||||||
},
|
},
|
||||||
// cancel按钮回调
|
// cancel按钮回调
|
||||||
cancel() {
|
cancel() {
|
||||||
|
|
|
||||||
|
|
@ -277,23 +277,27 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<!-- 注射时间(s) Unix 秒 或 相对秒-->
|
<!-- 注射时间 HHMMSS-->
|
||||||
<el-form-item class="form-item-half" :label="$t('trials:ptData:label:injectTime')" prop="RadiopharmaceuticalStartTime">
|
<el-form-item class="form-item-half" :label="$t('trials:ptData:label:injectTime')" prop="RadiopharmaceuticalStartTime">
|
||||||
<el-input
|
<el-input
|
||||||
v-model.number="formData.RadiopharmaceuticalStartTime"
|
v-model.trim="formData.RadiopharmaceuticalStartTime"
|
||||||
:placeholder="$t('trials:injectTime:eg')"
|
:placeholder="$t('trials:injectTime:eg')"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@input="computeTimeRelation"
|
@input="computeTimeRelation"
|
||||||
|
@blur="handleTimeBlur('RadiopharmaceuticalStartTime')"
|
||||||
|
maxlength="6"
|
||||||
:disabled="!isPatientFormCanEdit"
|
:disabled="!isPatientFormCanEdit"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 成像时间(s) Unix 秒 或 相对秒-->
|
<!-- 成像时间 HHMMSS-->
|
||||||
<el-form-item class="form-item-half" :label="$t('trials:ptData:label:acquisitionTime')" prop="AcquisitionTime">
|
<el-form-item class="form-item-half" :label="$t('trials:ptData:label:acquisitionTime')" prop="AcquisitionTime">
|
||||||
<el-input
|
<el-input
|
||||||
v-model.number="formData.AcquisitionTime"
|
v-model.trim="formData.AcquisitionTime"
|
||||||
:placeholder="$t('trials:injectTime:eg')"
|
:placeholder="$t('trials:injectTime:eg')"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@input="computeTimeRelation"
|
@input="computeTimeRelation"
|
||||||
|
@blur="handleTimeBlur('AcquisitionTime')"
|
||||||
|
maxlength="6"
|
||||||
:disabled="!isPatientFormCanEdit"
|
:disabled="!isPatientFormCanEdit"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -469,8 +473,8 @@ export default {
|
||||||
PatientWeight: null,
|
PatientWeight: null,
|
||||||
RadionuclideTotalDose: null,
|
RadionuclideTotalDose: null,
|
||||||
RadionuclideHalfLife: null,
|
RadionuclideHalfLife: null,
|
||||||
RadiopharmaceuticalStartTime: null,
|
RadiopharmaceuticalStartTime: '',
|
||||||
AcquisitionTime: null,
|
AcquisitionTime: '',
|
||||||
TimeCheck: '',
|
TimeCheck: '',
|
||||||
Reason: ''
|
Reason: ''
|
||||||
},
|
},
|
||||||
|
|
@ -492,11 +496,11 @@ export default {
|
||||||
],
|
],
|
||||||
RadiopharmaceuticalStartTime: [
|
RadiopharmaceuticalStartTime: [
|
||||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
{ type: 'number', message: this.$t('trials:ptData:ruleMessage:number2'), trigger: 'blur' }//请输入数字
|
{ validator: this.validateDicomTime, trigger: 'blur' }
|
||||||
],
|
],
|
||||||
AcquisitionTime: [
|
AcquisitionTime: [
|
||||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||||
{ type: 'number', message: this.$t('trials:ptData:ruleMessage:number2'), trigger: 'blur' },//请输入数字
|
{ validator: this.validateDicomTime, trigger: 'blur' },
|
||||||
// 自定义校验:确保成像时间不早于注射时间
|
// 自定义校验:确保成像时间不早于注射时间
|
||||||
{ validator: this.validateTime, trigger: 'blur' }
|
{ validator: this.validateTime, trigger: 'blur' }
|
||||||
],
|
],
|
||||||
|
|
@ -814,12 +818,68 @@ export default {
|
||||||
// 时间一致性校验
|
// 时间一致性校验
|
||||||
validateTime(rule, value, callback) {
|
validateTime(rule, value, callback) {
|
||||||
const { RadiopharmaceuticalStartTime } = this.formData
|
const { RadiopharmaceuticalStartTime } = this.formData
|
||||||
if (value && RadiopharmaceuticalStartTime !== null && value < RadiopharmaceuticalStartTime) {
|
const acquireSeconds = this.timeToSeconds(value)
|
||||||
|
const startSeconds = this.timeToSeconds(RadiopharmaceuticalStartTime)
|
||||||
|
if (acquireSeconds !== null && startSeconds !== null && acquireSeconds < startSeconds) {
|
||||||
callback(new Error(this.$t('trials:ptData:ruleMessage:number3')))//成像时间不能早于注射时间
|
callback(new Error(this.$t('trials:ptData:ruleMessage:number3')))//成像时间不能早于注射时间
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
validateDicomTime(rule, value, callback) {
|
||||||
|
if (value === undefined || value === null || value === '') {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const raw = String(value).trim()
|
||||||
|
if (!/^\d{1,6}$/.test(raw)) {
|
||||||
|
callback(new Error(this.$t('trials:ptData:ruleMessage:number2')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const normalized = this.normalizeClinicalTime(raw)
|
||||||
|
if (!this.isValidDicomTime(normalized)) {
|
||||||
|
callback(new Error(this.$t('trials:ptData:ruleMessage:number4')))//请输入有效时间(HHMMSS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
normalizeClinicalTime(value) {
|
||||||
|
if (value === undefined || value === null || value === '') return ''
|
||||||
|
const digits = String(value).trim().replace(/[^\d]/g, '')
|
||||||
|
if (!digits) return ''
|
||||||
|
return digits.slice(0, 6).padStart(6, '0')
|
||||||
|
},
|
||||||
|
isValidDicomTime(value) {
|
||||||
|
if (!/^\d{6}$/.test(String(value || ''))) return false
|
||||||
|
const normalized = String(value)
|
||||||
|
const hh = Number(normalized.slice(0, 2))
|
||||||
|
const mm = Number(normalized.slice(2, 4))
|
||||||
|
const ss = Number(normalized.slice(4, 6))
|
||||||
|
return hh >= 0 && hh <= 23 && mm >= 0 && mm <= 59 && ss >= 0 && ss <= 59
|
||||||
|
},
|
||||||
|
timeToSeconds(value) {
|
||||||
|
const normalized = this.normalizeClinicalTime(value)
|
||||||
|
if (!this.isValidDicomTime(normalized)) return null
|
||||||
|
const hh = Number(normalized.slice(0, 2))
|
||||||
|
const mm = Number(normalized.slice(2, 4))
|
||||||
|
const ss = Number(normalized.slice(4, 6))
|
||||||
|
return hh * 3600 + mm * 60 + ss
|
||||||
|
},
|
||||||
|
handleTimeBlur(field) {
|
||||||
|
const value = this.formData[field]
|
||||||
|
if (value === undefined || value === null || value === '') return
|
||||||
|
this.formData[field] = this.normalizeClinicalTime(value)
|
||||||
|
this.computeTimeRelation()
|
||||||
|
},
|
||||||
|
normalizeTimeFields() {
|
||||||
|
this.formData.RadiopharmaceuticalStartTime = this.normalizeClinicalTime(
|
||||||
|
this.formData.RadiopharmaceuticalStartTime
|
||||||
|
)
|
||||||
|
this.formData.AcquisitionTime = this.normalizeClinicalTime(
|
||||||
|
this.formData.AcquisitionTime
|
||||||
|
)
|
||||||
|
this.computeTimeRelation()
|
||||||
|
},
|
||||||
computeTimeRelation() {
|
computeTimeRelation() {
|
||||||
const startTime = this.formData.RadiopharmaceuticalStartTime
|
const startTime = this.formData.RadiopharmaceuticalStartTime
|
||||||
const acquireTime = this.formData.AcquisitionTime
|
const acquireTime = this.formData.AcquisitionTime
|
||||||
|
|
@ -829,7 +889,14 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startTime <= acquireTime) {
|
const startSeconds = this.timeToSeconds(startTime)
|
||||||
|
const acquireSeconds = this.timeToSeconds(acquireTime)
|
||||||
|
if (startSeconds === null || acquireSeconds === null) {
|
||||||
|
this.formData.TimeCheck = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startSeconds <= acquireSeconds) {
|
||||||
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val1') //注射时间 ≤ 成像时间
|
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val1') //注射时间 ≤ 成像时间
|
||||||
} else {
|
} else {
|
||||||
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val2') //注射时间 > 成像时间
|
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val2') //注射时间 > 成像时间
|
||||||
|
|
@ -847,8 +914,8 @@ export default {
|
||||||
PatientWeight: parseFloat(res.Result.PatientWeight) || null,
|
PatientWeight: parseFloat(res.Result.PatientWeight) || null,
|
||||||
RadionuclideTotalDose: parseFloat(res.Result.RadionuclideTotalDose) || null,
|
RadionuclideTotalDose: parseFloat(res.Result.RadionuclideTotalDose) || null,
|
||||||
RadionuclideHalfLife: parseFloat(res.Result.RadionuclideHalfLife) || null,
|
RadionuclideHalfLife: parseFloat(res.Result.RadionuclideHalfLife) || null,
|
||||||
RadiopharmaceuticalStartTime: parseFloat(res.Result.RadiopharmaceuticalStartTime) || '',
|
RadiopharmaceuticalStartTime: this.normalizeClinicalTime(res.Result.RadiopharmaceuticalStartTime),
|
||||||
AcquisitionTime: parseFloat(res.Result.AcquisitionTime) || '',
|
AcquisitionTime: this.normalizeClinicalTime(res.Result.AcquisitionTime),
|
||||||
TimeCheck: '',
|
TimeCheck: '',
|
||||||
Reason: res.Result.Reason
|
Reason: res.Result.Reason
|
||||||
}
|
}
|
||||||
|
|
@ -865,10 +932,12 @@ export default {
|
||||||
let valid = await this.$refs.patientForm.validate()
|
let valid = await this.$refs.patientForm.validate()
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
if (this.isAudit) {
|
if (this.isAudit) {
|
||||||
|
this.normalizeTimeFields()
|
||||||
const { CorrectImageExaminationInformation } = const_.processSignature
|
const { CorrectImageExaminationInformation } = const_.processSignature
|
||||||
this.signCode = CorrectImageExaminationInformation
|
this.signCode = CorrectImageExaminationInformation
|
||||||
this.signVisible = true
|
this.signVisible = true
|
||||||
} else {
|
} else {
|
||||||
|
this.normalizeTimeFields()
|
||||||
this.formLoading = true
|
this.formLoading = true
|
||||||
let res = await editPatientInfo(this.formData)
|
let res = await editPatientInfo(this.formData)
|
||||||
this.formLoading = false
|
this.formLoading = false
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,9 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 受试者中止状态 -->
|
<!-- 受试者中止状态 -->
|
||||||
<el-form-item style="margin-bottom: 10px" :label="$t('trials:crcUpload:table:IsSubjectQuit')">
|
<el-form-item style="margin-bottom: 10px" :label="$t('trials:crcUpload:table:IsSubjectQuit')">
|
||||||
<el-select v-model="searchData.IsSubjectQuit" clearable style="width: 120px">
|
<el-select v-model="searchData.SubjectStatus" clearable style="width: 120px">
|
||||||
<el-option v-for="item of $d.Subject_Visit_Status" :value="item.value" :label="item.label" :key="item.label" />
|
<el-option v-for="item of $d.Subject_Visit_Status" :value="item.value" :label="item.label"
|
||||||
|
:key="item.label" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 审核状态 -->
|
<!-- 审核状态 -->
|
||||||
|
|
@ -875,6 +876,7 @@ const searchDataDefault = () => {
|
||||||
SubmitState: null,
|
SubmitState: null,
|
||||||
ChallengeState: null,
|
ChallengeState: null,
|
||||||
IsSubjectQuit: "",
|
IsSubjectQuit: "",
|
||||||
|
SubjectStatus: null
|
||||||
// SortField: '',
|
// SortField: '',
|
||||||
// Asc: false
|
// Asc: false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
<!-- 上传时间 -->
|
<!-- 上传时间 -->
|
||||||
<el-table-column prop="UploadedTime" :label="$t('trials:audit:table:studyUploadTime')" min-width="80"
|
<el-table-column prop="UploadedTime" :label="$t('trials:audit:table:studyUploadTime')" min-width="80"
|
||||||
show-overflow-tooltip sortable />
|
show-overflow-tooltip sortable />
|
||||||
<el-table-column :label="$t('common:action:action')" min-width="100" fixed="right">
|
<el-table-column :label="$t('common:action:action')" min-width="100">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<!-- 预览 -->
|
<!-- 预览 -->
|
||||||
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
|
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<!--pet-ct临床数据预览-->
|
<!--pet-ct临床数据预览-->
|
||||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
<el-dialog v-if="petVisible" :close-on-click-modal="false" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" />
|
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -40,22 +40,30 @@
|
||||||
{{ $store.state.trials.uploadTip }}
|
{{ $store.state.trials.uploadTip }}
|
||||||
</div> -->
|
</div> -->
|
||||||
<el-tooltip v-if="
|
<el-tooltip v-if="
|
||||||
$store.state.trials.config.IsSupportQCDownloadImage &&
|
IsSupportQCDownloadImage &&
|
||||||
!hasPermi(['role:spm'])
|
!hasPermi(['role:spm'])
|
||||||
" :content="$t('trials:download:tip:message')" placement="top-end" effect="light">
|
" :content="$t('trials:download:tip:message')" placement="top-end" effect="light">
|
||||||
<i class="el-icon-warning-outline" style="font-size: 18px"></i>
|
<i class="el-icon-warning-outline" style="font-size: 18px"></i>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- 下载所有影像 -->
|
<!-- 下载所有影像 -->
|
||||||
<el-button v-if="
|
<el-button v-if="
|
||||||
$store.state.trials.config.IsSupportQCDownloadImage &&
|
IsSupportQCDownloadImage &&
|
||||||
!hasPermi(['role:spm'])
|
!hasPermi(['role:spm'])
|
||||||
" :loading="downloading" :disabled="selectTableDicom.length <= 0" size="small" type="primary"
|
" :loading="downloading" :disabled="selectTableDicom.length <= 0" size="small" type="primary"
|
||||||
style="margin-left: 10px" @click="getCRCUploadedStudyInfo('dicom')">
|
style="margin-left: 10px" @click="getCRCUploadedStudyInfo('dicom')">
|
||||||
{{ $t('trials:audit:button:downLoadAllDiocms') }}
|
{{ $t('trials:audit:button:downLoadAllDiocms') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<!-- 下载阅片影像 -->
|
||||||
|
<el-button v-if="
|
||||||
|
IsSupportQCDownloadImage &&
|
||||||
|
!hasPermi(['role:spm'])
|
||||||
|
" :loading="downloading" :disabled="selectTableDicom.length <= 0" size="small" type="primary"
|
||||||
|
style="margin-left: 10px" @click="getCRCUploadedStudyInfo('dicom', true)">
|
||||||
|
{{ $t('trials:audit:button:downLoadReadingDiocms') }}
|
||||||
|
</el-button>
|
||||||
<!-- 下载工具 -->
|
<!-- 下载工具 -->
|
||||||
<el-button v-if="
|
<el-button v-if="
|
||||||
$store.state.trials.config.IsSupportQCDownloadImage &&
|
IsSupportQCDownloadImage &&
|
||||||
!hasPermi(['role:spm'])
|
!hasPermi(['role:spm'])
|
||||||
" :loading="downloading" size="small" type="primary" style="margin-left: 10px"
|
" :loading="downloading" size="small" type="primary" style="margin-left: 10px"
|
||||||
@click="getCRCUploadedStudyInfo('tools')">
|
@click="getCRCUploadedStudyInfo('tools')">
|
||||||
|
|
@ -73,15 +81,13 @@
|
||||||
<el-table :data="studyList" :row-class-name="tableRowClassName"
|
<el-table :data="studyList" :row-class-name="tableRowClassName"
|
||||||
@selection-change="handleSelectionChangeDicom"
|
@selection-change="handleSelectionChangeDicom"
|
||||||
:default-sort="{ prop: 'UploadedTime', order: 'ascending' }">
|
:default-sort="{ prop: 'UploadedTime', order: 'ascending' }">
|
||||||
<el-table-column type="selection" width="55" v-if='$store.state.trials.config.IsSupportQCDownloadImage'>
|
<el-table-column type="selection" width="55" v-if='IsSupportQCDownloadImage'>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 检查编号 -->
|
<!-- 检查编号 -->
|
||||||
<el-table-column prop="StudyCode" :label="$t('trials:audit:table:studyId')" sortable>
|
<el-table-column prop="StudyCode" :label="$t('trials:audit:table:studyId')" sortable>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tooltip
|
<el-tooltip placement="top"
|
||||||
placement="top"
|
v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(scope.row.Modalities) && IsHaveStudyClinicalData && scope.row.IsHasEmptyPatientInfo">
|
||||||
v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(scope.row.Modalities) && IsHaveStudyClinicalData && scope.row.IsHasEmptyPatientInfo"
|
|
||||||
>
|
|
||||||
<div slot="content">{{ $t('trials:audit:message:ptDataValid') }}</div>
|
<div slot="content">{{ $t('trials:audit:message:ptDataValid') }}</div>
|
||||||
<span class="el-icon-warning" style="color: red; cursor: pointer"></span>
|
<span class="el-icon-warning" style="color: red; cursor: pointer"></span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
@ -158,12 +164,11 @@
|
||||||
:disabled="isAudit || scope.row.IsDeleted || SecondReviewState > 0"
|
:disabled="isAudit || scope.row.IsDeleted || SecondReviewState > 0"
|
||||||
@click="handleEditStudy(scope.row)" />
|
@click="handleEditStudy(scope.row)" />
|
||||||
<!-- 预览PET-CT数据 -->
|
<!-- 预览PET-CT数据 -->
|
||||||
<el-button icon="el-icon-document" :title="$t('trials:audit:tab:clinicalData')"
|
<el-button icon="el-icon-document" :title="$t('trials:audit:tab:clinicalData')" v-if="
|
||||||
v-if="
|
['PT、CT', 'CT、PT', 'PET-CT'].includes(
|
||||||
['PT、CT', 'CT、PT', 'PET-CT'].includes(
|
scope.row.Modalities
|
||||||
scope.row.Modalities
|
) && IsHaveStudyClinicalData
|
||||||
) && IsHaveStudyClinicalData
|
" circle :disabled="scope.row.IsDeleted" @click="handlePreviewClinicalData(scope.row)" />
|
||||||
" circle :disabled="scope.row.IsDeleted" @click="handlePreviewClinicalData(scope.row)" />
|
|
||||||
<!-- 质控后编辑 -->
|
<!-- 质控后编辑 -->
|
||||||
<el-button icon="el-icon-edit" :title="$t('trials:audit:action:Correction')" circle
|
<el-button icon="el-icon-edit" :title="$t('trials:audit:action:Correction')" circle
|
||||||
v-if="isAuditToEdit" @click="handleEditStudy(scope.row)" />
|
v-if="isAuditToEdit" @click="handleEditStudy(scope.row)" />
|
||||||
|
|
@ -257,19 +262,27 @@
|
||||||
{{ $store.state.trials.uploadTip }}
|
{{ $store.state.trials.uploadTip }}
|
||||||
</div> -->
|
</div> -->
|
||||||
<el-tooltip v-if="
|
<el-tooltip v-if="
|
||||||
$store.state.trials.config.IsSupportQCDownloadImage &&
|
IsSupportQCDownloadImage &&
|
||||||
!hasPermi(['role:spm'])
|
!hasPermi(['role:spm'])
|
||||||
" :content="$t('trials:download:tip:message')" placement="top-end" effect="light">
|
" :content="$t('trials:download:tip:message')" placement="top-end" effect="light">
|
||||||
<i class="el-icon-warning-outline" style="font-size: 18px"></i>
|
<i class="el-icon-warning-outline" style="font-size: 18px"></i>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- 下载所有影像 -->
|
<!-- 下载所有影像 -->
|
||||||
<el-button v-if="
|
<el-button v-if="
|
||||||
$store.state.trials.config.IsSupportQCDownloadImage &&
|
IsSupportQCDownloadImage &&
|
||||||
!hasPermi(['role:spm'])
|
!hasPermi(['role:spm'])
|
||||||
" :loading="downloading" :disabled="selectTableNonedicom.length <= 0" size="small" type="primary"
|
" :loading="downloading" :disabled="selectTableNonedicom.length <= 0" size="small" type="primary"
|
||||||
style="margin-left: 10px" @click="getCRCUploadedStudyInfo('noneDicom')">
|
style="margin-left: 10px" @click="getCRCUploadedStudyInfo('noneDicom')">
|
||||||
{{ $t('trials:audit:button:downLoadAllNonDiocms') }}
|
{{ $t('trials:audit:button:downLoadAllNonDiocms') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<!-- 下载阅片影像 -->
|
||||||
|
<el-button v-if="
|
||||||
|
IsSupportQCDownloadImage &&
|
||||||
|
!hasPermi(['role:spm'])
|
||||||
|
" :loading="downloading" :disabled="selectTableNonedicom.length <= 0" size="small" type="primary"
|
||||||
|
style="margin-left: 10px" @click="getCRCUploadedStudyInfo('noneDicom', true)">
|
||||||
|
{{ $t('trials:audit:button:downLoadReadingNonDiocms') }}
|
||||||
|
</el-button>
|
||||||
<!-- 预览 -->
|
<!-- 预览 -->
|
||||||
<el-button size="small" :disabled="noneDicomStudyList.length === 0" type="primary"
|
<el-button size="small" :disabled="noneDicomStudyList.length === 0" type="primary"
|
||||||
style="margin-left: 10px" @click="handleViewAllNoneDicoms(false)">
|
style="margin-left: 10px" @click="handleViewAllNoneDicoms(false)">
|
||||||
|
|
@ -283,7 +296,7 @@
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="noneDicomStudyList" @selection-change="handleSelectionChangeNonedicom"
|
<el-table :data="noneDicomStudyList" @selection-change="handleSelectionChangeNonedicom"
|
||||||
:row-class-name="tableRowClassName" :default-sort="{ prop: 'CreateTime', order: 'ascending' }">
|
:row-class-name="tableRowClassName" :default-sort="{ prop: 'CreateTime', order: 'ascending' }">
|
||||||
<el-table-column type="selection" width="55" v-if='$store.state.trials.config.IsSupportQCDownloadImage'>
|
<el-table-column type="selection" width="55" v-if='IsSupportQCDownloadImage'>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- 检查编号 -->
|
<!-- 检查编号 -->
|
||||||
<el-table-column prop="CodeView" :label="$t('trials:audit:table:nonDicomsStudyId')" sortable />
|
<el-table-column prop="CodeView" :label="$t('trials:audit:table:nonDicomsStudyId')" sortable />
|
||||||
|
|
@ -910,8 +923,7 @@
|
||||||
{{ $t('trials:audit:button:auditPassed') }}
|
{{ $t('trials:audit:button:auditPassed') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 跳过 -->
|
<!-- 跳过 -->
|
||||||
<el-button size="small" type="primary" round
|
<el-button size="small" type="primary" round @click="skipTask">
|
||||||
@click="skipTask">
|
|
||||||
{{ $t('trials:audit:button:skipTask') }}
|
{{ $t('trials:audit:button:skipTask') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 审核终止 -->
|
<!-- 审核终止 -->
|
||||||
|
|
@ -920,8 +932,11 @@
|
||||||
<!-- </el-button>-->
|
<!-- </el-button>-->
|
||||||
</div>
|
</div>
|
||||||
<!--petct临床数据预览-->
|
<!--petct临床数据预览-->
|
||||||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
<el-dialog v-if="petVisible" :close-on-click-modal="false" :show-close="true" :visible.sync="petVisible"
|
||||||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false" :isPatientFormAllowEdit="isAuditToEdit" :isAudit="isAuditToEdit" @close="petVisible = false"/>
|
append-to-body>
|
||||||
|
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="rowData" :allow-add-or-edit="false"
|
||||||
|
:isPatientFormAllowEdit="!isAudit || SecondReviewState > 0 || isAuditToEdit" :isAudit="isAuditToEdit"
|
||||||
|
@close="petVisible = false" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1117,7 +1132,8 @@ export default {
|
||||||
IsSecondPass: false,
|
IsSecondPass: false,
|
||||||
userId: zzSessionStorage.getItem('userId'),
|
userId: zzSessionStorage.getItem('userId'),
|
||||||
|
|
||||||
QCRiskControl: false
|
QCRiskControl: false,
|
||||||
|
IsSupportQCDownloadImage: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
|
@ -1153,13 +1169,14 @@ export default {
|
||||||
this.selectTableNonedicom = val
|
this.selectTableNonedicom = val
|
||||||
},
|
},
|
||||||
// 获取下载文件信息
|
// 获取下载文件信息
|
||||||
async getCRCUploadedStudyInfo(type) {
|
async getCRCUploadedStudyInfo(type, isReading = null) {
|
||||||
if (this.downloading) return
|
if (this.downloading) return
|
||||||
try {
|
try {
|
||||||
let data = {
|
let data = {
|
||||||
SubjectVisitId: this.data.Id,
|
SubjectVisitId: this.data.Id,
|
||||||
NoneDicomStudyIdList: [],
|
NoneDicomStudyIdList: [],
|
||||||
DicomStudyIdList: [],
|
DicomStudyIdList: [],
|
||||||
|
IsExportReading: isReading
|
||||||
}
|
}
|
||||||
if (type === 'tools') {
|
if (type === 'tools') {
|
||||||
return this.handleDownload()
|
return this.handleDownload()
|
||||||
|
|
@ -1324,6 +1341,7 @@ export default {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
getVisitQCInfo(this.data.Id, this.data.QCProcessEnum, this.currentQCType)
|
getVisitQCInfo(this.data.Id, this.data.QCProcessEnum, this.currentQCType)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
this.IsSupportQCDownloadImage = res.Result.IsSupportQCDownloadImage
|
||||||
this.secondReviewList = res.Result.SecondReviewList
|
this.secondReviewList = res.Result.SecondReviewList
|
||||||
if (this.secondReviewList.length > 0) {
|
if (this.secondReviewList.length > 0) {
|
||||||
let data = this.secondReviewList.find(item => item.SignTime) || {}
|
let data = this.secondReviewList.find(item => item.SignTime) || {}
|
||||||
|
|
@ -2176,7 +2194,7 @@ export default {
|
||||||
if (confirm !== 'confirm') return
|
if (confirm !== 'confirm') return
|
||||||
this.$emit('close')
|
this.$emit('close')
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
this.$emit('getList')
|
this.$emit('getList')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue