mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-07-27 04:20:43 +08:00
a510875d38
1. 将动态页面默认视图从时间线模式改为非时间线模式 2. 修复分享按钮的默认样式问题,移除多余边框和背景 3. 调整登录页分隔线上下间距与微信登录按钮高度 4. 隐藏文章卡片的分类信息展示
404 lines
12 KiB
Vue
404 lines
12 KiB
Vue
<script lang="ts" setup>
|
||
import { systemInfo } from '@/utils/systemInfo'
|
||
import { useTokenStore } from '@/store/token'
|
||
import { useGuestStore } from '@/store/guest'
|
||
import GuestInfoPanel from '@/components/post-detail/uh-guest-info-panel.vue'
|
||
|
||
defineOptions({ name: 'Login' })
|
||
|
||
definePage({
|
||
style: {
|
||
navigationBarTitleText: '登录',
|
||
navigationStyle: 'custom',
|
||
navigationBarBackgroundColor: '#ffffff',
|
||
},
|
||
})
|
||
|
||
const tokenStore = useTokenStore()
|
||
const guestStore = useGuestStore()
|
||
|
||
// ---- Tab 切换 ----
|
||
type AuthMode = 'login' | 'register'
|
||
const activeMode = ref<AuthMode>('login')
|
||
|
||
function switchMode(mode: AuthMode) {
|
||
activeMode.value = mode
|
||
// 切换时清空错误提示
|
||
clearErrors()
|
||
}
|
||
|
||
// ---- 登录表单 ----
|
||
const loginForm = reactive({
|
||
username: '',
|
||
password: '',
|
||
})
|
||
|
||
const loginErrors = reactive({
|
||
username: '',
|
||
password: '',
|
||
})
|
||
|
||
function validateLogin(): boolean {
|
||
let valid = true
|
||
loginErrors.username = ''
|
||
loginErrors.password = ''
|
||
|
||
if (!loginForm.username.trim()) {
|
||
loginErrors.username = '请输入用户名'
|
||
valid = false
|
||
}
|
||
if (!loginForm.password.trim()) {
|
||
loginErrors.password = '请输入密码'
|
||
valid = false
|
||
}
|
||
return valid
|
||
}
|
||
|
||
async function handleLogin() {
|
||
if (!validateLogin())
|
||
return
|
||
|
||
try {
|
||
await tokenStore.login({
|
||
username: loginForm.username.trim(),
|
||
password: loginForm.password.trim(),
|
||
})
|
||
handleLoginSuccess()
|
||
}
|
||
catch (error) {
|
||
console.error('登录失败:', error)
|
||
}
|
||
}
|
||
|
||
// ---- 注册表单 ----
|
||
const registerForm = reactive({
|
||
username: '',
|
||
password: '',
|
||
confirmPassword: '',
|
||
})
|
||
|
||
const registerErrors = reactive({
|
||
username: '',
|
||
password: '',
|
||
confirmPassword: '',
|
||
})
|
||
|
||
function validateRegister(): boolean {
|
||
let valid = true
|
||
registerErrors.username = ''
|
||
registerErrors.password = ''
|
||
registerErrors.confirmPassword = ''
|
||
|
||
if (!registerForm.username.trim()) {
|
||
registerErrors.username = '请输入用户名'
|
||
valid = false
|
||
}
|
||
if (!registerForm.password.trim()) {
|
||
registerErrors.password = '请输入密码'
|
||
valid = false
|
||
}
|
||
else if (registerForm.password.length < 6) {
|
||
registerErrors.password = '密码至少6位'
|
||
valid = false
|
||
}
|
||
if (!registerForm.confirmPassword.trim()) {
|
||
registerErrors.confirmPassword = '请确认密码'
|
||
valid = false
|
||
}
|
||
else if (registerForm.password !== registerForm.confirmPassword) {
|
||
registerErrors.confirmPassword = '两次密码不一致'
|
||
valid = false
|
||
}
|
||
return valid
|
||
}
|
||
|
||
async function handleRegister() {
|
||
if (!validateRegister())
|
||
return
|
||
|
||
try {
|
||
// TODO: 调用注册 API
|
||
// await register({
|
||
// username: registerForm.username.trim(),
|
||
// password: registerForm.password.trim(),
|
||
// })
|
||
uni.showToast({ title: '注册成功', icon: 'success' })
|
||
// 注册成功后切换到登录
|
||
switchMode('login')
|
||
loginForm.username = registerForm.username
|
||
loginForm.password = ''
|
||
}
|
||
catch (error) {
|
||
console.error('注册失败:', error)
|
||
}
|
||
}
|
||
|
||
function clearErrors() {
|
||
loginErrors.username = ''
|
||
loginErrors.password = ''
|
||
registerErrors.username = ''
|
||
registerErrors.password = ''
|
||
registerErrors.confirmPassword = ''
|
||
}
|
||
|
||
// ---- 密码可见性 ----
|
||
const showLoginPwd = ref(false)
|
||
const showRegisterPwd = ref(false)
|
||
const showConfirmPwd = ref(false)
|
||
|
||
// ---- 微信一键登录 ----
|
||
// #ifdef MP-WEIXIN
|
||
async function handleWxLogin() {
|
||
try {
|
||
await tokenStore.wxLogin()
|
||
handleLoginSuccess()
|
||
}
|
||
catch (error) {
|
||
console.error('微信登录失败:', error)
|
||
}
|
||
}
|
||
// #endif
|
||
|
||
// ---- 游客身份访问 ----
|
||
const showGuestPanel = ref(false)
|
||
|
||
function handleGuestAccess() {
|
||
showGuestPanel.value = true
|
||
}
|
||
|
||
function handleGuestSaved() {
|
||
showGuestPanel.value = false
|
||
uni.navigateBack()
|
||
}
|
||
|
||
// ---- 登录成功处理 ----
|
||
function handleLoginSuccess() {
|
||
// 检查是否有重定向地址(从路由拦截器传入)
|
||
const pages = getCurrentPages()
|
||
const currentPage = pages[pages.length - 1] as any
|
||
const redirect = currentPage?.$page?.options?.redirect || currentPage?.options?.redirect
|
||
|
||
if (redirect) {
|
||
uni.redirectTo({ url: decodeURIComponent(redirect) })
|
||
}
|
||
else {
|
||
uni.navigateBack()
|
||
}
|
||
}
|
||
|
||
// ---- 密码输入框切换可见性 ----
|
||
function togglePwdVisibility(target: 'login' | 'register' | 'confirm') {
|
||
if (target === 'login')
|
||
showLoginPwd.value = !showLoginPwd.value
|
||
else if (target === 'register')
|
||
showRegisterPwd.value = !showRegisterPwd.value
|
||
else showConfirmPwd.value = !showConfirmPwd.value
|
||
}
|
||
|
||
function handleBack() {
|
||
uni.navigateBack()
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<view
|
||
class="box-border min-h-screen w-full flex flex-col items-center justify-center bg-page3 px-6"
|
||
:class="[
|
||
systemInfo.uniPlatform ? 'pt-safe' : 'pt-12',
|
||
]"
|
||
>
|
||
<!-- 头部 Logo -->
|
||
<view
|
||
class="mb-8 mt-8 w-full flex flex-col items-center gap-y-2"
|
||
>
|
||
<image
|
||
class="h-16 w-16 rounded-2xl"
|
||
src="/static/logo.png"
|
||
mode="scaleToFill"
|
||
/>
|
||
<text class="text-xl text-gray-900 font-bold">欢迎回来</text>
|
||
<text class="text-xs text-gray-400">登录你的账号,探索更多精彩</text>
|
||
</view>
|
||
|
||
<!-- Tab 切换 -->
|
||
<view class="mb-6 box-border w-full flex items-center rounded-xl bg-gray-100 p-1">
|
||
<view
|
||
class="center flex-1 rounded-lg py-2 text-sm font-medium transition-all"
|
||
:class="activeMode === 'login' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-500'"
|
||
@click="switchMode('login')"
|
||
>
|
||
登录
|
||
</view>
|
||
<view
|
||
class="center flex-1 rounded-lg py-2 text-sm font-medium transition-all"
|
||
:class="activeMode === 'register' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-500'"
|
||
@click="switchMode('register')"
|
||
>
|
||
注册
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 登录表单 -->
|
||
<view v-if="activeMode === 'login'" class="w-full flex flex-col gap-y-4">
|
||
<!-- 用户名 -->
|
||
<view class="flex flex-col gap-y-1">
|
||
<view class="flex items-center rounded-xl bg-gray-100 px-4">
|
||
<wd-icon name="user" color="#9CA3AF" :size="16" />
|
||
<input
|
||
v-model="loginForm.username"
|
||
class="flex-1 py-2.5 pl-2 text-sm"
|
||
placeholder="请输入用户名"
|
||
:maxlength="30"
|
||
>
|
||
</view>
|
||
<text v-if="loginErrors.username" class="text-[11px] text-red-500">{{ loginErrors.username }}</text>
|
||
</view>
|
||
|
||
<!-- 密码 -->
|
||
<view class="flex flex-col gap-y-1">
|
||
<view class="flex items-center rounded-xl bg-gray-100 px-4">
|
||
<wd-icon name="lock" color="#9CA3AF" :size="16" />
|
||
<input
|
||
v-model="loginForm.password"
|
||
class="flex-1 py-2.5 pl-2 text-sm"
|
||
placeholder="请输入密码"
|
||
:password="!showLoginPwd"
|
||
:maxlength="30"
|
||
>
|
||
<view @click="togglePwdVisibility('login')">
|
||
<wd-icon :name="showLoginPwd ? 'view' : 'eye-close'" color="#9CA3AF" :size="16" />
|
||
</view>
|
||
</view>
|
||
<text v-if="loginErrors.password" class="text-[11px] text-red-500">{{ loginErrors.password }}</text>
|
||
</view>
|
||
|
||
<!-- 登录按钮 -->
|
||
<view
|
||
class="mt-2 h-11 w-full center rounded-xl bg-gray-900 text-sm text-white font-medium"
|
||
@click="handleLogin"
|
||
>
|
||
登录
|
||
</view>
|
||
<!-- 返回按钮 -->
|
||
<view
|
||
class="box-border h-10 w-full center gap-x-1 border border-gray-600 rounded-xl border-solid text-xs text-gray-600"
|
||
@click="handleBack"
|
||
>
|
||
暂不登录
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 注册表单 -->
|
||
<view v-if="activeMode === 'register'" class="w-full flex flex-col gap-y-4">
|
||
<!-- 用户名 -->
|
||
<view class="flex flex-col gap-y-1">
|
||
<view class="flex items-center rounded-xl bg-gray-100 px-4">
|
||
<wd-icon name="user" color="#9CA3AF" :size="16" />
|
||
<input
|
||
v-model="registerForm.username"
|
||
class="flex-1 py-2.5 pl-2 text-sm"
|
||
placeholder="请输入用户名"
|
||
:maxlength="30"
|
||
>
|
||
</view>
|
||
<text v-if="registerErrors.username" class="text-[11px] text-red-500">{{ registerErrors.username }}</text>
|
||
</view>
|
||
|
||
<!-- 密码 -->
|
||
<view class="flex flex-col gap-y-1">
|
||
<view class="flex items-center rounded-xl bg-gray-100 px-4">
|
||
<wd-icon name="lock" color="#9CA3AF" :size="16" />
|
||
<input
|
||
v-model="registerForm.password"
|
||
class="flex-1 py-2.5 pl-2 text-sm"
|
||
placeholder="请输入密码(至少6位)"
|
||
:password="!showRegisterPwd"
|
||
:maxlength="30"
|
||
>
|
||
<view @click="togglePwdVisibility('register')">
|
||
<wd-icon :name="showRegisterPwd ? 'view' : 'eye-close'" color="#9CA3AF" :size="16" />
|
||
</view>
|
||
</view>
|
||
<text v-if="registerErrors.password" class="text-[11px] text-red-500">{{ registerErrors.password }}</text>
|
||
</view>
|
||
|
||
<!-- 确认密码 -->
|
||
<view class="flex flex-col gap-y-1">
|
||
<view class="flex items-center rounded-xl bg-gray-100 px-4">
|
||
<wd-icon name="lock" color="#9CA3AF" :size="16" />
|
||
<input
|
||
v-model="registerForm.confirmPassword"
|
||
class="flex-1 py-2.5 pl-2 text-sm"
|
||
placeholder="请再次输入密码"
|
||
:password="!showConfirmPwd"
|
||
:maxlength="30"
|
||
>
|
||
<view @click="togglePwdVisibility('confirm')">
|
||
<wd-icon :name="showConfirmPwd ? 'view' : 'eye-close'" color="#9CA3AF" :size="16" />
|
||
</view>
|
||
</view>
|
||
<text v-if="registerErrors.confirmPassword" class="text-[11px] text-red-500">{{ registerErrors.confirmPassword }}</text>
|
||
</view>
|
||
|
||
<!-- 注册按钮 -->
|
||
<view
|
||
class="mt-2 h-11 w-full center rounded-xl bg-gray-900 text-sm text-white font-medium"
|
||
@click="handleRegister"
|
||
>
|
||
注册
|
||
</view>
|
||
<!-- 返回按钮 -->
|
||
<view
|
||
class="box-border h-10 w-full center gap-x-1 border border-gray-600 rounded-xl border-solid text-xs text-gray-600"
|
||
@click="handleBack"
|
||
>
|
||
暂不登录
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 分隔线 -->
|
||
<view class="my-6 w-full flex items-center justify-center gap-x-3">
|
||
<view class="h-px flex-1 bg-gray-100" />
|
||
<text class="text-xs text-gray-400">其他方式</text>
|
||
<view class="h-px flex-1 bg-gray-100" />
|
||
</view>
|
||
|
||
<!-- 第三方登录 & 游客访问 -->
|
||
<view class="w-full flex flex-col items-center gap-y-3">
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<view
|
||
class="h-10 w-full flex items-center justify-center gap-x-2 rounded-xl bg-[#07C160] text-sm text-white font-medium"
|
||
@click="handleWxLogin"
|
||
>
|
||
<wd-icon name="wechat" color="#FFFFFF" :size="18" />
|
||
<text>微信一键登录</text>
|
||
</view>
|
||
<!-- #endif -->
|
||
|
||
<view
|
||
class="w-full flex items-center justify-center gap-x-2 border border-gray-200 rounded-xl py-1 text-sm text-gray-600"
|
||
@click="handleGuestAccess"
|
||
>
|
||
<text>游客身份访问</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部协议提示 -->
|
||
<view class="mb-8 w-full flex flex-col items-center gap-y-1 pt-6">
|
||
<text class="text-[11px] text-gray-400">登录或注册即代表同意</text>
|
||
<view class="flex items-center gap-x-1">
|
||
<text class="text-[11px] text-gray-500 font-medium">《用户协议》</text>
|
||
<text class="text-[11px] text-gray-400">和</text>
|
||
<text class="text-[11px] text-gray-500 font-medium">《隐私政策》</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 游客信息编辑面板 -->
|
||
<GuestInfoPanel
|
||
v-if="showGuestPanel"
|
||
@close="showGuestPanel = false"
|
||
@saved="handleGuestSaved"
|
||
/>
|
||
</view>
|
||
</template>
|