This commit is contained in:
xiaozhou
2025-08-28 21:04:22 +08:00
parent 27f67ee523
commit b4731af0b1
17 changed files with 2412 additions and 10 deletions

7
components.d.ts vendored
View File

@ -11,8 +11,15 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button'] VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell']
VanCheckbox: typeof import('vant/es')['Checkbox']
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
VanIcon: typeof import('vant/es')['Icon']
VanNavBar: typeof import('vant/es')['NavBar'] VanNavBar: typeof import('vant/es')['NavBar']
VanPopup: typeof import('vant/es')['Popup']
VanTab: typeof import('vant/es')['Tab']
VanTabbar: typeof import('vant/es')['Tabbar'] VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem'] VanTabbarItem: typeof import('vant/es')['TabbarItem']
VanTabs: typeof import('vant/es')['Tabs']
} }
} }

859
package-lock.json generated
View File

@ -20,6 +20,7 @@
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.7.0", "@vue/tsconfig": "^0.7.0",
"npm-run-all2": "^8.0.4", "npm-run-all2": "^8.0.4",
"sass-embedded": "^1.91.0",
"typescript": "~5.8.0", "typescript": "~5.8.0",
"unplugin-auto-import": "^20.1.0", "unplugin-auto-import": "^20.1.0",
"unplugin-vue-components": "^29.0.0", "unplugin-vue-components": "^29.0.0",
@ -469,6 +470,13 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@bufbuild/protobuf": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/@bufbuild/protobuf/-/protobuf-2.7.0.tgz",
"integrity": "sha512-qn6tAIZEw5i/wiESBF4nQxZkl86aY4KoO0IkUa2Lh+rya64oTOdJQFlZuMwI1Qz9VBJQrQC4QlSA2DNek5gCOA==",
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.25.9", "version": "0.25.9",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
@ -930,6 +938,316 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"node_modules/@parcel/watcher": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.1",
"@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-freebsd-x64": "2.5.1",
"@parcel/watcher-linux-arm-glibc": "2.5.1",
"@parcel/watcher-linux-arm-musl": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
"@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-ia32": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@polka/url": { "node_modules/@polka/url": {
"version": "1.0.0-next.29", "version": "1.0.0-next.29",
"resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.29.tgz", "resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.29.tgz",
@ -1713,6 +2031,13 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/buffer-builder": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/buffer-builder/-/buffer-builder-0.2.0.tgz",
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
"dev": true,
"license": "MIT/X11"
},
"node_modules/bundle-name": { "node_modules/bundle-name": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz",
@ -1773,6 +2098,13 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/colorjs.io": {
"version": "0.5.2",
"resolved": "https://registry.npmmirror.com/colorjs.io/-/colorjs.io-0.5.2.tgz",
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
"dev": true,
"license": "MIT"
},
"node_modules/confbox": { "node_modules/confbox": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz", "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz",
@ -1903,6 +2235,20 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/echarts": { "node_modules/echarts": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-6.0.0.tgz", "resolved": "https://registry.npmmirror.com/echarts/-/echarts-6.0.0.tgz",
@ -2137,6 +2483,16 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/he": { "node_modules/he": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
@ -2160,6 +2516,13 @@
"node": ">=18.18.0" "node": ">=18.18.0"
} }
}, },
"node_modules/immutable": {
"version": "5.1.3",
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.3.tgz",
"integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
"dev": true,
"license": "MIT"
},
"node_modules/is-binary-path": { "node_modules/is-binary-path": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
@ -2399,6 +2762,35 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/mitt": { "node_modules/mitt": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
@ -2474,6 +2866,14 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.19", "version": "2.0.19",
"resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz", "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz",
@ -2830,6 +3230,419 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/sass": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.91.0.tgz",
"integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"
}
},
"node_modules/sass-embedded": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded/-/sass-embedded-1.91.0.tgz",
"integrity": "sha512-VTckYcH1AglrZ3VpPETilTo3Ef472XKwP13lrNfbOHSR6Eo5p27XTkIi+6lrCbuhBFFGAmy+4BRoLaeFUgn+eg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.5.0",
"buffer-builder": "^0.2.0",
"colorjs.io": "^0.5.0",
"immutable": "^5.0.2",
"rxjs": "^7.4.0",
"supports-color": "^8.1.1",
"sync-child-process": "^1.0.2",
"varint": "^6.0.0"
},
"bin": {
"sass": "dist/bin/sass.js"
},
"engines": {
"node": ">=16.0.0"
},
"optionalDependencies": {
"sass-embedded-all-unknown": "1.91.0",
"sass-embedded-android-arm": "1.91.0",
"sass-embedded-android-arm64": "1.91.0",
"sass-embedded-android-riscv64": "1.91.0",
"sass-embedded-android-x64": "1.91.0",
"sass-embedded-darwin-arm64": "1.91.0",
"sass-embedded-darwin-x64": "1.91.0",
"sass-embedded-linux-arm": "1.91.0",
"sass-embedded-linux-arm64": "1.91.0",
"sass-embedded-linux-musl-arm": "1.91.0",
"sass-embedded-linux-musl-arm64": "1.91.0",
"sass-embedded-linux-musl-riscv64": "1.91.0",
"sass-embedded-linux-musl-x64": "1.91.0",
"sass-embedded-linux-riscv64": "1.91.0",
"sass-embedded-linux-x64": "1.91.0",
"sass-embedded-unknown-all": "1.91.0",
"sass-embedded-win32-arm64": "1.91.0",
"sass-embedded-win32-x64": "1.91.0"
}
},
"node_modules/sass-embedded-all-unknown": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.91.0.tgz",
"integrity": "sha512-AXC1oPqDfLnLtcoxM+XwSnbhcQs0TxAiA5JDEstl6+tt6fhFLKxdyl1Hla39SFtxvMfB2QDUYE3Dmx49O59vYg==",
"cpu": [
"!arm",
"!arm64",
"!riscv64",
"!x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"sass": "1.91.0"
}
},
"node_modules/sass-embedded-android-arm": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.91.0.tgz",
"integrity": "sha512-DSh1V8TlLIcpklAbn4NINEFs3yD2OzVTbawEXK93IH990upoGNFVNRTstFQ/gcvlbWph3Y3FjAJvo37zUO485A==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-arm64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.91.0.tgz",
"integrity": "sha512-I8Eeg2CeVcZIhXcQLNEY6ZBRF0m7jc818/fypwMwvIdbxGWBekTzc3aKHTLhdBpFzGnDIyR4s7oB0/OjIpzD1A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-riscv64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.91.0.tgz",
"integrity": "sha512-qmsl1a7IIJL0fCOwzmRB+6nxeJK5m9/W8LReXUrdgyJNH5RyxChDg+wwQPVATFffOuztmWMnlJ5CV2sCLZrXcQ==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-x64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.91.0.tgz",
"integrity": "sha512-/wN0HBLATOVSeN3Tzg0yxxNTo1IQvOxxxwFv7Ki/1/UCg2AqZPxTpNoZj/mn8tUPtiVogMGbC8qclYMq1aRZsQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-arm64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.91.0.tgz",
"integrity": "sha512-gQ6ScInxAN+BDUXy426BSYLRawkmGYlHpQ9i6iOxorr64dtIb3l6eb9YaBV8lPlroUnugylmwN2B3FU9BuPfhA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-x64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.91.0.tgz",
"integrity": "sha512-DSvFMtECL2blYVTFMO5fLeNr5bX437Lrz8R47fdo5438TRyOkSgwKTkECkfh3YbnrL86yJIN2QQlmBMF17Z/iw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.91.0.tgz",
"integrity": "sha512-ppAZLp3eZ9oTjYdQDf4nM7EehDpkxq5H1hE8FOrx8LpY7pxn6QF+SRpAbRjdfFChRw0K7vh+IiCnQEMp7uLNAg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.91.0.tgz",
"integrity": "sha512-OnKCabD7f420ZEC/6YI9WhCVGMZF+ybZ5NbAB9SsG1xlxrKbWQ1s7CIl0w/6RDALtJ+Fjn8+mrxsxqakoAkeuA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.91.0.tgz",
"integrity": "sha512-znEsNC2FurPF9+XwQQ6e/fVoic3e5D3/kMB41t/bE8byJVRdaPhkdsszt3pZUE56nNGYoCuieSXUkk7VvyPHsw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.91.0.tgz",
"integrity": "sha512-VfbPpID1C5TT7rukob6CKgefx/TsLE+XZieMNd00hvfJ8XhqPr5DGvSMCNpXlwaedzTirbJu357m+n2PJI9TFQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.91.0.tgz",
"integrity": "sha512-ZfLGldKEEeZjuljKks835LTq7jDRI3gXsKKXXgZGzN6Yymd4UpBOGWiDQlWsWTvw5UwDU2xfFh0wSXbLGHTjVA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-x64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.91.0.tgz",
"integrity": "sha512-4kSiSGPKFMbLvTRbP/ibyiKheOA3fwsJKWU0SOuekSPmybMdrhNkTm0REp6+nehZRE60kC3lXmEV4a7w8Jrwyg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-riscv64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.91.0.tgz",
"integrity": "sha512-Y3Fj94SYYvMX9yo49T78yBgBWXtG3EyYUT5K05XyCYkcdl1mVXJSrEmqmRfe4vQGUCaSe/6s7MmsA9Q+mQez7Q==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-x64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.91.0.tgz",
"integrity": "sha512-XwIUaE7pQP/ezS5te80hlyheYiUlo0FolQ0HBtxohpavM+DVX2fjwFm5LOUJHrLAqP+TLBtChfFeLj1Ie4Aenw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-unknown-all": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.91.0.tgz",
"integrity": "sha512-Bj6v7ScQp/HtO91QBy6ood9AArSIN7/RNcT4E7P9QoY3o+e6621Vd28lV81vdepPrt6u6PgJoVKmLNODqB6Q+A==",
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"!android",
"!darwin",
"!linux",
"!win32"
],
"dependencies": {
"sass": "1.91.0"
}
},
"node_modules/sass-embedded-win32-arm64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.91.0.tgz",
"integrity": "sha512-yDCwTiPRex03i1yo7LwiAl1YQ21UyfOxPobD7UjI8AE8ZcB0mQ28VVX66lsZ+qm91jfLslNFOFCD4v79xCG9hA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-x64": {
"version": "1.91.0",
"resolved": "https://registry.npmmirror.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.91.0.tgz",
"integrity": "sha512-wiuMz/cx4vsk6rYCnNyoGE5pd73aDJ/zF3qJDose3ZLT1/vV943doJE5pICnS/v5DrUqzV6a1CNq4fN+xeSgFQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass/node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/sass/node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 14.18.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/scule": { "node_modules/scule": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz", "resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz",
@ -2964,6 +3777,45 @@
"node": ">=16" "node": ">=16"
} }
}, },
"node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/sync-child-process": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/sync-child-process/-/sync-child-process-1.0.2.tgz",
"integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"sync-message-port": "^1.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/sync-message-port": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/sync-message-port/-/sync-message-port-1.1.3.tgz",
"integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.14", "version": "0.2.14",
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz", "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz",
@ -3261,6 +4113,13 @@
"vue": "^3.0.0" "vue": "^3.0.0"
} }
}, },
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
"dev": true,
"license": "MIT"
},
"node_modules/vite": { "node_modules/vite": {
"version": "7.1.3", "version": "7.1.3",
"resolved": "https://registry.npmmirror.com/vite/-/vite-7.1.3.tgz", "resolved": "https://registry.npmmirror.com/vite/-/vite-7.1.3.tgz",

View File

@ -26,6 +26,7 @@
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.7.0", "@vue/tsconfig": "^0.7.0",
"npm-run-all2": "^8.0.4", "npm-run-all2": "^8.0.4",
"sass-embedded": "^1.91.0",
"typescript": "~5.8.0", "typescript": "~5.8.0",
"unplugin-auto-import": "^20.1.0", "unplugin-auto-import": "^20.1.0",
"unplugin-vue-components": "^29.0.0", "unplugin-vue-components": "^29.0.0",

BIN
public/assets/ats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/assets/back1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
public/assets/kt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/assets/menjin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
public/assets/pdx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/assets/ups.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,12 +1,13 @@
import { createApp } from 'vue' import { createApp } from "vue";
import { createPinia } from 'pinia' import { createPinia } from "pinia";
import App from './App.vue' import App from "./App.vue";
import router from './router' import router from "./router";
import "vant/es/toast/style"; // 引入Toast样式
const app = createApp(App) const app = createApp(App);
app.use(createPinia()) app.use(createPinia());
app.use(router) app.use(router);
app.mount('#app') app.mount("#app");

View File

@ -26,6 +26,29 @@ const router = createRouter({
path: "/demo", path: "/demo",
component: () => import("@/views/demo.vue"), component: () => import("@/views/demo.vue"),
}, },
{
path: "/menjinliebiao",
component: () => import("@/views/menjinliebiao.vue"),
},
{
name: "mjlbopen",
path: "/mjlbopen/:name",
component: () => import("@/views/mjlbopen.vue"),
},
{
name: "jmpdx",
path: "/jmpdx",
component: () => import("@/views/jmpdx.vue"),
},
{
path: "/ktlb",
component: () => import("@/views/ktlb.vue"),
},
{
name: "ktxx",
path: "/ktxx/:title",
component: () => import("@/views/ktxx.vue"),
},
], ],
}); });

227
src/views/jmpdx.vue Normal file
View File

@ -0,0 +1,227 @@
<template>
<van-nav-bar
title="精密配电箱列表"
left-arrow
@click-left="back"
placeholder
/>
<div class="container">
<h2 class="page-title">精密配电柜信息列表</h2>
<div class="cabinet-list">
<!-- 循环展示10条配柜信息 -->
<div
v-for="(cabinet, index) in cabinetData"
:key="index"
class="cabinet-item"
>
<!-- 左侧信息区域 -->
<div class="cabinet-left">
<div class="cabinet-title">
<span class="cabinet-tag">{{ cabinet.title }}</span>
</div>
<div class="cabinet-details">
<p><span class="label">位置</span>{{ cabinet.position }}</p>
<p>
<span class="label">设备型号</span>{{ cabinet.deviceModel }}
</p>
<p><span class="label">设备编码</span>{{ cabinet.deviceCode }}</p>
<p>
<span class="label">所属厂家</span>{{ cabinet.manufacturer }}
</p>
</div>
</div>
<!-- 右侧温湿度区域 -->
<div class="cabinet-right">
<div class="temp-humidity-title">温湿度监测</div>
<div class="temp-humidity-values">
<p v-for="(item, i) in cabinet.temperatures" :key="i">
传感器{{ i + 1 }}: {{ item.temp }} / {{ item.humidity }}%
</p>
</div>
</div>
<!-- 右侧箭头 -->
<div class="cabinet-arrow">
<i class="arrow-icon"></i>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
const router = useRouter();
const back = () => {
router.back();
};
// 生成随机温度数据 (20-35℃)
const getRandomTemp = () => {
return (Math.random() * 15 + 20).toFixed(1);
};
// 生成随机湿度数据 (30-60%)
const getRandomHumidity = () => {
return Math.floor(Math.random() * 30 + 30);
};
// 生成随机位置信息
const getRandomPosition = () => {
const areas = ["东区", "西区", "南区", "北区", "中区"];
const rooms = ["A", "B", "C", "D", "E"];
const floors = [1, 2, 3, 4, 5];
const area = areas[Math.floor(Math.random() * areas.length)];
const room = rooms[Math.floor(Math.random() * rooms.length)];
const floor = floors[Math.floor(Math.random() * floors.length)];
return `${area}${room}机房 ${floor}`;
};
// 设备型号列表
const deviceModels = [
"PDU-800A",
"PDU-800B",
"PDU-900A",
"PDU-900B",
"SPM-1000",
"SPM-1200",
];
// 生成10条随机数据
const cabinetData = ref([]);
for (let i = 1; i <= 10; i++) {
// 生成3组温湿度数据
const temps = Array.from({ length: 3 }, () => ({
temp: getRandomTemp(),
humidity: getRandomHumidity(),
}));
cabinetData.value.push({
title: `精密配电柜 ${i}`,
position: getRandomPosition(),
deviceModel: deviceModels[Math.floor(Math.random() * deviceModels.length)],
deviceCode: `PDU-${Math.floor(Math.random() * 10000)
.toString()
.padStart(4, "0")}`,
manufacturer: "四川省自贡电网",
temperatures: temps,
});
}
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
.page-title {
color: #333;
border-bottom: 2px solid #165dff;
padding-bottom: 10px;
margin-bottom: 20px;
}
.cabinet-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.cabinet-item {
display: flex;
align-items: stretch;
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
transition: box-shadow 0.3s ease;
}
.cabinet-item:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.cabinet-left {
flex: 2;
padding: 15px;
border-right: 1px solid #f0f0f0;
}
.cabinet-title {
margin-bottom: 15px;
}
.cabinet-tag {
display: inline-block;
background-color: #165dff;
color: white;
padding: 4px 12px;
border-radius: 4px;
font-weight: 500;
}
.cabinet-details {
color: #555;
}
.cabinet-details p {
margin: 8px 0;
line-height: 1.5;
}
.label {
color: #888;
display: inline-block;
width: 80px;
}
.cabinet-right {
flex: 1;
padding: 15px;
background-color: #f9f9f9;
display: flex;
flex-direction: column;
}
.temp-humidity-title {
font-weight: 500;
margin-bottom: 10px;
color: #333;
border-bottom: 1px dashed #ddd;
padding-bottom: 5px;
}
.temp-humidity-values {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
gap: 8px;
color: #666;
}
.cabinet-arrow {
width: 50px;
display: flex;
align-items: center;
justify-content: center;
border-left: 1px solid #f0f0f0;
background-color: #f5f5f5;
cursor: pointer;
transition: background-color 0.2s;
}
.cabinet-arrow:hover {
background-color: #eee;
}
.arrow-icon {
color: #999;
font-size: 20px;
}
</style>

138
src/views/ktlb.vue Normal file
View File

@ -0,0 +1,138 @@
<template>
<van-nav-bar title="空调列表" left-arrow @click-left="back" placeholder />
<div class="air-conditioner-container">
<div
v-for="(airCon, index) in airConditionerData"
:key="index"
class="air-conditioner-item"
@click="handleClick(airCon)"
>
<div class="content">
<div class="title">{{ airCon.title }}</div>
<div class="info">所在区域: {{ airCon.region }}</div>
<div class="info">设备型号: {{ airCon.model }}</div>
<div class="info">设备编码: {{ airCon.code }}</div>
<div class="info">所属厂家: {{ airCon.manufacturer }}</div>
<div class="info">
温度报警上下限: 上限{{ airCon.tempUpper }} 下限{{
airCon.tempLower
}}
</div>
<div class="info">
湿度报警上下限: 上限{{ airCon.humidityUpper }}% 下限{{
airCon.humidityLower
}}%
</div>
</div>
<div class="arrow">
<van-icon name="arrow" />
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { Icon } from "vant";
const router = useRouter();
const back = () => {
router.back();
};
// 生成随机数据的工具函数
const generateRandomData = (count) => {
const data = [];
const manufacturers = ["重庆"];
const models = ["Pco3", "Pco4", "Pco5", "Pco6", "Pco7"];
for (let i = 1; i <= count; i++) {
const title = `二楼机房${i}号空调`;
const region = "0";
const model = models[Math.floor(Math.random() * models.length)];
const code = Math.floor(Math.random() * 1000000)
.toString()
.padStart(6, "0");
const manufacturer =
manufacturers[Math.floor(Math.random() * manufacturers.length)];
const tempUpper = 40 + Math.floor(Math.random() * 20);
const tempLower = 20 + Math.floor(Math.random() * 20);
const humidityUpper = 50 + Math.floor(Math.random() * 20);
const humidityLower = 20 + Math.floor(Math.random() * 20);
data.push({
title,
region,
model,
code,
manufacturer,
tempUpper,
tempLower,
humidityUpper,
humidityLower,
});
}
return data;
};
// 生成15条随机数据
const airConditionerData = ref(generateRandomData(15));
// 点击事件处理方法
const handleClick = (item) => {
console.log("点击了", item.title, ",准备跳转详细页", item);
router.push({ name: "ktxx", params: { title: item.title } });
// 实际跳转逻辑可在这里实现
};
</script>
<style scoped>
.air-conditioner-container {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
max-width: 1000px;
margin: 0 auto;
}
.air-conditioner-item {
background-color: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
justify-content: space-between;
align-items: center;
}
.air-conditioner-item:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
border-color: #d0d0d0;
}
.content {
flex: 1;
}
.title {
font-size: 18px;
font-weight: 600;
margin-bottom: 10px;
color: #2c3e50;
}
.info {
margin-bottom: 6px;
color: #666;
font-size: 14px;
}
.arrow {
color: #b0b0b0;
margin-left: 20px;
transition: color 0.3s ease;
}
.air-conditioner-item:hover .arrow {
color: #3498db;
}
</style>

250
src/views/ktxx.vue Normal file
View File

@ -0,0 +1,250 @@
<template>
<van-nav-bar title="空调详情" left-arrow @click-left="back" placeholder />
<div class="air-conditioner-detail">
<!-- 标题区域 -->
<div class="title">
{{ title }}
</div>
<!-- 信息展示区域 -->
<div class="info-container">
<div class="info-item">
<span class="label">所在区域:</span>
<span class="value">{{ detailData.region }}</span>
</div>
<div class="info-item">
<span class="label">设备型号:</span>
<span class="value">{{ detailData.model }}</span>
</div>
<div class="info-item">
<span class="label">设备编码:</span>
<span class="value">{{ detailData.code }}</span>
</div>
<div class="info-item">
<span class="label">所属厂家:</span>
<span class="value">{{ detailData.manufacturer }}</span>
</div>
<div class="info-item">
<span class="label">温度上限:</span>
<span class="value temp-upper">{{ detailData.tempUpper }}</span>
</div>
<div class="info-item">
<span class="label">温度下限:</span>
<span class="value temp-lower">{{ detailData.tempLower }}</span>
</div>
<div class="info-item">
<span class="label">湿度上限:</span>
<span class="value humidity-upper"
>{{ detailData.humidityUpper }}%</span
>
</div>
<div class="info-item">
<span class="label">湿度下限:</span>
<span class="value humidity-lower"
>{{ detailData.humidityLower }}%</span
>
</div>
<div class="info-item">
<span class="label">回风温度:</span>
<span class="value">{{ detailData.returnAirTemp }}</span>
</div>
<div class="info-item">
<span class="label">送风温度:</span>
<span class="value">{{ detailData.supplyAirTemp }}</span>
</div>
<div class="info-item">
<span class="label">系统运行时间:</span>
<span class="value">{{ detailData.runTime }}</span>
</div>
</div>
<!-- 监控信息区域 -->
<div class="monitor-title">监控信息</div>
<div class="info-container">
<div class="info-item">
<span class="label">压缩机1排气压力:</span>
<span class="value">{{ detailData.compressor1Pressure }}</span>
</div>
<div class="info-item">
<span class="label">压缩机2排气压力:</span>
<span class="value">{{ detailData.compressor2Pressure }}</span>
</div>
<div class="info-item">
<span class="label">加湿电流:</span>
<span class="value">{{ detailData.humidificationCurrent }}</span>
</div>
<div class="info-item">
<span class="label">送风机保护:</span>
<span class="value warning">{{ detailData.fanProtection }}</span>
</div>
<div class="info-item">
<span class="label">过滤网状态:</span>
<span class="value">{{ detailData.filterClogged }}</span>
</div>
<div class="info-item">
<span class="label">漏水报警:</span>
<span class="value">{{ detailData.floorLeakAlarm }}</span>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";
import { useRoute } from "vue-router";
// 获取路由实例
const route = useRoute();
const router = useRouter();
const back = () => {
router.back();
};
// 存储当前设备标题和详情数据
const title = ref("");
const detailData = ref({});
// 生成随机数据的工具函数
const generateRandomData = () => {
// 基础数据池
const regions = ["0"];
const models = [
"Pco3",
"Pco4",
"Pco5",
"Pco6",
"Pco7",
"KFR-35GW",
"KFR-50LW",
];
const manufacturers = ["重庆"];
const statusOptions = ["正常", "开启", "关闭", "报警", "解除"];
const yesNoOptions = ["是", "否", "已堵塞", "未堵塞"];
// 生成随机数的辅助函数
const randomNum = (min, max, decimalPlaces = 0) => {
const num = Math.random() * (max - min) + min;
return decimalPlaces > 0 ? num.toFixed(decimalPlaces) : Math.floor(num);
};
return {
region: regions[Math.floor(Math.random() * regions.length)],
model: models[Math.floor(Math.random() * models.length)],
code: Math.floor(Math.random() * 1000000)
.toString()
.padStart(6, "0"),
manufacturer:
manufacturers[Math.floor(Math.random() * manufacturers.length)],
tempUpper: randomNum(40, 60),
tempLower: randomNum(10, 30),
humidityUpper: randomNum(50, 70),
humidityLower: randomNum(20, 40),
returnAirTemp: `${randomNum(20, 30, 1)}`,
supplyAirTemp: `${randomNum(18, 28, 1)}`,
runTime: `${randomNum(10, 100)}H`,
coolMode: statusOptions[Math.floor(Math.random() * 2)], // 只取开启/关闭
dehumidifyMode: statusOptions[Math.floor(Math.random() * 2)],
highWaterLevelSwitch: statusOptions[Math.floor(Math.random() * 2)],
remoteSwitch: statusOptions[Math.floor(Math.random() * 2)],
airPressureSwitch: statusOptions[Math.floor(Math.random() * 2)],
returnAirHumidity: `${randomNum(30, 60, 1)}%`,
compressor1Pressure: `${randomNum(14, 16, 4)}MPa`,
compressor2Pressure: `${randomNum(14, 16, 4)}MPa`,
humidificationCurrent: `${randomNum(0, 5, 1)}A`,
fanProtection:
statusOptions[Math.floor(Math.random() * statusOptions.length)],
filterClogged:
yesNoOptions[Math.floor(Math.random() * yesNoOptions.length)],
floorLeakAlarm:
statusOptions[Math.floor(Math.random() * 2)] === "开启" ? "报警" : "正常",
};
};
// 根据路由参数获取标题并生成随机数据
const generateData = () => {
// 从路由参数中获取title
const currentTitle = route.params.title;
title.value = currentTitle || "未知空调设备";
// 生成随机数据
detailData.value = generateRandomData();
};
// 初始化时生成数据
onMounted(generateData);
// 监听路由参数变化,当从其他详情页跳转过来时重新生成数据
watch(
() => route.params.title,
() => {
generateData();
}
);
</script>
<style scoped>
.air-conditioner-detail {
padding: 16px;
max-width: 800px;
margin: 0 auto;
}
.title,
.monitor-title {
font-size: 18px;
font-weight: bold;
color: #fff;
background-color: #007bff;
padding: 10px 16px;
border-radius: 4px;
margin: 0 0 16px 0;
}
.monitor-title {
margin-top: 24px;
}
.info-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
@media (max-width: 768px) {
.info-container {
grid-template-columns: 1fr;
}
}
.info-item {
padding: 10px;
background-color: #f9f9f9;
border-radius: 4px;
display: flex;
}
.label {
color: #666;
width: 120px;
flex-shrink: 0;
}
.value {
color: #333;
flex-grow: 1;
}
.temp-upper,
.humidity-upper {
color: #00bfff;
}
.temp-lower,
.humidity-lower {
color: #ff4500;
}
.warning {
color: #ff9800;
}
</style>

View File

@ -1,2 +1,404 @@
<template>动环管理</template> <template>
<script setup></script> <van-nav-bar title="动环管理" placeholder />
<van-tabs v-model:active="active" type="card">
<van-tab title="动环统计">
<div class="environment-dashboard">
<!-- 页面标题 -->
<h2 class="dashboard-title">环境监控数据</h2>
<!-- 环形图表区域 -->
<div class="ring-charts-container">
<div
class="chart-card"
v-for="(item, index) in ringChartData"
:key="index"
>
<div class="chart-header">{{ item.title }}</div>
<div class="chart-wrapper">
<div ref="chartRefs" class="chart"></div>
<div class="chart-value">
{{ item.value }}
<span class="chart-unit" v-if="item.unit">{{ item.unit }}</span>
</div>
</div>
</div>
</div>
<!-- 设备列表区域 -->
<div class="device-list-container">
<h3 class="list-title">设备统计</h3>
<div class="device-grid">
<div
class="device-item"
v-for="(device, index) in deviceList"
:key="index"
>
<img src="/assets/back1.png" style="width: 30px; height: 30px" />
<span class="device-name">{{ device.name }}</span>
<span class="device-count">{{ device.count }} </span>
</div>
</div>
</div>
</div>
</van-tab>
<van-tab title="设备查看">
<div class="device-list">
<!-- 遍历设备数据渲染列表 -->
<div
v-for="(item, index) in deviceLista"
:key="index"
class="device-item"
@click="handleView(item)"
>
<!-- 图片占位可后续替换为实际图片逻辑 -->
<div class="icon-placeholder">
<img :src="item.src" alt="" style="width: 30px; height: 30px" />
</div>
<span class="device-name">{{ item.name }}</span>
<span class="view-btn" @click="go(item.path)"
>查看 <van-icon name="arrow"
/></span>
</div>
</div>
</van-tab>
</van-tabs>
</template>
<style scoped lang="scss">
// 全局组件样式覆盖van-tabs 卡片式导航)
:deep(.van-tabs__nav--card) {
padding: 0;
margin: 0;
}
// 页面主容器
.environment-dashboard {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
// 页面标题
.dashboard-title {
color: #1f2329;
font-size: 24px;
margin-bottom: 30px;
font-weight: 600;
}
// 环形图表容器(核心:强制一行显示 + 横向滚动)
.ring-charts-container {
display: flex;
gap: 20px;
margin-bottom: 40px;
flex-wrap: nowrap; // 禁止换行,强制一行
overflow-x: auto; // 超出部分横向滚动
padding-bottom: 10px; // 给滚动条预留间距,避免遮挡
justify-content: flex-start; // 从左侧开始排列,不居中
}
// 优化横向滚动条样式(提升视觉体验)
.ring-charts-container::-webkit-scrollbar {
height: 6px; // 滚动条高度
}
.ring-charts-container::-webkit-scrollbar-thumb {
background-color: #e5e7eb; // 滚动条滑块颜色
border-radius: 3px; // 滑块圆角
}
.ring-charts-container::-webkit-scrollbar-thumb:hover {
background-color: #d1d5db; // 滑块 hover 时颜色
}
// 单个图表卡片
.chart-card {
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
padding: 20px;
width: 180px; // 卡片宽度(可根据需求调整,越小一行显示越多)
flex-shrink: 0; // 禁止卡片被压缩,保证大小统一
transition: transform 0.3s ease; // hover 上浮动画
}
// 图表卡片 hover 效果
.chart-card:hover {
transform: translateY(-5px);
}
// 图表标题(如“空调数量”“当前温度”)
.chart-header {
text-align: center;
font-size: 16px;
color: #4e5969;
margin-bottom: 15px;
font-weight: 500;
}
// 图表包裹容器(定位用)
.chart-wrapper {
position: relative;
height: 160px;
display: flex;
align-items: center;
justify-content: center;
}
// 环形图表容器echarts 渲染区域)
.chart {
width: 100%;
height: 140px;
}
// 图表中心数值如“7”“26.7”)
.chart-value {
position: absolute;
font-size: 22px;
font-weight: 600;
color: #1f2329;
}
// 数值单位(如“台”“℃”“%”)
.chart-unit {
font-size: 16px;
margin-left: 4px;
color: #6b7280;
}
// 设备列表容器
.device-list-container {
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
padding: 20px;
}
// 设备列表标题
.list-title {
color: #1f2329;
font-size: 18px;
margin-bottom: 20px;
font-weight: 600;
}
// 设备网格布局
.device-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); // 自动适配列数
gap: 15px; // 网格间距
}
// 单个设备项如“交流柜10台”
.device-item {
padding: 12px 15px;
background: #f9fafb;
border-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
transition: background 0.2s ease; // hover 背景变化动画
}
// 设备项 hover 效果
.device-item:hover {
background: #f0f2f5;
}
// 设备名称如“交流柜”“UPS”
.device-name {
color: #4e5969;
font-size: 14px;
}
// 设备数量如“10台”“8台”
.device-count {
color: #1f2329;
font-weight: 500;
font-size: 14px;
}
// 响应式适配(中屏:平板/大屏手机)
@media (max-width: 768px) {
.chart-card {
width: 160px; // 缩小卡片宽度,减少滚动需求
}
.device-grid {
grid-template-columns: repeat(2, 1fr); // 设备列表强制2列
}
}
// 响应式适配(小屏:手机竖屏)
@media (max-width: 375px) {
.ring-charts-container {
flex-wrap: wrap; // 允许换行,避免滚动条过长
justify-content: center; // 换行后居中排列
}
.chart-card {
width: 140px; // 进一步缩小卡片,适配小屏
max-width: none;
}
}
.device-list {
display: flex;
flex-direction: column;
gap: 8px; /* 项之间的间距 */
}
.device-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px;
border: 1px solid #eee;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s ease;
}
.device-item:hover {
background-color: #f8f8f8;
}
.icon-placeholder {
width: 24px;
height: 24px;
background-color: #ddd; /* 占位背景色,后续替换为图片 */
border-radius: 4px;
margin-right: 8px;
}
.device-name {
flex: 1;
}
.view-btn {
color: #409eff; /* 示例颜色,可自定义 */
font-size: 14px;
}
</style>
<script setup>
const router = useRouter();
import * as echarts from "echarts";
const deviceLista = [
{ name: "门禁", src: "/assets/menjin.png", path: "/menjinliebiao" },
{ name: "机密配电箱", src: "/assets/pdx.png", path: "/jmpdx" },
{ name: "空调", src: "/assets/kt.png", path: "/ktlb" },
{ name: "UPS", src: "/assets/ups.png" },
{ name: "ATS", src: "/assets/ats.png" },
];
const back = () => {
router.back();
};
const go = (src) => {
router.push(src);
};
// 环形图数据
const ringChartData = ref([
{ title: "空调数量", value: 7, unit: "台", color: "#42b983" },
{ title: "当前温度", value: 26.7, unit: "℃", color: "#ff4d4f" },
{ title: "当前湿度", value: 56, unit: "%", color: "#1890ff" },
]);
// 设备列表数据
const deviceList = ref([
{ name: "交流柜", count: 10 },
{ name: "UPS", count: 8 },
{ name: "ATS", count: 4 },
{ name: "漏水设备", count: 12 },
{ name: "蓄电池", count: 24 },
{ name: "温湿度设备", count: 16 },
{ name: "列头柜", count: 6 },
{ name: "安防设备", count: 9 },
]);
// 图表引用
const chartRefs = ref([]);
// 初始化图表
const initCharts = () => {
// 确保DOM已渲染
if (chartRefs.value.length === 0) return;
// 为每个图表初始化
chartRefs.value.forEach((el, index) => {
if (!el) return;
const chartInstance = echarts.init(el);
const chartData = ringChartData.value[index];
// 图表配置
const option = {
// 添加图表边距,减少外部空间占用
grid: {
top: 5,
right: 5,
bottom: 5,
left: 5,
containLabel: true,
},
series: [
{
type: "pie",
// 缩小圆环半径比例,使图表更紧凑
radius: ["60%", "85%"],
center: ["50%", "50%"], // 确保图表居中
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 8, // 略微减小圆角,适应小尺寸
borderColor: "#fff",
borderWidth: 1.5, // 减小边框宽度
},
label: {
show: false,
position: "center",
},
emphasis: {
label: {
show: false,
},
},
labelLine: {
show: false,
},
data: [
{
value: chartData.value,
name: chartData.title,
itemStyle: { color: chartData.color },
},
{
value: 100 - chartData.value,
itemStyle: { color: "#f0f2f5" },
},
],
},
],
};
chartInstance.setOption(option);
// 响应窗口大小变化
const handleResize = () => {
chartInstance.resize();
};
window.addEventListener("resize", handleResize);
// 组件卸载时清理
return () => {
window.removeEventListener("resize", handleResize);
chartInstance.dispose();
};
});
};
// 监听数据变化,重新渲染图表
watchEffect(() => {
initCharts();
});
// 组件挂载时初始化图表
onMounted(() => {
initCharts();
});
</script>

View File

@ -0,0 +1,79 @@
<template>
<van-nav-bar title="门禁列表" left-arrow @click-left="back" placeholder />
<div class="door-access-list">
<!-- 遍历门禁数据进行渲染 -->
<div
v-for="(item, index) in doorAccessData"
:key="index"
class="door-access-item"
>
<div class="info">
<p>门禁名称:{{ item.name }}</p>
<p>所在机房:{{ item.room }}</p>
<p>所在楼层:{{ item.floor }}</p>
</div>
<button class="open-btn" @click="handleOpen(item)">开门</button>
</div>
</div>
</template>
<script setup>
const router = useRouter();
const back = () => {
router.back();
};
const doorAccessData = [
{ name: "A01", room: "0", floor: "二楼机房1号空调" },
{ name: "A02", room: "0", floor: "二楼机房2号空调" },
{ name: "A03", room: "0", floor: "二楼机房3号空调" },
{ name: "A04", room: "0", floor: "二楼机房4号空调" },
{ name: "A05", room: "0", floor: "二楼机房5号空调" },
{ name: "A06", room: "0", floor: "二楼机房6号空调" },
];
const handleOpen = (item) => {
console.log(`尝试打开门禁 ${item.name}`);
router.push({ name: "mjlbopen", params: { name: item.name } });
// 示例:若有接口,可使用 axios 等发起请求
// axios.post('/api/openDoor', { doorName: item.name }).then(res => {
// console.log('开门请求结果:', res);
// }).catch(err => {
// console.error('开门失败:', err);
// });
};
</script>
<style scoped>
.door-access-list {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
}
.door-access-item {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 12px;
border: 1px solid #eee;
border-radius: 4px;
}
.info p {
margin: 0 0 4px 0;
line-height: 1.4;
}
.open-btn {
background-color: #409eff;
color: #fff;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
align-self: center;
}
.open-btn:hover {
background-color: #66b1ff;
}
</style>

415
src/views/mjlbopen.vue Normal file
View File

@ -0,0 +1,415 @@
<template>
<van-nav-bar title="门禁列表" left-arrow @click-left="back" placeholder />
<div class="door-access-detail">
<!-- 门禁基本信息 -->
<div class="basic-info-container">
<div>
<p>门禁名称:{{ doorName }}</p>
<p>所在机房:0</p>
<p>所在楼层:二楼机房{{ doorName.slice(-1) }}号空调</p>
<p>
授权人:
<span v-if="selectedAuthors.length > 0">
{{ selectedAuthors.join("") }}
</span>
<span v-else class="placeholder-text">未设置</span>
</p>
</div>
<div>
<button class="open-btn" @click="handleOpen">开门</button>
</div>
</div>
<div class="authorized-persons">
<div class="authorize-dots">
<div
v-for="(person, index) in displayedAuthors"
:key="index"
style="display: flex; flex-direction: column; position: relative"
>
<span class="dot"> </span>
<span class="person-name">{{ person }}</span>
</div>
<!-- 显示剩余数量 -->
<div v-if="selectedAuthors.length > 6" class="remaining-count">
+{{ selectedAuthors.length - 6 }}
</div>
<!-- + 按钮点击打开弹窗 -->
<span class="add-btn" @click="showPopup = true">+</span>
</div>
</div>
<!-- 开关门记录 -->
<div class="record-section">
<p class="record-title">开关门记录:</p>
<table class="record-table">
<thead>
<tr>
<th>门禁</th>
<th>时间</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr v-for="(record, index) in doorRecords" :key="index">
<td>{{ doorName }}</td>
<td>{{ record.time }}</td>
<td
:class="record.status === '开门' ? 'status-open' : 'status-close'"
>
{{ record.status }}
</td>
</tr>
</tbody>
</table>
</div>
<!-- 授权人选择弹窗从中间弹出 -->
<van-popup
v-model:show="showPopup"
position="center"
round
:style="{ width: '85%', maxWidth: '400px' }"
>
<div class="myPoput">
<div class="popup-content">
<div class="popup-title">选择授权人</div>
<div class="checkbox-container">
<van-checkbox-group v-model="selectedAuthors">
<van-checkbox
v-for="(author, index) in authorList"
:key="index"
:name="author"
class="author-item"
>
{{ author }}
</van-checkbox>
</van-checkbox-group>
</div>
<div class="popup-actions">
<van-button
type="info"
plain
@click="showPopup = false"
class="cancel-btn"
>
取消
</van-button>
<van-button
type="primary"
@click="confirmSelection"
class="confirm-btn"
>
确认
</van-button>
</div>
</div>
</div>
</van-popup>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import { showToast, showSuccessToast, showFailToast } from "vant";
const router = useRouter();
const route = useRoute();
// 返回上一页
const back = () => {
router.back();
};
// 接收路由传递的门禁名称
const doorName = route.params.name as string;
// 开关门记录数据
const doorRecords = [
{ name: "A01", time: "2023-10-07 20:50", status: "关门" },
{ name: "A01", time: "2023-10-07 19:30", status: "开门" },
{ name: "A01", time: "2023-10-06 17:10", status: "关门" },
{ name: "A01", time: "2023-10-06 12:06", status: "开门" },
{ name: "A01", time: "2023-10-05 11:20", status: "关门" },
{ name: "A01", time: "2023-10-05 10:20", status: "开门" },
];
// 授权人列表数据
const authorList = ref([
"张三",
"李四",
"王五",
"小明",
"韩信",
"赵云",
"李白",
"小红",
"孙尚香",
"诸葛亮",
"大乔",
"小乔",
"周瑜",
"吕布",
"貂蝉",
]);
// 选中的授权人
const selectedAuthors = ref<string[]>([]);
// 弹窗显示控制
const showPopup = ref(false);
// 计算显示的授权人最多显示6个
const displayedAuthors = computed(() => {
return selectedAuthors.value.slice(0, 6);
});
// 从localStorage加载授权人数据
const loadAuthorizations = () => {
try {
const storedData = localStorage.getItem("doorAuthorizations");
if (storedData) {
const doorAuthorizations = JSON.parse(storedData);
// 加载当前门的授权人
if (doorAuthorizations[doorName]) {
selectedAuthors.value = doorAuthorizations[doorName];
}
}
} catch (error) {
console.error("加载授权人数据失败:", error);
showFailToast("加载授权信息失败");
}
};
// 保存授权人数据到localStorage
const saveAuthorizations = () => {
try {
let doorAuthorizations = {};
const storedData = localStorage.getItem("doorAuthorizations");
if (storedData) {
doorAuthorizations = JSON.parse(storedData);
}
// 保存当前门的授权人
doorAuthorizations[doorName] = selectedAuthors.value;
localStorage.setItem(
"doorAuthorizations",
JSON.stringify(doorAuthorizations)
);
showSuccessToast("授权信息已保存");
} catch (error) {
console.error("保存授权人数据失败:", error);
showFailToast("保存授权信息失败");
}
};
// 页面加载时加载数据
onMounted(() => {
loadAuthorizations();
});
// 处理开门逻辑
const handleOpen = () => {
console.log(`尝试打开 ${doorName} 门禁`);
showToast(`正在尝试打开 ${doorName} 门禁`);
// 实际项目中可对接接口
};
// 确认选择授权人
const confirmSelection = () => {
console.log("选中的授权人:", selectedAuthors.value);
saveAuthorizations(); // 保存到本地存储
showPopup.value = false; // 关闭弹窗
};
</script>
<style scoped lang="scss">
/* 样式保持不变 */
.door-access-detail {
padding: 16px;
background-color: #fff;
min-height: 100vh;
}
.basic-info-container {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid #f5f5f5;
}
.basic-info-container p {
margin: 8px 0;
color: #333;
}
.placeholder-text {
color: #999;
}
.authorized-persons {
margin-bottom: 32px;
}
.authorize-dots {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.dot {
width: 40px;
height: 40px;
background-color: #409eff;
border-radius: 50%;
display: inline-block;
}
.person-name {
position: absolute;
bottom: -20px;
left: 50%;
transform: translateX(-50%);
font-size: 12px;
white-space: nowrap;
}
.remaining-count {
width: 40px;
height: 40px;
background-color: #e6f7ff;
color: #1890ff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
font-weight: bold;
}
.add-btn {
width: 40px;
height: 40px;
background-color: #f5f5f5;
color: #666;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
cursor: pointer;
transition: all 0.2s;
}
.add-btn:hover {
background-color: #e8e8e8;
}
.open-btn {
background-color: #409eff;
color: #fff;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin: 16px 0;
transition: background-color 0.2s;
}
.open-btn:hover {
background-color: #1890ff;
}
.record-section {
margin-top: 16px;
}
.record-title {
font-weight: bold;
margin-bottom: 12px;
color: #333;
font-size: 16px;
}
.record-table {
width: 100%;
border-collapse: collapse;
background-color: #fff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.record-table th,
.record-table td {
border-bottom: 1px solid #f5f5f5;
padding: 12px 8px;
text-align: left;
font-size: 14px;
}
.record-table th {
background-color: #fafafa;
color: #666;
}
.status-open {
color: #52c41a;
}
.status-close {
color: #f5222d;
}
/* 弹窗样式 */
.myPoput {
.popup-content {
padding: 20px;
}
.popup-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
text-align: center;
}
.checkbox-container {
max-height: 300px;
overflow-y: auto;
margin-bottom: 24px;
padding-right: 8px;
}
.author-item {
display: block;
margin-bottom: 12px;
padding: 8px;
border-radius: 4px;
transition: background-color 0.2s;
}
.author-item:hover {
background-color: #f5f5f5;
}
.popup-actions {
display: flex;
gap: 12px;
}
}
.cancel-btn,
.confirm-btn {
flex: 1;
}
</style>