mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-09-12 16:40:40 +08:00
02fa9e4294
1. 重构分类页面路由与实现,替换旧分类详情页为文章列表页 2. 统一使用自定义导航栏,替换原有原生导航配置 3. 重构加载状态管理,统一使用useDataLoadingStatus hook 4. 优化插件可用性检查逻辑与组件展示 5. 调整数据加载占位与空状态样式 6. 优化文章卡片样式与交互,新增分类跳转功能 7. 重构设置页枚举选择弹窗,使用wd-picker替换自定义实现 8. 删除废弃的IPluginAvailable类型与相关代码
228 lines
7.2 KiB
Vue
228 lines
7.2 KiB
Vue
<script lang="ts" setup>
|
|
import { computed, ref, watch } from 'vue'
|
|
import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
|
|
import { getPhotoGroupList, getPhotoListByGroupName } from '@/api/halo'
|
|
import { useAppConfigStore } from '@/store/appConfig'
|
|
import { checkImageUrl } from '@/utils/url'
|
|
import { t } from '@/locale'
|
|
import { DataLoadingStatusEnum, useDataLoadingStatus } from '@/hooks/useDataLoadingStatus'
|
|
import type { IPhoto, IPhotoGroup } from '@/api/types/halo'
|
|
|
|
definePage({
|
|
style: {
|
|
navigationBarTitleText: '图库',
|
|
enablePullDownRefresh: true,
|
|
},
|
|
})
|
|
|
|
const appConfigStore = useAppConfigStore()
|
|
const haloConfigs = computed(() => appConfigStore.configs)
|
|
const calcAuditModeEnabled = computed(() => appConfigStore.auditModeEnabled)
|
|
|
|
const galleryConfig = computed(() => haloConfigs.value.pageConfig?.galleryConfig)
|
|
|
|
/** 依赖插件(PluginPhotos) */
|
|
const { pluginId, checking, tips, available: uniHaloPluginAvailable, check: checkPluginAvailable } = usePluginAvailable({
|
|
pluginId: 'PluginPhotos',
|
|
tips: '很抱歉,功能正在维护中...',
|
|
callback: (isAvailable) => {
|
|
if (!isAvailable) { return }
|
|
uni.pageScrollTo({
|
|
scrollTop: 0,
|
|
duration: 0,
|
|
})
|
|
handleGetCategory()
|
|
}
|
|
})
|
|
|
|
/* ---------------- 状态 ---------------- */
|
|
const { loadingStatus, updateLoadingStatus } = useDataLoadingStatus()
|
|
const category = ref<{ activeIndex : number, list : IPhotoGroup[] }>({
|
|
activeIndex: 0,
|
|
list: [],
|
|
})
|
|
const queryParams = ref({ size: 10, page: 1, group: '' })
|
|
const isLoadMore = ref(false)
|
|
const loadMoreText = ref('')
|
|
const hasNext = ref(false)
|
|
const dataList = ref<IPhoto[]>([])
|
|
const lock = ref(false)
|
|
|
|
/* ---------------- 数据加载 ---------------- */
|
|
async function handleGetCategory() {
|
|
if (calcAuditModeEnabled.value) {
|
|
// 审核模式:仅展示所选图库分组(galleryGroups)内的照片,未分组照片不展示
|
|
const auditGroupNames = appConfigStore.auditData.spec?.galleryGroups || []
|
|
try {
|
|
const res = await getPhotoGroupList({ page: 1, size: 0 })
|
|
const filtered = ((res.data as unknown as IPhotoGroup[] | undefined) || [])
|
|
.filter(item => auditGroupNames.includes(item.metadata.name))
|
|
.sort((a, b) => a.spec.priority - b.spec.priority)
|
|
category.value.list = filtered
|
|
if (category.value.list.length !== 0) {
|
|
queryParams.value.group = category.value.list[0].metadata.name || ''
|
|
handleGetData(true)
|
|
}
|
|
else {
|
|
loadMoreText.value = t('common.noMore')
|
|
uni.stopPullDownRefresh()
|
|
}
|
|
}
|
|
catch (e) {
|
|
console.error(e)
|
|
category.value = { activeIndex: 0, list: [] }
|
|
}
|
|
return
|
|
}
|
|
try {
|
|
const res = await getPhotoGroupList({ page: 1, size: 0 })
|
|
category.value.list = ((res.data as unknown as IPhotoGroup[] | undefined) || [])
|
|
.sort((a, b) => a.spec.priority - b.spec.priority)
|
|
category.value.list.unshift({ metadata: { name: undefined }, spec: { displayName: '全部', priority: 0 } })
|
|
if (category.value.list.length !== 0) {
|
|
queryParams.value.group = category.value.list[0].metadata.name || ''
|
|
handleGetData(true)
|
|
}
|
|
}
|
|
catch (e) {
|
|
console.error(e)
|
|
category.value = { activeIndex: 0, list: [] }
|
|
}
|
|
}
|
|
|
|
async function handleGetData(isClearList = false) {
|
|
if (isClearList) {
|
|
dataList.value = []
|
|
queryParams.value.page = 1
|
|
}
|
|
|
|
if (!isLoadMore.value) {
|
|
updateLoadingStatus(DataLoadingStatusEnum.Loading)
|
|
}
|
|
loadMoreText.value = ''
|
|
|
|
try {
|
|
const res = await getPhotoListByGroupName({ ...queryParams.value })
|
|
hasNext.value = res.data.hasNext
|
|
if (res.data.items.length !== 0) {
|
|
const list = res.data.items.map(item => ({
|
|
...item,
|
|
spec: { ...item.spec, url: checkImageUrl(item.spec.url || item.spec.cover) },
|
|
}))
|
|
dataList.value = isLoadMore.value
|
|
? dataList.value.concat(list)
|
|
: list
|
|
}
|
|
updateLoadingStatus(dataList.value.length === 0 ? DataLoadingStatusEnum.Empty : DataLoadingStatusEnum.Success)
|
|
loadMoreText.value = res.data.hasNext ? t('common.loadMore') : t('common.noMore')
|
|
}
|
|
catch (err) {
|
|
console.error(err)
|
|
updateLoadingStatus(DataLoadingStatusEnum.Error)
|
|
loadMoreText.value = t('common.loadFailed')
|
|
}
|
|
finally {
|
|
setTimeout(() => {
|
|
uni.hideLoading()
|
|
uni.stopPullDownRefresh()
|
|
lock.value = false
|
|
}, 500)
|
|
}
|
|
}
|
|
|
|
function handleGetDataByCategory(index : number, cate : IPhotoGroup) {
|
|
queryParams.value.group = cate.metadata.name || ''
|
|
queryParams.value.page = 1
|
|
uni.pageScrollTo({ scrollTop: 0, duration: 500 })
|
|
dataList.value = []
|
|
category.value.activeIndex = index
|
|
handleGetData(true)
|
|
}
|
|
|
|
/* ---------------- 图片预览 ---------------- */
|
|
function handlePreview(data : IPhoto) {
|
|
const current = dataList.value.findIndex(x => x.metadata.name === data.metadata.name)
|
|
uni.previewImage({
|
|
current,
|
|
urls: dataList.value.map(x => x.spec.url),
|
|
indicator: 'number',
|
|
loop: true,
|
|
})
|
|
}
|
|
|
|
/* ---------------- 生命周期 ---------------- */
|
|
onLoad(async () => {
|
|
// 检查插件可用性
|
|
await checkPluginAvailable()
|
|
if (!uniHaloPluginAvailable.value) {
|
|
uni.stopPullDownRefresh()
|
|
return
|
|
}
|
|
handleGetCategory()
|
|
})
|
|
|
|
onPullDownRefresh(() => {
|
|
if (!uniHaloPluginAvailable.value) {
|
|
uni.stopPullDownRefresh()
|
|
return
|
|
}
|
|
dataList.value = []
|
|
isLoadMore.value = false
|
|
queryParams.value.page = 1
|
|
handleGetData(true)
|
|
})
|
|
|
|
onReachBottom(() => {
|
|
if (!uniHaloPluginAvailable.value) { return }
|
|
if (calcAuditModeEnabled.value) {
|
|
uni.showToast({ icon: 'none', title: t('common.noMoreData') })
|
|
return
|
|
}
|
|
if (hasNext.value) {
|
|
queryParams.value.page += 1
|
|
isLoadMore.value = true
|
|
handleGetData(false)
|
|
}
|
|
else {
|
|
uni.showToast({ icon: 'none', title: t('common.noMoreData') })
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<view class="min-h-screen w-screen flex flex-col bg-page pb-6">
|
|
<uh-plugin-unavailable v-if="!uniHaloPluginAvailable" :plugin-id="pluginId" :error-text="tips"
|
|
:checking="checking" @on-refresh="checkPluginAvailable" />
|
|
<template v-else>
|
|
<wd-sticky v-if="category.list.length!==0">
|
|
<scroll-view :scroll-x="true" class="w-full whitespace-nowrap pt-3">
|
|
<view v-for="(cate, index) in category.list" :key="cate.spec.displayName"
|
|
class="uh-global-card-glass uh-shadow-xs mb-1 ml-3 inline-block border rounded-2xl px-4 py-1 text-sm"
|
|
:class="{ 'bg-primary text-gray-900 font-bold': index === category.activeIndex }"
|
|
@click="handleGetDataByCategory(index, cate)">
|
|
{{ cate.spec.displayName }} <text
|
|
v-if="cate.spec.displayName!=='全部'">({{ cate.status?.photoCount ?? 0 }})</text>
|
|
</view>
|
|
</scroll-view>
|
|
</wd-sticky>
|
|
|
|
<!-- 加载/错误占位 -->
|
|
<uh-data-loading v-if="loadingStatus !== DataLoadingStatusEnum.Success" :loading-status="loadingStatus"
|
|
@refresh="handleGetCategory" />
|
|
|
|
<!-- 内容区域 -->
|
|
<view v-else class="box-border w-full p-3">
|
|
<view class="grid grid-cols-2 gap-2.5">
|
|
<view v-for="(item, index) in dataList" :key="index"
|
|
class="uh-global-card-glass h-38 w-full overflow-hidden rounded-xl">
|
|
<image class="h-full w-full" :src="item.spec.url" mode="aspectFill" lazy-load
|
|
@click="handlePreview(item)" />
|
|
</view>
|
|
</view>
|
|
<view class="load-text w-full py-4 text-center text-xs text-gray-500">
|
|
{{ loadMoreText }}
|
|
</view>
|
|
</view>
|
|
</template>
|
|
</view>
|
|
</template> |