feat: 初始化基本配置
This commit is contained in:
parent
64e93679f8
commit
5511769673
1
ui/env/.env
vendored
1
ui/env/.env
vendored
@ -1,3 +1,4 @@
|
|||||||
VITE_APP_NAME=ui
|
VITE_APP_NAME=ui
|
||||||
VITE_BASE_PATH=/ui/
|
VITE_BASE_PATH=/ui/
|
||||||
VITE_APP_PORT=3000
|
VITE_APP_PORT=3000
|
||||||
|
VITE_APP_TITLE = '智能知识库'
|
||||||
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Vite App</title>
|
<title>%VITE_APP_TITLE%</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
341
ui/package-lock.json
generated
341
ui/package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"element-plus": "^2.3.7",
|
"element-plus": "^2.3.14",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
@ -34,6 +34,7 @@
|
|||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"sass": "^1.66.1",
|
"sass": "^1.66.1",
|
||||||
"typescript": "~5.1.6",
|
"typescript": "~5.1.6",
|
||||||
|
"unplugin-vue-define-options": "^1.3.18",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vitest": "^0.34.2",
|
"vitest": "^0.34.2",
|
||||||
"vue-tsc": "^1.8.8"
|
"vue-tsc": "^1.8.8"
|
||||||
@ -48,6 +49,24 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/helper-string-parser": {
|
||||||
|
"version": "7.22.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||||
|
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
|
"version": "7.22.20",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||||
|
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.22.15",
|
"version": "7.22.15",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
|
||||||
@ -59,6 +78,20 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/types": {
|
||||||
|
"version": "7.23.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.23.0.tgz",
|
||||||
|
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-string-parser": "^7.22.5",
|
||||||
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
|
"to-fast-properties": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ctrl/tinycolor": {
|
"node_modules/@ctrl/tinycolor": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||||
@ -290,6 +323,28 @@
|
|||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/pluginutils": {
|
||||||
|
"version": "5.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.0.5.tgz",
|
||||||
|
"integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==",
|
||||||
|
"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||^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rushstack/eslint-patch": {
|
"node_modules/@rushstack/eslint-patch": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz",
|
||||||
@ -332,6 +387,12 @@
|
|||||||
"@types/chai": "*"
|
"@types/chai": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/estree": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/jsdom": {
|
"node_modules/@types/jsdom": {
|
||||||
"version": "21.1.2",
|
"version": "21.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.2.tgz",
|
||||||
@ -714,6 +775,31 @@
|
|||||||
"@volar/language-core": "1.10.1"
|
"@volar/language-core": "1.10.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vue-macros/common": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@vue-macros/common/-/common-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-auDJJzE0z3uRe3867e0DsqcseKImktNf5ojCZgUKqiVxb2yTlwlgOVAYCgoep9oITqxkXQymSvFeKhedi8PhaA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/types": "^7.22.17",
|
||||||
|
"@rollup/pluginutils": "^5.0.4",
|
||||||
|
"@vue/compiler-sfc": "^3.3.4",
|
||||||
|
"ast-kit": "^0.11.2",
|
||||||
|
"local-pkg": "^0.4.3",
|
||||||
|
"magic-string-ast": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^2.7.0 || ^3.2.25"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"vue": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vue/compiler-core": {
|
"node_modules/@vue/compiler-core": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
|
||||||
@ -1189,6 +1275,47 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ast-kit": {
|
||||||
|
"version": "0.11.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ast-kit/-/ast-kit-0.11.2.tgz",
|
||||||
|
"integrity": "sha512-Q0DjXK4ApbVoIf9GLyCo252tUH44iTnD/hiJ2TQaJeydYWSpKk0sI34+WMel8S9Wt5pbLgG02oJ+gkgX5DV3sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/parser": "^7.22.14",
|
||||||
|
"@rollup/pluginutils": "^5.0.4",
|
||||||
|
"pathe": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ast-walker-scope": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ast-walker-scope/-/ast-walker-scope-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-NsyHMxBh4dmdEHjBo1/TBZvCKxffmZxRYhmclfu0PP6Aftre47jOHYaYaNqJcV0bxihxFXhDkzLHUwHc0ocd0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/parser": "^7.22.7",
|
||||||
|
"ast-kit": "^0.9.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ast-walker-scope/node_modules/ast-kit": {
|
||||||
|
"version": "0.9.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ast-kit/-/ast-kit-0.9.5.tgz",
|
||||||
|
"integrity": "sha512-kbL7ERlqjXubdDd+szuwdlQ1xUxEz9mCz1+m07ftNVStgwRb2RWw+U6oKo08PAvOishMxiqz1mlJyLl8yQx2Qg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/parser": "^7.22.7",
|
||||||
|
"@rollup/pluginutils": "^5.0.2",
|
||||||
|
"pathe": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/async-validator": {
|
"node_modules/async-validator": {
|
||||||
"version": "4.2.5",
|
"version": "4.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
|
||||||
@ -1733,9 +1860,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/element-plus": {
|
"node_modules/element-plus": {
|
||||||
"version": "2.3.12",
|
"version": "2.3.14",
|
||||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.3.12.tgz",
|
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.3.14.tgz",
|
||||||
"integrity": "sha512-fAWpbKCyt+l1dsqSNPOs/F/dBN4Wp5CGAyxbiS5zqDwI4q3QPM+LxLU2h3GUHMIBtMGCvmsG98j5HPMkTKkvcA==",
|
"integrity": "sha512-9yvxUaU4jXf2ZNPdmIxoj/f8BG8CDcGM6oHa9JIqxLjQlfY4bpzR1E5CjNimnOX3rxO93w1TQ0jTVt0RSxh9kA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ctrl/tinycolor": "^3.4.1",
|
"@ctrl/tinycolor": "^3.4.1",
|
||||||
"@element-plus/icons-vue": "^2.0.6",
|
"@element-plus/icons-vue": "^2.0.6",
|
||||||
@ -3378,6 +3505,18 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/magic-string-ast": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/magic-string-ast/-/magic-string-ast-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-0shqecEPgdFpnI3AP90epXyxZy9g6CRZ+SZ7BcqFwYmtFEnZ1jpevcV5HoyVnlDS9gCnc1UIg3Rsvp3Ci7r8OA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"magic-string": "^0.30.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/memoize-one": {
|
"node_modules/memoize-one": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||||
@ -4945,6 +5084,15 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/to-fast-properties": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
@ -5152,6 +5300,32 @@
|
|||||||
"node": ">= 4.0.0"
|
"node": ">= 4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/unplugin": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.10.0",
|
||||||
|
"chokidar": "^3.5.3",
|
||||||
|
"webpack-sources": "^3.2.3",
|
||||||
|
"webpack-virtual-modules": "^0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unplugin-vue-define-options": {
|
||||||
|
"version": "1.3.18",
|
||||||
|
"resolved": "https://registry.npmmirror.com/unplugin-vue-define-options/-/unplugin-vue-define-options-1.3.18.tgz",
|
||||||
|
"integrity": "sha512-AaE10FCccfezT48yyYuUXdnTF9z8vQuXrlpNF5uQtq/AOD2pdkf38vnmJm8bJjpoqEkR6u72wNCJLZKXSUw+Og==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@vue-macros/common": "1.8.0",
|
||||||
|
"ast-walker-scope": "^0.5.0",
|
||||||
|
"unplugin": "^1.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/untildify": {
|
"node_modules/untildify": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
|
||||||
@ -5480,6 +5654,21 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack-sources": {
|
||||||
|
"version": "3.2.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/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.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/whatwg-encoding": {
|
"node_modules/whatwg-encoding": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
||||||
@ -5648,11 +5837,34 @@
|
|||||||
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
|
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@babel/helper-string-parser": {
|
||||||
|
"version": "7.22.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||||
|
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@babel/helper-validator-identifier": {
|
||||||
|
"version": "7.22.20",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||||
|
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@babel/parser": {
|
"@babel/parser": {
|
||||||
"version": "7.22.15",
|
"version": "7.22.15",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
|
||||||
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA=="
|
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA=="
|
||||||
},
|
},
|
||||||
|
"@babel/types": {
|
||||||
|
"version": "7.23.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.23.0.tgz",
|
||||||
|
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/helper-string-parser": "^7.22.5",
|
||||||
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
|
"to-fast-properties": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@ctrl/tinycolor": {
|
"@ctrl/tinycolor": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||||
@ -5819,6 +6031,17 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
|
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
|
||||||
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
|
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
|
||||||
},
|
},
|
||||||
|
"@rollup/pluginutils": {
|
||||||
|
"version": "5.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.0.5.tgz",
|
||||||
|
"integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/estree": "^1.0.0",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@rushstack/eslint-patch": {
|
"@rushstack/eslint-patch": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz",
|
||||||
@ -5858,6 +6081,12 @@
|
|||||||
"@types/chai": "*"
|
"@types/chai": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/estree": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/jsdom": {
|
"@types/jsdom": {
|
||||||
"version": "21.1.2",
|
"version": "21.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.2.tgz",
|
||||||
@ -6120,6 +6349,20 @@
|
|||||||
"@volar/language-core": "1.10.1"
|
"@volar/language-core": "1.10.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@vue-macros/common": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@vue-macros/common/-/common-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-auDJJzE0z3uRe3867e0DsqcseKImktNf5ojCZgUKqiVxb2yTlwlgOVAYCgoep9oITqxkXQymSvFeKhedi8PhaA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/types": "^7.22.17",
|
||||||
|
"@rollup/pluginutils": "^5.0.4",
|
||||||
|
"@vue/compiler-sfc": "^3.3.4",
|
||||||
|
"ast-kit": "^0.11.2",
|
||||||
|
"local-pkg": "^0.4.3",
|
||||||
|
"magic-string-ast": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@vue/compiler-core": {
|
"@vue/compiler-core": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
|
||||||
@ -6466,6 +6709,40 @@
|
|||||||
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ast-kit": {
|
||||||
|
"version": "0.11.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ast-kit/-/ast-kit-0.11.2.tgz",
|
||||||
|
"integrity": "sha512-Q0DjXK4ApbVoIf9GLyCo252tUH44iTnD/hiJ2TQaJeydYWSpKk0sI34+WMel8S9Wt5pbLgG02oJ+gkgX5DV3sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/parser": "^7.22.14",
|
||||||
|
"@rollup/pluginutils": "^5.0.4",
|
||||||
|
"pathe": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ast-walker-scope": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ast-walker-scope/-/ast-walker-scope-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-NsyHMxBh4dmdEHjBo1/TBZvCKxffmZxRYhmclfu0PP6Aftre47jOHYaYaNqJcV0bxihxFXhDkzLHUwHc0ocd0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/parser": "^7.22.7",
|
||||||
|
"ast-kit": "^0.9.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ast-kit": {
|
||||||
|
"version": "0.9.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ast-kit/-/ast-kit-0.9.5.tgz",
|
||||||
|
"integrity": "sha512-kbL7ERlqjXubdDd+szuwdlQ1xUxEz9mCz1+m07ftNVStgwRb2RWw+U6oKo08PAvOishMxiqz1mlJyLl8yQx2Qg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/parser": "^7.22.7",
|
||||||
|
"@rollup/pluginutils": "^5.0.2",
|
||||||
|
"pathe": "^1.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"async-validator": {
|
"async-validator": {
|
||||||
"version": "4.2.5",
|
"version": "4.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
|
||||||
@ -6869,9 +7146,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"element-plus": {
|
"element-plus": {
|
||||||
"version": "2.3.12",
|
"version": "2.3.14",
|
||||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.3.12.tgz",
|
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.3.14.tgz",
|
||||||
"integrity": "sha512-fAWpbKCyt+l1dsqSNPOs/F/dBN4Wp5CGAyxbiS5zqDwI4q3QPM+LxLU2h3GUHMIBtMGCvmsG98j5HPMkTKkvcA==",
|
"integrity": "sha512-9yvxUaU4jXf2ZNPdmIxoj/f8BG8CDcGM6oHa9JIqxLjQlfY4bpzR1E5CjNimnOX3rxO93w1TQ0jTVt0RSxh9kA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ctrl/tinycolor": "^3.4.1",
|
"@ctrl/tinycolor": "^3.4.1",
|
||||||
"@element-plus/icons-vue": "^2.0.6",
|
"@element-plus/icons-vue": "^2.0.6",
|
||||||
@ -8064,6 +8341,15 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"magic-string-ast": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/magic-string-ast/-/magic-string-ast-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-0shqecEPgdFpnI3AP90epXyxZy9g6CRZ+SZ7BcqFwYmtFEnZ1jpevcV5HoyVnlDS9gCnc1UIg3Rsvp3Ci7r8OA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"magic-string": "^0.30.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"memoize-one": {
|
"memoize-one": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||||
@ -9164,6 +9450,12 @@
|
|||||||
"integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
|
"integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"to-fast-properties": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"to-regex-range": {
|
"to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
@ -9315,6 +9607,29 @@
|
|||||||
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"unplugin": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"acorn": "^8.10.0",
|
||||||
|
"chokidar": "^3.5.3",
|
||||||
|
"webpack-sources": "^3.2.3",
|
||||||
|
"webpack-virtual-modules": "^0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unplugin-vue-define-options": {
|
||||||
|
"version": "1.3.18",
|
||||||
|
"resolved": "https://registry.npmmirror.com/unplugin-vue-define-options/-/unplugin-vue-define-options-1.3.18.tgz",
|
||||||
|
"integrity": "sha512-AaE10FCccfezT48yyYuUXdnTF9z8vQuXrlpNF5uQtq/AOD2pdkf38vnmJm8bJjpoqEkR6u72wNCJLZKXSUw+Og==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@vue-macros/common": "1.8.0",
|
||||||
|
"ast-walker-scope": "^0.5.0",
|
||||||
|
"unplugin": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"untildify": {
|
"untildify": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
|
||||||
@ -9509,6 +9824,18 @@
|
|||||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"webpack-sources": {
|
||||||
|
"version": "3.2.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||||
|
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"webpack-virtual-modules": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"whatwg-encoding": {
|
"whatwg-encoding": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"element-plus": "^2.3.7",
|
"element-plus": "^2.3.14",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
@ -39,6 +39,7 @@
|
|||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"sass": "^1.66.1",
|
"sass": "^1.66.1",
|
||||||
"typescript": "~5.1.6",
|
"typescript": "~5.1.6",
|
||||||
|
"unplugin-vue-define-options": "^1.3.18",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vitest": "^0.34.2",
|
"vitest": "^0.34.2",
|
||||||
"vue-tsc": "^1.8.8"
|
"vue-tsc": "^1.8.8"
|
||||||
|
|||||||
@ -10,6 +10,9 @@ const hasPermissionChild = (permission: Role | string | Permission | ComplexPerm
|
|||||||
const userStore = useUserStore(store)
|
const userStore = useUserStore(store)
|
||||||
const permissions = userStore.getPermissions()
|
const permissions = userStore.getPermissions()
|
||||||
const role = userStore.getRole()
|
const role = userStore.getRole()
|
||||||
|
if (!permission) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if (permission instanceof Role) {
|
if (permission instanceof Role) {
|
||||||
return role === permission.role
|
return role === permission.role
|
||||||
}
|
}
|
||||||
@ -24,6 +27,7 @@ const hasPermissionChild = (permission: Role | string | Permission | ComplexPerm
|
|||||||
if (typeof permission === 'string') {
|
if (typeof permission === 'string') {
|
||||||
return permissions.includes(permission)
|
return permissions.includes(permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { iconMap } from "@/components/icons/index"
|
import { iconMap } from "@/components/icons/index"
|
||||||
|
defineOptions({ name: 'AppIcon' });
|
||||||
withDefaults(defineProps<{
|
withDefaults(defineProps<{
|
||||||
iconName?: string;
|
iconName?: string;
|
||||||
}>(), {
|
}>(), {
|
||||||
|
|||||||
12
ui/src/components/index.ts
Normal file
12
ui/src/components/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { type App } from 'vue'
|
||||||
|
import AppIcon from './icons/AppIcon.vue'
|
||||||
|
import LoginLayout from './layout/login-layout/index.vue'
|
||||||
|
import LoginContainer from './layout/login-container/index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install(app: App) {
|
||||||
|
app.component(AppIcon.name, AppIcon)
|
||||||
|
app.component(LoginLayout.name, LoginLayout)
|
||||||
|
app.component(LoginContainer.name, LoginContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
48
ui/src/components/layout/login-container/index.vue
Normal file
48
ui/src/components/layout/login-container/index.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div class="login-form-container">
|
||||||
|
<div class="login-title">
|
||||||
|
<div class="title flex-center">
|
||||||
|
<div class="logo"></div>
|
||||||
|
<div>{{ title || defaultTitle }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="sub-title" v-if="subTitle">{{ subTitle }}</div>
|
||||||
|
</div>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
const defaultTitle = import.meta.env.VITE_APP_TITLE
|
||||||
|
defineOptions({ name: 'LoginContainer' })
|
||||||
|
defineProps({
|
||||||
|
title: String,
|
||||||
|
subTitle: String
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scope>
|
||||||
|
.login-form-container {
|
||||||
|
width: 420px;
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #101010;
|
||||||
|
height: 60px;
|
||||||
|
.logo {
|
||||||
|
background-image: url('@/assets/logo.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
text-align: center;
|
||||||
|
color: #101010;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,66 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-warp">
|
<div class="login-warp flex-center">
|
||||||
<div class="login-container">
|
<div class="login-container w-full h-full">
|
||||||
<el-row class="container">
|
<el-row class="container w-full h-full">
|
||||||
<el-col :span="14" class="left-container">
|
<el-col
|
||||||
<div class="login-image"></div>
|
:xs="8"
|
||||||
</el-col>
|
:sm="6"
|
||||||
<el-col :span="10" class="right-container">
|
:md="14"
|
||||||
<slot></slot>
|
:lg="14"
|
||||||
</el-col>
|
:xl="14"
|
||||||
|
class="left-container"
|
||||||
</el-row>
|
v-if="screenWidth && screenWidth >= 990"
|
||||||
</div>
|
>
|
||||||
|
<div class="login-image"></div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :sm="24" :md="10" :lg="10" :xl="10" class="right-container flex-center">
|
||||||
|
<slot></slot>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
|
defineOptions({ name: 'LoginLayout' })
|
||||||
|
const screenWidth: Ref<number | null> = ref(null)
|
||||||
|
onMounted(() => {
|
||||||
|
screenWidth.value = document.body.clientWidth
|
||||||
|
window.onresize = () => {
|
||||||
|
return (() => {
|
||||||
|
screenWidth.value = document.body.clientWidth
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scope>
|
<style lang="scss" scope>
|
||||||
.login-warp {
|
.login-warp {
|
||||||
display: flex;
|
height: 100vh;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
.login-image {
|
||||||
align-content: center;
|
background: url(@/assets/login.png) no-repeat;
|
||||||
height: 100%;
|
background-size: 100% 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
.login-container {
|
}
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.container {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.right-container {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 20vh;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.left-container {
|
|
||||||
.login-image {
|
|
||||||
background-image: url('@/assets/login.png');
|
|
||||||
background-size: 100% 100%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="top-bar-container">
|
<div class="top-bar-container">
|
||||||
<div class="app-title-container">
|
<div class="app-title-container">
|
||||||
<div class="app-title-icon"></div>
|
<div class="app-title-icon"></div>
|
||||||
<div class="app-title-text">智能客服</div>
|
<div class="app-title-text">{{ defaultTitle }}</div>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-top-menu-container">
|
<div class="app-top-menu-container">
|
||||||
@ -15,8 +15,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TopMenu from "@/components/layout/top-bar/components/top-menu/index.vue"
|
import TopMenu from '@/components/layout/top-bar/components/top-menu/index.vue'
|
||||||
import Avatar from "@/components/layout/top-bar/components/avatar/index.vue"
|
import Avatar from '@/components/layout/top-bar/components/avatar/index.vue'
|
||||||
|
const defaultTitle = import.meta.env.VITE_APP_TITLE
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.top-bar-container {
|
.top-bar-container {
|
||||||
@ -46,20 +47,18 @@ import Avatar from "@/components/layout/top-bar/components/avatar/index.vue"
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
|
||||||
.app-title-icon {
|
.app-title-icon {
|
||||||
background-image: url('@/assets/logo.png');
|
background-image: url('@/assets/logo.png');
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
width: 48px;
|
width: 40px;
|
||||||
height: 48px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-title-text {
|
.app-title-text {
|
||||||
color: var(--app-base-action-text-color);
|
color: var(--app-base-action-text-color);
|
||||||
font-size: 28px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { hasPermission } from '@/common/permission'
|
|||||||
|
|
||||||
const display = async (el: any, binding: any) => {
|
const display = async (el: any, binding: any) => {
|
||||||
const has = hasPermission(
|
const has = hasPermission(
|
||||||
binding.value.permission ? binding.value.permission : binding.value,
|
binding.value?.permission || binding.value,
|
||||||
binding.value.compare ? binding.value.compare : 'OR'
|
binding.value?.compare || 'OR'
|
||||||
)
|
)
|
||||||
if (!has) {
|
if (!has) {
|
||||||
el.style.display = 'none'
|
el.style.display = 'none'
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
import 'nprogress/nprogress.css'
|
|
||||||
import '@/styles/index.scss'
|
import '@/styles/index.scss'
|
||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import * as ElementPlusIcons from '@element-plus/icons-vue'
|
import * as ElementPlusIcons from '@element-plus/icons-vue'
|
||||||
import 'element-plus/dist/index.css'
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { store } from '@/stores'
|
import { store } from '@/stores'
|
||||||
import theme from '@/theme'
|
import theme from '@/theme'
|
||||||
import directives from '@/directives'
|
import directives from '@/directives'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
|
import Components from '@/components'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.use(directives)
|
app.use(directives)
|
||||||
const ElementPlusIconsVue: object = ElementPlusIcons
|
|
||||||
// 将elementIcon放到全局
|
for (const [key, component] of Object.entries(ElementPlusIcons)) {
|
||||||
app.config.globalProperties.$antIcons = ElementPlusIconsVue
|
app.component(key, component)
|
||||||
|
}
|
||||||
app.use(ElementPlus)
|
app.use(ElementPlus)
|
||||||
|
|
||||||
app.use(theme)
|
app.use(theme)
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
app.use(Components)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export const routes: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'home',
|
||||||
component: () => import('@/views/home/index.vue'),
|
component: () => import('@/components/layout/home-layout/index.vue'),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/first',
|
path: '/first',
|
||||||
@ -27,7 +27,7 @@ export const routes: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: '/setting',
|
path: '/setting',
|
||||||
name: 'setting',
|
name: 'setting',
|
||||||
meta: { icon: 'setting', title: '数据设置', permission: 'SETTING:READ' },
|
meta: { icon: 'setting', title: '系统设置', permission: 'SETTING:READ' },
|
||||||
component: () => import('@/views/setting/index.vue')
|
component: () => import('@/views/setting/index.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -40,17 +40,17 @@ export const routes: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: '/register',
|
path: '/register',
|
||||||
name: 'register',
|
name: 'register',
|
||||||
component: () => import('@/views/register/index.vue')
|
component: () => import('@/views/login/register/index.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/forgot_password',
|
path: '/forgot_password',
|
||||||
name: 'forgot_password',
|
name: 'forgot_password',
|
||||||
component: () => import('@/views/forgot-password/index.vue')
|
component: () => import('@/views/login/forgot-password/index.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/reset_password/:code/:email',
|
path: '/reset_password/:code/:email',
|
||||||
name: 'reset_password',
|
name: 'reset_password',
|
||||||
component: () => import('@/views/reset-password/index.vue')
|
component: () => import('@/views/login/reset-password/index.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)',
|
path: '/:pathMatch(.*)',
|
||||||
|
|||||||
@ -1,10 +1,19 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Helvetica, PingFang SC, Arial, sans-serif;
|
font-family:
|
||||||
|
Helvetica,
|
||||||
|
PingFang SC,
|
||||||
|
Arial,
|
||||||
|
sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
@ -15,7 +24,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
height:100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
@ -34,6 +43,16 @@ a:hover {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 滚动条整体部分
|
// 滚动条整体部分
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 6px; // 纵向滚动条宽度
|
width: 6px; // 纵向滚动条宽度
|
||||||
@ -52,30 +71,68 @@ a:hover {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.h-full {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-1 {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-1 {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.mr-1 {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.mb-1 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.mb-2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-between {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
// 创建表单
|
// 创建表单
|
||||||
.create-catalog-container {
|
.create-catalog-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-top: -20px;
|
margin-top: -20px;
|
||||||
.padding-top-30{
|
.padding-top-30 {
|
||||||
padding-top:30px;
|
padding-top: 30px;
|
||||||
}
|
}
|
||||||
.padding-top-40{
|
.padding-top-40 {
|
||||||
padding-top:40px;
|
padding-top: 40px;
|
||||||
}
|
}
|
||||||
// 表单外套
|
// 表单外套
|
||||||
.form-div{
|
.form-div {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
form{
|
form {
|
||||||
.el-form-item {margin-bottom: 28px;}
|
.el-form-item {
|
||||||
label{
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
color: #1F2329;
|
color: #1f2329;
|
||||||
flex: none;
|
flex: none;
|
||||||
order: 0;
|
order: 0;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
@ -84,13 +141,13 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除按钮样式
|
// 删除按钮样式
|
||||||
.delete-button-class{
|
.delete-button-class {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #646a73
|
color: #646a73;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加按钮样式
|
// 添加按钮样式
|
||||||
.add-button-class{
|
.add-button-class {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 0 solid;
|
border: 0 solid;
|
||||||
//width: 105px;
|
//width: 105px;
|
||||||
@ -102,23 +159,22 @@ a:hover {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
letter-spacing: -0.1px;
|
letter-spacing: -0.1px;
|
||||||
color: #3370FF;
|
color: #3370ff;
|
||||||
.span-class{
|
.span-class {
|
||||||
vertical-align:2px;
|
vertical-align: 2px;
|
||||||
color: #3370FF;
|
color: #3370ff;
|
||||||
padding-left: 5px
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button{
|
button {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
min-width: 80px
|
min-width: 80px;
|
||||||
}
|
}
|
||||||
.save-btn{
|
.save-btn {
|
||||||
background-color: #3370FF;
|
background-color: #3370ff;
|
||||||
}
|
}
|
||||||
.cancel-btn{
|
.cancel-btn {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下方操作按钮区域
|
// 下方操作按钮区域
|
||||||
@ -159,70 +215,65 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 自定义弹出框样式
|
// 自定义弹出框样式
|
||||||
.custom-dialog{
|
.custom-dialog {
|
||||||
//标题样式
|
//标题样式
|
||||||
.el-dialog__header{
|
.el-dialog__header {
|
||||||
padding: 24px !important;
|
padding: 24px !important;
|
||||||
}
|
}
|
||||||
//关闭按钮样式
|
//关闭按钮样式
|
||||||
.el-dialog__headerbtn .el-dialog__close{
|
.el-dialog__headerbtn .el-dialog__close {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
color: #646A73 !important;
|
color: #646a73 !important;
|
||||||
font-size: x-large !important;
|
font-size: x-large !important;
|
||||||
}
|
}
|
||||||
.el-dialog__headerbtn .el-dialog__close:hover{
|
.el-dialog__headerbtn .el-dialog__close:hover {
|
||||||
background: rgba(31, 35, 41, 0.1) !important;
|
background: rgba(31, 35, 41, 0.1) !important;
|
||||||
border-radius: 4px !important;
|
border-radius: 4px !important;
|
||||||
}
|
}
|
||||||
//内容间距
|
//内容间距
|
||||||
.el-dialog__body{
|
.el-dialog__body {
|
||||||
padding: 0px 24px 0px 24px;
|
padding: 0px 24px 0px 24px;
|
||||||
}
|
}
|
||||||
.el-dialog__footer{
|
.el-dialog__footer {
|
||||||
padding-bottom: 29px !important;
|
padding-bottom: 29px !important;
|
||||||
}
|
}
|
||||||
//下方按钮
|
//下方按钮
|
||||||
.footer-btn{
|
.footer-btn {
|
||||||
button{
|
button {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
min-width: 80px
|
min-width: 80px;
|
||||||
}
|
}
|
||||||
.save-btn{
|
.save-btn {
|
||||||
background-color: #3370FF;
|
background-color: #3370ff;
|
||||||
}
|
}
|
||||||
.cancel-btn{
|
.cancel-btn {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-radio-group.el-radio-group{
|
.custom-radio-group.el-radio-group {
|
||||||
border: 1px solid #BBBFC4;
|
border: 1px solid #bbbfc4;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
label{
|
label {
|
||||||
border: 0px solid;
|
border: 0px solid;
|
||||||
padding: 2px 10px 2px 4px;
|
padding: 2px 10px 2px 4px;
|
||||||
}
|
}
|
||||||
.el-radio-button__inner{
|
.el-radio-button__inner {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
.el-radio-button{
|
.el-radio-button {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.el-radio-button is-active{
|
.el-radio-button is-active {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.el-radio-button__original-radio:checked + .el-radio-button__inner{
|
.el-radio-button__original-radio:checked + .el-radio-button__inner {
|
||||||
color: #3370FF;
|
color: #3370ff;
|
||||||
border: 0;
|
border: 0;
|
||||||
box-shadow: 0 0 0 0;
|
box-shadow: 0 0 0 0;
|
||||||
background: rgba(51, 112, 255, 0.1);
|
background: rgba(51, 112, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
// 抽屉样式整体修改
|
|
||||||
.el-drawer{
|
|
||||||
|
|
||||||
.el-drawer__header{
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 24px;
|
|
||||||
height: 56px;
|
|
||||||
border-bottom: 1px solid #D5D6D8;
|
|
||||||
.el-drawer__title {
|
|
||||||
color: #1f2329;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.el-drawer__body{
|
|
||||||
--el-drawer-padding-primary:24px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,3 +6,23 @@
|
|||||||
--el-form-inline-content-width: 100%;
|
--el-form-inline-content-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 抽屉样式整体修改
|
||||||
|
.el-drawer{
|
||||||
|
|
||||||
|
.el-drawer__header{
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 24px;
|
||||||
|
height: 56px;
|
||||||
|
border-bottom: 1px solid #D5D6D8;
|
||||||
|
.el-drawer__title {
|
||||||
|
color: #1f2329;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.el-drawer__body{
|
||||||
|
--el-drawer-padding-primary:24px
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,7 @@
|
|||||||
@use "./variables/index.scss";
|
|
||||||
@use "./app.scss";
|
@import 'element-plus/dist/index.css';
|
||||||
@use "./element-plus.scss";
|
@import './variables.scss';
|
||||||
@use "./drawer.scss";
|
@import './app.scss';
|
||||||
|
@import './element-plus.scss';
|
||||||
|
@import 'nprogress/nprogress.css'
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
@mixin flex-row($justify: flex-start, $align: stretch) {
|
|
||||||
display: flex;
|
|
||||||
@if $justify != flex-start {
|
|
||||||
justify-content: $justify;
|
|
||||||
}
|
|
||||||
@if $align != stretch {
|
|
||||||
align-items: $align;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin variant($color, $background-color, $border-color) {
|
|
||||||
color: $color;
|
|
||||||
background-color: $background-color;
|
|
||||||
border-color: $border-color;
|
|
||||||
}
|
|
||||||
@ -4,4 +4,8 @@
|
|||||||
--app-base-text-hover-color:rgba(51, 112, 255, 1);
|
--app-base-text-hover-color:rgba(51, 112, 255, 1);
|
||||||
--app-base-text-hover-bg-color:rgba(51, 112, 255, 0.1);
|
--app-base-text-hover-bg-color:rgba(51, 112, 255, 0.1);
|
||||||
--app-base-action-text-color:var(--app-base-text-hover-color );
|
--app-base-action-text-color:var(--app-base-text-hover-color );
|
||||||
|
/** header 组件 */
|
||||||
|
--app-header-height: 56px;
|
||||||
|
--app-header-padding: 0 20px;
|
||||||
|
--app-header-bg-color: #252b3c;
|
||||||
}
|
}
|
||||||
@ -1,6 +0,0 @@
|
|||||||
:root{
|
|
||||||
--app-header-height: 56px;
|
|
||||||
--app-header-padding: 0 20px;
|
|
||||||
--app-header-bg-color: #252b3c;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
@use "./header.scss";
|
|
||||||
@use "./app.scss";
|
|
||||||
@ -1,169 +0,0 @@
|
|||||||
<template>
|
|
||||||
<LoiginLayout>
|
|
||||||
<div class="register-form-container">
|
|
||||||
<div class="register-form-title">
|
|
||||||
<div class="title">
|
|
||||||
<div class="logo"></div>
|
|
||||||
<div>智能客服</div>
|
|
||||||
</div>
|
|
||||||
<div class="sub-title">忘记密码</div>
|
|
||||||
</div>
|
|
||||||
<el-form class="register-form" ref="resetPasswordFormRef" :model="CheckEmailForm" :rules="rules">
|
|
||||||
|
|
||||||
<el-form-item prop="email">
|
|
||||||
<el-input size="large" class="input-item" v-model="CheckEmailForm.email" placeholder="请输入邮箱">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="UserFilled" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="code">
|
|
||||||
<el-input size="large" class="code-input" v-model="CheckEmailForm.code" placeholder="请输入验证码">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Key" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
<el-button size="large" class="send-email-button" @click="sendEmail"
|
|
||||||
:loading="loading">获取验证码</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<el-button type="primary" class="register-button" @click="checkCode">立即验证</el-button>
|
|
||||||
<div class="operate-container">
|
|
||||||
<span class="register" @click="router.push('login')">< 返回登陆</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</LoiginLayout>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from "vue"
|
|
||||||
import { UserFilled, Key } from '@element-plus/icons-vue'
|
|
||||||
import type {
|
|
||||||
CheckCodeRequest
|
|
||||||
} from "@/api/user/type"
|
|
||||||
import LoiginLayout from "@/components/layout/login-layout/index.vue"
|
|
||||||
import { useRouter } from "vue-router"
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
import UserApi from "@/api/user/index"
|
|
||||||
import { ElMessage } from "element-plus"
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const CheckEmailForm = ref<CheckCodeRequest>({
|
|
||||||
email: "",
|
|
||||||
code: "",
|
|
||||||
type: 'reset_password'
|
|
||||||
});
|
|
||||||
|
|
||||||
const resetPasswordFormRef = ref<FormInstance>()
|
|
||||||
const rules = ref<FormRules<CheckCodeRequest>>({
|
|
||||||
email: [
|
|
||||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
|
||||||
{
|
|
||||||
validator: (rule, value, callback) => {
|
|
||||||
const emailRegExp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/
|
|
||||||
if ((!emailRegExp.test(value) && value != '')) {
|
|
||||||
callback(new Error('请输入有效邮箱格式!'));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
code: [
|
|
||||||
{ required: true, message: '请输入验证码' }
|
|
||||||
]
|
|
||||||
|
|
||||||
})
|
|
||||||
const loading = ref<boolean>(false)
|
|
||||||
|
|
||||||
const checkCode = () => {
|
|
||||||
resetPasswordFormRef.value?.validate()
|
|
||||||
.then(() => UserApi.checkCode(CheckEmailForm.value, loading))
|
|
||||||
.then(() => router.push({ name: 'reset_password', params: CheckEmailForm.value }))
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 发送验证码
|
|
||||||
*/
|
|
||||||
const sendEmail = () => {
|
|
||||||
resetPasswordFormRef.value?.validateField("email", (v: boolean) => {
|
|
||||||
if (v) {
|
|
||||||
UserApi.sendEmit(CheckEmailForm.value.email, "reset_password", loading)
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success("发送验证码成功")
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scope>
|
|
||||||
.register-form-container {
|
|
||||||
width: 420px;
|
|
||||||
|
|
||||||
.code-input {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-email-button {
|
|
||||||
margin-left: 12px;
|
|
||||||
width: 158px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-form-title {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
background-image: url('@/assets/logo.png');
|
|
||||||
background-size: 100% 100%;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 900;
|
|
||||||
color: #101010;
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-title {
|
|
||||||
color: #101010;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.operate-container {
|
|
||||||
margin-top: 12px;
|
|
||||||
color: rgba(51, 112, 255, 1);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.register {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forgot-password {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-button {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
119
ui/src/views/login/forgot-password/index.vue
Normal file
119
ui/src/views/login/forgot-password/index.vue
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<login-layout>
|
||||||
|
<LoginContainer>
|
||||||
|
<h3 class="mb-2">忘记密码</h3>
|
||||||
|
<el-form
|
||||||
|
class="register-form"
|
||||||
|
ref="resetPasswordFormRef"
|
||||||
|
:model="CheckEmailForm"
|
||||||
|
:rules="rules"
|
||||||
|
>
|
||||||
|
<el-form-item prop="email">
|
||||||
|
<el-input
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="CheckEmailForm.email"
|
||||||
|
placeholder="请输入邮箱"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="UserFilled" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="code">
|
||||||
|
<div class="flex-between w-full">
|
||||||
|
<el-input
|
||||||
|
size="large"
|
||||||
|
class="code-input"
|
||||||
|
v-model="CheckEmailForm.code"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Key" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
size="large"
|
||||||
|
class="send-email-button ml-1"
|
||||||
|
@click="sendEmail"
|
||||||
|
:loading="loading"
|
||||||
|
>获取验证码</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-button type="primary" class="login-submit-button w-full" @click="checkCode"
|
||||||
|
>立即验证</el-button
|
||||||
|
>
|
||||||
|
<div class="operate-container mt-1">
|
||||||
|
<el-button
|
||||||
|
class="register"
|
||||||
|
@click="router.push('/login')"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="DArrowLeft"
|
||||||
|
>
|
||||||
|
返回登录
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</LoginContainer>
|
||||||
|
</login-layout>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { UserFilled, Key } from '@element-plus/icons-vue'
|
||||||
|
import type { CheckCodeRequest } from '@/api/user/type'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import UserApi from '@/api/user/index'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const CheckEmailForm = ref<CheckCodeRequest>({
|
||||||
|
email: '',
|
||||||
|
code: '',
|
||||||
|
type: 'reset_password'
|
||||||
|
})
|
||||||
|
|
||||||
|
const resetPasswordFormRef = ref<FormInstance>()
|
||||||
|
const rules = ref<FormRules<CheckCodeRequest>>({
|
||||||
|
email: [
|
||||||
|
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const emailRegExp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/
|
||||||
|
if (!emailRegExp.test(value) && value != '') {
|
||||||
|
callback(new Error('请输入有效邮箱格式!'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
code: [{ required: true, message: '请输入验证码' }]
|
||||||
|
})
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
|
||||||
|
const checkCode = () => {
|
||||||
|
resetPasswordFormRef.value
|
||||||
|
?.validate()
|
||||||
|
.then(() => UserApi.checkCode(CheckEmailForm.value, loading))
|
||||||
|
.then(() => router.push({ name: 'reset_password', params: CheckEmailForm.value }))
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 发送验证码
|
||||||
|
*/
|
||||||
|
const sendEmail = () => {
|
||||||
|
resetPasswordFormRef.value?.validateField('email', (v: boolean) => {
|
||||||
|
if (v) {
|
||||||
|
UserApi.sendEmit(CheckEmailForm.value.email, 'reset_password', loading).then(() => {
|
||||||
|
ElMessage.success('发送验证码成功')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scope>
|
||||||
|
@import '../index.scss';
|
||||||
|
</style>
|
||||||
4
ui/src/views/login/index.scss
Normal file
4
ui/src/views/login/index.scss
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.login-submit-button {
|
||||||
|
margin-top: 12px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
@ -1,152 +1,102 @@
|
|||||||
<template>
|
<template>
|
||||||
<LoiginLayout v-loading="loading">
|
<login-layout v-loading="loading">
|
||||||
<div class="login-form-container">
|
<LoginContainer subTitle="欢迎使用智能客服管理平台">
|
||||||
<div class="login-form-title">
|
<el-form class="login-form" :rules="rules" :model="loginForm" ref="loginFormRef">
|
||||||
<div class="title">
|
<el-form-item>
|
||||||
<div class="logo"></div>
|
<el-input
|
||||||
<div>智能客服</div>
|
size="large"
|
||||||
</div>
|
class="input-item"
|
||||||
<div class="sub-title">欢迎使用智能客服管理平台</div>
|
v-model="loginForm.username"
|
||||||
</div>
|
placeholder="请输入用户名"
|
||||||
<el-form class="login-form" :rules="rules" :model="loginForm" ref="loginFormRef">
|
>
|
||||||
<el-form-item>
|
<template #prepend>
|
||||||
<el-input size="large" class="input-item" v-model="loginForm.username" placeholder="请输入用户名">
|
<el-button icon="UserFilled" />
|
||||||
<template #prepend>
|
</template>
|
||||||
<el-button :icon="UserFilled" />
|
</el-input>
|
||||||
</template>
|
</el-form-item>
|
||||||
</el-input>
|
<el-form-item>
|
||||||
|
<el-input
|
||||||
</el-form-item>
|
type="password"
|
||||||
<el-form-item>
|
size="large"
|
||||||
<el-input type="password" size="large" class="input-item" v-model="loginForm.password"
|
class="input-item"
|
||||||
placeholder="请输入密码">
|
v-model="loginForm.password"
|
||||||
|
placeholder="请输入密码"
|
||||||
<template #prepend>
|
show-password
|
||||||
<el-button :icon="Lock" />
|
>
|
||||||
</template>
|
<template #prepend>
|
||||||
</el-input>
|
<el-button icon="Lock" />
|
||||||
</el-form-item>
|
</template>
|
||||||
</el-form>
|
</el-input>
|
||||||
<div class="operate-container">
|
</el-form-item>
|
||||||
<span class="register" @click="router.push('register')">注册</span>
|
</el-form>
|
||||||
<span class="forgot-password" @click="router.push('forgot_password')">忘记密码</span>
|
<div class="operate-container flex-between">
|
||||||
</div>
|
<el-button class="register" @click="router.push('/register')" link type="primary">
|
||||||
<el-button type="primary" class="login-button" @click="login">登录</el-button>
|
注册
|
||||||
</div>
|
</el-button>
|
||||||
</LoiginLayout>
|
<el-button
|
||||||
|
class="forgot-password"
|
||||||
|
@click="router.push('/forgot_password')"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
忘记密码
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" class="login-submit-button w-full" @click="login">登录</el-button>
|
||||||
|
</LoginContainer>
|
||||||
|
</login-layout>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue"
|
import { ref } from 'vue'
|
||||||
import type { LoginRequest } from "@/api/user/type"
|
import type { LoginRequest } from '@/api/user/type'
|
||||||
import { UserFilled, Lock } from '@element-plus/icons-vue'
|
import { useRouter } from 'vue-router'
|
||||||
import LoiginLayout from "@/components/layout/login-layout/index.vue"
|
|
||||||
import { useRouter } from "vue-router"
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import { useUserStore } from "@/stores/user"
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false)
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const loginForm = ref<LoginRequest>({
|
const loginForm = ref<LoginRequest>({
|
||||||
username: '',
|
username: '',
|
||||||
password: ''
|
password: ''
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|
||||||
const rules = ref<FormRules<LoginRequest>>({
|
const rules = ref<FormRules<LoginRequest>>({
|
||||||
username: [
|
username: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入用户名",
|
message: '请输入用户名',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入密码",
|
message: '请输入密码',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
min: 6,
|
min: 6,
|
||||||
max: 30,
|
max: 30,
|
||||||
message: "长度在 6 到 30 个字符",
|
message: '长度在 6 到 30 个字符',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
const loginFormRef = ref<FormInstance>()
|
const loginFormRef = ref<FormInstance>()
|
||||||
|
|
||||||
const login = () => {
|
const login = () => {
|
||||||
loginFormRef.value?.validate().then(() => {
|
loginFormRef.value?.validate().then(() => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
userStore.login(loginForm.value.username, loginForm.value.password)
|
userStore
|
||||||
.then(() => { router.push({ name: 'home' }) })
|
.login(loginForm.value.username, loginForm.value.password)
|
||||||
.finally(() => loading.value = false)
|
.then(() => {
|
||||||
})
|
router.push({ name: 'home' })
|
||||||
|
})
|
||||||
|
.finally(() => (loading.value = false))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scope>
|
<style lang="scss" scope>
|
||||||
.login-form-container {
|
@import './index.scss';
|
||||||
width: 420px;
|
|
||||||
|
|
||||||
|
|
||||||
.login-form-title {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
background-image: url('@/assets/logo.png');
|
|
||||||
background-size: 100% 100%;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 900;
|
|
||||||
color: #101010;
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: #101010;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.operate-container {
|
|
||||||
color: rgba(51, 112, 255, 1);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.register {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forgot-password {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-button {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
203
ui/src/views/login/register/index.vue
Normal file
203
ui/src/views/login/register/index.vue
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<template>
|
||||||
|
<login-layout>
|
||||||
|
<LoginContainer>
|
||||||
|
<h3 class="mb-2">注册</h3>
|
||||||
|
<el-form class="register-form" :model="registerForm" :rules="rules" ref="registerFormRef">
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="registerForm.username"
|
||||||
|
placeholder="请输入用户名"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="UserFilled" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="registerForm.password"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
show-password
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Lock" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="repassword">
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="registerForm.re_password"
|
||||||
|
placeholder="请输入确认密码"
|
||||||
|
show-password
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Lock" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="email">
|
||||||
|
<el-input
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="registerForm.email"
|
||||||
|
placeholder="请输入邮箱"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Message" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="code">
|
||||||
|
<div class="flex-between w-full">
|
||||||
|
<el-input
|
||||||
|
size="large"
|
||||||
|
class="code-input"
|
||||||
|
v-model="registerForm.code"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Key" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
size="large"
|
||||||
|
class="send-email-button ml-1"
|
||||||
|
@click="sendEmail"
|
||||||
|
:loading="sendEmailLoading"
|
||||||
|
>获取验证码</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-button type="primary" class="login-submit-button w-full" @click="register"
|
||||||
|
>注册</el-button
|
||||||
|
>
|
||||||
|
<div class="operate-container mt-1">
|
||||||
|
<el-button
|
||||||
|
class="register"
|
||||||
|
@click="router.push('/login')"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="DArrowLeft"
|
||||||
|
>
|
||||||
|
返回登录
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</LoginContainer>
|
||||||
|
</login-layout>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import type { RegisterRequest } from '@/api/user/type'
|
||||||
|
import { UserFilled, Lock, Message, Key } from '@element-plus/icons-vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import UserApi from '@/api/user/index'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const registerForm = ref<RegisterRequest>({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
re_password: '',
|
||||||
|
email: '',
|
||||||
|
code: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = ref<FormRules<RegisterRequest>>({
|
||||||
|
username: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入用户名',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入密码',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 6,
|
||||||
|
max: 30,
|
||||||
|
message: '长度在 6 到 30 个字符',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
re_password: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入确认密码',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 6,
|
||||||
|
max: 30,
|
||||||
|
message: '长度在 6 到 30 个字符',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (registerForm.value.password != registerForm.value.re_password) {
|
||||||
|
callback(new Error('密码不一致'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
email: [
|
||||||
|
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const emailRegExp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/
|
||||||
|
if (!emailRegExp.test(value) && value != '') {
|
||||||
|
callback(new Error('请输入有效邮箱格式!'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
code: [{ required: true, message: '请输入验证码' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
const registerFormRef = ref<FormInstance>()
|
||||||
|
const register = () => {
|
||||||
|
registerFormRef.value
|
||||||
|
?.validate()
|
||||||
|
.then(() => {
|
||||||
|
return UserApi.register(registerForm.value)
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
router.push('login')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const sendEmailLoading = ref<boolean>(false)
|
||||||
|
/**
|
||||||
|
* 发送验证码
|
||||||
|
*/
|
||||||
|
const sendEmail = () => {
|
||||||
|
registerFormRef.value?.validateField('email', (v: boolean) => {
|
||||||
|
if (v) {
|
||||||
|
UserApi.sendEmit(registerForm.value.email, 'register', sendEmailLoading).then(() => {
|
||||||
|
ElMessage.success('发送验证码成功')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scope>
|
||||||
|
@import '../index.scss';
|
||||||
|
</style>
|
||||||
137
ui/src/views/login/reset-password/index.vue
Normal file
137
ui/src/views/login/reset-password/index.vue
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<login-layout>
|
||||||
|
<LoginContainer>
|
||||||
|
<h3 class="mb-2">修改密码</h3>
|
||||||
|
<el-form
|
||||||
|
class="reset-password-form"
|
||||||
|
ref="resetPasswordFormRef"
|
||||||
|
:model="resetPasswordForm"
|
||||||
|
:rules="rules"
|
||||||
|
>
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="resetPasswordForm.password"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
show-password
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Lock" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="re_password">
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
class="input-item"
|
||||||
|
v-model="resetPasswordForm.re_password"
|
||||||
|
placeholder="请输入确认密码"
|
||||||
|
show-password
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-button :icon="Lock" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-button type="primary" class="login-submit-button w-full" @click="resetPassword"
|
||||||
|
>确认修改</el-button
|
||||||
|
>
|
||||||
|
<div class="operate-container mt-1">
|
||||||
|
<el-button
|
||||||
|
class="register"
|
||||||
|
@click="router.push('/login')"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="DArrowLeft"
|
||||||
|
>
|
||||||
|
返回登录
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</LoginContainer>
|
||||||
|
</login-layout>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import type { ResetPasswordRequest } from '@/api/user/type'
|
||||||
|
import { Lock } from '@element-plus/icons-vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import UserApi from '@/api/user/index'
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const resetPasswordForm = ref<ResetPasswordRequest>({
|
||||||
|
password: '',
|
||||||
|
re_password: '',
|
||||||
|
email: '',
|
||||||
|
code: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const code = route.params.code
|
||||||
|
const email = route.params.email
|
||||||
|
if (code && email) {
|
||||||
|
resetPasswordForm.value.code = code as string
|
||||||
|
resetPasswordForm.value.email = email as string
|
||||||
|
} else {
|
||||||
|
router.push('forgot_password')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = ref<FormRules<ResetPasswordRequest>>({
|
||||||
|
password: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入密码',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 6,
|
||||||
|
max: 30,
|
||||||
|
message: '长度在 6 到 30 个字符',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
re_password: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入确认密码',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 6,
|
||||||
|
max: 30,
|
||||||
|
message: '长度在 6 到 30 个字符',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||||
|
callback(new Error('密码不一致'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const resetPasswordFormRef = ref<FormInstance>()
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
const resetPassword = () => {
|
||||||
|
resetPasswordFormRef.value
|
||||||
|
?.validate()
|
||||||
|
.then(() => UserApi.resetPassword(resetPasswordForm.value, loading))
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('修改密码成功')
|
||||||
|
router.push({ name: 'login' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scope>
|
||||||
|
@import '../index.scss';
|
||||||
|
</style>
|
||||||
@ -1,236 +0,0 @@
|
|||||||
<template>
|
|
||||||
<LoiginLayout>
|
|
||||||
<div class="register-form-container">
|
|
||||||
<div class="register-form-title">
|
|
||||||
<div class="title">
|
|
||||||
<div class="logo"></div>
|
|
||||||
<div>智能客服</div>
|
|
||||||
</div>
|
|
||||||
<div class="sub-title">修改密码</div>
|
|
||||||
</div>
|
|
||||||
<el-form class="register-form" :model="registerForm" :rules="rules" ref="registerFormRef">
|
|
||||||
<el-form-item prop="username">
|
|
||||||
<el-input size="large" class="input-item" v-model="registerForm.username" placeholder="请输入用户名">
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="UserFilled" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input type="password" size="large" class="input-item" v-model="registerForm.password"
|
|
||||||
placeholder="请输入密码">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Lock" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="repassword">
|
|
||||||
<el-input type="password" size="large" class="input-item" v-model="registerForm.re_password"
|
|
||||||
placeholder="请输入确认密码">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Lock" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="email">
|
|
||||||
<el-input size="large" class="input-item" v-model="registerForm.email" placeholder="请输入邮箱">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Message" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="code">
|
|
||||||
<el-input size="large" class="code-input" v-model="registerForm.code" placeholder="请输入验证码">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Key" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
<el-button size="large" class="send-email-button" @click="sendEmail"
|
|
||||||
:loading="sendEmailLoading">获取验证码</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<el-button type="primary" class="register-button" @click="register">注册</el-button>
|
|
||||||
<div class="operate-container">
|
|
||||||
<span class="register" @click="router.push('login')">< 返回登陆</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</LoiginLayout>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from "vue"
|
|
||||||
import type { RegisterRequest } from "@/api/user/type"
|
|
||||||
import { UserFilled, Lock, Message, Key } from '@element-plus/icons-vue'
|
|
||||||
import LoiginLayout from "@/components/layout/login-layout/index.vue"
|
|
||||||
import { useRouter } from "vue-router"
|
|
||||||
import UserApi from "@/api/user/index"
|
|
||||||
import { ElMessage } from "element-plus"
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const registerForm = ref<RegisterRequest>({
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
re_password: '',
|
|
||||||
email: '',
|
|
||||||
code: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const rules = ref<FormRules<RegisterRequest>>({
|
|
||||||
username: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: "请输入用户名",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
password: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: "请输入密码",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 6,
|
|
||||||
max: 30,
|
|
||||||
message: "长度在 6 到 30 个字符",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
re_password: [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入确认密码',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 6,
|
|
||||||
max: 30,
|
|
||||||
message: "长度在 6 到 30 个字符",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: (rule, value, callback) => {
|
|
||||||
if (registerForm.value.password != registerForm.value.re_password) {
|
|
||||||
callback(new Error('密码不一致'));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
email: [
|
|
||||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
|
||||||
{
|
|
||||||
validator: (rule, value, callback) => {
|
|
||||||
const emailRegExp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/
|
|
||||||
if ((!emailRegExp.test(value) && value != '')) {
|
|
||||||
callback(new Error('请输入有效邮箱格式!'));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
code: [
|
|
||||||
{ required: true, message: '请输入验证码' }
|
|
||||||
]
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
const registerFormRef = ref<FormInstance>();
|
|
||||||
const register = () => {
|
|
||||||
registerFormRef.value?.validate().then(() => {
|
|
||||||
return UserApi.register(registerForm.value)
|
|
||||||
}).then(() => {
|
|
||||||
router.push("login")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const sendEmailLoading = ref<boolean>(false);
|
|
||||||
/**
|
|
||||||
* 发送验证码
|
|
||||||
*/
|
|
||||||
const sendEmail = () => {
|
|
||||||
registerFormRef.value?.validateField("email", (v: boolean) => {
|
|
||||||
if (v) {
|
|
||||||
UserApi.sendEmit(registerForm.value.email, "register",sendEmailLoading)
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success("发送验证码成功")
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scope>
|
|
||||||
.register-form-container {
|
|
||||||
width: 420px;
|
|
||||||
|
|
||||||
.code-input {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-email-button {
|
|
||||||
margin-left: 12px;
|
|
||||||
width: 158px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-form-title {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
background-image: url('@/assets/logo.png');
|
|
||||||
background-size: 100% 100%;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 900;
|
|
||||||
color: #101010;
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-title {
|
|
||||||
color: #101010;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.operate-container {
|
|
||||||
margin-top: 12px;
|
|
||||||
color: rgba(51, 112, 255, 1);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.register {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forgot-password {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-button {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
<template>
|
|
||||||
<LoiginLayout>
|
|
||||||
<div class="register-form-container">
|
|
||||||
<div class="register-form-title">
|
|
||||||
<div class="title">
|
|
||||||
<div class="logo"></div>
|
|
||||||
<div>智能客服</div>
|
|
||||||
</div>
|
|
||||||
<div class="sub-title">修改密码</div>
|
|
||||||
</div>
|
|
||||||
<el-form class="reset-password-form" ref="resetPasswordFormRef" :model="resetPasswordForm" :rules="rules">
|
|
||||||
|
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input type="password" size="large" class="input-item" v-model="resetPasswordForm.password"
|
|
||||||
placeholder="请输入密码">
|
|
||||||
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Lock" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="re_password">
|
|
||||||
<el-input type="password" size="large" class="input-item" v-model="resetPasswordForm.re_password"
|
|
||||||
placeholder="请输入确认密码">
|
|
||||||
<template #prepend>
|
|
||||||
<el-button :icon="Lock" />
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<el-button type="primary" class="register-button" @click="resetPassword">确认修改</el-button>
|
|
||||||
<div class="operate-container">
|
|
||||||
<span class="register" @click="router.push('login')">< 返回登陆</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</LoiginLayout>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, onMounted } from "vue"
|
|
||||||
import type { ResetPasswordRequest } from "@/api/user/type"
|
|
||||||
import { Lock } from '@element-plus/icons-vue'
|
|
||||||
import LoiginLayout from "@/components/layout/login-layout/index.vue"
|
|
||||||
import { useRouter, useRoute } from "vue-router"
|
|
||||||
import { ElMessage } from "element-plus"
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
import UserApi from "@/api/user/index"
|
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
|
||||||
const resetPasswordForm = ref<ResetPasswordRequest>({
|
|
||||||
password: '',
|
|
||||||
re_password: '',
|
|
||||||
email: '',
|
|
||||||
code: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const code = route.params.code;
|
|
||||||
const email = route.params.email;
|
|
||||||
if (code && email) {
|
|
||||||
resetPasswordForm.value.code = code as string;
|
|
||||||
resetPasswordForm.value.email = email as string;
|
|
||||||
} else {
|
|
||||||
router.push('forgot_password')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const rules = ref<FormRules<ResetPasswordRequest>>({
|
|
||||||
|
|
||||||
password: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: "请输入密码",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 6,
|
|
||||||
max: 30,
|
|
||||||
message: "长度在 6 到 30 个字符",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
re_password: [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入确认密码',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 6,
|
|
||||||
max: 30,
|
|
||||||
message: "长度在 6 到 30 个字符",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: (rule, value, callback) => {
|
|
||||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
|
||||||
callback(new Error('密码不一致'));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
|
|
||||||
})
|
|
||||||
const resetPasswordFormRef = ref<FormInstance>();
|
|
||||||
const loading = ref<boolean>(false);
|
|
||||||
const resetPassword = () => {
|
|
||||||
resetPasswordFormRef.value?.validate()
|
|
||||||
.then(() => UserApi.resetPassword(resetPasswordForm.value, loading))
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success("修改密码成功")
|
|
||||||
router.push({ name: 'login' })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scope>
|
|
||||||
.register-form-container {
|
|
||||||
width: 420px;
|
|
||||||
|
|
||||||
.code-input {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-email-button {
|
|
||||||
margin-left: 12px;
|
|
||||||
width: 158px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-form-title {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
background-image: url('@/assets/logo.png');
|
|
||||||
background-size: 100% 100%;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 900;
|
|
||||||
color: #101010;
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-title {
|
|
||||||
color: #101010;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.operate-container {
|
|
||||||
margin-top: 12px;
|
|
||||||
color: rgba(51, 112, 255, 1);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.register {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forgot-password {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-button {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,7 +1,10 @@
|
|||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
import type { ProxyOptions } from 'vite'
|
import type { ProxyOptions } from 'vite'
|
||||||
import { defineConfig, loadEnv } from 'vite'
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
|
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import DefineOptions from 'unplugin-vue-define-options/vite'
|
||||||
|
|
||||||
const envDir = './env'
|
const envDir = './env'
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
@ -13,10 +16,11 @@ export default defineConfig(({ mode }) => {
|
|||||||
rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/')
|
rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/')
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
preflight: false,
|
||||||
lintOnSave: false,
|
lintOnSave: false,
|
||||||
base: ENV.VITE_BASE_PATH,
|
base: ENV.VITE_BASE_PATH,
|
||||||
envDir: envDir,
|
envDir: envDir,
|
||||||
plugins: [vue()],
|
plugins: [vue(), DefineOptions()],
|
||||||
server: {
|
server: {
|
||||||
cors: true,
|
cors: true,
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user