189 lines
4.1 KiB
Vue
189 lines
4.1 KiB
Vue
<script setup lang="ts">
|
||
import { reactive, ref } from "vue";
|
||
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
|
||
import type { InternalRuleItem, Value } from "async-validator";
|
||
import router from "@/router";
|
||
import { login } from "@/api/login";
|
||
|
||
interface RegisterData {
|
||
username: string;
|
||
password: string;
|
||
}
|
||
|
||
const registerData = reactive<RegisterData>({
|
||
username: "",
|
||
password: "",
|
||
});
|
||
|
||
const loginForm = ref<FormInstance>();
|
||
const loading = ref(false);
|
||
|
||
const rules = reactive<FormRules<RegisterData>>({
|
||
password: [{ validator: isNotEmpty, message: "请输入密码!" }],
|
||
username: [{ validator: isNotEmpty, message: "请输入账号!" }],
|
||
});
|
||
|
||
function isNotEmpty(rule: InternalRuleItem, value: Value, callback: any) {
|
||
if (!value) {
|
||
callback(rule.message);
|
||
} else {
|
||
callback();
|
||
}
|
||
}
|
||
|
||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||
if (!formEl || loading.value) return;
|
||
await formEl.validate(async (valid) => {
|
||
if (!valid) return;
|
||
loading.value = true;
|
||
try {
|
||
const result = await login(registerData.username, registerData.password);
|
||
if (result.code === 200) {
|
||
localStorage.setItem("isLoggedIn", "true");
|
||
ElMessage.success(result.message);
|
||
await router.push("/welcome");
|
||
} else {
|
||
ElMessage.error(result.message);
|
||
}
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
});
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<section class="login-page">
|
||
<div class="login-panel surface-card">
|
||
<div class="hero">
|
||
<p class="hero-kicker">LPT · Focus Flow</p>
|
||
<h1>今天的学习,从一次清晰登录开始</h1>
|
||
<p>
|
||
你将看到任务优先级、学习会话和复习数据在同一个系统里自然衔接。
|
||
</p>
|
||
<ul class="hero-points">
|
||
<li>明确学习任务</li>
|
||
<li>记录会话与残片</li>
|
||
<li>持续复盘</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="form-area">
|
||
<h2>账号登录</h2>
|
||
<el-form ref="loginForm" :model="registerData" class="login-form">
|
||
<el-form-item label="账号" :rules="rules.username" prop="username">
|
||
<el-input
|
||
v-model="registerData.username"
|
||
placeholder="请输入账号"
|
||
@keyup.enter="submitForm(loginForm)"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="密码" :rules="rules.password" prop="password">
|
||
<el-input
|
||
v-model="registerData.password"
|
||
type="password"
|
||
show-password
|
||
placeholder="请输入密码"
|
||
@keyup.enter="submitForm(loginForm)"
|
||
/>
|
||
</el-form-item>
|
||
<el-button
|
||
type="success"
|
||
class="submit-btn"
|
||
:loading="loading"
|
||
@click="submitForm(loginForm)"
|
||
>
|
||
进入系统
|
||
</el-button>
|
||
</el-form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.login-page {
|
||
min-height: calc(100vh - 240px);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.login-panel {
|
||
width: min(980px, 100%);
|
||
display: grid;
|
||
grid-template-columns: 1.1fr 1fr;
|
||
gap: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.hero {
|
||
padding: 36px;
|
||
background: linear-gradient(150deg, var(--green-800) 0%, var(--green-600) 100%);
|
||
color: #effcf4;
|
||
}
|
||
|
||
.hero-kicker {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
letter-spacing: 1.4px;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.hero h1 {
|
||
margin: 14px 0 10px;
|
||
line-height: 1.35;
|
||
font-size: clamp(22px, 2.6vw, 32px);
|
||
}
|
||
|
||
.hero p {
|
||
margin: 0;
|
||
opacity: 0.88;
|
||
}
|
||
|
||
.hero-points {
|
||
margin: 20px 0 0;
|
||
padding-left: 18px;
|
||
}
|
||
|
||
.hero-points li {
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.form-area {
|
||
background: var(--surface-strong);
|
||
padding: 32px 30px;
|
||
}
|
||
|
||
.form-area h2 {
|
||
margin: 0 0 16px;
|
||
color: var(--green-900);
|
||
}
|
||
|
||
.login-form :deep(.el-form-item) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.submit-btn {
|
||
width: 100%;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.login-panel {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.login-page {
|
||
min-height: auto;
|
||
}
|
||
|
||
.hero,
|
||
.form-area {
|
||
padding: 22px 16px;
|
||
}
|
||
}
|
||
</style>
|