refactor(project): Reorganize frontend and backend directories

This commit is contained in:
2026-03-18 10:45:15 +08:00
parent cc9eaf4cdf
commit 92a139e470
513 changed files with 28251 additions and 287 deletions
@@ -0,0 +1,228 @@
<template>
<div class="login-container">
<div class="login-box">
<div class="login-header">
<h1 class="logo">HAOVP</h1>
<p class="title">管理后台</p>
</div>
<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form">
<!-- 验证码 -->
<div class="captcha-wrapper">
<el-image
:src="captchaImage"
fit="contain"
class="captcha-image"
@click="refreshCaptcha"
>
<template #error>
<div class="captcha-error" @click="refreshCaptcha">点击刷新</div>
</template>
</el-image>
</div>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
placeholder="用户名"
prefix-icon="User"
size="large"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="密码"
prefix-icon="Lock"
size="large"
show-password
@keyup.enter="handleLogin"
/>
</el-form-item>
<el-form-item prop="captcha">
<el-input
v-model="loginForm.captcha"
placeholder="验证码"
prefix-icon="Key"
size="large"
@keyup.enter="handleLogin"
>
<template #append>
<el-image
:src="captchaImage"
fit="contain"
class="captcha-btn"
@click="refreshCaptcha"
/>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
size="large"
:loading="loading"
class="login-btn"
@click="handleLogin"
>
登 录
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import { authApi, type CaptchaResult } from '@/api/auth.ts'
import { useUserStore } from '@/stores/user.ts'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
const loginFormRef = ref<FormInstance>()
const loading = ref(false)
const captchaKey = ref('')
const captchaImage = ref('')
const loginForm = reactive({
username: '',
password: '',
captcha: ''
})
const loginRules: FormRules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
],
captcha: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
}
// 获取验证码
const refreshCaptcha = async () => {
try {
const res: CaptchaResult = await authApi.getCaptcha()
captchaKey.value = res.captchaKey
captchaImage.value = res.captchaImage
} catch (error) {
console.error('获取验证码失败:', error)
}
}
// 登录
const handleLogin = async () => {
if (!loginFormRef.value) return
await loginFormRef.value.validate(async (valid) => {
if (!valid) return
loading.value = true
try {
await userStore.login({
username: loginForm.username,
password: loginForm.password,
captcha: loginForm.captcha,
captchaKey: captchaKey.value
})
ElMessage.success('登录成功')
// 跳转到之前的页面或首页
const redirect = (route.query.redirect as string) || '/'
router.replace(redirect)
} catch (error: any) {
ElMessage.error(error.message || '登录失败')
refreshCaptcha()
} finally {
loading.value = false
}
})
}
onMounted(() => {
refreshCaptcha()
})
</script>
<style scoped lang="scss">
.login-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-box {
width: 400px;
padding: 40px;
background: #fff;
border-radius: 8px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.login-header {
text-align: center;
margin-bottom: 30px;
.logo {
font-size: 36px;
font-weight: bold;
background: linear-gradient(to right, #00a1d6, #fb7299);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin: 0;
}
.title {
color: #666;
font-size: 16px;
margin-top: 8px;
}
}
.captcha-wrapper {
display: flex;
justify-content: center;
margin-bottom: 20px;
.captcha-image {
height: 50px;
cursor: pointer;
}
.captcha-error {
width: 150px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
color: #999;
cursor: pointer;
}
}
.login-form {
.captcha-btn {
width: 100px;
height: 32px;
cursor: pointer;
}
.login-btn {
width: 100%;
}
}
</style>