1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-09-12 16:40:40 +08:00
Files
uni-halo/src/components/uh-home-banner/uh-home-banner.vue
T
小莫唐尼 902faa70e7 refactor: 移除启动页逻辑,新增全局组件与偏好设置系统
1.  移除旧版启动页分流逻辑,直接跳转首页
2.  新增返回顶部、章节标题、导航栏等全局组件
3.  重构偏好设置系统,实现站点默认与本地差异分层管理
4.  删除冗余的测试mock、插件模块与样式文件
5.  优化文章卡片与评论组件样式,更新全局主题色
6.  清理废弃的请求参数与配置项
2026-09-03 22:36:26 +08:00

132 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import { getBanners } from '@/api/uni-halo'
import { useAppConfigStore } from '@/store/appConfig'
import { checkAvatarUrl, checkThumbnailUrl } from '@/utils/url'
import { formatTime } from '@/utils/formatTime'
import type { IBannerPublicItem } from '@/api/types/uni-halo'
export interface IBannerItem {
/** 条目标识(Banner 为 metadata.name;兼容旧数据) */
id ?: string | number
/** Banner 条目 metadata.name(custom 详情页跳转用) */
name ?: string
title ?: string
image ?: string
src ?: string
/** 来源:post=文章快照 / custom=自定义 */
type ?: string
/** 文章 id(source=post 时跳转文章详情) */
postId ?: string
content ?: string
url ?: string
/** 展示日期(ISO 快照) */
date ?: string
authorName ?: string
authorAvatar ?: string
[key : string] : unknown
}
const appConfigStore = useAppConfigStore()
const haloConfigs = computed(() => appConfigStore.configs)
const bannerConfig = computed(() => haloConfigs.value.pageConfig?.homeConfig?.bannerConfig)
/* ---------------- 数据(高内聚:内部请求公开接口) ---------------- */
const bannerList = ref<IBannerItem[]>([])
const currentIndex = ref(0)
const currentBanner = ref<IBannerItem | null>(null)
/** 公开 Banner 条目 → 轮播展示项 */
function mapBanners(items : IBannerPublicItem[]) : IBannerItem[] {
return items.map(item => ({
id: item.name,
name: item.name,
title: item.title || '',
image: checkThumbnailUrl(item.cover),
src: checkThumbnailUrl(item.cover),
type: item.source,
postId: item.postId,
url: item.link,
date: formatTime({
d: item.date,
f: 'yyyy年MM月dd日 星期w'
}),
authorName: item.authorName,
authorAvatar: item.authorAvatar ? checkAvatarUrl(item.authorAvatar) : '',
}))
}
onMounted(async () => {
try {
const res = await getBanners()
bannerList.value = mapBanners(res.data || [])
handleBannerChange({
detail: { current: 0 }
})
}
catch (err) {
console.error('获取轮播图失败', err)
}
})
function handleBannerChange(e : any) {
currentIndex.value = e?.detail?.current ?? 0
currentBanner.value = bannerList.value[currentIndex.value]
}
function handleOnClick(item : IBannerItem) {
// 审核模式下照常展示 Banner,点击分发不拦截(详情页自行处理审核限制)
if (item.type === 'custom') {
// 自定义条目:跳转 Banner 详情页,页面内调公开详情接口展示 content/外链
if (item.name) {
uni.navigateTo({
url: `/pages-blog/banner-detail/banner-detail?name=${item.name}`,
animationType: 'slide-in-right',
})
}
return
}
// 文章来源
uni.navigateTo({
url: `/pages-blog/article-detail/article-detail?name=${item.postId}`,
animationType: 'slide-in-right',
})
}
function handleToSearch() {
uni.navigateTo({ url: '/pages-blog/search/search' })
}
</script>
<template>
<view v-if="bannerList.length > 0" class="relative w-full mb-6 box-border ">
<view class="box-border relative w-full h-52 overflow-hidden">
<swiper class="w-full h-52" :circular="true" :indicator-dots="false" :autoplay="true" :interval="3000"
:duration="1000" @change="handleBannerChange">
<swiper-item v-for="(item, index) in bannerList" :key="index" class="relative">
<image :src="item.image || item.src" class="h-full w-full" mode="aspectFill"
@click.stop="handleOnClick(item)" />
</swiper-item>
</swiper>
<view v-if="currentBanner"
class="pointer-events-none absolute inset-0 z-10 flex flex-col items-center justify-center gap-y-2 bg-white/5 backdrop-blur-[2rpx]">
<text class="text-sm text-gray-900 font-bold bg-secondary px-3 py-0.5 rounded-xl">
{{ currentBanner.title }}
</text>
<text
class="text-xs text-white text-shadow-[0_2rpx_8rpx_rgba(0,0,0,0.4)]">{{ currentBanner.date }}</text>
</view>
</view>
<view class="absolute bottom-0 left-0 right-0 h-12 w-full bg-gradient-to-b from-white/0 to-page" />
<view class="absolute left-0 right-0 z-10 flex items-center justify-center -translate-y-6">
<view
class="uh-global-card-glass border w-4/5 rounded-full px-4 py-2 text-sm text-gray-600 flex items-center justify-center gap-x-2"
@click="handleToSearch()">
<wd-icon name="search-line" size="32rpx"></wd-icon>
<text>哈喽想看些什么 <text class="bg-secondary rounded-xl px-1">{ 内容 }</text> ~</text>
</view>
</view>
</view>
</template>