Files
cz-web/src/views/login/index.vue
2026-10-01 14:02:50 +08:00

204 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/stores/modules/user'
import { isPhone } from '@/utils/validate'
import LoginForm from './cpns/LoginForm.vue'
import SmsLoginForm from './cpns/SmsLoginForm.vue'
type LoginTab = 'account' | 'sms'
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const activeTab = ref<LoginTab>('account')
// 演示/联调默认账号:登录页打开即自动预填,可直接点登录(生产环境请清空)
const account = ref('admin')
const password = ref('admin123')
const phone = ref('')
const code = ref('')
const agree = ref(false)
function goAfterLogin(): void {
void router.push(String(route.query.redirect ?? '/'))
}
async function onAccountSubmit(): Promise<void> {
if (!account.value.trim() || !password.value) {
ElMessage.warning('请输入账号和密码')
return
}
if (!agree.value) {
ElMessage.warning('请先阅读并同意《用户协议》和《隐私政策》')
return
}
const ok = await userStore.loginByAccount({ account: account.value.trim(), password: password.value })
if (ok) goAfterLogin()
}
async function onSmsSubmit(): Promise<void> {
if (!isPhone(phone.value)) {
ElMessage.warning('手机号格式不正确')
return
}
if (!code.value) {
ElMessage.warning('请输入验证码')
return
}
if (!agree.value) {
ElMessage.warning('请先阅读并同意《用户协议》和《隐私政策》')
return
}
const ok = await userStore.loginBySms({ phone: phone.value, code: code.value })
if (ok) goAfterLogin()
}
async function onGetCode(target: string): Promise<void> {
if (!isPhone(target)) {
ElMessage.warning('手机号格式不正确')
return
}
try {
await userStore.sendSmsCode(target)
}
catch {
// 失败提示已由 store 统一弹出,此处仅避免未处理的 rejection
}
}
</script>
<template>
<div class="auth-page">
<!-- 设计稿:左侧品牌渐变面板 @(0,0) 784×1080,文案列 x257 -->
<aside class="auth-page__brand">
<h1 class="auth-page__logo">
虫子智造研发<br>一体化平台
</h1>
<p class="auth-page__key">
chongzizhizaoyanfayitihuaPINGTAI
</p>
<p class="auth-page__slogan">
安全 · 高效 · 可控
</p>
</aside>
<RouterLink class="auth-page__guest" to="/">
游客模式
</RouterLink>
<!-- 设计稿:右侧表单区起点 x1022,表单列宽 693(标签)/680(控件) -->
<main class="auth-page__main">
<div class="auth-page__card">
<h2 class="auth-page__title">
欢迎登录
</h2>
<p class="auth-page__subtitle">
登录您的账号,开启高效之旅
</p>
<div class="auth-page__tabs">
<!-- 设计稿 Tab 顺序:手机验证码登录在前、账号密码登录在后 -->
<button
class="auth-page__tab"
:class="{ 'is-active': activeTab === 'sms' }"
@click="activeTab = 'sms'"
>
手机验证码登录
</button>
<button
class="auth-page__tab"
:class="{ 'is-active': activeTab === 'account' }"
@click="activeTab = 'account'"
>
账号密码登录
</button>
</div>
<LoginForm
v-if="activeTab === 'account'"
v-model:account="account"
v-model:password="password"
v-model:agree="agree"
@submit="onAccountSubmit"
/>
<SmsLoginForm
v-else
v-model:phone="phone"
v-model:code="code"
v-model:agree="agree"
@get-code="onGetCode"
@submit="onSmsSubmit"
/>
<p class="auth-page__switch">
没有账号?<RouterLink class="auth-page__link" to="/register">立即注册</RouterLink>
</p>
</div>
</main>
</div>
</template>
<style lang="less">
// 共用外壳 .auth-page 定义在 styles/common.less(登录/注册/找回密码三页共享)
</style>
<style lang="less" scoped>
// ===== 账号密码 / 手机验证码登录页专属 =====
.auth-page {
&__subtitle {
margin: 12px 0 0;
font-size: 13px * @auth-font-scale; // 设计稿 13/400 #6B7280,整体 ×@auth-font-scale
font-weight: 400;
line-height: 17px * @auth-font-scale;
color: #6b7280;
}
// 设计稿:Tab 行 @(1039,406),两项间距 24(起 x1039 / x1163)
&__tabs {
.flex(row, flex-start, center);
gap: 24px;
margin: 26px 0 0 17px; // 406 − 363 = 43;x1039 − 1022 = 17
}
&__tab {
position: relative;
padding: 0 0 8px;
border: none;
background: transparent;
font-size: 22px; // 固定 22px
font-weight: 400;
color: #4b5563;
cursor: pointer;
transition: color 0.2s;
&.is-active {
font-weight: 600;
color: @primary-strong;
// 抵消 html zoom,保证两 Tab 下划线视觉均为 2px(否则 2px×zoom 会因亚像素取整一粗一细)
&::after {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: calc(2px / @page-zoom);
background: @primary-strong;
}
}
}
&__switch {
align-self: center; // 设计稿:X 居中 @(1325,774)
margin: 53px 0 0; // 按钮底 721 → 774
font-size: 12px * @auth-font-scale; // 设计稿 12/400 #6B7280
font-weight: 400;
line-height: 16px * @auth-font-scale;
color: #6b7280;
}
}
</style>