Merge branch 'ID1825-床旁副屏改版' into test
| | |
| | | "@vant/icons": "^3.0.2", |
| | | "@zxing/library": "^0.21.3", |
| | | "axios": "^1.9.0", |
| | | "dayjs": "^1.11.13", |
| | | "echarts": "^5.6.0", |
| | | "element-plus": "^2.9.2", |
| | | "event-source-polyfill": "^1.0.31", |
| | | "pinia": "^3.0.3", |
| | | "qs": "^6.14.0", |
| | | "speak-tts": "^2.0.8", |
| | | "vant": "^3.4.3", |
| | |
| | | "@vitejs/plugin-vue": "^5.2.1", |
| | | "@vue/compiler-sfc": "^3.5.13", |
| | | "@vue/tsconfig": "^0.7.0", |
| | | "amfe-flexible": "^2.2.1", |
| | | "install": "^0.13.0", |
| | | "less": "^4.2.1", |
| | | "npm": "^11.4.2", |
| | | "postcss-pxtorem": "^6.1.0", |
| | | "typescript": "~5.6.2", |
| | | "vite": "^6.0.5", |
| | | "vue-tsc": "^2.2.0" |
| | |
| | | "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/@vue/devtools-kit": { |
| | | "version": "7.7.7", |
| | | "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", |
| | | "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", |
| | | "license": "MIT", |
| | | "dependencies": { |
| | | "@vue/devtools-shared": "^7.7.7", |
| | | "birpc": "^2.3.0", |
| | | "hookable": "^5.5.3", |
| | | "mitt": "^3.0.1", |
| | | "perfect-debounce": "^1.0.0", |
| | | "speakingurl": "^14.0.1", |
| | | "superjson": "^2.2.2" |
| | | } |
| | | }, |
| | | "node_modules/@vue/devtools-shared": { |
| | | "version": "7.7.7", |
| | | "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", |
| | | "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", |
| | | "license": "MIT", |
| | | "dependencies": { |
| | | "rfdc": "^1.4.1" |
| | | } |
| | | }, |
| | | "node_modules/@vue/language-core": { |
| | | "version": "2.2.0", |
| | | "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.0.tgz", |
| | |
| | | "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/amfe-flexible": { |
| | | "version": "2.2.1", |
| | | "resolved": "https://registry.npmjs.org/amfe-flexible/-/amfe-flexible-2.2.1.tgz", |
| | | "integrity": "sha512-L2VfvDzoETBjhRptg5u/IUuzHSuxm22JpSRb404p/TBGeRfwWmmNEbB+TFPIP/sS/+pbM18bCFH9QnMojLuPNw==", |
| | | "dev": true, |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/async-validator": { |
| | | "version": "4.2.5", |
| | | "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", |
| | |
| | | "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", |
| | | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/birpc": { |
| | | "version": "2.4.0", |
| | | "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.4.0.tgz", |
| | | "integrity": "sha512-5IdNxTyhXHv2UlgnPHQ0h+5ypVmkrYHzL8QT+DwFZ//2N/oNV8Ch+BCRmTJ3x6/z9Axo/cXYBc9eprsUVK/Jsg==", |
| | | "license": "MIT", |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/antfu" |
| | | } |
| | | }, |
| | | "node_modules/brace-expansion": { |
| | | "version": "2.0.1", |
| | |
| | | }, |
| | | "node_modules/dayjs": { |
| | | "version": "1.11.13", |
| | | "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", |
| | | "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", |
| | | "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", |
| | | "license": "MIT" |
| | | }, |
| | |
| | | "he": "bin/he" |
| | | } |
| | | }, |
| | | "node_modules/hookable": { |
| | | "version": "5.5.3", |
| | | "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", |
| | | "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/iconv-lite": { |
| | | "version": "0.6.3", |
| | | "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", |
| | |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/isaacs" |
| | | } |
| | | }, |
| | | "node_modules/mitt": { |
| | | "version": "3.0.1", |
| | | "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", |
| | | "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/muggle-string": { |
| | | "version": "0.4.1", |
| | |
| | | "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/perfect-debounce": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", |
| | | "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/picocolors": { |
| | | "version": "1.1.1", |
| | | "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", |
| | |
| | | "optional": true, |
| | | "engines": { |
| | | "node": ">=6" |
| | | } |
| | | }, |
| | | "node_modules/pinia": { |
| | | "version": "3.0.3", |
| | | "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz", |
| | | "integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==", |
| | | "license": "MIT", |
| | | "dependencies": { |
| | | "@vue/devtools-api": "^7.7.2" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/posva" |
| | | }, |
| | | "peerDependencies": { |
| | | "typescript": ">=4.4.4", |
| | | "vue": "^2.7.0 || ^3.5.11" |
| | | }, |
| | | "peerDependenciesMeta": { |
| | | "typescript": { |
| | | "optional": true |
| | | } |
| | | } |
| | | }, |
| | | "node_modules/pinia/node_modules/@vue/devtools-api": { |
| | | "version": "7.7.7", |
| | | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz", |
| | | "integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==", |
| | | "license": "MIT", |
| | | "dependencies": { |
| | | "@vue/devtools-kit": "^7.7.7" |
| | | } |
| | | }, |
| | | "node_modules/postcss": { |
| | |
| | | }, |
| | | "engines": { |
| | | "node": "^10 || ^12 || >=14" |
| | | } |
| | | }, |
| | | "node_modules/postcss-pxtorem": { |
| | | "version": "6.1.0", |
| | | "resolved": "https://registry.npmjs.org/postcss-pxtorem/-/postcss-pxtorem-6.1.0.tgz", |
| | | "integrity": "sha512-ROODSNci9ADal3zUcPHOF/K83TiCgNSPXQFSbwyPHNV8ioHIE4SaC+FPOufd8jsr5jV2uIz29v1Uqy1c4ov42g==", |
| | | "dev": true, |
| | | "license": "MIT", |
| | | "peerDependencies": { |
| | | "postcss": "^8.0.0" |
| | | } |
| | | }, |
| | | "node_modules/proxy-from-env": { |
| | |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/ljharb" |
| | | } |
| | | }, |
| | | "node_modules/rfdc": { |
| | | "version": "1.4.1", |
| | | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", |
| | | "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/rollup": { |
| | | "version": "4.30.1", |
| | |
| | | "resolved": "https://registry.npmmirror.com/speak-tts/-/speak-tts-2.0.8.tgz", |
| | | "integrity": "sha512-VY6Q6mRjdou6bF+x0LspvM7GJhBxHx8CLyGPTNQQ7jrztiGutyI4QNZn0cA17c4uk0FnFbA4PaMI3skeZ6PiFg==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/speakingurl": { |
| | | "version": "14.0.1", |
| | | "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", |
| | | "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", |
| | | "license": "BSD-3-Clause", |
| | | "engines": { |
| | | "node": ">=0.10.0" |
| | | } |
| | | }, |
| | | "node_modules/superjson": { |
| | | "version": "2.2.2", |
| | | "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", |
| | | "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", |
| | | "license": "MIT", |
| | | "dependencies": { |
| | | "copy-anything": "^3.0.2" |
| | | }, |
| | | "engines": { |
| | | "node": ">=16" |
| | | } |
| | | }, |
| | | "node_modules/superjson/node_modules/copy-anything": { |
| | | "version": "3.0.5", |
| | | "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", |
| | | "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", |
| | | "license": "MIT", |
| | | "dependencies": { |
| | | "is-what": "^4.1.8" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12.13" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/mesqueeb" |
| | | } |
| | | }, |
| | | "node_modules/superjson/node_modules/is-what": { |
| | | "version": "4.1.16", |
| | | "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", |
| | | "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", |
| | | "license": "MIT", |
| | | "engines": { |
| | | "node": ">=12.13" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/mesqueeb" |
| | | } |
| | | }, |
| | | "node_modules/terser": { |
| | | "version": "5.43.1", |
| | |
| | | "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", |
| | | "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" |
| | | }, |
| | | "@vue/devtools-kit": { |
| | | "version": "7.7.7", |
| | | "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", |
| | | "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", |
| | | "requires": { |
| | | "@vue/devtools-shared": "^7.7.7", |
| | | "birpc": "^2.3.0", |
| | | "hookable": "^5.5.3", |
| | | "mitt": "^3.0.1", |
| | | "perfect-debounce": "^1.0.0", |
| | | "speakingurl": "^14.0.1", |
| | | "superjson": "^2.2.2" |
| | | } |
| | | }, |
| | | "@vue/devtools-shared": { |
| | | "version": "7.7.7", |
| | | "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", |
| | | "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", |
| | | "requires": { |
| | | "rfdc": "^1.4.1" |
| | | } |
| | | }, |
| | | "@vue/language-core": { |
| | | "version": "2.2.0", |
| | | "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.0.tgz", |
| | |
| | | "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", |
| | | "dev": true |
| | | }, |
| | | "amfe-flexible": { |
| | | "version": "2.2.1", |
| | | "resolved": "https://registry.npmjs.org/amfe-flexible/-/amfe-flexible-2.2.1.tgz", |
| | | "integrity": "sha512-L2VfvDzoETBjhRptg5u/IUuzHSuxm22JpSRb404p/TBGeRfwWmmNEbB+TFPIP/sS/+pbM18bCFH9QnMojLuPNw==", |
| | | "dev": true |
| | | }, |
| | | "async-validator": { |
| | | "version": "4.2.5", |
| | | "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", |
| | |
| | | "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", |
| | | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", |
| | | "dev": true |
| | | }, |
| | | "birpc": { |
| | | "version": "2.4.0", |
| | | "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.4.0.tgz", |
| | | "integrity": "sha512-5IdNxTyhXHv2UlgnPHQ0h+5ypVmkrYHzL8QT+DwFZ//2N/oNV8Ch+BCRmTJ3x6/z9Axo/cXYBc9eprsUVK/Jsg==" |
| | | }, |
| | | "brace-expansion": { |
| | | "version": "2.0.1", |
| | |
| | | }, |
| | | "dayjs": { |
| | | "version": "1.11.13", |
| | | "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", |
| | | "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", |
| | | "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" |
| | | }, |
| | | "de-indent": { |
| | |
| | | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", |
| | | "dev": true |
| | | }, |
| | | "hookable": { |
| | | "version": "5.5.3", |
| | | "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", |
| | | "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" |
| | | }, |
| | | "iconv-lite": { |
| | | "version": "0.6.3", |
| | | "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", |
| | |
| | | "requires": { |
| | | "brace-expansion": "^2.0.1" |
| | | } |
| | | }, |
| | | "mitt": { |
| | | "version": "3.0.1", |
| | | "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", |
| | | "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" |
| | | }, |
| | | "muggle-string": { |
| | | "version": "0.4.1", |
| | |
| | | "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", |
| | | "dev": true |
| | | }, |
| | | "perfect-debounce": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", |
| | | "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" |
| | | }, |
| | | "picocolors": { |
| | | "version": "1.1.1", |
| | | "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", |
| | |
| | | "dev": true, |
| | | "optional": true |
| | | }, |
| | | "pinia": { |
| | | "version": "3.0.3", |
| | | "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz", |
| | | "integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==", |
| | | "requires": { |
| | | "@vue/devtools-api": "^7.7.2" |
| | | }, |
| | | "dependencies": { |
| | | "@vue/devtools-api": { |
| | | "version": "7.7.7", |
| | | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz", |
| | | "integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==", |
| | | "requires": { |
| | | "@vue/devtools-kit": "^7.7.7" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | "postcss": { |
| | | "version": "8.4.49", |
| | | "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz", |
| | |
| | | "picocolors": "^1.1.1", |
| | | "source-map-js": "^1.2.1" |
| | | } |
| | | }, |
| | | "postcss-pxtorem": { |
| | | "version": "6.1.0", |
| | | "resolved": "https://registry.npmjs.org/postcss-pxtorem/-/postcss-pxtorem-6.1.0.tgz", |
| | | "integrity": "sha512-ROODSNci9ADal3zUcPHOF/K83TiCgNSPXQFSbwyPHNV8ioHIE4SaC+FPOufd8jsr5jV2uIz29v1Uqy1c4ov42g==", |
| | | "dev": true, |
| | | "requires": {} |
| | | }, |
| | | "proxy-from-env": { |
| | | "version": "1.1.0", |
| | |
| | | "requires": { |
| | | "side-channel": "^1.1.0" |
| | | } |
| | | }, |
| | | "rfdc": { |
| | | "version": "1.4.1", |
| | | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", |
| | | "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" |
| | | }, |
| | | "rollup": { |
| | | "version": "4.30.1", |
| | |
| | | "resolved": "https://registry.npmmirror.com/speak-tts/-/speak-tts-2.0.8.tgz", |
| | | "integrity": "sha512-VY6Q6mRjdou6bF+x0LspvM7GJhBxHx8CLyGPTNQQ7jrztiGutyI4QNZn0cA17c4uk0FnFbA4PaMI3skeZ6PiFg==" |
| | | }, |
| | | "speakingurl": { |
| | | "version": "14.0.1", |
| | | "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", |
| | | "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==" |
| | | }, |
| | | "superjson": { |
| | | "version": "2.2.2", |
| | | "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", |
| | | "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", |
| | | "requires": { |
| | | "copy-anything": "^3.0.2" |
| | | }, |
| | | "dependencies": { |
| | | "copy-anything": { |
| | | "version": "3.0.5", |
| | | "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", |
| | | "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", |
| | | "requires": { |
| | | "is-what": "^4.1.8" |
| | | } |
| | | }, |
| | | "is-what": { |
| | | "version": "4.1.16", |
| | | "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", |
| | | "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==" |
| | | } |
| | | } |
| | | }, |
| | | "terser": { |
| | | "version": "5.43.1", |
| | | "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", |
| | |
| | | "name": "my-project", |
| | | "private": true, |
| | | "version": "0.0.0", |
| | | "type": "module", |
| | | "scripts": { |
| | | "dev": "vite", |
| | | "dev:prod": "vite --mode production", |
| | |
| | | "@vant/icons": "^3.0.2", |
| | | "@zxing/library": "^0.21.3", |
| | | "axios": "^1.9.0", |
| | | "dayjs": "^1.11.13", |
| | | "echarts": "^5.6.0", |
| | | "element-plus": "^2.9.2", |
| | | "event-source-polyfill": "^1.0.31", |
| | | "pinia": "^3.0.3", |
| | | "qs": "^6.14.0", |
| | | "speak-tts": "^2.0.8", |
| | | "vant": "^3.4.3", |
| | |
| | | "@vitejs/plugin-vue": "^5.2.1", |
| | | "@vue/compiler-sfc": "^3.5.13", |
| | | "@vue/tsconfig": "^0.7.0", |
| | | "amfe-flexible": "^2.2.1", |
| | | "install": "^0.13.0", |
| | | "less": "^4.2.1", |
| | | "npm": "^11.4.2", |
| | | "postcss-pxtorem": "^6.1.0", |
| | | "typescript": "~5.6.2", |
| | | "vite": "^6.0.5", |
| | | "vue-tsc": "^2.2.0" |
| New file |
| | |
| | | module.exports = { |
| | | plugins: { |
| | | 'postcss-pxtorem': { |
| | | rootValue: 37.5, |
| | | propList: ['*'], |
| | | // include: file => { |
| | | // if (!file) return false; |
| | | // const normalized = file.replace(/\\/g, '/'); |
| | | // // 只转换 mobile 目录里的样式 OR element-plus 目录里的样式 |
| | | // // 但 element-plus 样式只在 mobile 目录被引用时才生效,需保证引用范围 |
| | | // return normalized.includes('/src/views/mobile/') || normalized.includes('/node_modules/element-plus/'); |
| | | // }, |
| | | // exclude: file => { |
| | | // if (!file) return false; |
| | | // const normalized = file.replace(/\\/g, '/'); |
| | | // // 排除除 element-plus 外的 node_modules,防止无关样式被转 |
| | | // if (/node_modules/.test(normalized) && !normalized.includes('/node_modules/element-plus/')) { |
| | | // return true; |
| | | // } |
| | | // return false; |
| | | // }, |
| | | minPixelValue: 2, |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | import { ref, onMounted, onUnmounted } from 'vue'; |
| | | |
| | | export function useWindowSize() { |
| | | const width = ref(window.innerWidth); |
| | | const height = ref(window.innerHeight); |
| | | |
| | | const updateSize = () => { |
| | | width.value = window.innerWidth; |
| | | height.value = window.innerHeight; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | window.addEventListener('resize', updateSize); |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | window.removeEventListener('resize', updateSize); |
| | | }); |
| | | |
| | | return { width, height }; |
| | | } |
| | |
| | | import 'amfe-flexible'; |
| | | import { createApp } from 'vue' |
| | | import ElementPlus from 'element-plus' |
| | | import 'element-plus/dist/index.css' |
| | |
| | | import router from './router'; |
| | | import App from './App.vue' |
| | | import VConsole from 'vconsole' |
| | | import { createPinia } from 'pinia' |
| | | |
| | | if (import.meta.env.VITE_ENV === 'development') { |
| | | // 如果需要在手机平板上打开控制台,安装一个这个 |
| | | const vConsole = new VConsole() |
| | | } |
| | | const pinia = createPinia() |
| | | |
| | | |
| | | createApp(App).use(router).use(ElementPlus).use(Vant).mount('#app') |
| | | createApp(App).use(router).use(pinia).use(ElementPlus).use(Vant).mount('#app') |
| | |
| | | // router/index.ts |
| | | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; |
| | | import Home from '../views/Home.vue'; // 假设这是你的主页组件 |
| | | import deviceWindows from '../views/deviceWindows.vue' |
| | | // import Home from '../views/Home.vue'; // 假设这是你的主页组件 |
| | | // import deviceWindows from '../views/deviceWindows.vue' |
| | | import deviceWindows2 from '../views/deviceWindoes2.vue' |
| | | import test from '../views/test.vue'; // 搜索结果页,接收查询参数 |
| | | import registerForNutrition from '../views/register/index.vue' |
| | | import registerSuu from '../views/registerSuu/index.vue' |
| | | import bedsideAuxiliaryScreen from '../views/mobile/bedsideAuxiliaryScreen/index.vue'; |
| | | |
| | | // 定义路由规则,并为每个路由指定类型安全的 props |
| | | const routes: Array<RouteRecordRaw> = [ |
| | | { |
| | | path: '/', |
| | | name: 'Home', |
| | | component: bedsideAuxiliaryScreen, |
| | | }, |
| | | { |
| | | path: '/test2', |
| | | name: 'test2', |
| | | component: deviceWindows2, |
| | | }, |
| | | { |
| New file |
| | |
| | | import { defineStore } from "pinia"; |
| | | import { ref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import cache from "../utils/cache"; |
| | | import { EventSourcePolyfill } from "event-source-polyfill"; |
| | | import type { BedsideAuxiliaryScreen, SseMsgData } from "./type/bedsideAuxiliaryScreen.type"; |
| | | import type { Task } from "./type/task.type"; |
| | | import { |
| | | defaultDeviceData, |
| | | defaultconsumablesCollection, |
| | | formatDeviceData, |
| | | } from "./type/bedsideAuxiliaryScreen.type"; |
| | | import { ElMessage } from "element-plus/es"; |
| | | |
| | | export const useBedsideAuxiliaryScreenStore = defineStore( |
| | | "bedsideAuxiliaryScreen", |
| | | () => { |
| | | /** 设备编号 */ |
| | | const deviceCode = ref<string>(cache.get("devcieCode") || ""); |
| | | |
| | | /** 设备信息数据 */ |
| | | const deviceData = ref<BedsideAuxiliaryScreen>(defaultDeviceData()); |
| | | |
| | | /** 任务列表 */ |
| | | const taskData = ref<Task[]>([]); |
| | | |
| | | /** |
| | | * 设置设备编号 |
| | | * @param code |
| | | */ |
| | | const setDeviceCode = (code: string) => { |
| | | deviceCode.value = code; |
| | | cache.set("devcieCode", code); |
| | | }; |
| | | |
| | | /** |
| | | * 清除设备信息 |
| | | */ |
| | | const clearDevice = () => { |
| | | deviceData.value = defaultDeviceData(); |
| | | }; |
| | | |
| | | /** |
| | | * 追加定时任务 |
| | | * @param taskItem |
| | | */ |
| | | const pushTask = (taskItem: Task) => { |
| | | taskData.value.push(taskItem); |
| | | }; |
| | | |
| | | /** |
| | | * 是否将当前任务设置为已过期 |
| | | * @param i |
| | | */ |
| | | // const deleteTask = (i: number) => { |
| | | // const task = taskData.value[i]; |
| | | // if (task) { |
| | | // // 二次判断,判断任务时间是否早于或等于当前时间 |
| | | // const taskTime = dayjs(task.taskDate).second(0).millisecond(0); |
| | | // const now = dayjs().second(0).millisecond(0); // 秒和毫秒都去掉 |
| | | // if (!taskTime.isAfter(now)) { |
| | | // taskData.value[i].overdue = true |
| | | // } |
| | | // } |
| | | // }; |
| | | |
| | | /** 设置当前定时任务 */ |
| | | const setSyncTask = (taskItem: Task) => { |
| | | taskData.value = [taskItem]; |
| | | }; |
| | | |
| | | /** 清除当前定时任务 */ |
| | | const clearTask = () => { |
| | | taskData.value = []; |
| | | }; |
| | | |
| | | // SSE 相关状态 |
| | | const source = ref<EventSource | null>(null); |
| | | const message = ref<string | null>(null); |
| | | const isConnected = ref(false); |
| | | |
| | | // 重连控制 |
| | | let retryCount = 0; |
| | | const maxRetryCount = 60; |
| | | const baseRetryDelay = 1000; // 1秒开始重连延迟 |
| | | |
| | | /** |
| | | * 连接 SSE 服务 |
| | | * @param url SSE 地址 |
| | | */ |
| | | const connect = (url: string) => { |
| | | if (source.value) return; // 已连接,避免重复连接 |
| | | ElMessage.success("正在连接设备,请稍候..."); |
| | | |
| | | source.value = new EventSourcePolyfill(url, { |
| | | heartbeatTimeout: 60000, |
| | | }); |
| | | |
| | | source.value.onopen = () => { |
| | | console.log("[SSE] 连接成功"); |
| | | ElMessage.success("链接服务成功"); |
| | | isConnected.value = true; |
| | | retryCount = 0; // 成功连接后重置重试计数 |
| | | }; |
| | | |
| | | source.value.onerror = (e) => { |
| | | console.warn("[SSE] 错误,等待重连中", e); |
| | | isConnected.value = false; |
| | | close(); // 关闭旧连接,避免残留 |
| | | if (retryCount < maxRetryCount) { |
| | | const delay = baseRetryDelay * Math.pow(2, retryCount); // 指数退避 |
| | | retryCount++; |
| | | console.log(`[SSE] 第${retryCount}次重连,延迟${delay}ms`); |
| | | ElMessage.warning( |
| | | `链接服务失败, 第${retryCount}次重连,请耐心等待重连。。` |
| | | ); |
| | | setTimeout(() => { |
| | | connect(url); |
| | | }, delay); |
| | | } else { |
| | | console.error("[SSE] 重连次数达到上限,停止重连"); |
| | | ElMessage.error("重连次数达到上限,请检查网络或设备状态"); |
| | | } |
| | | }; |
| | | |
| | | source.value.onmessage = (e) => { |
| | | console.log("[SSE] 消息:", e.data); |
| | | const msg = e.data; |
| | | let dif = msg.indexOf("event:message"); |
| | | let beng = msg.indexOf("{"); |
| | | let end = msg.length - 1; |
| | | if (beng !== -1 && end !== -1 && dif !== -1) { |
| | | const datax = msg.slice(beng, end + 1); |
| | | const dataBody = JSON.parse(datax) as SseMsgData; |
| | | console.log("dataBody: ", dataBody); |
| | | // 倒计时提示文本 |
| | | if (dataBody.倒计时?.提醒文本) { |
| | | const taskTime = dayjs(dataBody.倒计时?.当前服务器时间).add(dataBody.倒计时?.设定提醒倒计时, 'minute') |
| | | setSyncTask({ |
| | | deviceCode: dataBody.IOT信息.设备唯一编号, |
| | | recordCode: dataBody.透析状态?.透析单编号, |
| | | taskDate: taskTime.format('YYYY-MM-DD HH:mm'), |
| | | taskName: dataBody.倒计时?.提醒文本, |
| | | overdue: false, |
| | | countdown: dataBody.倒计时?.设定提醒倒计时 |
| | | }) |
| | | } else { |
| | | clearTask(); |
| | | } |
| | | |
| | | deviceData.value = formatDeviceData(dataBody); |
| | | } |
| | | }; |
| | | }; |
| | | |
| | | /** |
| | | * 关闭 SSE 连接 |
| | | */ |
| | | const close = () => { |
| | | if (source.value) { |
| | | source.value.close(); |
| | | source.value = null; |
| | | isConnected.value = false; |
| | | clearDevice(); |
| | | clearTask(); |
| | | console.log("[SSE] 连接已关闭"); |
| | | } |
| | | }; |
| | | |
| | | /** 刷新 SSE 连接 */ |
| | | const refresh = (url: string) => { |
| | | retryCount = 0; |
| | | close(); // 先关闭旧连接 |
| | | connect(url); // 再重新连接 |
| | | }; |
| | | |
| | | return { |
| | | deviceCode, |
| | | deviceData, |
| | | setDeviceCode, |
| | | source, |
| | | message, |
| | | isConnected, |
| | | connect, |
| | | close, |
| | | refresh, |
| | | taskData, |
| | | pushTask, |
| | | setSyncTask, |
| | | clearTask, |
| | | }; |
| | | } |
| | | ); |
| New file |
| | |
| | | import { tryConvertToInt } from "@/utils/utils"; |
| | | import cache from "@/utils/cache"; |
| | | export interface IotInfo { |
| | | 属性历史列表: any[]; |
| | | 床号: string; |
| | | 状态列表: IotInfoStatus[]; |
| | | 设备唯一编号: string; |
| | | 设备序列号: string; |
| | | } |
| | | |
| | | export interface IotInfoStatus { |
| | | 是否为警告标记: number; |
| | | 状态名称: string; |
| | | 状态类型: string; |
| | | 状态颜色: string; |
| | | } |
| | | |
| | | export interface ConsumablesCollection { |
| | | 抗凝剂: string[]; |
| | | 护理包: string[]; |
| | | 滤过器: string[]; |
| | | 穿刺针: string[]; |
| | | 管路: string[]; |
| | | 透析器: string[]; |
| | | 透析模式: string[]; |
| | | } |
| | | |
| | | enum EPushType { |
| | | SPHYGMOMANOMETR = "床旁血压计", |
| | | CENTRAL_MONITORING = "中央监控大屏信息", |
| | | } |
| | | |
| | | type PushType = "床旁血压计" | "中央监控大屏信息"; |
| | | |
| | | export interface KtvItem { |
| | | 时间: string; |
| | | ktv: string; |
| | | } |
| | | |
| | | export interface DialysisStatus { |
| | | clientCode: string; |
| | | deviceHospitalCode: string; |
| | | iot_传输时间: number | null; |
| | | iot_当前脱水量: number | null; |
| | | iot_脱水目标量: number | null; |
| | | iot_脱水速率: number | null; |
| | | iot_透析液流速: number | null; |
| | | iot_跨膜压: number | null; |
| | | iot_透析时间: number | null; |
| | | iot_静脉压: number | null; |
| | | iot_血流量: number | null; |
| | | sortOrder: number | null; |
| | | txTime: number | null; |
| | | 上次透后称重: number | null; |
| | | 体重增加: number | null; |
| | | 体重增长率: number | null; |
| | | 分区编号: string; |
| | | 处方脱水量: number | null; |
| | | 实时ktv: string; |
| | | 实时ktv计算结果列表: null | { |
| | | realTimeKtvCalcDetailResultInfo: KtvItem[]; |
| | | 透析单编号: string; |
| | | }; |
| | | 实时脱水量: number | null; |
| | | 干体重: number | null; |
| | | 年龄: number | null; |
| | | 异常检验指标: AnomalyIndex[] | null; |
| | | 当前血温: number | null; |
| | | 性别: string; |
| | | 患者头像: string; |
| | | 患者姓名: string; |
| | | 患者来源: 0 | 1; |
| | | 患者编号: string; |
| | | 患者透析号: string; |
| | | 患者门诊住院号: string; |
| | | 抗凝剂列表: Anticoagulant[] | null; |
| | | 护理包列表: string[] | null; |
| | | 报警_脱水量设定不一致: boolean; |
| | | 最后一条血压: number | null; |
| | | 最近平均脱水量: string; |
| | | 最近最大脱水量: string; |
| | | 最近最大脱水量日期: string; |
| | | 此次脱水量: number | null; |
| | | 监测血压是否低于百分之30: boolean; |
| | | 监测血压是否高于百分之30: boolean; |
| | | 监测记录列表: any[]; |
| | | 穿刺针列表: PunctureNeedle[] | null; |
| | | 第一条血压: number | null; |
| | | 管路列表: Piping[] | null; |
| | | 置换方式: string; |
| | | 脉搏列表: any[] | null; |
| | | 血压低值列表: any[] | null; |
| | | 血管通路列表: VascularAccess[] | null; |
| | | 设备分区位置: any; |
| | | 设备分区类型: number | null; |
| | | 设备号: string; |
| | | 设备名称: string; |
| | | 设备序列号: string; |
| | | 设备状态列表: IotInfoStatus[] | null; |
| | | 设备编号: string; |
| | | 超滤速度过快: boolean; |
| | | 跨膜压列表: any[] | null; |
| | | 跨膜压是否大于200: boolean; |
| | | 跨膜压是否小于0: boolean; |
| | | 透前称重: number | null; |
| | | 透前脉搏: number | null; |
| | | 透前血压_伸缩压: number | null; |
| | | 透前血压_舒张压: number | null; |
| | | 透析单医嘱列表: any[] | null; |
| | | 透析单编号: string | null; |
| | | 透析器: string; |
| | | 透析器列表: Dialyzer[] | null; |
| | | 透析处方是否已确认: number; |
| | | 透析处方的时长: number | null; |
| | | 透析处方的时长_分钟: string; |
| | | 透析处方的时长_小时: string; |
| | | 透析开始时间: number | null; |
| | | 透析方案: string; |
| | | 透析液列表: any[]; |
| | | 透析状态: string; // '0.0'这种格式的,得格式化一下 |
| | | 透析结束时间: number | null; |
| | | 透析处方备注: string; |
| | | 最近最大脱水量透析时长: string; |
| | | } |
| | | |
| | | export interface VascularAccess { |
| | | 位置: string; |
| | | 类型: string; |
| | | } |
| | | |
| | | export interface Dialyzer extends item {} |
| | | |
| | | export interface Piping extends item {} |
| | | |
| | | export interface PunctureNeedle extends item {} |
| | | |
| | | export interface item { |
| | | name: string; |
| | | 单位: string; |
| | | 数量: number | null; |
| | | } |
| | | |
| | | export interface Anticoagulant { |
| | | name: string; |
| | | 单位: string; |
| | | 数量: number | null; |
| | | 总量: number | null; |
| | | 是否为追加: number | null; |
| | | 维持剂量: number | null; |
| | | 追加剂量: number | null; |
| | | 首剂: number | null; |
| | | } |
| | | |
| | | export interface AnomalyIndex { |
| | | 单位: string; |
| | | 参考值: string; |
| | | 结果标记: string; |
| | | 项目名称: string; |
| | | 项目结果: string; |
| | | } |
| | | |
| | | export interface Countdown { |
| | | 当前服务器时间?: string; |
| | | 提醒文本?: string; |
| | | 提醒文本字典?: any[]; |
| | | 设定提醒倒计时?: number; |
| | | } |
| | | |
| | | export interface SseMsgData { |
| | | IOT信息: IotInfo | null; |
| | | 使用耗材字典: ConsumablesCollection | null; // 当透析状态为治疗中时该字段为null |
| | | 倒计时: Countdown | null; |
| | | 推送类型: PushType; |
| | | 透析状态: DialysisStatus | null; |
| | | } |
| | | |
| | | export interface BedsideAuxiliaryScreen { |
| | | deviceCode: string; |
| | | devicdeNo: string | number; |
| | | recordCode: string; |
| | | patientCode: string; |
| | | patientName: string; |
| | | patientPhone: string; |
| | | age: string; |
| | | gender: string; |
| | | patForm: PatForm; |
| | | patFormNumber: string; |
| | | treatmentStatus: MedStatus; |
| | | consumablesCollection: ConsumablesCollection; |
| | | pageType: PageType; |
| | | notSignedIn: NotSignedIn; |
| | | signedIn: SignedIn; |
| | | underTreatment: UnderTreatment; |
| | | } |
| | | |
| | | export enum EPageType { |
| | | NOT_INIT = 0, // 未初始化(没有设备编号) |
| | | LOADING = 1, // 加载中 |
| | | UNPLANNED_SCHEDULE = 2, // 未排班 |
| | | NOT_SIGNED_IN = 3, // 未签到 |
| | | SIGNED_IN = 4, // 已签到 |
| | | DURING_DIALYSIS = 5, // 透析中 |
| | | SPHYGMOMANOMETER = 6, // 床旁血压计 |
| | | } |
| | | |
| | | export type PageType = |
| | | | EPageType.NOT_INIT |
| | | | EPageType.LOADING |
| | | | EPageType.UNPLANNED_SCHEDULE |
| | | | EPageType.NOT_SIGNED_IN |
| | | | EPageType.SIGNED_IN |
| | | | EPageType.DURING_DIALYSIS |
| | | | EPageType.SPHYGMOMANOMETER; |
| | | |
| | | export enum EMedStatus { |
| | | /** 未签到 */ |
| | | NOT_CHECKED_IN = 0, |
| | | /** 已签到 */ |
| | | SIGNED_IN = 1, |
| | | /** 透析中 */ |
| | | DURING_DIALYSIS = 2, |
| | | /** 已结束 */ |
| | | END = 2.5, |
| | | /** 已检查 */ |
| | | CHECKED = 3, |
| | | /** 已归档 */ |
| | | ARCHIVED = 4, |
| | | } |
| | | |
| | | export type MedStatus = |
| | | | EMedStatus.NOT_CHECKED_IN |
| | | | EMedStatus.SIGNED_IN |
| | | | EMedStatus.DURING_DIALYSIS |
| | | | EMedStatus.END |
| | | | EMedStatus.CHECKED |
| | | | EMedStatus.ARCHIVED; |
| | | |
| | | export enum EPatForm { |
| | | OUTPATIENT_SERVICE = 0, |
| | | BE_IN_HOSPITAL = 1, |
| | | } |
| | | |
| | | export type PatForm = EPatForm.BE_IN_HOSPITAL | EPatForm.OUTPATIENT_SERVICE; |
| | | |
| | | export interface NotSignedIn { |
| | | dialysisMode: string; |
| | | dialyzerList: Dialyzer[]; |
| | | pipingList: Piping[]; |
| | | dialysateList: any[]; |
| | | anticoagulant: Anticoagulant[]; |
| | | carePackage: any[]; |
| | | punctureNeedle: PunctureNeedle[]; |
| | | vascularAccess: VascularAccess[]; |
| | | } |
| | | |
| | | export const defaultconsumablesCollection = (): ConsumablesCollection => { |
| | | return { |
| | | 抗凝剂: [], |
| | | 护理包: [], |
| | | 滤过器: [], |
| | | 穿刺针: [], |
| | | 管路: [], |
| | | 透析器: [], |
| | | 透析模式: [], |
| | | }; |
| | | }; |
| | | |
| | | export const defalutNotSignedIn = (): NotSignedIn => { |
| | | return { |
| | | dialysisMode: "", // 透析模式 |
| | | dialyzerList: [], // 透析器列表 |
| | | pipingList: [], // 一次性使用管路列表 |
| | | dialysateList: [], // 透析液列表 |
| | | anticoagulant: [], // 抗凝剂列表 |
| | | carePackage: [], // 一次性使用透析护理包列表 |
| | | punctureNeedle: [], // 穿刺针列表 |
| | | vascularAccess: [], // 血管通路列表 |
| | | }; |
| | | }; |
| | | |
| | | export interface SignedIn { |
| | | abnormalItems: AnomalyIndex[]; |
| | | dialysisPlan: string; // 透析方案 |
| | | prescriptionDehydrationVolume: number | null; // 透析处方脱水量 |
| | | dialyzer: string; // 透析器 |
| | | averageDehydrationRate: string; // 最近平均脱水量 |
| | | maximumDehydrationCapacity: string; // 最近最大脱水量 |
| | | maximumDehydrationCapacityDate: string; // 最近最大脱水量日期 |
| | | dryWeight: number | null; // 干体重 |
| | | preDialysisWeight: number | null; // 透前称重 |
| | | weightAfterLastDialysis: number | null; // 上次透后称重 |
| | | weightIncrease: number | null; // 体重增加 |
| | | weightIncreaseRate: number | null; // 体重增长率 |
| | | } |
| | | |
| | | export const defaultSignedIn = (): SignedIn => { |
| | | return { |
| | | abnormalItems: [], // 异常指标列表 |
| | | dialysisPlan: "", // 透析方案 |
| | | prescriptionDehydrationVolume: null, // 透析处方脱水量 |
| | | dialyzer: "", // 透析器 |
| | | averageDehydrationRate: "", // 最近平均脱水量 |
| | | maximumDehydrationCapacity: "", // 最近最大脱水量 |
| | | maximumDehydrationCapacityDate: "", // 最近最大脱水量日期 |
| | | dryWeight: null, // 干体重 |
| | | preDialysisWeight: null, // 透前称重 |
| | | weightAfterLastDialysis: null, // 上次透后称重 |
| | | weightIncrease: null, // 体重增加 |
| | | weightIncreaseRate: null, // 体重增长率 |
| | | }; |
| | | }; |
| | | |
| | | export interface UnderTreatment { |
| | | substituteMode: string; // 置换方式 |
| | | dialysisPlan: string; // 透析方案 |
| | | dialyzer: string; // 透析器 |
| | | averageDehydrationRate: string; // 平均脱水量 |
| | | maximumDehydrationCapacity: string; // 最大脱水量 |
| | | maximumDehydrationCapacityDate: string; // 最大脱水量日期 |
| | | maximumDehydrationDuration: string; // 最大脱水量那天的时长 |
| | | prescriptionRemarks: string; // 透析处方备注 |
| | | abnormalItems: AnomalyIndex[]; // 异常指标列表 |
| | | prescriptionDialysisDurationHour: string; // 透析处方的时长(小时部分) |
| | | prescriptionDialysisDurationMin: string; // 透析处方的时长(分钟部分) |
| | | prescriptionDialysisDuration: number | null; // 透析处方的时长(单位:小时) |
| | | dialysisStartTime: number | null; // 透析开始时间(时间戳) |
| | | dialysisEndTime: number | null; // 透析结束时间(时间戳) |
| | | dialysisDuration: number | null; // 已透析时长(单位:分钟) |
| | | prescriptionDehydrationVolume: number | null; // 透析处方脱水量 【】 |
| | | currentDehydrationVolume: number | null; // 当前脱水量 【实时脱水量】 |
| | | currentUltrafiltrationRate: number | null; // 当前超滤速率 |
| | | currentBloodTemperature: number | null; // 当前血温 |
| | | venousPressure: number | null; // 静脉压 |
| | | transmembranePressure: number | null; // 跨膜压 |
| | | ktv: string; // 实时ktv |
| | | monitoringRecord: MonitoringRecord[]; // 监测记录列表 |
| | | doctorAdvice: any[]; // 透析单医嘱列表 |
| | | bloodFlow: string; // 血流量 |
| | | bloodVolumeMonitoring: number | null; // 血容量监测 |
| | | dialysisFluidFlowRate: number | null; // 透析液流量 |
| | | ktvList: KtvItem[]; // 实时ktv计算结果列表 |
| | | } |
| | | |
| | | export interface MonitoringRecord { |
| | | 伸缩压: string; // 血压伸缩压 |
| | | 舒张压: string; // 血压舒张压 |
| | | 脉搏: string; // 脉搏 |
| | | } |
| | | |
| | | export const defaultUnderTreatment = (): UnderTreatment => { |
| | | return { |
| | | substituteMode: "", |
| | | dialysisPlan: "", |
| | | dialyzer: "", |
| | | averageDehydrationRate: "", |
| | | maximumDehydrationCapacity: "", |
| | | maximumDehydrationCapacityDate: "", |
| | | maximumDehydrationDuration: "", |
| | | prescriptionRemarks: "", |
| | | abnormalItems: [], |
| | | prescriptionDialysisDurationHour: "", |
| | | prescriptionDialysisDurationMin: "", |
| | | dialysisStartTime: null, |
| | | dialysisEndTime: null, |
| | | dialysisDuration: null, |
| | | prescriptionDehydrationVolume: null, |
| | | currentDehydrationVolume: null, |
| | | currentUltrafiltrationRate: null, |
| | | currentBloodTemperature: null, |
| | | venousPressure: null, |
| | | transmembranePressure: null, |
| | | ktv: "", |
| | | monitoringRecord: [], |
| | | doctorAdvice: [], |
| | | bloodFlow: "", |
| | | bloodVolumeMonitoring: null, |
| | | dialysisFluidFlowRate: null, |
| | | ktvList: [], |
| | | prescriptionDialysisDuration: null, // 透析处方的时长(单位:小时) |
| | | }; |
| | | }; |
| | | |
| | | export const defaultDeviceData = (): BedsideAuxiliaryScreen => { |
| | | const pageType = cache.get("devcieCode") |
| | | ? EPageType.LOADING |
| | | : EPatForm.OUTPATIENT_SERVICE; |
| | | return { |
| | | deviceCode: "", // 设备code |
| | | devicdeNo: "", // 设备号 |
| | | recordCode: "", // 透析单code |
| | | patientCode: "", // 患者code |
| | | patientName: "", // 患者姓名 |
| | | patientPhone: "", // 患者头像 |
| | | age: "", // 年龄 |
| | | gender: "", // 性别 |
| | | patForm: EPatForm.OUTPATIENT_SERVICE, // 患者来源 |
| | | patFormNumber: "", // 住院门诊号 |
| | | // @ts-ignore |
| | | pageType, // 当前要展示的页面 |
| | | treatmentStatus: EMedStatus.NOT_CHECKED_IN, // 透析状态 |
| | | consumablesCollection: defaultconsumablesCollection(), // 未排班时需要的数据 |
| | | notSignedIn: defalutNotSignedIn(), // 未签到时需要的数据 |
| | | signedIn: defaultSignedIn(), // 已签到时需要的数据 |
| | | underTreatment: defaultUnderTreatment(), // 治疗中需要的数据 |
| | | }; |
| | | }; |
| | | |
| | | export const formatDeviceData = ( |
| | | seeMsg: SseMsgData |
| | | ): BedsideAuxiliaryScreen => { |
| | | |
| | | const result = defaultDeviceData(); |
| | | |
| | | // 默认床号(设备号) |
| | | result.devicdeNo = seeMsg.IOT信息?.床号; |
| | | result.deviceCode = seeMsg.IOT信息?.设备唯一编号; |
| | | |
| | | if (seeMsg.推送类型 === EPushType.SPHYGMOMANOMETR) { |
| | | result.pageType = EPageType.SPHYGMOMANOMETER; |
| | | } else if (seeMsg.推送类型 === EPushType.CENTRAL_MONITORING) { |
| | | // 判断是否存在透析状态,如果不存在就是没有排班 |
| | | if (seeMsg.透析状态 === null || !seeMsg.透析状态) { |
| | | result.pageType = EPageType.UNPLANNED_SCHEDULE; |
| | | result.consumablesCollection = |
| | | seeMsg?.使用耗材字典 ?? defaultconsumablesCollection(); |
| | | } else { |
| | | const treatmentStatus = tryConvertToInt( |
| | | seeMsg.透析状态?.透析状态 |
| | | ) as MedStatus; |
| | | |
| | | // 这里就是有排班的 |
| | | result.treatmentStatus = treatmentStatus; |
| | | result.recordCode = seeMsg.透析状态?.透析单编号; |
| | | result.patientCode = seeMsg.透析状态?.患者编号; |
| | | result.patientName = seeMsg.透析状态?.患者姓名; |
| | | result.patientPhone = seeMsg.透析状态?.患者头像; |
| | | result.age = seeMsg.透析状态?.年龄 + ""; |
| | | result.gender = seeMsg.透析状态?.性别 + ""; |
| | | result.patForm = seeMsg.透析状态?.患者来源; |
| | | result.patFormNumber = seeMsg.透析状态?.患者门诊住院号; |
| | | |
| | | // 未签到页面需要显示的 |
| | | if (treatmentStatus === EMedStatus.NOT_CHECKED_IN) { |
| | | result.pageType = EPageType.NOT_SIGNED_IN; |
| | | const notSignedIn = defalutNotSignedIn(); |
| | | notSignedIn.dialysisMode = seeMsg.透析状态?.透析方案 ?? ""; |
| | | notSignedIn.dialyzerList = seeMsg.透析状态?.透析器列表 ?? []; |
| | | notSignedIn.pipingList = seeMsg.透析状态?.管路列表 ?? []; |
| | | notSignedIn.dialysateList = seeMsg.透析状态?.透析液列表 ?? []; |
| | | notSignedIn.carePackage = seeMsg.透析状态?.护理包列表 ?? []; |
| | | notSignedIn.punctureNeedle = seeMsg.透析状态?.穿刺针列表 ?? []; |
| | | notSignedIn.vascularAccess = seeMsg.透析状态?.血管通路列表 ?? []; |
| | | notSignedIn.anticoagulant = seeMsg.透析状态?.抗凝剂列表 ?? []; |
| | | |
| | | result.notSignedIn = notSignedIn; |
| | | } |
| | | // 已签到未开始透析需要显示的 |
| | | else if (treatmentStatus === EMedStatus.SIGNED_IN) { |
| | | result.pageType = EPageType.SIGNED_IN; |
| | | const signedIn = defaultSignedIn(); |
| | | signedIn.abnormalItems = seeMsg.透析状态?.异常检验指标 ?? []; |
| | | signedIn.dialysisPlan = seeMsg.透析状态?.透析方案 ?? ""; |
| | | signedIn.prescriptionDehydrationVolume = |
| | | seeMsg.透析状态?.处方脱水量 ?? null; |
| | | signedIn.dialyzer = seeMsg.透析状态?.透析器 ?? ""; |
| | | signedIn.averageDehydrationRate = seeMsg.透析状态?.最近平均脱水量 ?? ""; |
| | | signedIn.maximumDehydrationCapacity = |
| | | seeMsg.透析状态?.最近最大脱水量 ?? ""; |
| | | signedIn.maximumDehydrationCapacityDate = |
| | | seeMsg.透析状态?.最近最大脱水量日期 ?? ""; |
| | | signedIn.dryWeight = seeMsg.透析状态?.干体重 ?? null; |
| | | signedIn.preDialysisWeight = seeMsg.透析状态?.透前称重 ?? null; |
| | | signedIn.weightAfterLastDialysis = |
| | | seeMsg.透析状态?.上次透后称重 ?? null; |
| | | signedIn.weightIncrease = seeMsg.透析状态?.体重增加 ?? null; |
| | | signedIn.weightIncreaseRate = seeMsg.透析状态?.体重增长率 ?? null; |
| | | |
| | | result.signedIn = signedIn; |
| | | } |
| | | // 剩下的全使用治疗中的页面 |
| | | else { |
| | | result.pageType = EPageType.DURING_DIALYSIS; |
| | | const underTreatment = defaultUnderTreatment(); |
| | | underTreatment.substituteMode = seeMsg.透析状态?.置换方式 ?? ""; |
| | | underTreatment.dialysisPlan = seeMsg.透析状态?.透析方案 ?? ""; |
| | | underTreatment.dialyzer = seeMsg.透析状态?.透析器 ?? ""; |
| | | underTreatment.averageDehydrationRate = |
| | | seeMsg.透析状态?.最近平均脱水量 ?? ""; |
| | | underTreatment.maximumDehydrationCapacity = |
| | | seeMsg.透析状态?.最近最大脱水量 ?? ""; |
| | | underTreatment.maximumDehydrationCapacityDate = |
| | | seeMsg.透析状态?.最近最大脱水量日期 ?? ""; |
| | | underTreatment.maximumDehydrationDuration = |
| | | seeMsg.透析状态?.最近最大脱水量透析时长 ?? ""; |
| | | underTreatment.prescriptionRemarks = |
| | | seeMsg.透析状态?.透析处方备注 ?? ""; |
| | | underTreatment.abnormalItems = seeMsg.透析状态?.异常检验指标 ?? []; |
| | | underTreatment.prescriptionDialysisDuration = |
| | | seeMsg.透析状态?.透析处方的时长 ?? null; |
| | | underTreatment.prescriptionDialysisDurationHour = |
| | | seeMsg.透析状态?.透析处方的时长_小时 ?? ""; |
| | | underTreatment.prescriptionDialysisDurationMin = |
| | | seeMsg.透析状态?.透析处方的时长_分钟 ?? ""; |
| | | underTreatment.dialysisStartTime = |
| | | seeMsg.透析状态?.透析开始时间 ?? null; |
| | | underTreatment.dialysisEndTime = seeMsg.透析状态?.透析结束时间 ?? null; |
| | | underTreatment.dialysisDuration = seeMsg.透析状态?.iot_透析时间 ?? null; |
| | | underTreatment.prescriptionDehydrationVolume = |
| | | seeMsg.透析状态?.iot_脱水目标量 ?? null; |
| | | underTreatment.currentDehydrationVolume = |
| | | seeMsg.透析状态?.iot_当前脱水量 ?? null; |
| | | underTreatment.currentUltrafiltrationRate = |
| | | seeMsg.透析状态?.iot_脱水速率 ?? null; |
| | | underTreatment.currentBloodTemperature = |
| | | seeMsg.透析状态?.当前血温 ?? null; |
| | | underTreatment.venousPressure = seeMsg.透析状态?.iot_静脉压 ?? null; |
| | | underTreatment.transmembranePressure = |
| | | seeMsg.透析状态?.iot_跨膜压 ?? null; |
| | | underTreatment.ktv = seeMsg.透析状态?.实时ktv ?? ""; |
| | | underTreatment.monitoringRecord = seeMsg.透析状态?.监测记录列表 ?? []; |
| | | underTreatment.doctorAdvice = seeMsg.透析状态?.透析单医嘱列表 ?? []; |
| | | underTreatment.bloodFlow = ""; |
| | | underTreatment.dialysisFluidFlowRate = |
| | | seeMsg.透析状态?.iot_血流量 ?? null; |
| | | underTreatment.bloodVolumeMonitoring = |
| | | seeMsg.透析状态?.iot_透析液流速 ?? null; |
| | | underTreatment.ktvList = |
| | | seeMsg.透析状态?.实时ktv计算结果列表 |
| | | ?.realTimeKtvCalcDetailResultInfo ?? []; |
| | | result.underTreatment = underTreatment; |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | }; |
| | | |
| | | export const getItemName = (name: string) => { |
| | | if (name) { |
| | | if (name === "血红蛋白") { |
| | | return "HGB "; |
| | | } else if (name === "铁蛋白") { |
| | | return "FER "; |
| | | } else if (name === "白蛋白") { |
| | | return "ALB "; |
| | | } else if (name === "钙") { |
| | | return "Ca "; |
| | | } else if (name === "钾") { |
| | | return "K "; |
| | | } else if (name === "无机磷") { |
| | | return "P "; |
| | | } else if (name === "甲状旁腺激素") { |
| | | return "PTH "; |
| | | } else { |
| | | return name; |
| | | } |
| | | } else { |
| | | return ""; |
| | | } |
| | | }; |
| | | |
| | | export const formatTestColr = (reg: string) => { |
| | | const heightFlag = ["↑", "g"]; |
| | | const lowFlag = ["d", "↓"]; |
| | | let color = "#333"; |
| | | if (heightFlag.includes(reg)) { |
| | | color = "#CA7070"; |
| | | } else if (lowFlag.includes(reg)) { |
| | | color = "#409eff"; |
| | | } |
| | | return color; |
| | | }; |
| | | |
| | | export const formatTestFlag = (reg: string) => { |
| | | const heightFlag = ["↑", "g"]; |
| | | const lowFlag = ["d", "↓"]; |
| | | if (heightFlag.includes(reg)) { |
| | | return "↑"; |
| | | } else if (lowFlag.includes(reg)) { |
| | | return "↓"; |
| | | } else { |
| | | return ""; |
| | | } |
| | | }; |
| | | |
| | | export const formatSubstituteMode = (mode: string) => { |
| | | let result = ""; |
| | | if (mode === "前置换") { |
| | | result = "前"; |
| | | } else if (mode === "后置换") { |
| | | result = "后"; |
| | | } |
| | | return result; |
| | | }; |
| New file |
| | |
| | | export interface Task { |
| | | /** 设备code */ |
| | | deviceCode: string; |
| | | /** 透析单code */ |
| | | recordCode?: string; |
| | | /** 任务提醒时间 */ |
| | | taskDate: string; |
| | | /** 任务名称 */ |
| | | taskName: string; |
| | | /** 是否过期 */ |
| | | overdue: boolean; |
| | | } |
| | |
| | | :root { |
| | | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; |
| | | line-height: 1.5; |
| | | font-weight: 400; |
| | | |
| | | color-scheme: light dark; |
| | | color: rgba(255, 255, 255, 0.87); |
| | | background-color: #242424; |
| | | |
| | | font-synthesis: none; |
| | | text-rendering: optimizeLegibility; |
| | | -webkit-font-smoothing: antialiased; |
| | | -moz-osx-font-smoothing: grayscale; |
| | | } |
| | | |
| | | html, body { |
| | | margin: 0; |
| | | padding: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | #app { |
| | | width: 100%; |
| | | height: 100%; |
| | | border: 1px rgb(23, 7, 7) solid; |
| | | background-color: lightblue; /* 可选:用于可视化效果 */ |
| | | } |
| | | |
| | | @media (prefers-color-scheme: light) { |
| | | :root { |
| | | color: #213547; |
| | | background-color: #ffffff; |
| | | } |
| | | a:hover { |
| | | color: #747bff; |
| | | } |
| | | button { |
| | | background-color: #f9f9f9; |
| | | } |
| | | } |
| | | .el-loading-spinner .el-loading-text { |
| | | font-size: 16px; /* 修改为你需要的字体大小 */ |
| | | } |
| | | .el-dialog { |
| | | padding: 0; |
| | | padding-bottom: 20px; |
| | | border-radius: 10px; |
| | | } |
| New file |
| | |
| | | class Cache { |
| | | /** |
| | | * 设置本地缓存 |
| | | * @param key 键名 |
| | | * @param value 值(会自动序列化为 JSON) |
| | | */ |
| | | set<T = any>(key: string, value: T): void { |
| | | try { |
| | | const json = JSON.stringify(value) |
| | | localStorage.setItem(key, json) |
| | | } catch (e) { |
| | | console.error(`缓存写入失败(${key}):`, e) |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取本地缓存 |
| | | * @param key 键名 |
| | | * @returns 反序列化后的值,失败返回 null |
| | | */ |
| | | get<T = any>(key: string): T | null { |
| | | try { |
| | | const json = localStorage.getItem(key) |
| | | return json ? JSON.parse(json) as T : null |
| | | } catch (e) { |
| | | console.error(`缓存读取失败(${key}):`, e) |
| | | return null |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除指定缓存项 |
| | | * @param key 键名 |
| | | */ |
| | | delete(key: string): void { |
| | | try { |
| | | localStorage.removeItem(key) |
| | | } catch (e) { |
| | | console.error(`缓存删除失败(${key}):`, e) |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 判断某项缓存是否存在 |
| | | * @param key 键名 |
| | | * @returns 是否存在 |
| | | */ |
| | | has(key: string): boolean { |
| | | try { |
| | | return localStorage.getItem(key) !== null |
| | | } catch (e) { |
| | | console.error(`缓存判断失败(${key}):`, e) |
| | | return false |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 清空所有本地缓存 |
| | | */ |
| | | clear(): void { |
| | | try { |
| | | localStorage.clear() |
| | | } catch (e) { |
| | | console.error('缓存清空失败:', e) |
| | | } |
| | | } |
| | | } |
| | | |
| | | export default new Cache() |
| New file |
| | |
| | | /** |
| | | * 计算某个类名元素的可用高度(视口高度 - 元素顶部距离) |
| | | * @param className 元素类名(不带.) |
| | | * @returns 可用高度(px),找不到元素则返回 0 |
| | | */ |
| | | export function getAvailableHeightByClass(className: string): number { |
| | | const el = document.querySelector(`.${className}`) as HTMLElement | null |
| | | if (!el) return 0 |
| | | const rect = el.getBoundingClientRect() |
| | | return window.innerHeight - rect.top |
| | | } |
| | | |
| | | /** |
| | | * 将字符串转为数字 |
| | | * @param value |
| | | * @returns |
| | | */ |
| | | export function tryConvertToInt(value: string): string | number { |
| | | const num = Number(value); |
| | | // 判断是否是有效数字且是整数(小数部分为 0) |
| | | if (!isNaN(num) && Number.isInteger(num)) { |
| | | return num; |
| | | } |
| | | |
| | | // 判断是否是有效数字且小数部分为 0(例如 "1.0") |
| | | if (!isNaN(num) && Number(value).toString().endsWith('.0')) { |
| | | return parseInt(value, 10); |
| | | } |
| | | |
| | | return value; |
| | | } |
| New file |
| | |
| | | <template> |
| | | <div |
| | | class="block-botttom" |
| | | :style="{ |
| | | '--backgroundColor': props.backgroundColor, |
| | | }" |
| | | @click="props.onClick" |
| | | > |
| | | <img :src="icon" alt="" class="icon" /> |
| | | <span class="text">{{ text }}</span> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="BlockBotttom"> |
| | | interface Props { |
| | | icon: string; // 图标 |
| | | text: string; // 文本 |
| | | backgroundColor: string; // 背景颜色 |
| | | onClick: () => void; // 点击事件 |
| | | } |
| | | const props = defineProps<Props>(); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .block-botttom { |
| | | width: 18px; |
| | | height: 18px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background: var(--backgroundColor, #70a3dd); |
| | | border-radius: 2px; |
| | | .icon { |
| | | margin-bottom: 2px; |
| | | width: 6px; |
| | | height: 6px; |
| | | } |
| | | .text { |
| | | font-family: AlibabaPuHuiTi, AlibabaPuHuiTi; |
| | | font-weight: 500; |
| | | font-size: 3px; |
| | | color: #ffffff; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div |
| | | class="bedside-auxiliary-screen-card" |
| | | :style="{ |
| | | '--bg-color': props.backgroundColor, |
| | | }" |
| | | > |
| | | <div class="card-header" :class="props.headerClassName"> |
| | | <img :src="props.icon" class="card-icon" alt="" srcset="" /> |
| | | <span class="card-title">{{ props.title }}</span> |
| | | </div> |
| | | <div class="card-main"> |
| | | <slot /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="Card"> |
| | | interface Props { |
| | | backgroundColor: string; // 背景颜色 |
| | | title: string; // 标题 |
| | | icon: string; |
| | | height?: number; |
| | | headerClassName?: string; // 头部类名 |
| | | } |
| | | const props = defineProps<Props>(); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | * { |
| | | box-sizing: border-box; |
| | | } |
| | | .bedside-auxiliary-screen-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | // height: 100%; |
| | | padding: 3px 4px; |
| | | border-radius: 2px; |
| | | background-color: var(--bg-color, #70a3dd); |
| | | overflow: hidden; |
| | | overflow-y: auto; |
| | | height: 100%; |
| | | |
| | | .card-header { |
| | | flex: 0 0 6px; |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 2px; |
| | | |
| | | .card-icon { |
| | | width: 6px; |
| | | height: 6px; |
| | | margin-right: 2px; |
| | | } |
| | | |
| | | .card-title { |
| | | flex: 1; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 4px; |
| | | color: #333333; |
| | | text-align: left; |
| | | font-style: normal; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | |
| | | .card-main { |
| | | flex: 1; |
| | | overflow: hidden; |
| | | overflow-y: auto; |
| | | min-height: 0; |
| | | } |
| | | .card-main > * { |
| | | min-height: 0; |
| | | overflow: hidden; |
| | | } |
| | | } |
| | | :deep(.el-scrollbar__view) { |
| | | min-height: 0; |
| | | height: 100%; |
| | | overflow: hidden; |
| | | overflow-y: auto; |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="doctor_advice_container" :style="{ height: height }"> |
| | | <div class="doctor_advice_list"> |
| | | <div |
| | | v-for="(item, index) in drugOrders" |
| | | :key="index" |
| | | class="doctor_advice_item" |
| | | > |
| | | <div class="doctor_advice_item_name">{{ item.name }}</div> |
| | | <template v-if="item?.children && item.children.length > 0"> |
| | | <div |
| | | v-for="(child, childIndex) in item.children" |
| | | :key="childIndex" |
| | | class="doctor_advice_item_sub" |
| | | > |
| | | <img :src="trunImgSrc" alt="" /> |
| | | <span>{{ child }}</span> |
| | | </div> |
| | | </template> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { PropType, computed } from "vue"; |
| | | import type { Order } from "./type" |
| | | import trunImgSrc from "@/assets/turn.png"; |
| | | |
| | | export default { |
| | | name: "DoctorAdvice", |
| | | props: { |
| | | // 容器的高度 |
| | | height: { |
| | | type: String, |
| | | default: '100%', |
| | | required: false, |
| | | }, |
| | | // 医嘱列表 |
| | | list: { |
| | | type: Array as PropType<Order[]>, |
| | | default: () => [], |
| | | }, |
| | | }, |
| | | setup(props) { |
| | | const drugOrders = computed(() => { |
| | | // 格式化主医嘱数据(浅拷贝) |
| | | const formatList = props.list |
| | | .filter((e) => e.orderIsSub !== 1) |
| | | .map((e) => ({ ...e })); |
| | | |
| | | // 处理子医嘱并挂载到对应主医嘱上 |
| | | props.list.forEach((e) => { |
| | | if (e.orderIsSub === 1) { |
| | | const i = formatList.findIndex((v) => v.code === e.orderMainCode); |
| | | if (i !== -1) { |
| | | if (!formatList[i].subDrugOrders) { |
| | | formatList[i].subDrugOrders = []; |
| | | } |
| | | formatList[i].subDrugOrders.push(e); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | // 构建显示用的 name 和子医嘱 children |
| | | return formatList.map((order) => { |
| | | let name = ""; |
| | | |
| | | if (order.orderNameInfo) { |
| | | name = order.orderNameInfo.itemName || ""; |
| | | const drugSpec = order.orderNameInfo.feeDrugInfo?.drugSpec; |
| | | if (drugSpec) { |
| | | name += ` (${drugSpec})`; |
| | | } |
| | | } |
| | | |
| | | if (order.orderUsage && order.orderUsage !== 0) { |
| | | name += ` ${order.orderUsage}${ |
| | | order.orderNameInfo?.feeDrugInfo?.drugUnitName || "" |
| | | }`; |
| | | } |
| | | |
| | | if (order.orderCount) { |
| | | name += ` ${order.orderCount}`; |
| | | const pkgUnit = order.orderNameInfo?.feeDrugInfo?.drugPackageUnitName; |
| | | if (pkgUnit) { |
| | | name += pkgUnit; |
| | | } |
| | | } |
| | | |
| | | if (order.orderFromInfo?.dictText) { |
| | | name += ` ${order.orderFromInfo.dictText}`; |
| | | } |
| | | |
| | | if (order.orderFreqInfo?.dictText) { |
| | | name += ` ${order.orderFreqInfo.dictText}`; |
| | | } |
| | | |
| | | const children: string[] = []; |
| | | |
| | | if (order.subDrugOrders?.length) { |
| | | order.subDrugOrders.forEach((child: any) => { |
| | | let subName = child.orderNameInfo?.itemName || ""; |
| | | |
| | | const childSpec = child.orderNameInfo?.feeDrugInfo?.drugSpec; |
| | | if (childSpec) { |
| | | subName += ` (${childSpec})`; |
| | | } |
| | | |
| | | if (child.orderUsage) { |
| | | const unit = child.orderNameInfo?.feeDrugInfo?.drugUnitName || ""; |
| | | subName += ` ${child.orderUsage}${unit}`; |
| | | } |
| | | |
| | | if (child.orderCount) { |
| | | const pkgUnit = |
| | | child.orderNameInfo?.feeDrugInfo?.drugPackageUnitName; |
| | | if (pkgUnit) { |
| | | subName += ` ${child.orderCount}${pkgUnit}`; |
| | | } |
| | | } |
| | | |
| | | children.push(subName); |
| | | }); |
| | | } |
| | | |
| | | return { |
| | | name, |
| | | children, |
| | | }; |
| | | }); |
| | | }); |
| | | |
| | | return { |
| | | drugOrders, |
| | | trunImgSrc, |
| | | }; |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .doctor_advice_container { |
| | | box-sizing: border-box; |
| | | } |
| | | .doctor_advice_container .doctor_advice_list { |
| | | box-sizing: border-box; |
| | | height: 100%; |
| | | background: #ffffff; |
| | | overflow: hidden; |
| | | overflow-y: auto; |
| | | } |
| | | .doctor_advice_container .doctor_advice_item { |
| | | box-sizing: border-box; |
| | | border-bottom: 1px solid #e6e5e5; |
| | | } |
| | | .doctor_advice_container .doctor_advice_item:last-child { |
| | | /* box-sizing: border-box; |
| | | border-bottom: none; */ |
| | | } |
| | | .doctor_advice_container .doctor_advice_item .doctor_advice_item_name { |
| | | box-sizing: border-box; |
| | | font-weight: 400; |
| | | font-size: 5px; |
| | | color: #333333; |
| | | line-height: 12px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | .doctor_advice_container .doctor_advice_item_sub { |
| | | padding-left: 1px; |
| | | font-weight: 400; |
| | | font-size: 5px; |
| | | color: #777777; |
| | | line-height: 12px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | .doctor_advice_container .doctor_advice_item_sub img { |
| | | width: 7px; |
| | | height: 7px; |
| | | margin-right: 2px; |
| | | } |
| | | </style> |
| New file |
| | |
| | | export interface Order { |
| | | orderType: number; |
| | | code: string; |
| | | orderFreq: string; |
| | | orderDoctor: string; |
| | | confirmUserInfo: any | null; |
| | | remark: string | null; |
| | | isConfirm: number; |
| | | isDeleted: number; |
| | | orderExecuteCheckUser: any | null; |
| | | orderIsSub: number; |
| | | orderExecuteTime: any | null; |
| | | id: number; |
| | | recordCode: string; |
| | | deletedTime: any | null; |
| | | orderExecutePatient: any | null; |
| | | orderExecuteUser: any | null; |
| | | orderName: string; |
| | | orderExecuteCheckUserInfo: any | null; |
| | | subDrugOrders: any | null; |
| | | orderSort: number; |
| | | orderCount: number; |
| | | hisOrderNo: string | null; |
| | | updateUser: any | null; |
| | | confirmTime: any | null; |
| | | confirmUser: any | null; |
| | | updateTime: number; |
| | | orderDoctorInfo: UserDoctorInfo; |
| | | orderMainCode: string | null; |
| | | createTime: number; |
| | | orderFreqInfo: OrderFreqInfo; |
| | | orderNameInfo: OrderNameInfo; |
| | | createUser: any | null; |
| | | orderFrom: string; |
| | | orderUsage: number; |
| | | orderIsSpin: number; |
| | | orderExecuteUserInfo: any | null; |
| | | orderFromInfo: OrderFromInfo; |
| | | orderStartTime: number; |
| | | } |
| | | |
| | | interface UserDoctorInfo { |
| | | isRecvAlarmEmail: number; |
| | | prepareWorkMedicineStat: any | null; |
| | | userDegree: any | null; |
| | | isRecvAlarmWechat: number; |
| | | listReadyRows: any | null; |
| | | selectedFieldsInInventory2OutPage: any | null; |
| | | currentClientInfo: any | null; |
| | | signedInCountByDa: any | null; |
| | | selectFieldsInShangjiCanshuPage: any | null; |
| | | relatedClients: any | null; |
| | | userWorkState: any | null; |
| | | userIdentityCode: any | null; |
| | | clientInfos: any | null; |
| | | userMobile: string; |
| | | id: number; |
| | | loginWechatMpId: any | null; |
| | | userIsTongluDoctor: number; |
| | | canModifyHistoryHms: boolean; |
| | | 是否自动出库至二级默认仓库: any | null; |
| | | userGoDepartment: any | null; |
| | | userRfid: any | null; |
| | | userGraduateTime: any | null; |
| | | 管理员能看到的客户列表: any | null; |
| | | userSortOrder: number; |
| | | userCustomSetting: string; |
| | | hisCode: any | null; |
| | | isRecvAlarm: any | null; |
| | | selectedFieldsInCleanStatPage: any | null; |
| | | 排班时段选择项: any | null; |
| | | userVsRoleList: any | null; |
| | | userPassword: string; |
| | | code: string; |
| | | userSignPicUrl: any | null; |
| | | userFromDepartment: any | null; |
| | | roles: any | null; |
| | | userAvatar: any | null; |
| | | userNo: string; |
| | | admin: boolean; |
| | | remark: string; |
| | | userAdmin: boolean; |
| | | checkVersionCode: string; |
| | | selectedFieldsInMedStat2: any | null; |
| | | userTitle: string; |
| | | isDeleted: number; |
| | | nurse: boolean; |
| | | canDeleteHistoryHms: boolean; |
| | | userEmail: string; |
| | | deletedTime: any | null; |
| | | userWorkTimeFrom: any | null; |
| | | prepareWorkMedicine: any | null; |
| | | clientVsUserList: any | null; |
| | | isValid: number; |
| | | teamState: any | null; |
| | | updateUser: number; |
| | | updateTime: number; |
| | | 隐藏自备药: any | null; |
| | | userName: string; |
| | | selectFieldsInTodayOrderPage: any | null; |
| | | isShow: number; |
| | | doctor: boolean; |
| | | isValidForClient: number; |
| | | loginWechatUnionId: any | null; |
| | | userGoDate: any | null; |
| | | createTime: number; |
| | | userInDate: any | null; |
| | | clientCode: any | null; |
| | | selectedFieldsInInventory2QueryPage: any | null; |
| | | signedInCountByStatistics: any | null; |
| | | createUser: number; |
| | | userGender: number; |
| | | userPinyin: string; |
| | | listStatInfo: any | null; |
| | | } |
| | | |
| | | interface OrderFreqInfo { |
| | | code: string; |
| | | dictIsCustom: number; |
| | | updateUser: any | null; |
| | | remark: any | null; |
| | | updateTime: number; |
| | | dictNo: string; |
| | | dictType: string; |
| | | dictIsEnable: number; |
| | | isDeleted: number; |
| | | createTime: number; |
| | | hisCode: any | null; |
| | | sortOrder: number; |
| | | createUser: number; |
| | | id: number; |
| | | deletedTime: any | null; |
| | | dictText: string; |
| | | } |
| | | |
| | | interface OrderNameInfo { |
| | | itemAgent: any | null; |
| | | itemPermissionCode: any | null; |
| | | inventoryItemTypeInfo: InventoryItemTypeInfo; |
| | | itemIsUse: number; |
| | | itemIsRestrictUse: number; |
| | | itemCode: string; |
| | | itemHisType: any | null; |
| | | itemUnit: any | null; |
| | | suntopItemCode: any | null; |
| | | itemOutPrice: number; |
| | | itemFactoryInfo: any | null; |
| | | itemName: string; |
| | | itemCommonUseInBothSide: any | null; |
| | | id: number; |
| | | 当前使用量: any | null; |
| | | 剩余总量: any | null; |
| | | storageCode: any | null; |
| | | 入库总量: any | null; |
| | | 透析器国网上报: DialyzerReport; |
| | | hisCode: any | null; |
| | | itemIsOutToPatient: number; |
| | | itemSalePrice: number; |
| | | itemIsReUse: number; |
| | | itemPackageUnit: any | null; |
| | | inStorageCountInfo: any | null; |
| | | itemPackageUnitName: string; |
| | | itemIsFavor: number; |
| | | itemSpec: string; |
| | | itemYibaoPrice: any | null; |
| | | inventoryTypeCode: string; |
| | | code: string; |
| | | itemLicenseCode: any | null; |
| | | itemAgentInfo: any | null; |
| | | itemOperator: any | null; |
| | | remark: any | null; |
| | | 批号对象列表: any | null; |
| | | isDeleted: number; |
| | | itemIsEnableManage: number; |
| | | deletedTime: any | null; |
| | | itemIsUseAsXt: number; |
| | | itemName2: string; |
| | | inventoryItemType: number; |
| | | itemMoMaterial: any | null; |
| | | itemMoArea: number; |
| | | itemPinyin: string; |
| | | itemTxqCleanRate: any | null; |
| | | inventoryTypeName: any | null; |
| | | itemSortOrder: number; |
| | | updateUser: any | null; |
| | | updateTime: number; |
| | | 结存: any | null; |
| | | isShow: number; |
| | | itemFactory: any | null; |
| | | feeDrugInfo: FeeDrugInfo; |
| | | itemOperatorInfo: any | null; |
| | | itemPackageCount: any | null; |
| | | createTime: number; |
| | | clientCode: string; |
| | | itemExtendJson: string; |
| | | itemPeriodAlarmDays: number; |
| | | itemRestrictUseRemark: any | null; |
| | | createUser: number; |
| | | itemUnitInfo: any | null; |
| | | itemInPrice: number; |
| | | itemInventoryAlarmCount: number; |
| | | itemYibaoCode: any | null; |
| | | } |
| | | |
| | | interface InventoryItemTypeInfo { |
| | | code: string; |
| | | typeName: string; |
| | | updateUser: any | null; |
| | | remark: any | null; |
| | | updateTime: number; |
| | | typeCategory: number; |
| | | isShow: boolean; |
| | | isDeleted: number; |
| | | isEditable: number; |
| | | createTime: number; |
| | | clientCode: any | null; |
| | | sortOrder: number; |
| | | createUser: any | null; |
| | | id: number; |
| | | deletedTime: any | null; |
| | | } |
| | | |
| | | interface DialyzerReport { |
| | | eSA_促红素种类: string; |
| | | 抗凝剂_低分子肝素首剂量_IU: string; |
| | | 抗凝剂_总剂量: string; |
| | | 透析器透析膜: string; |
| | | 铁剂_其它静脉种类: string; |
| | | eSA_用药方式: any[]; // 根据实际元素类型替换 any |
| | | eSA_静脉剂量单位: string; |
| | | 铁剂_静脉剂量周: string; |
| | | 抗凝剂_枸橼酸钠速率每小时_ml: string; |
| | | 抗凝剂_阿加曲班追加速率_IU每小时: string; |
| | | 抗凝剂_肝素追加速率_mg每小时: string; |
| | | 透析器使用: string; |
| | | 抗凝剂_低分子肝素单位: string; |
| | | 抗凝剂_肝素首剂量_mg: string; |
| | | 抗凝剂_枸橼酸钠_其它钠浓度: string; |
| | | 抗凝剂_追加剂量: string; |
| | | 抗凝剂_其它抗凝剂: string; |
| | | 透析器类型: string; |
| | | 抗凝剂_阿加曲班_追加时间小时: string; |
| | | 抗凝剂_阿加曲班追加速率_mg每小时: string; |
| | | 抗凝剂_低分子肝素首剂量_mg: string; |
| | | 抗凝剂_阿加曲班首剂量_mg: string; |
| | | 透析器通量: string; |
| | | 抗凝剂_肝素首剂量_IU: string; |
| | | 铁剂_静脉种类: string; |
| | | 药品类型: string; |
| | | eSA_皮下剂量: string; |
| | | 铁剂_口服剂量日: string; |
| | | eSA_静脉剂量: string; |
| | | 抗凝剂_种类: string; |
| | | 抗凝剂_阿加曲班_追加时间分钟: string; |
| | | eSA_促红素名称: string; |
| | | 抗凝剂_低分子肝素类型: string; |
| | | 铁剂_给药方式: string; |
| | | 抗凝剂_首剂量: string; |
| | | 抗凝剂_低分子肝素总剂量: string; |
| | | 抗凝剂_低分子肝素追加时间: string; |
| | | 抗凝剂_低分子肝素追加剂量_mg: string; |
| | | 抗凝剂_肝素_追加时间小时: string; |
| | | 铁剂_其它口服种类: string; |
| | | 抗凝剂_阿加曲班首剂量_IU: string; |
| | | 抗凝剂_枸橼酸钠_使用时间小时: string; |
| | | 抗凝剂_肝素_追加时间分钟: string; |
| | | 抗凝剂_枸橼酸钠浓度百分比: string; |
| | | 抗凝剂_肝素单位: string; |
| | | 抗凝剂_阿加曲班单位: string; |
| | | eSA_皮下剂量单位: string; |
| | | 抗高血压药_分类: any[]; |
| | | 抗凝剂_枸橼酸钠_使用时间分钟: string; |
| | | 抗凝剂_肝素追加速率_IU每小时: string; |
| | | 铁剂_口服种类: string; |
| | | 透析器膜面积: string; |
| | | 抗凝剂_是否使用华法林: string; |
| | | 抗凝剂_低分子肝素追加剂量_IU: string; |
| | | eSA_其它促红素说明: string; |
| | | 铁剂_口服剂量单位: string; |
| | | 铁剂_静脉剂量单位: string; |
| | | } |
| | | |
| | | interface FeeDrugInfo { |
| | | drugBarcode: string; |
| | | drugIsNeedTest: number; |
| | | drugUsePeriodName: string; |
| | | drugProduceLocation: string; |
| | | drugPriceYibao: number; |
| | | drugUseTypeName: string; |
| | | drugPermissionCode: string; |
| | | drugCategory: number; |
| | | drugPackageType: number; |
| | | drugPackageUnitAlias: string; |
| | | drugSpec: string; |
| | | drugAntibioticLevel: number; |
| | | drugJixing: string; |
| | | drugHisCode: any | null; |
| | | drugInventoryPackageTypeName: any | null; |
| | | drugBenweiCode: string; |
| | | id: number; |
| | | drugUseMethodName: string; |
| | | drugIsFavor: number; |
| | | drugPackageUnitName: string; |
| | | drugPackageSum: number; |
| | | drugSortOrder: number; |
| | | drugYibaoCode: string; |
| | | inventoryItemDetailCode: string; |
| | | drugName2: string; |
| | | drugUseUnitName: string; |
| | | drugUnit: string; |
| | | drugUsePeriod: string; |
| | | drugInventoryPackageCount: number; |
| | | drugUseMethod: string; |
| | | drugName: string; |
| | | drugUseUnit: string; |
| | | drugInventoryPackageType: string; |
| | | drugUseOnetime: string; |
| | | code: string; |
| | | drugCode: string; |
| | | drugPackageUnit: string; |
| | | drugProduceFactoryName: any | null; |
| | | drugYlCode: string; |
| | | remark: string; |
| | | drugLimitUseText: string; |
| | | drugProduceFactory: string; |
| | | drugUnitName: string; |
| | | isDeleted: number; |
| | | drugInventoryAlertDays: number; |
| | | drugPriceIn: number; |
| | | drugStatus: number; |
| | | drugPriceCategory: number; |
| | | drugVsDiagnoseName: any | null; |
| | | drugSyncPrice: number; |
| | | deletedTime: any | null; |
| | | drugPackageUnitAliasName: string; |
| | | drugPinyin: string; |
| | | drugVsDiagnose: string; |
| | | drugGansuUseLimit: any | null; |
| | | drugProperty: string; |
| | | drugJixingName: string; |
| | | drugPriceSale: number; |
| | | updateUser: any | null; |
| | | drugTransfer1: any | null; |
| | | updateTime: number; |
| | | drugTransfer2: any | null; |
| | | drugUseType: string; |
| | | drugLimitUseType: number; |
| | | drugInventoryAlertValidDays: number; |
| | | createTime: number; |
| | | createUser: any | null; |
| | | drugMonitorCode: string; |
| | | drugPlusPercent: number; |
| | | drugInHospitalUseType: number; |
| | | drugSpecialProperty: number; |
| | | drugBaseType: number; |
| | | } |
| | | |
| | | interface OrderFromInfo { |
| | | code: string; |
| | | dictIsCustom: number; |
| | | updateUser: any | null; |
| | | remark: any | null; |
| | | updateTime: number; |
| | | dictNo: string; |
| | | dictType: string; |
| | | dictIsEnable: number; |
| | | isDeleted: number; |
| | | createTime: number; |
| | | hisCode: any | null; |
| | | sortOrder: number; |
| | | createUser: any | null; |
| | | id: number; |
| | | deletedTime: any | null; |
| | | dictText: string; |
| | | } |
| New file |
| | |
| | | <template> |
| | | <div class="bedside-auxiliary-screen-header"> |
| | | <div class="header-left"> |
| | | <!-- 没有设备编号 --> |
| | | <span v-if="pageType === 0" class="info-text">未绑定设备</span> |
| | | <template v-else> |
| | | <!-- 设备号 --> |
| | | <span class="info-text">{{ |
| | | bedsideAuxiliaryScreenStore.deviceData.devicdeNo |
| | | }}</span> |
| | | <!-- 加载中 --> |
| | | <span v-if="pageType === 1" class="info-text" |
| | | >页面初始化中,请耐心等待!</span |
| | | > |
| | | <!-- 未排班 --> |
| | | <span v-else-if="pageType === 2" class="info-text">当前尚未排班</span> |
| | | <!-- 有排班 --> |
| | | <template v-else> |
| | | <span class="info-text">{{ patientInfo.patientName }}</span> |
| | | <span class="info-text">{{ patientInfo.age }}岁</span> |
| | | <span class="info-text">{{ patientInfo.gender }}</span> |
| | | <span v-if="patientInfo.patFormNumber" class="info-text"> |
| | | {{ patientInfo.patForm }}:{{ patientInfo.patFormNumber }}</span |
| | | > |
| | | </template> |
| | | {{ taskCountdown }} |
| | | </template> |
| | | </div> |
| | | <div class="header-right"> |
| | | <img |
| | | :src="atRegularTimeImg" |
| | | class="btn-img" |
| | | alt="" |
| | | @click="openScheduledTaskDialog" |
| | | /> |
| | | <img |
| | | :src="setUpImg" |
| | | class="btn-img" |
| | | alt="" |
| | | @click="openSettingDeviceDialog" |
| | | /> |
| | | <img :src="userImg" class="btn-img" alt="" @click="openLoginDialog" /> |
| | | </div> |
| | | </div> |
| | | <!-- 设置设备编号组件 --> |
| | | <SettingDeviceDialog ref="settingDeviceDialogRef" /> |
| | | <!-- 定时任务组件 --> |
| | | <ScheduledTaskDialog ref="scheduledTaskDialogRef" /> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="Header"> |
| | | import { |
| | | ref, |
| | | computed, |
| | | defineAsyncComponent, |
| | | onMounted, |
| | | onUnmounted, |
| | | watch, |
| | | } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import type { Task } from "@/store/type/task.type"; |
| | | const SettingDeviceDialog = defineAsyncComponent( |
| | | () => import("./SettingDeviceDialog.vue") |
| | | ); |
| | | const ScheduledTaskDialog = defineAsyncComponent( |
| | | () => import("./ScheduledTask.vue") |
| | | ); |
| | | import atRegularTimeImg from "../../../../img/dingshi.png"; |
| | | import setUpImg from "../../../../img/shezhi.png"; |
| | | import userImg from "../../../../img/user.png"; |
| | | |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import { EPatForm } from "@/store/type/bedsideAuxiliaryScreen.type"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | let timer: number; |
| | | |
| | | const settingDeviceDialogRef = ref<any>(null); |
| | | const scheduledTaskDialogRef = ref<any>(null); |
| | | const taskCountdown = ref(""); // 定时任务倒计时文本 |
| | | |
| | | const pageType = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.deviceData.pageType; |
| | | }); |
| | | |
| | | const patientInfo = computed(() => { |
| | | return { |
| | | patientName: bedsideAuxiliaryScreenStore.deviceData.patientName, |
| | | patientPhone: bedsideAuxiliaryScreenStore.deviceData.patientPhone, |
| | | age: bedsideAuxiliaryScreenStore.deviceData.age, |
| | | gender: bedsideAuxiliaryScreenStore.deviceData.gender, |
| | | patForm: |
| | | bedsideAuxiliaryScreenStore.deviceData.patForm === |
| | | EPatForm.OUTPATIENT_SERVICE |
| | | ? "门诊号" |
| | | : "住院号", |
| | | patFormNumber: bedsideAuxiliaryScreenStore.deviceData.patFormNumber, |
| | | }; |
| | | }); |
| | | |
| | | watch( |
| | | () => bedsideAuxiliaryScreenStore.taskData, |
| | | (newData: Task[]) => { |
| | | console.log('定时任务更新了') |
| | | if ( |
| | | bedsideAuxiliaryScreenStore.deviceData.deviceCode && |
| | | newData.length > 0 |
| | | ) { |
| | | console.log('newData: ', newData) |
| | | updateCountdown(newData[0].taskDate); |
| | | } else { |
| | | taskCountdown.value = ""; |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ); |
| | | |
| | | const openSettingDeviceDialog = () => { |
| | | settingDeviceDialogRef.value?.openDialog(); |
| | | }; |
| | | |
| | | const openScheduledTaskDialog = () => { |
| | | scheduledTaskDialogRef.value?.openDialog(); |
| | | }; |
| | | |
| | | const openLoginDialog = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | |
| | | const getCountdown = (taskDate: string) => { |
| | | const now = dayjs(); |
| | | const target = dayjs(taskDate).second(0).millisecond(0); |
| | | |
| | | const diff = target.diff(now, "second"); |
| | | |
| | | if (diff <= 0) return ""; |
| | | |
| | | const minutes = Math.floor(diff / 60); |
| | | const seconds = diff % 60; |
| | | |
| | | return `${minutes}m${seconds}s`; |
| | | }; |
| | | |
| | | const updateCountdown = (taskDate: string) => { |
| | | taskCountdown.value = getCountdown(taskDate); |
| | | timer = window.setInterval(updateCountdown, 1000); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | if ( |
| | | bedsideAuxiliaryScreenStore.deviceData.deviceCode && |
| | | bedsideAuxiliaryScreenStore.taskData.length > 0 |
| | | ) { |
| | | getCountdown(bedsideAuxiliaryScreenStore.taskData[0].taskDate); |
| | | } |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | timer && clearInterval(timer); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .bedside-auxiliary-screen-header { |
| | | height: 25px; |
| | | padding: 0 15px 0 12px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | background: #70a3dd; |
| | | border-radius: 1px 0px 5px 5px; |
| | | .header-left { |
| | | display: flex; |
| | | align-items: center; |
| | | .info-text { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 11px; |
| | | color: #ffffff; |
| | | text-align: left; |
| | | font-style: normal; |
| | | &:not(:first-child) { |
| | | margin-left: 6px; |
| | | } |
| | | } |
| | | } |
| | | .header-right { |
| | | display: flex; |
| | | align-items: center; |
| | | .btn-img { |
| | | height: 10px; |
| | | object-fit: contain; |
| | | cursor: pointer; |
| | | &:not(:first-child) { |
| | | margin-left: 9px; |
| | | } |
| | | &:active { |
| | | opacity: 0.6; |
| | | transform: scale(0.95); |
| | | } |
| | | |
| | | transition: all 0.2s; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="progress-container" :style="{ backgroundColor: props.backgroundColor || '#d6def1' }"> |
| | | <div |
| | | class="progress-bar" |
| | | :style="{ |
| | | width: computedWidth, |
| | | backgroundColor: color, |
| | | borderRadius: '0 999px 999px 0', |
| | | }" |
| | | ></div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { computed } from "vue"; |
| | | |
| | | interface Props { |
| | | percent: number; // 0 ~ 100 |
| | | color?: string; |
| | | backgroundColor?: string; |
| | | borderRadius?: string; |
| | | } |
| | | |
| | | const props = defineProps<Props>(); |
| | | |
| | | const computedWidth = computed( |
| | | () => Math.min(Math.max(props.percent, 0), 100) + "%" |
| | | ); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .progress-container { |
| | | width: 46px; |
| | | height: 6px; |
| | | background: #d6def1; |
| | | border-radius: 999px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .progress-bar { |
| | | height: 100%; |
| | | transition: width 0.3s ease; |
| | | border-radius: 0 999px 999px 0; |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="scheduled-task-container"> |
| | | <el-dialog |
| | | v-model="isShow" |
| | | center |
| | | title="定时任务" |
| | | width="80%" |
| | | :show-close="false" |
| | | class="scheduled-task-dialog" |
| | | top="0" |
| | | > |
| | | <template #header> |
| | | <div class="scheduled-task-header"> |
| | | <span class="header-title">创建定时任务</span> |
| | | <img |
| | | :src="closeImg" |
| | | class="header-close" |
| | | @click="handleCancel" |
| | | alt="" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <div class="scheduled-task-content"> |
| | | <div class="content-left"> |
| | | <div class="content-left-date"> |
| | | <TimePicker v-model="timeValue" /> |
| | | <div class="date-btn"> |
| | | <div |
| | | v-for="(item, index) in dateOptions" |
| | | :key="index" |
| | | class="my-button date" |
| | | @click="onAddMinutesClick(item)" |
| | | > |
| | | {{ item.label }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="content-left-stereotyped-writing"> |
| | | <div class="stereotyped-writing"> |
| | | <input |
| | | v-model.trim="taskName" |
| | | type="text" |
| | | :disabled="isInpDisabled" |
| | | class="stereotyped-writing-input" |
| | | placeholder="请输入自定义内容" |
| | | /> |
| | | </div> |
| | | <div class="stereotyped-writing-list"> |
| | | <div |
| | | v-for="(item, index) in taskOptions" |
| | | :key="index" |
| | | class="my-button list-item" |
| | | @click="onStereotypedWritingClick(item)" |
| | | :class="taskItemCheck === item.value ? 'check' : ''" |
| | | > |
| | | {{ item.label }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="content-right"></div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="my-button cancel" @click="handleCancel">取消</div> |
| | | <div class="my-button confirm" @click="handleConfirm">确认</div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { computed, ref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { setTimeoutAlert } from "@/utils/httpApi"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | |
| | | // @ts-ignore |
| | | import TimePicker from "./TimePicker.vue"; |
| | | |
| | | import closeImg from "@/img/close.png"; |
| | | import alertbaojin from "@/assets/alert.wav"; |
| | | import cxybaojing from "@/assets/cxy.mp3"; |
| | | import gybaojing from "@/assets/gy.mp3"; |
| | | import kclbaojing from "@/assets/kcl.mp3"; |
| | | import tdddbaojing from "@/assets/tzddd.mp3"; |
| | | import tzxllbaojing from "@/assets/tzxll.mp3"; |
| | | import cgbaojing from "@/assets/cg.mp3"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | interface TaskItem { |
| | | label: string; |
| | | value: string; |
| | | backgroundColor: string; |
| | | promptTone: string; |
| | | } |
| | | |
| | | interface DateItem { |
| | | label: string; |
| | | value: number; |
| | | } |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const isShow = ref(false); |
| | | |
| | | const taskName = ref(""); // 任务名称 |
| | | const isInpDisabled = ref(false); // 输入框是否禁用 |
| | | |
| | | const timeValue = ref(""); |
| | | |
| | | const detaCheck = ref<number | null>(); // 这个是判断时间按钮的 |
| | | |
| | | const loading = ref(false); |
| | | |
| | | const taskOptions = ref<TaskItem[]>([ |
| | | { |
| | | label: "测血压", |
| | | value: "测血压", |
| | | backgroundColor: "#E6A23C", |
| | | promptTone: cxybaojing, |
| | | }, |
| | | { |
| | | label: "开超滤", |
| | | value: "开超滤", |
| | | backgroundColor: "#E6A23C", |
| | | promptTone: kclbaojing, |
| | | }, |
| | | { |
| | | label: "给药", |
| | | value: "给药", |
| | | backgroundColor: "#E6A23C", |
| | | promptTone: gybaojing, |
| | | }, |
| | | { |
| | | label: "调电导度", |
| | | value: "调电导度", |
| | | backgroundColor: "#E6A23C", |
| | | promptTone: tdddbaojing, |
| | | }, |
| | | { |
| | | label: "调血流量", |
| | | value: "调血流量", |
| | | backgroundColor: "#E6A23C", |
| | | promptTone: tzxllbaojing, |
| | | }, |
| | | { |
| | | label: "冲管", |
| | | value: "冲管", |
| | | backgroundColor: "#E6A23C", |
| | | promptTone: cgbaojing, |
| | | }, |
| | | ]); |
| | | |
| | | const dateOptions = ref<DateItem[]>([ |
| | | { label: "15分钟", value: 15 }, |
| | | { label: "30分钟", value: 30 }, |
| | | { label: "45分钟", value: 45 }, |
| | | { label: "60分钟", value: 60 }, |
| | | ]); |
| | | |
| | | const taskItemCheck = computed(() => { |
| | | return taskOptions.value.find((e) => e.value === taskName.value)?.value || ""; |
| | | }); |
| | | |
| | | const openDialog = () => { |
| | | isShow.value = true; |
| | | const time = dayjs(); |
| | | timeValue.value = time.format("HH:mm"); |
| | | }; |
| | | |
| | | const onStereotypedWritingClick = (item: TaskItem) => { |
| | | if (taskName.value === item.value) { |
| | | taskName.value = ""; |
| | | isInpDisabled.value = false; |
| | | } else { |
| | | taskName.value = item.value; |
| | | isInpDisabled.value = true; |
| | | } |
| | | }; |
| | | |
| | | const onAddMinutesClick = (item: DateItem) => { |
| | | // if (detaCheck.value === item.value) { |
| | | // detaCheck.value = null; |
| | | // timeValue.value = addMinutes(timeValue.value, -item.value) |
| | | // } else { |
| | | detaCheck.value = item.value; |
| | | timeValue.value = addMinutes(timeValue.value, item.value); |
| | | // console.log('addMinutes(timeValue.value, item.value): ', addMinutes(timeValue.value, item.value)) |
| | | // } |
| | | }; |
| | | |
| | | const addMinutes = (time: string, delta: number): string => { |
| | | const [hours, minutes] = time.split(":").map(Number); |
| | | const totalMinutes = hours * 60 + minutes + delta; |
| | | |
| | | // 处理负数和超过 1440(一天分钟数)情况 |
| | | const normalized = (totalMinutes + 1440) % 1440; |
| | | |
| | | const newHours = Math.floor(normalized / 60); |
| | | const newMinutes = normalized % 60; |
| | | |
| | | return `${newHours.toString().padStart(2, "0")}:${newMinutes |
| | | .toString() |
| | | .padStart(2, "0")}`; |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const handleConfirm = async () => { |
| | | const today = dayjs().format("YYYY-MM-DD"); |
| | | const fullDateTime = dayjs(`${today} ${timeValue.value}`).second(0).millisecond(0); // 秒和毫秒都去掉,要不然间隔短了就是0分钟 |
| | | |
| | | const now = dayjs().second(0).millisecond(0);; // 秒和毫秒都去掉 |
| | | if (!fullDateTime.isAfter(now)) |
| | | return ElMessage.warning("任务提醒时间不能早于或等于当前时间"); |
| | | if (!taskName.value) return ElMessage.warning("任务内容不能为空"); |
| | | loading.value = true; |
| | | try { |
| | | const diffMinutes = fullDateTime.diff(now, "minute"); |
| | | const params = { |
| | | deviceCode: bedsideAuxiliaryScreenStore.deviceData.deviceCode, |
| | | minutes: diffMinutes, |
| | | alertText: taskName.value, |
| | | } |
| | | const recordCode = bedsideAuxiliaryScreenStore.deviceData.recordCode; |
| | | const { data, message } = await setTimeoutAlert(params); |
| | | if (data !== "OK") return ElMessage.warning(message); |
| | | ElMessage.success('操作成功'); |
| | | bedsideAuxiliaryScreenStore.setSyncTask({ |
| | | deviceCode: params.deviceCode, |
| | | recordCode: recordCode, |
| | | taskDate: dayjs(fullDateTime).format("YYYY-MM-DD HH:mm"), |
| | | taskName: params.alertText, |
| | | overdue: false |
| | | }); |
| | | handleCancel(); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | * { |
| | | box-sizing: border-box; |
| | | } |
| | | .scheduled-task-container { |
| | | ::v-deep(.el-dialog) { |
| | | padding: 0; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | } |
| | | ::v-deep(.el-dialog__footer) { |
| | | padding: 4px; |
| | | } |
| | | ::v-deep(.el-upload-dragger) { |
| | | height: 65px; |
| | | padding: 0 !important; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | ::v-deep(.el-upload-dragger .el-icon--upload) { |
| | | display: none; |
| | | } |
| | | ::v-deep(.el-dialog__header) { |
| | | padding-bottom: 6px; |
| | | } |
| | | .scheduled-task-header { |
| | | position: relative; |
| | | height: 16px; |
| | | background: #ff7472; |
| | | .header-title { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translateX(-50%) translateY(-50%); |
| | | font-family: AlibabaPuHuiTi, AlibabaPuHuiTi; |
| | | font-weight: 500; |
| | | font-size: 8px; |
| | | color: #ffffff; |
| | | line-height: 11px; |
| | | text-align: center; |
| | | } |
| | | .header-close { |
| | | position: absolute; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | right: 6px; |
| | | width: 15px; |
| | | height: 15px; |
| | | transition: transform 0.2s; |
| | | |
| | | &:active { |
| | | opacity: 0.6; |
| | | transform: translateY(-50%) scale(0.95); |
| | | } |
| | | } |
| | | } |
| | | .scheduled-task-content { |
| | | padding: 0 12px 0px; |
| | | margin-bottom: 4px; |
| | | border-bottom: 1px solid #d8d8d8; |
| | | display: flex; |
| | | .content-left { |
| | | flex: 1; |
| | | border-right: 1px solid #d8d8d8; |
| | | padding-bottom: 6px; |
| | | padding-right: 12px; |
| | | .content-left-date { |
| | | border-bottom: 1px solid #d8d8d8; |
| | | display: flex; |
| | | |
| | | .date-btn { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 9px; |
| | | margin-left: 5px; |
| | | justify-content: flex-end; |
| | | .date { |
| | | margin-left: 0; |
| | | padding: 0; |
| | | width: 50px; |
| | | height: 23px; |
| | | line-height: 23px; |
| | | text-align: center; |
| | | font-size: 11px; |
| | | background-color: #769aff; |
| | | } |
| | | } |
| | | } |
| | | .content-left-stereotyped-writing { |
| | | .stereotyped-writing { |
| | | position: relative; |
| | | height: 16px; |
| | | padding-top: 6px; |
| | | margin-bottom: 6px; |
| | | border-radius: 2px; |
| | | border: 1px solid #979797; |
| | | overflow: hidden; |
| | | .stereotyped-writing-input { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | border: none; |
| | | outline: none; |
| | | padding: 0 4px; |
| | | line-height: 16px; |
| | | font-size: 9px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | vertical-align: middle; |
| | | box-sizing: border-box; // 避免padding撑高 |
| | | |
| | | &::placeholder { |
| | | font-family: inherit; |
| | | font-size: inherit; |
| | | line-height: inherit; |
| | | color: #aaaaaa; |
| | | opacity: 1; |
| | | } |
| | | &:disabled { |
| | | background-color: #f5f5f5; // 灰色背景 |
| | | color: #999999; // 灰色文字 |
| | | cursor: not-allowed; |
| | | } |
| | | } |
| | | } |
| | | .stereotyped-writing-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 7px; |
| | | .list-item { |
| | | width: 40px; |
| | | margin-left: 0; |
| | | padding-left: 0; |
| | | padding-right: 0; |
| | | background-color: #e6a23c; |
| | | &.check { |
| | | background-color: #bbc6dd; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .content-right { |
| | | width: 59px; |
| | | } |
| | | } |
| | | .my-button { |
| | | display: inline-block; |
| | | border-radius: 2px; |
| | | padding: 0px 10px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 7px; |
| | | color: #ffffff; |
| | | line-height: 16px; |
| | | letter-spacing: 1px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | transition: transform 0.1s ease, opacity 0.1s ease; |
| | | cursor: pointer; |
| | | &:active { |
| | | transform: scale(0.95); |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | &:not(:first-child) { |
| | | margin-left: 6px; |
| | | } |
| | | &.cancel { |
| | | background: #bbc6dd; |
| | | } |
| | | &.confirm { |
| | | background: #769aff; |
| | | } |
| | | &.refresh { |
| | | background: #e6a23c; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <style> |
| | | .scheduled-task-dialog { |
| | | margin: 0 auto; |
| | | top: 50% !important; |
| | | transform: translateY(-50%) !important; |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="setting-device-dialog-container"> |
| | | <el-dialog |
| | | v-model="isShow" |
| | | center |
| | | title="设置编号" |
| | | width="80%" |
| | | :show-close="false" |
| | | class="scheduled-task-dialog" |
| | | > |
| | | <template #header> |
| | | <div class="setting-dialog-header"> |
| | | <span class="header-title">设置编号</span> |
| | | <img |
| | | :src="closeImg" |
| | | class="header-close" |
| | | @click="handleCancel" |
| | | alt="" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <div class="setting-device-dialog-content"> |
| | | <div class="content-row1"> |
| | | <div class="row1-label">设备编号</div> |
| | | <div class="row1-inp-box"> |
| | | <input |
| | | v-model="devcieCode" |
| | | type="text" |
| | | class="row1-inp" |
| | | placeholder="请输入设备编号或扫码二维码" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="content-row2"> |
| | | <el-upload |
| | | v-loading="isUploading" |
| | | class="upload-demo" |
| | | drag |
| | | :show-file-list="false" |
| | | accept="image/*" |
| | | :limit="1" |
| | | :before-upload="onBeforeUpload" |
| | | > |
| | | <div class="el-upload__text"> |
| | | <img :src="uploadImg" class="upload-img" alt="" /> |
| | | <p class="upload-text">点击虚线区域选择文件并识别二维码</p> |
| | | <div class="upload-btn">二维码上传</div> |
| | | </div> |
| | | </el-upload> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="my-button cancel" @click="handleCancel">取消</div> |
| | | <div class="my-button confirm" @click="handleConfirm">确认</div> |
| | | <div class="my-button refresh" @click="handleRefresh">刷新</div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ElMessage, UploadRawFile } from "element-plus"; |
| | | import { ref } from "vue"; |
| | | import { |
| | | BrowserMultiFormatReader, |
| | | NotFoundException, |
| | | ChecksumException, |
| | | FormatException, |
| | | } from "@zxing/library"; |
| | | import closeImg from "@/img/close.png"; |
| | | import uploadImg from "@/img/upload.png"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const isShow = ref(false); |
| | | const isUploading = ref(false); |
| | | const devcieCode = ref(""); |
| | | |
| | | const openDialog = () => { |
| | | devcieCode.value = bedsideAuxiliaryScreenStore.deviceCode + ""; |
| | | isShow.value = true; |
| | | }; |
| | | |
| | | const onBeforeUpload = async (uploadFile: UploadRawFile) => { |
| | | const file = uploadFile; |
| | | if (!file) return; |
| | | |
| | | isUploading.value = true; |
| | | try { |
| | | const result = await decodeQRCodeFromFile(file); |
| | | devcieCode.value = result; |
| | | ElMessage.success("识别成功"); |
| | | } catch (err) { |
| | | if (err instanceof NotFoundException) { |
| | | ElMessage.error("未找到二维码"); |
| | | } else if (err instanceof ChecksumException) { |
| | | ElMessage.error("校验错误"); |
| | | } else if (err instanceof FormatException) { |
| | | ElMessage.error("格式错误"); |
| | | } else { |
| | | ElMessage.error("识别错误请重新识别"); |
| | | console.error(err); |
| | | } |
| | | } finally { |
| | | isUploading.value = false; |
| | | } |
| | | return false; |
| | | }; |
| | | |
| | | const decodeQRCodeFromFile = async (file: File): Promise<string> => { |
| | | return new Promise((resolve, reject) => { |
| | | const reader = new FileReader(); |
| | | |
| | | reader.onload = async (e: any) => { |
| | | const imageBase64 = e.target.result; |
| | | const codeReader = new BrowserMultiFormatReader(); |
| | | |
| | | try { |
| | | const result = await codeReader.decodeFromImage(undefined, imageBase64); |
| | | resolve(result.getText()); |
| | | } catch (err) { |
| | | reject(err); |
| | | } |
| | | }; |
| | | |
| | | reader.onerror = () => reject(new Error("读取文件失败")); |
| | | reader.readAsDataURL(file); |
| | | }); |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const handleConfirm = () => { |
| | | bedsideAuxiliaryScreenStore.setDeviceCode(devcieCode.value + ""); |
| | | handleRefresh(); |
| | | handleCancel(); |
| | | }; |
| | | |
| | | const handleRefresh = () => { |
| | | bedsideAuxiliaryScreenStore.refresh( |
| | | `${import.meta.env.VITE_SSE_BASE_URL}${devcieCode.value}` |
| | | ); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .setting-device-dialog-container { |
| | | ::v-deep(.el-dialog) { |
| | | padding: 0; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | } |
| | | ::v-deep(.el-dialog__footer) { |
| | | padding: 4px; |
| | | } |
| | | ::v-deep(.el-upload-dragger) { |
| | | height: 65px; |
| | | padding: 0 !important; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | ::v-deep(.el-upload-dragger .el-icon--upload) { |
| | | display: none; |
| | | } |
| | | ::v-deep(.el-dialog__header) { |
| | | padding-bottom: 6px; |
| | | } |
| | | .setting-dialog-header { |
| | | position: relative; |
| | | height: 16px; |
| | | background: #769aff; |
| | | .header-title { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translateX(-50%) translateY(-50%); |
| | | font-family: AlibabaPuHuiTi, AlibabaPuHuiTi; |
| | | font-weight: 500; |
| | | font-size: 8px; |
| | | color: #ffffff; |
| | | line-height: 11px; |
| | | text-align: center; |
| | | } |
| | | .header-close { |
| | | position: absolute; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | right: 6px; |
| | | width: 15px; |
| | | height: 15px; |
| | | transition: transform 0.2s; |
| | | |
| | | &:active { |
| | | opacity: 0.6; |
| | | transform: translateY(-50%) scale(0.95); |
| | | } |
| | | } |
| | | } |
| | | .setting-device-dialog-content { |
| | | padding: 0 12px 6px; |
| | | margin-bottom: 4px; |
| | | border-bottom: 1px solid #d8d8d8; |
| | | .content-row1 { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 6px; |
| | | |
| | | .row1-label { |
| | | margin-right: 6px; |
| | | padding: 0 4px; |
| | | background: #769aff; |
| | | border-radius: 2px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 8px; |
| | | line-height: 16px; |
| | | color: #ffffff; |
| | | font-style: normal; |
| | | } |
| | | .row1-inp-box { |
| | | flex: 1; |
| | | height: 16px; |
| | | border-radius: 2px; |
| | | border: 1px solid #979797; |
| | | overflow: hidden; |
| | | |
| | | .row1-inp { |
| | | width: 100%; |
| | | height: 100%; |
| | | border: none; |
| | | outline: none; |
| | | padding: 0 4px; |
| | | line-height: 16px; |
| | | font-size: 9px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | vertical-align: middle; |
| | | box-sizing: border-box; // 避免padding撑高 |
| | | |
| | | &::placeholder { |
| | | font-family: inherit; |
| | | font-size: inherit; |
| | | line-height: inherit; |
| | | color: #aaaaaa; |
| | | opacity: 1; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .el-upload__text { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | .upload-img { |
| | | height: 8px; |
| | | } |
| | | .upload-text { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 5px; |
| | | color: #5a6470; |
| | | letter-spacing: 0px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | } |
| | | .upload-btn { |
| | | padding: 0 2px; |
| | | background-color: #409eff; |
| | | border-radius: 1px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-size: 4px; |
| | | color: #fff; |
| | | letter-spacing: 0px; |
| | | line-height: 8px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .my-button { |
| | | display: inline-block; |
| | | border-radius: 2px; |
| | | padding: 0px 10px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 7px; |
| | | color: #ffffff; |
| | | line-height: 16px; |
| | | letter-spacing: 1px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | transition: transform 0.1s ease, opacity 0.1s ease; |
| | | cursor: pointer; |
| | | &:active { |
| | | transform: scale(0.95); |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | &:not(:first-child) { |
| | | margin-left: 6px; |
| | | } |
| | | &.cancel { |
| | | background: #bbc6dd; |
| | | } |
| | | &.confirm { |
| | | background: #769aff; |
| | | } |
| | | &.refresh { |
| | | background: #e6a23c; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <style> |
| | | .scheduled-task-dialog { |
| | | margin: 0 auto; |
| | | top: 50% !important; |
| | | transform: translateY(-50%) !important; |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="time-picker"> |
| | | <div class="picker-column" ref="hourRef" @scroll="onScroll('hour')"> |
| | | <div |
| | | v-for="(h, index) in loopHours" |
| | | :key="index" |
| | | class="picker-item hours" |
| | | :class="getClassByIndex(index, selectedIndexHour)" |
| | | :style="getStyleByIndex(index, selectedIndexHour)" |
| | | > |
| | | {{ h.toString().padStart(2, "0") }} |
| | | </div> |
| | | </div> |
| | | <span class="colon">:</span> |
| | | <div class="picker-column" ref="minuteRef" @scroll="onScroll('minute')"> |
| | | <div |
| | | v-for="(m, index) in loopMinutes" |
| | | :key="index" |
| | | class="picker-item minutes" |
| | | :class="getClassByIndex(index, selectedIndexMinute)" |
| | | :style="getStyleByIndex(index, selectedIndexMinute)" |
| | | > |
| | | {{ m.toString().padStart(2, "0") }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, watch, onMounted, nextTick } from "vue"; |
| | | |
| | | const props = defineProps<{ modelValue: string }>(); |
| | | const emit = defineEmits(["update:modelValue"]); |
| | | |
| | | const hours = Array.from({ length: 24 }, (_, i) => i); |
| | | const minutes = Array.from({ length: 60 }, (_, i) => i); |
| | | |
| | | // 为循环滚动,前面后面都各补两个,要不要选不中最后一个 |
| | | function createLoopArray(arr: number[]) { |
| | | return [...arr.slice(-2), ...arr, ...arr.slice(0, 2)]; |
| | | } |
| | | |
| | | const loopHours = createLoopArray(hours); |
| | | const loopMinutes = createLoopArray(minutes); |
| | | |
| | | const hourRef = ref<HTMLElement | null>(null); |
| | | const minuteRef = ref<HTMLElement | null>(null); |
| | | |
| | | const ITEM_REM = 0.4; |
| | | const itemHeight = remToPx(ITEM_REM); |
| | | |
| | | const selectedIndexHour = ref(2); |
| | | const selectedIndexMinute = ref(2); |
| | | |
| | | const selectedHour = ref(hours[0]); |
| | | const selectedMinute = ref(minutes[0]); |
| | | |
| | | // 标记程序主动滚动,防止滚动事件死循环 |
| | | const isProgrammaticScroll = { |
| | | hour: false, |
| | | minute: false, |
| | | }; |
| | | |
| | | // 初始化滚动,选中传入时间 |
| | | onMounted(() => { |
| | | const [h, m] = props.modelValue.split(":").map(Number); |
| | | const hourIdx = hours.indexOf(h); |
| | | const minuteIdx = minutes.indexOf(m); |
| | | |
| | | selectedIndexHour.value = hourIdx === -1 ? 2 : hourIdx + 2; |
| | | selectedIndexMinute.value = minuteIdx === -1 ? 2 : minuteIdx + 2; |
| | | |
| | | selectedHour.value = h; |
| | | selectedMinute.value = m; |
| | | |
| | | nextTick(() => { |
| | | scrollToSelected("hour", selectedIndexHour.value); |
| | | scrollToSelected("minute", selectedIndexMinute.value); |
| | | }); |
| | | }); |
| | | |
| | | watch( |
| | | () => |
| | | `${selectedHour.value.toString().padStart(2, "0")}:${selectedMinute.value |
| | | .toString() |
| | | .padStart(2, "0")}`, |
| | | (val) => { |
| | | emit("update:modelValue", val); |
| | | } |
| | | ); |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | (newVal) => { |
| | | const [h, m] = newVal.split(":").map(Number); |
| | | const hourIdx = hours.indexOf(h); |
| | | const minuteIdx = minutes.indexOf(m); |
| | | |
| | | if (hourIdx !== -1) { |
| | | selectedIndexHour.value = hourIdx + 2; |
| | | selectedHour.value = h; |
| | | scrollToSelected("hour", selectedIndexHour.value); |
| | | } |
| | | |
| | | if (minuteIdx !== -1) { |
| | | selectedIndexMinute.value = minuteIdx + 2; |
| | | selectedMinute.value = m; |
| | | scrollToSelected("minute", selectedIndexMinute.value); |
| | | } |
| | | } |
| | | ); |
| | | |
| | | function onScroll(type: "hour" | "minute") { |
| | | if (isProgrammaticScroll[type]) { |
| | | // 程序滚动,忽略,避免死循环 |
| | | isProgrammaticScroll[type] = false; |
| | | return; |
| | | } |
| | | |
| | | const refEl = type === "hour" ? hourRef.value : minuteRef.value; |
| | | if (!refEl) return; |
| | | |
| | | const scrollTop = refEl.scrollTop; |
| | | let index = Math.round(scrollTop / itemHeight + 2); |
| | | |
| | | const arrLen = type === "hour" ? hours.length : minutes.length; |
| | | |
| | | if (index < 2) { |
| | | isProgrammaticScroll[type] = true; |
| | | refEl.scrollTop = itemHeight * (arrLen + (index - 2)); |
| | | index = arrLen + (index - 2); |
| | | } else if (index > arrLen + 1) { |
| | | isProgrammaticScroll[type] = true; |
| | | refEl.scrollTop = itemHeight * (index - arrLen - 2); |
| | | index = index - arrLen - 2; |
| | | } |
| | | |
| | | if (type === "hour") { |
| | | selectedIndexHour.value = index; |
| | | selectedHour.value = loopHours[index]; |
| | | } else { |
| | | selectedIndexMinute.value = index; |
| | | selectedMinute.value = loopMinutes[index]; |
| | | } |
| | | } |
| | | |
| | | function scrollToSelected(type: "hour" | "minute", index: number) { |
| | | const refEl = type === "hour" ? hourRef.value : minuteRef.value; |
| | | if (!refEl) return; |
| | | |
| | | isProgrammaticScroll[type] = true; |
| | | refEl.scrollTo({ |
| | | top: (index - 2) * itemHeight, |
| | | behavior: "auto", |
| | | }); |
| | | } |
| | | |
| | | function getClassByIndex(index: number, selectedIndex: number) { |
| | | const diff = Math.abs(index - selectedIndex); |
| | | return { |
| | | active: diff === 0, |
| | | medium: diff === 1, |
| | | small: diff === 2, |
| | | }; |
| | | } |
| | | |
| | | function getStyleByIndex(index: number, selectedIndex: number) { |
| | | const diff = Math.min(Math.abs(index - selectedIndex), 2); |
| | | return { |
| | | opacity: diff === 2 ? 0.4 : 1, |
| | | zIndex: 10 - diff, |
| | | transition: "opacity 0.3s ease", |
| | | }; |
| | | } |
| | | |
| | | function remToPx(rem: number) { |
| | | return rem * parseFloat(getComputedStyle(document.documentElement).fontSize); |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .time-picker { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 2rem; // 5 * 0.4rem 每个item高度0.4rem |
| | | overflow: hidden; |
| | | |
| | | .picker-column { |
| | | height: 2rem; |
| | | width: 0.9rem; |
| | | overflow-y: scroll; |
| | | scroll-snap-type: y mandatory; |
| | | -webkit-overflow-scrolling: touch; |
| | | scrollbar-width: none; /* Firefox */ |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | &::-webkit-scrollbar { |
| | | display: none; /* Chrome Safari */ |
| | | } |
| | | |
| | | .picker-item { |
| | | height: 0.4rem; |
| | | line-height: 0.4rem; |
| | | text-align: center; |
| | | font-size: 0.24rem; |
| | | scroll-snap-align: center; |
| | | user-select: none; |
| | | cursor: pointer; |
| | | transition: color 0.3s ease, font-size 0.3s ease; |
| | | |
| | | &.active { |
| | | font-size: 0.5rem; |
| | | font-weight: 700; |
| | | color: #111; |
| | | &.hours { |
| | | text-align: left; |
| | | } |
| | | &.minutes { |
| | | text-align: right; |
| | | } |
| | | } |
| | | &.medium { |
| | | font-size: 0.3rem; |
| | | color: #666; |
| | | &.hours { |
| | | text-align: left; |
| | | padding-left: 0.2rem; |
| | | } |
| | | &.minutes { |
| | | text-align: right; |
| | | padding-right: 0.2rem; |
| | | } |
| | | } |
| | | &.small { |
| | | font-size: 0.24rem; |
| | | color: #aaa; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .colon { |
| | | font-size: 0.5rem; |
| | | font-weight: 600; |
| | | color: #444; |
| | | user-select: none; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="bedside-auxiliary-screen-container" :style="{ backgroundColor: backgroundColor }"> |
| | | <Header /> |
| | | <div class="bedside-auxiliary-screen-content"> |
| | | <div class="content-position"></div> |
| | | <!-- <UnplannedSchedule v-if="cotentHeight > 0" :height="cotentHeight" /> --> |
| | | <component v-if="cotentHeight > 0" :is="currentComponent" :height="cotentHeight" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref, watch, computed, onMounted, defineAsyncComponent } from "vue"; |
| | | // @ts-ignore |
| | | import Header from "./components/Header.vue"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import { EPageType } from '@/store/type/bedsideAuxiliaryScreen.type'; |
| | | import { getAvailableHeightByClass } from '@/utils/utils'; |
| | | import { useWindowSize } from '@/composables/useWindowSize'; |
| | | // 未排班时的组件 |
| | | const UnplannedSchedule = defineAsyncComponent(() => import('./pages/UnplannedSchedule.vue')); |
| | | // 未签到时的组件 |
| | | const NotSignedIn = defineAsyncComponent(() => import('./pages/NotSignedIn.vue')); |
| | | // 已签到时的组件 |
| | | const SignedIn = defineAsyncComponent(() => import('./pages/SignedIn.vue')); |
| | | // 治疗中的组件 |
| | | const UnderTreatment = defineAsyncComponent(() => import('./pages/UnderTreatment.vue')); |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | const cotentHeight = ref(0); |
| | | const { width, height } = useWindowSize(); |
| | | |
| | | |
| | | const backgroundColor = computed(() => { |
| | | let color = '#DAE5EC'; |
| | | // 如果是未排班、加载中或未签到页面,背景色为白色 |
| | | if ([EPageType.NOT_INIT, EPageType.LOADING, EPageType.UNPLANNED_SCHEDULE].includes(bedsideAuxiliaryScreenStore.deviceData.pageType)) { |
| | | color = '#fff'; |
| | | } |
| | | return color; |
| | | }); |
| | | |
| | | const currentComponent = computed(() => { |
| | | let name: any = UnplannedSchedule; |
| | | // 未排班 |
| | | if ([EPageType.NOT_INIT, EPageType.LOADING, EPageType.UNPLANNED_SCHEDULE].includes(bedsideAuxiliaryScreenStore.deviceData.pageType)) { |
| | | name = UnplannedSchedule; |
| | | } |
| | | // 未签到 |
| | | else if (bedsideAuxiliaryScreenStore.deviceData.pageType === EPageType.NOT_SIGNED_IN) { |
| | | name = NotSignedIn |
| | | } |
| | | // 已签到 |
| | | else if (bedsideAuxiliaryScreenStore.deviceData.pageType === EPageType.SIGNED_IN) { |
| | | name = SignedIn; |
| | | } |
| | | // 透析中 |
| | | else { |
| | | name = UnderTreatment; |
| | | } |
| | | return name; |
| | | }); |
| | | |
| | | watch([width, height], () => { |
| | | cotentHeight.value = getAvailableHeightByClass('content-position') |
| | | }); |
| | | |
| | | |
| | | onMounted(() => { |
| | | if (bedsideAuxiliaryScreenStore.deviceCode) { |
| | | bedsideAuxiliaryScreenStore.connect( |
| | | `${import.meta.env.VITE_SSE_BASE_URL}${ |
| | | bedsideAuxiliaryScreenStore.deviceCode |
| | | }` |
| | | ); |
| | | } |
| | | cotentHeight.value = getAvailableHeightByClass('content-position') |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | * { |
| | | margin: 0; |
| | | padding: 0; |
| | | box-sizing: border-box; |
| | | } |
| | | .bedside-auxiliary-screen-container { |
| | | background-color: #409eff; |
| | | .bedside-auxiliary-screen-content { |
| | | padding: 6px 12px 0; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="not-signed-in-container" :style="{ '--height': height + 'px' }"> |
| | | <div class="row1-container"> |
| | | <div class="row1-left"> |
| | | <el-image |
| | | :src="pageData.patientPhone" |
| | | style="width: 100%; height: 100%" |
| | | > |
| | | <template #placeholder> |
| | | <div class="image-slot">加载中<span class="dot">...</span></div> |
| | | </template> |
| | | </el-image> |
| | | </div> |
| | | <div class="row1-center"> |
| | | <div class="row1-center-row1"> |
| | | <Card |
| | | title="透析模式" |
| | | :icon="tslImg" |
| | | background-color="#E5EEFF" |
| | | class="row1-center-row1-item" |
| | | > |
| | | <div class="dialysis-mode-content"> |
| | | <span>{{ pageData.dialysisMode }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="治疗模式" |
| | | :icon="tslImg" |
| | | background-color="#F1EEFA" |
| | | class="row1-center-row1-item" |
| | | > |
| | | <div class="dialysis-mode-content item-2"> |
| | | <span>未签到</span> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <Card |
| | | title="一次性使用管路" |
| | | :icon="tslImg" |
| | | background-color="#D9F0E2" |
| | | class="row1-center-row2" |
| | | > |
| | | <div class="list-box-1"> |
| | | <div |
| | | v-for="(item, index) in pageData.pipingList" |
| | | :key="index" |
| | | class="list-item" |
| | | style="color: #3ab859" |
| | | > |
| | | <div class="list-item-left"> |
| | | {{ item.name }} |
| | | </div> |
| | | <div class="list-item-right">{{ item.数量 }}{{ item.单位 }}</div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="row1-right"> |
| | | <Card |
| | | title="透析器" |
| | | :icon="tslImg" |
| | | background-color="#F9DEDE" |
| | | class="row1-right-item" |
| | | > |
| | | <div class="list-box-1"> |
| | | <div |
| | | v-for="(item, index) in pageData.dialyzerList" |
| | | :key="index" |
| | | class="list-item" |
| | | > |
| | | <div class="list-item-left"> |
| | | {{ item.name }} |
| | | </div> |
| | | <div class="list-item-right">{{ item.数量 }}{{ item.单位 }}</div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="透析液" |
| | | :icon="tslImg" |
| | | background-color="#EFE5FF" |
| | | class="row1-right-item" |
| | | > |
| | | <div class="list-box-1"> |
| | | <div |
| | | v-for="(item, index) in pageData.dialysateList" |
| | | :key="index" |
| | | class="list-item" |
| | | > |
| | | <div class="list-item-left"> |
| | | {{ item.name }} |
| | | </div> |
| | | <div class="list-item-right">{{ item.数量 }}{{ item.单位 }}</div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | </div> |
| | | <div class="row2-container"> |
| | | <Card |
| | | title="抗凝剂" |
| | | :icon="tslImg" |
| | | background-color="#FFEDD2" |
| | | class="row-item" |
| | | > |
| | | <div class="list-box-2"> |
| | | <div |
| | | v-for="(item, index) in pageData.anticoagulant" |
| | | :key="index" |
| | | class="list-item" |
| | | > |
| | | <div class="list-item-name"> |
| | | {{ item.name }} |
| | | </div> |
| | | <div class="list-item-num"> |
| | | <span>首剂:{{ item.首剂 }}{{ item.单位 }}</span> |
| | | <span>追加/维持:{{ item.是否为追加 ? item.追加剂量 : item.维持剂量 }}{{ item.单位 }}</span> |
| | | <span>总量:{{ item.总量 }}{{ item.单位 }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="一次性使用透析护理包" |
| | | :icon="tslImg" |
| | | background-color="#E5EEFF" |
| | | class="row-item" |
| | | > |
| | | <div class="list-box-1"> |
| | | <div |
| | | v-for="(item, index) in pageData.carePackage" |
| | | :key="index" |
| | | class="list-item" |
| | | style="color: #1D77BD" |
| | | > |
| | | <div class="list-item-left"> |
| | | {{ item.name }} |
| | | </div> |
| | | <div class="list-item-right">{{ item.数量 }}{{ item.单位 }}</div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="row3-container"> |
| | | <Card |
| | | title="穿刺针" |
| | | :icon="tslImg" |
| | | background-color="#FFEDD2" |
| | | class="row-item" |
| | | > |
| | | <div class="list-box-1"> |
| | | <div |
| | | v-for="(item, index) in pageData.punctureNeedle" |
| | | :key="index" |
| | | class="list-item" |
| | | style="color: #A78718" |
| | | > |
| | | <div class="list-item-left"> |
| | | {{ item.name }} |
| | | </div> |
| | | <div class="list-item-right">{{ item.数量 }}{{ item.单位 }}</div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="血管通路" |
| | | :icon="tslImg" |
| | | background-color="#E5EEFF" |
| | | class="row-item" |
| | | > |
| | | <div class="list-box-1"> |
| | | <div |
| | | v-for="(item, index) in pageData.vascularAccess" |
| | | :key="index" |
| | | class="list-item" |
| | | style="color: #1D77BD" |
| | | > |
| | | <div class="list-item-left">{{ item.位置 }} {{ item.类型 }}</div> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="NotSignedIn"> |
| | | import { computed } from "vue"; |
| | | // @ts-ignore |
| | | import Card from "../components/Card.vue"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import tslImg from "@/img/tsl.png"; |
| | | |
| | | interface Props { |
| | | height: number; |
| | | } |
| | | const props = defineProps<Props>(); |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const pageData = computed(() => { |
| | | return Object.assign(bedsideAuxiliaryScreenStore.deviceData.notSignedIn, { |
| | | patientPhone: bedsideAuxiliaryScreenStore.deviceData.patientPhone, |
| | | }); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | * { |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .not-signed-in-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: var(--height); |
| | | gap: 4px; // 行间间距 |
| | | overflow: hidden; |
| | | padding-bottom: 2px; |
| | | |
| | | .row1-container { |
| | | display: flex; |
| | | flex: 59.3; // 59.3% |
| | | min-height: 0; |
| | | gap: 4px; // 行间间距 |
| | | |
| | | .row1-left { |
| | | width: 75px; |
| | | border-radius: 2px; |
| | | overflow: hidden; |
| | | } |
| | | .row1-center, |
| | | .row1-right { |
| | | flex: 1; |
| | | } |
| | | .row1-center { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; // 行间间距 |
| | | |
| | | .row1-center-row1 { |
| | | flex: 1; |
| | | display: flex; |
| | | gap: 4px; // 行间间距 |
| | | .row1-center-row1-item { |
| | | flex: 1; |
| | | .dialysis-mode-content { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 11px; |
| | | color: #3a75b8; |
| | | text-align: center; |
| | | font-style: normal; |
| | | &.item-2 { |
| | | color: #333; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .row1-center-row2 { |
| | | flex: 1; |
| | | } |
| | | } |
| | | .row1-right { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | .row1-right-item { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .row2-container, |
| | | .row3-container { |
| | | flex: 20.35; |
| | | min-height: 0; |
| | | display: flex; |
| | | gap: 4px; |
| | | .row-item { |
| | | flex: 1; |
| | | } |
| | | } |
| | | .list-box-1 { |
| | | .list-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-around; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 5px; |
| | | color: #a78718; |
| | | line-height: 6px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | .list-item-left { |
| | | flex: 1; |
| | | } |
| | | .list-item-right { |
| | | } |
| | | } |
| | | } |
| | | .list-box-2 { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 5px; |
| | | color: #A78718; |
| | | text-align: left; |
| | | font-style: normal; |
| | | .list-item { |
| | | &:not(:last-child) { |
| | | margin-bottom: 3px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="signed-in-container" :style="{ '--height': height + 'px' }"> |
| | | <div class="row1"> |
| | | <div class="row1-col1"> |
| | | <el-image |
| | | :src="pageData.patientPhone" |
| | | style="width: 100%; height: 100%" |
| | | > |
| | | <template #placeholder> |
| | | <div class="image-slot">加载中<span class="dot">...</span></div> |
| | | </template> |
| | | </el-image> |
| | | </div> |
| | | <div class="row1-col2"> |
| | | <Card |
| | | title="异常指标" |
| | | :icon="xinlvImg" |
| | | background-color="#ffffff" |
| | | header-class-name="mihi-header" |
| | | > |
| | | <div class="dialysis-mode-content"> |
| | | <span |
| | | v-for="(item, index) in pageData.abnormalItems" |
| | | :key="index" |
| | | class="abnormal-indicator" |
| | | :style="{ color: formatTestColr(item.结果标记) }" |
| | | > |
| | | {{ getItemName(item.项目名称) }} |
| | | {{ formatTestFlag(item.结果标记) }} |
| | | </span> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="row1-col3"> |
| | | <div class="row1-col3-row1"> |
| | | <Card |
| | | title="治疗模式" |
| | | :icon="zlmsImg" |
| | | background-color="#ffffff" |
| | | class="row1-col3-row1-item" |
| | | header-class-name="mihi-header" |
| | | > |
| | | <div class="item-box dialysis-mode-content"> |
| | | {{ pageData.dialysisPlan }} |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="治疗状态" |
| | | :icon="zlztImg" |
| | | background-color="#ffffff" |
| | | class="row1-col3-row1-item" |
| | | header-class-name="mihi-header" |
| | | > |
| | | <div class="item-box treatment-status">已签到</div> |
| | | </Card> |
| | | </div> |
| | | <Card |
| | | title="处方脱水量" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="row1-col3-row2" |
| | | header-class-name="mihi-header" |
| | | > |
| | | <div class="item-box prescription-ehydration-olume"> |
| | | {{ pageData.prescriptionDehydrationVolume }} L |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="row1-col4"> |
| | | <Card |
| | | title="透析器(显示规格)" |
| | | :icon="txqImg" |
| | | background-color="#ffffff" |
| | | class="row1-col4-row" |
| | | header-class-name="mihi-header" |
| | | > |
| | | <div class="item-box dialyzer"> |
| | | {{ pageData.dialyzer }} |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="脱水量详情" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="row1-col4-row" |
| | | header-class-name="mihi-header" |
| | | > |
| | | <div class="dehydrated-level"> |
| | | <div class="dehydrated-level-item"> |
| | | <span class="item-left" |
| | | >平均脱水量:{{ pageData.averageDehydrationRate }} L</span |
| | | > |
| | | <span class="item-right">(最近3周9次)</span> |
| | | </div> |
| | | <div class="dehydrated-level-item"> |
| | | <span class="item-left" |
| | | >最大脱水量:{{ pageData.maximumDehydrationCapacity }} L</span |
| | | > |
| | | <span class="item-right" |
| | | >({{ pageData.maximumDehydrationCapacityDate }})</span |
| | | > |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | </div> |
| | | <div class="row2"> |
| | | <Card |
| | | title="干体重" |
| | | :icon="tizhongImg" |
| | | background-color="#ffffff" |
| | | class="row2-item" |
| | | header-class-name="big-header" |
| | | > |
| | | <div class="weight-box"> |
| | | <span class="weight-text">{{ pageData.dryWeight }}</span> |
| | | <span class="unit-text">kg</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="透前体重" |
| | | :icon="tizhongImg" |
| | | background-color="#ffffff" |
| | | class="row2-item" |
| | | header-class-name="big-header" |
| | | > |
| | | <div class="weight-box"> |
| | | <span class="weight-text">{{ pageData.preDialysisWeight }}</span> |
| | | <span class="unit-text">kg</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="上次透后体重" |
| | | :icon="tizhongImg" |
| | | background-color="#ffffff" |
| | | class="row2-item" |
| | | header-class-name="big-header" |
| | | > |
| | | <div class="weight-box"> |
| | | <span class="weight-text">{{ |
| | | pageData.weightAfterLastDialysis |
| | | }}</span> |
| | | <span class="unit-text">kg</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="体重增长" |
| | | :icon="tizhongImg" |
| | | background-color="#ffffff" |
| | | class="row2-item" |
| | | header-class-name="big-header" |
| | | > |
| | | <div class="weight-box"> |
| | | <span v-if="pageData.weightIncreaseRate > 0" class="weight-text">+</span> |
| | | <span class="weight-text">{{ pageData.weightIncrease }}</span> |
| | | <span class="unit-text">kg</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="增长率" |
| | | :icon="tizhongImg" |
| | | background-color="#ffffff" |
| | | class="row2-item" |
| | | header-class-name="big-header" |
| | | > |
| | | <div class="weight-box"> |
| | | <span class="weight-text">{{ pageData.weightIncreaseRate }}</span> |
| | | <span class="unit-text">%</span> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="row3"> |
| | | <BlockBotttom |
| | | :icon="dingShiImg" |
| | | text="定时任务" |
| | | backgroundColor="#20C6B6" |
| | | @click="() => onScheduledTasksClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | :icon="jiaoHaoImg" |
| | | text="叫号" |
| | | backgroundColor="#20C6B6" |
| | | @click="() => onCallBumberClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | :icon="kaiShiImg" |
| | | text="开始" |
| | | backgroundColor="#409EFF" |
| | | @click="() => onStartClick()" |
| | | class="btn" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup name="SignedIn"> |
| | | import { computed } from "vue"; |
| | | // @ts-ignore |
| | | import Card from "../components/Card.vue"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import tslImg from "@/img/tsl.png"; |
| | | import dingShiImg from "@/img/dingshi2.png"; |
| | | import jiaoHaoImg from "@/img/jiaoHao.png"; |
| | | import kaiShiImg from "@/img/kaiShi.png"; |
| | | import xinlvImg from "@/img/xinlv.png"; |
| | | import zlmsImg from "@/img/zlms.png"; |
| | | import zlztImg from '@/img/txzt.png'; |
| | | import cljdImg from "@/img/cljd.png"; |
| | | import txqImg from "@/img/txq.png"; |
| | | import tizhongImg from "@/img/tizhong.png"; |
| | | |
| | | import { |
| | | getItemName, |
| | | formatTestColr, |
| | | formatTestFlag, |
| | | } from "@/store/type/bedsideAuxiliaryScreen.type"; |
| | | // @ts-ignore |
| | | import BlockBotttom from "../components/BlockBotttom.vue"; |
| | | import { ElMessage } from "element-plus/es"; |
| | | |
| | | interface Props { |
| | | height: number; |
| | | } |
| | | const props = defineProps<Props>(); |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const pageData = computed(() => { |
| | | return Object.assign(bedsideAuxiliaryScreenStore.deviceData.signedIn, { |
| | | patientPhone: bedsideAuxiliaryScreenStore.deviceData.patientPhone, |
| | | }); |
| | | }); |
| | | |
| | | /** 点击定时任务 */ |
| | | const onScheduledTasksClick = () => {}; |
| | | |
| | | const onCallBumberClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | |
| | | const onStartClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | </script> |
| | | <style lang="less" scoped> |
| | | * { |
| | | box-sizing: border-box; |
| | | } |
| | | .signed-in-container { |
| | | position: relative; |
| | | height: var(--height); |
| | | overflow: hidden; |
| | | .row1 { |
| | | height: 37.44%; |
| | | margin-bottom: 4px; |
| | | overflow: hidden; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .row1-col1 { |
| | | flex: 0 0 14.86%; |
| | | height: 100%; |
| | | border-radius: 2px; |
| | | overflow: hidden; |
| | | } |
| | | .row1-col2 { |
| | | flex: 0 0 32.86%; |
| | | height: 100%; |
| | | .dialysis-mode-content { |
| | | height: 100%; |
| | | .abnormal-indicator { |
| | | display: inline-block; |
| | | margin-right: 6px; |
| | | margin-bottom: 4px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 5px; |
| | | line-height: 6px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | } |
| | | .row1-col3 { |
| | | flex: 0 0 23.71%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | .row1-col3-row1 { |
| | | flex: 1; |
| | | display: flex; |
| | | gap: 4px; |
| | | .row1-col3-row1-item { |
| | | flex: 1; |
| | | } |
| | | } |
| | | .row1-col3-row2 { |
| | | flex: 1; |
| | | } |
| | | } |
| | | .row1-col4 { |
| | | flex: 0 0 25.14%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | .row1-col4-row { |
| | | flex: 1; |
| | | .dehydrated-level { |
| | | padding-left: 6px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .dehydrated-level-item { |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | .item-left { |
| | | flex: 1; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 4px; |
| | | color: #333333; |
| | | line-height: 6px; |
| | | font-style: normal; |
| | | } |
| | | .item-right { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 4px; |
| | | color: #777777; |
| | | line-height: 6px; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .row2 { |
| | | height: 21.72%; |
| | | overflow: hidden; |
| | | display: flex; |
| | | gap: 4px; |
| | | .row2-item { |
| | | flex: 1; |
| | | |
| | | .weight-box { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: center; |
| | | gap: 2px; |
| | | align-items: baseline; |
| | | .weight-text { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 11px; |
| | | color: #333333; |
| | | text-align: center; |
| | | font-style: normal; |
| | | } |
| | | .unit-text { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 7px; |
| | | color: #333333; |
| | | text-align: center; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .row3 { |
| | | position: absolute; |
| | | width: 100%; |
| | | bottom: 2px; |
| | | height: 13.33%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | padding-right: 13px; |
| | | overflow: hidden; |
| | | background: #ffffff; |
| | | border-radius: 2px; |
| | | .btn { |
| | | margin-left: 9px; |
| | | } |
| | | } |
| | | .item-box { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 8px; |
| | | color: #70a3dd; |
| | | text-align: center; |
| | | font-style: normal; |
| | | &.dialysis-mode-content { |
| | | color: #d58e56; |
| | | } |
| | | &.treatment-status { |
| | | color: #70a3dd; |
| | | } |
| | | &.prescription-ehydration-olume { |
| | | color: #8079cb; |
| | | } |
| | | } |
| | | // card header class |
| | | :deep(.mihi-header) { |
| | | flex: 0 0 4px; |
| | | .card-icon { |
| | | width: 4px; |
| | | height: 4px; |
| | | } |
| | | .card-title { |
| | | font-size: 4px; |
| | | } |
| | | } |
| | | :deep(.big-header) { |
| | | flex: 0 0 9px; |
| | | .card-icon { |
| | | width: 9px; |
| | | height: 9px; |
| | | } |
| | | .card-title { |
| | | font-size: 5px; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="under-treatment-container" :style="{ '--height': height + 'px' }"> |
| | | <div class="left-box"> |
| | | <div class="left-row1"> |
| | | <div class="left-row1-col1"> |
| | | <el-image |
| | | :src="pageData.patientPhone" |
| | | style="width: 100%; height: 100%" |
| | | > |
| | | <template #placeholder> |
| | | <div class="image-slot">加载中<span class="dot">...</span></div> |
| | | </template> |
| | | </el-image> |
| | | </div> |
| | | <div class="left-row1-col2"> |
| | | <Card |
| | | title="治疗模式" |
| | | :icon="zlmsImg" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row1-col2-row1" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box dialysis-mode-content"> |
| | | <div class="dialysis-mode-content-box"> |
| | | <span class="mini-text">{{ |
| | | formatSubstituteMode(pageData.substituteMode) |
| | | }}</span> |
| | | <span class="text">{{ pageData.dialysisPlan }}</span> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="处方备注" |
| | | :icon="zlmsImg" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row1-col2-item-row2" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="prescription-remarks"> |
| | | {{ pageData.prescriptionRemarks }} |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="left-row1-col3"> |
| | | <Card |
| | | title="透析器" |
| | | :icon="txqImg" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row1-col3-row1" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box prescription-ehydration-olume"> |
| | | <span class="text">{{ pageData.dialyzer }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="异常指标" |
| | | :icon="xinlvImg" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row1-col3-row2" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="dialysis-mode-content"> |
| | | <span |
| | | v-for="(item, index) in pageData.abnormalItems" |
| | | :key="index" |
| | | class="abnormal-indicator" |
| | | :style="{ color: formatTestColr(item.结果标记) }" |
| | | > |
| | | {{ getItemName(item.项目名称) }} |
| | | {{ formatTestFlag(item.结果标记) }} |
| | | </span> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | </div> |
| | | <div class="left-row2"> |
| | | <Card |
| | | title="血温监测" |
| | | :icon="xinLv2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row2-col1" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box current-lood0emperature"> |
| | | <span class="text">{{ pageData.currentBloodTemperature }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="血压监测" |
| | | :icon="xinLv2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row2-col2" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box venous-pressure"> |
| | | <span class="text" |
| | | >{{ pageData.venousPressure }}/{{ |
| | | pageData.transmembranePressure |
| | | }}</span |
| | | > |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="血压脉搏趋势图" |
| | | :icon="xinLv2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card ktv-card left-row2-col3" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div style="height: 100%"> |
| | | <div |
| | | ref="bloodPressureAndPulseEchartRef" |
| | | style="width: 100%; height: 100%" |
| | | ></div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="left-row3"> |
| | | <Card |
| | | title="血容量监测" |
| | | :icon="xinLv2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row3-col1" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box current-lood0emperature"> |
| | | <span class="text">{{ pageData.bloodVolumeMonitoring }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="KTV监测" |
| | | :icon="xinLv2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row3-col2" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box venous-pressure"> |
| | | <span class="text">{{ pageData.ktv }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="KTV趋势图" |
| | | :icon="xinLv2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card ktv-card left-row3-col3" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div style="height: 100%"> |
| | | <div ref="ktvListEchartRef" style="width: 100%; height: 100%"></div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="left-row4"> |
| | | <Card |
| | | title="血流量" |
| | | :icon="txqImg" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row4-col" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box current-lood0emperature"> |
| | | <span class="text">{{ pageData.bloodFlow }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="透析液流量" |
| | | :icon="txqImg" |
| | | background-color="#ffffff" |
| | | class="mini-card left-row4-col" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box current-lood0emperature"> |
| | | <span class="text">{{ pageData.dialysisFluidFlowRate }}</span> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | </div> |
| | | <div class="right-box"> |
| | | <div class="right-box-row1"> |
| | | <Card |
| | | title="治疗状态" |
| | | :icon="txztImg" |
| | | background-color="#ffffff" |
| | | class="mini-card right-box-row1-col1" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="item-box treatment-status"> |
| | | <span class="text">{{ treatmentStatusText }}</span> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="脱水量详情" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card right-box-row1-col2" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="dehydrated-level"> |
| | | <div class="dehydrated-level-item"> |
| | | <span class="item-left" |
| | | >平均脱水量:{{ pageData.averageDehydrationRate }} L</span |
| | | > |
| | | <span class="item-right">(最近3周9次)</span> |
| | | </div> |
| | | <div class="dehydrated-level-item"> |
| | | <div class="item-left"> |
| | | <span |
| | | >最大脱水量:{{ pageData.maximumDehydrationCapacity }} L</span |
| | | > |
| | | <template v-if="pageData.maximumDehydrationDuration" |
| | | >/ |
| | | <span class="level-dete">{{ |
| | | pageData.maximumDehydrationDuration |
| | | }}</span> |
| | | </template> |
| | | </div> |
| | | <span class="item-right" |
| | | >({{ pageData.maximumDehydrationCapacityDate }})</span |
| | | > |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="right-box-row2"> |
| | | <Card |
| | | title="时间进度" |
| | | :icon="sjjdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card right-box-row2-item" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="progress-box"> |
| | | <div class="item-num"> |
| | | {{ jgTime4(pageData.dialysisDuration) }}/{{ |
| | | pageData.prescriptionDialysisDuration |
| | | }}:{{ pageData.prescriptionDialysisDurationMin }} |
| | | </div> |
| | | <ProgressBar |
| | | :percent=" |
| | | (Number(pageData.dialysisDuration) / |
| | | (Number(pageData.prescriptionDialysisDuration) * 60)) * |
| | | 100 |
| | | " |
| | | color="#70A3DD" |
| | | backgroundColor="#D6DEF1" |
| | | borderRadius="50%" |
| | | /> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="超滤进度" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card right-box-row2-item" |
| | | header-class-name="mini-header" |
| | | > |
| | | <div class="progress-box"> |
| | | <div class="item-num"> |
| | | {{ pageData.currentDehydrationVolume }}/{{ |
| | | pageData.currentDehydrationVolume |
| | | }}({{ pageData.currentUltrafiltrationRate }}) |
| | | </div> |
| | | <ProgressBar |
| | | :percent=" |
| | | (pageData.currentDehydrationVolume / |
| | | pageData.prescriptionDehydrationVolume) * |
| | | 100 |
| | | " |
| | | color="#70CAAE" |
| | | backgroundColor="#D6DEF1" |
| | | borderRadius="50%" |
| | | /> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="right-box-row3"> |
| | | <Card |
| | | title="临时医嘱" |
| | | :icon="yizhuImg" |
| | | background-color="#ffffff" |
| | | class="mini-card right-box-row2-item" |
| | | header-class-name="mini-header" |
| | | > |
| | | <DoctorAdvice :list="pageData.doctorAdvice" /> |
| | | </Card> |
| | | </div> |
| | | <div class="right-box-row4"> |
| | | <BlockBotttom |
| | | :icon="dingShiImg" |
| | | text="定时任务" |
| | | backgroundColor="#20C6B6" |
| | | @click="() => onScheduledTasksClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | :icon="jiaoHaoImg" |
| | | text="叫号" |
| | | backgroundColor="#20C6B6" |
| | | @click="() => onCallBumberClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | :icon="addImg" |
| | | text="添加记录" |
| | | backgroundColor="#409EFF" |
| | | @click="() => onAddRecordClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | v-if="!whetherDialysisHasBeenEnded" |
| | | :icon="kaiShiImg" |
| | | text="结束透析" |
| | | backgroundColor="#E6A23C" |
| | | @click="() => onEndClick()" |
| | | class="btn" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup name="UnderTreatment"> |
| | | import { computed, ref, onMounted, onBeforeUnmount, watch } from "vue"; |
| | | import * as echarts from "echarts"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | // @ts-ignore |
| | | import Card from "../components/Card.vue"; |
| | | // @ts-ignore |
| | | import ProgressBar from "../components/ProgressBar.vue"; |
| | | import DoctorAdvice from "../components/DoctorAdvice/index.vue"; |
| | | // @ts-ignore |
| | | import BlockBotttom from "../components/BlockBotttom.vue"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import { |
| | | formatSubstituteMode, |
| | | formatTestColr, |
| | | getItemName, |
| | | formatTestFlag, |
| | | EMedStatus, |
| | | } from "@/store/type/bedsideAuxiliaryScreen.type"; |
| | | import type { |
| | | KtvItem, |
| | | MonitoringRecord, |
| | | } from "@/store/type/bedsideAuxiliaryScreen.type"; |
| | | import { formatDate, jgTime4, jgTime5 } from "@/utils/formatTime"; |
| | | import zlmsImg from "@/img/zlms.png"; |
| | | import dingShiImg from "@/img/dingshi2.png"; |
| | | import jiaoHaoImg from "@/img/jiaoHao.png"; |
| | | import kaiShiImg from "@/img/kaiShi.png"; |
| | | import addImg from "@/img/add.png"; |
| | | import txqImg from "@/img/txq.png"; |
| | | import xinlvImg from "@/img/xinlv.png"; |
| | | import xinLv2Img from "@/img/xinlv2.png"; |
| | | import txztImg from "@/img/txzt.png"; |
| | | import cljdImg from "@/img/cljd.png"; |
| | | import sjjdImg from "@/img/sjjd.png"; |
| | | import yizhuImg from "@/img/yizhu.png"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | interface Props { |
| | | height: number; |
| | | } |
| | | const props = defineProps<Props>(); |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | // ktv趋势图的 |
| | | const ktvListEchartRef = ref<HTMLElement | null>(null); |
| | | // 血压脉搏趋势图的 |
| | | const bloodPressureAndPulseEchartRef = ref<HTMLElement | null>(null); |
| | | |
| | | const pageData = computed(() => { |
| | | return Object.assign(bedsideAuxiliaryScreenStore.deviceData.underTreatment, { |
| | | patientPhone: bedsideAuxiliaryScreenStore.deviceData.patientPhone, |
| | | }); |
| | | }); |
| | | |
| | | const treatmentStatusText = computed(() => { |
| | | const status = +bedsideAuxiliaryScreenStore.deviceData.treatmentStatus; |
| | | if (status === EMedStatus.NOT_CHECKED_IN) return "未签到"; |
| | | if (status === EMedStatus.SIGNED_IN) return "已签到"; |
| | | if (status === EMedStatus.DURING_DIALYSIS) return "透析中"; |
| | | if (status === EMedStatus.END) return "已结束"; |
| | | if (status === EMedStatus.CHECKED) return "已检查"; |
| | | if (status === EMedStatus.ARCHIVED) return "已归档"; |
| | | return "未知状态"; |
| | | }); |
| | | |
| | | /** 是否已结束透析 */ |
| | | const whetherDialysisHasBeenEnded = computed(() => { |
| | | return ( |
| | | +bedsideAuxiliaryScreenStore.deviceData.treatmentStatus >= EMedStatus.END |
| | | ); |
| | | }); |
| | | |
| | | watch( |
| | | () => pageData.value.ktvList, |
| | | (newVal) => { |
| | | generateKtvListEchart(newVal); |
| | | }, |
| | | { deep: true } |
| | | ); |
| | | |
| | | watch( |
| | | () => pageData.value.monitoringRecord, |
| | | (newVal) => { |
| | | generatBloodPressureAndPulseEchart(newVal); |
| | | }, |
| | | { deep: true } |
| | | ); |
| | | |
| | | /** 生成ktv趋势图 */ |
| | | const generateKtvListEchart = (ktvList: KtvItem[]) => { |
| | | if (!ktvListEchartRef.value) return; |
| | | // if (!ktvList || ktvList.length === 0) return; |
| | | |
| | | // 检查是否已经有实例 |
| | | let chart = echarts.getInstanceByDom(ktvListEchartRef.value); |
| | | if (!chart) { |
| | | chart = echarts.init(ktvListEchartRef.value); |
| | | } |
| | | |
| | | const option = { |
| | | grid: { |
| | | top: 6, |
| | | bottom: 20, |
| | | right: 20, |
| | | }, |
| | | xAxis: { |
| | | type: "category", |
| | | data: ktvList.map((item) => dayjs(item.时间).format("HH:mm")), |
| | | axisLine: { show: true }, |
| | | axisTick: { show: true }, |
| | | splitLine: { show: false }, |
| | | }, |
| | | yAxis: { |
| | | type: "value", |
| | | axisLine: { show: true }, |
| | | axisTick: { show: true }, |
| | | splitLine: { show: false }, |
| | | |
| | | splitNumber: 4, |
| | | }, |
| | | series: [ |
| | | { |
| | | data: ktvList.map((item) => item.ktv), |
| | | type: "line", |
| | | smooth: false, |
| | | symbol: "circle", |
| | | symbolSize: 6, |
| | | lineStyle: { |
| | | width: 2, |
| | | color: "#70CAAE", |
| | | }, |
| | | itemStyle: { |
| | | color: "#70CAAE", |
| | | }, |
| | | }, |
| | | ], |
| | | tooltip: { |
| | | trigger: "axis", |
| | | }, |
| | | }; |
| | | |
| | | chart.setOption(option, true); // 第二个参数为 true 表示全量更新 |
| | | }; |
| | | |
| | | /** 生成血压脉搏趋势图 */ |
| | | const generatBloodPressureAndPulseEchart = ( |
| | | bloodPressureAndPulses: MonitoringRecord[] |
| | | ) => { |
| | | if (!bloodPressureAndPulseEchartRef.value) return; |
| | | |
| | | let chart = echarts.getInstanceByDom(bloodPressureAndPulseEchartRef.value); |
| | | if (!chart) { |
| | | chart = echarts.init(bloodPressureAndPulseEchartRef.value); |
| | | } |
| | | |
| | | const telescopicPressureDatas: number[] = []; // 伸缩压 |
| | | const diastolicPressureDatas: number[] = []; // 舒张压 |
| | | const pulseDatas: number[] = []; // 脉搏 |
| | | const xAxisData: string[] = []; // 横坐标 |
| | | |
| | | bloodPressureAndPulses.forEach((item, index) => { |
| | | telescopicPressureDatas.push(+item.伸缩压); |
| | | diastolicPressureDatas.push(+item.舒张压); |
| | | pulseDatas.push(+item.脉搏); |
| | | xAxisData.push(String(index + 1)); |
| | | }); |
| | | |
| | | const option = { |
| | | grid: [ |
| | | { top: "10%", height: "25%", left: 30, right: 20 }, |
| | | { top: "38%", height: "25%", left: 30, right: 20 }, |
| | | { top: "66%", height: "25%", left: 30, right: 20 }, |
| | | ], |
| | | tooltip: { |
| | | trigger: "axis", |
| | | }, |
| | | xAxis: [ |
| | | { |
| | | type: "category", |
| | | data: xAxisData, |
| | | boundaryGap: false, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | axisLabel: { show: false }, |
| | | splitLine: { show: false }, |
| | | gridIndex: 0, |
| | | }, |
| | | { |
| | | type: "category", |
| | | data: xAxisData, |
| | | boundaryGap: false, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | axisLabel: { show: false }, |
| | | splitLine: { show: false }, |
| | | gridIndex: 1, |
| | | }, |
| | | { |
| | | type: "category", |
| | | data: xAxisData, |
| | | boundaryGap: false, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | axisLabel: { show: true }, // 最下面一层显示时间轴 |
| | | splitLine: { show: false }, |
| | | gridIndex: 2, |
| | | }, |
| | | ], |
| | | yAxis: [ |
| | | { |
| | | type: "value", |
| | | show: false, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | axisLabel: { show: false }, |
| | | splitLine: { show: false }, |
| | | min: "dataMin", // 自动以数据最小值为最小值 |
| | | max: "dataMax", |
| | | gridIndex: 0, |
| | | }, |
| | | { |
| | | type: "value", |
| | | show: false, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | axisLabel: { show: false }, |
| | | splitLine: { show: false }, |
| | | min: "dataMin", // 自动以数据最小值为最小值 |
| | | max: "dataMax", |
| | | gridIndex: 1, |
| | | }, |
| | | { |
| | | type: "value", |
| | | show: false, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | axisLabel: { show: false }, |
| | | splitLine: { show: false }, |
| | | min: "dataMin", // 自动以数据最小值为最小值 |
| | | max: "dataMax", |
| | | gridIndex: 2, |
| | | }, |
| | | ], |
| | | series: [ |
| | | { |
| | | name: "伸缩压", |
| | | xAxisIndex: 0, |
| | | yAxisIndex: 0, |
| | | data: wrapData(telescopicPressureDatas), |
| | | type: "line", |
| | | smooth: false, |
| | | symbol: "circle", |
| | | symbolSize: 6, |
| | | lineStyle: { width: 2, color: "#FE0201" }, |
| | | itemStyle: { color: "#FE0201" }, |
| | | label: { color: "#FE0201" }, |
| | | }, |
| | | { |
| | | name: "舒张压", |
| | | xAxisIndex: 1, |
| | | yAxisIndex: 1, |
| | | data: wrapData(diastolicPressureDatas), |
| | | type: "line", |
| | | smooth: false, |
| | | symbol: "circle", |
| | | symbolSize: 6, |
| | | lineStyle: { width: 2, color: "#70A3DD" }, |
| | | itemStyle: { color: "#70A3DD" }, |
| | | label: { color: "#70A3DD" }, |
| | | }, |
| | | { |
| | | name: "脉搏", |
| | | xAxisIndex: 2, |
| | | yAxisIndex: 2, |
| | | data: wrapData(pulseDatas), |
| | | type: "line", |
| | | smooth: false, |
| | | symbol: "circle", |
| | | symbolSize: 6, |
| | | lineStyle: { width: 2, color: "#8079CB" }, |
| | | itemStyle: { color: "#8079CB" }, |
| | | label: { color: "#8079CB" }, |
| | | }, |
| | | ], |
| | | }; |
| | | |
| | | chart.setOption(option); |
| | | }; |
| | | |
| | | // 给首尾点加上 label |
| | | const wrapData = (arr: number[]) => { |
| | | return arr.map((v, i) => ({ |
| | | value: v, |
| | | label: { |
| | | show: i === 0 || i === arr.length - 1, |
| | | position: "top", |
| | | fontSize: 12, |
| | | }, |
| | | })); |
| | | }; |
| | | |
| | | /** 定时任务 */ |
| | | const onScheduledTasksClick = () => {}; |
| | | |
| | | /** 叫号 */ |
| | | const onCallBumberClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | |
| | | /** 添加记录 */ |
| | | const onAddRecordClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | |
| | | /** 结束透析 */ |
| | | const onEndClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | // 生成ktv趋势图 |
| | | generateKtvListEchart(pageData.value.ktvList); |
| | | generatBloodPressureAndPulseEchart(pageData.value.monitoringRecord); |
| | | }); |
| | | |
| | | onBeforeUnmount(() => { |
| | | // 销毁图表实例 |
| | | if (ktvListEchartRef.value) { |
| | | const chart = echarts.getInstanceByDom(ktvListEchartRef.value); |
| | | if (chart) { |
| | | chart.dispose(); |
| | | } |
| | | } |
| | | if (bloodPressureAndPulseEchartRef.value) { |
| | | const chart = echarts.getInstanceByDom( |
| | | bloodPressureAndPulseEchartRef.value |
| | | ); |
| | | if (chart) { |
| | | chart.dispose(); |
| | | } |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | * { |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .under-treatment-container { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | height: var(--height); |
| | | gap: 4px; |
| | | padding-bottom: 2px; |
| | | overflow: hidden; |
| | | .left-box { |
| | | width: 58.25%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | |
| | | .left-row1 { |
| | | width: 100%; |
| | | height: 38.97%; |
| | | display: flex; |
| | | gap: 4px; |
| | | |
| | | .left-row1-col1, |
| | | .left-row1-col2, |
| | | .left-row1-col3 { |
| | | height: 100%; |
| | | } |
| | | |
| | | .left-row1-col1 { |
| | | width: 26.94%; |
| | | border-radius: 2px; |
| | | overflow: hidden; |
| | | } |
| | | .left-row1-col2 { |
| | | width: 26.43%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | .left-row1-col2-row1 { |
| | | height: 36.62%; |
| | | } |
| | | |
| | | .left-row1-col2-item-row2 { |
| | | height: 63.38%; |
| | | } |
| | | } |
| | | .left-row1-col3 { |
| | | width: 46.63%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | .left-row1-col3-row1 { |
| | | height: 36.62%; |
| | | } |
| | | .left-row1-col3-row2 { |
| | | height: 63.38%; |
| | | .dialysis-mode-content { |
| | | height: 100%; |
| | | .abnormal-indicator { |
| | | display: inline-block; |
| | | margin-right: 6px; |
| | | margin-bottom: 4px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 5px; |
| | | line-height: 6px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .left-row2 { |
| | | width: 100%; |
| | | height: 21.03%; |
| | | display: flex; |
| | | gap: 4px; |
| | | .left-row2-col1 { |
| | | width: 26.94%; |
| | | } |
| | | .left-row2-col2 { |
| | | width: 26.43%; |
| | | } |
| | | .left-row2-col3 { |
| | | width: 46.62%; |
| | | } |
| | | } |
| | | .left-row3 { |
| | | width: 100%; |
| | | height: 21.03%; |
| | | display: flex; |
| | | gap: 4px; |
| | | .left-row3-col1 { |
| | | width: 26.94%; |
| | | } |
| | | .left-row3-col2 { |
| | | width: 26.43%; |
| | | } |
| | | .left-row3-col3 { |
| | | width: 46.62%; |
| | | } |
| | | } |
| | | .left-row4 { |
| | | width: 100%; |
| | | height: 11.79%; |
| | | display: flex; |
| | | gap: 4px; |
| | | .left-row4-col { |
| | | width: 50%; |
| | | } |
| | | } |
| | | } |
| | | .right-box { |
| | | width: 41.75%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | .right-box-row1, |
| | | .right-box-row2, |
| | | .right-box-row3 .right-box-row4 { |
| | | width: 100%; |
| | | } |
| | | .right-box-row1 { |
| | | height: 14.44%; |
| | | display: flex; |
| | | gap: 4px; |
| | | .right-box-row1-col1 { |
| | | width: 36.17%; |
| | | } |
| | | .right-box-row1-col2 { |
| | | width: 63.83%; |
| | | } |
| | | } |
| | | .right-box-row2 { |
| | | height: 25%; |
| | | display: flex; |
| | | gap: 4px; |
| | | .right-box-row2-item { |
| | | width: 50%; |
| | | } |
| | | } |
| | | .right-box-row3 { |
| | | height: 47.78%; |
| | | } |
| | | |
| | | .right-box-row4 { |
| | | height: 12.78%; |
| | | background: #ffffff; |
| | | border-radius: 2px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | padding-right: 13px; |
| | | .btn { |
| | | margin-left: 9px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .progress-box { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | .item-num { |
| | | margin-bottom: 4px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 8px; |
| | | color: #333333; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | |
| | | .item-box { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 8px; |
| | | color: #70a3dd; |
| | | text-align: center; |
| | | font-style: normal; |
| | | &.dialysis-mode-content { |
| | | color: #d58e56; |
| | | display: flex; |
| | | align-items: center; |
| | | // align-items: baseline; |
| | | .dialysis-mode-content-box { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | line-height: 1; |
| | | .mini-text { |
| | | margin-right: 1px; |
| | | font-size: 5px; |
| | | color: #c9a589; |
| | | } |
| | | } |
| | | } |
| | | &.treatment-status { |
| | | color: #70a3dd; |
| | | } |
| | | &.prescription-ehydration-olume { |
| | | color: #8079cb; |
| | | } |
| | | &.current-lood0emperature { |
| | | color: #70a3dd; |
| | | font-size: 9px; |
| | | } |
| | | &.venous-pressure { |
| | | color: #70a3dd; |
| | | font-size: 9px; |
| | | } |
| | | } |
| | | .prescription-remarks { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 5px; |
| | | color: #d58e56; |
| | | line-height: 7px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | .dehydrated-level { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .dehydrated-level-item { |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | .item-left { |
| | | flex: 1; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 4px; |
| | | color: #333333; |
| | | line-height: 6px; |
| | | font-style: normal; |
| | | .level-dete { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 4px; |
| | | color: #d58e56; |
| | | text-align: left; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | .item-right { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 4px; |
| | | color: #777777; |
| | | line-height: 6px; |
| | | font-style: normal; |
| | | } |
| | | } |
| | | } |
| | | // card header class |
| | | .mini-card { |
| | | padding: 2px; |
| | | } |
| | | .ktv-card { |
| | | overflow: visible; |
| | | .card-header { |
| | | margin-bottom: 0px; |
| | | } |
| | | ::v-deep(.card-main) { |
| | | overflow: visible !important; |
| | | div { |
| | | overflow: visible; |
| | | } |
| | | } |
| | | } |
| | | :deep(.mini-header) { |
| | | flex: 0 0 4px; |
| | | .card-icon { |
| | | width: 4px; |
| | | height: 4px; |
| | | } |
| | | .card-title { |
| | | font-size: 4px; |
| | | } |
| | | } |
| | | :deep(.big-header) { |
| | | flex: 0 0 9px; |
| | | .card-icon { |
| | | width: 9px; |
| | | height: 9px; |
| | | } |
| | | .card-title { |
| | | font-size: 5px; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div |
| | | class="unplanned-schedule-container" |
| | | :style="{ '--height': height + 'px' }" |
| | | > |
| | | <div class="row1-container"> |
| | | <Card |
| | | title="抗凝剂" |
| | | :icon="tslImg" |
| | | background-color="#FFEDD2" |
| | | class="row1-left" |
| | | > |
| | | <div class="list-1"> |
| | | <div |
| | | v-for="(item, index) in consumablesCollection.抗凝剂" |
| | | :key="index" |
| | | class="list-1-item" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <div class="row1-content"> |
| | | <Card |
| | | title="透析模式" |
| | | :icon="tslImg" |
| | | background-color="#E5EEFF" |
| | | class="row1-content-card" |
| | | > |
| | | <div class="list-2"> |
| | | <div |
| | | v-for="(item, index) in consumablesCollection.透析模式" |
| | | :key="index" |
| | | class="list-2-item" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="一次性血液透析体外循环管路" |
| | | :icon="tslImg" |
| | | background-color="#D9F0E2" |
| | | class="row1-content-card" |
| | | > |
| | | <div class="list-3"> |
| | | <div |
| | | v-for="(item, index) in consumablesCollection.管路" |
| | | :key="index" |
| | | class="list-3-item" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="一次性使用透析护理包" |
| | | :icon="tslImg" |
| | | background-color="#F9DEDE" |
| | | class="row1-content-card" |
| | | /> |
| | | </div> |
| | | <Card |
| | | title="一次性使用内瘘穿刺针" |
| | | :icon="tslImg" |
| | | background-color="#EFE5FF" |
| | | class="row1-right" |
| | | > |
| | | <div class="list-1"> |
| | | <div |
| | | v-for="(item, index) in consumablesCollection.穿刺针" |
| | | :key="index" |
| | | class="list-1-item" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | <div class="row2-container"> |
| | | <Card |
| | | title="血液透析器" |
| | | :icon="tslImg" |
| | | background-color="#F6F5FA" |
| | | class="row2-card" |
| | | > |
| | | <div class="list-4"> |
| | | <div |
| | | v-for="(item, index) in consumablesCollection.透析器" |
| | | :key="index" |
| | | class="list-4-item" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | <Card |
| | | title="血液透析滤过器" |
| | | :icon="tslImg" |
| | | background-color="#F6F5FA" |
| | | class="row2-card" |
| | | > |
| | | <div class="list-4"> |
| | | <div |
| | | v-for="(item, index) in consumablesCollection.滤过器" |
| | | :key="index" |
| | | class="list-4-item" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="UnplannedSchedule"> |
| | | import { computed } from "vue"; |
| | | // @ts-ignore |
| | | import Card from "../components/Card.vue"; |
| | | import tslImg from "@/img/tsl.png"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | |
| | | interface Props { |
| | | height: number; |
| | | } |
| | | const props = defineProps<Props>(); |
| | | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const consumablesCollection = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.deviceData.consumablesCollection; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | * { |
| | | box-sizing: border-box; |
| | | } |
| | | .unplanned-schedule-container { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | height: var(--height); |
| | | overflow: hidden; |
| | | .row1-container { |
| | | flex: 1; |
| | | margin-bottom: 4px; |
| | | display: flex; |
| | | width: 100%; |
| | | gap: 4px; |
| | | min-height: 0; |
| | | > .row1-left, |
| | | .row1-right { |
| | | width: 103px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .row1-content { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | |
| | | // 卡片高度平均分(3个) |
| | | > .row1-content-card { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | .row2-container { |
| | | flex: 1; |
| | | margin-bottom: 4px; |
| | | display: flex; |
| | | width: 100%; |
| | | gap: 4px; |
| | | min-height: 0; |
| | | > .row2-card { |
| | | flex: 1; |
| | | } |
| | | } |
| | | .list-1 { |
| | | .list-1-item { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 4px; |
| | | color: #a78718; |
| | | text-align: left; |
| | | font-style: normal; |
| | | &:not(:first-child) { |
| | | margin-top: 2px; |
| | | } |
| | | } |
| | | } |
| | | .list-2 { |
| | | .list-2-item { |
| | | display: inline-block; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 5px; |
| | | color: #3a75b8; |
| | | text-align: left; |
| | | font-style: normal; |
| | | &:not(:first-child) { |
| | | margin-left: 5px; |
| | | } |
| | | } |
| | | } |
| | | .list-3 { |
| | | .list-3-item { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 4px; |
| | | color: #3ab859; |
| | | text-align: left; |
| | | font-style: normal; |
| | | &:not(:first-child) { |
| | | margin-top: 2px; |
| | | } |
| | | } |
| | | } |
| | | .list-4 { |
| | | .list-4-item { |
| | | display: inline-block; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 4px; |
| | | color: #333333; |
| | | text-align: left; |
| | | font-style: normal; |
| | | margin-bottom: 4px; |
| | | &:not(:first-child) { |
| | | margin-right: 2px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <div class="register-form"> |
| | | <van-image width="100" height="100" :src="logo" /> |
| | | <h1>用户注册</h1> |
| | | <p>创建您的账户,开始使用我们的服务</p> |
| | | <p class="desc">创建您的账户,开始使用我们的服务</p> |
| | | |
| | | <van-form @submit="onSubmit"> |
| | | <!-- 用户名 --> |
| | |
| | | color: #666; |
| | | margin-bottom: 20px; |
| | | } |
| | | .desc { |
| | | font-size: 14px; |
| | | } |
| | | </style> |
| | |
| | | color: #4caf50; |
| | | margin-bottom: 20px; |
| | | } |
| | | p { |
| | | font-size: 14px; |
| | | } |
| | | </style> |
| | |
| | | "moduleResolution": "node", |
| | | "baseUrl": ".", |
| | | "paths": { |
| | | "@/*": ["src/*"], |
| | | "*": ["node_modules/*", "src/types/*"] |
| | | }, |
| | | "esModuleInterop": true, |
| | |
| | | import { defineConfig } from 'vite'; |
| | | import vue from '@vitejs/plugin-vue'; |
| | | import path from 'path'; |
| | | |
| | | export default defineConfig({ |
| | | plugins: [vue()], |
| | | css: { |
| | | postcss: path.resolve(__dirname, 'postcss.config.js') |
| | | }, |
| | | server: { |
| | | port: 3034, // 指定端口号为 3000 |
| | | strictPort: true, // 如果端口被占用,则抛出错误而不是尝试下一个可用端口 |
| | |
| | | }, |
| | | resolve: { |
| | | alias: { |
| | | '@': '/src' |
| | | '@': path.resolve(__dirname, 'src') |
| | | } |
| | | }, |
| | | base:'/test' |