diff --git a/assets/admin/src/constants/sections/index.js b/assets/admin/src/constants/sections/index.js index 239c67df..ddb007c8 100644 --- a/assets/admin/src/constants/sections/index.js +++ b/assets/admin/src/constants/sections/index.js @@ -11,23 +11,206 @@ import { themeInfoSection } from './theme-info' import { docsSection } from './docs' import { toolsSection } from './tools' +const DEMOTED_CHILDREN = { + 'post-list': ['post-list-submit'], + users: [ + 'users-invite-codes', + 'users-sms', + 'users-wechat', + 'users-wechat-template', + 'users-messages', + 'users-ban', + 'users-report', + ], + payment: ['payment-paid'], + shop: ['shop-dashboard'], + forum: ['forum-dashboard'], + extensions: [ + 'extensions-audit', + 'extensions-push', + 'extensions-docs-mode', + 'extensions-security', + 'extensions-tools', + 'extensions-ai', + ], +} + +const COMPAT_PAGE_ORDER = [ + 'tools-import-export', + 'tools-backup', + 'tools-health', + 'tools-migration', + 'tools-email-rollback', + 'tools-update', + 'theme-info-dashboard', + 'docs-dashboard', + 'theme-authorization', + 'payment-paid', + 'post-list-submit', + 'users-invite-codes', + 'users-sms', + 'users-wechat', + 'users-wechat-template', + 'users-messages', + 'users-ban', + 'users-report', + 'extensions-docs-mode', + 'extensions-audit', + 'extensions-push', + 'extensions-security', + 'extensions-tools', + 'extensions-ai', + 'shop-dashboard', + 'forum-dashboard', +] + +const COMPAT_PAGE_ORDER_INDEX = new Map(COMPAT_PAGE_ORDER.map((key, index) => [key, index])) + +const DEMOTED_PAGE_OVERRIDES = { + 'post-list-submit': { + label: '前台投稿(兼容)', + title: '前台投稿(兼容)', + desc: '兼容保留前台投稿入口,避免其继续主导内容主线配置。', + }, + 'users-invite-codes': { + label: '邀请码运营(兼容)', + title: '邀请码运营(兼容)', + desc: '兼容保留邀请码运营入口,避免其压过登录、用户功能与签到积分主线。', + }, + 'users-sms': { + label: '短信接口(兼容)', + title: '短信接口(兼容)', + desc: '兼容保留短信供应商配置,不再作为用户主线高权重入口。', + }, + 'users-wechat': { + label: '微信通知(兼容)', + title: '微信通知(兼容)', + desc: '兼容保留微信通知配置,不再进入用户主线设置前排。', + }, + 'users-wechat-template': { + label: '微信模板消息(兼容)', + title: '微信模板消息(兼容)', + desc: '兼容保留微信模板消息入口,作为次级通信能力访问。', + }, + 'users-messages': { + label: '消息中心(兼容)', + title: '消息中心(兼容)', + desc: '兼容保留站内消息治理入口,不再主导用户主线后台路径。', + }, + 'users-ban': { + label: '禁封管理(治理兼容)', + title: '禁封管理(治理兼容)', + desc: '兼容保留禁封治理入口,避免其压过登录与用户功能配置。', + }, + 'users-report': { + label: '禁封/举报(治理兼容)', + title: '禁封/举报(治理兼容)', + desc: '兼容保留举报治理入口,作为次级治理能力访问。', + }, + 'payment-paid': { + label: '下载/付费内容(兼容)', + title: '下载/付费内容(兼容)', + desc: '兼容保留资源型下载/付费内容入口,避免资源主线继续占据支付域前排。', + }, + 'shop-dashboard': { + label: '商城概览(兼容)', + title: '商城概览(兼容)', + desc: '兼容保留商城概览页,默认主路径仍以商品与订单管理为先。', + }, + 'forum-dashboard': { + label: '论坛概览(兼容)', + title: '论坛概览(兼容)', + desc: '兼容保留论坛概览页,默认主路径仍以板块与配置管理为先。', + }, + 'extensions-docs-mode': { + label: '文档模式(兼容)', + title: '文档模式(兼容)', + desc: '兼容保留 docs mode,不再作为主线产品能力入口。', + }, + 'extensions-audit': { + label: 'API内容审核(兼容)', + title: 'API内容审核(兼容)', + desc: '兼容保留治理型审核能力,避免其影响核心内容与用户主线。', + }, + 'extensions-push': { + label: '百度推送(兼容)', + title: '百度推送(兼容)', + desc: '兼容保留搜索推送能力,不再占用主线后台入口。', + }, + 'extensions-security': { + label: '网站安全(兼容)', + title: '网站安全(兼容)', + desc: '兼容保留扩展安全能力,作为低频次级入口访问。', + }, + 'extensions-tools': { + label: '系统工具(兼容)', + title: '系统工具(兼容)', + desc: '兼容保留扩展工具中心,避免与主工具区重复争夺主路径。', + }, + 'extensions-ai': { + label: 'AI 子系统(兼容)', + title: 'AI 子系统(兼容)', + desc: '兼容保留 AI 入口,不再进入 Zibll 主线后台路径。', + }, +} + +function withoutChildren(section, childKeys = []) { + if (!childKeys.length) { + return section + } + + const childKeySet = new Set(childKeys) + + return { + ...section, + children: (section.children || []).filter((child) => !childKeySet.has(child.key)), + } +} + +function pickChildren(section, childKeys = []) { + if (!childKeys.length) { + return [] + } + + const childKeySet = new Set(childKeys) + + return (section.children || []) + .filter((child) => childKeySet.has(child.key)) + .map((child) => ({ + ...child, + ...(DEMOTED_PAGE_OVERRIDES[child.key] || {}), + secondaryEntry: true, + compatSourceSection: section.key, + })) +} + const primarySections = [ globalSection, pageDisplaySection, - postListSection, + withoutChildren(postListSection, DEMOTED_CHILDREN['post-list']), permissionsSection, - usersSection, - paymentSection, - shopSection, - forumSection, - extensionsSection, + withoutChildren(usersSection, DEMOTED_CHILDREN.users), + withoutChildren(paymentSection, DEMOTED_CHILDREN.payment), + withoutChildren(shopSection, DEMOTED_CHILDREN.shop), + withoutChildren(forumSection, DEMOTED_CHILDREN.forum), + withoutChildren(extensionsSection, DEMOTED_CHILDREN.extensions), ] const compatChildren = [ ...(toolsSection.children || []), ...(themeInfoSection.children || []), ...(docsSection.children || []), -] + ...pickChildren(paymentSection, DEMOTED_CHILDREN.payment), + ...pickChildren(postListSection, DEMOTED_CHILDREN['post-list']), + ...pickChildren(usersSection, DEMOTED_CHILDREN.users), + ...pickChildren(extensionsSection, DEMOTED_CHILDREN.extensions), + ...pickChildren(shopSection, DEMOTED_CHILDREN.shop), + ...pickChildren(forumSection, DEMOTED_CHILDREN.forum), +].sort((left, right) => { + const leftIndex = COMPAT_PAGE_ORDER_INDEX.get(left.key) ?? Number.MAX_SAFE_INTEGER + const rightIndex = COMPAT_PAGE_ORDER_INDEX.get(right.key) ?? Number.MAX_SAFE_INTEGER + return leftIndex - rightIndex +}) export const compatToolsSection = { key: 'tools-compat', diff --git a/assets/admin/src/router/index.js b/assets/admin/src/router/index.js index 0a197069..6d28ca64 100644 --- a/assets/admin/src/router/index.js +++ b/assets/admin/src/router/index.js @@ -2,6 +2,8 @@ import { createRouter, createWebHashHistory } from 'vue-router' import { getAllAdminPages } from '@/constants/admin-sections' import { componentLoaders } from './component-loaders/index.js' +const ADMIN_DEFAULT_ROUTE = '/global/common' + function resolveComponent(page) { if (componentLoaders[page.component]) { return componentLoaders[page.component] @@ -23,6 +25,11 @@ function createRouteMeta(page) { section: page.sectionKey || '', desc: page.desc || '', status: page.status || 'available', + secondaryEntry: page.secondaryEntry === true, + } + + if (page.compatSourceSection) { + meta.compatSourceSection = page.compatSourceSection } if (page.canonicalDomain) { @@ -51,7 +58,7 @@ function createRouteMeta(page) { } const routes = [ - { path: '/', redirect: '/global/common' }, + { path: '/', redirect: ADMIN_DEFAULT_ROUTE }, ...getAllAdminPages().map((page) => ({ path: page.route, name: page.name, @@ -64,3 +71,4 @@ export default createRouter({ history: createWebHashHistory(), routes, }) +