bc518174
王天杨
提交两个项目文件
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
<template>
<div class="login-page">
<div class="login-card">
<div class="brand">
<h1>稻城亚丁</h1>
<p>内容管理后台</p>
</div>
<el-form ref="formRef" :model="form" :rules="rules" class="login-form" @submit.prevent>
<el-form-item prop="username">
<el-input
v-model="form.username"
size="large"
placeholder="管理员账号"
:prefix-icon="User"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="form.password"
type="password"
size="large"
placeholder="密码"
show-password
:prefix-icon="Lock"
@keyup.enter="onSubmit"
/>
</el-form-item>
<el-button
type="primary"
size="large"
class="submit-btn"
:loading="loading"
@click="onSubmit"
>
登 录
</el-button>
</el-form>
<p class="hint">默认账号:<code>admin</code> / <code>admin123</code>(首次登录后请修改密码)</p>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import type { FormInstance, FormRules } from "element-plus";
import { User, Lock } from "@element-plus/icons-vue";
import { login, fetchMyMenus } from "@/api/admin";
import { withDashboardMenu } from "@/utils/menuExtras";
import { useUserStore } from "@/stores/user";
import { getToken } from "@/utils/request";
const router = useRouter();
const route = useRoute();
const store = useUserStore();
const formRef = ref<FormInstance>();
const loading = ref(false);
const form = reactive({
username: "admin",
password: "",
});
const rules: FormRules = {
username: [{ required: true, message: "请输入账号", trigger: "blur" }],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
};
onMounted(() => {
if (getToken()) {
void router.replace("/dashboard");
}
});
async function onSubmit() {
if (!formRef.value) return;
await formRef.value.validate(async (ok) => {
if (!ok) return;
loading.value = true;
try {
const res = await login(form.username.trim(), form.password);
store.afterLogin(res.data.token, res.data.admin);
const menus = await fetchMyMenus();
store.setMenus(withDashboardMenu(menus.data.list));
const redirect = (route.query.redirect as string) || "/dashboard";
await router.replace(redirect);
} finally {
loading.value = false;
}
});
}
</script>
<style scoped>
.login-page {
display: flex;
min-height: 100%;
align-items: center;
justify-content: center;
padding: 24px;
background: linear-gradient(145deg, #0f172a 0%, #1e3a5f 45%, #0c4a6e 100%);
}
.login-card {
width: 100%;
max-width: 400px;
padding: 40px 36px 32px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.98);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.35);
}
.brand {
margin-bottom: 32px;
text-align: center;
}
.brand h1 {
margin: 0 0 8px;
font-size: 26px;
font-weight: 700;
color: #0f172a;
letter-spacing: 0.06em;
}
.brand p {
margin: 0;
font-size: 14px;
color: #64748b;
}
.login-form {
margin-top: 8px;
}
.submit-btn {
width: 100%;
margin-top: 8px;
}
.hint {
margin: 20px 0 0;
font-size: 12px;
line-height: 1.5;
color: #94a3b8;
text-align: center;
}
.hint code {
padding: 2px 6px;
font-size: 11px;
color: #0f172a;
background: #f1f5f9;
border-radius: 4px;
}
</style>
|