1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-09-12 16:40:40 +08:00

feat: 新增公告模块、数据加载hook与多项体验优化

- 新增公告全流程功能:首页公告轮播、公告列表页、公告详情页
- 新增统一数据加载状态hook useDataLoading与配套测试
- 重构配置加载逻辑,新增统一bootstrap静态配置拉取
- 新增维护模式、恋爱模块支持与验证码防刷功能
- 优化投票卡片、联系页、关于页UI样式
- 新增测试页面与全局玻璃卡片样式
- 修复markdown容器内边距与首页生命周期逻辑
This commit is contained in:
小莫唐尼
2026-09-04 02:57:25 +08:00
parent 902faa70e7
commit 5f22f4fa01
39 changed files with 4474 additions and 2244 deletions
+48 -55
View File
@@ -320,10 +320,10 @@ onReachBottom(() => {
</script>
<template>
<view class="app-page min-h-screen w-screen flex flex-col" style="background-color: #fafafd;">
<view class="app-page min-h-screen w-screen flex flex-col bg-page">
<!-- 顶部 tabs -->
<view class="tabs-wrap sticky top-0 z-10 bg-white px-6">
<wd-tabs v-model="activeTabIndex" align="left" @change="handleOnTabChange">
<view class="tabs-wrap uh-global-card-glass sticky top-0 z-10 px-6">
<wd-tabs v-model="activeTabIndex" align="left" custom-style="background: transparent;" @change="handleOnTabChange">
<wd-tab title="站点" />
<wd-tab v-if="!appConfigStore.auditModeEnabled" title="小程序" />
</wd-tabs>
@@ -342,43 +342,42 @@ onReachBottom(() => {
<wd-skeleton :row="5" :animated="true" />
</view>
<view v-else class="content pt-6" :class="{ 'bg-white': dataList.length !== 0 }">
<view v-else class="content pt-4">
<view v-if="dataList.length === 0" class="h-[60vh] flex items-center justify-center content-empty">
<wd-empty description="啊偶,博主还没有朋友呢~" />
</view>
<!-- 友链列表 -->
<view v-else class="link-list px-6">
<view v-for="(link, index) in dataList" :key="index">
<view v-else class="link-list flex flex-col gap-4 px-4 pb-4">
<view v-for="link in dataList" :key="link.metadata?.name || link.spec.displayName">
<!-- 色彩版 -->
<view
v-if="!globalAppSettings.links.useSimple"
class="info flex bg-white p-3"
:class="{ 'border-b-2 border-[#f5f5f5]': index !== dataList.length - 1 }"
class="info uh-global-card-glass flex rounded-2xl p-3"
@click="handleOnLinkEvent(link)"
>
<image class="link-logo h-[140rpx] w-[140rpx] shrink-0 rounded-xl" :src="link.spec.logo" mode="aspectFill" />
<view class="info-detail flex flex-1 flex-col justify-center pl-7">
<view class="link-card-name text-[30rpx] text-[#f44336] font-bold">
<text class="group-tag mr-3 rounded-md px-1.5 py-0.5 text-[20rpx] text-white font-normal" style="background: linear-gradient(135deg, #64b5f6, #2196f3);">{{ link.spec.groupName || '暂未分组' }}</text>
<view class="info-detail flex flex-1 flex-col justify-center pl-5">
<view class="link-card-name text-[30rpx] text-gray-900 font-bold">
<text class="group-tag mr-3 rounded-md bg-secondary px-1.5 py-0.5 text-[20rpx] text-[#4d7c0f] font-normal">{{ link.spec.groupName || '暂未分组' }}</text>
{{ link.spec.displayName }}
</view>
<view class="link-card-url mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-[#666]">
<view class="link-card-url mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-gray-400">
站点地址{{ link.spec.url }}
</view>
<view class="link-card-desc mt-2 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-[#303133]">
<view class="link-card-desc mt-2 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-gray-600">
博客简介{{ link.spec.description || '这个博主很懒,没写简介~' }}
</view>
</view>
</view>
<!-- 简洁版 -->
<view v-else class="link-card mb-6 flex items-center rounded-xl bg-white p-6 shadow-sm" @click="handleOnLinkEvent(link)">
<image class="logo h-[80rpx] w-[80rpx] shrink-0 border-6 border-white rounded-xl" :src="link.spec.logo" mode="aspectFill" />
<view class="link-info flex-1 pl-6">
<view class="name text-[30rpx] text-[#303133] font-bold">
<view v-else class="link-card uh-global-card-glass flex items-center rounded-2xl p-4" @click="handleOnLinkEvent(link)">
<image class="logo h-[80rpx] w-[80rpx] shrink-0 border-4 border-white/90 rounded-xl" :src="link.spec.logo" mode="aspectFill" />
<view class="link-info flex-1 pl-5">
<view class="name text-[30rpx] text-gray-900 font-bold">
{{ link.spec.displayName }}
</view>
<view class="desc mt-3 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-[#909399]">
<view class="desc mt-2 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-gray-400">
{{ link.spec.description }}
</view>
</view>
@@ -388,39 +387,39 @@ onReachBottom(() => {
<!-- 悬浮按钮 -->
<view class="flot-buttons fixed bottom-[100rpx] right-8 z-999 flex flex-col gap-1.5">
<view class="fab-btn h-[72rpx] w-[72rpx] flex items-center justify-center rounded-full bg-white shadow-sm" @click="handleToTopPage()">
<wd-icon name="arrow-up" size="20px" color="#03a9f4" />
<view class="fab-btn uh-global-card-glass h-[72rpx] w-[72rpx] flex items-center justify-center rounded-full" @click="handleToTopPage()">
<wd-icon name="arrow-up" size="20px" color="#6b7280" />
</view>
<view v-if="(haloPluginConfigs?.linksSubmitPlugin as { enabled?: boolean } | undefined)?.enabled" class="fab-btn h-[72rpx] w-[72rpx] flex items-center justify-center rounded-full bg-white shadow-sm" @click="toSubmitLinkPage">
<wd-icon name="edit" size="20px" color="#ff9800" />
<view v-if="(haloPluginConfigs?.linksSubmitPlugin as { enabled?: boolean } | undefined)?.enabled" class="fab-btn uh-global-card-glass h-[72rpx] w-[72rpx] flex items-center justify-center rounded-full" @click="toSubmitLinkPage">
<wd-icon name="edit" size="20px" color="#6b7280" />
</view>
</view>
<!-- 详情弹窗 -->
<wd-popup v-model="detail.show" position="center" custom-style="width:640rpx;border-radius:12rpx;">
<view v-if="detail.data" class="poup p-9">
<view v-if="detail.data" class="poup p-8">
<view class="info flex">
<image class="poup-logo h-[140rpx] w-[140rpx] shrink-0 rounded-full" :src="checkImageUrl(detail.data.spec.logo)" mode="aspectFill" />
<view class="poup-info ml-6 flex flex-1 flex-col justify-center">
<view class="poup-name text-[34rpx] font-bold">
<view class="poup-name text-[34rpx] text-gray-900 font-bold">
{{ detail.data.spec.displayName }}
</view>
<view class="poup-tag mt-2 text-[24rpx] text-[#999]">
<view class="poup-tag mt-2 text-[24rpx] text-gray-400">
{{ detail.data.spec.groupName }}
</view>
<view class="poup-link mt-3" @click="handleCopyLink(detail.data)">
<text class="poup-url text-[24rpx] text-[#ff9800]">{{ detail.data.spec.url }}</text>
<text class="poup-url rounded-lg bg-secondary px-2 py-1 text-[24rpx] text-[#4d7c0f]">{{ detail.data.spec.url }}</text>
</view>
</view>
</view>
<view class="poup-desc mt-5 text-[28rpx] text-[#555] leading-[1.6]">
<view class="poup-desc mt-5 text-[28rpx] text-gray-600 leading-[1.6]">
博客简介{{ detail.data.spec.description || '这个博主很懒,没写简介~' }}
</view>
<image class="poup-img mt-6 h-[320rpx] w-[568rpx] rounded-xl" :src="calcSiteThumbnail(detail.data.spec.url)" mode="aspectFill" />
<image class="poup-img mt-6 h-[320rpx] w-full rounded-xl" :src="calcSiteThumbnail(detail.data.spec.url)" mode="aspectFill" />
</view>
</wd-popup>
<view class="load-text py-5 text-center text-[24rpx] text-[#999]">
<view class="load-text py-5 text-center text-[24rpx] text-gray-400">
{{ loadMoreText }}
</view>
</view>
@@ -450,15 +449,15 @@ onReachBottom(() => {
<view v-else class="mini-link-list flex-1 px-6 py-4">
<view v-for="group in miniGroups" :key="group.groupName || 'ungrouped'" class="group-item mb-8">
<view class="group-title mb-4 flex items-center">
<text class="mr-2 inline-block h-[28rpx] w-[8rpx] rounded-full" style="background-color:#2196f3;" />
<text class="text-[30rpx] text-[#303133] font-bold">{{ group.displayName || '未分组' }}</text>
<text class="ml-3 text-[24rpx] text-[#999]">{{ group.links.length }}</text>
<text class="mr-2 inline-block h-[28rpx] w-[8rpx] rounded-full bg-secondary" />
<text class="text-[30rpx] text-gray-900 font-bold">{{ group.displayName || '未分组' }}</text>
<text class="ml-3 text-[24rpx] text-gray-400">{{ group.links.length }}</text>
</view>
<view class="group-cards flex flex-col gap-4">
<view
v-for="link in group.links"
:key="link.metadata?.name"
class="mini-card flex items-center rounded-xl bg-white p-4 shadow-sm"
class="mini-card uh-global-card-glass flex items-center rounded-2xl p-4"
@click="handleOnMiniLinkEvent(link)"
>
<image
@@ -467,17 +466,17 @@ onReachBottom(() => {
mode="aspectFill"
/>
<view class="mini-info flex flex-1 flex-col pl-5">
<view class="mini-name overflow-hidden text-ellipsis whitespace-nowrap text-[30rpx] text-[#303133] font-bold">
<view class="mini-name overflow-hidden text-ellipsis whitespace-nowrap text-[30rpx] text-gray-900 font-bold">
{{ link.spec?.displayName }}
</view>
<view v-if="link.spec?.authorName" class="mini-author mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-[#999]">
<view v-if="link.spec?.authorName" class="mini-author mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-gray-400">
{{ link.spec.authorName }}
</view>
<view class="mini-desc mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-[#666]">
<view class="mini-desc mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-gray-500">
{{ link.spec?.description || '暂无简介~' }}
</view>
</view>
<wd-icon name="arrow-right" size="16px" color="#c0c4cc" />
<wd-icon name="arrow-right" size="16px" color="#c8c2b4" />
</view>
</view>
</view>
@@ -485,7 +484,7 @@ onReachBottom(() => {
<!-- 申请收录悬浮按钮 -->
<view class="apply-btn-wrap fixed bottom-[100rpx] right-8 z-999">
<view class="apply-btn h-[88rpx] flex items-center rounded-full bg-[#2196f3] px-6 shadow-sm" @click="handleOpenApply">
<view class="apply-btn h-[88rpx] flex items-center rounded-full bg-gray-900 px-6" @click="handleOpenApply">
<wd-icon name="add" size="20px" color="#fff" />
<text class="ml-2 text-[26rpx] text-white">申请收录</text>
</view>
@@ -504,42 +503,42 @@ onReachBottom(() => {
@click="handlePreviewMiniProgramCode(miniDetail.data)"
@longpress="handleSaveMiniProgramCode(miniDetail.data)"
/>
<view class="code-tip mt-3 flex items-center text-[24rpx] text-[#999]">
<wd-icon name="picture" size="14px" color="#999" />
<view class="code-tip mt-3 flex items-center text-[24rpx] text-gray-400">
<wd-icon name="picture" size="14px" color="#a8a294" />
<text class="ml-1">点击预览长按保存太阳码</text>
</view>
</view>
<!-- 名称与分组 -->
<view class="mini-head mt-5 flex items-center">
<text class="mini-name text-[34rpx] text-[#303133] font-bold">{{ miniDetail.data.spec?.displayName }}</text>
<text v-if="miniDetail.data.spec?.groupName" class="group-tag ml-3 rounded-md px-2 py-0.5 text-[20rpx] text-white" style="background: linear-gradient(135deg, #64b5f6, #2196f3);">
<text class="mini-name text-[34rpx] text-gray-900 font-bold">{{ miniDetail.data.spec?.displayName }}</text>
<text v-if="miniDetail.data.spec?.groupName" class="group-tag ml-3 rounded-md bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f]">
{{ miniDetail.data.spec.groupName }}
</text>
</view>
<!-- 描述 -->
<view v-if="miniDetail.data.spec?.description" class="mini-desc mt-4 text-[28rpx] text-[#555] leading-[1.6]">
<view v-if="miniDetail.data.spec?.description" class="mini-desc mt-4 text-[28rpx] text-gray-600 leading-[1.6]">
{{ miniDetail.data.spec.description }}
</view>
<!-- 作者信息 -->
<view v-if="miniDetail.data.spec?.authorName || miniDetail.data.spec?.avatar || miniDetail.data.spec?.website" class="mini-author-info mt-5 flex items-center rounded-xl bg-[#f5f5f5] p-4">
<view v-if="miniDetail.data.spec?.authorName || miniDetail.data.spec?.avatar || miniDetail.data.spec?.website" class="mini-author-info mt-5 flex items-center rounded-xl bg-[#f6f3ee] p-4">
<image v-if="miniDetail.data.spec?.avatar" class="author-avatar h-[72rpx] w-[72rpx] shrink-0 rounded-full" :src="checkAvatarUrl(miniDetail.data.spec.avatar)" mode="aspectFill" />
<view class="author-detail ml-4 flex flex-1 flex-col">
<text v-if="miniDetail.data.spec?.authorName" class="author-name text-[28rpx] text-[#303133] font-medium">{{ miniDetail.data.spec.authorName }}</text>
<text v-if="miniDetail.data.spec?.website" class="author-website mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-[#999]" @click="handleCopyMiniProgramCode(miniDetail.data)">
<text v-if="miniDetail.data.spec?.authorName" class="author-name text-[28rpx] text-gray-900 font-medium">{{ miniDetail.data.spec.authorName }}</text>
<text v-if="miniDetail.data.spec?.website" class="author-website mt-1 overflow-hidden text-ellipsis whitespace-nowrap text-[24rpx] text-gray-400" @click="handleCopyMiniProgramCode(miniDetail.data)">
网站{{ miniDetail.data.spec.website }}
</text>
</view>
</view>
<!-- 小程序地址 -->
<view v-if="miniDetail.data.spec?.link" class="mini-link mt-5 flex items-center justify-between rounded-xl bg-[#fff8f0] p-4">
<view class="link-text flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-[26rpx] text-[#ff9800]">
<view v-if="miniDetail.data.spec?.link" class="mini-link mt-5 flex items-center justify-between rounded-xl bg-secondary p-4">
<view class="link-text flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-[26rpx] text-[#4d7c0f]">
{{ miniDetail.data.spec.link }}
</view>
<text class="ml-3 shrink-0 text-[26rpx] text-[#ff9800]" @click="handleCopyMiniProgramCode(miniDetail.data)">复制</text>
<text class="ml-3 shrink-0 text-[26rpx] text-[#4d7c0f] font-bold" @click="handleCopyMiniProgramCode(miniDetail.data)">复制</text>
</view>
<!-- 预览图轮播 -->
@@ -559,9 +558,3 @@ onReachBottom(() => {
</template>
</view>
</template>
<style scoped>
.app-page {
/* 布局全部由 UnoCSS 原子类实现 */
}
</style>