|
@@ -1,78 +1,83 @@
|
|
|
<template>
|
|
|
<div class="login-container">
|
|
|
+ <div class="gradient-background"></div>
|
|
|
+ <canvas id="canvas1"></canvas>
|
|
|
<div class="form-content">
|
|
|
- <div class="title-container">
|
|
|
+ <!-- <div class="title-container">
|
|
|
<img src="../../assets/images/login-head.png" class="images" />
|
|
|
- </div>
|
|
|
- <el-form
|
|
|
- v-if="loginOrRetrieve == 'login'"
|
|
|
- ref="loginForm"
|
|
|
- :model="loginForm"
|
|
|
- :rules="loginRules"
|
|
|
- class="login-form"
|
|
|
- autocomplete="on"
|
|
|
- label-position="left"
|
|
|
- >
|
|
|
- <el-form-item prop="username">
|
|
|
- <span class="svg-container">
|
|
|
- <svg-icon icon-class="user" />
|
|
|
- </span>
|
|
|
- <el-input
|
|
|
- ref="username"
|
|
|
- v-model="loginForm.username"
|
|
|
- placeholder="登录用户名"
|
|
|
- name="username"
|
|
|
- type="text"
|
|
|
- tabindex="1"
|
|
|
- autocomplete="on"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-tooltip
|
|
|
- v-model="capsTooltip"
|
|
|
- content="Caps lock is On"
|
|
|
- placement="right"
|
|
|
- manual
|
|
|
+ </div> -->
|
|
|
+ <div class="login_form" v-if="loginOrRetrieve == 'login'">
|
|
|
+ <h2>AI知识库管理</h2>
|
|
|
+ <el-form
|
|
|
+ ref="loginForm"
|
|
|
+ :model="loginForm"
|
|
|
+ :rules="loginRules"
|
|
|
+ class="login-form"
|
|
|
+ autocomplete="on"
|
|
|
+ label-position="left"
|
|
|
>
|
|
|
- <el-form-item prop="password">
|
|
|
+ <el-form-item prop="username">
|
|
|
<span class="svg-container">
|
|
|
- <svg-icon icon-class="password" />
|
|
|
+ <svg-icon icon-class="user" />
|
|
|
</span>
|
|
|
<el-input
|
|
|
- :key="passwordType"
|
|
|
- ref="password"
|
|
|
- v-model="loginForm.password"
|
|
|
- :type="passwordType"
|
|
|
- placeholder="登录密码"
|
|
|
- name="password"
|
|
|
- tabindex="2"
|
|
|
+ ref="username"
|
|
|
+ v-model="loginForm.username"
|
|
|
+ placeholder="登录用户名"
|
|
|
+ name="username"
|
|
|
+ type="text"
|
|
|
+ tabindex="1"
|
|
|
autocomplete="on"
|
|
|
- @keyup.native="checkCapslock"
|
|
|
- @blur="capsTooltip = false"
|
|
|
- @keyup.enter.native="handleLogin"
|
|
|
/>
|
|
|
- <span class="show-pwd" @click="showPwd">
|
|
|
- <svg-icon
|
|
|
- :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
|
|
|
- />
|
|
|
- </span>
|
|
|
</el-form-item>
|
|
|
- </el-tooltip>
|
|
|
|
|
|
- <el-button
|
|
|
- :loading="loading"
|
|
|
- type="primary"
|
|
|
- style="width: 100%; margin-bottom: 30px"
|
|
|
- @click="handleLogin"
|
|
|
- >立即登录</el-button
|
|
|
- >
|
|
|
- <div class="tips">
|
|
|
- <div @click="Retrieve('retrieve')" style="cursor: pointer">
|
|
|
- 找回密码
|
|
|
+ <el-tooltip
|
|
|
+ v-model="capsTooltip"
|
|
|
+ content="Caps lock is On"
|
|
|
+ placement="right"
|
|
|
+ manual
|
|
|
+ >
|
|
|
+ <el-form-item prop="password">
|
|
|
+ <span class="svg-container">
|
|
|
+ <svg-icon icon-class="password" />
|
|
|
+ </span>
|
|
|
+ <el-input
|
|
|
+ :key="passwordType"
|
|
|
+ ref="password"
|
|
|
+ v-model="loginForm.password"
|
|
|
+ :type="passwordType"
|
|
|
+ placeholder="登录密码"
|
|
|
+ name="password"
|
|
|
+ tabindex="2"
|
|
|
+ autocomplete="on"
|
|
|
+ @keyup.native="checkCapslock"
|
|
|
+ @blur="capsTooltip = false"
|
|
|
+ @keyup.enter.native="handleLogin"
|
|
|
+ />
|
|
|
+ <span class="show-pwd" @click="showPwd">
|
|
|
+ <svg-icon
|
|
|
+ :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-tooltip>
|
|
|
+ <div class="tips">
|
|
|
+ <div @click="Retrieve('retrieve')" style="cursor: pointer">
|
|
|
+ 找回密码?
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-form>
|
|
|
- <div v-if="loginOrRetrieve == 'retrieve'">
|
|
|
+ <el-button
|
|
|
+ :loading="loading"
|
|
|
+ class="btns"
|
|
|
+ type="primary"
|
|
|
+ style="width: 100%; margin-bottom: 30px"
|
|
|
+ @click="handleLogin"
|
|
|
+ >立即登录</el-button
|
|
|
+ >
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div class="login_form" v-if="loginOrRetrieve == 'retrieve'">
|
|
|
+ <h2>AI知识库管理</h2>
|
|
|
<el-form
|
|
|
ref="RetrieveForm"
|
|
|
:model="RetrieveForm"
|
|
@@ -109,7 +114,7 @@
|
|
|
autocomplete="on"
|
|
|
/>
|
|
|
<span class="show-pwd">
|
|
|
- <el-button :disabled="isDisabled" @click="getCode">
|
|
|
+ <el-button type="primary" :disabled="isDisabled" @click="getCode">
|
|
|
{{ buttonText }}
|
|
|
</el-button>
|
|
|
</span>
|
|
@@ -176,17 +181,19 @@
|
|
|
</span>
|
|
|
</el-form-item>
|
|
|
</el-tooltip>
|
|
|
-
|
|
|
+ <div class="tips">
|
|
|
+ <div @click="Retrieve('login')" style="cursor: pointer">
|
|
|
+ 返回登录
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<el-button
|
|
|
:loading="loading"
|
|
|
type="primary"
|
|
|
+ class="btns"
|
|
|
style="width: 100%; margin-bottom: 30px"
|
|
|
@click="retPass"
|
|
|
>重置密码</el-button
|
|
|
>
|
|
|
- <div class="tips">
|
|
|
- <div @click="Retrieve('login')" style="cursor: pointer">返回登录</div>
|
|
|
- </div>
|
|
|
</el-form>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -316,6 +323,7 @@ export default {
|
|
|
} else if (this.loginForm.password === "") {
|
|
|
this.$refs.password.focus();
|
|
|
}
|
|
|
+ this.initParticles();
|
|
|
},
|
|
|
destroyed() {
|
|
|
// window.removeEventListener('storage', this.afterQRScan)
|
|
@@ -403,7 +411,7 @@ export default {
|
|
|
.dispatch("user/login", this.loginForm)
|
|
|
.then(() => {
|
|
|
this.$router.push({
|
|
|
- path: "/knowledge/knowledgeMenu/index",/* this.redirect || */
|
|
|
+ path: this.redirect || "/",
|
|
|
query: this.otherQuery,
|
|
|
});
|
|
|
this.loading = false;
|
|
@@ -447,12 +455,181 @@ export default {
|
|
|
Retrieve(val) {
|
|
|
this.loginOrRetrieve = val;
|
|
|
},
|
|
|
+
|
|
|
+ /* 粒子动画 */
|
|
|
+ initParticles() {
|
|
|
+ const canvas = document.getElementById("canvas1");
|
|
|
+ const ctx = canvas.getContext("2d");
|
|
|
+ canvas.width = window.innerWidth;
|
|
|
+ canvas.height = window.innerHeight;
|
|
|
+
|
|
|
+ let area = Math.sqrt(canvas.width * canvas.height);
|
|
|
+ let radiusLength = (canvas.width * canvas.height) / 8000;
|
|
|
+
|
|
|
+ let particlesArray;
|
|
|
+
|
|
|
+ let mouse = {
|
|
|
+ x: null,
|
|
|
+ y: null,
|
|
|
+ radius: radiusLength,
|
|
|
+ };
|
|
|
+
|
|
|
+ window.addEventListener("mousemove", function (event) {
|
|
|
+ mouse.x = event.x;
|
|
|
+ mouse.y = event.y;
|
|
|
+ });
|
|
|
+
|
|
|
+ window.addEventListener("mouseout", function (event) {
|
|
|
+ mouse.x = undefined;
|
|
|
+ mouse.y = undefined;
|
|
|
+ });
|
|
|
+
|
|
|
+ window.addEventListener("resize", function (event) {
|
|
|
+ canvas.width = innerWidth;
|
|
|
+ canvas.height = innerHeight;
|
|
|
+ radiusLength = (canvas.width * canvas.height) / 9000;
|
|
|
+ createParticles();
|
|
|
+ });
|
|
|
+
|
|
|
+ class Particle {
|
|
|
+ constructor(x, y, velX, velY, size, color) {
|
|
|
+ this.x = x;
|
|
|
+ this.y = y;
|
|
|
+ this.velX = velX;
|
|
|
+ this.velY = velY;
|
|
|
+ this.size = size;
|
|
|
+ this.color = color;
|
|
|
+ }
|
|
|
+
|
|
|
+ draw() {
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
|
|
|
+ ctx.fillStyle = "#ffffff";
|
|
|
+ ctx.fill();
|
|
|
+ }
|
|
|
+
|
|
|
+ update() {
|
|
|
+ if (this.x > canvas.width || this.x < 0) {
|
|
|
+ this.velX = -this.velX;
|
|
|
+ }
|
|
|
+ if (this.y > canvas.height || this.y < 0) {
|
|
|
+ this.velY = -this.velY;
|
|
|
+ }
|
|
|
+
|
|
|
+ let dx = mouse.x - this.x;
|
|
|
+ let dy = mouse.y - this.y;
|
|
|
+ let dist = Math.sqrt(dx * dx + dy * dy);
|
|
|
+ if (dist < mouse.radius + this.size) {
|
|
|
+ const buffer = this.size * 10;
|
|
|
+ if (mouse.x < this.x && this.x < canvas.width - buffer) {
|
|
|
+ this.x += 10;
|
|
|
+ }
|
|
|
+ if (mouse.x > this.x && this.x > buffer) {
|
|
|
+ this.x -= 10;
|
|
|
+ }
|
|
|
+ if (mouse.y < this.y && this.y < canvas.height - buffer) {
|
|
|
+ this.y += 10;
|
|
|
+ }
|
|
|
+ if (mouse.y > this.y && this.y > buffer) {
|
|
|
+ this.y -= 10;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.x += this.velX;
|
|
|
+ this.y += this.velY;
|
|
|
+ this.draw();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function createParticles() {
|
|
|
+ particlesArray = [];
|
|
|
+ let noOfParticles = (canvas.width * canvas.height) / 10000;
|
|
|
+ for (let i = 0; i < noOfParticles; i++) {
|
|
|
+ let size = Math.random() * 5 + 1;
|
|
|
+ let x = Math.random() * (innerWidth - 2 * size) + 2 * size;
|
|
|
+ let y = Math.random() * (innerHeight - 2 * size) + 2 * size;
|
|
|
+ let velX = Math.random() * 2;
|
|
|
+ let velY = Math.random() * 2;
|
|
|
+ let color = "#ffffff";
|
|
|
+ particlesArray.push(new Particle(x, y, velX, velY, size, color));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function connect() {
|
|
|
+ let vicinityDist = (canvas.width * canvas.height) / 81;
|
|
|
+ for (let i = 0; i < particlesArray.length; i++) {
|
|
|
+ for (let j = i; j < particlesArray.length; j++) {
|
|
|
+ let distance =
|
|
|
+ Math.pow(particlesArray[i].x - particlesArray[j].x, 2) +
|
|
|
+ Math.pow(particlesArray[i].y - particlesArray[j].y, 2);
|
|
|
+ let opacity = 1 - distance / 25000;
|
|
|
+ if (distance < vicinityDist) {
|
|
|
+ ctx.strokeStyle = "rgba(255,255,255," + opacity + ")";
|
|
|
+ ctx.lineWidth = 1;
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(particlesArray[i].x, particlesArray[i].y);
|
|
|
+ ctx.lineTo(particlesArray[j].x, particlesArray[j].y);
|
|
|
+ ctx.stroke();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function animate() {
|
|
|
+ requestAnimationFrame(animate);
|
|
|
+ ctx.clearRect(0, 0, innerWidth, innerHeight);
|
|
|
+ for (let i = 0; i < particlesArray.length; i++) {
|
|
|
+ particlesArray[i].update();
|
|
|
+ }
|
|
|
+ connect();
|
|
|
+ }
|
|
|
+
|
|
|
+ createParticles();
|
|
|
+ animate();
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
-<style lang="scss">
|
|
|
+<style lang="scss" >
|
|
|
/* 修复input 背景不协调 和光标变色 */
|
|
|
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
|
|
|
@import "./index.scss";
|
|
|
+.btns {
|
|
|
+ width: 100%;
|
|
|
+ font-size: 16px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ background-image: linear-gradient(to right, #6366f1, #2563eb);
|
|
|
+ color: #f3f4f6;
|
|
|
+ padding: 1rem;
|
|
|
+ border-radius: 9999px;
|
|
|
+ font-weight: 600;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.5s ease-in;
|
|
|
+}
|
|
|
+.el-button {
|
|
|
+ border: none;
|
|
|
+ box-shadow: none;
|
|
|
+}
|
|
|
+.btns:hover {
|
|
|
+ background-image: linear-gradient(to left, #3b82f6, #6366f1) !important;
|
|
|
+}
|
|
|
+.btns:focus {
|
|
|
+ border-color: #3b82f6 !important;
|
|
|
+ background-image: linear-gradient(to left, #3b82f6, #6366f1) !important;
|
|
|
+}
|
|
|
+.login-container {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+#canvas1 {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ z-index: 1;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
</style>
|