docs: 精简 README,细节拆分到 docs/
README 仅保留概览/结构/基础设施/安装/开发命令; 架构、新增页签、子模块管理细节移至 docs/ 下三个 md: - docs/architecture.md:模块注册/PageShell/KeepAlive/存活校验 - docs/add-module.md:新增页签步骤 + 元数据字段速查 + 常见变体 - docs/submodule-timeTableFix.md:submodule 升级/clone/移除/独立访问
This commit is contained in:
79
docs/architecture.md
Normal file
79
docs/architecture.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# 架构
|
||||
|
||||
mainPage 是一个 Vue 3 模块化多项目展示站。核心设计目标:**高内聚低耦合** -- 每个项目页签是一个独立「模块」,由注册表自动生成页签与路由,新增/删除页签只增删一个文件夹,互不影响。
|
||||
|
||||
## 模块注册表(扩展点核心)
|
||||
|
||||
`src/modules/index.js` 用 `import.meta.glob('./*/index.js', { eager: true })` 约定式收集每个子模块的 `index.js`。每个模块默认导出元数据:
|
||||
|
||||
```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` 是可复用的页面外壳组件,统一所有页面的:
|
||||
|
||||
- **容器宽度**:默认复用全局 `.container`(`max-width: 1080px`,居中,左右 `padding`);`fluid` 变体突破限制全宽(如日历页)
|
||||
- **垂直节奏**:`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` Map),`useProjects`(页签可见性)与 `App.vue`(KeepAlive 卸载)共用同一 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)。
|
||||
Reference in New Issue
Block a user