1
0
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:
小莫唐尼
2026-06-16 00:43:48 +08:00
parent 1ba71ff43f
commit a9e649e110
19 changed files with 1077 additions and 597 deletions
+354 -16
View File
@@ -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>