再次优化了登陆注册界面与跳转逻辑

This commit is contained in:
yml
2026-05-22 23:52:15 +08:00
parent b68411166d
commit 94edda9710
6 changed files with 473 additions and 593 deletions
+34
View File
@@ -14,3 +14,37 @@ apiClient.interceptors.request.use((config) => {
}
return config
})
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error?.response?.status !== 401) {
return Promise.reject(error)
}
const requestUrl = error.config?.url || ''
const isAdminRequest = requestUrl.startsWith('/admin')
const currentPath = window.location.pathname + window.location.search
if (isAdminRequest) {
localStorage.removeItem('admin_access_token')
localStorage.removeItem('admin_refresh_token')
if (!window.location.pathname.startsWith('/admin/login')) {
window.location.assign('/admin/login')
}
return Promise.reject(error)
}
localStorage.removeItem('access_token')
localStorage.removeItem('refresh_token')
localStorage.removeItem('user_id')
if (!window.location.pathname.startsWith('/m/login') && !window.location.pathname.startsWith('/m/register')) {
const redirect = encodeURIComponent(currentPath)
const loginPath = window.location.pathname.startsWith('/m') ? '/m/login' : '/login'
window.location.assign(`${loginPath}?redirect=${redirect}`)
}
return Promise.reject(error)
},
)
+9 -5
View File
@@ -40,32 +40,32 @@ const router = createRouter({
path: "/m/messages",
name: "mobile-messages",
component: () => import("@/views/mobile/MobileMessagesView.vue"),
meta: { layout: "blank" },
meta: { layout: "blank", requiresAuth: true },
},
{
path: "/m/realname",
name: "mobile-realname",
component: () => import("@/views/mobile/MobileRealnameView.vue"),
meta: { layout: "blank" },
meta: { layout: "blank", requiresAuth: true },
},
{
path: "/m/profile",
name: "mobile-profile",
component: () => import("@/views/mobile/MobileProfileView.vue"),
meta: { layout: "blank" },
meta: { layout: "blank", requiresAuth: true },
},
{
path: "/m/orders",
name: "mobile-orders",
component: () => import("@/views/mobile/MobileOrdersView.vue"),
meta: { layout: "blank" },
meta: { layout: "blank", requiresAuth: true },
},
{
path: "/m/seller/listings/create",
name: "mobile-seller-listing-create",
component: () =>
import("@/views/mobile/MobileSellerListingCreateView.vue"),
meta: { layout: "blank" },
meta: { layout: "blank", requiresAuth: true },
},
{
path: "/",
@@ -217,6 +217,10 @@ router.beforeEach((to) => {
return { path: toMobilePath(to.path), query: to.query, hash: to.hash };
}
if (to.meta.requiresAuth && !localStorage.getItem("access_token")) {
return { path: "/m/login", query: { redirect: to.fullPath } };
}
if (
to.path === "/admin/login" &&
localStorage.getItem("admin_access_token")
+204 -246
View File
@@ -1,12 +1,13 @@
<script setup lang="ts">
import { onUnmounted, reactive, ref } from "vue";
import { RouterLink, useRouter } from "vue-router";
import { RouterLink, useRoute, useRouter } from "vue-router";
import { showToast, showDialog } from "vant";
import { sendSmsCode } from "@/api/auth";
import { useSessionStore } from "@/stores/session";
const router = useRouter();
const route = useRoute();
const session = useSessionStore();
const loading = ref(false);
const sending = ref(false);
@@ -83,7 +84,8 @@ async function handleLogin() {
loading.value = true;
try {
await session.login(form.phone, form.code);
await router.push("/m/profile");
const redirect = typeof route.query.redirect === "string" ? route.query.redirect : "/m/profile";
await router.replace(redirect);
} catch {
showToast({ message: "登录失败,请检查手机号和验证码", icon: "cross" });
} finally {
@@ -94,276 +96,278 @@ async function handleLogin() {
<template>
<main class="mobile-login-shell">
<section class="login-card">
<!-- 品牌区域 -->
<div class="login-top">
<div class="monster-logo"></div>
<header class="page-header">
<button class="back-btn" type="button" @click="router.back()">
<van-icon name="arrow-left" :size="20" />
</button>
<h1>登录</h1>
<span class="header-spacer"></span>
</header>
<section class="auth-body">
<div class="brand-row">
<div class="brand-logo"></div>
<div>
<p>大锤商行</p>
<small>平台担保 · 安全租号</small>
<strong>大锤商行</strong>
<p>平台担保 · 安全租号</p>
</div>
</div>
<!-- 登录/注册 Tab 切换 -->
<div class="auth-switch" aria-label="登录注册切换">
<RouterLink to="/m/login" class="active">登录</RouterLink>
<RouterLink to="/m/register">注册</RouterLink>
</div>
<p class="login-eyebrow">SMS LOGIN</p>
<h1>手机号登录</h1>
<p class="login-subtitle">验证码登录开发环境验证码查看后端日志</p>
<div class="form-section">
<div class="section-heading">
<h2>手机号登录</h2>
<p>使用短信验证码登录开发环境验证码查看后端日志</p>
</div>
<!-- 手机号输入 -->
<van-field
v-model="form.phone"
type="tel"
maxlength="11"
placeholder="请输入手机号"
clearable
class="login-field"
>
<template #left-icon>
<label class="auth-input-row">
<span class="input-label">手机号</span>
<span class="field-prefix">+86</span>
</template>
</van-field>
<input
v-model="form.phone"
type="tel"
maxlength="11"
placeholder="请输入手机号"
/>
</label>
<!-- 验证码输入 -->
<van-field
v-model="form.code"
type="digit"
maxlength="6"
placeholder="6 位验证码"
class="login-field"
:left-icon="'shield-o'"
>
<template #button>
<van-button
size="small"
type="primary"
plain
round
:disabled="sending || countDown > 0"
:loading="sending"
@click="handleSendCode"
>
{{
countDown > 0
? `${countDown}s`
: sending
? "发送中"
: "发送验证码"
}}
</van-button>
</template>
</van-field>
<label class="auth-input-row code-row">
<span class="input-label">验证码</span>
<input
v-model="form.code"
type="text"
inputmode="numeric"
maxlength="6"
placeholder="6 位验证码"
/>
<span class="code-action">
<van-button
size="small"
type="primary"
plain
:disabled="sending || countDown > 0"
:loading="sending"
class="code-btn"
@click="handleSendCode"
>
{{
countDown > 0
? `${countDown}s`
: sending
? "发送中"
: "发送验证码"
}}
</van-button>
</span>
</label>
<!-- 底部链接行 -->
<div class="login-links">
<van-button size="mini" plain type="primary">忘记密码</van-button>
</div>
<div class="agreement-row">
<van-checkbox v-model="agreed" shape="square" icon-size="16px">
我已阅读并同意<b>用户协议</b><b>隐私政策</b>
</van-checkbox>
</div>
<!-- 用户协议 -->
<div class="agreement-row">
<van-checkbox v-model="agreed" shape="square" icon-size="16px">
我已阅读并同意<b>用户协议</b><b>隐私政策</b>
</van-checkbox>
</div>
<!-- 登录按钮 -->
<van-button
type="primary"
block
round
class="login-button"
:loading="loading"
loading-text="登录中..."
@click="handleLogin"
>
登录
</van-button>
<!-- 底部注册入口 -->
<RouterLink
to="/m/register"
class="register-entry"
custom
v-slot="{ navigate }"
>
<van-button
plain
type="primary"
block
round
size="small"
class="register-button"
@click="navigate"
class="primary-button"
:loading="loading"
loading-text="登录中..."
@click="handleLogin"
>
没有账号立即注册
登录
</van-button>
</div>
<RouterLink to="/m/register" class="secondary-entry">
没有账号立即注册
</RouterLink>
</section>
</main>
</template>
<style scoped>
/* ========== Vant 主题变量覆盖 ========== */
:root {
--van-primary-color: #1477ff;
--van-button-primary-background: #1477ff;
--van-button-primary-border-color: transparent;
}
/* ========== 页面容器 ========== */
.mobile-login-shell {
min-height: 100dvh;
box-sizing: border-box;
overflow: hidden;
background: #f5f7fa;
background: #f4f6f8;
color: #151c28;
padding: 40px 24px;
}
.login-card {
.page-header {
position: sticky;
top: 0;
z-index: 10;
display: flex;
min-height: calc(100dvh - 80px);
flex-direction: column;
justify-content: center;
align-items: center;
height: 48px;
padding: 0 12px;
background: #fff;
border-bottom: 1px solid #eceff3;
}
/* ========== 品牌区域 ========== */
.login-top {
.page-header h1 {
flex: 1;
margin: 0;
font-size: 17px;
font-weight: 700;
text-align: center;
}
.back-btn {
display: grid;
width: 36px;
height: 36px;
place-items: center;
border: none;
background: none;
color: #25282d;
}
.header-spacer {
width: 36px;
}
.auth-body {
padding: 14px;
}
.brand-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 14px;
padding: 8px 2px 14px;
}
.monster-logo {
.brand-logo {
display: grid;
width: 48px;
height: 48px;
flex: 0 0 auto;
width: 42px;
height: 42px;
place-items: center;
border-radius: 16px;
border-radius: 12px;
background: #1477ff;
color: #ffffff;
font-size: 21px;
font-size: 18px;
font-weight: 900;
box-shadow: 0 4px 12px rgba(20, 119, 255, 0.18);
}
.login-top p {
.brand-row strong {
display: block;
margin: 0 0 2px;
font-size: 20px;
color: #171a1f;
font-size: 18px;
font-weight: 900;
}
.login-top small,
.login-subtitle {
color: #667386;
.brand-row p {
margin: 0;
color: #6b7280;
font-size: 12px;
}
/* ========== Tab 切换 ========== */
.auth-switch {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-bottom: 16px;
border-radius: 15px;
background: #eef4fb;
padding: 5px;
gap: 6px;
margin-bottom: 12px;
padding: 4px;
border-radius: 8px;
background: #eaf0f8;
}
.auth-switch a {
border-radius: 11px;
color: #667386;
padding: 10px 0;
padding: 9px 0;
border-radius: 7px;
color: #5f6875;
text-align: center;
font-size: 14px;
font-weight: 900;
font-size: 13px;
font-weight: 800;
text-decoration: none;
}
.auth-switch a.active {
background: #ffffff;
color: #111827;
box-shadow: 0 8px 18px rgba(23, 35, 61, 0.08);
color: #1477ff;
}
/* ========== 标题区 ========== */
.login-eyebrow {
margin: 0 0 5px;
color: #02846e;
.form-section {
padding: 14px;
background: #fff;
border: 1px solid #edf0f4;
border-radius: 8px;
}
.section-heading h2 {
margin: 0 0 4px;
color: #171a1f;
font-size: 18px;
font-weight: 800;
}
.section-heading p {
margin: 0 0 12px;
color: #858c96;
font-size: 12px;
font-weight: 900;
letter-spacing: 0.04em;
line-height: 1.5;
}
.login-card h1 {
margin: 0;
font-size: 28px;
line-height: 1.15;
.auth-input-row {
display: grid;
grid-template-columns: 58px 38px minmax(0, 1fr);
align-items: center;
min-height: 44px;
margin-bottom: 8px;
padding: 0 12px;
border-radius: 8px;
background: #f8fafc;
}
.login-subtitle {
margin: 7px 0 14px;
.auth-input-row.code-row {
grid-template-columns: 58px minmax(0, 1fr) 92px;
gap: 8px;
}
.input-label {
color: #30343a;
font-size: 13px;
line-height: 1.45;
}
/* ========== Vant Field 覆盖样式 ========== */
.login-field {
margin-top: 12px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.92);
box-shadow: inset 0 1px 3px rgba(23, 35, 61, 0.04);
overflow: hidden;
}
.login-field :deep(.van-field__control) {
font-size: 15px;
color: #151c28;
}
.login-field :deep(.van-field__label) {
width: auto;
margin-right: 8px;
color: #333b48;
font-weight: 700;
font-size: 13px;
}
.login-field :deep(.van-field__left-icon) {
color: #1777ff;
margin-right: 0;
}
.login-field :deep(.van-field__right-icon) {
color: #999;
.auth-input-row input {
width: 100%;
min-width: 0;
border: none;
background: transparent;
color: #20242a;
font-size: 14px;
outline: none;
}
.auth-input-row input::placeholder {
color: #c0c4cc;
}
.field-prefix {
color: #1777ff;
color: #1477ff;
font-weight: 800;
font-size: 14px;
margin-right: 4px;
}
/* ========== 底部链接行 ========== */
.login-links {
.code-action {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 0 12px;
color: #566274;
font-size: 12px;
justify-content: flex-end;
}
.code-btn {
border-radius: 8px;
}
/* ========== 协议行 ========== */
.agreement-row {
display: flex;
align-items: center;
margin-bottom: 16px;
margin: 10px 0 14px;
}
.agreement-row :deep(.van-checkbox__label) {
@@ -378,72 +382,26 @@ async function handleLogin() {
font-weight: 600;
}
/* ========== 登录按钮 ========== */
.login-button {
margin-top: 6px;
height: 46px;
font-size: 15px;
font-weight: 800;
background: #1477ff !important;
.primary-button {
height: 42px;
border: none !important;
box-shadow: 0 4px 12px rgba(20, 119, 255, 0.18);
border-radius: 8px !important;
background: #1477ff !important;
font-size: 15px;
font-weight: 700;
}
/* ========== 注册入口按钮 ========== */
.register-button {
.secondary-entry {
display: block;
margin-top: 12px;
padding: 12px;
border: 1px solid #d7dce3;
border-radius: 8px;
background: #fff;
color: #1477ff;
font-size: 13px;
font-weight: 800;
}
.register-entry {
text-align: center;
text-decoration: none;
}
/* ========== 响应式 ========== */
@media (max-height: 620px) {
.mobile-login-shell {
padding-top: 10px;
padding-bottom: 10px;
}
.login-card {
min-height: calc(100dvh - 20px);
}
.login-top {
margin-bottom: 10px;
}
.monster-logo {
width: 42px;
height: 42px;
border-radius: 14px;
}
.auth-switch {
margin-bottom: 11px;
}
.login-card h1 {
font-size: 24px;
}
.login-field {
margin-top: 8px;
}
.login-button {
height: 42px;
margin-top: 10px;
}
}
@media (min-width: 520px) {
.mobile-login-shell {
max-width: 430px;
margin: 0 auto;
box-shadow: 0 0 0 1px rgba(23, 35, 61, 0.08);
}
}
</style>
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import { computed, onMounted, ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useSessionStore } from "@/stores/session";
import { showDialog, showToast } from "vant";
@@ -88,6 +88,13 @@ function isNavActive(path: string) {
}
const isLoggedIn = computed(() => Boolean(session.token));
onMounted(() => {
if (!isLoggedIn.value) {
router.replace({ path: "/m/login", query: { redirect: route.fullPath } });
}
});
const displayName = computed(() =>
session.phone
? `用户${session.phone.slice(-6)}`
@@ -99,39 +106,12 @@ const maskedPhone = computed(() =>
? `${session.phone.slice(0, 3)}****${session.phone.slice(-4)}`
: "登录后查看手机号"
);
function goToLogin() {
router.push("/m/login");
}
</script>
<template>
<main class="mobile-profile-shell">
<!-- 未登录区 - 自定义卡片布局 -->
<template v-if="!isLoggedIn">
<section class="guest-card">
<div class="guest-logo"></div>
<h1>登录大锤商行</h1>
<p>登录后查看订单管理发布提现余额并享受平台担保交易服务</p>
<van-button
type="primary"
block
round
class="guest-login-btn"
@click="goToLogin"
>
立即登录
</van-button>
<div class="guest-benefits">
<van-tag type="primary" plain size="medium" round>担保交易</van-tag>
<van-tag type="primary" plain size="medium" round>订单留痕</van-tag>
<van-tag type="primary" plain size="medium" round>安全交接</van-tag>
</div>
</section>
</template>
<!-- 已登录区 -->
<template v-else>
<template v-if="isLoggedIn">
<!-- Hero 顶部蓝色横幅 -->
<section class="profile-hero">
<div class="hero-bg"></div>
@@ -267,64 +247,6 @@ function goToLogin() {
padding: 0 0 60px;
}
/* ========== 未登录区 - 自定义卡片 ========== */
.guest-card {
text-align: center;
padding: 34px 26px;
margin: 12px;
border-radius: 16px;
background: #fff;
box-shadow: 0 8px 26px rgba(24, 30, 45, 0.06);
}
.guest-card h1 {
margin: 18px 0 0;
font-size: 22px;
font-weight: 900;
color: #1a202c;
}
.guest-card p {
margin: 10px 0 0;
font-size: 14px;
color: #667386;
line-height: 1.7;
}
.guest-logo {
display: grid;
width: 74px;
height: 74px;
margin: 0 auto;
place-items: center;
border-radius: 22px;
background: #1477ff;
color: #fff;
font-size: 30px;
font-weight: 900;
}
.guest-login-btn {
margin-top: 20px;
border-radius: 13px;
background: #1477ff;
border-color: transparent;
font-size: 16px;
font-weight: 900;
height: 48px;
}
.guest-benefits {
display: flex;
justify-content: center;
gap: 8px;
margin-top: 16px;
}
.guest-benefits :deep(.van-tag) {
font-weight: 800;
}
/* ========== 已登录区 - Hero蓝色横幅 ========== */
.profile-hero {
position: relative;
+217 -248
View File
@@ -1,12 +1,13 @@
<script setup lang="ts">
import { onUnmounted, reactive, ref } from "vue";
import { RouterLink, useRouter } from "vue-router";
import { RouterLink, useRoute, useRouter } from "vue-router";
import { showToast } from "vant";
import { sendSmsCode } from "@/api/auth";
import { useSessionStore } from "@/stores/session";
const router = useRouter();
const route = useRoute();
const session = useSessionStore();
const loading = ref(false);
const sending = ref(false);
@@ -85,7 +86,8 @@ async function handleRegister() {
loading.value = true;
try {
await session.login(form.phone, form.code);
await router.push("/m/profile");
const redirect = typeof route.query.redirect === "string" ? route.query.redirect : "/m/profile";
await router.replace(redirect);
} catch {
showToast({ message: "注册失败,请检查手机号和验证码", icon: "cross" });
} finally {
@@ -96,275 +98,288 @@ async function handleRegister() {
<template>
<main class="mobile-register-shell">
<section class="register-card">
<!-- 品牌区域 -->
<div class="register-top">
<div class="monster-logo"></div>
<header class="page-header">
<button class="back-btn" type="button" @click="router.back()">
<van-icon name="arrow-left" :size="20" />
</button>
<h1>注册</h1>
<span class="header-spacer"></span>
</header>
<section class="auth-body">
<div class="brand-row">
<div class="brand-logo"></div>
<div>
<p>加入大锤商行</p>
<small>注册后即可租号下单发布账号</small>
<strong>加入大锤商行</strong>
<p>注册后即可租号下单发布账号</p>
</div>
</div>
<!-- 登录/注册 Tab 切换 -->
<div class="auth-switch" aria-label="登录注册切换">
<RouterLink to="/m/login">登录</RouterLink>
<RouterLink to="/m/register" class="active">注册</RouterLink>
</div>
<p class="register-eyebrow">CREATE ACCOUNT</p>
<h1>手机号注册</h1>
<p class="register-subtitle">
先用短信验证码创建账号后续再补充实名和收款信息
</p>
<div class="form-section">
<div class="section-heading">
<h2>手机号注册</h2>
<p>先用短信验证码创建账号后续再补充实名和收款信息</p>
</div>
<!-- 手机号输入 -->
<van-field
v-model="form.phone"
type="tel"
maxlength="11"
inputmode="tel"
placeholder="请输入手机号"
clearable
class="register-field"
>
<template #left-icon>
<label class="auth-input-row">
<span class="input-label">手机号</span>
<span class="field-prefix">+86</span>
</template>
</van-field>
<input
v-model="form.phone"
type="tel"
maxlength="11"
inputmode="tel"
placeholder="请输入手机号"
/>
</label>
<!-- 验证码输入 -->
<van-field
v-model="form.code"
type="digit"
maxlength="6"
placeholder="6 位验证码"
class="register-field"
:left-icon="'shield-o'"
>
<template #button>
<van-button
size="small"
type="primary"
plain
round
:disabled="sending || countDown > 0"
:loading="sending"
@click="handleSendCode"
>
{{
countDown > 0
? `${countDown}s`
: sending
? "发送中"
: "发送验证码"
}}
</van-button>
</template>
</van-field>
<label class="auth-input-row code-row">
<span class="input-label">验证码</span>
<input
v-model="form.code"
type="text"
inputmode="numeric"
maxlength="6"
placeholder="6 位验证码"
/>
<span class="code-action">
<van-button
size="small"
type="primary"
plain
:disabled="sending || countDown > 0"
:loading="sending"
class="code-btn"
@click="handleSendCode"
>
{{
countDown > 0
? `${countDown}s`
: sending
? "发送中"
: "发送验证码"
}}
</van-button>
</span>
</label>
<!-- 邀请码输入 -->
<van-field
v-model="form.inviteCode"
maxlength="16"
placeholder="选填,有邀请码填入"
clearable
class="register-field"
:left-icon="'friends-o'"
/>
<label class="auth-input-row">
<span class="input-label">邀请码</span>
<input
v-model="form.inviteCode"
maxlength="16"
placeholder="选填,有邀请码填入"
/>
</label>
<!-- 用户协议 -->
<div class="agreement-row">
<van-checkbox v-model="agreed" shape="square" icon-size="16px">
我已阅读并同意<b>用户协议</b><b>隐私政策</b>
</van-checkbox>
</div>
<div class="agreement-row">
<van-checkbox v-model="agreed" shape="square" icon-size="16px">
我已阅读并同意<b>用户协议</b><b>隐私政策</b>
</van-checkbox>
</div>
<!-- 注册按钮 -->
<van-button
type="primary"
block
round
class="register-button"
:loading="loading"
loading-text="注册中..."
@click="handleRegister"
>
注册并登录
</van-button>
<!-- 底部登录入口 -->
<RouterLink
to="/m/login"
class="login-entry"
custom
v-slot="{ navigate }"
>
<van-button
plain
type="primary"
block
round
size="small"
class="login-link-button"
@click="navigate"
class="primary-button"
:loading="loading"
loading-text="注册中..."
@click="handleRegister"
>
已有账号登录
注册并登录
</van-button>
</div>
<RouterLink to="/m/login" class="secondary-entry">
已有账号去登录
</RouterLink>
</section>
</main>
</template>
<style scoped>
/* ========== Vant 主题变量覆盖 ========== */
:root {
--van-primary-color: #5b6ee1;
--van-button-primary-background: #5b6ee1;
--van-button-primary-border-color: transparent;
}
/* ========== 页面容器 ========== */
.mobile-register-shell {
min-height: 100dvh;
box-sizing: border-box;
overflow: hidden;
background: #f5f6f8;
background: #f4f6f8;
color: #151c28;
padding: 40px 24px;
}
.register-card {
.page-header {
position: sticky;
top: 0;
z-index: 10;
display: flex;
min-height: calc(100dvh - 80px);
flex-direction: column;
justify-content: center;
align-items: center;
height: 48px;
padding: 0 12px;
background: #fff;
border-bottom: 1px solid #eceff3;
}
/* ========== 品牌区域 ========== */
.register-top {
.page-header h1 {
flex: 1;
margin: 0;
font-size: 17px;
font-weight: 700;
text-align: center;
}
.back-btn {
display: grid;
width: 36px;
height: 36px;
place-items: center;
border: none;
background: none;
color: #25282d;
}
.header-spacer {
width: 36px;
}
.auth-body {
padding: 14px;
}
.brand-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 14px;
padding: 8px 2px 14px;
}
.monster-logo {
.brand-logo {
display: grid;
width: 48px;
height: 48px;
flex: 0 0 auto;
width: 42px;
height: 42px;
place-items: center;
border-radius: 16px;
background: #5b6ee1;
border-radius: 12px;
background: #1477ff;
color: #ffffff;
font-size: 21px;
font-size: 18px;
font-weight: 900;
box-shadow: 0 4px 12px rgba(91, 110, 225, 0.18);
}
.register-top p {
.brand-row strong {
display: block;
margin: 0 0 2px;
font-size: 20px;
color: #171a1f;
font-size: 18px;
font-weight: 900;
}
.register-top small,
.register-subtitle {
color: #667386;
.brand-row p {
margin: 0;
color: #6b7280;
font-size: 12px;
}
/* ========== Tab 切换 ========== */
.auth-switch {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-bottom: 16px;
border-radius: 15px;
background: #eef4fb;
padding: 5px;
gap: 6px;
margin-bottom: 12px;
padding: 4px;
border-radius: 8px;
background: #eaf0f8;
}
.auth-switch a {
border-radius: 11px;
color: #667386;
padding: 10px 0;
padding: 9px 0;
border-radius: 7px;
color: #5f6875;
text-align: center;
font-size: 14px;
font-weight: 900;
font-size: 13px;
font-weight: 800;
text-decoration: none;
}
.auth-switch a.active {
background: #ffffff;
color: #111827;
box-shadow: 0 8px 18px rgba(23, 35, 61, 0.08);
color: #1477ff;
}
/* ========== 标题区 ========== */
.register-eyebrow {
margin: 0 0 5px;
color: #02846e;
.form-section {
padding: 14px;
background: #fff;
border: 1px solid #edf0f4;
border-radius: 8px;
}
.section-heading h2 {
margin: 0 0 4px;
color: #171a1f;
font-size: 18px;
font-weight: 800;
}
.section-heading p {
margin: 0 0 12px;
color: #858c96;
font-size: 12px;
font-weight: 900;
letter-spacing: 0.04em;
line-height: 1.5;
}
.register-card h1 {
margin: 0;
font-size: 28px;
line-height: 1.15;
.auth-input-row {
display: grid;
grid-template-columns: 58px 38px minmax(0, 1fr);
align-items: center;
min-height: 44px;
margin-bottom: 8px;
padding: 0 12px;
border-radius: 8px;
background: #f8fafc;
}
.register-subtitle {
margin: 7px 0 14px;
.auth-input-row.code-row {
grid-template-columns: 58px minmax(0, 1fr) 92px;
gap: 8px;
}
.input-label {
color: #30343a;
font-size: 13px;
line-height: 1.45;
}
/* ========== Vant Field 覆盖样式 ========== */
.register-field {
margin-top: 12px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.92);
box-shadow: inset 0 1px 3px rgba(23, 35, 61, 0.04);
overflow: hidden;
}
.register-field :deep(.van-field__control) {
font-size: 15px;
color: #151c28;
}
.register-field :deep(.van-field__label) {
width: auto;
margin-right: 8px;
color: #333b48;
font-weight: 700;
font-size: 13px;
}
.register-field :deep(.van-field__left-icon) {
color: #1777ff;
margin-right: 0;
}
.register-field :deep(.van-field__right-icon) {
color: #999;
.auth-input-row input {
width: 100%;
min-width: 0;
border: none;
background: transparent;
color: #20242a;
font-size: 14px;
outline: none;
}
.auth-input-row input::placeholder {
color: #c0c4cc;
}
.field-prefix {
color: #1777ff;
color: #1477ff;
font-weight: 800;
font-size: 14px;
margin-right: 4px;
}
/* ========== 协议行 ========== */
.code-action {
display: flex;
justify-content: flex-end;
}
.code-btn {
border-radius: 8px;
}
.agreement-row {
display: flex;
align-items: center;
margin-top: 16px;
margin-bottom: 16px;
margin: 10px 0 14px;
}
.agreement-row :deep(.van-checkbox__label) {
@@ -379,72 +394,26 @@ async function handleRegister() {
font-weight: 600;
}
/* ========== 注册按钮 ========== */
.register-button {
margin-top: 6px;
height: 46px;
font-size: 15px;
font-weight: 800;
background: #5b6ee1 !important;
.primary-button {
height: 42px;
border: none !important;
box-shadow: 0 4px 12px rgba(91, 110, 225, 0.18);
border-radius: 8px !important;
background: #1477ff !important;
font-size: 15px;
font-weight: 700;
}
/* ========== 登录入口按钮 ========== */
.login-link-button {
.secondary-entry {
display: block;
margin-top: 12px;
padding: 12px;
border: 1px solid #d7dce3;
border-radius: 8px;
background: #fff;
color: #1477ff;
font-size: 13px;
font-weight: 800;
}
.login-entry {
text-align: center;
text-decoration: none;
}
/* ========== 响应式 ========== */
@media (max-height: 620px) {
.mobile-register-shell {
padding-top: 10px;
padding-bottom: 10px;
}
.register-card {
min-height: calc(100dvh - 20px);
}
.register-top {
margin-bottom: 10px;
}
.monster-logo {
width: 42px;
height: 42px;
border-radius: 14px;
}
.auth-switch {
margin-bottom: 11px;
}
.register-card h1 {
font-size: 24px;
}
.register-field {
margin-top: 8px;
}
.register-button {
height: 42px;
margin-top: 10px;
}
}
@media (min-width: 520px) {
.mobile-register-shell {
max-width: 430px;
margin: 0 auto;
box-shadow: 0 0 0 1px rgba(23, 35, 61, 0.08);
}
}
</style>