Commit 849c265f authored by 夏敏伟's avatar 夏敏伟

首次提交

parents
Pipeline #506 canceled with stages
# just a flag
ENV = 'prodution'
# base api
VITE_APP_API_NAME = '/api'
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
# 项目插件
目前store有两种,一种是pinia,另外一种是vuex,据网友说第一种好用点,样式提供了scss以及less,项目路由vue-router,样式datav,ui框架ant-design-vue,项目不需要在页面使用引入vue的ref,reactive等,可直接使用。
此项目是旅馆项目。
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>旅馆项目</title>
<style>
html,body{
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{
"name": "xxx_phaseTwo_web",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "xxx_phaseTwo_web",
"version": "0.0.0",
"dependencies": {
"@kjgl77/datav-vue3": "^1.6.1",
"ant-design-vue": "^3.2.20",
"axios": "^1.4.0",
"cropperjs": "^1.5.13",
"dayjs": "^1.11.9",
"nprogress": "^0.2.0",
"pinia": "^2.1.4",
"pinia-plugin-persistedstate": "^3.2.0",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"less": "^4.1.3",
"sass": "^1.63.6",
"unplugin-auto-import": "^0.16.6",
"unplugin-vue-components": "^0.25.1",
"vite": "^4.4.0"
}
},
"node_modules/@ant-design/colors": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
"integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.0"
}
},
"node_modules/@ant-design/icons-svg": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz",
"integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw=="
},
"node_modules/@ant-design/icons-vue": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz",
"integrity": "sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-svg": "^4.2.1"
},
"peerDependencies": {
"vue": ">=3.0.3"
}
},
"node_modules/@antfu/utils": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.5.tgz",
"integrity": "sha512-dlR6LdS+0SzOAPx/TPRhnoi7hE251OVeT2Snw0RguNbBSbjUHdWr0l3vcUUDg26rEysT89kCbtw1lVorBXLLCg==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@babel/parser": {
"version": "7.22.10",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.10.tgz",
"integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==",
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz",
"integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==",
"dependencies": {
"regenerator-runtime": "^0.13.11"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@ctrl/tinycolor": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz",
"integrity": "sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==",
"engines": {
"node": ">=10"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.13.tgz",
"integrity": "sha512-KwqFhxRFMKZINHzCqf8eKxE0XqWlAVPRxwy6rc7CbVFxzUWB2sA/s3hbMZeemPdhN3fKBkqOaFhTbS8xJXYIWQ==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.13.tgz",
"integrity": "sha512-j7NhycJUoUAG5kAzGf4fPWfd17N6SM3o1X6MlXVqfHvs2buFraCJzos9vbeWjLxOyBKHyPOnuCuipbhvbYtTAg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.13.tgz",
"integrity": "sha512-M2eZkRxR6WnWfVELHmv6MUoHbOqnzoTVSIxgtsyhm/NsgmL+uTmag/VVzdXvmahak1I6sOb1K/2movco5ikDJg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.13.tgz",
"integrity": "sha512-f5goG30YgR1GU+fxtaBRdSW3SBG9pZW834Mmhxa6terzcboz7P2R0k4lDxlkP7NYRIIdBbWp+VgwQbmMH4yV7w==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.13.tgz",
"integrity": "sha512-RIrxoKH5Eo+yE5BtaAIMZaiKutPhZjw+j0OCh8WdvKEKJQteacq0myZvBDLU+hOzQOZWJeDnuQ2xgSScKf1Ovw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.13.tgz",
"integrity": "sha512-AfRPhHWmj9jGyLgW/2FkYERKmYR+IjYxf2rtSLmhOrPGFh0KCETFzSjx/JX/HJnvIqHt/DRQD/KAaVsUKoI3Xg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.13.tgz",
"integrity": "sha512-pGzWWZJBInhIgdEwzn8VHUBang8UvFKsvjDkeJ2oyY5gZtAM6BaxK0QLCuZY+qoj/nx/lIaItH425rm/hloETA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.13.tgz",
"integrity": "sha512-4iMxLRMCxGyk7lEvkkvrxw4aJeC93YIIrfbBlUJ062kilUUnAiMb81eEkVvCVoh3ON283ans7+OQkuy1uHW+Hw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.13.tgz",
"integrity": "sha512-hCzZbVJEHV7QM77fHPv2qgBcWxgglGFGCxk6KfQx6PsVIdi1u09X7IvgE9QKqm38OpkzaAkPnnPqwRsltvLkIQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.13.tgz",
"integrity": "sha512-I3OKGbynl3AAIO6onXNrup/ttToE6Rv2XYfFgLK/wnr2J+1g+7k4asLrE+n7VMhaqX+BUnyWkCu27rl+62Adug==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.13.tgz",
"integrity": "sha512-8pcKDApAsKc6WW51ZEVidSGwGbebYw2qKnO1VyD8xd6JN0RN6EUXfhXmDk9Vc4/U3Y4AoFTexQewQDJGsBXBpg==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.13.tgz",
"integrity": "sha512-6GU+J1PLiVqWx8yoCK4Z0GnfKyCGIH5L2KQipxOtbNPBs+qNDcMJr9euxnyJ6FkRPyMwaSkjejzPSISD9hb+gg==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.13.tgz",
"integrity": "sha512-pfn/OGZ8tyR8YCV7MlLl5hAit2cmS+j/ZZg9DdH0uxdCoJpV7+5DbuXrR+es4ayRVKIcfS9TTMCs60vqQDmh+w==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.13.tgz",
"integrity": "sha512-aIbhU3LPg0lOSCfVeGHbmGYIqOtW6+yzO+Nfv57YblEK01oj0mFMtvDJlOaeAZ6z0FZ9D13oahi5aIl9JFphGg==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.13.tgz",
"integrity": "sha512-Pct1QwF2sp+5LVi4Iu5Y+6JsGaV2Z2vm4O9Dd7XZ5tKYxEHjFtb140fiMcl5HM1iuv6xXO8O1Vrb1iJxHlv8UA==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.13.tgz",
"integrity": "sha512-zTrIP0KzYP7O0+3ZnmzvUKgGtUvf4+piY8PIO3V8/GfmVd3ZyHJGz7Ht0np3P1wz+I8qJ4rjwJKqqEAbIEPngA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.13.tgz",
"integrity": "sha512-I6zs10TZeaHDYoGxENuksxE1sxqZpCp+agYeW039yqFwh3MgVvdmXL5NMveImOC6AtpLvE4xG5ujVic4NWFIDQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.13.tgz",
"integrity": "sha512-W5C5nczhrt1y1xPG5bV+0M12p2vetOGlvs43LH8SopQ3z2AseIROu09VgRqydx5qFN7y9qCbpgHLx0kb0TcW7g==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.13.tgz",
"integrity": "sha512-X/xzuw4Hzpo/yq3YsfBbIsipNgmsm8mE/QeWbdGdTTeZ77fjxI2K0KP3AlhZ6gU3zKTw1bKoZTuKLnqcJ537qw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.13.tgz",
"integrity": "sha512-4CGYdRQT/ILd+yLLE5i4VApMPfGE0RPc/wFQhlluDQCK09+b4JDbxzzjpgQqTPrdnP7r5KUtGVGZYclYiPuHrw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.13.tgz",
"integrity": "sha512-D+wKZaRhQI+MUGMH+DbEr4owC2D7XnF+uyGiZk38QbgzLcofFqIOwFs7ELmIeU45CQgfHNy9Q+LKW3cE8g37Kg==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.13.tgz",
"integrity": "sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@jiaminghi/bezier-curve": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/@jiaminghi/bezier-curve/-/bezier-curve-0.0.9.tgz",
"integrity": "sha512-u9xJPOEl6Dri2E9FfmJoGxYQY7vYJkURNX04Vj64tdi535tPrpkuf9Sm0lNr3QTKdHQh0DdNRsaa62FLQNQEEw==",
"dependencies": {
"@babel/runtime": "^7.5.5"
}
},
"node_modules/@jiaminghi/c-render": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@jiaminghi/c-render/-/c-render-0.4.3.tgz",
"integrity": "sha512-FJfzj5hGj7MLqqqI2D7vEzHKbQ1Ynnn7PJKgzsjXaZpJzTqs2Yw5OSeZnm6l7Qj7jyPAP53lFvEQNH4o4j6s+Q==",
"dependencies": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/bezier-curve": "*",
"@jiaminghi/color": "*",
"@jiaminghi/transition": "*"
}
},
"node_modules/@jiaminghi/charts": {
"version": "0.2.18",
"resolved": "https://registry.npmjs.org/@jiaminghi/charts/-/charts-0.2.18.tgz",
"integrity": "sha512-K+HXaOOeWG9OOY1VG6M4mBreeeIAPhb9X+khG651AbnwEwL6G2UtcAQ8GWCq6GzhczcLwwhIhuaHqRygwHC0sA==",
"dependencies": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/c-render": "^0.4.3"
}
},
"node_modules/@jiaminghi/color": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@jiaminghi/color/-/color-1.1.3.tgz",
"integrity": "sha512-ZY3hdorgODk4OSTbxyXBPxAxHPIVf9rPlKJyK1C1db46a50J0reFKpAvfZG8zMG3lvM60IR7Qawgcu4ZDO3+Hg=="
},
"node_modules/@jiaminghi/transition": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/@jiaminghi/transition/-/transition-1.1.11.tgz",
"integrity": "sha512-owBggipoHMikDHHDW5Gc7RZYlVuvxHADiU4bxfjBVkHDAmmck+fCkm46n2JzC3j33hWvP9nSCAeh37t6stgWeg==",
"dependencies": {
"@babel/runtime": "^7.5.5"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@kjgl77/datav-vue3": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/@kjgl77/datav-vue3/-/datav-vue3-1.6.1.tgz",
"integrity": "sha512-HgEr/McsMhYIIqUhBQR0LB9Q2rFARUd4VrjcsTCyEW6RPZsCJO1Yoto/7P9jLO2uRmzfDOyxJxLx4c67rORziw==",
"dependencies": {
"@jiaminghi/c-render": "^0.4.3",
"@jiaminghi/charts": "^0.2.18",
"@jiaminghi/color": "^1.1.3",
"@vueuse/core": "^10.1.2",
"lodash-es": "^4.17.21"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.stat": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
"integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@simonwep/pickr": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.2.tgz",
"integrity": "sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==",
"dependencies": {
"core-js": "^3.15.1",
"nanopop": "^2.1.0"
}
},
"node_modules/@types/estree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
"dev": true
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.17",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz",
"integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA=="
},
"node_modules/@vitejs/plugin-vue": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz",
"integrity": "sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==",
"dev": true,
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"peerDependencies": {
"vite": "^4.0.0",
"vue": "^3.2.25"
}
},
"node_modules/@vue/compiler-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
"integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==",
"dependencies": {
"@babel/parser": "^7.21.3",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz",
"integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==",
"dependencies": {
"@vue/compiler-core": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz",
"integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==",
"dependencies": {
"@babel/parser": "^7.20.15",
"@vue/compiler-core": "3.3.4",
"@vue/compiler-dom": "3.3.4",
"@vue/compiler-ssr": "3.3.4",
"@vue/reactivity-transform": "3.3.4",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.0",
"postcss": "^8.1.10",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz",
"integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==",
"dependencies": {
"@vue/compiler-dom": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
"integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q=="
},
"node_modules/@vue/reactivity": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz",
"integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==",
"dependencies": {
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/reactivity-transform": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz",
"integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==",
"dependencies": {
"@babel/parser": "^7.20.15",
"@vue/compiler-core": "3.3.4",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.0"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz",
"integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==",
"dependencies": {
"@vue/reactivity": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz",
"integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==",
"dependencies": {
"@vue/runtime-core": "3.3.4",
"@vue/shared": "3.3.4",
"csstype": "^3.1.1"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz",
"integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==",
"dependencies": {
"@vue/compiler-ssr": "3.3.4",
"@vue/shared": "3.3.4"
},
"peerDependencies": {
"vue": "3.3.4"
}
},
"node_modules/@vue/shared": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
},
"node_modules/@vueuse/core": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.2.1.tgz",
"integrity": "sha512-c441bfMbkAwTNwVRHQ0zdYZNETK//P84rC01aP2Uy/aRFCiie9NE/k9KdIXbno0eDYP5NPUuWv0aA/I4Unr/7w==",
"dependencies": {
"@types/web-bluetooth": "^0.0.17",
"@vueuse/metadata": "10.2.1",
"@vueuse/shared": "10.2.1",
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.2.1.tgz",
"integrity": "sha512-3Gt68mY/i6bQvFqx7cuGBzrCCQu17OBaGWS5JdwISpMsHnMKKjC2FeB5OAfMcCQ0oINfADP3i9A4PPRo0peHdQ==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.2.1.tgz",
"integrity": "sha512-QWHq2bSuGptkcxx4f4M/fBYC3Y8d3M2UYyLsyzoPgEoVzJURQ0oJeWXu79OiLlBb8gTKkqe4mO85T/sf39mmiw==",
"dependencies": {
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/acorn": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ant-design-vue": {
"version": "3.2.20",
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.20.tgz",
"integrity": "sha512-YWpMfGaGoRastIXEYfCoJiaRiDHk4chqtYhlKQM5GqPt6NfvrM1Vg2e60yHtjxlZjed91wCMm0rAmyUr7Hwzdg==",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.1.0",
"@babel/runtime": "^7.10.5",
"@ctrl/tinycolor": "^3.4.0",
"@simonwep/pickr": "~1.8.0",
"array-tree-filter": "^2.1.0",
"async-validator": "^4.0.0",
"dayjs": "^1.10.5",
"dom-align": "^1.12.1",
"dom-scroll-into-view": "^2.0.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.15",
"resize-observer-polyfill": "^1.5.1",
"scroll-into-view-if-needed": "^2.2.25",
"shallow-equal": "^1.0.0",
"vue-types": "^3.0.0",
"warning": "^4.0.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ant-design-vue"
},
"peerDependencies": {
"vue": ">=3.2.0"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/array-tree-filter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
"integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw=="
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/compute-scroll-into-view": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
"integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
},
"node_modules/copy-anything": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
"integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
"dev": true,
"dependencies": {
"is-what": "^3.14.1"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/core-js": {
"version": "3.31.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz",
"integrity": "sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cropperjs": {
"version": "1.5.13",
"resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.13.tgz",
"integrity": "sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA=="
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"node_modules/dayjs": {
"version": "1.11.9",
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz",
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA=="
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dom-align": {
"version": "1.12.4",
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz",
"integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw=="
},
"node_modules/dom-scroll-into-view": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz",
"integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w=="
},
"node_modules/errno": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"optional": true,
"dependencies": {
"prr": "~1.0.1"
},
"bin": {
"errno": "cli.js"
}
},
"node_modules/esbuild": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.13.tgz",
"integrity": "sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.18.13",
"@esbuild/android-arm64": "0.18.13",
"@esbuild/android-x64": "0.18.13",
"@esbuild/darwin-arm64": "0.18.13",
"@esbuild/darwin-x64": "0.18.13",
"@esbuild/freebsd-arm64": "0.18.13",
"@esbuild/freebsd-x64": "0.18.13",
"@esbuild/linux-arm": "0.18.13",
"@esbuild/linux-arm64": "0.18.13",
"@esbuild/linux-ia32": "0.18.13",
"@esbuild/linux-loong64": "0.18.13",
"@esbuild/linux-mips64el": "0.18.13",
"@esbuild/linux-ppc64": "0.18.13",
"@esbuild/linux-riscv64": "0.18.13",
"@esbuild/linux-s390x": "0.18.13",
"@esbuild/linux-x64": "0.18.13",
"@esbuild/netbsd-x64": "0.18.13",
"@esbuild/openbsd-x64": "0.18.13",
"@esbuild/sunos-x64": "0.18.13",
"@esbuild/win32-arm64": "0.18.13",
"@esbuild/win32-ia32": "0.18.13",
"@esbuild/win32-x64": "0.18.13"
}
},
"node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/fast-glob": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2",
"merge2": "^1.3.0",
"micromatch": "^4.0.4"
},
"engines": {
"node": ">=8.6.0"
}
},
"node_modules/fastq": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
"dev": true,
"dependencies": {
"reusify": "^1.0.4"
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"optional": true
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"optional": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
"dev": true,
"optional": true,
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/immutable": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.1.tgz",
"integrity": "sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A==",
"dev": true
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-core-module": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-plain-object": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
"integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-what": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
"dev": true
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/jsonc-parser": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
"node_modules/less": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz",
"integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==",
"dev": true,
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",
"tslib": "^2.3.0"
},
"bin": {
"lessc": "bin/lessc"
},
"engines": {
"node": ">=6"
},
"optionalDependencies": {
"errno": "^0.1.1",
"graceful-fs": "^4.1.2",
"image-size": "~0.5.0",
"make-dir": "^2.1.0",
"mime": "^1.4.1",
"needle": "^3.1.0",
"source-map": "~0.6.0"
}
},
"node_modules/local-pkg": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
"integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
"dev": true,
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/magic-string": {
"version": "0.30.1",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
"integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
"engines": {
"node": ">=12"
}
},
"node_modules/make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"optional": true,
"dependencies": {
"pify": "^4.0.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
"dependencies": {
"braces": "^3.0.2",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"optional": true,
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/mlly": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz",
"integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==",
"dev": true,
"dependencies": {
"acorn": "^8.9.0",
"pathe": "^1.1.1",
"pkg-types": "^1.0.3",
"ufo": "^1.1.2"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/nanopop": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.3.0.tgz",
"integrity": "sha512-fzN+T2K7/Ah25XU02MJkPZ5q4Tj5FpjmIYq4rvoHX4yb16HzFdCO6JxFFn5Y/oBhQ8no8fUZavnyIv9/+xkBBw=="
},
"node_modules/needle": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz",
"integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==",
"dev": true,
"optional": true,
"dependencies": {
"debug": "^3.2.6",
"iconv-lite": "^0.6.3",
"sax": "^1.2.4"
},
"bin": {
"needle": "bin/needle"
},
"engines": {
"node": ">= 4.4.x"
}
},
"node_modules/needle/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"optional": true,
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz",
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
},
"node_modules/parse-node-version": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
"dev": true,
"engines": {
"node": ">= 0.10"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/pathe": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
"integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==",
"dev": true
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true,
"optional": true,
"engines": {
"node": ">=6"
}
},
"node_modules/pinia": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.4.tgz",
"integrity": "sha512-vYlnDu+Y/FXxv1ABo1vhjC+IbqvzUdiUC3sfDRrRyY2CQSrqqaa+iiHmqtARFxJVqWQMCJfXx1PBvFs9aJVLXQ==",
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@vue/composition-api": "^1.4.0",
"typescript": ">=4.4.4",
"vue": "^2.6.14 || ^3.3.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/pinia-plugin-persistedstate": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.0.tgz",
"integrity": "sha512-tZbNGf2vjAQcIm7alK40sE51Qu/m9oWr+rEgNm/2AWr1huFxj72CjvpQcIQzMknDBJEkQznCLAGtJTIcLKrKdw==",
"peerDependencies": {
"pinia": "^2.0.0"
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/pkg-types": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
"integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
"dev": true,
"dependencies": {
"jsonc-parser": "^3.2.0",
"mlly": "^1.2.0",
"pathe": "^1.1.0"
}
},
"node_modules/postcss": {
"version": "8.4.26",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz",
"integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
"dev": true,
"optional": true
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
},
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"dev": true,
"dependencies": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
},
"node_modules/rollup": {
"version": "3.26.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.3.tgz",
"integrity": "sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=14.18.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"queue-microtask": "^1.2.2"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"node_modules/sass": {
"version": "1.63.6",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.63.6.tgz",
"integrity": "sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"node_modules/scroll-into-view-if-needed": {
"version": "2.2.31",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
"integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
"dependencies": {
"compute-scroll-into-view": "^1.0.20"
}
},
"node_modules/scule": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/scule/-/scule-1.0.0.tgz",
"integrity": "sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==",
"dev": true
},
"node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"optional": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/shallow-equal": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strip-literal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz",
"integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==",
"dev": true,
"dependencies": {
"acorn": "^8.8.2"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/tslib": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
"integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==",
"dev": true
},
"node_modules/ufo": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz",
"integrity": "sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==",
"dev": true
},
"node_modules/unimport": {
"version": "3.0.14",
"resolved": "https://registry.npmjs.org/unimport/-/unimport-3.0.14.tgz",
"integrity": "sha512-67Rh/sGpEuVqdHWkXaZ6NOq+I7sKt86o+DUtKeGB6dh4Hk1A8AQrzyVGg2+LaVEYotStH7HwvV9YSaRjyT7Uqg==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.2",
"escape-string-regexp": "^5.0.0",
"fast-glob": "^3.3.0",
"local-pkg": "^0.4.3",
"magic-string": "^0.30.0",
"mlly": "^1.4.0",
"pathe": "^1.1.1",
"pkg-types": "^1.0.3",
"scule": "^1.0.0",
"strip-literal": "^1.0.1",
"unplugin": "^1.3.1"
}
},
"node_modules/unplugin": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.4.0.tgz",
"integrity": "sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==",
"dev": true,
"dependencies": {
"acorn": "^8.9.0",
"chokidar": "^3.5.3",
"webpack-sources": "^3.2.3",
"webpack-virtual-modules": "^0.5.0"
}
},
"node_modules/unplugin-auto-import": {
"version": "0.16.6",
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.16.6.tgz",
"integrity": "sha512-M+YIITkx3C/Hg38hp8HmswP5mShUUyJOzpifv7RTlAbeFlO2Tyw0pwrogSSxnipHDPTtI8VHFBpkYkNKzYSuyA==",
"dev": true,
"dependencies": {
"@antfu/utils": "^0.7.5",
"@rollup/pluginutils": "^5.0.2",
"fast-glob": "^3.3.0",
"local-pkg": "^0.4.3",
"magic-string": "^0.30.1",
"minimatch": "^9.0.2",
"unimport": "^3.0.14",
"unplugin": "^1.3.2"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@nuxt/kit": "^3.2.2",
"@vueuse/core": "*"
},
"peerDependenciesMeta": {
"@nuxt/kit": {
"optional": true
},
"@vueuse/core": {
"optional": true
}
}
},
"node_modules/unplugin-vue-components": {
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.25.1.tgz",
"integrity": "sha512-kzS2ZHVMaGU2XEO2keYQcMjNZkanDSGDdY96uQT9EPe+wqSZwwgbFfKVJ5ti0+8rGAcKHColwKUvctBhq2LJ3A==",
"dev": true,
"dependencies": {
"@antfu/utils": "^0.7.4",
"@rollup/pluginutils": "^5.0.2",
"chokidar": "^3.5.3",
"debug": "^4.3.4",
"fast-glob": "^3.2.12",
"local-pkg": "^0.4.3",
"magic-string": "^0.30.0",
"minimatch": "^9.0.1",
"resolve": "^1.22.2",
"unplugin": "^1.3.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@babel/parser": "^7.15.8",
"@nuxt/kit": "^3.2.2",
"vue": "2 || 3"
},
"peerDependenciesMeta": {
"@babel/parser": {
"optional": true
},
"@nuxt/kit": {
"optional": true
}
}
},
"node_modules/vite": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.4.tgz",
"integrity": "sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==",
"dev": true,
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.25",
"rollup": "^3.25.2"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
},
"node_modules/vue": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz",
"integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==",
"dependencies": {
"@vue/compiler-dom": "3.3.4",
"@vue/compiler-sfc": "3.3.4",
"@vue/runtime-dom": "3.3.4",
"@vue/server-renderer": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/vue-router": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz",
"integrity": "sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==",
"dependencies": {
"@vue/devtools-api": "^6.5.0"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/vue-types": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz",
"integrity": "sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==",
"dependencies": {
"is-plain-object": "3.0.1"
},
"engines": {
"node": ">=10.15.0"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/webpack-sources": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
"dev": true,
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/webpack-virtual-modules": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz",
"integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
"dev": true
}
}
}
{
"name": "xxx_phaseTwo_web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@kjgl77/datav-vue3": "^1.6.1",
"ant-design-vue": "^3.2.20",
"axios": "^1.4.0",
"cropperjs": "^1.5.13",
"dayjs": "^1.11.9",
"nprogress": "^0.2.0",
"pinia": "^2.1.4",
"pinia-plugin-persistedstate": "^3.2.0",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"less": "^4.1.3",
"sass": "^1.63.6",
"unplugin-auto-import": "^0.16.6",
"unplugin-vue-components": "^0.25.1",
"vite": "^4.4.0"
}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
<script setup>
import zhCN from 'ant-design-vue/es/locale/zh_CN';
</script>
<template>
<a-config-provider :locale="zhCN">
<router-view></router-view>
</a-config-provider>
</template>
<style scoped>
</style>
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取所有国家
export const getAllCountry = () => {
return request({
url: '/agile/rest/index/api/default/queryNationalityType',
method: 'GET'
});
}
//获取签证类型
export const getAllVisa = () => {
return request({
url: '/agile/rest/index/api/default/queryVisaType',
method: 'GET'
});
}
//获取性别
export const getAllGender = () => {
return request({
url: '/agile/rest/index/api/default/queryGenderType',
method: 'GET'
});
}
//获取外宾证件种类
export const getAllForeignGuest = () => {
return request({
url: '/agile/rest/index/api/default/queryForeignGuestType',
method: 'GET'
});
}
//获取内宾证件种类
export const getAllInternalGuest = () => {
return request({
url: '/agile/rest/index/api/default/queryInternalGuestType',
method: 'GET'
});
}
//获取车牌类型
export const getAllPlateNumber = () => {
return request({
url: '/agile/rest/index/api/default/queryPlateNumberType',
method: 'GET'
});
}
//入境事由
export const getAllReasonEntry = () => {
return request({
url: '/agile/rest/index/api/default/queryReasonEntryType',
method: 'GET'
});
}
//查询省市县
export const getAllProvinciaUrbanAreas = () => {
return request({
url: '/agile/rest/index/api/default/queryProvincialUrbanAreas',
method: 'GET'
});
}
//查询民族
export const getAllNation = () => {
return request({
url: '/agile/rest/index/api/default/queryNationType',
method: 'GET'
});
}
//查询房间类型
export const getAllRoomType = () => {
return request({
url: '/agile/rest/index/api/default/queryRoomType',
method: 'GET'
});
}
//查询所有字典
export const getAllCode = () => {
return request({
url: '/rest/hotel/code/queryList',
method: 'GET'
});
}
//图片上传
export const uploadImg = (data) => {
return request({
url: '/rest/file/upload?bucket=PHOTO',
method: 'POST',
data
});
}
//查看图片路径
export const getImgByUrl = (params) => {
return request({
url: '/rest/file/pathPhoto',
method: 'POST',
params
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取派出所组织机构
export const getDeptTree = () => {
return request({
url: '/rest/hotel/dept/queryTree',
method: 'GET'
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
/**内宾分页查询 */
export const inlandQuery = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/queryListByParams',
method: 'POST',
data
});
}
/**内宾单个查询 */
export const inlandQueryOne = (params) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/queryDomesticGuestDetail',
method: 'GET',
params
});
}
/**内宾登记 */
export const inlandAdd = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/add',
method: 'POST',
data
});
}
/**内宾更新 */
export const inlandEdit = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/updateInfo',
method: 'POST',
data
});
}
/**内宾删除 */
export const inlandDelete = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/bulkRemove',
method: 'POST',
data
});
}
/**内宾离店 */
export const inlandCheckOut = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/departure',
method: 'POST',
data
});
}
// /**内宾个人信息查询 */
// export const inlandOneQuery = params => {
// return request({
// url: '/rest/hotel/domesticGuestCheckIn/departure',
// method: 'GET',
// params
// });
// }
/**字典查询 */
export const inlandGender = params => {
return request({
url: '/agile/rest/index/api/default/queryGenderType',
method: 'GET',
params
});
}
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//新增外宾
export const addForeignGuestCheckIn = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/add',
method: 'POST',
data
});
}
//查询外宾
export const getForeignGuestCheckInList = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/queryListByParams',
method: 'POST',
data
});
}
//外宾离店
export const departureForeignGuestCheckIn = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/departure',
method: 'POST',
data
});
}
//更新外宾
export const updateForeignGuestCheckInList = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/updateInfo',
method: 'POST',
data
});
}
//查询外宾详情
export const queryForeignGuestDetail = (params) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/queryForeignGuestDetail',
method: 'GET',
params
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//根据派出所编号查找旅馆
export const queryHotelByDept = (params) => {
return request({
url: '/rest/hotel/hotel/queryList',
method: 'GET',
params
});
}
//根据旅馆编号查找旅馆信息
export const queryHotel = (params) => {
return request({
url: '/rest/hotel/hotel/queryHotelInfo',
method: 'POST',
params
});
}
//修改旅馆基本信息
export const updateHotel = (data) => {
return request({
url: '/rest/hotel/hotel/updateInfo',
method: 'POST',
data
});
}
//多图片上传
export const upLoadArrayImage = (data) => {
return request({
url: "/rest/hotel/hotel/uploadImage",
method: 'POST',
data
})
}
//删除旅馆单图片上传的图片
export const removeArrayImage = (data) => {
return request({
url: "/rest/file/batchRemove",
method: 'POST',
data
})
}
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//查询主页面菜单
export const getTree = (data) => {
return request({
url: '/rest/system/menu/queryTree',
method: "POST",
data
})
};
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
/**恢复内宾 */
export const restoreDomesticGuestsToStay = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/restoreDomesticGuestsToStay',
method: 'POST',
data
});
}
/**恢复外宾 */
export const restoreForeignGuestsToStay = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/restoreForeignGuestsToStay',
method: 'POST',
data
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//权限查询
export const queryRole = () => {
return request({
url: '/rest/system/role/queryList',
method: 'GET'
})
}
//权限菜单提交
export const grantMenuRole = (data,roleId) => {
return request({
url: '/rest/system/role/grantMenu/'+roleId,
method: 'POST',
data
})
}
//角色新增
export const addRoles = (data) => {
return request({
url: '/rest/system/role/add',
method: 'POST',
data
})
}
//角色编辑
export const updateRoles = (data) => {
return request({
url: '/rest/system/role/updateInfo',
method: 'POST',
data
})
}
//角色删除
export const bulkRemoveRoles = (data) => {
return request({
url: '/rest/system/role/bulkRemove',
method: 'POST',
data
})
}
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取所有房间号
export const getAllRoom = params => {
return request({
url: '/rest/hotel/room/queryList',
method: 'GET',
params
});
}
//新增房间号
export const addRooms = data => {
return request({
url: '/rest/hotel/room/batchAddRoom',
method: 'POST',
data
});
}
//预览新增房间号
export const previewRooms = data => {
return request({
url: '/rest/hotel/room/createRooms',
method: 'POST',
data
});
}
//分页查询房间
export const getRooms = data=>{
return request({
url:'/rest/hotel/room/queryListByParams',
method:'POST',
data
})
}
//编辑房间
export const updateRoomsInfo = data=>{
return request({
url:'/rest/hotel/room/updateInfo',
method:'POST',
data
})
}
//删除房间
export const bulkRemoveRooms = data=>{
return request({
url:'/rest/hotel/room/bulkRemove',
method:'POST',
data
})
}
//查询房间状态 上部分
export const queryRoomStatus = params=>{
return request({
url:'/rest/hotel/hotelManger/statistics',
method:'POST',
params
})
}
//查询房间状态 下部分
export const queryStatisticsRoomStatus = params=>{
return request({
url:'/rest/hotel/hotelManger/statisticsRoomStatus',
method:'POST',
params
})
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//入境事由
export const getAllTeam = (params) => {
return request({
url: '/rest/hotel/team/queryList',
method: 'GET',
params
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取验证码
export const getVerifyCode = (params) => {
return request({
url: "/rest/system/user/verifyCode",
method: "GET",
params,
responseType: 'arraybuffer'
});
};
//查询用户列表
export const getUserList = (data) => {
return request({
url: '/rest/system/user/queryList',
method: "POST",
data
})
}
//用户登录
export const login = (data) => {
return request({
url: '/rest/system/user/login',
method: 'POST',
data
})
}
//用户注册
export const register = (data) => {
return request({
url: '/rest/system/user/add',
method: 'POST',
data
});
}
//修改用户密码
export const editPassword = params => {
return request({
url: "/rest/system/user/updatePassword",
method: 'GET',
params
})
}
//重置密码
export const resetPassword = params => {
return request({
url: "/rest/system/user/resetPassword",
method: 'GET',
params
})
}
//图片上传
export const upLoadImg = (data) => {
return request({
url: "/rest/file/uploadPhoto",
method: 'POST',
data
})
}
//用户新增
export const addPersonnel = (data) => {
return request({
url: "/rest/system/user/add",
method: 'POST',
data
})
}
//用户更新
export const updatePersonnel = (data) => {
return request({
url: "/rest/system/user/updateInfo",
method: 'POST',
data
})
}
//删除用户
export const removePersonnel = (params) => {
return request({
url: "/rest/system/user/remove",
method: 'GET',
params
})
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//新增访客
export const addVisitorRegist = (data) => {
return request({
url: '/rest/hotel/visitorRegist/add',
method: 'POST',
data
});
}
//查询访客
export const getVisitorList = (data) => {
return request({
url: '/rest/hotel/visitorRegist/queryListByParams',
method: 'POST',
data
});
}
//编辑访客
export const updateVisitorRegist = (data) => {
return request({
url: '/rest/hotel/visitorRegist/updateInfo',
method: 'POST',
data
});
}
//离店访客
export const departureVisitorRegist = (data) => {
return request({
url: '/rest/hotel/visitorRegist/departure',
method: 'POST',
data
});
}
//查询访客详情
export const queryVisitorRegistDetail = (params) => {
return request({
url: '/rest/hotel/visitorRegist/queryVisitorRegistDetail',
method: 'GET',
params
});
}
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
\ No newline at end of file
import { Modal, message } from 'ant-design-vue';
import 'ant-design-vue/es/message/style/css';
import 'ant-design-vue/es/modal/style/css';
export default {
install(app) {
//挂载全局对象
app.config.globalProperties.$message = message
app.config.globalProperties.$Modal = Modal
}
}
\ No newline at end of file
<template>
<a-modal class="handleForm" :visible="visible" :title="title" :width="600" :bodyStyle="{ padding: '16px 24px' }" @ok="handleOk" @cancel="handleCancel" :destroyOnClose="true" :maskClosable="false">
<video ref="local_video1" width="560" height="480" style="object-fit: fill" autoplay></video>
</a-modal>
</template>
<script setup>
import { reactive, ref, defineProps, onMounted, getCurrentInstance } from "vue";
import { message } from 'ant-design-vue';
const props = defineProps({
visible: Boolean,
title: String,
});
const emit = defineEmits(["handleSubmit", "changeCancel"]);
const local_video = ref("");
/**打开摄像头 */
const OnCamera = () => {
navigator.getUserMedia(
{
audio: false,
video: true,
},
function (stream) {
local_video.value.srcObject = stream;
},
function (error) {
console.log(error);
message.warning('未找到摄像头设备,请检查设备是否插紧');
}
);
};
/**关闭摄像头 */
const OffCamera = () => {
if (local_video.value.srcObject != null) {
let stream = local_video.value.srcObject;
stream.getTracks().forEach(function (track) {
track.stop();
});
local_video.value.srcObject = null;
}
};
const imgBase64 = ref("");
/**截图 */
const screenshot = () => {
const canvas = document.createElement("canvas");
const canvasCtx = canvas.getContext("2d");
const ratio = window.devicePixelRatio || 1;
canvasCtx.scale(ratio, ratio);
canvas.width = local_video.value.offsetWidth * ratio;
canvas.height = local_video.value.offsetHeight * ratio;
canvasCtx.drawImage(local_video.value, 0, 0, canvas.width, canvas.height);
imgBase64.value = canvas.toDataURL("image/png");
OffCamera();
};
// 提交事件
const handleOk = async () => {
screenshot();
await emit("handleSubmit", imgBase64, handleCancel);
};
// 关闭弹框事件
const handleCancel = async () => {
OffCamera();
await emit("changeCancel", false);
};
onMounted(() => {
const instance = getCurrentInstance();
local_video.value = instance?.refs.local_video1;
OnCamera();
});
</script>
<style lang="less" scoped>
.handleForm {
:deep(.ant-modal-content .ant-modal-close-x) {
width: 49px;
height: 49px;
line-height: 49px;
}
:deep(.ant-modal-content .ant-modal-body) {
padding-block: 16px;
}
.form {
:deep(.ant-form-item-with-help) {
margin-bottom: -16px;
}
:deep(.ant-input-number, .ant-picker) {
width: 100%;
}
:deep(.ant-form-item) {
margin-right: 0;
margin-bottom: 10px;
}
}
.dropPoint {
display: flex;
justify-content: space-between;
align-items: center;
> .ant-input {
flex: 1;
margin-right: 10px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal
class="handleForm"
:visible="visible"
:title="title"
:width="800"
:bodyStyle="{ padding: '16px 24px' }"
@ok="handleOk"
@cancel="handleCancel"
:destroyOnClose="true"
:maskClosable="false"
>
<div style="display: flex">
<div style="width: 65%">
<!--使用ref属性给图片元素命名为imageRef-->
<img ref="imageRef" :src="imageSrc" alt="image" style="width: 600px" />
<div style="margin-top: 20px">
<a-space :size="40">
<a-button type="primary" @click="retake">重拍</a-button>
<a-button type="primary" @click="cropImage">裁剪图片</a-button>
</a-space>
</div>
</div>
<div style="width: 35%; text-align: center; margin-left: 20px">
<div style="font-size: 20px; line-height: 70px; font-weight: 600">
<span>预览</span>
</div>
<div>
<a-image
width="186.829px"
height="230px"
:src="croppedImage"
fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="
/>
</div>
</div>
</div>
</a-modal>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import Cropper from "cropperjs";
import "cropperjs/dist/cropper.css";
const props = defineProps({
//图片地址
imageSrc: {
type: String,
required: true,
},
//aspectRatio:置裁剪框为固定的宽高比
aspectRatio: {
type: Number,
default: 0.812,
},
//viewMode: 视图控制
viewMode: {
type: Number,
default: 1,
},
//autoCropArea: 设置裁剪区域占图片的大小 值为 0-1 默认 0.8 表示 80%的区域
autoCropArea: {
type: Number,
default: 0.8,
},
visible: Boolean,
title: String,
});
//绑定图片的dom对象
const imageRef = ref(null);
let cropper = null;
//使用Cropper构造函数创建裁剪器实例,并将图片元素和一些裁剪选项传入
onMounted(() => {
new_Cropper();
});
/**导入图片 */
const new_Cropper = () => {
cropper = new Cropper(imageRef.value, {
aspectRatio: props.aspectRatio,
viewMode: props.viewMode,
autoCropArea: props.autoCropArea,
});
};
//定义方法
const emit = defineEmits([
"updateImageSrc",
"changeCancel",
"handleSubmit",
"handleRetake",
]);
//在cropImage函数中,获取裁剪后的图片数据URL,并使用emit方法触发updateImageSrc事件,
// 将裁剪后的图片数据URL传递给父组件。
const croppedImage = ref("");
const cropImage = () => {
const canvas = cropper.getCroppedCanvas();
croppedImage.value = canvas.toDataURL();
// emit("updateImageSrc", croppedImage);
};
/**重拍 */
const retake = async () => {
await emit("handleRetake", {}, handleCancel);
};
// 提交事件
const handleOk = async () => {
await emit("handleSubmit", croppedImage, handleCancel);
};
// 关闭弹框事件
const handleCancel = async () => {
await emit("changeCancel");
};
//销毁
onBeforeUnmount(() => {
cropper.destroy();
});
</script>
\ No newline at end of file
<script setup>
import { onMounted, reactive } from "vue";
import { getInfo } from "../api/commonapi";//引入接口方法
import { BorderBox3 as DvBorderBox3 } from '@kjgl77/datav-vue3'
const userInfo = reactive({
userName: "XXX",
age: "XX",
});
onMounted(() => {
//调接口,处理返回结果
getInfo({ orgid: "3348847743" }).then((res) => {
userInfo.userName=res.userName
userInfo.age=res.age
});
});
</script>
<template>
<h1>{{ userInfo.userName }}---{{ userInfo.age }}</h1>
<div w50rem h18rem flex justify-center items-center bg-dark>
<dv-decoration1 style="width:200px;height:50px;" />
</div>
</template>
<style scoped>
</style>
\ No newline at end of file
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index'//引入路由
//ant-design-vue
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
import * as Icons from '@ant-design/icons-vue';
// import base from './base';
import DataVVue3 from '@kjgl77/datav-vue3'
// 引用
import {createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
// 创建Pinia实例
const Pinia = createPinia()
Pinia.use(piniaPluginPersistedstate);
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-zn');
const app = createApp(App)
app.use(router)
.use(Antd)
// .use(base)
.use(Pinia)
.use(DataVVue3)
.mount('#app')
for (const i in Icons){
app.component(i,Icons[i])
}
\ No newline at end of file
// 用于处理动态菜单数据,将其转为 route 形式
export const addRoutes = (menulist = [], routes = []) => {
let temp = [];
let route = [];
for (let i = 0; i < menulist.length; i++) {
if (menulist[i].children && menulist[i].children.length > 0) {
route = getRoute(menulist[i]);
route.children = addRoutes(menulist[i].children);
routes.push(route);
} else {
temp.push(getRoute(menulist[i]));
}
}
// 返回路由结果
return routes.concat(temp)
}
// 路由懒加载
const loadView = (path) => {
return () => import(`../view${path}.vue`);
}
// 返回路由的基本格式
const getRoute = item => {
// const modules =
// import.meta.glob('../views/**/*.vue')
let route = {
path: item.path,
name: item.label,
component: loadView(item.path) ,
// 路由的子路由
children: []
};
// 返回 route
return route
}
\ No newline at end of file
import {
createRouter,
createWebHashHistory
} from "vue-router";
import nProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {
useStore
} from '../store/index';
nProgress.configure({
showSpinner: false
})
const router = createRouter({
// 内部提供了 history 模式的实现
// createWebHistory路由模式路径不带#号(生产环境下不能直接访问项目,需要nginx转发)
// createWebHashHistory路由模式路径带#号
history: createWebHashHistory(),
routes: [{
path: "/login",
name: "login",
component: () => import("../views/login/login.vue"),
},
{
path: "/",
name: "homepage",
component: () => import("../views/homePage/homepage.vue"),
redirect: '/inland/inlandAdd',
meta: {
keepAlive: false
},
children: [{
path: "/hotel/index",
name: "旅馆概况",
component: () => import("@/views/hotel/index.vue"),
},
{
path: "/inland/inland",
name: "内宾基本情况",
component: () => import("@/views/inland/inland.vue"),
},
{
path: "/inland/inlandAdd",
name: "内宾入住",
component: () => import("@/views/inland/inlandAdd.vue"),
},
{
path: "/abroad/abroad",
name: "外宾基本情况",
component: () => import("@/views/abroad/abroad.vue"),
},
{
path: "/abroad/abroadAdd",
name: "外宾入住",
component: () => import("@/views/abroad/abroadAdd.vue"),
},
{
path: "/room/room",
name: "房号管理",
component: () => import("@/views/room/room.vue"),
},
{
path: "/visitor/visitor",
name: "访客管理",
component: () => import("@/views/visitor/visitor.vue"),
},
{
path: "/visitor/visitorAdd",
name: "访客登记",
component: () => import("@/views/visitor/visitorAdd.vue"),
},
{
path: "/departure/departure",
name: "离店",
component: () => import("@/views/departure/departure.vue"),
},
{
path: "/hotel/hotelEdit",
name: "旅馆基础信息管理",
component: () => import("@/views/hotel/hotelEdit.vue"),
},
{
path: "/restoreCheckIn/restoreCheckIn",
name: "酒店误操作恢复在住",
component: () => import("@/views/restoreCheckIn/restoreCheckIn.vue"),
},
{
path: "/employeeManagement/personnelManagement",
name: "人员管理",
component: () => import("@/views//employeeManagement/personnelManagement.vue"),
},
{
path: "/employeeManagement/rolesManagement",
name: "角色管理",
component: () => import("@/views//employeeManagement/rolesManagement.vue"),
}
]
},
],
});
// 全局前置守卫
router.beforeEach(async (to, from, next) => {
nProgress.start()
const usestor = useStore();
const hasToken = usestor.token;
// 1.路由跳转前先判断是否有token
if (hasToken) {
// 1.1登录成功,跳转到首页
if (to.path === '/login') {
next();
nProgress.done();
} else {
// 1.2登录成功,去其他页面----要判断是否有用户信息
const hasUserInfo = usestor.userInfo.username;
//有用户信息
if (hasUserInfo) {
// 1.2.1如果没有从已有的所有路由中匹配到路由,有从上个路由过来的就直接跳到上个路由,否则就跳到登录页
if (to.matched.length === 0) {
// next({name: ''})----通过名称导航到特定路由。name: 是我要导航到的路由名称
from.name ? next({
name: from.name
}) : next('/login');
} else {
next();
}
} else {
// 1.2.2 登录成功但 没有用户信息----先通过store获取用户信息,根据用户来获取并添加动态路由
next();
}
}
} else {
//2.没有token的话可以访问白名单页面(登录页面)
if (to.name == 'login') {
next()
} else {
next('/login');
}
// console.log(1);
nProgress.done();
}
})
// 全局后置钩子
router.afterEach(() => {
nProgress.done(true)
})
export default router;
\ No newline at end of file
import {
defineStore
} from 'pinia'
import {
login
} from '@/api/user';
import {
message
} from 'ant-design-vue';
import router from '@/router/index';
import {
getAllRoom
} from '@/api/room.js'
import {
// getAllCountry,
// getAllVisa,
// getAllGender,
// getAllForeignGuest,
// getAllInternalGuest,
// getAllPlateNumber,
// getAllReasonEntry,
// getAllProvinciaUrbanAreas,
// getAllNation,
// getAllRoomType,
getAllCode
} from '@/api/default';
export const useStore = defineStore('user', () => {
const userInfo = ref();
const token = ref(null);
const hotelInfo = ref({
hotelId: null,
hotelAddress: null
});
const menuParams = ref({
selectedKeys: ['/inland/inlandAdd'],
openKeys: ['lkgl', '/inland/inlandAdd'],
preOpenKeys: ['lkgl'],
activeKey: '/inland/inlandAdd',
panes: [{ title: '内宾入住', key: '/inland/inlandAdd', closable: false }]
});
// const hotelId = ref(null);
const roomAll = ref([]);
// const defaultType = ref({
// countryAll: [],
// visaAll: [],
// genderAll: [],
// foreignGuestAll: [],
// internalGuestAll: [],
// plateNumberAll: [],
// reasonEntryAll: [],
// provinciaUrbanAreasAll: [],
// nationAll: [],
// roomAllType: [],
// checkInStatusAll: [],
// departmentAll: []
// });
const defaultType = ref([]);
const getUserInfo = async (param) => {
login(param).then(res => {
if (res.code == '9000') {
message.success('登录成功!');
hotelInfo.value.hotelId = param.hotelId;
hotelInfo.value.hotelAddress = param.address;
token.value = res.data;
let strings = res.data.split("."); //截取token,获取载体
userInfo.value = JSON.parse(decodeURIComponent(escape(window.atob(strings[1].replace(/-/g, "+").replace(/_/g, "/")))));
router.push({
name: 'homepage'
});
getAllCode().then(res => {
defaultType.value = res.data;
// for (let i = 0; i < res.data.length; i++) {
// switch (res.data[i].key) {
// case 1: //查询房间类型
// defaultType.value.roomAllType = res.data[i];
// break;
// case 2: //查询入住状态
// defaultType.value.checkInStatusAll = res.data[i];
// break;
// case 3: //查询所有内宾证件种类
// defaultType.value.internalGuestAll = res.data[i];
// break;
// case 4: //查询所有外宾证件种类
// defaultType.value.foreignGuestAll = res.data[i];
// break;
// case 5: //查询性别
// defaultType.value.genderAll = res.data[i];
// break;
// case 6: //查询所有车牌类型
// defaultType.value.plateNumberAll = res.data[i];
// break;
// case 7: //查询入境事由
// defaultType.value.reasonEntryAll = res.data[i];
// break;
// case 8: //查询所有签证种类
// defaultType.value.visaAll = res.data[i];
// break;
// case 9: //查询所有国家
// defaultType.value.countryAll = res.data[i];
// break;
// case 10: //查询所有民族
// defaultType.value.visaAll = res.data[i];
// break;
// case 11: //查询全国省市县
// defaultType.value.departmentAll = res.data[i];
// break;
// }
// }
})
//当前酒店下所有的房间号
getAllRoom({
hotelid: param.hotelId
}).then(res => {
roomAll.value = res.data;
});
// //查询所有国家
// getAllCountry().then(res => {
// defaultType.value.countryAll = res.data;
// });
// //查询所有签证种类
// getAllVisa().then(res => {
// defaultType.value.visaAll = res.data;
// })
// //查询性别
// getAllGender().then(res => {
// defaultType.value.genderAll = res.data;
// })
// //查询所有外宾证件种类
// getAllForeignGuest().then(res => {
// defaultType.value.foreignGuestAll = res.data;
// })
// //查询所有内宾证件种类
// getAllInternalGuest().then(res => {
// defaultType.value.internalGuestAll = res.data;
// })
// //查询所有车牌类型
// getAllPlateNumber().then(res => {
// defaultType.value.plateNumberAll = res.data;
// });
// //查询入境事由
// getAllReasonEntry().then(res => {
// defaultType.value.reasonEntryAll = res.data;
// })
// //查询省市县
// getAllProvinciaUrbanAreas().then(res => {
// defaultType.value.provinciaUrbanAreasAll = res.data;
// })
// //查询所有民族
// getAllNation().then(res => {
// defaultType.value.nationAll = res.data;
// })
// //查询所有房间类型
// getAllRoomType().then(res => {
// defaultType.value.roomAllType = res.data;
// })
}
}).catch(err => {
message.error(err.message);
})
}
const clearUserInfo = () => {
userInfo.value = {};
localStorage.removeItem('user');
};
const returnCode = key => {
if (defaultType.value.length > 0) {
let mateCode = defaultType.value.filter(item => {
return item.key == key
});
return mateCode[0].value
} else {
getCode();
}
}
const getCode = () => {
getAllCode().then(res => {
defaultType.value = res.data;
let mateCode = defaultType.value.filter(item => {
return item.key == key
});
return mateCode[0].value
})
}
const clearAll = () => {
defaultType.value = [];
roomAll.value = [];
}
const setAll = (dataCode,dataRoom) => {
defaultType.value = dataCode;
roomAll.value = dataRoom
}
return {
userInfo,
token,
hotelInfo,
menuParams,
// hotelId,
roomAll,
defaultType,
returnCode,
getUserInfo,
clearUserInfo,
clearAll,
setAll,
}
}, {
persist: true
})
\ No newline at end of file
import {
defineStore
} from 'pinia';
export const websocketStore = defineStore('websocket', () => {
const identityInformation = ref({});
return {
identityInformation
}
}, {
persist: true
})
\ No newline at end of file
: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;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
width: 100%;
height: 100%;
overflow: hidden;
/* margin: 0 auto;
padding: 2rem;
text-align: center; */
}
div::-webkit-scrollbar {
width: 10px;
height: 10px;
/**/
}
div::-webkit-scrollbar-track {
background: #dfdfdf;
border-radius: 2px;
}
div::-webkit-scrollbar-thumb {
background: #bbbbbb;
border-radius: 10px;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
import {
upLoadImg
} from '@/api/user.js';
import {
upLoadArrayImage
} from '@/api/hotel.js';
// base64转file,dataurl为base64地址,filename为文件名称,自定义即可
export const dataURLtoFile = (dataurl, filename) => {
let arr = dataurl.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {
type: mime
});
}
/**路径转为文件 */
export const getImageFileFromUrl=(url, imageName)=>{
return new Promise((resolve, reject) => {
let blob = null;
let imgFile = null;
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.setRequestHeader("Accept", "image/png");
xhr.responseType = "blob";
xhr.onload = () => {
blob = xhr.response;
imgFile = new File([blob], imageName, { type: "image/png" });
resolve(imgFile);
};
xhr.onerror = e => {
reject(e);
};
xhr.send();
});
}
//获取当前时间 传1返回YYYY-MM-DD HH-MM-SS 传2返回YYYY-MM-DD
export const getCurrentDate = (val) => {
const nowDate = new Date();
const {
year,
month,
day,
hour,
minute,
second
} = {
year: nowDate.getFullYear(),
month: nowDate.getMonth(),
day: nowDate.getDay(),
hour: nowDate.getHours(),
minute: nowDate.getMinutes(),
second: nowDate.getSeconds()
}
const YYYYMMDD = year + '-' + month + '-' + day;
const HHMMSS = hour + ':' + minute + ':' + second;
if (val == 1) {
return YYYYMMDD + ' ' + HHMMSS;
} else if (val == 2) {
return YYYYMMDD
}
}
Date.prototype.format = function (format) {
var o = {
"M+": this.getMonth() + 1, //month
"d+": this.getDate(), //day
"h+": this.getHours(), //hour
"m+": this.getMinutes(), //minute
"s+": this.getSeconds(), //second
"q+": Math.floor((this.getMonth() + 3) / 3), //quarter
"S": this.getMilliseconds() //millisecond
}
if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
(this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(format))
format = format.replace(RegExp.$1,
RegExp.$1.length == 1 ? o[k] :
("00" + o[k]).substr(("" + o[k]).length));
return format;
};
export const ChangeDateType = (TM, TMformat) => {
let result = TM;
try {
result = TM.format(TMformat);
} catch (e) {
//TODO handle the exception
};
return result;
}
/**现场图片提交 */
export const file_img_src = (base64_img, hotelId, type) => {
const timestamp = Date.parse(new Date());
let file = dataURLtoFile(base64_img, timestamp + ".png");
let fd = new FormData();
fd.append("file", file);
fd.append("hotelId", hotelId);
fd.append("bucket", type);
return new Promise((resolve) => {
upLoadImg(fd).then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
};
//遍历树状结构
export const treeForeach = (tree, func) => {
let node, list = [...tree]
while (node = list.shift()) {
func(node)
node.children && list.push(...node.children)
}
}
\ No newline at end of file
import {
websocketStore
} from "@/store/websocketStore.js";
const myWebsocketStore = websocketStore();
class initWebsocket {
constructor() {
this.obj = {
certificatecardid: '',
msg: '',
cardinfo: '',
cardName: '',
str: '',
devicetype: '',
statusbar: '',
certificatePhoto: ''
};
this.websocket = null;
}
connect() {
try {
var readyState = new Array("on connection", "Connection established",
"Closing connection", "Close connection");
var host = "ws://127.0.0.1:90/echo/";
this.websocket = new WebSocket(host);
this.websocket.onopen = () => {
this.obj.statusbar = readyState[this.websocket.readyState];
this.websocket.send(18601);
this.websocket.send(18402);
}
this.websocket.onmessage = (event) => {
var str = event.data;
var strsub = str;
//此处要加多种扫描仪
var deviceArr = new Array();
deviceArr[0] = "D300+";
deviceArr[1] = "D800II";
deviceArr[2] = "D120+";
deviceArr[3] = "L1250+";
deviceArr[4] = "L1250";
deviceArr[5] = "B660";
deviceArr[6] = "M110";
deviceArr[7] = "E2000";
deviceArr[8] = "CR620+";
deviceArr[9] = "DSL3100";
deviceArr[10] = "AVA5";
deviceArr[11] = "B6680";
deviceArr[12] = "AW570";
deviceArr[13] = "M1260";
deviceArr[14] = "DSL62";
deviceArr[15] = "U350II";
deviceArr[16] = "L7280+";
deviceArr[17] = "AVA5+";
deviceArr[18] = "D800II+";
deviceArr[19] = "AVA5 Plus";
if (this.IsInArray(deviceArr, str)) {
//此处可更换为自己使用的扫描仪型号
this.obj.devicetype = "scanner";
return;
}
if (strsub != "") {
str = strsub.replace(/\*/g, "\r\n");
this.obj.str = str; //传入textarea中
//console.log('Message state', websocket.readyState);
}
this.tup() //对返回信息进行处理,显示到页面
}
this.websocket.onclose = () => {
this.obj.statusbar = readyState[this.websocket.readyState];
}
setInterval(() => {
this.AutoPhotoAndRecog()
}, 1000);
} catch (exception) {
this.obj.statusbar = "Error";
}
}
//判断字符串是否在数组中方法
IsInArray(arr, val) {
let testStr = ',' + arr.join(",") + ",";
return testStr.indexOf("," + val + ",") != -1;
}
send() {
try {
this.websocket.send("181026150"); //发送护照芯片内容读取设置指令,固定指令,请勿变动
this.websocket.send("1810331"); //设置保存图片类型,18103+31 表示所有图片都保存
this.websocket.send("181041"); //是否识别识读区,请勿变动
this.websocket.send("181061"); //是否返回base64格式图片
this.websocket.send("1810731"); //哪些图片返回base64,默认所有图片都返回
} catch (exception) {
this.obj.msg = "Error sending data";
}
}
AutoPhotoAndRecog() {
var str = this.obj.devicetype;
if (str = "scanner") {
setInterval(() => {
this.getInformation()
}, 2000);
} else {
this.getInformation();
}
}
getInformation() {
if (this.websocket != null) {
this.websocket.send("11112");
}
}
tup() {
var str = this.obj.str;
//字符分割
var seek = str.split("data:image/jpeg;base64,");
var len = seek.length; //没有找到报头 此时会返回原串,长度也为1
if (len > 1) //有证件信息和图像,当只有一张图片的时候,有一个base64的头,会分割成两段,第一段为空,第二段会去掉头的图像base64串
{
var seek0 = seek[0]; //身份信息数据
//alert(seek0);
var strhead = "";
var strChipHead = "";
for (var i = 1; i < len; i++) //头像数据//头像数据 data:image/jpeg;base64,xx.... xx 表示图片的类型 01 为白光,以此类推
{
if (seek[i].length > 2) {
var strType = seek[i][0] + seek[i][1];
seek[i] = seek[i].substr(2);
if (strType == "01") //白光
{
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "02") //红外
{
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "04") //紫外
{
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "08") //版面头像
{
strhead = seek[i];
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "16") //芯片头像
{
strChipHead = seek[i];
seek[i] = "data:image/jpeg;base64," + seek[i];
}
}
}
//优先显示芯片头像
let seek1 = null;
if (strChipHead != "") {
seek1 = "data:image/jpeg;base64," + strChipHead;
this.obj.certificatePhoto = seek1;
} else {
seek1 = "data:image/jpeg;base64," + strhead;
}
if (seek0 != "") {
seek0 = seek0.replace(/\*/g, "\r\n");
this.obj.msg = "Receive information:" + seek0;
this.getcardInfo();
}
} else {
//var strsub = str.substr(1);
if (str != "") {
str = str.replace(/\*/g, "\r\n");
this.obj.msg = "Receive information:" + str;
//getcardInfo();
}
}
}
singlerecog() {
var str = this.obj.msg;
if (str == "scanner") {
this.websocket.send("1000" + this.obj.certificateType + "02");
}
this.websocket.send("18201" + this.obj.certificateType);
}
getcardInfo() {
var str = this.obj.msg;
var cardid = str.substring(str.indexOf(":") + 1, str.indexOf("\r\n")); //获取返回信息中的证件类型编号IDCardID
if (cardid == "二代证读卡") {
this.obj.cardinfo = "二代证读芯片";
myWebsocketStore.identityInformation = {};
myWebsocketStore.identityInformation = this.obj;
return;
}
var card1by1;
var cardname;
for (var i = 0; i < 80; i++) {
if (this.obj.certificateType) {
card1by1 = this.obj.certificatecardid;
}
if (card1by1 == cardid) {
cardname = this.obj.cardName;
break;
}
this.obj.msg = "证件类型:" + cardid + "\n" + "证件名称:" + cardname;
myWebsocketStore.identityInformation = this.obj;
return this.obj;
}
}
close() {
// 关闭连接
this.websocket.close()
// 销毁 websocket 实例对象
this.websocket = null;
}
}
export default initWebsocket;
\ No newline at end of file
import { useStore } from "@/store/index.js";
const userstore = useStore();
export function provincialUrbanAreas() {
let aa = userstore.returnCode(11);
for (let i = 0; i < aa.length; i++) {
if (aa[i].code.substring(2, 6) == '0000') {
aa[i]['parentCode'] = ''
}
if (aa[i].code.substring(4, 6) == '00'&&aa[i].code.substring(2, 4) != '00') {
aa[i]['parentCode'] = aa[i].code.substring(0, 2) + '0000';
} else if (aa[i].code.substring(4, 6) != '00') {
aa[i]['parentCode'] = aa[i].code.substring(0, 4) + '00';
}
}
return recursionDataTree(aa);
}
function recursionDataTree(menu) {
let result = [];
menu.forEach(item => {
delete item.children;
});
let map = {};
menu.forEach(item => {
map[item.code] = item;
});
menu.forEach(item => {
let parent = map[item.parentCode];
if (parent) {
(parent.children || (parent.children = [])).push(item);
} else {
result.push(item);
}
});
return result;
}
import axios from "axios";
import {
useStore
} from "../store";
const service = axios.create({
//根据环境变量 统一设置 域名 前缀,实际请求的路径是 baseURL + requestUrl
baseURL: '/api',
withCredentials: true, //跨域请求时发送Cookie
timeout: 20000, // 设置超时时间
});
// 请求拦截
service.interceptors.request.use(
(config) => {
const store = useStore();
// 请求前加一些需要的逻辑,如再请求头中加参数
if (store.token) {
config.headers['Authorization'] = store.token
}
//最终要返回这个配置
return config;
},
(error) => {
//请求失败时的逻辑
return Promise.reject(error);
}
);
// 响应拦截
service.interceptors.response.use(
(response) => {
//response中包含响应的所有数据包括响应头,状态等
// 前后端约定的接口回来的数据格式,接口成功或接口失败,做一些逻辑处理再返回结果
if (response.status !== 200) {
alert(response.statusText);
//最终都要返回结果
return Promise.reject(new Error(response.statusText || "Error"));
} else {
//最终都要返回结果
if (response.data.code == '9000' || response.data.constructor !== Object) {
return response.data;
} else {
return Promise.reject(response.data);
}
}
},
(error) => {
console.log("err" + error); // for debug
return Promise.reject(error);
}
);
export default service;
\ No newline at end of file
import axios from "axios";
import {
useStore
} from "../store";
const service = axios.create({
//根据环境变量 统一设置 域名 前缀,实际请求的路径是 baseURL + requestUrl
baseURL: '',
withCredentials: true, //跨域请求时发送Cookie
timeout: 10000, // 设置超时时间
});
// 请求拦截
service.interceptors.request.use(
(config) => {
const store = useStore();
// 请求前加一些需要的逻辑,如再请求头中加参数
if (store.token) {
config.headers['Authorization'] = store.token
}
//最终要返回这个配置
return config;
},
(error) => {
//请求失败时的逻辑
return Promise.reject(error);
}
);
// 响应拦截
service.interceptors.response.use(
(response) => {
//response中包含响应的所有数据包括响应头,状态等
// 前后端约定的接口回来的数据格式,接口成功或接口失败,做一些逻辑处理再返回结果
if (response.status !== 200) {
alert(response.statusText);
//最终都要返回结果
return Promise.reject(new Error(response.statusText || "Error"));
} else {
//最终都要返回结果
if (response.data.code == '9000' || response.data.constructor !== Object) {
return response.data;
} else {
return Promise.reject(response.data.message);
}
}
},
(error) => {
let status = "";
if (error.request) {
status = error.request;
} else if (error.response) {
status = error.response;
}
if (status) {
switch (status.status) {
case 400:
error.message = "请求错误(400)";
break;
case 401:
error.message = "未授权,请重新登录(401)";
router.push("/401");
break;
case 403:
error.message = "拒绝访问(403)";
break;
case 404:
error.message = "请求出错(404)";
router.push("/404");
break;
case 408:
error.message = "请求超时(408)";
break;
case 500:
error.message = "服务器错误(500)";
router.push("/a500");
break;
case 501:
error.message = "服务未实现(501)";
break;
case 502:
error.message = "网络错误(502)";
break;
case 503:
error.message = "服务不可用(503)";
break;
case 504:
error.message = "网络超时(504)";
break;
case 505:
error.message = "HTTP版本不受支持(505)";
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = "连接服务器失败!";
}
// console.log("err" + error); // for debug
return Promise.reject(error);
}
);
export default service;
\ No newline at end of file
/*是否合法IP地址*/
export function validateIP(rule, value, callback) {
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入IP地址'));
} else {
const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的IP地址'));
} else {
callback();
}
}
}
/*护照验证
* 规则: G + 8位数字, P + 7位数字, S/D + 7或8位数字,等
* 例: G12345678, P1234567
*/
export function validatePassportCard(rule, value, callback) {
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入护照'));
} else {
const reg = /^([a-zA-z]|[0-9]){5,17}$/;
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的护照'));
} else {
callback();
}
}
}
/**
* 台湾居民来往大陆通行证
* 规则: 新版8位或18位数字 或 旧版9位数字 + 英文字母 或 8位数字 + 英文字母
* 样本: 12345678
*/
export function validateTWCard(rule, value, callback) {
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入通行证'));
} else {
const reg = /^\\d{8}|^[a-zA-Z0-9]{10}|^[a-zA-Z0-9]{9}|^\\d{18}$/;
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的台湾通行证'));
} else {
callback();
}
}
}
/**
* 港澳居民来往内地通行证
* 规则: H/M + 10位或6位数字
* 例:H1234567890
*/
export function validateHKCard(rule, value, callback) {
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入港澳通行证'));
} else {
const reg = /^([A-Z]\\d{6,10}(\\(\\w{1}\\))?)$/;
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的港澳通行证'));
} else {
callback();
}
}
}
/* 是否手机号码或者固话*/
export function validatePhoneTwo(rule, value, callback) {
const reg = /^((0\d{2,3}-\d{7,8})|(1[34578]\d{9}))$/;;
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入电话号码或者固话号码'));
} else {
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的电话号码或者固话号码'));
} else {
callback();
}
}
}
/* 是否固话 */
export function validateTelphone(rule, value, callback) {
const reg = /0\d{2}-\d{7,8}/;
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入固话(格式:区号+号码,如010-1234567)'));
} else {
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的固话(格式:区号+号码,如010-1234567)'));
} else {
callback();
}
}
}
/* 是否手机号码*/
export function validatePhone(rule, value, callback) {
const reg = /^[1][3,4,5,7,8][0-9]{9}$/;
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入电话号码'));
} else {
if ((!reg.test(value)) && value != '') {
callback(new Error('请输入正确的电话号码'));
} else {
callback();
}
}
}
/* 是否身份证号码*/
export function validateIdNo(rule, value, callback) {
const reg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[X])$)$/;
if (value == '' || value == undefined || value == null) {
return Promise.reject('请输入身份证号码');
} else {
if ((!reg.test(value)) && value != '') {
return Promise.reject("请输入正确的身份证号码");
} else {
return Promise.resolve();
}
}
}
/*不是身份证号码*/
export function validateIdNoNot(rule, value, callback) {
const reg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[X])$)$/;
if (value == '' || value == undefined || value == null) {
callback();
} else {
if ((reg.test(value)) && value != '') {
callback(new Error('请不要填写身份证号码'));
} else {
callback();
}
}
}
/* 是否邮箱*/
export function validateEMail(rule, value, callback) {
const reg = /^([a-zA-Z0-9]+[-_\.]?)+@[a-zA-Z0-9]+\.[a-z]+$/;
if (value == '' || value == undefined || value == null) {
callback(new Error('请输入邮箱地址'));
} else {
if (!reg.test(value)) {
callback(new Error('请输入正确的邮箱地址'));
} else {
callback();
}
}
}
/* 合法uri*/
export function validateURL(textval) {
const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
return urlregex.test(textval);
}
/*验证内容是否英文数字以及下划线*/
export function isPassword(rule, value, callback) {
const reg = /^[_a-zA-Z0-9]+$/;
if (value == '' || value == undefined || value == null) {
callback();
} else {
if (!reg.test(value)) {
callback(new Error('账号、密码仅由英文字母,数字以及下划线组成'));
} else {
callback();
}
}
}
/*验证内容只能输入整数和两位小数*/
export function isDecimalsAndNumbers(rule, value, callback) {
const reg = /^[0-9]+(\.[0-9]{1,2})?$/;
if (value == '' || value == undefined || value == null) {
callback();
} else {
if (!reg.test(value)) {
callback(new Error('只能输入整数和两位小数'));
} else {
callback();
}
}
}
/*自动检验数值的范围*/
export function checkMax20000(rule, value, callback) {
if (value == '' || value == undefined || value == null) {
callback();
} else if (!Number(value)) {
callback(new Error('请输入[1,20000]之间的数字'));
} else if (value < 1 || value > 20000) {
callback(new Error('请输入[1,20000]之间的数字'));
} else {
callback();
}
}
//验证数字输入框最大数值,32767
export function checkMaxVal(rule, value, callback) {
if (value < 0 || value > 32767) {
callback(new Error('请输入[0,32767]之间的数字'));
} else {
callback();
}
}
//验证是否1-99之间
export function isOneToNinetyNine(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入正整数'));
} else {
const re = /^[1-9][0-9]{0,1}$/;
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('请输入正整数,值为【1,99】'));
} else {
callback();
}
}
}, 0);
}
// 验证是否整数
export function isInteger(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入正整数'));
} else {
const re = /^[0-9]*[1-9][0-9]*$/;
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('请输入正整数'));
} else {
callback();
}
}
}, 0);
}
// 验证是否整数,非必填
export function isIntegerNotMust(rule, value, callback) {
if (!value) {
callback();
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入正整数'));
} else {
const re = /^[0-9]*[1-9][0-9]*$/;
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('请输入正整数'));
} else {
callback();
}
}
}, 1000);
}
// 验证是否是[0-1]的小数
export function isDecimal(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入[0,1]之间的数字'));
} else {
if (value < 0 || value > 1) {
callback(new Error('请输入[0,1]之间的数字'));
} else {
callback();
}
}
}, 100);
}
// 验证是否是[1-10]的小数,即不可以等于0
export function isBtnOneToTen(rule, value, callback) {
if (typeof value == 'undefined') {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入正整数,值为[1,10]'));
} else {
if (!(value == '1' || value == '2' || value == '3' || value == '4' || value == '5' || value == '6' || value == '7' || value == '8' || value == '9' || value == '10')) {
callback(new Error('请输入正整数,值为[1,10]'));
} else {
callback();
}
}
}, 100);
}
// 验证是否是[1-100]的小数,即不可以等于0
export function isBtnOneToHundred(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入整数,值为[1,100]'));
} else {
if (value < 1 || value > 100) {
callback(new Error('请输入整数,值为[1,100]'));
} else {
callback();
}
}
}, 100);
}
//验证银行卡号
export function isBankCount(rule, bankno, callback) {
var lastNum = bankno.substr(bankno.length - 1, 1); //取出最后一位(与luhn进行比较)
var first15Num = bankno.substr(0, bankno.length - 1); //前15或18位
var newArr = new Array();
for (var i = first15Num.length - 1; i > -1; i--) { //前15或18位倒序存进数组
newArr.push(first15Num.substr(i, 1));
}
var arrJiShu = new Array(); //奇数位*2的积 <9
var arrJiShu2 = new Array(); //奇数位*2的积 >9
var arrOuShu = new Array(); //偶数位数组
for (var j = 0; j < newArr.length; j++) {
if ((j + 1) % 2 == 1) { //奇数位
if (parseInt(newArr[j]) * 2 < 9) arrJiShu.push(parseInt(newArr[j]) * 2);
else arrJiShu2.push(parseInt(newArr[j]) * 2);
} else //偶数位
arrOuShu.push(newArr[j]);
}
var jishu_child1 = new Array(); //奇数位*2 >9 的分割之后的数组个位数
var jishu_child2 = new Array(); //奇数位*2 >9 的分割之后的数组十位数
for (var h = 0; h < arrJiShu2.length; h++) {
jishu_child1.push(parseInt(arrJiShu2[h]) % 10);
jishu_child2.push(parseInt(arrJiShu2[h]) / 10);
}
var sumJiShu = 0; //奇数位*2 < 9 的数组之和
var sumOuShu = 0; //偶数位数组之和
var sumJiShuChild1 = 0; //奇数位*2 >9 的分割之后的数组个位数之和
var sumJiShuChild2 = 0; //奇数位*2 >9 的分割之后的数组十位数之和
var sumTotal = 0;
for (var m = 0; m < arrJiShu.length; m++) {
sumJiShu = sumJiShu + parseInt(arrJiShu[m]);
}
for (var n = 0; n < arrOuShu.length; n++) {
sumOuShu = sumOuShu + parseInt(arrOuShu[n]);
}
for (var p = 0; p < jishu_child1.length; p++) {
sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]);
sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]);
}
//计算总和
sumTotal = parseInt(sumJiShu) + parseInt(sumOuShu) + parseInt(sumJiShuChild1) + parseInt(sumJiShuChild2);
//计算luhn值
var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10;
var luhn = 10 - k;
if (lastNum == luhn) {
callback();
} else {
callback(new Error('银行卡号必须符合luhn校验'));
}
}
// 验证是否是[0-100]的小数
export function isBtnZeroToHundred(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (!Number(value)) {
callback(new Error('请输入[1,100]之间的数字'));
} else {
if (value < 0 || value > 100) {
callback(new Error('请输入[1,100]之间的数字'));
} else {
callback();
}
}
}, 100);
}
// 验证端口是否在[0,65535]之间
export function isPort(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
if (value == '' || typeof (value) == undefined) {
callback(new Error('请输入端口值'));
} else {
const re = /^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/;
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('请输入在[0-65535]之间的端口值'));
} else {
callback();
}
}
}, 100);
}
// 验证端口是否在[0,65535]之间,非必填,isMust表示是否必填
export function isCheckPort(rule, value, callback) {
if (!value) {
callback();
}
setTimeout(() => {
if (value == '' || typeof (value) == undefined) {
//callback(new Error('请输入端口值'));
} else {
const re = /^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/;
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('请输入在[0-65535]之间的端口值'));
} else {
callback();
}
}
}, 100);
}
//验证邮编
export function validateZipCode(rule, value, callback) {
if (!value) {
return callback(new Error('输入不可以为空'));
}
setTimeout(() => {
const re = /^[0-8][0-7]\d{4}$/
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('邮政编码格式不正确'));
} else {
callback();
}
}, 100);
}
//不判断是否为空
export function validateZipCode2(rule, value, callback) {
if (!value) {
callback();
}
setTimeout(() => {
const re = /^[0-8][0-7]\d{4}$/
const rsCheck = re.test(value);
if (!rsCheck) {
callback(new Error('邮政编码格式不正确'));
} else {
callback();
}
}, 100);
}
/* 小写字母*/
export function validateLowerCase(str) {
const reg = /^[a-z]+$/;
return reg.test(str);
}
/*保留2为小数*/
export function validatetoFixedNew(str) {
return str;
}
/* 验证key*/
// export function validateKey(str) {
// var reg = /^[a-z_\-:]+$/;
// return reg.test(str);
// }
/* 大写字母*/
export function validateUpperCase(str) {
const reg = /^[A-Z]+$/;
return reg.test(str);
}
/* 大小写字母*/
export function validatAlphabets(str) {
const reg = /^[A-Za-z]+$/;
return reg.test(str);
}
<template>
<div class="abroad">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">外宾登记信息列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="4">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="gender" label="性别">
<a-select v-model:value="formState.gender" :allowClear="true" show-search placeholder="请选择性别" :options="dictionaryAll.allGender" optionLabelProp="name" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="出生日期">
<a-range-picker v-model:value="csrq" :allowClear="true" @change="(data, dateString) => handleChangeTime(data, dateString, 1)" />
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="nationalityCode" label="国籍(地区)">
<a-select v-model:value="formState.nationalityCode" :allowClear="true" show-search placeholder="请选择国籍(地区)" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="certificateType" label="证件类型">
<a-select v-model:value="formState.certificateType" :allowClear="true" show-search placeholder="请选择证件类型" :options="dictionaryAll.allForeignGuest" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="certificateNumber" label="证件号码">
<a-input v-model:value="formState.certificateNumber" :allowClear="true" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="visaType" label="签证种类">
<a-select v-model:value="formState.visaType" :allowClear="true" show-search placeholder="请选择签证种类" :options="dictionaryAll.allVisa" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="state" label="旅客状态">
<a-select v-model:value="formState.state" :allowClear="true" show-search placeholder="请选择旅客状态" :options="dictionaryAll.allCheckInState" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="checkinTime" label="入住时间">
<a-range-picker v-model:value="rzsj" :allowClear="true" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 2)" />
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="checkOutTime" label="离店时间">
<a-range-picker v-model:value="ldsj" :allowClear="true" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 3)" />
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="roomId" label="房号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="dictionaryAll.allRoom" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }"></a-select>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" html-type="submit" @click="searchForeignGuest">搜索</a-button>
<a-button style="margin: 0 8px" @click="qx()">清除</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :row-selection="{selectedRowKeys: state.selectedRowKeys,onChange: onSelectChange}" :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color:#52c41a" @click="eyes(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="是否离店?" @confirm="checkOut(record)" v-if="record.state=='DEPART'?false:true">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
<a-button type="link" primary size="small" @click="visitorJump(record)">
<template #icon>
<contacts-filled />
</template>
访客登记
</a-button>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" show-quick-jumper show-size-changer :total="total" v-show="data.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChangePagination" style="margin: 20px 0px" />
</div>
<AbroadInfo v-if="abroadInfoVisible" :flogStatus="operateStatus" :visible="abroadInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="abroadInfo" @change-Cancel="changeCancel" :visibleEdit="hotelFormVisible_edit_s" />
</a-spin>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { useStore } from '@/store/index.js';
import { getForeignGuestCheckInList, departureForeignGuestCheckIn } from '@/api/foreignGuestCheckIn.js';
import AbroadInfo from '@/views/abroad/abroadInfo.vue'
import { message } from "ant-design-vue";
import router from "../../router";
import { getAllTeam } from '@/api/team.js'
const loading = ref(false);
const userstore = useStore();
const operateStatus = ref(false);
const hotelFormVisible_edit_s = ref(false);
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: '',
checkinTime: '',
nationalityCode: '',
certificateNumber: '',
certificateType: '',
checkinTimeEnd: '',
checkinTimeStart: '',
name: '',
gender: '',
dateBirth: '',
visaType: '',
state: '',
checkOutTime: '',
dateBirthEnd: '',
dateBirthStart: '',
departureTimeEnd: '',
departureTimeStart: '',
state:'',
current: 1,
pageSize: 10,
});
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9),
allVisa: userstore.returnCode(8),
allGender: userstore.returnCode(5),
allForeignGuest: userstore.returnCode(4),
allCheckInState: userstore.returnCode(2),
allReasonEntry:userstore.returnCode(7),
allTeam:[],
});
/**时间变化 */
const handleChangeTime = (data, dataArr, type) => {
if (dataArr && dataArr.length > 0) {
if (type == 1) {
formState.dateBirthEnd = dataArr[1];
formState.dateBirthStart = dataArr[0];
} else if (type == 2) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.departureTimeEnd = dataArr[1];
formState.departureTimeStart = dataArr[0];
}
} else {
if (type == 1) {
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
} else if (type == 2) {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
} else {
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
}
};
const csrq = ref(undefined);
const rzsj = ref(undefined);
const ldsj = ref(undefined);
/**清除 */
const qx = ()=>{
formRef.value.resetFields();
csrq.value = undefined;
rzsj.value = undefined;
ldsj.value = undefined;
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
//搜索
const data = ref([]);
const total = ref();
const searchForeignGuest = () => {
loading.value = true;
getForeignGuestCheckInList(formState).then(res => {
if (res?.code == 9000) {
data.value = res.data.records;
total.value = res.data.total;
}
loading.value = false;
}).catch(error => {
loading.value = false;
})
}
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
// {
// title: "序号",
// dataIndex: 'key',
// },
{
title: "姓名",
dataIndex: "chineseName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "出生日期",
dataIndex: 'dateBirth',
},
{
title: "国籍地区",
dataIndex: "nationalityCodeName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离店时间",
dataIndex: 'departureTime',
},
{
title: "旅客状态",
dataIndex: "stateName",
},
{
title: "证件核验",
dataIndex: "verificationState",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 320,
}
];
const state = reactive({
selectedRowKeys: [],
loading: false,
});
const onSelectChange = (selectedRowKeys) => {
state.selectedRowKeys = selectedRowKeys;
};
/**分页 */
const onChangePagination = (page, pageSize) => {
formState.current = page;
formState.pageSize = pageSize;
searchForeignGuest();
};
/**访客登记跳转 */
const visitorJump = (record) => {
// if(record.roomId==''||record.roomId==undefined){
// message.warning('该旅馆暂未入住')
// }
router.push({ path: '/visitor/visitorAdd', query: { roomId: record.roomId, name: record.firstName + record.lastName } });//使用英文姓和英文名拼接
}
/**查看 */
const abroadInfo = ref({});
const dictionaryAllInfo = ref({});
const abroadInfoVisible = ref(false);
/**查看 */
const eyes = (e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = true;
hotelFormVisible_edit_s.value = true;
}
const changeCancel = () => {
abroadInfoVisible.value = false;
}
//编辑
const edit = (e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = false;
hotelFormVisible_edit_s.value = true;
}
//离店
const checkOut = async (record) => {
loading.value = true;
await departureForeignGuestCheckIn([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
searchForeignGuest();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
}
onMounted(() => {
getAllTeam({ hotelid: userstore.hotelInfo.hotelId }).then(res => {
dictionaryAll.allTeam = res.data;
})
searchForeignGuest();
});
</script>
<style lang="less">
.abroad {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
// overflow-y: auto;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="loading">
<div class="abroadAddFrom">
<div class="titleBox">
<div>
<span class="sign">外宾登记表</span>
</div>
</div>
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" show-search placeholder="请选择房间号" :options="dictionaryAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker v-model:value="formState.checkinTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择入住时间" @change="onChange" @ok="onOk" style="width: 100%;"/>
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span">
<span>证件人像</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取头像</a-radio>
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhoto == ''">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhoto" v-else />
</div>
<div class="check-div" @click="OnCamera()">
<a-button type="primary" size="small">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取资料页</a-radio>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value3" @click="dx_click(3)">截取签证页</a-radio>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="nationalityCode" :label="`国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择国籍(地区)" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`">
<a-select v-model:value="formState.certificateType" show-search placeholder="请选择证件类型" :options="dictionaryAll.allForeignGuest" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="chineseName" :label="`中文姓名`">
<a-input v-model:value="formState.chineseName" placeholder="请输入中文姓名" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="firstName" :label="`英文姓`">
<a-input v-model:value="formState.firstName" placeholder="请输入英文姓" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="lastName" :label="`英文名`">
<a-input v-model:value="formState.lastName" placeholder="请输入英文名" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="gender" :label="`性别`">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="dictionaryAll.allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="dateBirth" v-model:value="formState.dateBirth" :label="`出生日期`">
<a-date-picker v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" :disabled-date="disabledDateMax" placeholder="请选择出生日期" style="width: 100%;"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="visaType" :label="`签证种类`">
<a-select v-model:value="formState.visaType" show-search placeholder="请选择签证种类" :options="dictionaryAll.allVisa" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="periodStay" :label="`停留期至`">
<a-date-picker v-model:value="formState.periodStay" placeholder="请选择时间" value-format="YYYY-MM-DD HH:mm:ss" :disabled-date="disabledDateMin" style="width: 100%;"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="reasonEntry" :label="`入境事由`">
<a-select v-model:value="formState.reasonEntry" show-search placeholder="请选择入境事由" :options="dictionaryAll.allReasonEntry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="receptionUnit" :label="`接待单位`">
<a-input v-model:value="formState.receptionUnit" placeholder="请输入接待单位" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="emergencyContact" :label="`紧急情况联系人`">
<a-input v-model:value="formState.emergencyContact" placeholder="请输入紧急情况联系人" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="emergencyPhoneNumber" :label="`紧急情况联系电话`" :rules="[
{ message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.emergencyPhoneNumber" placeholder="请输入紧急情况联系电话" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`国内邀请人或本人联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入国内邀请人或本人联系电话" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="teamId" :label="`所属团队`">
<a-select v-model:value="formState.teamId" show-search placeholder="请选择所属团队" :options="dictionaryAll.allTeam" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="hotelAdress" :label="`旅馆地址`">
<a-input v-model:value="formState.hotelAddress" :allowClear="true" placeholder="请输入旅馆地址" :disabled="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="remark" :label="`备注`">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large">扫描证件</a-button>
<a-button type="primary" size="large">读取外国人永久居留证</a-button>
<a-button type="primary" size="large" @click="saveInfo"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="qk()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
</template>
<script setup>
import { onMounted } from "vue";
import Camera from "@/components/Camera.vue";
import { useStore } from '@/store/index.js'
import { getAllTeam } from '@/api/team.js'
import { validatePhoneTwo } from '@/utils/validates.js';
import { addForeignGuestCheckIn } from '@/api/foreignGuestCheckIn.js';
import { uploadImg } from '@/api/default.js';
import { file_img_src } from '@/utils/http_util.js';
import { message } from 'ant-design-vue';
import dayjs from 'dayjs';
const userstore = useStore();
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9).filter(item=>{return item.code!='44'}),
allVisa: userstore.returnCode(8),
allGender: userstore.returnCode(5),
allForeignGuest: userstore.returnCode(4),
allReasonEntry: userstore.returnCode(7),
allTeam: []
});
const loading = ref(false);
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: '',
checkinTime: '',
nationalityCode: '',
certificateNumber: '',
certificateType: '',
chineseName: '',
firstName: '',
lastName: '',
gender: '',
dateBirth: '',
visaType: '',
periodStay: '',
reasonEntry: '',
receptionUnit: '',
emergencyContact: '',
emergencyPhoneNumber: '',
phoneNumber: '',
teamId: '',
hotelAddress: userstore.hotelInfo.hotelAddress,
remark: '',
certificatePhoto: '',
sitePhoto: '',
informationPhoto: '',
visasPhoto: '',
state: "ARRIVE",
});
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
checkinTime: [
{
required: true,
message: '请选择入住时间'
}
],
nationalityCode: [
{
required: true,
message: '请选择国籍(地区)'
},
],
certificateNumber: [
{
required: true,
message: '请输入证件号码'
},
],
certificateType: [
{
required: true,
message: '请输入证件类型'
}
],
gender: [
{
required: true,
message: '请选择性别'
}
],
dateBirth: [
{
required: true,
message: '请选择出生日期'
},
],
visaType: [
{
required: true,
message: '请选择签证种类'
},
],
reasonEntry: [
{
required: true,
message: '请选择入境事由'
},
],
phoneNumber: [
{
required: true,
message: '请输入国内邀请人或本人联系电话'
}
],
teamId: [
{
required: true,
message: '请选择所属团队'
}
],
// hotelAdress: [
// {
// required: true,
// message: '请输入旅馆地址'
// },
// ]
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**设置最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
const screenshot_url = ref("");
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
screenshot_url.value = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**清空 */
const qk = () => {
formRef.value.resetFields();
formState.sitePhoto = '';
}
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**右侧切换截取图片 */
const checked_value1 = ref(true);
const checked_value2 = ref(false);
const checked_value3 = ref(false);
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
// await emit("changeform", false);
};
const dx_click = (e) => {
if (e == 1) {
checked_value1.value = true;
checked_value2.value = false;
checked_value3.value = false;
} else if (e == 2) {
checked_value1.value = false;
checked_value2.value = true;
checked_value3.value = false;
} else {
checked_value1.value = false;
checked_value2.value = false;
checked_value3.value = true;
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
};
const onOk = (value, dateString) => {
formState.pass = dateString;
};
const handleMenuClick = (e) => {
};
//上报信息
const saveInfo = () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (formState.sitePhoto != "") {
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'FOREIGN_GUEST'));
} else {
arr_http.push("");
}
// if (formState.certificatePhoto != "") {
// arr_http.push(file_img_src(formState.certificatePhoto,userstore.hotelInfo.hotelId,'FOREIGN_GUEST'));
// } else {
// arr_http.push("");
// }
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (formState.sitePhoto != "") {
arr.sitePhoto = res1;
}
// if (formState.certificatePhoto != "") {
// arr.certificatePhoto = res2;
// }
addForeignGuestCheckIn(arr)
.then((res) => {
if (res.code == 9000) {
message.success("入住成功");
reset();
}
loading.value = false;
})
.catch((res) => {
message.warning("入住失败");
loading.value = false;
});
});
});
}
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
onMounted(() => {
//查询所属团队
getAllTeam({ hotelid: userstore.hotelInfo.hotelId }).then(res => {
dictionaryAll.allTeam = res.data;
})
})
</script>
<style lang="less">
.abroadAddFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y:auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" title="查看详情" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="visitorFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" show-search placeholder="请选择房间号" :options="defaultTypeAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker v-model:value="formState.checkinTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择入住时间" style="width: 100%;" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span">
<span>证件人像</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取头像</a-radio>
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhotoPath == ''||formState.sitePhotoPath==null">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhotoPath" :fallback="default_img" v-else />
</div>
<div class="check-div" @click="OnCamera()" v-if="visibleEdit">
<a-button type="primary" size="small" :disabled="operateStatus?true:false">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;" v-if="!operateStatus">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取资料页</a-radio>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value3" @click="dx_click(3)">截取签证页</a-radio>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="nationalityCode" :label="`国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择国籍(地区)" :options="defaultTypeAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`">
<a-select v-model:value="formState.certificateType" show-search placeholder="请选择证件类型" :options="defaultTypeAll.allForeignGuest" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="chineseName" :label="`中文姓名`">
<a-input v-model:value="formState.chineseName" placeholder="请输入中文姓名" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="firstName" :label="`英文姓`">
<a-input v-model:value="formState.firstName" placeholder="请输入英文姓" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="lastName" :label="`英文名`">
<a-input v-model:value="formState.lastName" placeholder="请输入英文名" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="gender" :label="`性别`">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="defaultTypeAll.allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="dateBirth" :label="`出生日期`">
<a-date-picker v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" :disabled="operateStatus?true:false" style="width: 100%;" :disabled-date="disabledDateMax" placeholder="请选择出生日期"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="visaType" :label="`签证种类`">
<a-select v-model:value="formState.visaType" show-search placeholder="请选择签证种类" :options="defaultTypeAll.allVisa" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="periodStay" :label="`停留期至`">
<a-date-picker v-model:value="formState.periodStay" placeholder="请选择时间" value-format="YYYY-MM-DD" style="width: 100%;" :disabled="operateStatus?true:false" :disabled-date="disabledDateMin"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="reasonEntry" :label="`入境事由`">
<a-select v-model:value="formState.reasonEntry" show-search placeholder="请选择入境事由" :options="defaultTypeAll.allReasonEntry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="receptionUnit" :label="`接待单位`">
<a-input v-model:value="formState.receptionUnit" placeholder="请输入接待单位" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="emergencyContact" :label="`紧急情况联系人`">
<a-input v-model:value="formState.emergencyContact" placeholder="请输入紧急情况联系人" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="emergencyPhoneNumber" :label="`紧急情况联系电话`" :rules="[
{ message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.emergencyPhoneNumber" placeholder="请输入紧急情况联系电话" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`国内邀请人或本人联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入国内邀请人或本人联系电话" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="teamId" :label="`所属团队`">
<a-select v-model:value="formState.teamId" show-search placeholder="请选择所属团队" :options="defaultTypeAll.allTeam" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="hotelAdress" :label="`旅馆地址`">
<a-input v-model:value="formState.hotelAddress" :allowClear="true" placeholder="请输入旅馆地址" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="remark" :label="`备注`">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox" v-if="visibleEdit">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit" v-if="operateStatus">编辑</a-button>
<a-button type="primary" size="large" v-if="!operateStatus">扫描证件</a-button>
<a-button type="primary" size="large" v-if="!operateStatus">读取外国人永久居留证</a-button>
<a-button type="primary" size="large" @click="saveInfo" v-if="!operateStatus"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="() => formRef.resetFields()" v-if="!operateStatus"><template #icon>
<reload-outlined />
</template>
清空</a-button>
<a-button size="large" @click="qx()" v-if="!operateStatus"><template #icon>
<reload-outlined />
</template>
取消</a-button>
</a-space>
</div>
</div>
</div>
</a-spin>
<template #footer>
</template>
</a-modal>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</template>
<script setup>
import { EditFilled } from "@ant-design/icons-vue";
import { onMounted, reactive, watch } from "vue";
import { useStore } from '@/store/index.js'
import { forIn } from "lodash-es";
import Camera from "@/components/Camera.vue";
import { uploadImg } from '@/api/default.js';
import { message } from 'ant-design-vue';
import { file_img_src } from '@/utils/http_util.js';
import { updateForeignGuestCheckInList, queryForeignGuestDetail } from '@/api/foreignGuestCheckIn.js';
import default_img from '@/assets/img/default.png';
import dayjs from 'dayjs';
const userstore = useStore();
const props = defineProps({
visible: Boolean,
formData: {},
dictionaryAll: {},
flogStatus: Boolean,
visibleEdit: Boolean,//讲底下的编辑按钮隐藏 从离店页面进入是不显示按钮的
});
const formRef = ref();
const operateStatus = ref(true);
const loading = ref(false);
/**判断现场照片修改 */
const sitePhotos = ref(false);
/**判断证件照 */
const certificatePhotos = ref(false);
const emit = defineEmits(["changeCancel"]);
/**提交事件 */
const handleOk = async () => {
await emit("changeCancel");
};
const handleCancel = async () => {
await emit("changeCancel");
};
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
checkinTime: [
{
required: true,
message: '请选择入住时间'
}
],
nationalityCode: [
{
required: true,
message: '请选择国籍(地区)'
},
],
certificateNumber: [
{
required: true,
message: '请输入证件号码'
},
],
certificateType: [
{
required: true,
message: '请输入证件类型'
}
],
gender: [
{
required: true,
message: '请选择性别'
}
],
dateBirth: [
{
required: true,
message: '请选择出生日期'
},
],
visaType: [
{
required: true,
message: '请选择签证种类'
},
],
reasonEntry: [
{
required: true,
message: '请选择入境事由'
},
],
phoneNumber: [
{
required: true,
message: '请输入国内邀请人或本人联系电话'
}
],
teamId: [
{
required: true,
message: '请选择所属团队'
}
],
hotelAdress: [
{
required: true,
message: '请输入旅馆地址'
},
]
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**设置最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
const screenshot_url = ref("");
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
sitePhotos.value = false;
certificatePhotos.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
sitePhotos.value = true;
formState.sitePhoto = e.value;
formState.sitePhotoPath = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**右侧切换截取图片 */
const checked_value1 = ref(true);
const checked_value2 = ref(false);
const checked_value3 = ref(false);
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const formState = reactive({});
const defaultTypeAll = reactive({});
const getData = (data) => {
forIn(data, (value, key) => (formState[key] = value))
}
const getData1 = (data) => {
forIn(props?.dictionaryAll, (value, key) => (defaultTypeAll[key] = value))
}
const edit = () => {
operateStatus.value = false;
}
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
formState.sitePhotoPath = reader.result;
sitePhotos.value = true;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
//上报信息
const saveInfo = () => {
/**批量操作上传图片 */
const arr_http = [];
if (sitePhotos.value) {/**现场照片 */
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'FOREIGN_GUEST'));
} else {
arr_http.push('');
}
if (certificatePhotos.value) {/**身份证 */
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'FOREIGN_GUEST'));
} else {
arr_http.push('');
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (sitePhotos.value) {
arr.sitePhoto = res1
}
if (certificatePhotos.value) {
arr.certificatePhoto = res2
}
updateForeignGuestCheckInList(arr)
.then((res) => {
if (res.code == 9000) {
message.success("已保存");
operateStatus.value = true;
sitePhotos.value = false;
certificatePhotos.value = false;
// reset();
}
loading.value = false;
})
.catch((res) => {
message.warning("保存失败");
loading.value = false;
});
});
}
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
onMounted(() => {
if (props?.visible) {
loading.value =true;
queryForeignGuestDetail({ id: props?.formData.id }).then(res => {
loading.value =false;
forIn(res.data, (value, key) => (formState[key] = value));
}).catch(error=>{
loading.value =false;
})
forIn(props?.dictionaryAll, (value, key) => (defaultTypeAll[key] = value));
operateStatus.value = props?.flogStatus;
// screenshot_url.value = props?.formData.sitePhotoPath;
};
});
const qx = () => {
queryForeignGuestDetail({ id: props?.formData.id }).then(res => {
forIn(res.data, (value, key) => (formState[key] = value));
})
operateStatus.value = true;
}
</script>
<style lang="less">
.visitorFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="departure">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">离店列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="roomId" label="房间号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="options_room" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item name="name" label="证件号码">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="入住时间">
<a-range-picker show-time @change="(data, dateString) => handleChangeTime(data, dateString)" />
</a-form-item>
</a-col>
<a-col>
<a-space :size="10">
<a-button type="primary" @click="queryList()">查询</a-button>
<a-button type="primary" @click="departure()">批量离店</a-button>
<!-- <a-button type="primary">团队离店</a-button> -->
</a-space>
</a-col>
</a-row>
</a-form>
</div>
<div class="titleBox">
<div>
<span class="sign">内宾登记情况</span>
</div>
</div>
<a-spin :spinning="loading_inland">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_inland" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_inland" :data-source="data_inland" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_inland(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'ARRIVE'" title="是否离店" @confirm="setState_inland(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_inland" :rowKey="item=>item.id" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_inland" show-quick-jumper show-size-changer :total="total_inland" v-show="data_inland.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_inland" style="margin: 20px 0px" />
</div>
</a-spin>
<div class="titleBox">
<div>
<span class="sign">外宾登记情况</span>
</div>
</div>
<a-spin :spinning="loading_abroad">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_abroad" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_abroad" :data-source="data_abroad" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_abroad(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'ARRIVE'" title="是否离店" @confirm="setState_abroad(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_abroad" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_abroad" show-quick-jumper show-size-changer :total="total_abroad" v-show="data_abroad.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_abroad" style="margin: 20px 0px" />
</div>
</a-spin>
</a-spin>
<InlandEyes v-if="hotelFormVisible" :visible="hotelFormVisible" :visibleEdit="hotelFormVisible_edit" :id="info_id" :title="titles" @change-Cancel="changeCancel_inland"/>
<AbroadInfo v-if="abroadInfoVisible" :flogStatus="operateStatus" :visible="abroadInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="abroadInfo" @change-Cancel="changeCancel_adroad" :visibleEdit="hotelFormVisible_edit_s"/>
</div>
</template>
<script setup>
import { useStore } from "@/store/index.js";
import { inlandQuery, inlandCheckOut } from "@/api/domesticGuestCheckIn";
import { getForeignGuestCheckInList, departureForeignGuestCheckIn } from '@/api/foreignGuestCheckIn.js';
import { onMounted } from "vue";
import { message } from "ant-design-vue";
import InlandEyes from '@/views/inland/inlandEyes.vue';
import AbroadInfo from '@/views/abroad/abroadInfo.vue';
const userstore = useStore();
const formState = reactive({
name: "",
certificateNumber: "",
checkinTimeEnd: "",
checkinTimeStart: "",
state: "ARRIVE",
roomId: "",
hotelId: userstore.hotelInfo.hotelId, //旅馆id
current: 1,
pageSize: 4,
});
/**字典表查询---性别*/
const options_room = ref(userstore.roomAll); //房间字典
/**spinning*/
const loading = ref(false);
/**分页下拉框选项 */
const pageSizeOptions = ref(['4', '10', '20', '30', '40', '50']);
/**内宾表格----------------------- */
const columns_inland = [
{
title: "姓名",
dataIndex: "name",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "民族",
dataIndex: "nationName",
},
{
title: "户籍地省市县区",
dataIndex: "provincialUrbanAreasName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_inland = ref([]);
const page_inland = ref(formState.current);/**当前第几页 */
const pageSize_inland = ref(formState.pageSize);/**当前每页的数据 */
const total_inland = ref(0);/**总数 */
const selectedRowKeys_inland = ref([]);/**当前选中集合 */
const loading_inland = ref(false);
const rowSelection_inland = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_inland.value = selectedRowKeys;
},
}
const onChange_inland = (page, pageSize) => {
page_inland.value = page;
pageSize_inland.value = pageSize;
queryInland_dd();
};
/**--------------------------- */
/**外宾表格----------------------- */
const columns_abroad = [
{
title: "姓名",
dataIndex: "chineseName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "出生日期",
dataIndex: 'dateBirth',
},
{
title: "国籍地区",
dataIndex: "nationalityCodeName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_abroad = ref([]);
const page_abroad = ref(formState.current);/**当前第几页 */
const pageSize_abroad = ref(formState.pageSize);/**当前每页的数据 */
const total_abroad = ref(0);/**总数 */
const selectedRowKeys_abroad = ref([]);/**当前选中集合 */
const loading_abroad = ref(false);
const rowSelection_abroad = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_abroad.value = selectedRowKeys;
},
}
const onChange_abroad = (page, pageSize) => {
page_abroad.value = page;
pageSize_abroad.value = pageSize;
queryAbroad_dd();
};
/**--------------------------- */
/**时间变化 */
const handleChangeTime = (data, dataArr,) => {
if (dataArr && dataArr.length > 0) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**内宾查询 */
const queryInland = () => {
return new Promise((resolve) => {
inlandQuery(formState).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**内宾单独查询 */
const queryInland_dd = () => {
const arr = { ...formState };
arr.current = page_inland.value;
arr.pageSize = pageSize_inland.value;
loading_inland.value = true;
inlandQuery(arr).then((res) => {
if (res?.code == 9000) {
data_inland.value = res.data.records;
total_inland.value = res.data.total;
}
loading_inland.value = false;
}).catch(error => {
loading_inland.value = false;
});
}
/**外宾查询 */
const queryAbroad = () => {
const arr = { ...formState };
return new Promise((resolve) => {
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单独查询 */
const queryAbroad_dd = () => {
const arr = { ...formState };
arr.current = page_abroad.value;
arr.pageSize = pageSize_abroad.value;
loading_abroad.value = true;
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
data_abroad.value = res.data.records;
total_abroad.value = res.data.total;
}
loading_abroad.value = false;
}).catch(error => {
loading_abroad.value = false;
});
}
/**分页查询 */
const queryList = async () => {
loading.value = true;
page_inland.value = formState.current;
pageSize_inland.value = formState.pageSize;
page_abroad.value = formState.current;
pageSize_abroad.value = formState.pageSize;
Promise.all([queryInland(), queryAbroad()]).then(([res1, res2]) => {
loading.value = false;
data_inland.value = res1.data.records;
total_inland.value = res1.data.total;
data_abroad.value = res2.data.records;
total_abroad.value = res2.data.total;
}).catch(error => {
loading.value = false;
});
};
/**内宾单个离店 */
const setState_inland = (record) => {
loading.value = true;
inlandCheckOut([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
queryInland_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
}
/**内宾批量离店 */
const departure_inland = () => {
return new Promise((resolve) => {
inlandCheckOut(selectedRowKeys_inland.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单个离店 */
const setState_abroad = (record) => {
loading.value = true;
departureForeignGuestCheckIn([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
queryAbroad_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
}
/**外宾批量离店 */
const departure_abroad = () => {
return new Promise((resolve) => {
departureForeignGuestCheckIn(selectedRowKeys_abroad.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**批量离店 */
const departure = () => {
if (selectedRowKeys_inland.value.length > 0 || selectedRowKeys_abroad.value.length > 0) {
loading.value = true;
const arr_http = [];
if (selectedRowKeys_inland.value.length > 0) {
arr_http.push(departure_inland());
} else {
arr_http.push("");
}
if (selectedRowKeys_abroad.value.length > 0) {
arr_http.push(departure_abroad());
} else {
arr_http.push("");
}
Promise.all(arr_http).then(([res1, res2]) => {
loading.value = false;
message.success('离店成功')
queryList();
// if (selectedRowKeys_inland.value.length > 0) {
// if (res1?.code==9000){
// message.success('内宾离店成功')
// }
// }
// if (selectedRowKeys_abroad.value.length > 0) {
// if (res2?.code==9000){
// message.success('外宾离店成功')
// }
// }
}).catch(error => {
loading.value = false;
})
} else {
message.warning('请选择行')
}
}
/**内宾查看 */
const info_id = ref('');
const hotelFormVisible = ref(false);
const hotelFormVisible_edit = ref(false);
const titles = ref("查看内宾详情");
const changeCancel_inland = () => {
hotelFormVisible.value = false;
};
const eye_inland = ( e) => {
info_id.value = e.id;
hotelFormVisible.value = true;
hotelFormVisible_edit.value = false;
};
/**外宾查看 */
const abroadInfoVisible = ref(false);
const operateStatus = ref(false);
const dictionaryAllInfo = ref({});
const abroadInfo = ref('');
const hotelFormVisible_edit_s = ref(false);
const changeCancel_adroad = () => {
abroadInfoVisible.value = false;
};
const eye_abroad = ( e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
operateStatus.value = true;
hotelFormVisible_edit_s.value = false;
};
onMounted(() => {
queryList();
})
</script>
<style lang="less">
.departure {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
.form {
.ant-form-item {
margin-bottom: 0px;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="personnelAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="nickname" :label="`姓名`">
<a-input v-model:value="formState.nickname" placeholder="请输入姓名" :allowClear="true" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
<td colspan="1" rowspan="5">
<div style="display: flex;flex-direction: row;justify-content: space-around;flex-wrap: wrap;">
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="!formState.photo">
<span>照片</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="tmpImg" v-else />
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;" v-if="operateStatus!=2">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
上传照片
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="username" :label="`用户名`">
<a-input v-model:value="formState.username" placeholder="请输入用户名" :allowClear="true" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="password" :label="`密码`">
<a-input v-model:value="formState.password" placeholder="请输入密码" :allowClear="true" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="email" :label="`邮箱`">
<a-input v-model:value="formState.email" :allowClear="true" placeholder="请输入邮箱" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="phone" :label="`手机号`">
<a-input v-model:value="formState.phone" :allowClear="true" placeholder="请输入手机号" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="identityCard" :label="`身份证号`">
<a-input v-model:value="formState.identityCard" :allowClear="true" placeholder="请输入身份证号码" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="licensePlate" :label="`车牌号`">
<a-input-group compact>
<a-form-item style="width: 20%" name="plateProvince">
<a-select show-search v-model:value="formState.licensePlate" :filter-option="filterOption" :options="allProvince" placeholder="请选择省份" :allowClear="true" optionLabelProp="name" style="width: 100%" :fieldNames="{ label: 'name', value: 'name' }">
</a-select>
</a-form-item>
<a-input v-model:value="formState.plateNumber" style="width: 80%" />
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="gender" :label="`性别`">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus==2?true:false"></a-select>
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="roles" :label="'权限'">
<a-select mode="multiple" v-model:value="formState.roles" show-search placeholder="请选择" :options="roles" :filter-option="filterOptionRoles" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus==2?true:false"></a-select>
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" v-if="operateStatus==2" @click="edit"><template #icon><file-protect-outlined /></template>编辑</a-button>
<a-button type="primary" size="large" @click="saveInfo" v-if="operateStatus==1||operateStatus==3"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()" v-if="operateStatus==1"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
</a-modal>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { message } from 'ant-design-vue';
import { onMounted, reactive } from 'vue';
import { queryRole } from '@/api/role.js';
import { addPersonnel, updatePersonnel } from '@/api/user.js';
import { file_img_src } from '@/utils/http_util.js';
import { getImgByUrl } from '@/api/default.js';
import { forIn } from "lodash-es";
const props = defineProps({
visible: Boolean,
title: String,
formData: {},
flogStatus: Number
});
const emit = defineEmits(["changeCancel", "updateUserList"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
nickname: null,
username: null,
gender: null,
password: null,
email: null,
phone: null,
roles: [],
identityCard: null,
licensePlate: null,
plateNumber: null,
photo: null
});
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
residentName: [
{
required: true,
message: '请输入住客姓名'
}
],
certificateNumber: [
{
required: true,
message: '请选择访客证件号码'
},
],
nationalityCode: [
{
required: true,
message: '请选择访客国籍(地址)'
},
]
};
const roles = ref([]);
const allGender = ref(userstore.returnCode(5));
const allProvince = ref(userstore.returnCode(6)); //全省信息
const operateStatus = ref(1);
const loading = ref(false);
const tmpImg = ref('');
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const filterOptionRoles = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleMenuClick = (e) => {
console.log("click", e);
};
const saveInfo = () => {
formState.licensePlate = formState.licensePlate + formState.plateNumber;
if (operateStatus.value == 1) {
addPersonnel(formState).then(res => {
if (res.code == '9000') {
message.success('新增成功!');
formRef.value.resetFields();
formState.plateNumber = null;
formState.photo = null;
emit("updateUserList");
}
}).catch(error => {
message.error(error.message);
})
} else if (operateStatus.value == 3) {
updatePersonnel(formState).then(res => {
if (res.code == '9000') {
message.success('编辑成功!');
operateStatus.value = 2;
emit("updateUserList");
}
}).catch(error => {
message.error(error.message);
})
}
}
//选择头像
const handleChange = async info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
tmpImg.value = reader.result;
file_img_src(tmpImg.value, userstore.hotelInfo.hotelId, "PRACTICE_USER").then(res => {
formState.photo = res;
});
};
}
};
//不让文件直接上传
const beforeUpload = (file) => {
return false
};
//编辑
const edit = () => {
operateStatus.value = 3;
}
onMounted(() => {
//查询权限列表
queryRole().then(res => {
roles.value = res.data;
})
operateStatus.value = props?.flogStatus;
if (operateStatus.value == 2 || operateStatus.value == 3) {
forIn(props?.formData, (value, key) => (formState[key] = value));
let tmpRoles = formState.roles, tmpArr = [];
tmpRoles.forEach(item => {
tmpArr.push(item.id);
});
formState.roles = tmpArr;
let carNo = formState.licensePlate;
if (carNo?.length > 0) {
formState.licensePlate = carNo.slice(0, 1);
formState.plateNumber = carNo.slice(1, carNo.length - 1);
}
if (formState.photo) {
getImgByUrl({ bucket: 'PRACTICE_USER', filename: formState.photo, hotelId: formState.hotelId }).then(res => {
if (res.code == '9000') {
tmpImg.value = res.data;
}
}).catch(error => {
message.error(error.message);
})
}
}
})
</script>
<style lang="less">
.personnelAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 80px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roleAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="name" :label="`角色名称`">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入角色名称" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="description" :label="`角色描述`">
<a-input v-model:value="formState.description" :allowClear="true" placeholder="角色描述" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="saveInfo">
<template #icon><file-protect-outlined /></template>保存
</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()" v-if="operateStatus==1">
<template #icon>
<reload-outlined />
</template>清空
</a-button>
</a-space>
</div>
</div>
</div>
</a-modal>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { message } from 'ant-design-vue';
import { onMounted, reactive } from 'vue';
import { addRoles, updateRoles } from '@/api/role.js';
import { forIn } from "lodash-es";
const props = defineProps({
visible: Boolean,
title: String,
formData: {},
flogStatus: Number
});
const emit = defineEmits(["changeCancel", "changeData"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const userstore = useStore();
const formRef = ref();
const formState = reactive({
name: '',
description: ''
});
const rules = {
name: [
{
required: true,
message: '请输入角色名称'
}
],
description: [
{
required: true,
message: '请输入角色描述'
}
]
};
const roles = ref([]);
const operateStatus = ref(1);
const loading = ref(false);
const saveInfo = () => {
if (operateStatus.value == 1) {
addRoles(formState).then(res => {
if (res.code == '9000') {
message.success('新增成功!');
handleCancel();
emit("changeData");
}
}).catch(error => {
message.error(error.message);
});
} else if (operateStatus.value == 2) {
updateRoles(formState).then(res => {
if (res.code == '9000') {
message.success('编辑成功!');
handleCancel();
emit("changeData");
}
}).catch(error => {
message.error(error.message);
});
}
}
// let socket = null;
// // 提交按钮的点击事件处理函数
// const send = () => {
// // 向服务器发送消息
// socket.emit('send', '')
// }
onMounted(() => {
operateStatus.value = props?.flogStatus;
if (operateStatus.value == 2) {
forIn(props?.formData, (value, key) => (formState[key] = value));
}
// //实例websocket
// socket = io('ws://127.0.0.1:90/echo/');
// // 建立连接的事件
// socket.on('connect', () => console.log('connect: websocket 连接成功!'));
// // 关闭连接的事件
// socket.on('disconnect', () => console.log('disconnect: websocket 连接关闭!'));
// // 接收到消息的事件
// socket.on('message', msg => console.log(msg));
})
// onBeforeUnmount(() => {
// // 关闭连接
// socket.close()
// // 销毁 websocket 实例对象
// socket = null;
// })
</script>
<style lang="less">
.roleAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 80px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-drawer v-model:visible="visible" class="custom-class" style="color: red" title="编辑权限" placement="right" @close="handleClose">
<a-tree mode="inline" v-model:checkedKeys="checkedKeys" checkable :tree-data="treeData" :fieldNames="{title:'label',key:'id'}" @check="changeChecked">
<template #label="{ label, id }">
<template>{{ label }}</template>
</template>
</a-tree>
<div style="margin-top:40px;margin-left:40px;">
<a-button type="primary" @click="confirm">
<template #icon>
<edit-filled />
</template>
确定
</a-button>
</div>
</a-drawer>
</template>
<script setup>
import { onMounted } from "vue";
import { forIn } from "lodash-es";
import { grantMenuRole } from '@/api/role.js';
import { message } from "ant-design-vue";
import { treeForeach } from '@/utils/http_util.js';
const props = defineProps({
visible: Boolean,
roleInfo: {},
treeData: []
});
const emit = defineEmits(["changeCancel"]);
const visible = ref(false);
const roleInformation = ref({});
const treeData = ref([]);
const checkedKeys = ref([]);
const showDrawer = () => {
visible.value = true;
};
const handleClose = () => {
emit("changeCancel");
}
const changeChecked = e => {
console.log(e);
}
//权限提交
const confirm = () => {
grantMenuRole(checkedKeys.value, roleInformation.value.id).then(res => {
if (res.code == '9000') {
message.success('权限添加成功!');
}
}).catch(error => {
message.error(error.message);
});
};
onMounted(() => {
visible.value = props.visible;
forIn(props?.roleInfo, (value, key) => { roleInformation.value[key] = value });
treeData.value = props?.treeData;
treeForeach(roleInformation.value.roles, node => {
checkedKeys.value.push(node.id);
})
});
</script>
\ No newline at end of file
<template>
<div class="personnelManagement">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">人员管理</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入用户姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="username" label="账号">
<a-input v-model:value="formState.username" placeholder="请输入用户账号"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="gender" label="性别">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" @click="queryUser">
<template #icon>
<SearchOutlined />
</template>查询</a-button>&nbsp;
<a-button type="primary" @click="add">
<template #icon><plus-outlined /></template>新增</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="showInfo(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-button type="link" primary size="small" style="color: #52c41a" @click="reset(record)">
<template #icon>
<eye-filled />
</template>
重置密码
</a-button>
<a-popconfirm title="删除不可恢复,是否确认?" @confirm="deleteUser(record)">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
删除
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
</div>
</a-spin>
</div>
<PersonnelAdd v-if="personnelAddVisible" :flogStatus="operateStatus" :visible="personnelAddVisible" :formData="personnelInfo" @change-Cancel="changeCancelPersonnelAdd" :title="title" :updateUserList="queryUser" />
</template>
<script setup>
import { onMounted, reactive } from "vue";
import { getUserList, removePersonnel, resetPassword } from '@/api/user.js';
import { useStore } from '@/store/index.js';
import { message } from "ant-design-vue";
import PersonnelAdd from '@/views/employeeManagement/components/personnelAdd.vue';
const userstore = useStore();
const allGender = ref(userstore.returnCode(5));
const loading = ref(false);
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
username: null,
name: null,
gender: null
});
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const personnelAddVisible = ref(false);
const operateStatus = ref(1);
const personnelInfo = ref({});
const title = ref('');
const changeCancelPersonnelAdd = () => {
personnelAddVisible.value = false;
}
const data = ref([]);
//查询用户
const queryUser = () => {
loading.value = true;
getUserList(formState).then(res => {
if (res.code == '9000') {
data.value = [];
res.data.forEach((item, index) => {
item['index'] = index + 1;
item['key'] = item.id;
data.value.push(item);
});
loading.value = false;
}
}).catch(error => {
message.error(error.message);
})
}
const columns = [
{
title: "序号",
dataIndex: "index",
},
{
title: "姓名",
dataIndex: "nickname",
},
{
title: "联系方式",
dataIndex: "phone",
},
{
title: "身份证号",
dataIndex: "identityCard",
},
{
title: "车牌号",
dataIndex: "licensePlate",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 350
}
];
//查看详情
const showInfo = (record) => {
personnelInfo.value = record;
operateStatus.value = 2;
personnelAddVisible.value = true;
title.value = '查看用户';
}
//新增
const add = () => {
personnelInfo.value = [];
operateStatus.value = 1;
personnelAddVisible.value = true;
title.value = '新增用户';
}
//编辑详情
const edit = (record) => {
personnelInfo.value = record;
operateStatus.value = 3;
personnelAddVisible.value = true;
title.value = '编辑用户';
}
//删除用户
const deleteUser = record => {
removePersonnel({ userId: record.id }).then(res => {
if (res.code == '9000') {
message.success('删除成功!');
queryUser();
}
}).catch(error => {
message.error(error.message);
});
}
const reset = record=> {
resetPassword({username: record.username, hotelId: userstore.hotelInfo.hotelId}).then(res => {
message.success('重置成功:' + res);
}).catch(error => {
message.error(error.message);
});
}
onMounted(() => {
queryUser();
})
</script>
<style lang="less">
.personnelManagement {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
<template>
<div class="rolesManagement">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">角色管理</span>
</div>
</div>
<div style="margin: 0px 25px 20px 25px">
<a-button type="primary" @click="queryRoleList">
<template #icon>
<SearchOutlined />
</template>查询</a-button>&nbsp;
<a-button type="primary" @click="addRoles">
<template #icon><plus-outlined /></template>新增</a-button>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="删除不可恢复,是否确认?" @confirm="deleteRole(record)">
<a-button type="link" primary size="small" style="color:#ff4d1f;">
<template #icon>
<swap-outlined />
</template>
删除
</a-button>
</a-popconfirm>
<a-button type="link" primary size="small" style="color: #52c41a;" @click="changeRole(record)">
<template #icon>
<edit-filled />
</template>
权限
</a-button>
</a-space>
</template>
</template>
</a-table>
</div>
</a-spin>
<RolePermissionDrawer v-if="drawerVisible" :visible="drawerVisible" :roleInfo="roleInfo" @change-Cancel="changeCancelRole" :treeData="treeData" />
<RoleAdd v-if="roleAddVisible" :flogStatus="operateStatus" :visible="roleAddVisible" :formData="roleData" @change-Cancel="changeCancelRoleAdd" :title="title" @changeData="queryRoleList" />
</div>
</template>
<script setup>
import { onMounted, reactive } from "vue";
import { queryRole, bulkRemoveRoles } from '@/api/role.js';
import { useStore } from '@/store/index.js';
import { getTree } from '@/api/menu.js';
import { message } from "ant-design-vue";
import RolePermissionDrawer from '@/views/employeeManagement/components/rolePermissionDrawer.vue';
import RoleAdd from '@/views/employeeManagement/components/roleAdd.vue';
const userstore = useStore();
const loading = ref(false);
const data = ref([]);
const roleAddVisible = ref(false);
const operateStatus = ref(1);//1为新增 2为编辑
const roleData = ref({});
const title = ref('角色新增');
//查询用户
const queryRoleList = () => {
loading.value = true;
queryRole().then(res => {
if (res.code == '9000') {
data.value = res.data;
loading.value = false;
}
}).catch(error => {
message.error(error.message);
loading.value = false;
})
}
const columns = [
{
title: "角色名称",
dataIndex: "name",
},
{
title: "创建时间",
dataIndex: "createTime",
},
{
title: "描述",
dataIndex: "description",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 300
},
];
const changeCancelRoleAdd = () => {
roleAddVisible.value = false;
}
//编辑详情
const edit = (record) => {
roleData.value = record;
operateStatus.value = 2;
title.value = '角色编辑!';
roleAddVisible.value = true;
}
//新增角色
const addRoles = () => {
operateStatus.value = 1;
title.value = '角色新增!';
roleAddVisible.value = true;
}
//删除
const deleteRole = record => {
bulkRemoveRoles([record.id]).then(res => {
if (res.code == '9000') {
message.success('删除成功!');
queryRoleList();
}
}).catch(error=>{
message.error(error.message);
});
}
//权限
const drawerVisible = ref(false);
const roleInfo = ref({});
const treeData = ref([]);
const changeRole = async record => {
getTree({ type: 'ROLE', value: record.id }).then(res => {
if (res.code == '9000') {
roleInfo.value = record;
roleInfo.value['roles'] = res.data;
drawerVisible.value = true;
}
});
}
const changeCancelRole = () => {
drawerVisible.value = false;
}
const defaultRoleMenu = (paramas, type) => {
}
onMounted(() => {
queryRoleList();
getTree({ type: 'USER', value: '1' }).then(res => {
if (res.code == '9000') {
treeData.value = res.data;
}
}).catch(error => {
console.log(error);
});
})
</script>
<style lang="less">
.rolesManagement {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
<template>
<div>
<a-modal v-model:visible="visible" title="修改密码" @ok="handleOk" :footer="null">
<a-form :model="formState" name="basic" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" autocomplete="off" @finish="onFinish" @finishFailed="onFinishFailed">
<a-form-item label="旧密码" name="password" :rules="[{ required: true, message: '请输入你的原密码' }]">
<a-input-password v-model:value="formState.password" />
</a-form-item>
<a-form-item label="新密码" name="newPassword" :rules="[{ required: true, message: '请输入新密码' }]">
<a-input-password v-model:value="formState.newPassword" />
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button type="primary" html-type="submit" @click="confirmPassword">确定</a-button>
<a-button type="primary" style="margin-left:10px;" html-type="submit" @click="handleOk">取消</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script setup>
import { editPassword } from '@/api/user';
import { useStore } from '@/store/index.js'
import { message } from 'ant-design-vue';
import router from '../../../router';
const userStore = useStore();
const visible = ref(false);
const showModal = () => {
visible.value = true;
};
const handleOk = e => {
console.log(e);
visible.value = false;
};
const formState = reactive({
password: '',
newPassword: ''
});
const onFinish = values => {
// console.log('Success:', values);
};
const onFinishFailed = errorInfo => {
// console.log('Failed:', errorInfo);
};
//提交密码
const confirmPassword = () => {
const params = {
userId: userStore.userInfo.id,
oldPassword: btoa(encodeURI(formState.password)),
newPassword: btoa(encodeURI(formState.newPassword))
};
editPassword(params).then(res => {
if (res.code == '9000') {
message.success('密码修改成功,请重新登录!');
localStorage.removeItem('user')
userStore.token = null;
router.push('/login');
}
}).catch(error => {
message.error(error.message);
})
}
defineExpose({
showModal
})
</script>
\ No newline at end of file
<template>
<a-layout class="homepage">
<a-layout-header class="home-header">
<div class="header-logo">
<img :src="homeLogo" alt="" style="width:40px;height:40px;">&nbsp;
<span>旅游业治安管理信息系统</span>
</div>
<div class="header-btn">
<a-button type="primary" @click="()=>{router.push('/inland/inlandAdd')}">
<template #icon>
<IdcardOutlined />
</template>
内宾入住
</a-button>
<a-button type="primary" @click="()=>{router.push('/abroad/abroadAdd')}">
<template #icon>
<ScheduleOutlined />
</template>
外宾入住
</a-button>
<a-button type="primary">
<template #icon>
<UserDeleteOutlined />
</template>
离店
</a-button>
<a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<!-- <a-menu-item key="1">
<EditOutlined />
修改密码
</a-menu-item>
<a-menu-item key="2">
<LoginOutlined />
退出
</a-menu-item> -->
</a-menu>
</template>
<a-button>
其他
<DownOutlined />
</a-button>
</a-dropdown>
</div>
<div class="header-info">
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent style="color:white;">
{{loginUser}}
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item key="1">
<a-button @click="editPassword">修改密码</a-button>
</a-menu-item>
<a-menu-item key="2">
<a-button @click="clearCache">刷新缓存</a-button>
</a-menu-item>
<a-menu-item key="2">
<a-button @click="loginOut">退出系统</a-button>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</a-layout-header>
<a-layout class="home-bottom" style="background: white;">
<a-layout-sider class="bottom-sider" :collapsed="collapsed" width="260">
<div>
<a-button type="primary" class="collapsedButton" @click="toggleCollapsed">
<MenuUnfoldOutlined v-if="collapsed" />
<MenuFoldOutlined v-else />
</a-button>
<a-menu class="myMenu" mode="inline" theme="dark" v-model:openKeys="openKeys" v-model:selectedKeys="selectedKeys" @click="handleClick" @openChange="changeOpenClick">
<template v-for="item in menuList" :key="item.path">
<template v-if="item.children.length==0">
<a-menu-item :key="item.path" :text='item.label'>
<template #icon>
<PieChartOutlined />
</template>
{{ item.label }}
</a-menu-item>
</template>
<template v-else>
<a-sub-menu :key="item.path" :text='item.label'>
<template #icon>
<MailOutlined />
</template>
<template #title>{{ item.label }}</template>
<template v-for="item1 in item.children" :key="item.path">
<template v-if="item1.children.length==0">
<a-menu-item :key="item1.path" :text='item1.label'>
<template #icon>
<PieChartOutlined />
</template>
{{ item1.label }}
</a-menu-item>
</template>
<template v-else>
<a-sub-menu :key="item1.path" :text='item1.label'>
<template #icon>
<MailOutlined />
</template>
<template #title>{{ item1.label }}</template>
<template v-for="item11 in item1.children" :key="item.path">
<template v-if="item11.children.length==0">
<a-menu-item :key="item11.path" :text='item11.label'>
<template #icon>
<PieChartOutlined />
</template>
{{ item11.label }}
</a-menu-item>
</template>
<template v-else>
<!-- <sub-menu :menu-info="item" :key="item.id" /> -->
</template>
</template>
</a-sub-menu>
</template>
</template>
</a-sub-menu>
</template>
</template>
</a-menu>
</div>
</a-layout-sider>
<a-layout-content class="bottom-content">
<a-tabs class="myTabs" v-model:activeKey="activeKey" hide-add type="editable-card" @edit="onEdit" size="small">
<a-tab-pane v-for="pane in panes" :key="pane.key" :tab="pane.title" :closable="pane.closable">
</a-tab-pane>
</a-tabs>
<router-view v-if="visible" class="router-content"></router-view>
</a-layout-content>
</a-layout>
</a-layout>
<EditPassword ref="editPasswordRef" />
</template>
<script setup>
import { onMounted, watch } from "vue";
import { useRouter } from "vue-router";
import { getTree } from '@/api/menu';
import { useStore } from '@/store/index.js'
import EditPassword from '@/views/homePage/components/editPasswordModal.vue';
import { addRoutes } from '@/router/dynamicRoutes';
import homeLogo from '@/assets/img/homepage/logo.png';
import { getAllCode } from '@/api/default';
import { getAllRoom } from '@/api/room.js';
import { message } from "ant-design-vue";
const userStore = useStore();
const editPasswordRef = ref();
//左侧菜单栏参数
const router = useRouter();
const menuList = ref([]);
const collapsed = ref(false);
const selectedKeys = ref([]);
const openKeys = ref([]);
const preOpenKeys = ref([]);
const loginUser = ref('');
watch(
() => openKeys,
(val, oldVal) => {
preOpenKeys.value = oldVal;
userStore.menuParams.preOpenKeys = preOpenKeys.value;
},
);
//折叠菜单栏
const toggleCollapsed = () => {
collapsed.value = !collapsed.value;
openKeys.value = collapsed.value ? [] : preOpenKeys.value;
userStore.menuParams.openKeys = openKeys.value;
};
//左侧菜单栏点击
const handleClick = (e) => {
selectedKeys.value[0] = e.key;
if (e.key.indexOf('/') > -1) {
if (panes.value.some(item => item.key == e.key)) {
activeKey.value = e.key;
return
}
router.push(e.key);
activeKey.value = e.key;
panes.value.push({
title: e.item.text,
key: e.key,
});
userStore.menuParams.selectedKeys = selectedKeys.value;
userStore.menuParams.panes = panes.value;
userStore.menuParams.activeKey = activeKey.value;
}
}
//设置左侧菜单栏只能打开一个
const changeOpenClick = e => {
if (e.length > 0) {
if (e.indexOf('cyrygl') <= -1) {
openKeys.value = openKeys.value.slice(-1);
} else {
if (openKeys.value.slice(-1) != 'cyrygl') {
openKeys.value = openKeys.value.filter(item => item != 'ldgl' && item != 'cyrygl');
}
}
userStore.menuParams.openKeys = openKeys.value;
}
}
//右侧tabs参数
const panes = ref([]);
const activeKey = ref('');
const newTabIndex = ref(0);
const visible = ref(true);
//移除tabs
const remove = targetKey => {
let lastIndex = 0;
panes.value.forEach((pane, i) => {
if (pane.key === targetKey) {
lastIndex = i - 1;
}
});
panes.value = panes.value.filter(pane => pane.key !== targetKey);
if (panes.value.length && activeKey.value === targetKey) {
if (lastIndex >= 0) {
activeKey.value = panes.value[lastIndex].key;
} else {
activeKey.value = panes.value[0].key;
}
}
userStore.menuParams.panes = panes.value;
userStore.menuParams.activeKey = activeKey.value;
};
const onEdit = targetKey => {
remove(targetKey);
};
//监听被选中的tabs的key
watch(activeKey, (newValue, oldValue) => {
router.push(activeKey.value);
userStore.menuParams.activeKey = activeKey.value;
})
//监听tabs的数组
watch(panes, (newValue, oldValue) => {
visible.value = newValue.length > 0 ? true : false;
panes.value.forEach((item, index) => {
if (panes.value.length - 1 != index) {
delete item.closable
} else {
panes.value[panes.value.length - 1]['closable'] = false;
}
})
userStore.menuParams.panes = panes.value;
}, { deep: true })
onMounted(() => {
getTree({ type: 'USER', value: '1' }).then(res => {
menuList.value = res.data;
loginUser.value = userStore.userInfo.account;
selectedKeys.value = userStore.menuParams.selectedKeys;
openKeys.value = userStore.menuParams.openKeys;
preOpenKeys.value = userStore.menuParams.preOpenKeys;
activeKey.value = userStore.menuParams.activeKey;
panes.value = userStore.menuParams.panes;
});
});
//查询所有字典
const getAllCode_pro = () => {
return new Promise((resolve) => {
getAllCode().then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
}
//查询所有房间
const getAllRoom_pro = () => {
return new Promise((resolve) => {
getAllRoom({hotelid: userStore.hotelInfo.hotelId}).then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
}
const clearCache = ()=>{
Promise.all([getAllCode_pro(),getAllRoom_pro()]).then(([res1, res2]) => {
userStore.clearAll();
userStore.setAll(res1, res2);
message.success('刷新缓存完成!');
router.go(0);
}).catch(error=>{
message.warning('刷新缓存失败');
})
}
const loginOut = () => {
localStorage.removeItem('user')
userStore.token = null;
router.push('/login');
userStore.$patch(state => {
userStore.menuParams.selectedKeys = ['/inland/inlandAdd'];
userStore.menuParams.openKeys = ['lkgl', '/inland/inlandAdd'];
userStore.menuParams.preOpenKeys = ['lkgl'];
userStore.menuParams.activeKey = '/inland/inlandAdd';
userStore.menuParams.panes = [{ title: '内宾入住', key: '/inland/inlandAdd', closable: false }]
})
}
//修改密码
const editPassword = () => {
editPasswordRef.value.showModal();
}
</script>
<style scoped lang="less">
.homepage {
width: 100%;
height: 100%;
.home-header {
width: 100%;
height: 80px;
// display: flex;
color: white;
background-color: #0e5de5;
.header-logo {
width: 350px;
height: 100%;
font-size: 22px;
float: left;
display: flex;
/* align-content: center; */
justify-content: center;
align-items: center;
}
.header-btn {
display: none;
// width: 600px;
float: left;
padding-top: 15px;
button {
margin-right: 15px;
color: white;
background-color: rgb(41, 23, 91);
border: 1px solid white;
box-shadow: 0px 0px 1px 1px #ddddddb3;
}
}
.header-info {
width: 200px;
float: right;
margin-top: 11px;
margin-right: -10px;
text-align: right;
}
}
.home-bottom {
width: 100%;
height: calc(100% - 80px);
.bottom-sider {
width: 260px !important;
height: 100%;
border-top: 2px solid #3c5f9d;
// background-color: rgb(41, 23, 91);
background-color: #0e5de5;
.collapsedButton {
margin-top: 20px;
margin-left: 16px;
margin-bottom: 16px;
// background-color: rgb(41, 23, 91);
background-color: #0e5de5;
border: 1px solid white;
box-shadow: 0px 0px 1px 1px #ddddddb3;
}
.myMenu {
// background-color: rgb(41, 23, 91);
background-color: #0e5de5;
:deep(.ant-menu-inline.ant-menu-sub) {
// background-color: rgb(41, 23, 91);
background-color: #0e5de5;
}
}
:deep(
.ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal)
.ant-menu-item-selected
) {
background-color: white !important;
span {
// color: rgb(41, 23, 91);
color: #0e5de5;
}
}
}
.bottom-content {
width: calc(100% - 260px);
height: 100%;
padding: 10px;
.router-content {
width: 100%;
height: calc(100% - 60px);
border-top: 1px solid #ddd;
}
:deep(
.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active,
.ant-tabs-card > div > .ant-tabs-nav .ant-tabs-tab-active
) {
color: white !important;
background-color: #0e5de5 !important;
// background-color: rgb(41, 23, 91) !important;
}
:deep(.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn) {
color: white !important;
}
}
}
}
</style>
<template>
<a-modal class="handleForm" :visible="visible" :title="title" :width="600" :bodyStyle="{ padding: '16px 24px' }" @ok="handleOk" @cancel="handleCancel">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 5 }" :wrapper-col="{ span: 19 }">
<a-form-item name="pass" :label="`旅馆代码`" :rules="{
required: true,
message: '请输入旅馆代码',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`旅馆名称`" :rules="{
required: true,
message: '请输入旅馆名称',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`旅馆招牌名称`" :rules="{
required: true,
message: '请输入旅馆招牌名称',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`旅馆负责人`" :rules="{
required: true,
message: '请输入旅馆负责人',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass1" :label="`联系电话`" :rules="{
required: true,
}">
<a-input v-model:value="formState.pass1" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`地址`" :rules="{
required: true,
message: '请输入地址',
}">
<a-textarea v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`相关证书`">
<a-upload v-model:file-list="fileList1" list-type="picture-card" @preview="handlePreview" :before-upload="beforeUpload" accept=".jpg, .jpeg, .png">
<div v-if="fileList1.length < 1">
<plus-outlined />
<div style="margin-top: 8px">Upload</div>
</div>
</a-upload>
</a-form-item>
<a-form-item name="pass" :label="`旅馆平面图`">
<a-upload v-model:file-list="fileList" list-type="picture-card" @preview="handlePreview" :before-upload="beforeUpload" :multiple="true" accept=".jpg, .jpeg, .png">
<div>
<plus-outlined />
<div style="margin-top: 8px">Upload</div>
</div>
</a-upload>
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup>
import { reactive, ref, defineProps, onMounted } from "vue";
import { PlusOutlined } from "@ant-design/icons-vue";
const props = defineProps({
visible: Boolean,
title: String,
edits: Boolean,
});
const fileList = ref([]);
const fileList1 = ref([]);
const previewVisible = ref(false);
const previewImage = ref("");
const previewTitle = ref("");
const formState = reactive({
pass: "",
pass1: "",
});
const emit = defineEmits(["handleSubmit", "changeform", "previewImage"]);
const formRef = ref();
// 提交事件
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
await emit("handleSubmit", values);
});
};
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
}
const handlePreview = async (file) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value =
file.name || file.url.substring(file.url.lastIndexOf("/") + 1);
await emit("previewImage", {
previewVisibles: previewVisible.value,
previewImages: previewImage.value,
previewTitles: previewTitle.value,
});
};
const beforeUpload = (file) => {
return false;
};
const checkePhonenumber = (rule, value) => {
if (value) {
const reg = /^1[3456789]\d{9}$/;
if (!reg.test(value)) {
return Promise.reject("请输入正确的手机号格式");
} else {
return Promise.resolve();
}
} else {
return Promise.reject("请输入联系电话");
}
};
// 关闭弹框事件
const handleCancel = async () => {
await emit("changeform", false);
};
onMounted(() => {
if (!props.edits) {
formState.pass = 1;
}
});
</script>
<style lang="less" scoped>
.handleForm {
:deep(.ant-modal-content .ant-modal-close-x) {
width: 49px;
height: 49px;
line-height: 49px;
}
:deep(.ant-modal-content .ant-modal-body) {
padding-block: 16px;
}
.form {
:deep(.ant-form-item-with-help) {
margin-bottom: -16px;
}
:deep(.ant-input-number, .ant-picker) {
width: 100%;
}
:deep(.ant-form-item) {
margin-right: 0;
margin-bottom: 10px;
}
}
.dropPoint {
display: flex;
justify-content: space-between;
align-items: center;
> .ant-input {
flex: 1;
margin-right: 10px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="hotelEdit">
<a-spin :spinning="loading">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="hotelCode" :label="`旅馆代码`" :rules="{
required: true,
message: '请输入旅馆代码',
}">
<a-input v-model:value="formState.hotelCode" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆名称" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="name" :label="`旅馆名称`" :rules="{
required: true,
message: '请输入旅馆名称',
}">
<a-input v-model:value="formState.name" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆名称" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="signboardName" :label="`旅馆招牌名称`" :rules="{
required: true,
message: '请输入旅馆招牌名称',
}">
<a-input v-model:value="formState.signboardName" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆招牌名称" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="hotelManager" :label="`旅馆负责人`" :rules="{
required: true,
message: '请输入旅馆负责人',
}">
<a-input v-model:value="formState.hotelManager" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆负责人" />
</a-form-item>
</td>
<td colspan="6">
<a-form-item name="telephone" :label="`联系电话`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.telephone" :disabled="!is_edit" :allowClear="true" placeholder="联系电话" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="9">
<a-form-item name="address" :label="`地址`" :wrapper-col="{ span: 22 }" :label-col="{ span: 2 }" :rules="{
required: true,
message: '请输入地址',
}">
<a-input v-model:value="formState.address" :disabled="!is_edit" :allowClear="true" placeholder="请输入地址" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="9">
<a-form-item class="lgjc" :label="`旅馆检查二维码`" :wrapper-col="{ span: 22 }" :label-col="{ span: 2 }">
<a-image :width="200" :src="formState.inspectionQrCodePath" v-if="formState.inspectionQrCodePath!=''&&formState.inspectionQrCodePath!=null" />
<div style="width: 200px;height:200px;border:1px solid #a5a5a5" v-else>
</div>
<a-space :size="10" style="margin-left: 10px;">
<a-button size="large" v-if="is_edit&&formState.inspectionQrCodePath!=''&&formState.inspectionQrCodePath!=null" @click="delete_img(1)">
删除</a-button>
<a-upload name="file" @change="(file)=>handleChange(file,1)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择二维码
</a-button>
</a-upload>
</a-space>
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div>
<span class="sign">相关证书</span>
</div>
</div>
<div style="margin: 0px 25px" class="xgzs">
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.businessLicensePath" v-if="formState.businessLicensePath!=''&&formState.businessLicensePath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>营业执照</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.businessLicensePath!=''&&formState.businessLicensePath!=null" @click="delete_img(2)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,2)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.specialIndustryLicensePath" v-if="formState.specialIndustryLicensePath!=''&&formState.specialIndustryLicensePath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>特种行业许可证</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.specialIndustryLicensePath!=''&&formState.specialIndustryLicensePath!=null" @click="delete_img(3)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,3)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.fireSafetyCertificationPath" v-if="formState.fireSafetyCertificationPath!=''&&formState.fireSafetyCertificationPath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>消防验收合格证明文件</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.fireSafetyCertificationPath!=''&&formState.fireSafetyCertificationPath!=null" @click="delete_img(4)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,4)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.systemUsageNotificationPath" v-if="formState.systemUsageNotificationPath!=''&&formState.systemUsageNotificationPath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>系统使用告知书</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.systemUsageNotificationPath!=''&&formState.systemUsageNotificationPath!=null" @click="delete_img(5)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,5)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">房屋平面图纸</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.planPhotoPath?.length>0" v-for="item in formState?.planPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_plan_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_plan_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">结构图</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.structuralPhotoPath?.length>0" v-for="item in formState?.structuralPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_structural_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_structural_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">内部实景图</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.internalPhotoPath?.length>0" v-for="item in formState?.internalPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_internal_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_internal_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">外观图</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.appearancePhotoPath?.length>0" v-for="item in formState?.appearancePhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_appearance_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_appearance_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<a-modal :visible="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
<a-affix :offset-bottom="0">
<div class="titleBox" style="margin: 0px;">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit()" v-if="!is_edit"><template #icon>
</template>
编辑</a-button>
<a-button type="primary" size="large" @click="handleOk" v-if="is_edit"><template #icon>
</template>
保存</a-button>
<a-button size="large" v-if="is_edit" @click="qx()"><template #icon>
</template>
取消</a-button>
</a-space>
</div>
</div>
</a-affix>
</a-spin>
</div>
</template>
<script setup>
import { onMounted, ref, toRaw, watch } from "vue";
import requests from "@/utils/request_test";
import { file_img_src, dataURLtoFile, getImageFileFromUrl } from "@/utils/http_util.js";
import { message, Upload } from "ant-design-vue";
import { uploadImg } from "@/api/default.js";
import { useStore } from "@/store/index.js";
import { queryHotel, updateHotel, upLoadArrayImage, removeArrayImage } from '@/api/hotel.js'
import { forIn } from "lodash-es";
import default_img from '@/assets/img/default.png';
const props = defineProps({
visible: Boolean,
title: String,
datas: Object,
eyesEdit: Boolean,
});
const loading = ref(false);
const is_edit = ref(false);
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelCode: '',
name: '',
signboardName: '',
hotelManager: '',
telephone: '',
address: '',
updater: '',
});
const reset = () => {
inspectionQrCode.value = false;
businessLicense.value = false;
specialIndustryLicense.value = false;
fireSafetyCertification.value = false;
systemUsageNotification.value = false;
};
const inspectionQrCode = ref(false);
const businessLicense = ref(false);
const specialIndustryLicense = ref(false);
const fireSafetyCertification = ref(false);
const systemUsageNotification = ref(false);
/**选择图片 */
const handleChange = (info, type) => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
if (type == 1) {
// formState.inspectionQrCode = reader.result;
formState.inspectionQrCodePath = reader.result;
inspectionQrCode.value = true;
} else if (type == 2) {
// formState.businessLicense = reader.result;
formState.businessLicensePath = reader.result;
businessLicense.value = true;
} else if (type == 3) {
// formState.specialIndustryLicense = reader.result;
formState.specialIndustryLicensePath = reader.result;
specialIndustryLicense.value = true;
} else if (type == 4) {
// formState.fireSafetyCertification = reader.result;
formState.fireSafetyCertificationPath = reader.result;
fireSafetyCertification.value = true;
} else {
// formState.systemUsageNotification = reader.result;
formState.systemUsageNotificationPath = reader.result;
systemUsageNotification.value = true;
}
};
}
};
/**删除各类图片 */
const delete_img = (type) => {
if (type == 1) {
// formState.inspectionQrCode = '';
formState.inspectionQrCodePath = '';
inspectionQrCode.value = true;
} else if (type == 2) {
/**删除营业执照 */
// formState.businessLicense = '';
formState.businessLicensePath = '';
businessLicense.value = true;
} else if (type == 3) {
/**删除特种行业许可证 */
// formState.specialIndustryLicense = '';
formState.specialIndustryLicensePath = '';
specialIndustryLicense.value = true;
} else if (type == 4) {
/**删除消防验收合格证明文件 */
// formState.fireSafetyCertification = '';
formState.fireSafetyCertificationPath = '';
fireSafetyCertification.value = true;
} else {
/**删除系统使用告知书 */
// formState.systemUsageNotification = '';
formState.systemUsageNotificationPath = '';
systemUsageNotification.value = true;
}
}
/**多图片上传 */
const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');
const handleCancel = () => {
previewVisible.value = false;
previewTitle.value = '';
};
/**多图片的预览(未上传时的预览) */
const handlePreview = async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**多文件上传时选择文件,进行判断 */
const beforeUpload_arr = file => {
const isPNG = file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
return Upload.LIST_IGNORE
}
return false;
};
/**开启编辑 */
const edit = () => {
is_edit.value = true;
}
/** 取消 */
const qx = () => {
queryJBXX();
is_edit.value = false;
}
/**提交事件 */
const handleOk = () => {
// plan_photo_64();
/**多图片上传 */
let fd = new FormData();
fd.append("hotelId", userstore.hotelInfo.hotelId);
toRaw(fileList_plan_photo.value).forEach(item => {//判断平面图是否修改
fd.append("plan_photo", item.url ? item : item.originFileObj);
})
toRaw(fileList_structural_photo.value).forEach(item => {//判断结构图是否修改
fd.append("structural_photo", item.url ? item : item.originFileObj);
})
toRaw(fileList_internal_photo.value).forEach(item => {//判断内部实景图是否修改
fd.append("internal_photo", item.url ? item : item.originFileObj);
})
toRaw(fileList_appearance_photo.value).forEach(item => {//判断外观图是否修改
fd.append("appearance_photo", item.url ? item : item.originFileObj);
})
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (inspectionQrCode.value && formState.inspectionQrCodePath != '') {
arr_http.push(file_img_src(formState.inspectionQrCodePath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (businessLicense.value && formState.businessLicensePath != '') {
arr_http.push(file_img_src(formState.businessLicensePath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (specialIndustryLicense.value && formState.specialIndustryLicensePath != '') {
arr_http.push(file_img_src(formState.specialIndustryLicensePath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (fireSafetyCertification.value && formState.fireSafetyCertificationPath != '') {
arr_http.push(file_img_src(formState.fireSafetyCertificationPath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (systemUsageNotification.value && formState.systemUsageNotificationPath != '') {
arr_http.push(file_img_src(formState.systemUsageNotificationPath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
arr_http.push(upLoadArrayImage(fd));
/**单个删除相关证书和二维码 */
const arr_http_delete = [];
if (inspectionQrCode.value && formState.inspectionQrCode) {
arr_http_delete.push(formState.inspectionQrCode)
}
if (businessLicense.value && formState.businessLicense) {
arr_http_delete.push(formState.businessLicense)
}
if (specialIndustryLicense.value && formState.specialIndustryLicense) {
arr_http_delete.push(formState.specialIndustryLicense)
}
if (fireSafetyCertification.value && formState.fireSafetyCertification) {
arr_http_delete.push(formState.fireSafetyCertification)
}
if (systemUsageNotification.value && formState.systemUsageNotification) {
arr_http_delete.push(formState.systemUsageNotification)
}
// console.log(arr_http_delete)
// return
loading.value = true;
Promise.all(arr_http).then(([res1, res2, res3, res4, res5, res6]) => {
// let fds = new FormData();
// fds.append("bucket", 'HOTEL');
// fds.append("hotelId", userstore.hotelInfo.hotelId);
// fds.append("filenames", arr_http_delete);
removeArrayImage({ bucket: 'HOTEL', hotelId: userstore.hotelInfo.hotelId, filenames: arr_http_delete }).then(a => {
console.log('删除成功');
})
const arr = { ...formState };
if (inspectionQrCode.value) {
arr.inspectionQrCode = res1;
}
if (businessLicense.value) {
arr.businessLicense = res2;
}
if (specialIndustryLicense.value) {
arr.specialIndustryLicense = res3;
}
if (fireSafetyCertification.value) {
arr.fireSafetyCertification = res4;
}
if (systemUsageNotification.value) {
arr.systemUsageNotification = res5;
}
// arr.inspectionQrCodePath = '';
// arr.businessLicensePath = '';
// arr.specialIndustryLicensePath = '';
// arr.fireSafetyCertificationPath = '';
// arr.systemUsageNotificationPath = '';
delete arr.inspectionQrCodePath;
delete arr.businessLicensePath;
delete arr.specialIndustryLicensePath;
delete arr.fireSafetyCertificationPath;
delete arr.systemUsageNotificationPath;
updateHotel(arr).then(res => {
if (res?.code == 9000) {
message.success('修改成功');
queryJBXX();
reset();
is_edit.value = false;
}
loading.value = false;
}).catch(error => {
message.warning('修改失败')
loading.value = false;
})
});
});
};
const setValue = (values) => {
forIn(values, (value, key) => (formState[key] = value));
};
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
/**旅馆基本信息查询 */
const queryJBXX = async () => {
loading.value = true;
queryHotel({ hotelId: userstore.hotelInfo.hotelId }).then(res => {
if (res?.code == 9000) {
setValue(res.data);
fileList_plan_photo.value = [];
if (res.data.planPhotoPath.length > 0) {
res.data.planPhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_plan_photo.value.push(e);
})
})
}
fileList_structural_photo.value = [];
if (res.data.structuralPhotoPath.length > 0) {
res.data.structuralPhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_structural_photo.value.push(e);
})
})
}
fileList_internal_photo.value = [];
if (res.data.internalPhotoPath.length > 0) {
res.data.internalPhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_internal_photo.value.push(e);
})
})
}
fileList_appearance_photo.value = [];
if (res.data.appearancePhotoPath.length > 0) {
res.data.appearancePhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_appearance_photo.value.push(e);
})
})
}
// /**将当前5个单传图片转为file文件 */
// if (res.data.inspectionQrCode != '' || res.data.inspectionQrCode != null) {//二维码
// getImageFileFromUrl(res.data.inspectionQrCodePath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// inspectionQrCode_file.value = es;
// });
// })
// }
// if (res.data.businessLicensePath != '' || res.data.businessLicensePath != null) {//营业执照
// getImageFileFromUrl(res.data.businessLicensePath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// businessLicense_file.value = es;
// });
// })
// }
// if (res.data.specialIndustryLicensePath != '' || res.data.specialIndustryLicensePath != null) {//特种行业许可证
// getImageFileFromUrl(res.data.specialIndustryLicensePath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// specialIndustryLicense_file.value = es;
// });
// })
// }
// if (res.data.fireSafetyCertificationPath != '' || res.data.fireSafetyCertificationPath != null) {//消防验收合格证明文件
// getImageFileFromUrl(res.data.fireSafetyCertificationPath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// fireSafetyCertification_file.value = es;
// });
// })
// }
// if (res.data.systemUsageNotificationPath != '' || res.data.systemUsageNotificationPath != null) {//系统使用告知书
// getImageFileFromUrl(res.data.systemUsageNotificationPath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// systemUsageNotification_file.value = es;
// });
// })
// }
}
loading.value = false;
}).catch(error => {
loading.value = false;
})
}
/**5个单传图片 */
const inspectionQrCode_file = ref('');
const businessLicense_file = ref('');
const specialIndustryLicense_file = ref('');
const fireSafetyCertification_file = ref('');
const systemUsageNotification_file = ref('');
onMounted(() => {
queryJBXX();
});
/**判断plan_photo 平面图*/
const fileList_plan_photo = ref([]);//获取平面图的文件
const file_64_plan_photo = ref([]);//获取修改后的文件转为64位
// const plan_photo_64 = () => {
// file_64_plan_photo.value = [];
// fileList_plan_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_plan_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// // fileList_plan_photo.value.map(item => {
// // const reader = new FileReader();
// // reader.readAsDataURL(toRaw(item).originFileObj);
// // reader.onload = () => {
// // file_64_plan_photo.value.push(dataURLtoFile(reader.result, Date.parse(new Date()) + ".png"));
// // };
// // })
// }
/**判断structural_photo 结构图*/
const fileList_structural_photo = ref([]);//获取平面图的文件
const file_64_structural_photo = ref([]);//获取修改后的文件转为64位
// const structural_photo_64 = () => {
// file_64_structural_photo.value = [];
// fileList_structural_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_structural_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// }
/**判断internal_photo 内部实景图*/
const fileList_internal_photo = ref([]);//获取平面图的文件
const file_64_internal_photo = ref([]);//获取修改后的文件转为64位
// const internal_photo_64 = () => {
// file_64_internal_photo.value = [];
// fileList_internal_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_internal_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// }
/**判断appearance_photo 外观图*/
const fileList_appearance_photo = ref([]);//获取平面图的文件
const file_64_appearance_photo = ref([]);//获取修改后的文件转为64位
// const appearance_photo_64 = () => {
// file_64_appearance_photo.value = [];
// fileList_appearance_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_appearance_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// }
</script>
<style lang="less">
.hotelEdit {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
.lgjc {
.ant-form-item-label {
display: flex;
align-items: center;
justify-content: flex-end;
}
.ant-form-item-control {
margin: 20px 0px;
}
.ant-form-item-control-input-content {
display: flex;
}
}
}
.xgzs {
display: flex;
justify-content: space-evenly;
.img-xgzs {
.img-div {
// border-image-source: radial-gradient(
// 60% 60%,
// transparent 0px,
// transparent 100%,
// #6691ef 100%
// );
// border-image-slice: 1;
// border-width: 1px;
// border-style: solid;
// border-image-outset: 0px;
// width: calc(100% - 40px);
// height: calc(100% - 40px);
border: 1px solid #a5a5a5;
padding: 5px;
width: 200px;
height: 200px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
.span-div {
line-height: 50px;
text-align: center;
font-weight: 600;
letter-spacing: 2px;
}
}
}
.ant-upload-list {
display: flex;
justify-content: center;
}
.ant-image-img {
object-fit: contain;
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="main">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">旅馆基本信息</span>
</div>
</div>
<div style="margin: 0px 5px">
<a-descriptions title="" bordered size="small">
<a-descriptions-item label="旅馆代码:">{{ dataInfo?.hotelCode }}</a-descriptions-item>
<a-descriptions-item label="旅馆名称:">{{ dataInfo?.name }}</a-descriptions-item>
<a-descriptions-item label="旅馆招牌名称:">{{ dataInfo?.signboardName }}</a-descriptions-item>
<a-descriptions-item label="旅馆负责人:">{{ dataInfo?.hotelManager }}</a-descriptions-item>
<a-descriptions-item label="联系电话:" :span="2">{{ dataInfo?.telephone }}</a-descriptions-item>
<a-descriptions-item label="地址:" :span="3">{{ dataInfo?.address }}</a-descriptions-item>
<a-descriptions-item label="旅馆房间数:">{{ data_statistics?.hotelRooms }}</a-descriptions-item>
<a-descriptions-item label="入住房间数:">{{ data_statistics?.numberOfRoomsOccupied }}</a-descriptions-item>
<a-descriptions-item label="房屋入住率:">
<a-progress :stroke-color="{
'0%': '#108ee9',
'100%': '#87d068',
}" :percent="data_statistics?.occupancyRate?.toFixed(2)" />
</a-descriptions-item>
<a-descriptions-item label="入住旅客数:"> {{ data_statistics?.numberOfOccupants }}</a-descriptions-item>
<a-descriptions-item label="内宾数:">{{ data_statistics?.numberOfDomesticGuests }} </a-descriptions-item>
<a-descriptions-item label="外宾数:">{{ data_statistics?.numberOfForeignGuests }} </a-descriptions-item>
<a-descriptions-item label="旅馆检查二维码:">
<a-image :width="200" :src="dataInfo?.inspectionQrCodePath" v-if="dataInfo?.inspectionQrCodePath" />
</a-descriptions-item>
</a-descriptions>
</div>
<div class="titleBox">
<div>
<span class="sign">相关证书照片</span>
</div>
</div>
<div class="zp-class">
<a-image-preview-group>
<div class="xgzs">
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.businessLicensePath" v-if="dataInfo?.businessLicensePath"/>
</div>
<div class="span-div">
<span>营业执照</span>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.specialIndustryLicensePath" v-if="dataInfo?.specialIndustryLicensePath"/>
</div>
<div class="span-div">
<span>特种行业许可证</span>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.fireSafetyCertificationPath" v-if="dataInfo?.fireSafetyCertificationPath"/>
</div>
<div class="span-div">
<span>消防验收合格证明文件</span>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.systemUsageNotificationPath" v-if="dataInfo?.systemUsageNotificationPath"/>
</div>
<div class="span-div">
<span>系统使用告知书</span>
</div>
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">平面图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.planPhotoPath?.length>0" v-for="item in dataInfo?.planPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">结构图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.structuralPhotoPath?.length>0" v-for="item in dataInfo?.structuralPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">内部实景图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.internalPhotoPath?.length>0" v-for="item in dataInfo?.internalPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">外观图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.appearancePhotoPath?.length>0" v-for="item in dataInfo?.appearancePhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
</a-spin>
</div>
</template>
<script setup>
import { onMounted } from "vue";
import { useStore } from "@/store/index.js";
import { queryHotel } from '@/api/hotel.js'
import { forIn } from "lodash-es";
import { queryRoomStatus } from '@/api/room.js';
const userstore = useStore();
const dataInfo = ref({});
const data_statistics = ref({});
const loading = ref(false);
/**旅馆基本信息查询 */
const queryHotels = () => {
return new Promise((resolve) => {
queryHotel({ hotelId: userstore.hotelInfo.hotelId }).then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
}
/**旅馆统计列表 */
const hotelStatistics = () => {
return new Promise((resolve) => {
queryRoomStatus({ hotelId: userstore.hotelInfo.hotelId }).then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
}
/**查询 */
const query = () => {
loading.value = true;
Promise.all([queryHotels(), hotelStatistics()]).then(([res1, res2]) => {
dataInfo.value = res1;
console.log(res1)
data_statistics.value = res2;
loading.value = false;
}).catch(error=>{
loading.value = false;
})
}
onMounted(() => {
query();
});
</script>
<style lang="less" scoped>
.main {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
:deep(.ant-descriptions-bordered .ant-descriptions-item-label) {
text-align: right;
width: 140px;
color: #0e5de5;
font-weight: 600;
}
:deep(.ant-descriptions-bordered .ant-descriptions-item-content) {
font-weight: 600;
color: #434343;
width: 200px;
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
.zp-class {
margin: 0px 5px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
.xgzs {
display: flex;
justify-content: space-evenly;
width: 100%;
.img-xgzs {
.img-div {
border: 1px solid #a5a5a5;
padding: 5px;
width: 200px;
height: 200px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
.span-div {
line-height: 50px;
text-align: center;
font-weight: 600;
letter-spacing: 2px;
}
}
}
}
:deep(.ant-image-img) {
object-fit: contain;
}
}
</style>
\ No newline at end of file
<template>
<div class="inland">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">内宾登记信息列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="isVerification" label="是否核验">
<a-select v-model:value="formState.isVerification" placeholder="请选择" :allowClear="true">
<a-select-option value="1"></a-select-option>
<a-select-option value="0"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="gender" label="性别">
<a-select v-model:value="formState.gender" placeholder="请选择性别" :allowClear="true" :options="options_gender" optionLabelProp="name" show-search :filter-option="filterOption" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="nation" label="民族">
<a-select show-search v-model:value="formState.nation" :filter-option="filterOption" placeholder="请选择民族" :allowClear="true" optionLabelProp="name" :options="options_nation" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="出生日期">
<a-range-picker v-model:value="csrq" @change="(data, dateString) => handleChangeTime(data, dateString, 1)" />
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item name="provincialUrbanAreas" label="户籍地省市县(区)">
<a-select show-search v-model:value="formState.provincialUrbanAreas" :filter-option="filterOption" placeholder="请选择户籍地" :allowClear="true" optionLabelProp="name" :options="options_provincialUrbanAreas" :fieldNames="{ label: 'name', value: 'code' }">
<template #option="{ name, code }">
{{ name }}&nbsp;&nbsp;{{ "[" + code + "]" }}
</template>
</a-select>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="入住时间">
<a-range-picker v-model:value="rzsj" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 2)" />
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="离店时间">
<a-range-picker v-model:value="ldsj" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 3)" />
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="state" label="旅客状态">
<a-select show-search v-model:value="formState.state" :filter-option="filterOption" placeholder="请选择旅客状态" :allowClear="true" :options="options_state" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="roomId" label="房间号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="options_room" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</a-col>
<a-col>
<a-button type="primary" @click="queryList()">查询</a-button>
<a-button style="margin: 0 8px" @click="qx()">清除</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_abroad" :rowKey="item=>JSON.stringify(item.id)" :columns="columns" :data-source="data" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eyes(index, record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color: #faad14" @click="edits(index, record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm v-if="record.state === 'ARRIVE'" title="是否离店" @confirm="setState(index, record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
<a-button type="link" primary size="small" @click="visitorJump(record)">
<template #icon>
<contacts-filled />
</template>
访客登记
</a-button>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" show-quick-jumper show-size-changer :total="total" v-show="data.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange" style="margin: 20px 0px" />
</div>
</a-spin>
<InlandEyes v-if="hotelFormVisible" :visible="hotelFormVisible" :id="info_id" :title="titles" @change-Cancel="changeCancel" @change-Edit="changeEdit" :visibleEdit="hotelFormVisible_edit_s" />
<InlandEdit v-if="hotelFormVisible_edit" :visible="hotelFormVisible_edit" :eyesEdit="hotelFormVisible_eyes_edit" :datas="data_edit" :title="title_edit" @change-Cancel="changeCancel_edit" @change-Data="changeData" />
</div>
</template>
<script setup>
import { onMounted, reactive, ref, watch, toRaw } from "vue";
import {
inlandQuery,
inlandGender,
inlandCheckOut,
} from "@/api/domesticGuestCheckIn";
import { useStore } from "@/store/index.js";
import InlandEdit from "@/views/inland/inlandEdit.vue";
import InlandEyes from "@/views/inland/inlandEyes.vue";
import { message } from "ant-design-vue";
import router from "../../router";
const userstore = useStore();
const loading = ref(false);
const formRef = ref();
const formState = reactive({
name: "",
gender: "",
nation: "",
dateBirthEnd: "",
dateBirthStart: "",
provincialUrbanAreas: "",
checkinTimeEnd: "",
checkinTimeStart: "",
departureTimeEnd: "",
departureTimeStart: "",
state: "",
roomId: "",
hotelId: userstore.hotelInfo.hotelId, //旅馆id
current: 1,
pageSize: 10,
isVerification: ''
});
const hotelFormVisible = ref(false);
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
{
title: "姓名",
dataIndex: "name",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "民族",
dataIndex: "nationName",
},
{
title: "户籍地省市县区",
dataIndex: "provincialUrbanAreasName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离店时间",
dataIndex: "departureTime",
},
{
title: "旅客状态",
dataIndex: "stateName",
},
{
title: "是否核验",
dataIndex: "isVerification",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data = ref([]);
const selectedRowKeys_abroad = ref([]);/**当前选中集合 */
const rowSelection_abroad = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_abroad.value = selectedRowKeys;
},
}
/**时间变化 */
const handleChangeTime = (data, dataArr, type) => {
if (dataArr && dataArr.length > 0) {
if (type == 1) {
formState.dateBirthEnd = dataArr[1];
formState.dateBirthStart = dataArr[0];
} else if (type == 2) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.departureTimeEnd = dataArr[1];
formState.departureTimeStart = dataArr[0];
}
} else {
if (type == 1) {
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
} else if (type == 2) {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
} else {
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
}
};
/**分页 */
const total = ref(0);
/**分页切换 */
const onChange = (page, pageSize) => {
formState.current = page;
formState.pageSize = pageSize;
queryList();
};
/**查看 */
const info_id = ref({});
const titles = ref("查看内宾详情");
const changeCancel = () => {
hotelFormVisible.value = false;
};
const hotelFormVisible_edit_s = ref(false);
const indexs = ref(0);
const eyes = (index, e) => {
indexs.value = index;
info_id.value = e.id;
hotelFormVisible.value = true;
hotelFormVisible_edit_s.value = true;
};
const changeEdit = (e) => {
hotelFormVisible_eyes_edit.value = true;
hotelFormVisible.value = false;
hotelFormVisible_edit.value = true;
data_edit.value = e.value;
};
/**出生日期 */
const csrq = ref(undefined);
const rzsj = ref(undefined);
const ldsj = ref(undefined);
/**清除 */
const qx = () => {
formRef.value.resetFields();
csrq.value = undefined;
rzsj.value = undefined;
ldsj.value = undefined;
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
/**修改内宾 */
const edits = (index, e) => {
indexs.value = index;
data_edit.value = e;
hotelFormVisible_eyes_edit.value = false;
hotelFormVisible_edit.value = true;
};
const hotelFormVisible_edit = ref(false);
const hotelFormVisible_eyes_edit = ref(false);
/**判断是从查看界面进入还是直接编辑 */
const data_edit = ref({});
const title_edit = ref("修改内宾");
const changeCancel_edit = (e) => {
if (toRaw(e)) {
hotelFormVisible.value = true;
}
hotelFormVisible_edit.value = false;
};
const changeData = (e) => {
queryList();
eyes(indexs.value, e);
};
/**离店 */
// const cancel_ld = (e) => {
// message.error("操作已取消!!!");
// };
const setState = async (index, record) => {
loading.value = true;
await inlandCheckOut([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
queryList();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
};
/**分页查询 */
const queryList = async () => {
loading.value = true;
await inlandQuery(formState)
.then((res) => {
if (res?.code == 9000) {
data.value = res.data.records;
total.value = res.data.total;
}
loading.value = false;
})
.catch((res) => {
loading.value = false;
});
};
/**访客登记跳转 */
const visitorJump = (record) => {
// if(record.roomId==''||record.roomId==undefined){
// message.warning('该旅馆暂未入住')
// }
router.push({ path: '/visitor/visitorAdd', query: { roomId: record.roomId, name: record.name } });
}
/**字典表查询---性别*/
const options_room = ref(userstore.roomAll); //房间字典
const options_gender = ref(userstore.returnCode(5)); //性别
const options_nation = ref(userstore.returnCode(10)); //民族
const options_state = ref(userstore.returnCode(2)); //民族
const options_provincialUrbanAreas = ref(userstore.returnCode(11)); //省市县区
onMounted(() => {
// gender();
queryList();
});
</script>
<style lang="less">
.inland {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
overflow-y: auto;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="loading">
<div class="inlandFrom">
<div class="titleBox">
<div>
<span class="sign">内宾登记表</span>
</div>
</div>
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`" :rules="{
required: true,
message: '请选择房间号',
}">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" :options="options_room" placeholder="请选择房间号" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker show-time placeholder="请选择时间" v-model:value="formState.checkinTime" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div style="
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
">
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.certificatePhoto == ''">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhoto" v-else />
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhoto == ''">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhoto" v-else />
</div>
<div class="check-div" style="text-align: center;" @click="OnCamera()">
<a-button type="primary">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`" :rules="{
required: true,
message: '请选择证件类型',
}">
<a-select show-search v-model:value="formState.certificateType" :filter-option="filterOption" :options="options_certificateType" placeholder="请选择证件类型" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="name" :label="`姓名`" :rules="{
required: true,
message: '请输入姓名',
}">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="gender" :label="`性别`" :rules="{
required: true,
message: '请选择性别',
}">
<a-select show-search v-model:value="formState.gender" :filter-option="filterOption" :options="options_gender" placeholder="请选择性别" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="dateBirth" :label="`出生日期`" :rules="{
required: true,
message: '请选择出生日期',
}">
<a-date-picker placeholder="请选择出生日期" :disabled-date="disabledDateMax" v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" style="width: 100%" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="nation" :label="`民族`" :rules="{
required: true,
message: '请选择民族',
}">
<a-select show-search v-model:value="formState.nation" :filter-option="filterOption" :options="options_nation" placeholder="请选择民族" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="provincialUrbanAreas" :label="`省市县区`" :rules="{
required: true,
message: '请选择省市县区',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.provincialUrbanAreas" :filter-option="filterOptions" :options="options_provincialUrbanAreas" placeholder="请选择省市县区" :allowClear="true" :fieldNames="{ label: 'name', value: 'code' }">
<template #option="{ name, code }">
{{ name }}&nbsp;&nbsp;{{ "[" + code + "]" }}
</template>
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="address" :label="`住址`" :rules="{
required: true,
message: '请输入住址',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.address" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="plateNumber" :label="`车牌号`" :rules="[
{ pattern:new RegExp('([A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})'),message:'输入有效车牌号'}]">
<a-input-group compact>
<a-form-item style="width: 20%" name="plateProvince">
<a-select show-search v-model:value="formState.plateProvince" :filter-option="filterOption" :options="options_plate_province" placeholder="请选择省份" :allowClear="true" optionLabelProp="name" style="width: 100%" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
<a-input v-model:value="formState.plateNumber" style="width: 80%" />
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="teamId" :label="`所属团队`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.teamId" :filter-option="filterOption" :options="options_team" placeholder="请选择所属团队" :allowClear="true" optionLabelProp="name">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="handle_ID_reading()">读取证件</a-button>
<!-- <a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
读取证件
<DownOutlined />
</a-button>
</a-dropdown> -->
<a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
扫一扫
<DownOutlined />
</a-button>
</a-dropdown>
<!-- style="background-color: #faad14;color:white" -->
<a-button type="primary" size="large">扫描证件</a-button>
<a-button size="large">人证核验</a-button>
<a-button type="primary" size="large" @click="handleOk"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="reset()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
</template>
<script setup>
import Camera from "@/components/Camera.vue";
import Cropper from "@/components/Cropper.vue";
import { onMounted, ref, toRaw, watch } from "vue";
import requests from "@/utils/request_test";
import { inlandAdd } from "@/api/domesticGuestCheckIn";
// import { provincialUrbanAreas } from "@/utils/provincialUrbanAreas";
import { validateIdNo } from "@/utils/validates.js"
import { file_img_src } from "@/utils/http_util.js";
import { message } from "ant-design-vue";
import { uploadImg } from "@/api/default.js";
import { useStore } from "@/store/index.js";
import dayjs from 'dayjs';
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId, //旅馆id
roomId: "",
checkinTime: "",
certificateType: "",
certificateNumber: "",
name: "",
gender: "",
dateBirth: "",
nation: "",
provincialUrbanAreas: "",
address: "",
phoneNumber: "",
plateProvince: "",
plateNumber: "",
remark: "",
certificatePhoto: "", //证件照片
sitePhoto: "", //现场照片
state: "ARRIVE",
creator: userstore.userInfo.username,
});
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
const loading = ref(false);
/**摄像头调用 */
const hotelFormVisible = ref(false);
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
formState.sitePhoto = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**设置最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (formState.sitePhoto != "") {
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
if (formState.certificatePhoto != "") {
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (formState.sitePhoto != "") {
arr.sitePhoto = res1;
}
if (formState.certificatePhoto != "") {
arr.certificatePhoto = res2;
}
inlandAdd(arr)
.then((res) => {
if (res.code == 9000) {
message.success("入住成功");
reset();
}
loading.value = false;
})
.catch((res) => {
message.warning("入住失败");
loading.value = false;
});
});
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
// await emit("changeform", false);
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const filterOptions = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0 || option.code.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleMenuClick = (e) => {
console.log("click", e);
};
/**字典表查询 */
const options_room = ref(userstore.roomAll); //房间字典
const options_certificateType = ref(userstore.returnCode(3)); //证件类型
const options_gender = ref(userstore.returnCode(5)); //性别
const options_nation = ref(userstore.returnCode(10)); //民族
const options_provincialUrbanAreas = ref(userstore.returnCode(11)); //省市县区
const options_plate_province = ref(userstore.returnCode(6)); //全省信息
const options_team = ref([]); //旅游团队
onMounted(() => { });
const handle_ID_reading = () => {
loading.value = true;
requests({
url: "/dev",
method: "GET",
})
.then((res) => {
loading.value = false;
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
}
})
.catch((res) => {
message.warning(res);
loading.value = false;
});
};
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
</script>
<style lang="less">
.inlandFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y:auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="inlandFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`" :rules="{
required: true,
message: '请选择房间号',
}">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" :options="options_room" placeholder="请选择房间号" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker show-time placeholder="请选择时间" v-model:value="formState.checkinTime" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div style="
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
">
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="
formState.certificatePhotoPath == '' ||
formState.certificatePhotoPath == null
">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhotoPath" v-else />
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="
formState.sitePhotoPath == '' ||
formState.sitePhotoPath == null
">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhotoPath" v-else />
</div>
<div class="check-div" style="text-align: center" @click="OnCamera()">
<a-button type="primary">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`" :rules="{
required: true,
message: '请选择证件类型',
}">
<a-select show-search v-model:value="formState.certificateType" :filter-option="filterOption" :options="options_certificateType" placeholder="请选择证件类型" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="name" :label="`姓名`" :rules="{
required: true,
message: '请输入姓名',
}">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="gender" :label="`性别`" :rules="{
required: true,
message: '请选择性别',
}">
<a-select show-search v-model:value="formState.gender" :filter-option="filterOption" :options="options_gender" placeholder="请选择性别" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="dateBirth" :label="`出生日期`" :rules="{
required: true,
message: '请选择出生日期',
}">
<a-date-picker placeholder="请选择出生日期" :disabled-date="disabledDateMax" v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" style="width: 100%" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="nation" :label="`民族`" :rules="{
required: true,
message: '请选择民族',
}">
<a-select show-search v-model:value="formState.nation" :filter-option="filterOption" :options="options_nation" placeholder="请选择民族" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="provincialUrbanAreas" :label="`省市县区`" :rules="{
required: true,
message: '请选择省市县区',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.provincialUrbanAreas" :filter-option="filterOptions" :options="options_provincialUrbanAreas" placeholder="请选择省市县区" :allowClear="true" :fieldNames="{ label: 'name', value: 'code' }">
<template #option="{ name, code }">
{{ name }}&nbsp;&nbsp;{{ "[" + code + "]" }}
</template>
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="address" :label="`住址`" :rules="{
required: true,
message: '请输入住址',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.address" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="plateNumber" :label="`车牌号`" :rules="[
{ pattern:new RegExp('([A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})'),message:'输入有效车牌号'}]">
<a-input-group compact>
<a-form-item style="width: 20%" name="plateProvince">
<a-select show-search v-model:value="formState.plateProvince" :filter-option="filterOption" :options="options_plate_province" placeholder="请选择省份" :allowClear="true" optionLabelProp="name" style="width: 100%" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
<a-input v-model:value="formState.plateNumber" style="width: 80%" />
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="teamId" :label="`所属团队`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.teamId" :filter-option="filterOption" :options="options_team" placeholder="请选择所属团队" :allowClear="true" optionLabelProp="name">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="handle_ID_reading()">读取证件</a-button>
<!-- <a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
读取证件
<DownOutlined />
</a-button>
</a-dropdown> -->
<a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
扫一扫
<DownOutlined />
</a-button>
</a-dropdown>
<!-- style="background-color: #faad14;color:white" -->
<a-button type="primary" size="large">扫描证件</a-button>
<a-button size="large">人证核验</a-button>
<a-button type="primary" size="large" @click="handleOk"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="handleCancel()"> 取消</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import Camera from "@/components/Camera.vue";
import Cropper from "@/components/Cropper.vue";
import { onMounted, ref, toRaw, watch } from "vue";
import requests from "@/utils/request_test";
import { inlandEdit,inlandQueryOne } from "@/api/domesticGuestCheckIn";
// import { provincialUrbanAreas } from "@/utils/provincialUrbanAreas";
import { file_img_src } from "@/utils/http_util.js";
import { message } from "ant-design-vue";
import { uploadImg } from "@/api/default.js";
import { useStore } from "@/store/index.js";
import { forIn } from "lodash-es";
import dayjs from 'dayjs';
const props = defineProps({
visible: Boolean,
title: String,
datas: Object,
eyesEdit: Boolean,
});
const loading = ref(false);
const userstore = useStore();
const formRef = ref();
const formState = reactive({});
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
sitePhotos.value = true;
formState.sitePhoto = e.value;
formState.sitePhotoPath = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png'||info.file.type === 'image/jpg'||info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
}else{
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
formState.sitePhotoPath = reader.result;
sitePhotos.value = true;
};
}
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (sitePhotos.value) {
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
if (certificatePhotos.value) {
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (sitePhotos.value) {
arr.sitePhoto = res1;
}
if (certificatePhotos.value) {
arr.certificatePhoto = res2;
}
arr.updater = userstore.userInfo.username;
inlandEdit(arr)
.then((res) => {
if (res.code == 9000) {
message.success("已保存");
emit("changeData", formState);
handleCancel();
}
loading.value = false;
})
.catch((res) => {
message.warning("保存失败");
loading.value = false;
});
});
});
};
const emit = defineEmits(["changeCancel", "changeData"]);
/**关闭弹框事件 */
const handleCancel = async () => {
sitePhotos.value = false;
certificatePhotos.value = false;
await emit("changeCancel", props.eyesEdit);
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const filterOptions = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0||option.code.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleMenuClick = (e) => {
console.log("click", e);
};
/**字典表查询 */
const options_room = ref(userstore.roomAll); //房间字典
const options_certificateType = ref(userstore.returnCode(3)); //证件类型
const options_gender = ref(userstore.returnCode(5)); //性别
const options_nation = ref(userstore.returnCode(10)); //民族
const options_provincialUrbanAreas = ref(userstore.returnCode(11)); //省市县区
const options_plate_province = ref(userstore.returnCode(6)); //全省信息
const options_team = ref([]); //旅游团队
const setValue = (values) => {
forIn(values, (value, key) => (formState[key] = value));
};
onMounted(() => {
setValue(props?.datas);
queryList({ id: props?.datas.id });
});
const queryList = async (params) => {
loading.value = true;
await inlandQueryOne(params)
.then((res) => {
if (res?.code == 9000) {
setValue(res.data);
}
loading.value = false;
})
.catch((res) => {
loading.value = false;
});
};
const handle_ID_reading = () => {
requests({
url: "/dev",
method: "GET",
})
.then((res) => {
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
formState.certificatePhotoPath =
"data:image/png;base64," + res.data.profilephoto;
certificatePhotos.value = true;
}
})
.catch((res) => {
message.warning(res);
});
};
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
/**判断现场照片修改 */
const sitePhotos = ref(false);
/**判断证件照 */
const certificatePhotos = ref(false);
</script>
<style lang="less">
.inlandFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="inlandEyes">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 10 }" :wrapper-col="{ span: 14 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="2" class="td1">
<span>证件类型:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.certificateTypeName }}</span>
</td>
<td colspan="2" class="td1">证件号码:</td>
<td colspan="2" class="td2">
<span>{{ data?.certificateNumber }}</span>
</td>
<td colspan="3" rowspan="11">
<div style="
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
">
<div class="img-wp">
<div class="img-div">
<a-image width="100%" height="100%" :src="
data?.certificatePhotoPath == null
? ''
: data?.certificatePhotoPath
" :fallback="default_img" />
</div>
<div class="img-span">
<span>证件人像</span>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>姓名:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.name }}</span>
</td>
<td colspan="2" class="td1"><span>性别: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.genderName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>民族:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.nationName }}</span>
</td>
<td colspan="2" class="td1"><span>出生日期: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.dateBirth }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>户籍地省市县区:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.provincialUrbanAreasName }}</span>
</td>
<td colspan="2" class="td1"><span>住址: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.address }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>联系电话:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.phoneNumber }}</span>
</td>
<td colspan="2" class="td1"><span>车牌号: </span></td>
<td colspan="2" class="td2">
<span>{{
data?.plateProvinceName != null && data?.plateNumber != null
? data?.plateProvinceName + "-" + data?.plateNumber
: ""
}}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>所属团队:</span>
</td>
<td colspan="6" class="td2">
<span>{{ data?.teamName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>房间号:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.roomName }}</span>
</td>
<!-- <td colspan="4" v-show="update">
<a-form-item
name="roomId"
:label="`房间号`"
:rules="{
required: true,
message: '请选择房间号',
}"
>
<a-select
show-search
v-model:value="formState.roomId"
:filter-option="filterOption"
:options="options_room"
placeholder="请选择房间号"
:allowClear="true"
optionLabelProp="name"
:fieldNames="{ label: 'name', value: 'id' }"
>
</a-select>
</a-form-item>
</td> -->
<td colspan="2" class="td1"><span>旅客状态: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.stateName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>入住时间:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.checkinTime }}</span>
</td>
<td colspan="2" class="td1"><span>离店时间: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.departureTime }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>登记时间:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.createTime }}</span>
</td>
<td colspan="2" class="td1"><span>修改时间: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.updateTime }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>登记人:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.creatorName }}</span>
</td>
<td colspan="2" class="td1"><span>修改人:</span></td>
<td colspan="2" class="td2">
<span>{{ data?.updaterName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>是否未成年人:</span>
</td>
<td colspan="2" class="td2">
<span :style="{ color: data?.minority == 0 ? '' : 'red' }">{{
data?.minority == 0 ? "成年" : "未成年"
}}</span>
</td>
<td colspan="2" class="td1"><span>备注:</span></td>
<td colspan="2" class="td2">
<span>{{ data?.remark }}</span>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox" v-if="visibleEdit">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button size="large" type="primary" @click="edit()"><template #icon> <edit-filled /> </template>编辑</a-button>
<a-button size="large" type="primary">人证核验</a-button>
<a-button size="large">打印登记单</a-button>
</a-space>
</div>
</div>
</div>
</a-spin>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { EditFilled } from "@ant-design/icons-vue";
import { onMounted, watch } from "vue";
import { useStore } from "@/store/index.js";
import { forIn } from "lodash-es";
import { inlandQueryOne } from "@/api/domesticGuestCheckIn";
import default_img from '@/assets/img/default.png';
const userstore = useStore();
const props = defineProps({
visible: Boolean,
id: {},
title: String,
visibleEdit: Boolean,
});
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId, //旅馆id
roomId: "",
checkinTime: "",
certificateType: "",
certificateNumber: "",
name: "",
gender: "",
dateBirth: "",
nation: "",
provincialUrbanAreas: "",
address: "",
phoneNumber: "",
plateProvince: "",
plateNumber: "",
teamId: "",
remark: "",
});
const emit = defineEmits(["changeCancel", "changeEdit"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const data = ref({});
onMounted(() => {
queryList({ id: props?.id });
});
const loading = ref(false);
const queryList = async (params) => {
loading.value = true;
await inlandQueryOne(params)
.then((res) => {
if (res?.code == 9000) {
data.value = res.data;
}
loading.value = false;
})
.catch((res) => {
loading.value = false;
});
};
const edit = async () => {
await emit("changeEdit", data);
};
</script>
<style lang="less">
.inlandEyes {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 40px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
width: 110px;
.img-wp {
width: 186.829px;
height: 230px;
// border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
}
.img-span {
text-align: center;
color: orange;
font-weight: 400;
font-size: 15px;
}
}
}
.td1 {
font-weight: 600;
font-size: 13px;
text-align: right;
padding: 0px 20px;
color: #007cef;
letter-spacing: 2px;
}
.td2 {
text-align: left;
padding: 0px 20px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="login">
<div class="login-content">
<div class="left-content"> </div>
<div class="right-content">
<div class="login-form">
<div class="login-img">
<img :src="logoImg" alt="">
</div>
<h2>旅馆业治安管理信息系统</h2>
<p>系统的实施对于促进旅游业的发展,维护公众安全、保障人民群众生命财产安全具有重要作用。</p>
<a-form ref="formRef" :model="formState" :rules="rules">
<a-form-item name="department">
<a-tree-select v-model:value="formState.department" size="large" v-model:searchValue="searchValue" show-search style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="请选择派出所" allow-clear tree-default-expand-all :tree-data="treeData" tree-node-filter-prop="label">
<template #title="{ value: val, label }">
<b v-if="val === 'parent 1-1'" style="color: #08c">sss</b>
<template v-else>
<template v-for="(fragment, i) in label.toString().split(new RegExp(`(?<=${searchValue})|(?=${searchValue})`, 'i'))">
<span v-if="fragment.toLowerCase() === searchValue.toLowerCase()" :key="i" style="color: #08c">
{{ fragment }}
</span>
<template v-else>{{ fragment }}</template>
</template>
</template>
</template>
</a-tree-select>
</a-form-item>
<a-form-item name="hotel">
<a-spin :spinning="loading">
<a-select v-model:value="formState.hotel" show-search placeholder="请选择旅馆" :options="hotelList" size="large" :filter-option="filterOption" @change="handleChange" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-spin>
</a-form-item>
<a-form-item ref="username" name="username">
<a-input v-model:value="formState.username" placeholder="请输入您的用户名" size="large">
<template #prefix>
<UserOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="password" name="password">
<a-input-password v-model:value="formState.password" placeholder="请输入您的密码" size="large">
<template #prefix>
<LockOutlined />
</template>
</a-input-password>
</a-form-item>
<a-form-item ref="code" name="code">
<a-input v-model:value="formState.code" placeholder="验证码" style="width:200px;" size="large">
<template #prefix>
<KeyOutlined />
</template>
</a-input>
<img :src="formState.imgCode" alt="" style="width:120px;height:40px;margin-left:2px;margin-top: -2px;margin-right: 10px;">
<a-button type="primary" class="login-button" @click="getVerifyCodeFn" style="position:relative;top:0px;" size="large">
<template #icon>
<ReloadOutlined />
</template>
</a-button>
</a-form-item>
<a-form-item>
<a-button class="login-button" type="primary" block @click="onSubmit" size="large">登录</a-button>
</a-form-item>
<!-- <a-form-item>
<a-button class="login-button" type="primary" block @click="onRegister">单位注册</a-button>
</a-form-item> -->
</a-form>
</div>
</div>
</div>
<registerModal ref="register" />
</div>
</template>
<script setup>
import router from '../../router/index.js';
import registerModal from '../login/register.vue';
import { getVerifyCode, getUserList, login, } from '../../api/user';
import { getDeptTree } from '../../api/dept';
import { queryHotelByDept } from '../../api/hotel';
import { onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { useStore } from '@/store/index.js'
import logoImg from '@/assets/img/login/logo.png';
const userStore = useStore();
const formRef = ref();
const treeData = ref([]);
const searchValue = ref('');
const loading = ref(false);
const register = ref();
const hotelAdress = ref('');
const formState = reactive({
department: undefined,
hotel: undefined,
username: '',
password: '',
imgCode: ''
});
const checkKey1 = ref();
const rules = {
username: [
{
required: true,
message: '请输入您的真实用户信息',
trigger: 'blur',
},
{
min: 2,
max: 10,
message: '用户名长度为 2 到 10',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入正确的密码',
trigger: 'blur',
}
],
department: [
{
required: true,
message: '请选择派出所',
trigger: 'change',
},
],
hotel: [
{
required: true,
message: '请选择旅馆',
trigger: 'change',
},
],
};
const hotelList = ref([]);
const onSubmit = () => {
const param = {
// "hotelId": "1",
"hotelId": formState.hotel,
"passwordBase64": btoa(formState.password),
"username": formState.username,
"verifyCode": formState.code,
"checkKey": checkKey1.value,
"address": hotelAdress.value
};
userStore.getUserInfo(param);
getVerifyCodeFn();
//表单验证 ---- 暂时封闭
// formRef.value
// .validate()
// .then(() => {
// console.log('values', formState, toRaw(formState));
// })
// .catch(error => {
// console.log('error', error);
// });
};
const onRegister = () => {
register.value.showModal();
};
const resetForm = () => {
formRef.value.resetFields();
};
//获取验证码
const getVerifyCodeFn = () => {
checkKey1.value = new Date().getTime();
getVerifyCode({ checkKey: checkKey1.value }).then(res => {
let blob = new Blob([res], { type: "image/png" });
let imageUrl = (window.URL || window.webkitURL).createObjectURL(blob)
formState.imgCode = imageUrl || '';
});
}
//获取派出所组织机构树
const getDeptTreeFn = () => {
getDeptTree().then(res => {
treeData.value = res.data;
}).catch(err => {
message.error(err.message);
});
}
//监听派出所部门变化
watch(() => formState.department, (newVal, oldVal) => {
formState.hotel = undefined;
loading.value = true;
queryHotelByDept({ 'deptid': formState.department }).then(res => {
hotelList.value = res.data;
loading.value = false;
}).catch(res => {
loading.value = false;
});
});
const handleChange = (value, options) => {
hotelAdress.value = options.address;
};
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//获取验证码
onMounted(() => {
//获取派出所组织机构树
getDeptTreeFn();
//首次获取验证码
getVerifyCodeFn();
})
</script>
<style lang="less" scoped>
.login {
width: 100%;
height: 100%;
// display: flex;
// align-items: center;
// justify-content: center;
// background-color: rgb(41, 23, 91);
.login-content {
width: 100%;
height: 100%;
display: flex;
// margin-top: 13%;
.left-content {
width: calc(100% - 768px);
height: 100%;
background: url("@/assets/img/login/bg.png");
}
.right-content {
width: 768px;
height: 100%;
padding-top: 6%;
display: flex;
justify-content: center;
.login-form {
width: 60%;
height: 100%;
.login-img {
text-align: center;
}
h2 {
margin-top: 40px;
text-align: center;
font-size: 37px;
font-weight: 600;
letter-spacing: 4px;
}
p {
color: #b8b5b5;
}
// .login-button {
// // background-color: rgb(41, 23, 91);
// // border: 1px solid white;
// // box-shadow: 0px 0px 1px 1px #ddddddb3;
// &:hover,
// &:focus,
// &:visited {
// background-color: #26184b;
// border: 1px solid #26184b;
// }
// }
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="login">
<div class="login-content">
<h2>旅馆业治安管理信息系统</h2>
<a-form ref="formRef" :model="formState" :rules="rules">
<a-form-item name="department">
<a-tree-select v-model:value="formState.department" v-model:searchValue="searchValue" show-search style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="请选择派出所" allow-clear tree-default-expand-all :tree-data="treeData" tree-node-filter-prop="label">
<template #title="{ value: val, label }">
<b v-if="val === 'parent 1-1'" style="color: #08c">sss</b>
<template v-else>
<template v-for="(fragment, i) in label.toString().split(new RegExp(`(?<=${searchValue})|(?=${searchValue})`, 'i'))">
<span v-if="fragment.toLowerCase() === searchValue.toLowerCase()" :key="i" style="color: #08c">
{{ fragment }}
</span>
<template v-else>{{ fragment }}</template>
</template>
</template>
</template>
</a-tree-select>
</a-form-item>
<a-form-item name="hotel">
<a-spin :spinning="loading">
<a-select v-model:value="formState.hotel" show-search placeholder="请选择旅馆" :options="hotelList" :filter-option="filterOption" @change="handleChange" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-spin>
</a-form-item>
<a-form-item ref="username" name="username">
<a-input v-model:value="formState.username" placeholder="请输入您的用户名">
<template #prefix>
<UserOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="password" name="password">
<a-input-password v-model:value="formState.password" placeholder="请输入您的密码">
<template #prefix>
<LockOutlined />
</template>
</a-input-password>
</a-form-item>
<a-form-item ref="code" name="code">
<a-input v-model:value="formState.code" placeholder="验证码" style="width:200px;">
<template #prefix>
<KeyOutlined />
</template>
</a-input>
<img :src="formState.imgCode" alt="" style="width:100px;height:30px;margin-left:2px;margin-top: -2px;margin-right: 10px;">
<a-button type="primary" class="login-button" @click="getVerifyCodeFn" style="position:relative;top:0px;">
<template #icon>
<ReloadOutlined />
</template>
</a-button>
</a-form-item>
<a-form-item>
<a-button class="login-button" type="primary" block @click="onSubmit">登录</a-button>
</a-form-item>
<a-form-item>
<a-button class="login-button" type="primary" block @click="onRegister">单位注册</a-button>
</a-form-item>
</a-form>
</div>
<registerModal ref="register" />
</div>
</template>
<script setup>
import router from '../../router/index.js';
import registerModal from '../login/register.vue';
import { getVerifyCode, getUserList, login, } from '../../api/user';
import { getDeptTree } from '../../api/dept';
import { queryHotelByDept } from '../../api/hotel';
import { onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { useStore } from '@/store/index.js'
const userStore = useStore();
const formRef = ref();
const treeData = ref([]);
const searchValue = ref('');
const loading = ref(false);
const register = ref();
const hotelAdress = ref('');
const formState = reactive({
department: undefined,
hotel: undefined,
username: '',
password: '',
imgCode: ''
});
const checkKey1 = ref();
const rules = {
username: [
{
required: true,
message: '请输入您的真实用户信息',
trigger: 'blur',
},
{
min: 2,
max: 10,
message: '用户名长度为 2 到 10',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入正确的密码',
trigger: 'blur',
}
],
department: [
{
required: true,
message: '请选择派出所',
trigger: 'change',
},
],
hotel: [
{
required: true,
message: '请选择旅馆',
trigger: 'change',
},
],
};
const hotelList = ref([]);
const onSubmit = () => {
const param = {
// "hotelId": "1",
"hotelId": formState.hotel,
"passwordBase64": btoa(formState.password),
"username": formState.username,
"verifyCode": formState.code,
"checkKey": checkKey1.value,
"address": hotelAdress.value
};
userStore.getUserInfo(param);
getVerifyCodeFn();
//表单验证 ---- 暂时封闭
// formRef.value
// .validate()
// .then(() => {
// console.log('values', formState, toRaw(formState));
// })
// .catch(error => {
// console.log('error', error);
// });
};
const onRegister = () => {
register.value.showModal();
};
const resetForm = () => {
formRef.value.resetFields();
};
//获取验证码
const getVerifyCodeFn = () => {
checkKey1.value = new Date().getTime();
getVerifyCode({ checkKey: checkKey1.value }).then(res => {
let blob = new Blob([res], { type: "image/png" });
let imageUrl = (window.URL || window.webkitURL).createObjectURL(blob)
formState.imgCode = imageUrl || '';
});
}
//获取派出所组织机构树
const getDeptTreeFn = () => {
getDeptTree().then(res => {
treeData.value = res.data;
}).catch(err => {
message.error(err.message);
});
}
//监听派出所部门变化
watch(() => formState.department, (newVal, oldVal) => {
formState.hotel = undefined;
loading.value = true;
queryHotelByDept({ 'deptid': formState.department }).then(res => {
hotelList.value = res.data;
loading.value = false;
}).catch(res => {
loading.value = false;
});
});
const handleChange = (value, options) => {
hotelAdress.value = options.address;
};
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//获取验证码
onMounted(() => {
//获取派出所组织机构树
getDeptTreeFn();
//首次获取验证码
getVerifyCodeFn();
})
</script>
<style lang="less" scoped>
.login {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgb(41, 23, 91);
.login-content {
width: 500px;
height: 600px;
margin-top: 13%;
h2 {
padding: 20px 0px;
text-align: center;
color: white;
}
.login-button {
background-color: rgb(41, 23, 91);
border: 1px solid white;
box-shadow: 0px 0px 1px 1px #ddddddb3;
&:hover,
&:focus,
&:visited {
background-color: #26184b;
border: 1px solid #26184b;
}
}
}
}
</style>
\ No newline at end of file
<template>
<div>
<a-modal v-model:visible="visible" title="用户注册" :footer="null">
<a-form ref="formRef" :model="formState" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item name="department" label="派出所">
<a-select v-model:value="formState.department" placeholder="请选择派出所" size="large">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item name="hotel" label="旅馆">
<a-select v-model:value="formState.hotel" placeholder="请选择旅馆" size="large">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item name="role" label="角色">
<a-select v-model:value="formState.role" placeholder="请选择角色" size="large">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item ref="iphone" name="iphone" label="手机号">
<a-input v-model:value="formState.iphone" placeholder="请输入您的手机号" size="large">
<template #prefix>
<PhoneOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="email" name="email" label="邮箱">
<a-input v-model:value="formState.email" placeholder="请输入您的邮箱" size="large">
<template #prefix>
<MailOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="nickname" name="nickname" label="昵称">
<a-input v-model:value="formState.nickname" placeholder="请输入您的昵称" size="large">
<template #prefix>
<SolutionOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="username" name="username" label="用户名">
<a-input v-model:value="formState.username" placeholder="请输入您的用户名" size="large">
<template #prefix>
<UserOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="password" name="password" label="密码">
<a-input v-model:value="formState.password" placeholder="请输入您的密码" size="large">
<template #prefix>
<LockOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item :wrapper-col="{ span: 14, offset: 8 }">
<a-button class="login-button" size="large" type="primary" @click="onRegister">注册</a-button>
<a-button class="login-button" size="large" type="primary" style="margin-left:10px;" @click="onCancle">取消</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import { register } from '../../api/user'
import { queryRole } from '../../api/role'
const formRef = ref();
const formState = reactive({
department: undefined,
hotel: undefined,
role: undefined,
username: '',
password: '',
iphone: '',
email: '',
nickname: ''
});
const labelCol = {
span: 4,
};
const wrapperCol = {
span: 18,
};
const rules = {
username: [
{
required: true,
message: '请输入您的真实用户信息',
trigger: 'blur',
},
{
min: 3,
max: 5,
message: 'Length should be 3 to 5',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入正确的密码',
trigger: 'blur',
}
],
department: [
{
required: true,
message: '请选择派出所',
trigger: 'change',
},
],
hotel: [
{
required: true,
message: '请选择旅馆',
trigger: 'change',
},
],
};
const visible = ref(false);
const showModal = () => {
visible.value = true;
};
const onRegister = e => {
console.log(e);
// visible.value = false;
register({
"email": formState.email,
"hotel_id": "test",
"nickname": formState.nickname,
"password": formState.password,
"phone": formState.iphone,
"roles": [
0
],
"username": formState.username,
}).then(res => {
// debugger
})
};
const onCancle = () => {
visible.value = false;
}
onMounted(() => {
queryRole({ user_id: 1 }).then(res => {
// debugger
})
})
defineExpose({
showModal
})
</script>
\ No newline at end of file
<template>
<div class="restoreCheckIn">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign" style="color: red;">离店列表(只能恢复近8小时)</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="roomId" label="房间号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="options_room" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item name="name" label="证件号码">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="入住时间">
<a-range-picker show-time @change="(data, dateString) => handleChangeTime(data, dateString)" />
</a-form-item>
</a-col>
<a-col>
<a-space :size="10">
<a-button type="primary" @click="queryList()">查询</a-button>
<a-button type="primary" @click="restore()">批量恢复</a-button>
</a-space>
</a-col>
</a-row>
</a-form>
</div>
<div class="titleBox">
<div>
<span class="sign">内宾离店情况</span>
</div>
</div>
<a-spin :spinning="loading_inland">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_inland" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_inland" :data-source="data_inland" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_inland(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'DEPART'" title="是否恢复" @confirm="setState_inland(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<undo-outlined />
</template>
恢复
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_inland" :rowKey="item=>item.id" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_inland" show-quick-jumper show-size-changer :total="total_inland" v-show="data_inland.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_inland" style="margin: 20px 0px" />
</div>
</a-spin>
<div class="titleBox">
<div>
<span class="sign">外宾离店情况</span>
</div>
</div>
<a-spin :spinning="loading_abroad">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_abroad" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_abroad" :data-source="data_abroad" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_abroad(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'DEPART'" title="是否恢复" @confirm="setState_abroad(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<undo-outlined />
</template>
恢复
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_abroad" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_abroad" show-quick-jumper show-size-changer :total="total_abroad" v-show="data_abroad.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_abroad" style="margin: 20px 0px" />
</div>
</a-spin>
</a-spin>
<InlandEyes v-if="hotelFormVisible" :visible="hotelFormVisible" :visibleEdit="hotelFormVisible_edit" :id="info_id" :title="titles" @change-Cancel="changeCancel_inland" />
<AbroadInfo v-if="abroadInfoVisible" :flogStatus="operateStatus" :visible="abroadInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="abroadInfo" @change-Cancel="changeCancel_adroad" :visibleEdit="hotelFormVisible_edit_s" />
</div>
</template>
<script setup>
import { useStore } from "@/store/index.js";
import { inlandQuery } from "@/api/domesticGuestCheckIn";
import { getForeignGuestCheckInList } from '@/api/foreignGuestCheckIn.js';
import { onMounted } from "vue";
import { message } from "ant-design-vue";
import InlandEyes from '@/views/inland/inlandEyes.vue';
import AbroadInfo from '@/views/abroad/abroadInfo.vue';
import { ChangeDateType } from '@/utils/http_util.js';
import { restoreForeignGuestsToStay, restoreDomesticGuestsToStay } from '@/api/restoreCheckIn.js';
const userstore = useStore();
const formState = reactive({
name: "",
certificateNumber: "",
checkinTimeEnd: "",
checkinTimeStart: "",
state: "DEPART",
roomId: "",
hotelId: userstore.hotelInfo.hotelId, //旅馆id
current: 1,
pageSize: 4,
departureTimeStart: '',
departureTimeEnd: '',
});
/**字典表查询---性别*/
const options_room = ref(userstore.roomAll); //房间字典
/**spinning*/
const loading = ref(false);
/**分页下拉框选项 */
const pageSizeOptions = ref(['4', '10', '20', '30', '40', '50']);
/**内宾表格----------------------- */
const columns_inland = [
{
title: "姓名",
dataIndex: "name",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "民族",
dataIndex: "nationName",
},
{
title: "户籍地省市县区",
dataIndex: "provincialUrbanAreasName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离开时间",
dataIndex: "departureTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_inland = ref([]);
const page_inland = ref(formState.current);/**当前第几页 */
const pageSize_inland = ref(formState.pageSize);/**当前每页的数据 */
const total_inland = ref(0);/**总数 */
const selectedRowKeys_inland = ref([]);/**当前选中集合 */
const loading_inland = ref(false);
const rowSelection_inland = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_inland.value = selectedRowKeys;
},
}
const onChange_inland = (page, pageSize) => {
page_inland.value = page;
pageSize_inland.value = pageSize;
queryInland_dd();
};
/**--------------------------- */
/**外宾表格----------------------- */
const columns_abroad = [
{
title: "姓名",
dataIndex: "chineseName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "出生日期",
dataIndex: 'dateBirth',
},
{
title: "国籍地区",
dataIndex: "nationalityCodeName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离店时间",
dataIndex: "departureTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_abroad = ref([]);
const page_abroad = ref(formState.current);/**当前第几页 */
const pageSize_abroad = ref(formState.pageSize);/**当前每页的数据 */
const total_abroad = ref(0);/**总数 */
const selectedRowKeys_abroad = ref([]);/**当前选中集合 */
const loading_abroad = ref(false);
const rowSelection_abroad = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_abroad.value = selectedRowKeys;
},
}
const onChange_abroad = (page, pageSize) => {
page_abroad.value = page;
pageSize_abroad.value = pageSize;
queryAbroad_dd();
};
/**--------------------------- */
/**时间变化 */
const handleChangeTime = (data, dataArr,) => {
if (dataArr && dataArr.length > 0) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**内宾查询 */
const queryInland = () => {
formState.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
formState.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
return new Promise((resolve) => {
inlandQuery(formState).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**内宾单独查询 */
const queryInland_dd = () => {
const arr = { ...formState };
arr.current = page_inland.value;
arr.pageSize = pageSize_inland.value;
loading_inland.value = true;
arr.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
arr.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
inlandQuery(arr).then((res) => {
if (res?.code == 9000) {
data_inland.value = res.data.records;
total_inland.value = res.data.total;
}
loading_inland.value = false;
}).catch(error => {
loading_inland.value = false;
});
}
/**外宾查询 */
const queryAbroad = () => {
const arr = { ...formState };
arr.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
arr.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
return new Promise((resolve) => {
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单独查询 */
const queryAbroad_dd = () => {
const arr = { ...formState };
arr.current = page_abroad.value;
arr.pageSize = pageSize_abroad.value;
loading_abroad.value = true;
arr.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
arr.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
data_abroad.value = res.data.records;
total_abroad.value = res.data.total;
}
loading_abroad.value = false;
}).catch(error => {
loading_abroad.value = false;
});
}
/**分页查询 */
const queryList = async () => {
loading.value = true;
page_inland.value = formState.current;
pageSize_inland.value = formState.pageSize;
page_abroad.value = formState.current;
pageSize_abroad.value = formState.pageSize;
Promise.all([queryInland(), queryAbroad()]).then(([res1, res2]) => {
loading.value = false;
data_inland.value = res1.data.records;
total_inland.value = res1.data.total;
data_abroad.value = res2.data.records;
total_abroad.value = res2.data.total;
}).catch(error => {
loading.value = false;
});
};
/**内宾单个恢复 */
const setState_inland = (record) => {
loading.value = true;
restoreDomesticGuestsToStay([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("恢复成功");
queryInland_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("恢复失败");
});
}
/**内宾批量恢复 */
const departure_inland = () => {
return new Promise((resolve) => {
restoreDomesticGuestsToStay(selectedRowKeys_inland.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单个恢复 */
const setState_abroad = (record) => {
loading.value = true;
restoreForeignGuestsToStay([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("恢复成功");
queryAbroad_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("恢复失败");
});
}
/**外宾批量恢复 */
const departure_abroad = () => {
return new Promise((resolve) => {
restoreForeignGuestsToStay(selectedRowKeys_abroad.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**批量恢复 */
const restore = () => {
if (selectedRowKeys_inland.value.length > 0 || selectedRowKeys_abroad.value.length > 0) {
loading.value = true;
const arr_http = [];
if (selectedRowKeys_inland.value.length > 0) {
arr_http.push(departure_inland());
} else {
arr_http.push("");
}
if (selectedRowKeys_abroad.value.length > 0) {
arr_http.push(departure_abroad());
} else {
arr_http.push("");
}
Promise.all(arr_http).then(([res1, res2]) => {
loading.value = false;
message.success('恢复成功')
queryList();
}).catch(error => {
loading.value = false;
})
} else {
message.warning('请选择行')
}
}
/**内宾查看 */
const info_id = ref('');
const hotelFormVisible = ref(false);
const hotelFormVisible_edit = ref(false);
const titles = ref("查看内宾详情");
const changeCancel_inland = () => {
hotelFormVisible.value = false;
};
const eye_inland = (e) => {
info_id.value = e.id;
hotelFormVisible.value = true;
hotelFormVisible_edit.value = false;
};
/**外宾查看 */
const abroadInfoVisible = ref(false);
const operateStatus = ref(false);
const dictionaryAllInfo = ref({});
const abroadInfo = ref('');
const hotelFormVisible_edit_s = ref(false);
const changeCancel_adroad = () => {
abroadInfoVisible.value = false;
};
const eye_abroad = (e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
operateStatus.value = true;
hotelFormVisible_edit_s.value = false;
};
onMounted(() => {
queryList();
})
</script>
<style lang="less">
.restoreCheckIn {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
.form {
.ant-form-item {
margin-bottom: 0px;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="room">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">房号列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="name" label="房号">
<a-input v-model:value="formState.name" placeholder="请输入房号"></a-input>
</a-form-item>
</a-col>
<!-- <a-col :span="3">
<a-form-item name="field1" label="房间类型">
<a-input v-model:value="formState.field1" placeholder="请输入房间类型"></a-input>
</a-form-item>
</a-col> -->
<a-col :span="3">
<a-form-item name="floor" label="楼层">
<a-input v-model:value="formState.floor" placeholder="请输入楼层"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="roomPhone" label="房间电话">
<a-input v-model:value="formState.roomPhone" placeholder="请输入房间电话"></a-input>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item name="room_num1" label="床位数">
<a-form-item style="width: calc(40% - 11px);float: left;" name="room_num">
<a-input-number style="width: 100%;" v-model:value="formState.minBed" @change="" placeholder="床位数" :min="0" :max="formState.maxBed"></a-input-number>
</a-form-item><span>&nbsp;&nbsp;</span>
<a-input-number style="width: calc(40% - 11px)" v-model:value="formState.maxBed" placeholder="床位数" :min="formState.minBed"></a-input-number>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" @click="queryRoomsByParamsButton">
<template #icon>
<SearchOutlined />
</template>查询</a-button>&nbsp;
<a-button type="primary" @click="addSingleRoom">
<template #icon><plus-outlined /></template>新增</a-button>&nbsp;
<a-button type="primary" @click="addBatchRoom">
<template #icon><appstore-add-outlined /></template>批量新增</a-button>&nbsp;
<a-button type="primary" :disabled="state.selectedRowKeys.length>0?false:true" @click="bulkDeleteRooms">
<template #icon><delete-outlined /></template>批量删除</a-button>&nbsp;
<!-- <a-button style="margin: 0 8px" @click="() => formRef.resetFields()">清除</a-button>&nbsp; -->
<a-button type="primary" html-type="submit" @click="eye_info">查看房态</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :row-selection="{selectedRowKeys: state.selectedRowKeys,onChange: onSelectChange}" :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eyes(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="删除不可恢复,是否确认?" @confirm="deleteRooms(record)">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
删除
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" :page-size="10" show-quick-jumper :total="formState.total" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChangePagination" style="margin: 20px 0px" />
</div>
<RoomDynamics v-if="hotelFormVisible" :visible="hotelFormVisible" :title="title" @change-Cancel="changeCancel" />
<RoomEyes v-if="hotelFormVisibles" :visible="hotelFormVisibles" :flogStatus="operateStatus" :title="titles" :records='currentData' @change-Cancel="changeCancelEye" @refresh-Table="queryRoomsByParams" />
<RoomSingleAdd v-if="roomSingleAddVisible" :visible="roomSingleAddVisible" :title="roomSingleAddTitle" @change-Cancel="changeCancelSingleAdd" />
<RoomBatchAdd v-if="roomBatchAddVisible" :visible="roomBatchAddVisible" :title="roomBatchAddTitle" @change-Cancel="changeCancelBatchAdd" />
</a-spin>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import RoomDynamics from "@/views/room/roomDynamics.vue";
import RoomEyes from "@/views/room/roomEyes.vue";
import RoomSingleAdd from '@/views/room/roomSingleAdd.vue';
import RoomBatchAdd from '@/views/room/roomBatchAdd.vue';
import { EyeFilled } from "@ant-design/icons-vue";
import { getRooms, bulkRemoveRooms } from "@/api/room.js";
import { useStore } from '@/store/index.js'
import { message } from "ant-design-vue";
const usestore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: usestore.hotelInfo.hotelId,
current: 1,
floor: 1,
minBed: 1,
maxBed: 5,
name: '',
pageSize: 10,
roomPhone: '',
state: '',
type: '',
total: 0
});
const loading = ref(false);
const roomIds = ref([]);
const hotelFormVisible = ref(false);
const title = ref('房间动态');
const changeCancel = () => {
hotelFormVisible.value = false;
};
const eye_info = () => {
hotelFormVisible.value = true;
}
const hotelFormVisibles = ref(false);
const titles = ref('房间详情');
const changeCancelEye = () => {
hotelFormVisibles.value = false;
};
/**查看 */
const currentData = ref({});
const operateStatus = ref(false);
const eyes = (e) => {
currentData.value = e;
operateStatus.value = true;
hotelFormVisibles.value = true;
};
//编辑
const edit = e => {
currentData.value = e;
operateStatus.value = false;
hotelFormVisibles.value = true;
}
//删除
const deleteDefault = data => {
bulkRemoveRooms(data).then(res => {
if (res.code == '9000') {
queryRoomsByParams();
message.success('删除成功!');
} else {
message.error('删除失败');
}
}).catch(error => {
message.error(error.message);
})
};
const deleteRooms = e => {
deleteDefault([e.id]);
}
//批量删除
const bulkDeleteRooms = () => {
deleteDefault(state.selectedRowKeys);
}
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
{
title: "序号",
dataIndex: "index",
},
{
title: "房间号",
dataIndex: "name",
},
{
title: "楼层",
dataIndex: "floor",
},
{
title: "房间电话",
dataIndex: "roomPhone",
},
{
title: "床位数",
dataIndex: "bed",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 300
},
];
const data = ref([]);
const state = reactive({
selectedRowKeys: [],
// Check here to configure the default column
loading: false,
});
const onSelectChange = (selectedRowKeys) => {
console.log("selectedRowKeys changed: ", selectedRowKeys);
state.selectedRowKeys = selectedRowKeys;
};
/**分页 */
const onChangePagination = (pageNumber) => {
loading.value = true;
formState.current = pageNumber;
queryRoomsByParams();
// console.log("Page: ", pageNumber);
};
//单个房间新增
const roomSingleAddVisible = ref(false);
const roomSingleAddTitle = ref('单个房间新增');
const changeCancelSingleAdd = () => {
roomSingleAddVisible.value = false;
}
const addSingleRoom = () => {
roomSingleAddVisible.value = true;
}
//批量房间新增
const roomBatchAddVisible = ref(false);
const roomBatchAddTitle = ref('房间批量新增');
const changeCancelBatchAdd = () => {
roomBatchAddVisible.value = false;
}
const addBatchRoom = () => {
roomBatchAddVisible.value = true;
}
//按钮查询
const queryRoomsByParamsButton = () => {
formState.current = 1;
queryRoomsByParams();
}
//分页查询房间
const queryRoomsByParams = () => {
loading.value = true;
getRooms(formState).then(res => {
if (res.code == '9000') {
data.value = [];
formState.pageSize = 10;
formState.total = res.data.total;
res.data.records.forEach((item, index) => {
item['index'] = (formState.current - 1) * 10 + index + 1;
item['key'] = item.id;
data.value.push(item);
});
loading.value = false;
}
}).catch(error => {
message.error(error.message);
loading.value = false;
});
}
//刷新主页面表格
onMounted(() => {
loading.value = true;
//默认查询
queryRoomsByParams();
})
</script>
<style lang="less">
.room {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomBatchAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="'minFloorNo'" :label="'楼层'">
<a-input-number v-model:value="formState.minFloorNo" placeholder="开始楼层" :allowClear="true" />
&nbsp;&nbsp;
<a-form-item-rest>
<a-input-number v-model:value="formState.maxFloorNo" placeholder="结束楼层" :allowClear="true" />
</a-form-item-rest>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="floorDigit" :label="'楼层位数'">
<a-input-number v-model:value="formState.floorDigit" placeholder="请输入楼层位数" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="minRoomNo" :label="'房间号'">
<a-input-number v-model:value="formState.minRoomNo" placeholder="开始房号" :allowClear="true" />
&nbsp;&nbsp;
<a-form-item-rest>
<a-input-number v-model:value="formState.maxRoomNo" placeholder="结束房号" :allowClear="true" />
</a-form-item-rest>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="roomDigit" :label="'房号位数'">
<a-input-number v-model:value="formState.roomDigit" placeholder="请输入房号位数" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="buildingNo" :label="'房号模板'">
<a-input-group compact>
<a-input v-model:value="formState.buildingNo" style="width: 20%" />
<a-form-item-rest>
<a-input value="【楼层】【房间号】" style="width: 40%" />
</a-form-item-rest>
</a-input-group>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="phoneTemplate" :label="'电话号码模板'">
<a-input-group compact>
<a-input v-model:value="formState.phoneTemplate" style="width: 20%" />
<a-form-item-rest>
<a-input value="【楼层】【房间号】" style="width: 40%" />
</a-form-item-rest>
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="bed" :label="'床位数'">
<a-input-number v-model:value="formState.bed" placeholder="请输入床位数" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="avoidFloorNum" :label="'楼层规避数字'">
<a-input v-model:value="formState.avoidFloorNum" placeholder="请输入楼层规避数字,多个数字以@隔开,例如3@4" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item v-for="(domain, index) in floorRules.domains" :key="domain.key" formItemLayout :label="`楼层数字转换${index+1}`" :name="`domains${index}`" style="margin-top:10px;">
<a-form-item-rest>
<a-input v-model:value="domain.no" placeholder="原始楼层顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>
=>
<a-form-item-rest>
<a-input v-model:value="domain.value" placeholder="新的楼层顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>&nbsp;
<MinusCircleOutlined v-if="floorRules.domains.length > 0" class="dynamic-delete-button" :disabled="floorRules.domains.length === 0" @click="removeDomainFloor(domain)" />
</a-form-item>
<a-form-item style="margin-top:10px;margin-bottom:10px;">
<a-button type="dashed" style="width: 60%;margin-left:100px;" @click="addDomainFloor">
<PlusOutlined />
新增转换楼层
</a-button>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="avoidRoomNum" :label="'房号规避数字'">
<a-input v-model:value="formState.avoidRoomNum" placeholder="请输入房号规避数字,多个数字以@隔开,例如3@4" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item v-for="(domain, index) in roomRules.domains" :key="domain.key" formItemLayout :label="`房号数字转换${index+1}`" :name="`domains${index}`" style="margin-top:10px;">
<a-form-item-rest>
<a-input v-model:value="domain.no" placeholder="原始房间顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>
=>
<a-form-item-rest>
<a-input v-model:value="domain.value" placeholder="新的房间顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>&nbsp;
<MinusCircleOutlined v-if="roomRules.domains.length > 0" class="dynamic-delete-button" :disabled="roomRules.domains.length === 0" @click="removeDomainRoom(domain)" />
</a-form-item>
<a-form-item style="margin-top:10px;margin-bottom:10px;">
<a-button type="dashed" style="width: 60%;margin-left:100px;" @click="addDomainRoom">
<PlusOutlined />
新增转换房号
</a-button>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="roomNumPreview" :label="'房号预览'">
<a-input v-model:value="formState.roomNumPreview" readonly style="color:red;font-weight:600;" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="phoneNumPreview" :label="'电话号码预览'">
<a-input v-model:value="formState.phoneNumPreview" readonly style="color:red;font-weight:600;" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="preview">预览</a-button>
<a-button type="primary" size="large" @click="saveRoom" :disabled="previewData.length>0?false:true">保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
<template #footer>
</template>
</a-modal>
</template>
<script setup>
import { reactive } from "vue";
import { useStore } from '@/store/index.js';
import { previewRooms, addRooms } from '@/api/room.js';
import { message } from "ant-design-vue";
const usestore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
});
const formRef = ref();
const formState = reactive({
hotelId: usestore.hotelInfo.hotelId,
creator: usestore.userInfo.username,
bed: null,
buildingNo: null,
floorDigit: null,
minRoomNo: null,
maxRoomNo: null,
roomRule: [],
roomDigit: null,
minFloorNo: null,
maxFloorNo: null,
avoidFloorNum: null,
floorRule: [],
phoneTemplate: '',
avoidRoomNum: null,
roomNumPreview: '',
phoneNumPreview: ''
})
const defalutDictionaryAll = reactive({
allRoomType: usestore.returnCode(1),
allRoomBedNum: [{ id: 1, code: 1, name: '一张床' }, { id: 2, code: 2, name: '两张床' }, { id: 1, code: 1, name: '三张床' }, { id: 1, code: 1, name: '四张床' }, { id: 5, code: 5, name: '五张床' }],
allRoomState: [{ id: 1, code: 1, name: '正常' }, { id: 1, code: 1, name: '维修' }, { id: 1, code: 1, name: '关闭' }]
});
const rules = {
name: [
{
required: true,
message: '请输入房间号'
}
],
type: [
{
required: true,
message: '请选择房间类型'
}
],
floor: [
{
required: true,
message: '请输入楼层'
},
],
room_phone: [
{
required: true,
message: '请输入房间电话'
},
],
bed: [
{
required: true,
message: '请选择床数量'
}
],
state: [
{
required: true,
message: '请选择房间状态'
}
]
};
//预览的数据
const previewData = ref([]);
const emit = defineEmits(["changeCancel"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const preview = () => {
//楼层号
if (formState.avoidFloorNum) {
if (formState.avoidFloorNum.indexOf('@') > -1) {
const avoidList = formState.avoidFloorNum.split('@');
avoidList.forEach(item => {
const obj = {};
obj['no'] = item;
obj['value'] = null;
formState.floorRule.push(obj);
});
} else {
formState.floorRule.push({ no: formState.avoidFloorNum, value: null });
}
}
floorRules.domains.forEach(item => {
if (item.no) {
formState.floorRule.push(item);
}
})
// formState.floorRule = formState.floorRule.concat(floorRules.domains);
//房间号
if (formState.avoidRoomNum) {
if (formState.avoidRoomNum.indexOf('@') > -1) {
const avoidList = formState.avoidRoomNum.split('@');
avoidList.forEach(item => {
const obj = {};
obj['no'] = item;
obj['value'] = null;
formState.roomRule.push(obj);
});
} else {
formState.roomRule.push({ no: formState.avoidRoomNum, value: null });
}
}
roomRules.domains.forEach(item => {
if (item.no) {
formState.roomRule.push(item);
}
});
// formState.roomRule = formState.roomRule.concat(roomRules.domains);
previewRooms(formState).then(res => {
if (res.code == '9000') {
// message.success('规则创建成功!');
previewData.value = res.data;
// floorRules.domains = [];
// roomRules.domains = [];
// formState.floorRule = [];
// formState.roomRule = [];
// formRef.value.resetFields();
formState.roomNumPreview = `第一个房号:${res.data[0].name},最后一个房号是:${res.data[res.data.length - 1].name}。`;
}
}).catch(error => {
message.error(error.message);
})
}
//保存房号
const saveRoom = () => {
if (previewData.value.length > 0) {
addRooms(previewData.value).then(res => {
if (res.code == '9000') {
message.success('新增成功:'+res.data.success+',新增失败:'+res.data.failure+',失败原因:'+res.data.message.join(''),10);
floorRules.domains = [];
roomRules.domains = [];
formRef.value.resetFields();
}
});
} else {
message.warning('暂无数据新增!');
}
}
//楼层规则
const floorRules = reactive({
domains: [],
});
const addDomainFloor = () => {
floorRules.domains.push({
no: null,
value: null,
key: Date.now()
});
};
const removeDomainFloor = item => {
let index = floorRules.domains.indexOf(item);
if (index !== -1) {
floorRules.domains.splice(index, 1);
}
};
//房间规则
const roomRules = reactive({
domains: [],
});
const addDomainRoom = () => {
roomRules.domains.push({
value: '',
key: '',
});
};
const removeDomainRoom = item => {
let index = roomRules.domains.indexOf(item);
if (index !== -1) {
roomRules.domains.splice(index, 1);
}
};
const formItemLayout = {
labelCol: {
span: 10,
},
wrapperCol: {
span: 14
}
};
</script>
<style lang="less">
.roomBatchAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="80%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomDynamics">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 4 }" :wrapper-col="{ span: 20 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="2" class="td1">
<span>旅馆房间数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.hotelRooms"></span>
</td>
<td colspan="2" class="td1">入住房间数:</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfRoomsOccupied"></span>
</td>
<td colspan="2" class="td1">
<span>房间入住率:</span>
</td>
<td colspan="2" class="td2">
<a-progress :stroke-color="{'0%': '#108ee9','100%': '#87d068'}" :percent="parseFloat(formState.occupancyRate).toFixed(2)" />
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>入住旅客数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfOccupants"></span>
</td>
<td colspan="2" class="td1">
<span>内宾数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfDomesticGuests"></span>
</td>
<td colspan="2" class="td1">
<span>外宾数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfForeignGuests"></span>
</td>
</tr>
</table>
</a-form>
</div>
<div style="margin: 0px 5px">
<div style="width: 100%; float: left; margin: 20px 10px; font-weight: 400">
<div style="float: left">
<span style="font-weight: 900">说明: </span>
<span>右上角&nbsp;</span>
</div>
<div style=" width: 20px; height: 20px; background: #13c2c2; float: left; text-align: center; color: white ">
<span>[1]</span>
</div>
<div style="float: left">
<span>&nbsp;表示房间床位数;&nbsp;</span>
</div>
<div style="width: 20px;height: 20px;background: #2db7f5;float: left;text-align: center; color: white;">
<span></span>
</div>
<div style="float: left">
<span>&nbsp;表示房间入住总人数;&nbsp;</span>
</div>
<div style="width: 20px;height: 20px;background: #87d068;float: left;text-align: center;color: white;">
<span></span>
</div>
<div style="float: left">
<span>&nbsp;表示入住内宾数;&nbsp;</span>
</div>
<div style="width: 20px;height: 20px;background: #f1ce03;float: left;text-align: center;color: white;">
<span></span>
</div>
<div style="float: left">
<span>&nbsp;表示入住外宾数; 灰色背景房间无人入住</span>
</div>
</div>
<a-list :grid="{ gutter: 16, column: 8 }" :data-source="formStateArr" class="list-div">
<template #renderItem="{ item }">
<a-list-item>
<a-badge-ribbon :text="'[' + item.bed + ']'" color="cyan">
<a-card :style="{background:item.totalCheckIn > 0? '#d1ffbe' : '#ebebeb'}">
<div style="line-height: 50px; text-align: center">
<span style="color: #ff4d1f;font-size: 17px;letter-spacing: 2px;font-weight: 600;">{{ item.roomNo }}</span>
</div>
<div style="height: 20px;width: 100%;display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: space-evenly;">
<div style="padding: 0px 6px;background: #2db7f5;width: fit-content;color: white; " v-show="item.total != 0">
<span>{{"总(" + (item.totalCheckIn) + ")"}}</span>
</div>
<div style="padding: 0px 6px;background: #87d068;width: fit-content;color: white;" v-show="item.domesticGuestCheckIn != 0">
<span>{{ "内(" + item.domesticGuestCheckIn + ")" }}</span>
</div>
<div style="padding: 0px 6px;background: #f1ce03;width: fit-content;color: white;" v-show="item.foreignGuestCheckIn != 0">
<span>{{ "外(" + item.foreignGuestCheckIn + ")" }}</span>
</div>
</div>
</a-card>
</a-badge-ribbon>
</a-list-item>
</template>
</a-list>
</div>
</div>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { queryRoomStatus, queryStatisticsRoomStatus } from '@/api/room.js';
import { useStore } from '@/store/index.js';
import { message } from 'ant-design-vue';
import { onMounted } from 'vue';
const usestore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
});
const formRef = ref();
const formState = ref({});
const formStateArr = ref([]);
const emit = defineEmits(["changeCancel"]);
const handleCancel = async () => {
await emit("changeCancel");
}
onMounted(() => {
//上半部分
queryRoomStatus({ hotelId: usestore.hotelInfo.hotelId }).then(res => {
if (res.code == '9000') {
formState.value = res.data;
}
}).catch(error => {
message.error(error.message);
})
//下半部分
queryStatisticsRoomStatus({ hotelId: usestore.hotelInfo.hotelId }).then(res => {
if (res.code == '9000') {
formStateArr.value = res.data;
}
}).catch(error => {
message.error(error.message);
})
})
</script>
<style lang="less">
.roomDynamics {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
width: 110px;
.img-wp {
width: 175px;
height: 230px;
// border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
}
.img-span {
text-align: center;
color: orange;
font-weight: 400;
font-size: 15px;
}
}
}
.td1 {
font-weight: 600;
font-size: 13px;
text-align: right;
padding: 0px 20px;
color: #007cef;
letter-spacing: 2px;
}
.td2 {
text-align: left;
padding: 0px 20px;
color: #ff4d1f;
font-weight: 600;
.ant-progress-text {
color: #ff4d1f;
}
}
}
}
.list-div {
.ant-card-body {
padding: 10px;
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomEyesFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 4 }" :wrapper-col="{ span: 20 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="2" class="td1">
<span>房号:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.name" placeholder="请输入房号" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.name"></span> -->
</td>
<td colspan="2" class="td1">房间类型:</td>
<td colspan="2" class="td2">
<!-- <a-input v-model:value="formState.type" placeholder="请输入房间类型" :readonly="operateStatus?true:false"></a-input> -->
<a-select style="width:100%;" show-search v-model:value="formState.type" :filter-option="filterOption" placeholder="请选择房间类型" :allowClear="true" :options="roomType" optionLabelProp="name"
:fieldNames="{ label: 'name', value: 'code' }" :disabled="operateStatus?true:false">
</a-select>
<!-- <span v-text="formState.type"></span> -->
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>楼层:</span>
</td>
<td colspan="6" class="td2">
<!-- <span v-text="formState.floor"></span> -->
<a-input v-model:value="formState.floor" placeholder="请输入楼层" :readonly="operateStatus?true:false"></a-input>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>床位数:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.bed" placeholder="请输入床位数" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.bed"></span> -->
</td>
<td colspan="2" class="td1"><span>房间电话: </span></td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.roomPhone" placeholder="请输入房间电话" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.roomPhone"></span> -->
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>创建人:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.creator" readonly></a-input>
</td>
<td colspan="2" class="td1"><span>创建时间: </span></td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.createTime" readonly></a-input>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>修改人:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.updater" readonly></a-input>
</td>
<td colspan="2" class="td1"><span>修改时间: </span></td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.updateTime" readonly></a-input>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>备注:</span>
</td>
<td colspan="6" class="td2">
<a-input v-model:value="formState.remark" placeholder="请输入备注" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.remark"></span> -->
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit">编辑</a-button>
<a-button type="primary" size="large" @click="saveInfo"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { onMounted } from "vue";
import { forIn } from "lodash-es";
import { updateRoomsInfo } from '@/api/room.js';
import { message } from "ant-design-vue";
import { useStore } from "@/store/index.js";
const userstore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
records: {},
flogStatus: Boolean
});
const roomType = ref(ref(userstore.returnCode(1)));
const formRef = ref();
const formState = reactive({});
const operateStatus = ref(true);
const emit = defineEmits(["changeCancel","refreshTable"]);
const handleCancel = async () => {
await emit("changeCancel");
};
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
console.log("Selected Time: ", value);
console.log("Formatted Selected Time: ", dateString);
};
const onOk = (value, dateString) => {
formState.pass = dateString;
console.log("onOk: ", value);
};
const handleMenuClick = (e) => {
console.log("click", e);
};
//编辑
const edit = () => {
operateStatus.value = false;
}
//保存
const saveInfo = () => {
updateRoomsInfo(formState).then(res => {
if (res.code == '9000') {
emit('refreshTable');
message.success('保存成功!');
}
}).catch(error => {
message.error(error.message);
})
}
onMounted(() => {
forIn(props?.records, (value, key) => (formState[key] = value));
operateStatus.value = props?.flogStatus;
})
</script>
<style lang="less">
.roomEyesFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
width: 110px;
.img-wp {
width: 175px;
height: 230px;
// border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
}
.img-span {
text-align: center;
color: orange;
font-weight: 400;
font-size: 15px;
}
}
}
.td1 {
font-weight: 600;
font-size: 13px;
text-align: right;
padding: 0px 20px;
color: #007cef;
letter-spacing: 2px;
}
.td2 {
text-align: left;
padding: 0px 20px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomSingleAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="floor" :label="'楼层'">
<a-input v-model:value="formState.floor" placeholder="请输入楼层" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="name" :label="'房间号'">
<a-input v-model:value="formState.name" placeholder="请输入房间号" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="type" :label="'房间类型'">
<a-select v-model:value="formState.type" show-search placeholder="请选择房间类型" :options="defalutDictionaryAll.allRoomType" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="bed" :label="'床数量'">
<a-select v-model:value="formState.bed" show-search placeholder="请选择床数量" :options="defalutDictionaryAll.allRoomBedNum" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="roomPhone" :label="'房间电话'">
<a-input v-model:value="formState.roomPhone" placeholder="请输入房间电话" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="state" :label="'房间状态'">
<a-select v-model:value="formState.state" show-search placeholder="请选择房间状态" :options="defalutDictionaryAll.allRoomState" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="reamrk" :label="'备注'" :label-col="{ span: 3 }" :wrapper-col="{ span: 21 }">
<a-input v-model:value="formState.reamrk" placeholder="请输入备注" :allowClear="true" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="saveRoom">保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
<template #footer>
</template>
</a-modal>
</template>
<script setup>
import { reactive } from "vue";
import { useStore } from '@/store/index.js';
import { addRooms } from '@/api/room.js';
import { message } from "ant-design-vue";
const usestore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
});
const formRef = ref();
const formState = reactive({
hotelId: usestore.hotelInfo.hotelId,
creator: usestore.userInfo.username,
name: '',
type: '',
floor: '',
roomPhone: '',
bed: '',
state: '',
remark: ''
})
const defalutDictionaryAll = reactive({
allRoomType: usestore.returnCode(1),
allRoomBedNum: [{ id: 1, code: 1, name: '一张床' }, { id: 2, code: 2, name: '两张床' }, { id: 3, code: 3, name: '三张床' }, { id: 4, code: 4, name: '四张床' }, { id: 5, code: 5, name: '五张床' }],
allRoomState: [{ id: 1, code: 1, name: '正常' }, { id: 2, code: 2, name: '维修' }, { id: 3, code: 3, name: '关闭' }]
});
const rules = {
name: [
{
required: true,
message: '请输入房间号'
}
],
type: [
{
required: true,
message: '请选择房间类型'
}
],
floor: [
{
required: true,
message: '请输入楼层'
},
],
room_phone: [
{
required: true,
message: '请输入房间电话'
},
],
bed: [
{
required: true,
message: '请选择床数量'
}
],
state: [
{
required: true,
message: '请选择房间状态'
}
]
};
const emit = defineEmits(["changeCancel"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//保存房号
const saveRoom = () => {
addRooms([formState]).then(res => {
if (res.code == '9000') {
message.success('房号新增成功!');
formRef.value.resetFields();
}
}).catch(error => {
message.error(error.message);
});
}
</script>
<style lang="less">
.roomSingleAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
}
</style>
\ No newline at end of file
<template>
<div class="visitor">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">访客登记信息列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="4">
<a-form-item name="roomId" label="房号">
<a-select v-model:value="formState.roomId" :allowClear="true" show-search placeholder="请选择房号" :options="dictionaryAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="name" label="访客中文姓名">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入中文姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item name="certificateNumber" label="访客证件号码">
<a-input v-model:value="formState.certificateNumber" :allowClear="true" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="residentName" label="住客姓名">
<a-input v-model:value="formState.residentName" :allowClear="true" placeholder="请输入住客姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item name="nationalityCode" label="访客国籍(地区)">
<a-select v-model:value="formState.nationalityCode" :allowClear="true" show-search placeholder="请选择国家及地区" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="visitTime" label="来访时间">
<a-range-picker :allowClear="true" show-time @change="onChangeRangeDate" />
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="state" label="访客状态">
<a-select v-model:value="formState.state" :allowClear="true" show-search placeholder="请选择访客状态" :options="dictionaryAll.allCheckInState" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" html-type="submit" @click="searchVisitor">搜索</a-button>
<a-button style="margin: 0 8px" @click="() => formRef.resetFields()">清除</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :row-selection="{selectedRowKeys: state.selectedRowKeys,onChange: onSelectChange,}" :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color:#52c41a" @click="eyes(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="是否离店?" @confirm="checkOut(record)" v-if="record.state=='DEPART'?false:true">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" show-quick-jumper show-size-changer :total="total" v-show="data.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChangePagination" style="margin: 20px 0px" />
</div>
</a-spin>
<VisitorInfo v-if="visitorInfoVisible" :flogStatus="operateStatus" :visible="visitorInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="visitorInfo" @change-Cancel="changeCancel" />
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { getVisitorList, departureVisitorRegist } from '@/api/visitorRegist.js'
import { useStore } from '@/store/index.js';
import { message } from "ant-design-vue";
import VisitorInfo from "@/views/visitor/visitorInfo.vue";
const loading = ref(false);
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: '',
name: '',
certificateNumber: '',
residentName: '',
nationalityCode: '',
visitingTimeStart: '',
visitingTimeEnd: '',
state: '',
current: 1,
pageSize: 10,
});
//获取a-range-date时间
const onChangeRangeDate = (value, dataArr) => {
if (dataArr && dataArr.length > 0) {
formState.visitingTimeEnd = dataArr[1];
formState.visitingTimeStart = dataArr[0];
}
}
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9),
allCheckInState: userstore.returnCode(2)
});
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
// {
// title: "序号",
// dataIndex: 'key',
// },
{
title: "房号",
dataIndex: "roomName",
},
{
title: "访客中文姓名",
dataIndex: "name",
},
{
title: "访客英文姓名",
dataIndex: "foreignName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "联系电话",
dataIndex: 'phoneNumber',
},
{
title: "访客状态",
dataIndex: "stateName",
},
{
title: "住客姓名",
dataIndex: "residentName",
},
{
title: "来访时间",
dataIndex: "visitingTime",
},
{
title: "离开时间",
dataIndex: "departureTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 230,
}
];
const state = reactive({
selectedRowKeys: [],
// Check here to configure the default column
loading: false,
});
const onSelectChange = (selectedRowKeys) => {
console.log("selectedRowKeys changed: ", selectedRowKeys);
state.selectedRowKeys = selectedRowKeys;
};
/**分页 */
const onChangePagination = (page, pageSize) => {
formState.current = page;
formState.pageSize = pageSize;
searchVisitor();
};
/**查看 */
const visitorInfo = ref({});
const dictionaryAllInfo = ref({});
const visitorInfoVisible = ref(false);
const operateStatus = ref(false);
const changeCancel = () => {
visitorInfoVisible.value = false;
}
const eyes = (e) => {
visitorInfo.value = e;
visitorInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = true;
}
//编辑
const edit = (e) => {
visitorInfo.value = e;
visitorInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = false;
}
//离店
const checkOut = record => {
loading.value = true;
departureVisitorRegist([record.id]).then(res => {
if (res.code == '9000') {
message.success('离店成功')
searchVisitor();
}
loading.value = false;
}).catch(error => {
message.warning('离店失败');
loading.value = false;
})
}
//搜索
const data = ref([]);
const total = ref(0);
const searchVisitor = () => {
loading.value = true;
getVisitorList(formState).then(res => {
loading.value = false;
if (res?.code == 9000) {
data.value = res.data.records;
total.value = res.data.total;
}
}).catch(err => {
loading.value = false;
})
}
onMounted(() => {
searchVisitor();
});
</script>
<style lang="less">
.visitor {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="loading">
<div class="hotelFrom">
<div class="titleBox">
<div>
<span class="sign">访客登记信息列表</span>
</div>
<div v-if="id_disabled">
<a-space :size="10">
<a-button type="primary" size="large" @click="returnToPreviousPage()">返回</a-button>
</a-space>
</div>
</div>
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" :disabled="id_disabled" show-search placeholder="请选择旅馆" :options="dictionaryAll.allRoom" :filter-option="filterOption" optionLabelProp="name" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="1" rowspan="5">
<div class="img-pub">
<div class="img-wp">
<div class="img-div" style="width: calc(100% - 32px);height: calc(100% - 20px);margin: 10px 16px 10px;">
<!-- <div class="img-span">
<span>证件人像</span>
</div> -->
<div class="img-span" style="line-height: 36px;" v-if="formState.certificatePhoto == ''">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhoto" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取人像照片</a-radio>
</div> -->
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhoto == ''">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhoto" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取现场照片</a-radio>
</div> -->
<div class="check-div" style="text-align: center" @click="OnCamera()">
<a-button type="primary" size="small">截取现场照片</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="residentName" :label="`住客姓名`">
<a-input v-model:value="formState.residentName" :disabled="id_disabled" placeholder="请输入" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="certificateNumber" :label="`访客证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="nationalityCode" :label="`访客国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择访客国籍" :options="dictionaryAll.allCountry" :filter-option="filterOption" optionLabelProp="name" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="name" :label="`访客中文姓名`">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入中文姓名" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="foreignName" :label="`访客英文姓名`">
<a-input v-model:value="formState.foreignName" :allowClear="true" placeholder="请输入英文姓名" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="phoneNumber" :label="`访客联系电话`" :rules="[
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" :allowClear="true" placeholder="请输入联系电话" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="2">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 20 }" :label-col="{ span: 4 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="handle_ID_reading()">读取证件</a-button>
<a-button type="primary" size="large">扫描证件</a-button>
<a-button type="primary" size="large" @click="saveInfo"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button size="large" @click="qk()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { file_img_src, ChangeDateType } from '@/utils/http_util.js';
import { addVisitorRegist } from '@/api/visitorRegist.js';
import { uploadImg } from '@/api/default.js';
import { message } from 'ant-design-vue';
import { onMounted, toRaw } from 'vue';
import requests from "@/utils/request_test";
import { useRoute } from 'vue-router';
import { forIn } from "lodash-es";
import router from "../../router";
const route = useRoute();
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: "",
residentName: "",
certificateNumber: "",//证件号码
certificatePhoto: "",//证件照片
nationalityCode: "",
name: "",
foreignName: "",
phoneNumber: "",
remark: "",
sitePhoto: "",
visitingTime: undefined,
state: "ARRIVE",
verificationState: "",
creator: userstore.userInfo.username,
departureTime: "",
updater: ""
});
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
residentName: [
{
required: true,
message: '请输入住客姓名'
}
],
certificateNumber: [
{
required: true,
message: '请选择访客证件号码'
},
],
nationalityCode: [
{
required: true,
message: '请选择访客国籍(地址)'
},
]
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
// const screenshot_url = ref("");
const onSubmit = (e) => {
// formState.sitePhoto = e.value;
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
formState.sitePhoto = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**清空 */
const qk = ()=>{
formRef.value.resetFields();
formState.sitePhoto = '';
}
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9)
});
const checked_value1 = ref(false);
const checked_value2 = ref(false);
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
// await emit("changeform", false);
};
const dx_click = (e) => {
if (e == 1) {
checked_value1.value = true;
checked_value2.value = false;
} else {
checked_value1.value = false;
checked_value2.value = true;
}
};
const loading = ref(false);
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
console.log("Selected Time: ", value);
console.log("Formatted Selected Time: ", dateString);
};
const onOk = (value, dateString) => {
formState.pass = dateString;
console.log("onOk: ", value);
};
const handleMenuClick = (e) => {
console.log("click", e);
};
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png'||info.file.type === 'image/jpg'||info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
}else{
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**返回 */
const returnToPreviousPage = ()=>{
router.go(-1);
}
const saveInfo = () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (formState.sitePhoto != "") {/**现场照片 */
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
if (formState.certificatePhoto != "") {/**身份证 */
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (formState.sitePhoto != "") {
arr.sitePhoto = res1
}
if (formState.certificatePhoto != "") {
arr.certificatePhoto = res2
}
arr.visitingTime = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
addVisitorRegist(arr).then((res) => {
if (res.code == 9000) {
message.success("已保存");
reset();
returnToPreviousPage();
}
loading.value = false;
}).catch((res) => {
message.warning("保存失败");
});
loading.value = false;
});
})
}
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
const id_disabled = ref(false);
onMounted(() => {
if(route.query.roomId){//判断是否传过来
// console.log(typeof())
formState.roomId = parseInt(route.query.roomId);
formState.residentName = route.query.name;
id_disabled.value = true;
}
})
const handle_ID_reading = () => {
loading.value = true;
requests({ url: "/dev", method: "GET", }).then((res) => {
loading.value = false;
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
}
})
.catch((res) => {
message.warning(res);
loading.value = false;
});
};
</script>
<style lang="less">
.hotelFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y:auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" title="查看详情" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="hotelFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" show-search placeholder="请选择旅馆" :options="dictionaryAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="1" rowspan="5">
<div class="img-pub">
<div class="img-wp">
<div class="img-div" style="width: calc(100% - 32px);height: calc(100% - 20px);margin: 10px 16px 10px;">
<!-- <div class="img-span">
<span>证件人像</span>
</div> -->
<div class="img-span" style="line-height: 36px;" v-if="formState.certificatePhotoPath == ''||formState.certificatePhotoPath==null">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhotoPath" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取人像照片</a-radio>
</div> -->
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhotoPath == ''||formState.sitePhotoPath==null">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhotoPath" :fallback="default_img" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取现场照片</a-radio>
</div> -->
<div class="check-div" style="text-align: center" @click="OnCamera()">
<a-button type="primary" size="small" :disabled="operateStatus?true:false">截取现场照片</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;" v-if="!operateStatus">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="residentName" :label="`住客姓名`">
<a-input v-model:value="formState.residentName" placeholder="请输入" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="certificateNumber" :label="`访客证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="nationalityCode" :label="`访客国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择访客国籍" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="name" :label="`访客中文姓名`">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入中文姓名" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="foreignName" :label="`访客英文姓名`">
<a-input v-model:value="formState.foreignName" :allowClear="true" placeholder="请输入英文姓名" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="phoneNumber" :label="`访客联系电话`" :rules="[
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" :allowClear="true" placeholder="请输入联系电话" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="2">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 20 }" :label-col="{ span: 4 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit" v-if="operateStatus">编辑</a-button>
<a-button type="primary" size="large" @click="handle_ID_reading()" v-if="!operateStatus">读取证件</a-button>
<a-button type="primary" size="large" v-if="!operateStatus">扫描证件</a-button>
<a-button type="primary" size="large" v-if="!operateStatus" @click="saveInfo"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button size="large" @click="() => formRef.resetFields()" v-if="!operateStatus"><template #icon>
<reload-outlined />
</template>
清空</a-button>
<a-button size="large" @click="handleCancel()" v-if="!operateStatus">取消</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { file_img_src } from '@/utils/http_util.js';
import { updateVisitorRegist, queryVisitorRegistDetail } from '@/api/visitorRegist.js';
import { uploadImg } from '@/api/default.js';
import { message } from 'ant-design-vue';
import { onMounted } from 'vue';
import { forIn } from "lodash-es";
import requests from "@/utils/request_test";
import default_img from '@/assets/img/default.png';
const userstore = useStore();
const formRef = ref();
const formState = reactive({});
const operateStatus = ref(true);
const loading = ref(false);
const props = defineProps({
visible: Boolean,
formData: {},
dictionaryAll: {},
flogStatus: Boolean
});
const emit = defineEmits(["changeCancel"]);
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
residentName: [
{
required: true,
message: '请输入住客姓名'
}
],
certificateNumber: [
{
required: true,
message: '请选择访客证件号码'
},
],
nationalityCode: [
{
required: true,
message: '请选择访客国籍(地址)'
},
]
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
// const screenshot_url = ref("");
const onSubmit = (e) => {
// screenshot_url.value = e.value;
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
sitePhotos.value = false;
certificatePhotos.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
sitePhotos.value = true;
formState.sitePhoto = e.value;
formState.sitePhotoPath = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
const dictionaryAll = reactive({
});
const checked_value1 = ref(false);
const checked_value2 = ref(false);
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
await emit("changeCancel");
};
const dx_click = (e) => {
if (e == 1) {
checked_value1.value = true;
checked_value2.value = false;
} else {
checked_value1.value = false;
checked_value2.value = true;
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
console.log("Selected Time: ", value);
console.log("Formatted Selected Time: ", dateString);
};
const onOk = (value, dateString) => {
formState.pass = dateString;
console.log("onOk: ", value);
};
const handleMenuClick = (e) => {
console.log("click", e);
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png'||info.file.type === 'image/jpg'||info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
}else{
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
formState.sitePhotoPath = reader.result;
sitePhotos.value = true;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
const reset = () => {
// formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
sitePhotos.value = false;
certificatePhotos.value = false;
};
const saveInfo = () => {
/**批量操作上传图片 */
formRef.value?.validateFields().then((values) => {
const arr_http = [];
if (sitePhotos.value) {/**现场照片 */
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
if (certificatePhotos.value) {/**身份证 */
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (sitePhotos.value) {
arr.sitePhoto = res1
}
if (certificatePhotos.value) {
arr.certificatePhoto = res2
}
updateVisitorRegist(arr)
.then((res) => {
if (res.code == 9000) {
message.success("已保存");
operateStatus.value = true;
// reset();
sitePhotos.value = false;
certificatePhotos.value = false;
}
loading.value = false;
})
.catch((res) => {
message.warning("保存失败");
loading.value = false;
});
});
})
}
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
const handle_ID_reading = () => {
requests({
url: "/dev",
method: "GET",
})
.then((res) => {
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
formState.certificatePhotoPath =
"data:image/png;base64," + res.data.profilephoto;
certificatePhotos.value = true
}
})
.catch((res) => {
message.warning(res);
});
};
const edit = () => {
operateStatus.value = false;
}
onMounted(() => {
if (props?.visible) {
loading.value = true;
queryVisitorRegistDetail({ id: props?.formData.id }).then(res => {
forIn(res.data, (value, key) => (formState[key] = value));
loading.value = false;
}).catch(error => {
loading.value = true;
});
forIn(props?.dictionaryAll, (value, key) => (dictionaryAll[key] = value));
operateStatus.value = props?.flogStatus;
};
})
/**判断现场照片修改 */
const sitePhotos = ref(false);
/**判断证件照 */
const certificatePhotos = ref(false);
</script>
<style lang="less">
.hotelFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
import { defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve} from "path";
import AutoImport from 'unplugin-auto-import/vite';
//自动导入ui-组件 比如说ant-design-vue element-plus等
import Components from "unplugin-vue-components/vite";
//ant-design-vue
import { AntDesignVueResolver} from "unplugin-vue-components/resolvers";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
// 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
imports: ['vue', 'vue-router'],
}),
Components({
//ant-design-vue importStyle = false 样式就没了
resolvers: [
AntDesignVueResolver({
importStyle: "less",
resolveIcons: true
}),
],
})
],
//别名src下的资源路径都可以以@/替换
resolve: {
alias: [{
find: "@",
replacement: resolve(__dirname, "src"),
}, ],
},
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true
}
}
},
//服务器
server: {
host: "0.0.0.0", //本地打开 地址栏为 http://localhost:3366/
port: 3366, //指定端口号
open: true, //项目启动成功自动打开浏览器
proxy: {
//拦截请求地址包含/api,匹配到的是生产环境
"/api": {
target: "http://172.16.60.201:8081", //后台服务地址
changeOrigin: true,
//重写,/api开头的替换成空字符串,即去掉接口中去掉这个字符串
rewrite: (path) => path.replace(/^\/api/, "")
},
//匹配到的时开发环境
"/dev": {
target: "http://localhost:5000", //后台服务地址
changeOrigin: true,
//重写,/api开头的替换成空字符串,即去掉接口中去掉这个字符串
rewrite: (path) => path.replace(/^\/dev/, ""),
},
}
},
})
\ No newline at end of file
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@ant-design/colors@^6.0.0":
version "6.0.0"
resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz"
integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==
dependencies:
"@ctrl/tinycolor" "^3.4.0"
"@ant-design/icons-svg@^4.2.1":
version "4.2.1"
resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz"
integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==
"@ant-design/icons-vue@^6.1.0":
version "6.1.0"
resolved "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz"
integrity sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==
dependencies:
"@ant-design/colors" "^6.0.0"
"@ant-design/icons-svg" "^4.2.1"
"@antfu/utils@^0.7.4", "@antfu/utils@^0.7.5":
version "0.7.5"
resolved "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.5.tgz"
integrity sha512-dlR6LdS+0SzOAPx/TPRhnoi7hE251OVeT2Snw0RguNbBSbjUHdWr0l3vcUUDg26rEysT89kCbtw1lVorBXLLCg==
"@babel/parser@^7.15.8", "@babel/parser@^7.20.15", "@babel/parser@^7.21.3":
version "7.22.10"
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.10.tgz"
integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==
"@babel/runtime@^7.10.5", "@babel/runtime@^7.5.5":
version "7.22.6"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz"
integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==
dependencies:
regenerator-runtime "^0.13.11"
"@ctrl/tinycolor@^3.4.0":
version "3.6.0"
resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz"
integrity sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==
"@esbuild/win32-x64@0.18.13":
version "0.18.13"
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.13.tgz"
integrity sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==
"@jiaminghi/bezier-curve@*":
version "0.0.9"
resolved "https://registry.npmjs.org/@jiaminghi/bezier-curve/-/bezier-curve-0.0.9.tgz"
integrity sha512-u9xJPOEl6Dri2E9FfmJoGxYQY7vYJkURNX04Vj64tdi535tPrpkuf9Sm0lNr3QTKdHQh0DdNRsaa62FLQNQEEw==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/c-render@^0.4.3":
version "0.4.3"
resolved "https://registry.npmjs.org/@jiaminghi/c-render/-/c-render-0.4.3.tgz"
integrity sha512-FJfzj5hGj7MLqqqI2D7vEzHKbQ1Ynnn7PJKgzsjXaZpJzTqs2Yw5OSeZnm6l7Qj7jyPAP53lFvEQNH4o4j6s+Q==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/bezier-curve" "*"
"@jiaminghi/color" "*"
"@jiaminghi/transition" "*"
"@jiaminghi/charts@^0.2.18":
version "0.2.18"
resolved "https://registry.npmjs.org/@jiaminghi/charts/-/charts-0.2.18.tgz"
integrity sha512-K+HXaOOeWG9OOY1VG6M4mBreeeIAPhb9X+khG651AbnwEwL6G2UtcAQ8GWCq6GzhczcLwwhIhuaHqRygwHC0sA==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/c-render" "^0.4.3"
"@jiaminghi/color@*", "@jiaminghi/color@^1.1.3":
version "1.1.3"
resolved "https://registry.npmjs.org/@jiaminghi/color/-/color-1.1.3.tgz"
integrity sha512-ZY3hdorgODk4OSTbxyXBPxAxHPIVf9rPlKJyK1C1db46a50J0reFKpAvfZG8zMG3lvM60IR7Qawgcu4ZDO3+Hg==
"@jiaminghi/transition@*":
version "1.1.11"
resolved "https://registry.npmjs.org/@jiaminghi/transition/-/transition-1.1.11.tgz"
integrity sha512-owBggipoHMikDHHDW5Gc7RZYlVuvxHADiU4bxfjBVkHDAmmck+fCkm46n2JzC3j33hWvP9nSCAeh37t6stgWeg==
dependencies:
"@babel/runtime" "^7.5.5"
"@jridgewell/sourcemap-codec@^1.4.15":
version "1.4.15"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@kjgl77/datav-vue3@^1.6.1":
version "1.6.1"
resolved "https://registry.npmjs.org/@kjgl77/datav-vue3/-/datav-vue3-1.6.1.tgz"
integrity sha512-HgEr/McsMhYIIqUhBQR0LB9Q2rFARUd4VrjcsTCyEW6RPZsCJO1Yoto/7P9jLO2uRmzfDOyxJxLx4c67rORziw==
dependencies:
"@jiaminghi/c-render" "^0.4.3"
"@jiaminghi/charts" "^0.2.18"
"@jiaminghi/color" "^1.1.3"
"@vueuse/core" "^10.1.2"
lodash-es "^4.17.21"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
version "2.0.5"
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
version "1.2.8"
resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@rollup/pluginutils@^5.0.2":
version "5.0.2"
resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz"
integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
dependencies:
"@types/estree" "^1.0.0"
estree-walker "^2.0.2"
picomatch "^2.3.1"
"@simonwep/pickr@~1.8.0":
version "1.8.2"
resolved "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.2.tgz"
integrity sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==
dependencies:
core-js "^3.15.1"
nanopop "^2.1.0"
"@types/estree@^1.0.0":
version "1.0.1"
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz"
integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==
"@types/web-bluetooth@^0.0.17":
version "0.0.17"
resolved "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz"
integrity sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==
"@vitejs/plugin-vue@^4.2.3":
version "4.2.3"
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz"
integrity sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==
"@vue/compiler-core@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz"
integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==
dependencies:
"@babel/parser" "^7.21.3"
"@vue/shared" "3.3.4"
estree-walker "^2.0.2"
source-map-js "^1.0.2"
"@vue/compiler-dom@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz"
integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==
dependencies:
"@vue/compiler-core" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/compiler-sfc@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz"
integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==
dependencies:
"@babel/parser" "^7.20.15"
"@vue/compiler-core" "3.3.4"
"@vue/compiler-dom" "3.3.4"
"@vue/compiler-ssr" "3.3.4"
"@vue/reactivity-transform" "3.3.4"
"@vue/shared" "3.3.4"
estree-walker "^2.0.2"
magic-string "^0.30.0"
postcss "^8.1.10"
source-map-js "^1.0.2"
"@vue/compiler-ssr@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz"
integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==
dependencies:
"@vue/compiler-dom" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/devtools-api@^6.5.0":
version "6.5.0"
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz"
integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
"@vue/reactivity-transform@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz"
integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==
dependencies:
"@babel/parser" "^7.20.15"
"@vue/compiler-core" "3.3.4"
"@vue/shared" "3.3.4"
estree-walker "^2.0.2"
magic-string "^0.30.0"
"@vue/reactivity@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz"
integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==
dependencies:
"@vue/shared" "3.3.4"
"@vue/runtime-core@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz"
integrity sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==
dependencies:
"@vue/reactivity" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/runtime-dom@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz"
integrity sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==
dependencies:
"@vue/runtime-core" "3.3.4"
"@vue/shared" "3.3.4"
csstype "^3.1.1"
"@vue/server-renderer@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz"
integrity sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==
dependencies:
"@vue/compiler-ssr" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/shared@3.3.4":
version "3.3.4"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz"
integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
"@vueuse/core@*", "@vueuse/core@^10.1.2":
version "10.2.1"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-10.2.1.tgz"
integrity sha512-c441bfMbkAwTNwVRHQ0zdYZNETK//P84rC01aP2Uy/aRFCiie9NE/k9KdIXbno0eDYP5NPUuWv0aA/I4Unr/7w==
dependencies:
"@types/web-bluetooth" "^0.0.17"
"@vueuse/metadata" "10.2.1"
"@vueuse/shared" "10.2.1"
vue-demi ">=0.14.5"
"@vueuse/metadata@10.2.1":
version "10.2.1"
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.2.1.tgz"
integrity sha512-3Gt68mY/i6bQvFqx7cuGBzrCCQu17OBaGWS5JdwISpMsHnMKKjC2FeB5OAfMcCQ0oINfADP3i9A4PPRo0peHdQ==
"@vueuse/shared@10.2.1":
version "10.2.1"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-10.2.1.tgz"
integrity sha512-QWHq2bSuGptkcxx4f4M/fBYC3Y8d3M2UYyLsyzoPgEoVzJURQ0oJeWXu79OiLlBb8gTKkqe4mO85T/sf39mmiw==
dependencies:
vue-demi ">=0.14.5"
acorn@^8.8.2, acorn@^8.9.0:
version "8.10.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
ant-design-vue@^3.2.20:
version "3.2.20"
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.20.tgz"
integrity sha512-YWpMfGaGoRastIXEYfCoJiaRiDHk4chqtYhlKQM5GqPt6NfvrM1Vg2e60yHtjxlZjed91wCMm0rAmyUr7Hwzdg==
dependencies:
"@ant-design/colors" "^6.0.0"
"@ant-design/icons-vue" "^6.1.0"
"@babel/runtime" "^7.10.5"
"@ctrl/tinycolor" "^3.4.0"
"@simonwep/pickr" "~1.8.0"
array-tree-filter "^2.1.0"
async-validator "^4.0.0"
dayjs "^1.10.5"
dom-align "^1.12.1"
dom-scroll-into-view "^2.0.0"
lodash "^4.17.21"
lodash-es "^4.17.15"
resize-observer-polyfill "^1.5.1"
scroll-into-view-if-needed "^2.2.25"
shallow-equal "^1.0.0"
vue-types "^3.0.0"
warning "^4.0.0"
anymatch@~3.1.2:
version "3.1.3"
resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
array-tree-filter@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz"
integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==
async-validator@^4.0.0:
version "4.2.5"
resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz"
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
axios@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz"
integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
braces@^3.0.2, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0":
version "3.5.3"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
compute-scroll-into-view@^1.0.20:
version "1.0.20"
resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz"
integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
copy-anything@^2.0.1:
version "2.0.6"
resolved "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz"
integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==
dependencies:
is-what "^3.14.1"
core-js@^3.15.1:
version "3.31.1"
resolved "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz"
integrity sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==
cropperjs@^1.5.13:
version "1.5.13"
resolved "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.13.tgz"
integrity sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA==
csstype@^3.1.1:
version "3.1.2"
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
dayjs@^1.10.5, dayjs@^1.11.9:
version "1.11.9"
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz"
integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
debug@^3.2.6:
version "3.2.7"
resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
debug@^4.3.4:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
dom-align@^1.12.1:
version "1.12.4"
resolved "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz"
integrity sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==
dom-scroll-into-view@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz"
integrity sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==
errno@^0.1.1:
version "0.1.8"
resolved "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz"
integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
dependencies:
prr "~1.0.1"
esbuild@^0.18.10:
version "0.18.13"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.13.tgz"
integrity sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==
optionalDependencies:
"@esbuild/android-arm" "0.18.13"
"@esbuild/android-arm64" "0.18.13"
"@esbuild/android-x64" "0.18.13"
"@esbuild/darwin-arm64" "0.18.13"
"@esbuild/darwin-x64" "0.18.13"
"@esbuild/freebsd-arm64" "0.18.13"
"@esbuild/freebsd-x64" "0.18.13"
"@esbuild/linux-arm" "0.18.13"
"@esbuild/linux-arm64" "0.18.13"
"@esbuild/linux-ia32" "0.18.13"
"@esbuild/linux-loong64" "0.18.13"
"@esbuild/linux-mips64el" "0.18.13"
"@esbuild/linux-ppc64" "0.18.13"
"@esbuild/linux-riscv64" "0.18.13"
"@esbuild/linux-s390x" "0.18.13"
"@esbuild/linux-x64" "0.18.13"
"@esbuild/netbsd-x64" "0.18.13"
"@esbuild/openbsd-x64" "0.18.13"
"@esbuild/sunos-x64" "0.18.13"
"@esbuild/win32-arm64" "0.18.13"
"@esbuild/win32-ia32" "0.18.13"
"@esbuild/win32-x64" "0.18.13"
escape-string-regexp@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
estree-walker@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
fast-glob@^3.2.12, fast-glob@^3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz"
integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fastq@^1.6.0:
version "1.15.0"
resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz"
integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
dependencies:
reusify "^1.0.4"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
graceful-fs@^4.1.2:
version "4.2.11"
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
image-size@~0.5.0:
version "0.5.5"
resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz"
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
immutable@^4.0.0:
version "4.3.1"
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.1.tgz"
integrity sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A==
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-core-module@^2.11.0:
version "2.12.1"
resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz"
integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
dependencies:
has "^1.0.3"
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.3"
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-plain-object@3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz"
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
is-what@^3.14.1:
version "3.14.1"
resolved "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz"
integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
jsonc-parser@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
less@*, less@^4.1.3:
version "4.1.3"
resolved "https://registry.npmjs.org/less/-/less-4.1.3.tgz"
integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==
dependencies:
copy-anything "^2.0.1"
parse-node-version "^1.0.1"
tslib "^2.3.0"
optionalDependencies:
errno "^0.1.1"
graceful-fs "^4.1.2"
image-size "~0.5.0"
make-dir "^2.1.0"
mime "^1.4.1"
needle "^3.1.0"
source-map "~0.6.0"
local-pkg@^0.4.3:
version "0.4.3"
resolved "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz"
integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==
lodash-es@^4.17.15, lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.0.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
magic-string@^0.30.0, magic-string@^0.30.1:
version "0.30.1"
resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz"
integrity sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.15"
make-dir@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz"
integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
dependencies:
pify "^4.0.1"
semver "^5.6.0"
merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4:
version "4.0.5"
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mime@^1.4.1:
version "1.6.0"
resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
minimatch@^9.0.1, minimatch@^9.0.2:
version "9.0.3"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz"
integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
dependencies:
brace-expansion "^2.0.1"
mlly@^1.2.0, mlly@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz"
integrity sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==
dependencies:
acorn "^8.9.0"
pathe "^1.1.1"
pkg-types "^1.0.3"
ufo "^1.1.2"
ms@^2.1.1, ms@2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
nanoid@^3.3.6:
version "3.3.6"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
nanopop@^2.1.0:
version "2.3.0"
resolved "https://registry.npmjs.org/nanopop/-/nanopop-2.3.0.tgz"
integrity sha512-fzN+T2K7/Ah25XU02MJkPZ5q4Tj5FpjmIYq4rvoHX4yb16HzFdCO6JxFFn5Y/oBhQ8no8fUZavnyIv9/+xkBBw==
needle@^3.1.0:
version "3.2.0"
resolved "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz"
integrity sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==
dependencies:
debug "^3.2.6"
iconv-lite "^0.6.3"
sax "^1.2.4"
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
nprogress@^0.2.0:
version "0.2.0"
resolved "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz"
integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==
parse-node-version@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz"
integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
pathe@^1.1.0, pathe@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz"
integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pinia-plugin-persistedstate@^3.2.0:
version "3.2.0"
resolved "https://registry.npmmirror.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.0.tgz"
integrity sha512-tZbNGf2vjAQcIm7alK40sE51Qu/m9oWr+rEgNm/2AWr1huFxj72CjvpQcIQzMknDBJEkQznCLAGtJTIcLKrKdw==
pinia@^2.0.0, pinia@^2.1.4:
version "2.1.4"
resolved "https://registry.npmjs.org/pinia/-/pinia-2.1.4.tgz"
integrity sha512-vYlnDu+Y/FXxv1ABo1vhjC+IbqvzUdiUC3sfDRrRyY2CQSrqqaa+iiHmqtARFxJVqWQMCJfXx1PBvFs9aJVLXQ==
dependencies:
"@vue/devtools-api" "^6.5.0"
vue-demi ">=0.14.5"
pkg-types@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz"
integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==
dependencies:
jsonc-parser "^3.2.0"
mlly "^1.2.0"
pathe "^1.1.0"
postcss@^8.1.10, postcss@^8.4.25:
version "8.4.26"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz"
integrity sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz"
integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
regenerator-runtime@^0.13.11:
version "0.13.11"
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve@^1.22.2:
version "1.22.2"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz"
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rollup@^1.20.0||^2.0.0||^3.0.0, rollup@^3.25.2:
version "3.26.3"
resolved "https://registry.npmjs.org/rollup/-/rollup-3.26.3.tgz"
integrity sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==
optionalDependencies:
fsevents "~2.3.2"
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
"safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sass@*, sass@^1.63.6:
version "1.63.6"
resolved "https://registry.npmjs.org/sass/-/sass-1.63.6.tgz"
integrity sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
sax@^1.2.4:
version "1.2.4"
resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
scroll-into-view-if-needed@^2.2.25:
version "2.2.31"
resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz"
integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
dependencies:
compute-scroll-into-view "^1.0.20"
scule@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/scule/-/scule-1.0.0.tgz"
integrity sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==
semver@^5.6.0:
version "5.7.2"
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
shallow-equal@^1.0.0:
version "1.2.1"
resolved "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz"
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
source-map-js@^1.0.2, "source-map-js@>=0.6.2 <2.0.0":
version "1.0.2"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map@~0.6.0:
version "0.6.1"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
strip-literal@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz"
integrity sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==
dependencies:
acorn "^8.8.2"
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
tslib@^2.3.0:
version "2.6.0"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz"
integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==
ufo@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz"
integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==
unimport@^3.0.14:
version "3.0.14"
resolved "https://registry.npmjs.org/unimport/-/unimport-3.0.14.tgz"
integrity sha512-67Rh/sGpEuVqdHWkXaZ6NOq+I7sKt86o+DUtKeGB6dh4Hk1A8AQrzyVGg2+LaVEYotStH7HwvV9YSaRjyT7Uqg==
dependencies:
"@rollup/pluginutils" "^5.0.2"
escape-string-regexp "^5.0.0"
fast-glob "^3.3.0"
local-pkg "^0.4.3"
magic-string "^0.30.0"
mlly "^1.4.0"
pathe "^1.1.1"
pkg-types "^1.0.3"
scule "^1.0.0"
strip-literal "^1.0.1"
unplugin "^1.3.1"
unplugin-auto-import@^0.16.6:
version "0.16.6"
resolved "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.16.6.tgz"
integrity sha512-M+YIITkx3C/Hg38hp8HmswP5mShUUyJOzpifv7RTlAbeFlO2Tyw0pwrogSSxnipHDPTtI8VHFBpkYkNKzYSuyA==
dependencies:
"@antfu/utils" "^0.7.5"
"@rollup/pluginutils" "^5.0.2"
fast-glob "^3.3.0"
local-pkg "^0.4.3"
magic-string "^0.30.1"
minimatch "^9.0.2"
unimport "^3.0.14"
unplugin "^1.3.2"
unplugin-vue-components@^0.25.1:
version "0.25.1"
resolved "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.25.1.tgz"
integrity sha512-kzS2ZHVMaGU2XEO2keYQcMjNZkanDSGDdY96uQT9EPe+wqSZwwgbFfKVJ5ti0+8rGAcKHColwKUvctBhq2LJ3A==
dependencies:
"@antfu/utils" "^0.7.4"
"@rollup/pluginutils" "^5.0.2"
chokidar "^3.5.3"
debug "^4.3.4"
fast-glob "^3.2.12"
local-pkg "^0.4.3"
magic-string "^0.30.0"
minimatch "^9.0.1"
resolve "^1.22.2"
unplugin "^1.3.1"
unplugin@^1.3.1, unplugin@^1.3.2:
version "1.4.0"
resolved "https://registry.npmjs.org/unplugin/-/unplugin-1.4.0.tgz"
integrity sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==
dependencies:
acorn "^8.9.0"
chokidar "^3.5.3"
webpack-sources "^3.2.3"
webpack-virtual-modules "^0.5.0"
vite@^4.0.0, vite@^4.4.0:
version "4.4.4"
resolved "https://registry.npmjs.org/vite/-/vite-4.4.4.tgz"
integrity sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==
dependencies:
esbuild "^0.18.10"
postcss "^8.4.25"
rollup "^3.25.2"
optionalDependencies:
fsevents "~2.3.2"
vue-demi@>=0.14.5:
version "0.14.5"
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz"
integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
vue-router@^4.2.4:
version "4.2.4"
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz"
integrity sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==
dependencies:
"@vue/devtools-api" "^6.5.0"
vue-types@^3.0.0:
version "3.0.2"
resolved "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz"
integrity sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==
dependencies:
is-plain-object "3.0.1"
"vue@^2.6.14 || ^3.3.0", vue@^3.0.0, "vue@^3.0.0-0 || ^2.6.0", vue@^3.2.0, vue@^3.2.25, vue@^3.3.4, vue@>=3.0.3, vue@>=3.2.0, "vue@2 || 3", vue@3.3.4:
version "3.3.4"
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
dependencies:
"@vue/compiler-dom" "3.3.4"
"@vue/compiler-sfc" "3.3.4"
"@vue/runtime-dom" "3.3.4"
"@vue/server-renderer" "3.3.4"
"@vue/shared" "3.3.4"
warning@^4.0.0:
version "4.0.3"
resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
webpack-sources@^3.2.3:
version "3.2.3"
resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack-virtual-modules@^0.5.0:
version "0.5.0"
resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz"
integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment