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:
@@ -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-10,app 端改插件启用检测判定))
|
||||
*/
|
||||
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>
|
||||
|
||||
@@ -7,9 +7,7 @@ export const DefaultAppConfigs: IAppConfig = {
|
||||
authorConfig: {},
|
||||
appConfig: {},
|
||||
pluginConfig: {
|
||||
votePlugin: {},
|
||||
toolsPlugin: {},
|
||||
linksPlugin: {},
|
||||
doubanPlugin: {
|
||||
position: 'bottom',
|
||||
},
|
||||
|
||||
@@ -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<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.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 }}
|
||||
</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">
|
||||
|
||||
@@ -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<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>
|
||||
|
||||
Reference in New Issue
Block a user