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

feat: 对接插件端功能入口配置并移除 votePlugin/linksPlugin 消费

- 快捷导航 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) <noreply@atomgit.com>
This commit is contained in:
小莫唐尼
2026-09-10 14:39:48 +08:00
parent be55d9ac2c
commit 0c1c71a290
5 changed files with 165 additions and 48 deletions
+2 -4
View File
@@ -14,14 +14,12 @@ export interface IImagesConfig {
[key: string]: unknown
}
/** 插件配置(toolsPlugin/linksPlugin 等带 Authorization) */
/** 插件配置(toolsPlugin 等带 Authorization) */
export interface IPluginConfig {
votePlugin?: Record<string, unknown>
toolsPlugin?: { Authorization?: string } & Record<string, unknown>
linksPlugin?: Record<string, unknown>
/**
* 链接配置(插件端 spec.linkInfo 直接下发到本键,结构 = {miniInfo, siteInfo, authorInfo},字段名无映射;
* linksSubmitPlugin 旧键已弃用不再下发)
* linksSubmitPlugin 旧键已弃用不再下发votePlugin/linksPlugin 已下线(2026-09-10app 端改插件启用检测判定)
*/
linkInfo?: {
/** 小程序信息(「申请信息」弹窗展示) */
@@ -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,8 +119,13 @@
}">
<wd-icon :class-prefix="item.iconPrefix" :name="item.icon" size="64rpx" />
</view>
<view class="text-xs text-gray-900">
<view class="flex flex-col items-center gap-0.5">
<text class="max-w-16 truncate text-xs text-gray-900">
{{ item.title }}
</text>
<text v-if="item.subTitle" class="max-w-16 truncate text-[10rpx] text-gray-400">
{{ item.subTitle }}
</text>
</view>
</view>
</view>
-2
View File
@@ -7,9 +7,7 @@ export const DefaultAppConfigs: IAppConfig = {
authorConfig: {},
appConfig: {},
pluginConfig: {
votePlugin: {},
toolsPlugin: {},
linksPlugin: {},
doubanPlugin: {
position: 'bottom',
},
+75 -28
View File
@@ -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/visibledesc 已改名 subTitle */
navList ?: ILoveNavItem[]
[key : string] : unknown
}
/** 恋爱页入口项(对齐插件端 GeneralConfig.LoveNavItemkey 固定 stories/album/list */
interface ILoveNavItem {
key : string
title ?: string
/** 副标题(原 app 端 desc 文案改名 subTitle */
subTitle ?: string
/** 排序(越大越靠前) */
priority ?: number
/** 是否展示(不可删除,仅禁用/启用) */
visible ?: boolean
}
const loveConfig = ref<ILoveConfigPage>({
enabled: false,
loveDateTitle: '',
@@ -60,8 +75,34 @@
const loveDayCount = ref({ d: 0, h: 0, m: 0, s: 0 })
let loveDayTimer : ReturnType<typeof setTimeout> | 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<string, { iconPrefix: string, icon: string, page: string }> = {
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<ILoveNavRenderItem[]>([])
/* ---------------- 数据加载 ---------------- */
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.navListvisible 过滤 + 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 }}
</view>
<view class="text-xs truncate" :class="[index%2===0?'text-love/60':'text-blue-300']">
{{ nav.desc }}
{{ nav.subTitle }}
</view>
</view>
<view class="shrink-0">
+76 -8
View File
@@ -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
/** 插件端 myPageConfigadditive:未配置/为空返回 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<INavItem[]>([])
/** 分组渲染(过滤后空组整组隐藏) */
/** 分组渲染(过滤后空组整组隐藏;组标题对齐插件端:常用功能/其他功能) */
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) }">
<wd-icon :class-prefix="nav.iconPrefix" :name="nav.icon" size="36rpx"
:color="toSolidColor(nav.bgColor)" />
:color="nav.color || toSolidColor(nav.bgColor)" />
</view>
<text class="nav-title text-sm text-gray-900 font-bold">{{ nav.title }}</text>
</view>