初始化
This commit is contained in:
203
src/views/login/index.vue
Normal file
203
src/views/login/index.vue
Normal file
@@ -0,0 +1,203 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useUserStore } from "@/store/modules/user.js";
|
||||
import { encryptPasswordPayload } from '@/utils/passwordEncrypt.js'
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const form = reactive({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref("");
|
||||
|
||||
const redirectPath = computed(() => {
|
||||
const redirect = route.query.redirect;
|
||||
if (
|
||||
typeof redirect === "string" &&
|
||||
redirect.startsWith("/") &&
|
||||
!redirect.startsWith("//")
|
||||
) {
|
||||
return redirect;
|
||||
}
|
||||
return "/dashboard/integrated-center";
|
||||
});
|
||||
|
||||
// 校验登录表单,避免空账号或空密码提交到后端。
|
||||
function validateLoginForm() {
|
||||
if (!form.username.trim()) {
|
||||
errorMessage.value = "请输入账号";
|
||||
return false;
|
||||
}
|
||||
if (!form.password) {
|
||||
errorMessage.value = "请输入密码";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 提交登录信息,成功后回到登录前访问的页面。
|
||||
async function handleLogin() {
|
||||
if (!validateLoginForm() || loading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
errorMessage.value = "";
|
||||
|
||||
try {
|
||||
const encryptedForm = await encryptPasswordPayload(form, ['password'])
|
||||
await userStore.login(encryptedForm)
|
||||
router.replace(redirectPath.value);
|
||||
} catch (error) {
|
||||
errorMessage.value =
|
||||
error instanceof Error ? error.message : "登录失败,请检查账号或密码";
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="login-page">
|
||||
<form class="login-card" @submit.prevent="handleLogin">
|
||||
<div class="login-card__eyebrow">Robot Manager</div>
|
||||
<h1>系统登录</h1>
|
||||
<p>请输入账号和密码进入巡检管理大屏</p>
|
||||
|
||||
<label class="login-field">
|
||||
<span>账号</span>
|
||||
<input v-model="form.username" autocomplete="username" placeholder="请输入账号" type="text" />
|
||||
</label>
|
||||
|
||||
<label class="login-field">
|
||||
<span>密码</span>
|
||||
<input v-model="form.password" autocomplete="current-password" placeholder="请输入密码" type="password" />
|
||||
</label>
|
||||
|
||||
<div v-if="errorMessage" class="login-error">{{ errorMessage }}</div>
|
||||
|
||||
<button class="login-button" :disabled="loading" type="submit">
|
||||
{{ loading ? "登录中..." : "登录" }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.login-page {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #dff7ff;
|
||||
background:
|
||||
radial-gradient(circle at 50% 42%,
|
||||
rgba(31, 126, 202, 0.32),
|
||||
transparent 34%),
|
||||
radial-gradient(circle at center, #15385d 0%, #061426 60%, #02070f 100%);
|
||||
}
|
||||
|
||||
.login-card {
|
||||
box-sizing: border-box;
|
||||
width: 440px;
|
||||
padding: 44px 48px 48px;
|
||||
text-align: left;
|
||||
border: 1px solid rgba(116, 236, 255, 0.28);
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(180deg,
|
||||
rgba(7, 31, 61, 0.9),
|
||||
rgba(4, 15, 31, 0.86));
|
||||
box-shadow:
|
||||
0 0 40px rgba(69, 188, 255, 0.18),
|
||||
inset 0 0 26px rgba(116, 236, 255, 0.08);
|
||||
}
|
||||
|
||||
.login-card__eyebrow {
|
||||
margin-bottom: 12px;
|
||||
color: #74ecff;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.login-card h1 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 34px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.login-card p {
|
||||
margin: 0 0 34px;
|
||||
color: rgba(223, 247, 255, 0.72);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.login-field {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-field span {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: rgba(223, 247, 255, 0.78);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.login-field input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding: 0 16px;
|
||||
color: #e8fbff;
|
||||
border: 1px solid rgba(116, 236, 255, 0.26);
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
background: rgba(3, 15, 32, 0.74);
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.login-field input:focus {
|
||||
border-color: rgba(116, 236, 255, 0.78);
|
||||
box-shadow: 0 0 18px rgba(116, 236, 255, 0.16);
|
||||
}
|
||||
|
||||
.login-field input::placeholder {
|
||||
color: rgba(223, 247, 255, 0.34);
|
||||
}
|
||||
|
||||
.login-error {
|
||||
min-height: 20px;
|
||||
margin: -4px 0 16px;
|
||||
color: #ff9c9c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
color: #062239;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.12em;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(90deg, #74ecff, #46a7ff);
|
||||
box-shadow: 0 0 24px rgba(70, 167, 255, 0.32);
|
||||
}
|
||||
|
||||
.login-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.68;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user