|
|
@@ -0,0 +1,164 @@
|
|
|
+<template>
|
|
|
+ <div class="login-container">
|
|
|
+ <div class="login-box">
|
|
|
+ <h2 class="login-title">后台管理系统</h2>
|
|
|
+ <el-form
|
|
|
+ ref="loginFormRef"
|
|
|
+ :model="loginForm"
|
|
|
+ :rules="loginRules"
|
|
|
+ class="login-form"
|
|
|
+ @keyup.enter="handleLogin"
|
|
|
+ >
|
|
|
+ <el-form-item prop="username">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.username"
|
|
|
+ placeholder="用户名: admin"
|
|
|
+ size="large"
|
|
|
+ :prefix-icon="User"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="password">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.password"
|
|
|
+ type="password"
|
|
|
+ placeholder="密码: 123456"
|
|
|
+ size="large"
|
|
|
+ :prefix-icon="Lock"
|
|
|
+ show-password
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ class="login-btn"
|
|
|
+ :loading="loading"
|
|
|
+ @click="handleLogin"
|
|
|
+ >
|
|
|
+ 登 录
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div class="login-tips">
|
|
|
+ <p>用户名: admin | 密码: 123456</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, reactive } from 'vue'
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import { User, Lock } from '@element-plus/icons-vue'
|
|
|
+import { useUserStore } from '@/store/user'
|
|
|
+import { http } from '@/utils/request'
|
|
|
+import type { FormInstance, FormRules } from 'element-plus'
|
|
|
+import type { UserInfo } from '@/types/menu'
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const userStore = useUserStore()
|
|
|
+const loginFormRef = ref<FormInstance>()
|
|
|
+const loading = ref(false)
|
|
|
+
|
|
|
+const loginForm = reactive({
|
|
|
+ username: 'admin',
|
|
|
+ password: '123456'
|
|
|
+})
|
|
|
+
|
|
|
+const loginRules: FormRules = {
|
|
|
+ username: [
|
|
|
+ { required: true, message: '请输入用户名', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ password: [
|
|
|
+ { required: true, message: '请输入密码', trigger: 'blur' },
|
|
|
+ { min: 6, message: '密码长度至少6位', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+// 获取用户信息
|
|
|
+const fetchUserInfo = async () => {
|
|
|
+ return await http.get<UserInfo>('/upms/user/info')
|
|
|
+}
|
|
|
+
|
|
|
+// 获取用户菜单
|
|
|
+const fetchUserMenus = async () => {
|
|
|
+ return await http.get('/upms/menu/list')
|
|
|
+}
|
|
|
+
|
|
|
+const handleLogin = async () => {
|
|
|
+ if (!loginFormRef.value) return
|
|
|
+
|
|
|
+ await loginFormRef.value.validate(async (valid) => {
|
|
|
+ if (!valid) return
|
|
|
+
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ // 1. 调用登录接口
|
|
|
+ const loginRes = await http.post<{
|
|
|
+ token: string
|
|
|
+ userInfo: UserInfo
|
|
|
+ }>('/upms/auth/login', {
|
|
|
+ username: loginForm.username,
|
|
|
+ password: loginForm.password
|
|
|
+ })
|
|
|
+
|
|
|
+ // 2. 保存 token
|
|
|
+ userStore.setToken(loginRes.token)
|
|
|
+ userStore.setUserInfo(loginRes.userInfo)
|
|
|
+
|
|
|
+ // 3. 获取菜单数据
|
|
|
+ const menus = await fetchUserMenus()
|
|
|
+ userStore.setMenus(menus)
|
|
|
+
|
|
|
+ ElMessage.success('登录成功')
|
|
|
+ router.push('/')
|
|
|
+ } catch (error) {
|
|
|
+ // 错误已由拦截器处理
|
|
|
+ console.error('登录失败:', error)
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.login-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100vh;
|
|
|
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.login-box {
|
|
|
+ width: 400px;
|
|
|
+ padding: 40px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
|
+}
|
|
|
+
|
|
|
+.login-title {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 24px;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 30px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form {
|
|
|
+ .login-btn {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.login-tips {
|
|
|
+ margin-top: 20px;
|
|
|
+ text-align: center;
|
|
|
+ color: #999;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+</style>
|