初始化

This commit is contained in:
zg
2026-07-15 16:13:27 +08:00
parent 6d6f559793
commit c4023c1623
276 changed files with 42622 additions and 0 deletions

View File

@@ -0,0 +1,281 @@
<template>
<div class="login-page">
<div class="login-container">
<!-- 左侧品牌区 -->
<div class="login-brand">
<div class="brand-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>
</div>
<h1 class="brand-title">Mokee Gateway</h1>
<p class="brand-desc">统一登录网关管理平台</p>
<div class="brand-features">
<div class="feature-item">
<span class="feature-dot" />
<span>统一身份认证</span>
</div>
<div class="feature-item">
<span class="feature-dot" />
<span>智能网关转发</span>
</div>
<div class="feature-item">
<span class="feature-dot" />
<span>细粒度权限管控</span>
</div>
</div>
</div>
<!-- 右侧登录表单 -->
<div class="login-form-panel">
<div class="form-header">
<h2>欢迎回来</h2>
<p>请输入账号密码登录系统</p>
</div>
<el-form
ref="formRef"
:model="form"
:rules="rules"
@keyup.enter="handleLogin"
>
<el-form-item prop="username">
<el-input
v-model="form.username"
placeholder="用户名"
:prefix-icon="User"
size="large"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="form.password"
type="password"
placeholder="密码"
:prefix-icon="Lock"
size="large"
show-password
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
size="large"
:loading="loading"
class="submit-btn"
@click="handleLogin"
>
</el-button>
</el-form-item>
</el-form>
</div>
</div>
<footer class="login-footer">
&copy; 2026 Mokee Gateway
</footer>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { User, Lock } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import { useAuthStore } from '@/stores/auth'
const router = useRouter()
const authStore = useAuthStore()
const formRef = ref<FormInstance>()
const loading = ref(false)
const form = reactive({ username: '', password: '' })
const rules: FormRules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
}
async function handleLogin() {
const valid = await formRef.value?.validate().catch(() => false)
if (!valid) return
loading.value = true
try {
await authStore.login(form.username, form.password)
// PROD: 登录后切到主应用域名,避免从 login 域名加载 JS
const webUrl = import.meta.env.VITE_WEB_URL
if (webUrl && webUrl !== window.location.origin) {
window.location.href = webUrl + '/select'
} else {
router.push('/select')
}
} catch (e: any) {
// 响应拦截器已展示通用错误(如 401/403/429
// 此处处理拦截器未覆盖的业务异常信息
const msg = e?.response?.data?.msg || e?.message
if (msg && msg !== '请求失败') ElMessage.error(msg)
} finally {
loading.value = false
}
}
</script>
<style scoped>
.login-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #f8fafc;
padding: 24px;
}
.login-container {
display: flex;
width: 880px;
max-width: 100%;
min-height: 480px;
background: #fff;
border-radius: 20px;
box-shadow:
0 0 0 1px rgba(0, 0, 0, 0.04),
0 20px 60px -20px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* ===== 左侧品牌区 ===== */
.login-brand {
flex: 1;
background: linear-gradient(160deg, #4f46e5 0%, #6366f1 40%, #818cf8 100%);
padding: 48px 40px;
display: flex;
flex-direction: column;
justify-content: center;
color: #fff;
}
.brand-icon {
width: 52px;
height: 52px;
background: rgba(255, 255, 255, 0.18);
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 28px;
backdrop-filter: blur(10px);
}
.brand-icon svg {
width: 28px;
height: 28px;
}
.brand-title {
font-size: 26px;
font-weight: 700;
letter-spacing: -0.5px;
margin-bottom: 6px;
}
.brand-desc {
font-size: 14px;
opacity: 0.8;
font-weight: 400;
margin-bottom: 40px;
}
.brand-features {
display: flex;
flex-direction: column;
gap: 14px;
}
.feature-item {
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
opacity: 0.85;
}
.feature-dot {
width: 6px;
height: 6px;
background: rgba(255, 255, 255, 0.6);
border-radius: 50%;
flex-shrink: 0;
}
/* ===== 右侧登录表单 ===== */
.login-form-panel {
flex: 1;
padding: 48px 44px;
display: flex;
flex-direction: column;
justify-content: center;
}
.form-header {
margin-bottom: 32px;
}
.form-header h2 {
font-size: 24px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 6px;
letter-spacing: -0.3px;
}
.form-header p {
font-size: 14px;
color: var(--text-muted);
}
.submit-btn {
width: 100%;
height: 46px;
font-size: 15px;
letter-spacing: 3px;
border-radius: var(--radius-lg);
margin-top: 4px;
}
.login-footer {
margin-top: 28px;
color: var(--text-muted);
font-size: 12px;
}
/* ===== 响应式 ===== */
@media (max-width: 768px) {
.login-page { padding: 0; justify-content: flex-start; }
.login-container {
flex-direction: column;
min-height: 100vh;
border-radius: 0;
box-shadow: none;
width: 100%;
}
.login-brand {
padding: 40px 24px 24px;
text-align: center;
align-items: center;
}
.brand-icon { width: 44px; height: 44px; margin-bottom: 16px; }
.brand-icon svg { width: 22px; height: 22px; }
.brand-title { font-size: 22px; }
.brand-features { display: none; }
.brand-desc { margin-bottom: 0; }
.login-form-panel { padding: 24px 24px 40px; }
.form-header h2 { font-size: 20px; }
.login-footer { display: none; }
}
</style>