From 0c1c71a2908a2f99ffd27def3c5a83a97ff6233e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=8E=AB=E5=94=90=E5=B0=BC?= Date: Thu, 10 Sep 2026 14:39:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9=E6=8E=A5=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E7=AB=AF=E5=8A=9F=E8=83=BD=E5=85=A5=E5=8F=A3=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=B9=B6=E7=A7=BB=E9=99=A4=20votePlugin/linksPlugin=20?= =?UTF-8?q?=E6=B6=88=E8=B4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 快捷导航 QuickNavItem 新增 subTitle,模板渲染对齐(truncate 小字),保留 useLocalNav - love.vue navList 改读 loveConfig.navList(desc→subTitle、priority 排序、visible 过滤、key 映射图标/路径),保留 useLocalNav - about.vue 优先读 pageConfig.myPageConfig 渲染常用/其他两组入口,未配置回退本地默认,组标题改「常用功能」 - 清理 pluginConfig.votePlugin/linksPlugin(types/config/appConfig.ts),about.vue 投票/友链显隐改用 usePluginAvailable 插件启用检测 Co-Authored-By: AtomCode (deepseek-v4-flash) --- src/api/types/uni-halo.ts | 6 +- .../uh-home-quick-nav/uh-home-quick-nav.vue | 18 ++- src/config/appConfig.ts | 2 - src/pages-blog/love/love.vue | 103 +++++++++++++----- src/pages/tabbar/about/about.vue | 84 ++++++++++++-- 5 files changed, 165 insertions(+), 48 deletions(-) diff --git a/src/api/types/uni-halo.ts b/src/api/types/uni-halo.ts index 2c89338..7e5252a 100644 --- a/src/api/types/uni-halo.ts +++ b/src/api/types/uni-halo.ts @@ -14,14 +14,12 @@ export interface IImagesConfig { [key: string]: unknown } -/** 插件配置(toolsPlugin/linksPlugin 等带 Authorization) */ +/** 插件配置(toolsPlugin 等带 Authorization) */ export interface IPluginConfig { - votePlugin?: Record toolsPlugin?: { Authorization?: string } & Record - linksPlugin?: Record /** * 链接配置(插件端 spec.linkInfo 直接下发到本键,结构 = {miniInfo, siteInfo, authorInfo},字段名无映射; - * linksSubmitPlugin 旧键已弃用不再下发) + * linksSubmitPlugin 旧键已弃用不再下发;votePlugin/linksPlugin 已下线(2026-09-10,app 端改插件启用检测判定)) */ linkInfo?: { /** 小程序信息(「申请信息」弹窗展示) */ diff --git a/src/components/uh-home-quick-nav/uh-home-quick-nav.vue b/src/components/uh-home-quick-nav/uh-home-quick-nav.vue index bd32af7..5b89197 100644 --- a/src/components/uh-home-quick-nav/uh-home-quick-nav.vue +++ b/src/components/uh-home-quick-nav/uh-home-quick-nav.vue @@ -7,13 +7,13 @@ const calcAuditModeEnabled = computed(() => appConfigStore.auditModeEnabled) const calcIsShowQuickNavigationEnabled = computed(() => haloConfigs.value.pageConfig?.homeConfig?.useQuickNavigation) - const calcVotePluginEnabled = computed(() => !!haloConfigs.value.pluginConfig?.votePlugin?.enabled) - const calcLinksPluginEnabled = computed(() => !!haloConfigs.value.pluginConfig?.linksPlugin?.enabled) - /** 快捷导航项(字段命名与插件端 quickNavigation 一致:key/title/color/bgColor/iconPrefix/icon/path/visible,无 borderColor) */ + /** 快捷导航项(字段命名与插件端 quickNavigation 一致:key/title/subTitle/color/bgColor/iconPrefix/icon/path/visible,无 borderColor) */ interface QuickNavItem { key : string title ?: string + /** 副标题(对标 about 页 rightText,如「全部文章」;2026-09-10 插件端新增可空字段) */ + subTitle ?: string color ?: string bgColor ?: string iconPrefix ?: string @@ -29,6 +29,7 @@ { key: 'archives', title: '文章归档', + subTitle: '全部文章', color: '#03A9F4', bgColor: 'rgba(3, 169, 244, 0.14)', iconPrefix: 'uhemoji2-icon', @@ -118,10 +119,15 @@ }"> - - {{ item.title }} + + + {{ item.title }} + + + {{ item.subTitle }} + - \ No newline at end of file + diff --git a/src/config/appConfig.ts b/src/config/appConfig.ts index 740b622..872b40f 100644 --- a/src/config/appConfig.ts +++ b/src/config/appConfig.ts @@ -7,9 +7,7 @@ export const DefaultAppConfigs: IAppConfig = { authorConfig: {}, appConfig: {}, pluginConfig: { - votePlugin: {}, toolsPlugin: {}, - linksPlugin: {}, doubanPlugin: { position: 'bottom', }, diff --git a/src/pages-blog/love/love.vue b/src/pages-blog/love/love.vue index 9aa5d8c..0aabc78 100644 --- a/src/pages-blog/love/love.vue +++ b/src/pages-blog/love/love.vue @@ -34,9 +34,24 @@ ourStory : { enabled : boolean, passwordEnabled ?: boolean } lovePhoto : { enabled : boolean, passwordEnabled ?: boolean } loveDaily : { enabled : boolean, passwordEnabled ?: boolean } + /** 恋爱页入口列表(插件端 spec.love.navList 经 getConfigs 下发,additive; + * 字段 key/title/subTitle/priority/visible,desc 已改名 subTitle) */ + navList ?: ILoveNavItem[] [key : string] : unknown } + /** 恋爱页入口项(对齐插件端 GeneralConfig.LoveNavItem;key 固定 stories/album/list) */ + interface ILoveNavItem { + key : string + title ?: string + /** 副标题(原 app 端 desc 文案改名 subTitle) */ + subTitle ?: string + /** 排序(越大越靠前) */ + priority ?: number + /** 是否展示(不可删除,仅禁用/启用) */ + visible ?: boolean + } + const loveConfig = ref({ enabled: false, loveDateTitle: '', @@ -60,8 +75,34 @@ const loveDayCount = ref({ d: 0, h: 0, m: 0, s: 0 }) let loveDayTimer : ReturnType | null = null - const navList = ref<{ key : string, use : boolean, iconPrefix : string, icon : string, title : string, desc : string }[]>([]) + /** 恋爱页入口渲染项(字段由 initList 从插件端 loveConfig.navList 合成:key 映射图标/路径、desc→subTitle) */ + interface ILoveNavRenderItem { + key : string + use : boolean + iconPrefix : string + icon : string + title : string + subTitle : string + } + // 是否使用本地的恋爱页入口数据(本地的可以任意修改图标/路径/文案,插件端的仅可配置 title/subTitle/排序/显隐) + const useLocalNav = false + + /** 内置默认入口项(未配置时回退;字段命名与插件端 loveConfig.navList 一致,desc 文案改名 subTitle) */ + const DEFAULT_NAV_LIST : ILoveNavItem[] = [ + { key: 'stories', title: '恋爱故事', subTitle: '我们一起度过的那些经历', priority: 1, visible: true }, + { key: 'album', title: '恋爱相册', subTitle: '定格了我们的那些小美好', priority: 2, visible: true }, + { key: 'list', title: '恋爱清单', subTitle: '你我之间的约定我们都在努力实现', priority: 3, visible: true }, + ] + + /** 入口 key → 图标与跳转页映射(固定:key=stories/album/list,对应恋爱三模块) */ + const NAV_META: Record = { + stories: { iconPrefix: 'uhlove-icon', icon: 'gushi', page: 'stories' }, + album: { iconPrefix: 'uhlove-icon', icon: 'xiangce', page: 'album' }, + list: { iconPrefix: 'uhlove-icon', icon: 'liebiao', page: 'list' }, + } + + const navList = ref([]) /* ---------------- 数据加载 ---------------- */ function syncLoveConfigFromStore() { @@ -88,6 +129,7 @@ ourStory: loveModuleConfig.ourStory || loveConfig.value.ourStory, lovePhoto: loveModuleConfig.lovePhoto || loveConfig.value.lovePhoto, loveDaily: loveModuleConfig.loveDaily || loveConfig.value.loveDaily, + navList: loveModuleConfig.navList || loveConfig.value.navList, } } @@ -98,34 +140,39 @@ } } + /** 恋爱页入口:优先读插件端 loveConfig.navList(visible 过滤 + priority 排序,desc→subTitle, + * key 映射图标/路径,模块开关 enabled 与条目 visible 均 true 才展示);未配置/为空回退内置默认 */ function initList() { const configs = loveConfig.value - navList.value = [ - { - key: 'stories', - use: configs.ourStory.enabled, - title: '恋爱故事', - desc: '我们一起度过的那些经历', - iconPrefix: 'uhlove-icon', - icon: 'gushi', - }, - { - key: 'album', - use: configs.lovePhoto.enabled, - title: '恋爱相册', - desc: '定格了我们的那些小美好', - iconPrefix: 'uhlove-icon', - icon: 'xiangce' - }, - { - key: 'list', - use: configs.loveDaily.enabled, - title: '恋爱清单', - desc: '你我之间的约定我们都在努力实现', - iconPrefix: 'uhlove-icon', - icon: 'liebiao' - }, - ] + const configured = configs.navList + let source : ILoveNavItem[] + if (!useLocalNav && configured && configured.length) { + source = configured + } else { + source = DEFAULT_NAV_LIST; + } + // priority 排序(越大越靠前;缺失按默认顺序兜底) + const sorted = [...source].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0)) + navList.value = sorted.map((item) => { + const meta = NAV_META[item.key] + if (!meta) { + return null + } + const moduleKey = MODULE_KEY_MAP[item.key] + const moduleCfg = moduleKey + ? (configs[moduleKey] as { enabled ?: boolean } | undefined) + : undefined + const fallback = DEFAULT_NAV_LIST.find((d) => d.key === item.key) + return { + key: item.key, + // 模块开关与条目显示开关均开启才展示(与插件端语义一致) + use: !!moduleCfg?.enabled && item.visible !== false, + iconPrefix: meta.iconPrefix, + icon: meta.icon, + title: item.title || fallback?.title || '', + subTitle: item.subTitle || fallback?.subTitle || '', + } + }).filter((item): item is ILoveNavRenderItem => item !== null) } /* ---------------- 恋爱计时 ---------------- */ @@ -300,7 +347,7 @@ {{ nav.title }} - {{ nav.desc }} + {{ nav.subTitle }} diff --git a/src/pages/tabbar/about/about.vue b/src/pages/tabbar/about/about.vue index f0f1b35..7dba81a 100644 --- a/src/pages/tabbar/about/about.vue +++ b/src/pages/tabbar/about/about.vue @@ -27,12 +27,18 @@ const favoritesStore = useFavoritesStore() const haloConfigs = computed(() => appConfigStore.configs) const calcAuditModeEnabled = computed(() => appConfigStore.auditModeEnabled) - const calcVotePluginEnabled = computed(() => !!haloConfigs.value.pluginConfig?.votePlugin?.enabled) - const calcLinksPluginEnabled = computed(() => !!haloConfigs.value.pluginConfig?.linksPlugin?.enabled) /** 数据看板插件可用性(供导航项显隐判断,参考 gallery 对象传参模式) */ const { check: checkDataVisualPlugin } = usePluginAvailable({ pluginId: NeedPluginIds.PluginDataStatistics, }) + /** 投票插件可用性(投票中心导航项显隐;pluginConfig.votePlugin 已下线,2026-09-10 改插件启用检测) */ + const { check: checkVotePluginAvailable } = usePluginAvailable({ + pluginId: NeedPluginIds.PluginVote, + }) + /** 链接插件可用性(友情链接导航项显隐;pluginConfig.linksPlugin 已下线,2026-09-10 改插件启用检测) */ + const { check: checkLinksPluginAvailable } = usePluginAvailable({ + pluginId: NeedPluginIds.PluginLinks, + }) /* ---------------- 计算属性 ---------------- */ const bloggerInfo = computed(() => { @@ -89,6 +95,8 @@ icon : string /** 图标块背景色(与首页快捷导航同色板,同一功能同色) */ bgColor : string + /** 图标颜色(插件端 myPageConfig 条目 color;本地默认缺省由 toSolidColor(bgColor) 派生) */ + color ?: string rightText : string path : string | null isAdmin ?: boolean @@ -98,13 +106,41 @@ group : 'blog' | 'more' } + /** 插件端 myPageConfig 条目(pageConfig.myPageConfig.commonFeatures/otherFeatures; + * 字段命名与插件端一致:key/title/subTitle/color/bgColor/iconPrefix/icon/path/visible) */ + interface IMyPageEntry { + key ?: string + title ?: string + subTitle ?: string + color ?: string + bgColor ?: string + iconPrefix ?: string + icon ?: string + path ?: string + visible ?: boolean + } + + // 是否使用本地的功能入口数据(true=忽略插件端 myPageConfig,用内置默认;便于二次开发本地定制) + const useLocalNav = false + + /** 插件端 myPageConfig(additive:未配置/为空返回 null,回退本地内置默认) */ + const configuredFeatures = computed(() => { + const mp = haloConfigs.value.pageConfig?.myPageConfig as + | { commonFeatures ?: IMyPageEntry[], otherFeatures ?: IMyPageEntry[] } + | undefined + if (useLocalNav || !mp || (!mp.commonFeatures?.length && !mp.otherFeatures?.length)) { + return null + } + return mp + }) + const navList = ref([]) - /** 分组渲染(过滤后空组整组隐藏) */ + /** 分组渲染(过滤后空组整组隐藏;组标题对齐插件端:常用功能/其他功能) */ const calcNavGroups = computed(() => { const visible = navList.value.filter(n => n.show) const groupDefs : { key : 'blog' | 'more', title : string }[] = [ - { key: 'blog', title: '博客功能' }, + { key: 'blog', title: '常用功能' }, { key: 'more', title: '其他功能' }, ] return groupDefs @@ -132,7 +168,39 @@ } async function handleGetNavList() { - const dataVisualAvailable = await checkDataVisualPlugin() + // 配置模式:插件端 myPageConfig 两组(常用功能→blog、其他功能→more), + // 未配置/为空时回退本地内置默认(保留原显隐推导) + const mp = configuredFeatures.value + if (mp) { + const mapEntry = (e : IMyPageEntry, group : 'blog' | 'more') : INavItem | null => { + if (!e.key) + return null + return { + key: e.key, + title: e.title || '', + iconPrefix: e.iconPrefix, + icon: e.icon || '', + bgColor: e.bgColor || 'rgba(150, 150, 150, 0.95)', + color: e.color, + rightText: e.subTitle || '', + path: e.path || null, + show: e.visible !== false, + group, + } + } + navList.value = [ + ...(mp.commonFeatures || []).map(e => mapEntry(e, 'blog')).filter((n): n is INavItem => n !== null), + ...(mp.otherFeatures || []).map(e => mapEntry(e, 'more')).filter((n): n is INavItem => n !== null), + ] + syncFavoritesNavText() + return + } + + const [dataVisualAvailable, voteAvailable, linksAvailable] = await Promise.all([ + checkDataVisualPlugin(), + checkVotePluginAvailable(), + checkLinksPluginAvailable(), + ]) navList.value = [ { @@ -188,7 +256,7 @@ bgColor: 'rgba(0, 188, 212, 0.95)', rightText: '查看和进行投票', path: '/pages-blog/votes/votes', - show: !calcAuditModeEnabled.value && calcVotePluginEnabled.value, + show: !calcAuditModeEnabled.value && voteAvailable, // show: true, group: 'blog', }, @@ -200,7 +268,7 @@ bgColor: 'rgba(0, 150, 136, 0.95)', rightText: '看看博主朋友们吧', path: '/pages-blog/friend-links/friend-links', - show: calcLinksPluginEnabled.value, + show: linksAvailable, // show: true, group: 'blog', }, @@ -364,7 +432,7 @@ class="uh-global-card-glass border uh-shadow-xs h-8 w-8 flex items-center justify-center rounded-xl" :style="{ backgroundColor: toLightBg(nav.bgColor) }"> + :color="nav.color || toSolidColor(nav.bgColor)" /> {{ nav.title }}