mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-07-27 12:30:41 +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>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { LOGIN_PAGE } from '@/router/config'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '注册',
|
||||
},
|
||||
})
|
||||
|
||||
function doRegister() {
|
||||
uni.showToast({
|
||||
title: '注册成功',
|
||||
})
|
||||
// 注册成功后跳转到登录页
|
||||
uni.navigateTo({
|
||||
url: LOGIN_PAGE,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen w-full flex flex-col items-center justify-center gap-y-6 bg-page">
|
||||
<view class="text-center">
|
||||
注册页
|
||||
</view>
|
||||
<button class="mt-4 w-40 text-center" @click="doRegister">
|
||||
点击模拟注册
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
@@ -1,348 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { getPicSumImages } from '@/utils/randomResources'
|
||||
import { queryLinks } from '@/api/halo-plugin/link'
|
||||
|
||||
defineOptions({
|
||||
name: 'Gallery',
|
||||
})
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '相册',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
enablePullDownRefresh: true,
|
||||
},
|
||||
})
|
||||
|
||||
interface GalleryItem {
|
||||
metadataName: string
|
||||
displayName: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface GalleryGroup {
|
||||
metadataName: string
|
||||
displayName: string
|
||||
images: GalleryItem[]
|
||||
}
|
||||
|
||||
const groupBanner = reactive({
|
||||
current: 0,
|
||||
})
|
||||
const galleryStyle = ref('list')
|
||||
const showListPanel = reactive({
|
||||
show: false,
|
||||
metadataName: '',
|
||||
})
|
||||
|
||||
// 相册分组预览
|
||||
const galleryGroups = ref<GalleryGroup[]>([
|
||||
{
|
||||
metadataName: 'photo-group-HGaGs',
|
||||
displayName: '我们的故事',
|
||||
images: [{
|
||||
metadataName: '',
|
||||
displayName: '图片名称1',
|
||||
url: getPicSumImages(800, 600),
|
||||
}, {
|
||||
metadataName: '',
|
||||
displayName: '图片名称2',
|
||||
url: getPicSumImages(800, 600),
|
||||
}, {
|
||||
metadataName: '',
|
||||
displayName: '图片名称3',
|
||||
url: getPicSumImages(800, 600),
|
||||
}, {
|
||||
metadataName: '',
|
||||
displayName: '图片名称4',
|
||||
url: getPicSumImages(800, 600),
|
||||
}],
|
||||
},
|
||||
{
|
||||
metadataName: '履行记录',
|
||||
displayName: '履行记录',
|
||||
images: [{
|
||||
metadataName: '',
|
||||
displayName: '图片名称1',
|
||||
url: getPicSumImages(800, 600),
|
||||
}, {
|
||||
metadataName: '',
|
||||
displayName: '图片名称2',
|
||||
url: getPicSumImages(800, 600),
|
||||
}, {
|
||||
metadataName: '',
|
||||
displayName: '图片名称3',
|
||||
url: getPicSumImages(800, 600),
|
||||
}],
|
||||
},
|
||||
{
|
||||
metadataName: '家庭时光',
|
||||
displayName: '家庭时光',
|
||||
images: [{
|
||||
metadataName: '',
|
||||
displayName: '图片名称1',
|
||||
url: getPicSumImages(800, 600),
|
||||
}, {
|
||||
metadataName: '',
|
||||
displayName: '图片名称2',
|
||||
url: getPicSumImages(800, 600),
|
||||
}],
|
||||
},
|
||||
{
|
||||
metadataName: '其他',
|
||||
displayName: '其他',
|
||||
images: [{
|
||||
metadataName: '',
|
||||
displayName: '图片名称1',
|
||||
url: getPicSumImages(800, 600),
|
||||
}],
|
||||
},
|
||||
])
|
||||
|
||||
// 相册图片
|
||||
const galleryItems = ref<GalleryItem[]>([
|
||||
{
|
||||
metadataName: '',
|
||||
displayName: '图片名称1',
|
||||
url: getPicSumImages(400, 400),
|
||||
},
|
||||
{
|
||||
metadataName: '',
|
||||
displayName: '图片名称2',
|
||||
url: getPicSumImages(800, 600),
|
||||
},
|
||||
{
|
||||
metadataName: '',
|
||||
displayName: '图片名称3',
|
||||
url: getPicSumImages(400, 800),
|
||||
},
|
||||
{
|
||||
metadataName: '',
|
||||
displayName: '图片名称4',
|
||||
url: getPicSumImages(1920, 1080),
|
||||
},
|
||||
{
|
||||
metadataName: '',
|
||||
displayName: '图片名称5',
|
||||
url: getPicSumImages(800, 1920),
|
||||
},
|
||||
])
|
||||
|
||||
const { loading, error, data, run } = useRequest<any, IPaginationParams>(queryLinks, { loadingToast: false, loadingToastContent: '加载中...', loadingToastMask: true })
|
||||
|
||||
const { list: links, refresh } = useListData<any>({
|
||||
params: {
|
||||
page: 1,
|
||||
size: 0,
|
||||
},
|
||||
loading: toRef(loading),
|
||||
onPullDownRefresh: async (params, updateData) => {
|
||||
await run({ ...params })
|
||||
updateData({
|
||||
error: error.value,
|
||||
hasNext: data.value?.hasNext,
|
||||
items: data.value?.items ?? [],
|
||||
})
|
||||
},
|
||||
onReachBottom: async (params, updateData) => {
|
||||
await run({ ...params })
|
||||
updateData({
|
||||
error: error.value,
|
||||
hasNext: data.value?.hasNext,
|
||||
items: data.value?.items ?? [],
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
function onGroupBannerChange(e: any) {
|
||||
groupBanner.current = e.detail.current
|
||||
}
|
||||
|
||||
function getGroupImageRotateClass(index: number) {
|
||||
if (index === 0) {
|
||||
return 'z-30 border-2 border-solid border-white uh-shadow-card group-hover:scale-95'
|
||||
}
|
||||
if (index === 1) {
|
||||
return 'z-20 -rotate-6 group-hover:-rotate-22 border-2 border-solid border-white uh-shadow-card'
|
||||
}
|
||||
if (index === 2) {
|
||||
return 'z-10 rotate-6 group-hover:rotate-22 border-2 border-solid border-white uh-shadow-card'
|
||||
}
|
||||
}
|
||||
|
||||
// -- 图片列表模式
|
||||
// 图片列表容器样式
|
||||
function getGalleryListContainerClass(total: number) {
|
||||
if (total === 1) {
|
||||
return 'h-36'
|
||||
}
|
||||
if (total === 2) {
|
||||
return 'grid-cols-2 h-32'
|
||||
}
|
||||
if (total === 3) {
|
||||
return 'grid-cols-2 grid-rows-2 h-36'
|
||||
}
|
||||
if (total === 4) {
|
||||
return 'grid-cols-2 grid-rows-2 h-42'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
// 图片项样式
|
||||
function getGalleryListItemClass(index: number, total: number) {
|
||||
if (total === 1) {
|
||||
return ''
|
||||
}
|
||||
if (total === 2) {
|
||||
return ''
|
||||
}
|
||||
if (total === 3) {
|
||||
if (index === 0) {
|
||||
return 'row-span-2'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
if (total === 4) {
|
||||
return ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function handleShowListPanel(metadataName: string) {
|
||||
showListPanel.metadataName = metadataName
|
||||
showListPanel.show = true
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
refresh()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
})
|
||||
|
||||
onPageScroll(() => { })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen w-full flex flex-col bg-page">
|
||||
<!-- 分组列表:常态显示 -->
|
||||
<view class="box-border w-full px-4 py-4">
|
||||
<!-- 顶部区域固定区域 -->
|
||||
<view class="relative w-full">
|
||||
<swiper
|
||||
autoplay circular class="h-46 w-full overflow-hidden rounded-xl" :current="groupBanner.current"
|
||||
@change="onGroupBannerChange"
|
||||
>
|
||||
<swiper-item v-for="img in galleryGroups[0].images" :key="img.metadataName">
|
||||
<image :src="img.url" class="h-full w-full object-cover" />
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view
|
||||
class="absolute left-4 top-4 flex flex-col items-center justify-center rounded-2xl bg-orange-500 px-2 py-1.5 text-xs text-white font-bold"
|
||||
>
|
||||
最新精选
|
||||
</view>
|
||||
<view class="absolute bottom-4 left-4 flex flex-col gap-y-1">
|
||||
<view class="text-sm text-white font-bold">
|
||||
显示图片的名称
|
||||
</view>
|
||||
<view class="text-xs text-white/50">
|
||||
显示描述/日期
|
||||
</view>
|
||||
<view class="w-full flex items-center justify-center gap-x-2">
|
||||
<image
|
||||
v-for="(item, index) in galleryGroups[0].images" :key="item.metadataName" :src="item.url"
|
||||
mode="scaleToFill"
|
||||
class="box-border h-8 w-8 border-2 border-white rounded-lg border-solid transition-all duration-300"
|
||||
:class="[
|
||||
{
|
||||
'scale-110': groupBanner.current === index,
|
||||
},
|
||||
index % 2 === 0 ? '-rotate-4' : 'rotate-4',
|
||||
]" @click="groupBanner.current = index"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分组列表区域 -->
|
||||
<view class="mt-6 w-full flex items-center justify-between">
|
||||
<text class="text-sm text-gray-900 font-bold">我的相册</text>
|
||||
<text class="text-[10px] text-gray-600">共 30 组记录</text>
|
||||
</view>
|
||||
<!-- 混合模式 -->
|
||||
<view v-if="galleryStyle === 'mix'" class="grid grid-cols-2 mt-4 w-full gap-4">
|
||||
<view
|
||||
v-for="group in galleryGroups" :key="group.metadataName"
|
||||
class="group relative box-border h-36 w-full flex items-center justify-center p-1"
|
||||
>
|
||||
<!-- 预览图区域 -->
|
||||
<view class="relative h-full w-full">
|
||||
<view
|
||||
v-for="(img, index) in group.images.slice(0, 3)" :key="img.metadataName"
|
||||
class="absolute left-0 top-0 box-border h-full w-full origin-center overflow-hidden rounded-2xl transition-all duration-300"
|
||||
:class="[getGroupImageRotateClass(index)]"
|
||||
>
|
||||
<image :src="img.url" mode="scaleToFill" class="h-full w-full" />
|
||||
<!-- 文字区域 -->
|
||||
<view
|
||||
v-if="index === 0"
|
||||
class="absolute bottom-0 left-0 right-0 z-40 w-full flex flex-col gap-y-0.5 from-transparent to-black/90 bg-gradient-to-b px-2 py-1.5"
|
||||
>
|
||||
<text class="text-xs text-white font-bold">{{ group.displayName }}</text>
|
||||
<text class="text-[8px] text-white/80">{{ group.images.length }} 张图片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表卡片模式 -->
|
||||
<view v-else-if="galleryStyle === 'list'" class="mt-2 w-full flex flex-col gap-y-4">
|
||||
<view
|
||||
v-for="group in galleryGroups" :key="group.metadataName"
|
||||
class="box-border flex flex-col gap-y-2 overflow-hidden rounded-xl bg-white p-4 pt-3" @click="handleShowListPanel(group.metadataName)"
|
||||
>
|
||||
<!-- 顶部区域 -->
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="flex items-center gap-x-2 text-sm font-bold">
|
||||
<view class="hidden h-2 w-2 rounded-full bg-gray-900" /> {{ group.displayName }}
|
||||
</view>
|
||||
<view class="shrink-0">
|
||||
<text class="text-[10px] text-gray-400">{{ group.images.length }} 张</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图片列表 -->
|
||||
<view
|
||||
class="grid gap-1 overflow-hidden rounded-lg"
|
||||
:class="[getGalleryListContainerClass(group.images.slice(0, 4).length)]"
|
||||
>
|
||||
<view
|
||||
v-for="(img, index) in group.images.slice(0, 4)" :key="img.metadataName"
|
||||
class="overflow-hidden"
|
||||
:class="getGalleryListItemClass(index, group.images.slice(0, 4).length)"
|
||||
>
|
||||
<image
|
||||
:src="img.url" mode="scaleToFill"
|
||||
class="h-full w-full object-cover transition-transform duration-500 hover:scale-105"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 分组列表:无数据显示 -->
|
||||
<view class="hidden">
|
||||
无数据
|
||||
</view>
|
||||
|
||||
<!-- 相册列表:根据分组显示 -->
|
||||
<uh-gallery-panel v-if="showListPanel.show" :group-name="showListPanel.metadataName" @close="showListPanel.show = false" />
|
||||
|
||||
<!-- 底部导航占位 -->
|
||||
<view class="w-full shrink-0">
|
||||
<uh-tabbar-page-placeholder />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import useRequest from '@/hooks/useRequest'
|
||||
import { useAppShare } from '@/hooks/useShare'
|
||||
import { useRequest } from '@/hooks/useRequest'
|
||||
import { completeUrl } from '@/utils/url'
|
||||
import { random } from '@/utils/base/random'
|
||||
import { queryPhotoGroups, queryPhotos } from '@/api/halo-plugin/photo'
|
||||
import type { IPhoto, IPhotoGroup } from '@/api/halo-plugin/photo'
|
||||
import { completeUrl } from '@/utils/url'
|
||||
import random from '@/utils/base/random'
|
||||
|
||||
defineOptions({
|
||||
name: 'Gallery',
|
||||
@@ -11,7 +12,7 @@ defineOptions({
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '相册',
|
||||
navigationBarTitleText: '图库',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
enablePullDownRefresh: true,
|
||||
},
|
||||
@@ -26,6 +27,13 @@ interface IGalleryGroup {
|
||||
photos: IPhoto[]
|
||||
}
|
||||
|
||||
const { setShareOptions } = useAppShare()
|
||||
|
||||
setShareOptions({
|
||||
title: '图库',
|
||||
path: '/pages/gallery/gallery',
|
||||
})
|
||||
|
||||
const groupBanner = reactive({
|
||||
current: 0,
|
||||
})
|
||||
@@ -180,7 +188,7 @@ onPageScroll(() => { })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-page3 min-h-screen w-full flex flex-col">
|
||||
<view class="min-h-screen w-full flex flex-col bg-page3">
|
||||
<!-- 测试 -->
|
||||
<view v-if="false" class="box-border w-full p-4 pb-0">
|
||||
<view class="uh-shadow-card box-border w-full flex items-center gap-x-4 rounded-xl bg-white p-4 text-sm">
|
||||
|
||||
+9
-11
@@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import useRequest from '@/hooks/useRequest'
|
||||
import { useAppShare } from '@/hooks/useShare'
|
||||
import { useRequest } from '@/hooks/useRequest'
|
||||
import { queryPostByName, queryPosts } from '@/api/halo-base/post'
|
||||
import { cover } from '@/utils/imageHelper'
|
||||
import { timeFrom } from '@/utils/base/timeFrom'
|
||||
@@ -23,6 +24,12 @@ definePage({
|
||||
},
|
||||
})
|
||||
|
||||
const { setShareOptions } = useAppShare()
|
||||
|
||||
setShareOptions({
|
||||
path: '/pages/home/home',
|
||||
})
|
||||
|
||||
type PostCardStyle = 'noCover' | 'leftCover' | 'bottomCover' | 'rightCover' | 'topCover'
|
||||
const postCardStyle = ref<PostCardStyle>('leftCover')
|
||||
|
||||
@@ -129,16 +136,7 @@ onPageScroll(() => { })
|
||||
<template>
|
||||
<view class="min-h-screen bg-page3">
|
||||
<!-- 顶部banner -->
|
||||
<view v-if="false" class="relative h-72 w-full">
|
||||
<image class="h-72 w-full object-cover" :src="exampleImageUrls.banner" />
|
||||
<view class="absolute bottom-4 left-4 flex flex-col gap-y-2">
|
||||
<text class="text-xs text-white">welcome to new world</text>
|
||||
<text class="text-2xl text-white font-bold">UNI HALO V3.0 </text>
|
||||
<text class="text-xs text-white">新全新探索简约的艺术风格</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
<view class="box-border w-full">
|
||||
<wd-swiper
|
||||
v-model:current="banner.current" :list="banner.items" indicator-position="right" autoplay
|
||||
:height="340"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useAppShare } from '@/hooks/useShare'
|
||||
import { useRequest } from '@/hooks/useRequest'
|
||||
import { random } from '@/utils/base/random'
|
||||
import { queryLinkGroups, queryLinks } from '@/api/halo-plugin/link'
|
||||
@@ -26,9 +27,16 @@ definePage({
|
||||
},
|
||||
})
|
||||
|
||||
const { setShareOptions } = useAppShare()
|
||||
|
||||
const { config } = storeToRefs(useUniHaloConfigStore())
|
||||
const { reset } = useUniHaloConfigStore()
|
||||
|
||||
setShareOptions({
|
||||
title: '友情链接',
|
||||
path: '/pages/links/links',
|
||||
})
|
||||
|
||||
const { loading: loadingGroups, error: errorGroups, data: dataGroups, run: runGroups } = useRequest<ILinkGroup[]>(queryLinkGroups, { loadingToast: false, loadingToastContent: '加载中...', loadingToastMask: true })
|
||||
const { loading, error, data, run } = useRequest<IHaloListResponseBase<ILink>, IPaginationParams>(queryLinks, { loadingToast: false, loadingToastContent: '加载中...', loadingToastMask: true })
|
||||
|
||||
@@ -165,7 +173,7 @@ onLoad(async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-page3 min-h-screen w-full flex flex-col">
|
||||
<view class="min-h-screen w-full flex flex-col bg-page3">
|
||||
<!-- 分组列表 -->
|
||||
<view v-if="linkGroups.length !== 0" class="box-border w-full flex flex-col gap-y-6 overflow-hidden p-4 pb-0">
|
||||
<view v-for="(item, index) in linkGroups" :key="item.name" class="flex flex-col gap-y-4">
|
||||
@@ -223,7 +231,7 @@ onLoad(async () => {
|
||||
<view v-if="false" class="shrink-0">
|
||||
<view
|
||||
class="uh-shadow-md rounded-xl bg-gray-900 px-4 py-1.5 text-xs text-white"
|
||||
@click="copy(link.spec.url, true)"
|
||||
@click="copy(link.spec.url, '链接已复制')"
|
||||
>
|
||||
复制
|
||||
</view>
|
||||
@@ -258,7 +266,7 @@ onLoad(async () => {
|
||||
<button
|
||||
v-if="config.base.isIndividual"
|
||||
class="uh-shadow-md rounded-lg bg-gray-900 px-4 py-2 text-xs text-white outline-0 border-none!"
|
||||
@click="copy(link.spec.url, true)"
|
||||
@click="copy(link.spec.url, '链接已复制')"
|
||||
>
|
||||
<wd-icon name="copy" :size="14" /> 复制
|
||||
</button>
|
||||
|
||||
+176
-87
@@ -2,38 +2,92 @@
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { LOGIN_PAGE } from '@/router/config'
|
||||
import { useUserStore } from '@/store'
|
||||
import { useGuestStore } from '@/store/guest'
|
||||
import { useTokenStore } from '@/store/token'
|
||||
import i18n, { t } from '@/locale/index'
|
||||
import { setTabbarItem } from '@/tabbar/i18n'
|
||||
import GuestInfoPanel from '@/components/post-detail/uh-guest-info-panel.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'Mine',
|
||||
})
|
||||
defineOptions({ name: 'Mine' })
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '我的',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
enablePullDownRefresh: true,
|
||||
},
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
const tokenStore = useTokenStore()
|
||||
// 使用storeToRefs解构userInfo
|
||||
const guestStore = useGuestStore()
|
||||
|
||||
const { userInfo } = storeToRefs(userStore)
|
||||
|
||||
// 微信小程序下登录
|
||||
async function handleLogin() {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信登录
|
||||
await tokenStore.wxLogin()
|
||||
/** 是否已登录 */
|
||||
const hasLogin = computed(() => tokenStore.hasLogin)
|
||||
/** 是否已填写游客信息 */
|
||||
const hasGuestInfo = computed(() => guestStore.isComplete)
|
||||
|
||||
/** 显示的头像 */
|
||||
const displayAvatar = computed(() => {
|
||||
if (hasLogin.value && userInfo.value.avatar) {
|
||||
return userInfo.value.avatar
|
||||
}
|
||||
return '/static/images/default-avatar.png'
|
||||
})
|
||||
|
||||
/** 显示的名称 */
|
||||
const displayName = computed(() => {
|
||||
if (hasLogin.value) {
|
||||
return userInfo.value.nickname || userInfo.value.username
|
||||
}
|
||||
if (hasGuestInfo.value) {
|
||||
return guestStore.info.displayName
|
||||
}
|
||||
return '未登录'
|
||||
})
|
||||
|
||||
/** 显示的副标题 */
|
||||
const displaySubtitle = computed(() => {
|
||||
if (hasLogin.value) {
|
||||
return userInfo.value.role || userInfo.value.username
|
||||
}
|
||||
if (hasGuestInfo.value) {
|
||||
return guestStore.info.email
|
||||
}
|
||||
return '登录后解锁更多功能'
|
||||
})
|
||||
|
||||
/** 用户状态标签 */
|
||||
const statusLabel = computed(() => {
|
||||
if (hasLogin.value) return '已登录'
|
||||
if (hasGuestInfo.value) return '游客'
|
||||
return '未登录'
|
||||
})
|
||||
|
||||
const statusColor = computed(() => {
|
||||
if (hasLogin.value) return 'bg-green-50 text-green-600'
|
||||
if (hasGuestInfo.value) return 'bg-amber-50 text-amber-600'
|
||||
return 'bg-gray-100 text-gray-500'
|
||||
})
|
||||
|
||||
// ---- 游客信息编辑 ----
|
||||
const showGuestPanel = ref(false)
|
||||
|
||||
function handleEditGuest() {
|
||||
showGuestPanel.value = true
|
||||
}
|
||||
|
||||
function handleGuestSaved() {
|
||||
showGuestPanel.value = false
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
}
|
||||
|
||||
// ---- 登录/退出 ----
|
||||
function handleLogin() {
|
||||
// #ifdef MP-WEIXIN
|
||||
tokenStore.wxLogin()
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.navigateTo({
|
||||
url: `${LOGIN_PAGE}`,
|
||||
})
|
||||
uni.navigateTo({ url: LOGIN_PAGE })
|
||||
// #endif
|
||||
}
|
||||
|
||||
@@ -43,93 +97,121 @@ function handleLogout() {
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 清空用户信息
|
||||
useTokenStore().logout()
|
||||
// 执行退出登录逻辑
|
||||
uni.showToast({
|
||||
title: '退出登录成功',
|
||||
icon: 'success',
|
||||
})
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序,去首页
|
||||
// uni.reLaunch({ url: '/pages/index/index' })
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
// 非微信小程序,去登录页
|
||||
// uni.navigateTo({ url: LOGIN_PAGE })
|
||||
// #endif
|
||||
tokenStore.logout()
|
||||
uni.showToast({ title: '已退出登录', icon: 'success' })
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const current = ref(uni.getLocale())
|
||||
const languages = [
|
||||
{
|
||||
value: 'zh-Hans',
|
||||
name: '中文',
|
||||
checked: 'true',
|
||||
},
|
||||
{
|
||||
value: 'en',
|
||||
name: '英文',
|
||||
},
|
||||
// ---- 功能导航 ----
|
||||
interface NavItem {
|
||||
icon: string
|
||||
label: string
|
||||
path?: string
|
||||
showArrow?: boolean
|
||||
}
|
||||
|
||||
const navList: NavItem[] = [
|
||||
{ icon: 'file', label: '免责声明', path: '', showArrow: true },
|
||||
{ icon: 'chat', label: '在线客服', path: '', showArrow: true },
|
||||
{ icon: 'edit', label: '意见反馈', path: '', showArrow: true },
|
||||
{ icon: 'info-circle', label: '关于项目', path: '/subpkg-blog/about/about', showArrow: true },
|
||||
]
|
||||
|
||||
function radioChange(evt) {
|
||||
// console.log(evt)
|
||||
current.value = evt.detail.value
|
||||
// 下面2句缺一不可!!!
|
||||
uni.setLocale(evt.detail.value)
|
||||
i18n.global.locale = evt.detail.value
|
||||
|
||||
// 底部tabbar需要重新设置一下
|
||||
setTabbarItem()
|
||||
// 本页的标题也需要重新设置一下
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('i18n.title'),
|
||||
})
|
||||
function handleNavClick(item: NavItem) {
|
||||
if (item.path) {
|
||||
uni.navigateTo({ url: item.path })
|
||||
}
|
||||
else {
|
||||
uni.showToast({ title: '即将开放,敬请期待', icon: 'none' })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-page3 box-border min-h-screen w-full flex flex-col items-center justify-center gap-y-6 px-4">
|
||||
<view class="mt-3 break-all px-3 text-center text-green-500">
|
||||
{{ userInfo.username ? '已登录' : '未登录' }}
|
||||
</view>
|
||||
<view class="mt-3 break-all px-3">
|
||||
{{ JSON.stringify(userInfo, null, 2) }}
|
||||
</view>
|
||||
|
||||
<!-- 切换语言 -->
|
||||
<view class="mt-6 w-full flex flex-col items-center justify-center">
|
||||
<view class="mb-2 text-gray-900 font-bold">
|
||||
切换语言
|
||||
</view>
|
||||
<view class="w-full flex items-center justify-center gap-4">
|
||||
<radio-group class="flex flex-col items-center justify-center gap-2" @change="radioChange">
|
||||
<label
|
||||
v-for="item in languages"
|
||||
:key="item.value"
|
||||
class="flex items-center gap-x-2"
|
||||
>
|
||||
<view>
|
||||
<radio :value="item.value" :checked="item.value === current" />
|
||||
<view class="bg-page3 box-border min-h-screen w-full flex flex-col gap-y-4 px-4 pt-4">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="uh-shadow-xs box-border flex flex-col rounded-2xl bg-white p-4">
|
||||
<view class="w-full flex items-center gap-x-3">
|
||||
<!-- 头像 -->
|
||||
<image
|
||||
class="uh-shadow-xs h-16 w-16 shrink-0 border-2 border-white rounded-full border-solid"
|
||||
:src="displayAvatar"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<!-- 信息区 -->
|
||||
<view class="flex flex-1 flex-col gap-y-1">
|
||||
<view class="flex items-center gap-x-2">
|
||||
<text class="text-base text-gray-900 font-bold">{{ displayName }}</text>
|
||||
<view class="rounded-full px-2 py-0.5" :class="statusColor">
|
||||
<text class="text-[10px] font-medium">{{ statusLabel }}</text>
|
||||
</view>
|
||||
<view>{{ item.name }}</view>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
<text class="line-clamp-1 text-xs text-gray-500">{{ displaySubtitle }}</text>
|
||||
</view>
|
||||
<!-- 游客编辑入口 -->
|
||||
<view
|
||||
v-if="!hasLogin && hasGuestInfo"
|
||||
class="h-8 w-8 center shrink-0 rounded-full bg-gray-50"
|
||||
@click="handleEditGuest"
|
||||
>
|
||||
<wd-icon name="edit" color="#6B7280" :size="16" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 游客信息快捷编辑入口(未登录且未填写游客信息时) -->
|
||||
<view
|
||||
v-if="!hasLogin && !hasGuestInfo"
|
||||
class="mt-3 box-border flex items-center gap-x-2 rounded-xl bg-gray-50 px-3 py-2.5"
|
||||
@click="handleEditGuest"
|
||||
>
|
||||
<wd-icon name="edit" color="#9CA3AF" :size="14" />
|
||||
<text class="text-xs text-gray-400">填写游客信息(用于评论互动)</text>
|
||||
<wd-icon name="arrow-right" color="#D1D5DB" :size="14" />
|
||||
</view>
|
||||
|
||||
<!-- 已登录时显示的额外信息 -->
|
||||
<view v-if="hasLogin" class="mt-3 my-1 h-px w-full bg-gray-50" />
|
||||
<view v-if="hasLogin" class="flex items-center justify-between">
|
||||
<text class="text-xs text-gray-400">账号:{{ userInfo.username }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mt-6">
|
||||
<view class="m-auto w-160px text-center">
|
||||
<button v-if="tokenStore.hasLogin" type="warn" class="w-full rounded-xl text-xs" @click="handleLogout">
|
||||
退出登录
|
||||
</button>
|
||||
<button v-else class="w-full rounded-xl bg-gray-900 py-2.5 text-xs text-white" @click="handleLogin">
|
||||
立即登录
|
||||
</button>
|
||||
<!-- 功能导航 -->
|
||||
<view class="uh-shadow-xs box-border flex flex-col rounded-2xl bg-white">
|
||||
<view
|
||||
v-for="(item, index) in navList"
|
||||
:key="item.label"
|
||||
class="box-border flex items-center justify-between px-4 py-3.5"
|
||||
:class="{ 'border-b border-gray-50': index < navList.length - 1 }"
|
||||
@click="handleNavClick(item)"
|
||||
>
|
||||
<view class="flex items-center gap-x-3">
|
||||
<view class="h-8 w-8 center rounded-xl bg-gray-50">
|
||||
<wd-icon :name="item.icon" color="#6B7280" :size="16" />
|
||||
</view>
|
||||
<text class="text-sm text-gray-800">{{ item.label }}</text>
|
||||
</view>
|
||||
<wd-icon v-if="item.showArrow" name="arrow-right" color="#D1D5DB" :size="14" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 登录/退出按钮 -->
|
||||
<view class="mt-2 w-full">
|
||||
<view
|
||||
v-if="hasLogin"
|
||||
class="uh-shadow-xs h-11 w-full center rounded-2xl bg-white text-sm text-red-500 font-medium"
|
||||
@click="handleLogout"
|
||||
>
|
||||
退出登录
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="h-11 w-full center rounded-2xl bg-gray-900 text-sm text-white font-medium"
|
||||
@click="handleLogin"
|
||||
>
|
||||
立即登录
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -137,5 +219,12 @@ function radioChange(evt) {
|
||||
<view class="w-full shrink-0">
|
||||
<uh-tabbar-page-placeholder />
|
||||
</view>
|
||||
|
||||
<!-- 游客信息编辑面板 -->
|
||||
<GuestInfoPanel
|
||||
v-if="showGuestPanel"
|
||||
@close="showGuestPanel = false"
|
||||
@saved="handleGuestSaved"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { useAppShare } from '@/hooks/useShare'
|
||||
import { cover } from '@/utils/imageHelper'
|
||||
import { queryMoments } from '@/api/halo-plugin/moment'
|
||||
import { parseDateTime } from '@/utils/base/time'
|
||||
@@ -17,6 +18,13 @@ definePage({
|
||||
},
|
||||
})
|
||||
|
||||
const { setShareOptions } = useAppShare()
|
||||
|
||||
setShareOptions({
|
||||
title: '瞬间',
|
||||
path: '/pages/moments/moments',
|
||||
})
|
||||
|
||||
const useTimeline = ref(true)
|
||||
|
||||
const { loading, error, data, run } = useRequest<IHaloListResponseBase<IMoment>, IMomentListRequest>(queryMoments, { loadingToast: false, loadingToastContent: '加载中...', loadingToastMask: true })
|
||||
@@ -63,7 +71,7 @@ onPageScroll(() => { })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-page3 min-h-screen w-full flex flex-col">
|
||||
<view class="min-h-screen w-full flex flex-col bg-page3">
|
||||
<!-- 测试 -->
|
||||
<view v-if="false" class="box-border w-full p-4 pb-0">
|
||||
<view class="uh-shadow-card box-border w-full flex items-center gap-x-4 rounded-xl bg-white p-4 text-sm">
|
||||
|
||||
Reference in New Issue
Block a user