mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-07-27 04:20:43 +08:00
feat: 新增点赞、游客评论、分享等核心功能,重构页面逻辑
1. 新增全局点赞状态管理,使用metadata.name做key并持久化存储 2. 新增游客信息存储与评论面板,支持游客评论互动 3. 新增全局分享hook,为多个页面配置分享功能 4. 重构登录页面,支持登录/注册切换与游客访问模式 5. 合并注册页到登录页,简化路由结构 6. 优化剪贴板工具函数,支持自定义提示文本 7. 重构个人中心页面,支持游客信息管理 8. 修复相册页面标题与样式问题 9. 移除无用的备份文件与测试代码
This commit is contained in:
+354
-16
@@ -1,40 +1,378 @@
|
||||
<script lang="ts" setup>
|
||||
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: '登录',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
},
|
||||
})
|
||||
|
||||
const tokenStore = useTokenStore()
|
||||
async function doLogin() {
|
||||
if (tokenStore.hasLogin) {
|
||||
uni.navigateBack()
|
||||
return
|
||||
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: '小莫唐尼',
|
||||
password: '123456',
|
||||
username: loginForm.username.trim(),
|
||||
password: loginForm.password.trim(),
|
||||
})
|
||||
uni.navigateBack()
|
||||
handleLoginSuccess()
|
||||
}
|
||||
catch (error) {
|
||||
console.log('登录失败', 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
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen w-full flex flex-col items-center justify-center gap-y-6 bg-page">
|
||||
<!-- 本页面是非MP的登录页,主要用于 h5 和 APP -->
|
||||
<view class="text-center">
|
||||
登录页
|
||||
<view class="bg-page3 box-border min-h-screen w-full flex flex-col px-6 pt-12">
|
||||
<!-- 头部 Logo -->
|
||||
<view class="mb-8 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>
|
||||
<button class="mt-4 w-40 text-center" @click="doLogin">
|
||||
点击模拟登录
|
||||
</button>
|
||||
|
||||
<!-- Tab 切换 -->
|
||||
<view class="mb-6 flex items-center rounded-xl bg-gray-100 p-1">
|
||||
<view
|
||||
class="flex-1 center 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="flex-1 center 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="flex flex-col gap-y-4">
|
||||
<!-- 用户名 -->
|
||||
<view class="flex flex-col gap-y-1">
|
||||
<text class="text-xs text-gray-500 font-medium">用户名</text>
|
||||
<view class="flex items-center rounded-xl bg-gray-50 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">
|
||||
<text class="text-xs text-gray-500 font-medium">密码</text>
|
||||
<view class="flex items-center rounded-xl bg-gray-50 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>
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<view v-if="activeMode === 'register'" class="flex flex-col gap-y-4">
|
||||
<!-- 用户名 -->
|
||||
<view class="flex flex-col gap-y-1">
|
||||
<text class="text-xs text-gray-500 font-medium">用户名</text>
|
||||
<view class="flex items-center rounded-xl bg-gray-50 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">
|
||||
<text class="text-xs text-gray-500 font-medium">密码</text>
|
||||
<view class="flex items-center rounded-xl bg-gray-50 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">
|
||||
<text class="text-xs text-gray-500 font-medium">确认密码</text>
|
||||
<view class="flex items-center rounded-xl bg-gray-50 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>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<view class="my-6 flex items-center gap-x-3">
|
||||
<view class="h-px flex-1 bg-gray-200" />
|
||||
<text class="text-xs text-gray-400">其他方式</text>
|
||||
<view class="h-px flex-1 bg-gray-200" />
|
||||
</view>
|
||||
|
||||
<!-- 第三方登录 & 游客访问 -->
|
||||
<view class="flex flex-col items-center gap-y-3">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view
|
||||
class="h-11 w-full flex items-center justify-center gap-x-2 rounded-xl border border-green-500 text-sm text-green-600 font-medium"
|
||||
@click="handleWxLogin"
|
||||
>
|
||||
<wd-icon name="wechat" color="#16A34A" :size="18" />
|
||||
<text>微信一键登录</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<view
|
||||
class="h-11 w-full flex items-center justify-center gap-x-2 rounded-xl border border-gray-200 text-sm text-gray-600"
|
||||
@click="handleGuestAccess"
|
||||
>
|
||||
<wd-icon name="user" color="#6B7280" :size="16" />
|
||||
<text>游客身份访问</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部协议提示 -->
|
||||
<view class="mt-auto mb-8 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>
|
||||
|
||||
Reference in New Issue
Block a user