通过 /api/private/deployment/status 判断部署模式,PRIVATE 模式下不渲染注册链接。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
166 行
4.2 KiB
Vue
166 行
4.2 KiB
Vue
<template>
|
|
<div class="login-page">
|
|
<el-card class="login-card">
|
|
<h2 class="title">XuqmGroup 开放平台</h2>
|
|
|
|
<el-form ref="formRef" :model="form" :rules="rules" @submit.prevent="handleLogin">
|
|
<el-form-item prop="account">
|
|
<el-input v-model="form.account" placeholder="用户名 / 邮箱" prefix-icon="User" />
|
|
</el-form-item>
|
|
<el-form-item prop="password">
|
|
<el-input v-model="form.password" type="password" placeholder="密码"
|
|
prefix-icon="Lock" show-password />
|
|
</el-form-item>
|
|
<el-form-item prop="captchaCode">
|
|
<div class="captcha-row">
|
|
<el-input v-model="form.captchaCode" placeholder="验证码" style="flex:1" />
|
|
<img :src="captchaImage" class="captcha-img" @click="loadCaptcha" alt="captcha" />
|
|
</div>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" native-type="submit" :loading="loading" style="width:100%">
|
|
登 录
|
|
</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<div class="links">
|
|
<router-link v-if="!isPrivate" to="/register">注册账号</router-link>
|
|
<router-link to="/forgot-password">忘记密码</router-link>
|
|
</div>
|
|
</el-card>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, onMounted } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { ElMessage } from 'element-plus'
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
import { authApi } from '@/api/auth'
|
|
import { useAuthStore } from '@/stores/auth'
|
|
import { getDeploymentStatus } from '@/api/system'
|
|
|
|
const router = useRouter()
|
|
const auth = useAuthStore()
|
|
|
|
const formRef = ref<FormInstance>()
|
|
const loading = ref(false)
|
|
const captchaKey = ref('')
|
|
const captchaImage = ref('')
|
|
const isPrivate = ref(false)
|
|
|
|
const form = reactive({ account: '', password: '', captchaCode: '' })
|
|
const rules: FormRules = {
|
|
account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
|
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
captchaCode: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
|
}
|
|
|
|
async function loadCaptcha() {
|
|
try {
|
|
const res = await authApi.getCaptcha()
|
|
captchaKey.value = res.data.data.key
|
|
captchaImage.value = res.data.data.image
|
|
} catch {}
|
|
}
|
|
|
|
async function handleLogin() {
|
|
await formRef.value?.validate()
|
|
loading.value = true
|
|
try {
|
|
const res = await authApi.login({
|
|
account: form.account,
|
|
password: form.password,
|
|
captchaKey: captchaKey.value,
|
|
captchaCode: form.captchaCode,
|
|
})
|
|
auth.setToken(res.data.data.token)
|
|
router.push('/dashboard')
|
|
} finally {
|
|
loading.value = false
|
|
loadCaptcha()
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
loadCaptcha()
|
|
try {
|
|
const status = await getDeploymentStatus()
|
|
isPrivate.value = status.mode === 'PRIVATE'
|
|
} catch {}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.login-page {
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 16px;
|
|
background:
|
|
radial-gradient(circle at top left, rgba(102, 126, 234, 0.35), transparent 35%),
|
|
radial-gradient(circle at bottom right, rgba(118, 75, 162, 0.32), transparent 32%),
|
|
linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
}
|
|
.login-card {
|
|
width: min(420px, calc(100vw - 32px));
|
|
box-sizing: border-box;
|
|
border-radius: 18px;
|
|
box-shadow: 0 20px 50px rgba(15, 23, 42, 0.18);
|
|
backdrop-filter: blur(8px);
|
|
}
|
|
.title {
|
|
text-align: center;
|
|
margin-bottom: 24px;
|
|
color: #333;
|
|
}
|
|
.captcha-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
width: 100%;
|
|
}
|
|
.captcha-img {
|
|
height: 36px;
|
|
cursor: pointer;
|
|
border: 1px solid #dcdfe6;
|
|
border-radius: 4px;
|
|
}
|
|
.links {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: 14px;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.login-page {
|
|
align-items: flex-start;
|
|
padding-top: 12vh;
|
|
}
|
|
|
|
.login-card {
|
|
width: 100%;
|
|
}
|
|
|
|
.captcha-row {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 8px;
|
|
}
|
|
|
|
.captcha-img {
|
|
width: 100%;
|
|
height: 44px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.links {
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
align-items: center;
|
|
}
|
|
}
|
|
</style>
|