Files
zMainPage/docs/architecture.md
zikai 4334dec00d docs: 精简 README,细节拆分到 docs/
README 仅保留概览/结构/基础设施/安装/开发命令;
架构、新增页签、子模块管理细节移至 docs/ 下三个 md:
- docs/architecture.md:模块注册/PageShell/KeepAlive/存活校验
- docs/add-module.md:新增页签步骤 + 元数据字段速查 + 常见变体
- docs/submodule-timeTableFix.md:submodule 升级/clone/移除/独立访问
2026-07-23 04:09:42 +00:00

4.7 KiB
Raw Blame History

架构

mainPage 是一个 Vue 3 模块化多项目展示站。核心设计目标:高内聚低耦合 -- 每个项目页签是一个独立「模块」,由注册表自动生成页签与路由,新增/删除页签只增删一个文件夹,互不影响。

模块注册表(扩展点核心)

src/modules/index.jsimport.meta.glob('./*/index.js', { eager: true }) 约定式收集每个子模块的 index.js。每个模块默认导出元数据:

export default {
  id: 'whiteboard',                              // 必填:唯一标识,同时作路由 path / KeepAlive 匹配名
  tabKey: 'tabs.whiteboard',                     // 必填i18n 键,页签标题与 PageShell 标题均用此
  component: () => import('./Whiteboard.vue'),   // 必填:懒加载组件(函数形式,独立 chunk
  order: 2,                                      // 可选:页签排序,缺省 999排在显式页签之后
  hidden: true,                                  // 可选:不在导航显示,但 URL 访问后保持可见(如 cqy
  requiresAlive: 'https://f.zikai.wang/health',  // 可选:存活探针 URL服务失活则隐藏页签并卸载组件
  param: 'boardId',                              // 可选:路由参数名,生成 /<id>/:<param>? 子路径
}

元数据字段 -> 消费方矩阵

字段 注册表 router useProjects App.vue TabNav
id 必填校验 path+name+meta.moduleId visited 集合 / 路由关联 keepInclude 名单 :to + :key
tabKey 必填校验 - - - 标题文案
component 必填校验 路由 component - RouterView 渲染 -
order 排序 决定 / 重定向目标 继承顺序 - 继承顺序
hidden 透传 - 可见性门控 - -
requiresAlive 透传 - 可见性门控 keepInclude + startPolling -
param 透传 /:<param>? 后缀 - - -

容错

注册表对每个模块做字段完整性校验(缺 id/tabKey/component 的模块跳过),单个模块异常不影响其余页签加载。

PageShell统一页面外壳

src/components/ui/PageShell.vue 是可复用的页面外壳组件,统一所有页面的:

  • 容器宽度:默认复用全局 .containermax-width: 1080px,居中,左右 paddingfluid 变体突破限制全宽(如日历页)
  • 垂直节奏padding: var(--space-xl) 0 var(--space-2xl)padded: false 可关
  • 标题titleKey prop -> i18n 文案,渲染为 <h1>
  • 操作区#actions 具名插槽,放在标题旁(如白板的切换白板表单)

各模块根组件用 <PageShell> 包裹内容,不再各写一套 .container/标题/间距。新增页签照此复用。

KeepAlive 缓存与卸载

App.vue<KeepAlive :include="keepInclude"> 包裹路由组件,切换页签不卸载(状态保留)。

  • keepInclude 是模块 id 列表,默认包含所有模块。
  • 声明了 requiresAlive 的模块,当存活探测为 down 时移出名单 -> 组件卸载;恢复 up 后重新纳入。
  • 匹配约定KeepAlive 按组件 name 匹配,因此每个模块组件需 defineOptions({ name: <模块 id> })
    • 内置模块mobile-game/whiteboard/calendar直接在组件内声明。
    • 子模块集成timetable由 mainPage 侧包装器 Timetable.vue 持有 name子项目自身不持 name保持纯净

存活校验requiresAlive

src/composables/useLiveness.js 提供跨域存活探测:

  • 探测方式:fetch(url, { mode: 'no-cors', cache: 'no-store' })resolve 即存活4s 超时。
  • 时机:应用加载即探测一次,之后每 30s 周期重探(startPolling)。
  • 结果在全应用共享(模块级 cache MapuseProjects(页签可见性)与 App.vueKeepAlive 卸载)共用同一 ref。
  • 乐观显示探测中pending/存活up都显示页签仅明确不可达down才隐藏并卸载恢复后自动重新加载。

目前仅白板页签使用(requiresAlive: 'https://f.zikai.wang/health')。

路由

src/router/index.js 遍历注册表生成路由每个模块一条路由path = /<id> + 可选 /:<param>?。history 模式,需站点根 .htaccess 做 SPA 回退(见 README 安装步骤)。

国际化

src/i18n/ -- 中文同步注入主 chunk默认语言英文通过动态 import() 懒加载成独立 chunk只看中文的访客不会下载英文资源。各模块 tabKey 指向 tabs.* 下的文案。

集中配置

src/config/app.config.js -- 外部服务 URL白板地址、存活探针路径等集中管理模块按需 import。改 URL 只改这里(需重新 build