mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-09-13 00:50:40 +08:00
feat: 重构评论交互与请求错误处理,新增搜索页
- 请求层:非 200 响应统一抛 UniHaloError,Halo 来源响应归一化 - 评论弹窗:新增 allowNotification、验证码错误自动刷新与错误详情提示 - 评论回复结构调整为分页结果(replies.items) - 首页:快捷导航改 5 列、最新列表跳转搜索页,移除旧文章列表页 - 图库:分类切换改用 wd-tabs/wd-tab 组件 - 新增搜索页、uh-data-loading 组件、useDataLoadingStatus 与 exception 工具 Co-Authored-By: AtomCode (deepseek-v4-flash) <noreply@atomgit.com>
This commit is contained in:
@@ -28,7 +28,7 @@ const articleDetailPath = '/pages-blog/article-detail/article-detail'
|
||||
// 本地开发快速跳转页面,发布请置为 false
|
||||
const DEV_MODE = false
|
||||
const DEV_TO_TYPE = 'page' as 'page' | 'tabbar'
|
||||
const DEV_TO_PATH = '/pages-blog/data-visual/data-visual'
|
||||
const DEV_TO_PATH = articleDetailPath + '?name=01a057b2-3200-74af-8afe-28a054092e82'
|
||||
|
||||
/* ---------------- 状态 ---------------- */
|
||||
const appConfigStore = useAppConfigStore()
|
||||
|
||||
@@ -51,7 +51,8 @@ async function handleGetCategory() {
|
||||
}
|
||||
try {
|
||||
const res = await getPhotoGroupList({ page: 1, size: 0 })
|
||||
category.value.list = (res.data.items || [])
|
||||
console.log('分类数据',res.data)
|
||||
category.value.list = (res.data || [])
|
||||
.map(item => ({
|
||||
name: item.metadata.name,
|
||||
displayName: item.spec.displayName,
|
||||
@@ -134,10 +135,11 @@ function handleGetDataByCategory(index: number) {
|
||||
handleGetData(true)
|
||||
}
|
||||
|
||||
function handleOnCategoryChange(e: { detail: { current: number } }) {
|
||||
function handleOnCategoryChange(e:{index:number,name:number}) {
|
||||
console.log('切换分类', e)
|
||||
if (lock.value)
|
||||
return
|
||||
handleGetDataByCategory(e.detail.current)
|
||||
handleGetDataByCategory(e.index)
|
||||
}
|
||||
|
||||
/* ---------------- 图片预览 ---------------- */
|
||||
@@ -207,17 +209,17 @@ onReachBottom(() => {
|
||||
/>
|
||||
<template v-else>
|
||||
<!-- 顶部切换 -->
|
||||
<view v-if="category.list.length > 0" class="category-tabs fixed inset-x-0 top-0 z-6 bg-white">
|
||||
<wd-tabs
|
||||
<wd-tabs
|
||||
v-if="category.list.length > 0"
|
||||
v-model="category.activeIndex"
|
||||
:tabs="category.list.map(item => ({ title: item.displayName }))"
|
||||
align="left"
|
||||
sticky
|
||||
:offset-top="0"
|
||||
@change="handleOnCategoryChange"
|
||||
/>
|
||||
</view>
|
||||
<!-- 占位区域 -->
|
||||
<view v-if="category.list.length > 0" class="h-[90rpx] w-screen" />
|
||||
|
||||
>
|
||||
<wd-tab v-for="cate in category.list" :key="cate.displayName" :title="cate.displayName"></wd-tab>
|
||||
</wd-tabs>
|
||||
|
||||
<!-- 骨架屏 -->
|
||||
<view v-if="loading === 'loading'" class="loading-wrap box-border p-3">
|
||||
<wd-skeleton :row="4" :animated="true" />
|
||||
|
||||
@@ -18,6 +18,7 @@ definePage({
|
||||
navigationBarTitleText: '首页',
|
||||
enablePullDownRefresh: true,
|
||||
navigationStyle: 'custom',
|
||||
backgroundColor:'#F8F8F8'
|
||||
},
|
||||
})
|
||||
|
||||
@@ -66,7 +67,7 @@ const bloggerInfo = computed(() => {
|
||||
|
||||
const calcAuditModeEnabled = computed(() => !!haloConfigs.value.auditConfig?.auditModeEnabled)
|
||||
|
||||
const calcIsShowQuickNavigationEnabled = computed(() => !!haloConfigs.value.pageConfig?.homeConfig?.useQuickNavigation)
|
||||
const calcIsShowQuickNavigationEnabled = computed(() => haloConfigs.value.pageConfig?.homeConfig?.useQuickNavigation)
|
||||
|
||||
const calcIsShowCategory = computed(() => {
|
||||
if (calcAuditModeEnabled.value)
|
||||
@@ -241,7 +242,7 @@ async function handleGetArticleList() {
|
||||
loadMoreText.value = t('common.loading')
|
||||
|
||||
try {
|
||||
const res = await getPostList({ ...queryParams.value })
|
||||
const res = await getPostList({ ...toRaw(queryParams.value) })
|
||||
result.value.hasNext = res.data.hasNext
|
||||
articleList.value = isLoadMore.value
|
||||
? articleList.value.concat(res.data.items)
|
||||
@@ -277,11 +278,7 @@ function handleToArticleDetail(article: IPost) {
|
||||
function handleToCategoryPage() {
|
||||
uni.switchTab({ url: '/pages/tabbar/category/category' })
|
||||
}
|
||||
|
||||
function handleToArticlesPage() {
|
||||
uni.navigateTo({ url: '/pages-blog/articles/articles' })
|
||||
}
|
||||
|
||||
|
||||
function handleToCategoryBy(category: ICategory) {
|
||||
if (calcAuditModeEnabled.value)
|
||||
return
|
||||
@@ -291,7 +288,7 @@ function handleToCategoryBy(category: ICategory) {
|
||||
}
|
||||
|
||||
function handleToSearch() {
|
||||
uni.navigateTo({ url: '/pages-blog/articles/articles' })
|
||||
uni.navigateTo({ url: '/pages-blog/search/search' })
|
||||
}
|
||||
|
||||
function handleOnLogoToPage() {
|
||||
@@ -374,7 +371,7 @@ handleQuery()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="app-page min-h-screen w-screen flex flex-col">
|
||||
<view class="min-h-screen w-screen flex flex-col">
|
||||
<!-- 顶部栏 -->
|
||||
<view class="header flex items-center gap-4 px-3 py-1.5">
|
||||
<image class="logo h-[60rpx] w-[60rpx] rounded-3xl" :src="appInfo.logo" mode="scaleToFill" @click="handleOnLogoToPage" />
|
||||
@@ -398,7 +395,7 @@ handleQuery()
|
||||
|
||||
<block v-else>
|
||||
<!-- 轮播 Banner -->
|
||||
<view v-if="bannerConfig?.enabled" class="bg-white pb-6">
|
||||
<view v-if="bannerConfig?.enabled" class="bg-white mb-4">
|
||||
<view v-if="bannerList.length !== 0" class="banner mx-3 mt-3 overflow-hidden rounded-xl">
|
||||
<uh-swiper
|
||||
:height="bannerConfig.height"
|
||||
@@ -414,11 +411,11 @@ handleQuery()
|
||||
</view>
|
||||
|
||||
<!-- 快捷导航 -->
|
||||
<view v-if="calcIsShowQuickNavigationEnabled && navList.filter(x => x.show).length" class="nav-box mx-6 mb-6 mt-4 overflow-hidden rounded-xl bg-white p-3">
|
||||
<view v-if="navList.filter(x => x.show).length" class="nav-box px-4 overflow-hidden rounded-xl bg-white p-3">
|
||||
<view class="page-item-title font-bold">
|
||||
快捷导航
|
||||
</view>
|
||||
<view class="nav-list grid grid-cols-4 mt-6 gap-6">
|
||||
<view class="nav-list grid grid-cols-5 mt-6 gap-6">
|
||||
<template v-for="item in navList.filter(x => x.show)" :key="item.key">
|
||||
<view class="nav-item flex flex-col items-center gap-3" @click="handleClickNav(item)">
|
||||
<view class="nav-item-icon h-[88rpx] w-[88rpx] flex items-center justify-center rounded-3xl" :style="{ backgroundColor: item.bgColor }">
|
||||
@@ -463,7 +460,7 @@ handleQuery()
|
||||
<view class="page-item-title font-bold">
|
||||
最新列表
|
||||
</view>
|
||||
<view class="show-more flex items-center justify-center rounded-xl bg-white" @click="handleToArticlesPage">
|
||||
<view class="show-more flex items-center justify-center rounded-xl bg-white" @click="handleToSearch">
|
||||
<wd-icon name="arrow-right" size="12px" color="#909399" />
|
||||
</view>
|
||||
</view>
|
||||
@@ -500,61 +497,4 @@ handleQuery()
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.app-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
.logo {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
.search-text {
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-item-title {
|
||||
position: relative;
|
||||
padding-left: 24rpx;
|
||||
font-size: 32rpx;
|
||||
color: #303133;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 8rpx;
|
||||
width: 8rpx;
|
||||
height: 30rpx;
|
||||
background-color: rgb(33 150 243);
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.show-more {
|
||||
width: 42rpx;
|
||||
height: 42rpx;
|
||||
box-shadow: 0 0 24rpx rgb(0 0 0 / 3%);
|
||||
}
|
||||
|
||||
.to-top-btn {
|
||||
position: fixed;
|
||||
right: 24rpx;
|
||||
bottom: 120rpx;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 4rpx 16rpx rgb(0 0 0 / 10%);
|
||||
z-index: 6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
|
||||
import dayjs from 'dayjs'
|
||||
import { getMomentList } from '@/api/halo'
|
||||
import { useAppConfigStore } from '@/store/appConfig'
|
||||
import { checkAvatarUrl, checkThumbnailUrl } from '@/utils/url'
|
||||
@@ -95,7 +94,6 @@ async function handleGetData() {
|
||||
|
||||
try {
|
||||
const res = await getMomentList({ ...queryParams.value })
|
||||
console.log('获取瞬间数据成功', res)
|
||||
loading.value = 'success'
|
||||
loadMoreText.value = res.data.hasNext ? t('common.loadMore') : t('common.noMore')
|
||||
hasNext.value = res.data.hasNext
|
||||
@@ -250,7 +248,7 @@ onReachBottom(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="app-page box-border min-h-screen w-screen flex flex-col py-6">
|
||||
<view class=" box-border min-h-screen w-screen flex flex-col py-6">
|
||||
<uh-plugin-unavailable
|
||||
v-if="!uniHaloPluginAvailable"
|
||||
:plugin-id="uniHaloPluginId"
|
||||
@@ -262,14 +260,14 @@ onReachBottom(() => {
|
||||
<wd-skeleton :row="3" :animated="true" />
|
||||
</view>
|
||||
|
||||
<view v-else class="app-page-content">
|
||||
<view v-else class="flex flex-col gap-y-2 p-4">
|
||||
<view v-if="dataList.length === 0" class="min-h-[70vh] w-full flex items-center justify-center content-empty">
|
||||
<wd-empty :description="t('common.empty')" />
|
||||
</view>
|
||||
|
||||
<block v-else>
|
||||
<!-- 瞬间卡片 -->
|
||||
<view v-for="moment in dataList" :key="moment.metadata.name" class="moment-card mx-6 mb-6 flex flex-col overflow-hidden rounded-xl bg-white shadow-sm">
|
||||
<view v-for="moment in dataList" :key="moment.metadata.name" class="flex flex-col overflow-hidden rounded-xl bg-white shadow-sm">
|
||||
<view class="head flex items-center p-3 pb-0">
|
||||
<image class="avatar h-[66rpx] w-[66rpx] shrink-0 rounded-full" :src="moment.spec.owner?.avatar || bloggerInfo.avatar" mode="aspectFill" />
|
||||
<view class="nickname ml-3">
|
||||
@@ -361,19 +359,3 @@ onReachBottom(() => {
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.app-page {
|
||||
/* 布局全部由 UnoCSS 原子类实现 */
|
||||
}
|
||||
|
||||
.moment-card {
|
||||
.head {
|
||||
.nickname {
|
||||
.nickname-text {
|
||||
/* 无额外样式 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user