From 4334dec00dc42b5b8d6aa5451c5f03384fe3eccd Mon Sep 17 00:00:00 2001 From: zikai <1621362626@qq.com> Date: Thu, 23 Jul 2026 04:09:42 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20=E7=B2=BE=E7=AE=80=20README=EF=BC=8C?= =?UTF-8?q?=E7=BB=86=E8=8A=82=E6=8B=86=E5=88=86=E5=88=B0=20docs/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README 仅保留概览/结构/基础设施/安装/开发命令; 架构、新增页签、子模块管理细节移至 docs/ 下三个 md: - docs/architecture.md:模块注册/PageShell/KeepAlive/存活校验 - docs/add-module.md:新增页签步骤 + 元数据字段速查 + 常见变体 - docs/submodule-timeTableFix.md:submodule 升级/clone/移除/独立访问 --- README.md | 71 +++++---------------- docs/add-module.md | 112 +++++++++++++++++++++++++++++++++ docs/architecture.md | 79 +++++++++++++++++++++++ docs/submodule-timeTableFix.md | 59 +++++++++++++++++ 4 files changed, 265 insertions(+), 56 deletions(-) create mode 100644 docs/add-module.md create mode 100644 docs/architecture.md create mode 100644 docs/submodule-timeTableFix.md diff --git a/README.md b/README.md index 12adbaa..3d97451 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ Zikai 的作品集主页 -- Vue 3 模块化多项目展示站。浅色极简、中英双语(英文按需懒加载)。 每个项目页签是一个独立「模块」,由注册表自动生成页签与路由 -- 新增/删除页签只增删一个文件夹,互不影响。 +> 架构细节、新增页签指南、子项目管理见 [`docs/`](./docs/)。 + --- ## 项目结构 @@ -14,18 +16,16 @@ mainPage/ ├── vite.config.js # 构建输出到 /root/html(emptyOutDir=false,不清空既有文件) ├── .gitmodules # git submodule:third_party/timeTableFix ├── README.md +├── docs/ # 架构 / 新增页签 / 子模块管理文档 ├── public/favicon.svg ├── third_party/ │ └── timeTableFix/ # ★ git submodule:ICS 日程整理器,独立仓库 -│ # src/App.vue 被 timetable 模块直接 import 为路由组件 └── src/ ├── main.js # 应用入口(挂载 i18n / router / 全局样式) ├── App.vue # 根布局:顶栏 + 标签导航 + + 页脚 ├── config/ - │ └── app.config.js # ★ 集中配置:外部服务 URL(白板地址 / 存活探针等) + │ └── app.config.js # 集中配置:外部服务 URL(白板地址 / 存活探针等) ├── i18n/ # 国际化(中文同步注入;英文动态 import() 懒加载) - │ ├── index.js - │ └── locales/{zh-CN,en}.js ├── router/index.js # 路由表由模块注册表自动生成 ├── modules/ # ★ 扩展点:每个页签一个文件夹 │ ├── index.js # 注册表(import.meta.glob 约定式收集,带容错) @@ -33,32 +33,11 @@ mainPage/ │ ├── whiteboard/ # 共享记事本页签(iframe 嵌入 + 存活校验) │ ├── timetable/ # 日程整理页签(构建期 import 子模块 App.vue) │ └── calendar/ # 隐藏页(仅手动访问 /cqy) - ├── components/ # 共享组件(TabNav / LanguageSwitcher / ui 基元) - ├── composables/ # useProjects(页签+存活联动)/ useLiveness / useI18nLazy / useLocale + ├── components/ # 共享组件(TabNav / LanguageSwitcher / ui 基元含 PageShell) + ├── composables/ # useProjects / useLiveness / useI18nLazy / useLocale └── styles/ # variables.css(主题令牌)+ base.css ``` -## 模块机制(高内聚低耦合) - -- `src/modules/index.js` 用 `import.meta.glob('./*/index.js', { eager: true })` 收集所有模块,单个模块导出异常会跳过并告警,不影响其余页签。 -- 每个模块 `index.js` 默认导出元数据: - ```js - export default { - id: 'whiteboard', // 唯一标识 + 路由 path - tabKey: 'tabs.whiteboard', // i18n 键 - order: 2, // 页签排序 - component: () => import('./Whiteboard.vue'), // 懒加载组件(独立 chunk) - requiresAlive: 'https://f.zikai.wang/health' // 可选:存活探针 URL,挂掉则隐藏页签 - } - ``` -- `TabNav` 遍历注册表渲染页签;`router` 遍历注册表生成路由。 -- 删除一个页签 = 删 `src/modules//` 文件夹并重新 build,其余页签不受影响。 - -### 存活校验 - -声明了 `requiresAlive` 的模块,应用加载即探测探针 URL(`no-cors` fetch,4s 超时),之后每 30s 周期重探。 -乐观显示:探测中/存活都显示页签,仅明确不可达时才隐藏并从 KeepAlive 移出(卸载组件);恢复后自动重新加载。目前仅白板页签使用。 - ## 依赖的基础设施 | 项 | 要求 | @@ -67,9 +46,8 @@ mainPage/ | Web 服务器 | Apache 2.4(启用 `mod_rewrite`),对外静态服务 `/root/html` | | SPA 回退 | history 模式需站点根 `.htaccess` 回退到 `index.html`(见下) | -> 共享记事本页签通过 iframe 嵌入外部服务(默认 `https://f.zikai.wang/wb/share`),URL 在 `src/config/app.config.js` 集中配置。该服务需公开且允许被 iframe 嵌入。 -> -> 日程整理页签(timeTableFix)通过 **git submodule** 作为子项目,构建期直接 import 其 `App.vue` 为路由组件(非 iframe);同时其独立 app 可经 Apache `/ttf/` 反代单独访问。 +> 共享记事本页签 iframe 嵌入外部服务(`https://f.zikai.wang/wb/share`),URL 在 `src/config/app.config.js` 配置。 +> 日程整理页签(timeTableFix)经 git submodule 构建期集成(非 iframe),详见 [`docs/submodule-timeTableFix.md`](./docs/submodule-timeTableFix.md)。 ## Ubuntu 从 0 安装 @@ -102,32 +80,7 @@ RewriteRule ^ - [L] RewriteRule ^ index.html [L] ``` -把 `/root/html`(或 `/var/www/html`)设为 `DocumentRoot`,访问站点即可。开发预览用 `npm run dev`(http://localhost:5173)。 - -## 如何新增一个项目页签 - -1. 复制 `src/modules/whiteboard/`(或 `mobile-game/`)为 `src/modules/<新项目>/`。 -2. 改 `<新项目>/index.js` 的 `id` / `tabKey` / `order` / `component`。 -3. 在 `src/i18n/locales/zh-CN.js` 与 `en.js` 的 `tabs` 下加对应文案。 -4. `npm run build` -- 页签与路由自动出现,无需改导航或路由代码。 - -## 子项目 timeTableFix 的升级 - -timeTableFix 作为 git submodule 独立维护,升级流程: - -```bash -cd mainPage -git submodule update --remote third_party/timeTableFix # 拉取最新 -cd third_party/timeTableFix && git checkout master # 固定到目标分支/commit -cd ../.. -git add third_party/timeTableFix # 更新 gitlink 指针 -git commit -m "chore: 升级 timeTableFix 子模块" -npm run build # 重新构建 mainPage -``` - -timeTableFix 本身完全独立,可单独 `npm run build` / `npm test`,也可经 Apache `/ttf/` 反代单独访问。 - ---- +把 `/root/html`(或 `/var/www/html`)设为 `DocumentRoot`,访问站点即可。 ## 开发命令 @@ -137,3 +90,9 @@ npm run dev # 开发服务器 http://localhost:5173 npm run build # 构建到 /root/html npm run preview # 本地预览构建产物 ``` + +## 了解更多 + +- [架构(模块注册 / PageShell / KeepAlive / 存活校验)](./docs/architecture.md) +- [如何新增一个项目页签](./docs/add-module.md) +- [子项目 timeTableFix 管理(submodule 升级 / 移除)](./docs/submodule-timeTableFix.md) diff --git a/docs/add-module.md b/docs/add-module.md new file mode 100644 index 0000000..43de715 --- /dev/null +++ b/docs/add-module.md @@ -0,0 +1,112 @@ +# 新增一个项目页签 + +新增页签 = 新建 `src/modules/<新项目>/` 文件夹,无需改动导航或路由代码。注册表自动收集并生成页签与路由。 + +## 步骤 + +### 1. 建模块文件夹与元数据 + +复制 `src/modules/timetable/`(最简范式)或 `whiteboard/`(带存活校验)为 `src/modules/<新项目>/`。 + +`index.js` 默认导出元数据(字段含义见 [architecture.md](./architecture.md#模块注册表扩展点核心)): + +```js +export default { + id: 'my-project', // 必填:唯一标识,同时作路由 path / KeepAlive 匹配名 + tabKey: 'tabs.myProject', // 必填:i18n 键 + order: 4, // 可选:页签排序,缺省 999 + component: () => import('./MyProject.vue') // 必填:懒加载组件 +} +``` + +### 2. 实现组件,用 PageShell 包裹 + +组件内 `defineOptions({ name: })`(KeepAlive 匹配用),并用 `` 统一容器宽度与标题: + +```vue + + + +``` + +PageShell props: +- `titleKey`:i18n 键,渲染页面标题;不传则无标题 +- `fluid`:true 突破 1080px 全宽(如日历页) +- `padded`:false 去掉默认上下间距(页面自管布局时用) +- `#actions` 具名插槽:标题旁的操作区(如白板切换表单) + +### 3. 加 i18n 文案 + +在 `src/i18n/locales/zh-CN.js` 与 `en.js` 的 `tabs` 下加对应文案: + +```js +tabs: { + // ... + myProject: '我的项目', // zh-CN + myProject: 'My Project', // en +} +``` + +### 4. 构建 + +```bash +npm run build +``` + +页签与路由自动出现。 + +## 常见变体 + +### 隐藏页签(仅 URL 访问) + +```js +export default { id: 'secret', tabKey: 'tabs.secret', order: 99, hidden: true, component: () => import('./Secret.vue') } +``` + +`hidden: true` 的页签不在导航显示,但 URL 访问后保持可见(访问过的隐藏页签不会因切走而消失)。 + +### 依赖外部服务存活(挂掉则隐藏并卸载) + +```js +import { healthUrl } from '../../config/app.config.js' +export default { + id: 'my-service', tabKey: 'tabs.myService', order: 5, + requiresAlive: 'https://example.com/health', // 存活探针 URL + component: () => import('./MyService.vue') +} +``` + +服务失活时页签隐藏、组件卸载;恢复后自动重新加载。详见 [architecture.md](./architecture.md#存活校验requiresalive)。 + +### 路由参数(如 /my-project/:id) + +```js +export default { id: 'my-project', tabKey: 'tabs.myProject', order: 4, param: 'itemId', component: () => import('./MyProject.vue') } +``` + +生成路由 `//:?`,组件内用 `useRoute().params.` 读取。 + +### 集成独立子项目(git submodule) + +参照 `timetable` 模块:建 mainPage 侧包装器组件 import 子项目 `App.vue`,套 `PageShell`,包装器持有 `defineOptions({ name })`。子项目保持纯净。详见 [submodule-timeTableFix.md](./submodule-timeTableFix.md)。 + +## 元数据字段速查 + +| 字段 | 必填 | 说明 | +|------|------|------| +| `id` | 是 | 唯一标识,路由 path / KeepAlive 匹配名 | +| `tabKey` | 是 | i18n 键,页签与页面标题 | +| `component` | 是 | 懒加载组件函数 | +| `order` | 否 | 排序,缺省 999 | +| `hidden` | 否 | 隐藏页签,URL 访问后保持可见 | +| `requiresAlive` | 否 | 存活探针 URL,失活则隐藏并卸载 | +| `param` | 否 | 路由参数名,生成 `/:?` | diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..8525bd9 --- /dev/null +++ b/docs/architecture.md @@ -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', // 可选:路由参数名,生成 //:? 子路径 +} +``` + +### 元数据字段 -> 消费方矩阵 + +| 字段 | 注册表 | router | useProjects | App.vue | TabNav | +|------|--------|--------|-------------|---------|--------| +| `id` | 必填校验 | path+name+meta.moduleId | visited 集合 / 路由关联 | keepInclude 名单 | `:to` + `:key` | +| `tabKey` | 必填校验 | - | - | - | 标题文案 | +| `component` | 必填校验 | 路由 component | - | RouterView 渲染 | - | +| `order` | 排序 | 决定 `/` 重定向目标 | 继承顺序 | - | 继承顺序 | +| `hidden` | 透传 | - | 可见性门控 | - | - | +| `requiresAlive` | 透传 | - | 可见性门控 | keepInclude + startPolling | - | +| `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 文案,渲染为 `

` +- **操作区**:`#actions` 具名插槽,放在标题旁(如白板的切换白板表单) + +各模块根组件用 `` 包裹内容,不再各写一套 `.container`/标题/间距。新增页签照此复用。 + +## KeepAlive 缓存与卸载 + +`App.vue` 用 `` 包裹路由组件,切换页签不卸载(状态保留)。 + +- `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 = `/` + 可选 `/:?`。history 模式,需站点根 `.htaccess` 做 SPA 回退(见 README 安装步骤)。 + +## 国际化 + +`src/i18n/` -- 中文同步注入主 chunk(默认语言),英文通过动态 `import()` 懒加载成独立 chunk,只看中文的访客不会下载英文资源。各模块 `tabKey` 指向 `tabs.*` 下的文案。 + +## 集中配置 + +`src/config/app.config.js` -- 外部服务 URL(白板地址、存活探针路径等)集中管理,模块按需 import。改 URL 只改这里(需重新 build)。 diff --git a/docs/submodule-timeTableFix.md b/docs/submodule-timeTableFix.md new file mode 100644 index 0000000..505da9e --- /dev/null +++ b/docs/submodule-timeTableFix.md @@ -0,0 +1,59 @@ +# 子项目 timeTableFix(git submodule) + +timeTableFix(ICS 日程整理器)作为 **git submodule** 被 mainPage 引入,位于 `third_party/timeTableFix`,独立仓库为 https://git.zikai.wang/zikai/timeTableFix.git 。 + +## 集成方式 + +mainPage 侧的 `src/modules/timetable/Timetable.vue` 包装器 import 子模块的 `src/App.vue` 作为组件,套 `PageShell` 统一容器与标题,并持有 KeepAlive 匹配名 `defineOptions({ name: 'timetable' })`。 + +- 子模块 `App.vue` 保持纯净(不持 name、不依赖宿主),可独立 `npm run build` / `npm test` / 部署。 +- 构建期集成(非 iframe),共享 mainPage 的构建、依赖(`ical.js`)与 KeepAlive 缓存。 +- 子模块样式已隔离(scoped + `ttf-` 前缀类名),全局重置仅在独立 app 的 `main.js` 加载,不污染宿主。 + +## 克隆(含子模块) + +```bash +git clone --recursive https://git.zikai.wang/zikai/zMainPage.git mainPage +``` + +若已 clone 但未带子模块: + +```bash +cd mainPage +git submodule update --init --recursive +``` + +## 升级子模块到最新版本 + +```bash +cd mainPage +git submodule update --remote third_party/timeTableFix # 拉取最新 +cd third_party/timeTableFix && git checkout master # 固定到目标分支/commit +cd ../.. +git add third_party/timeTableFix # 更新 gitlink 指针 +git commit -m "chore: 升级 timeTableFix 子模块" +npm run build # 重新构建 mainPage +git push # 推送 mainPage(gitlink) +``` + +> 推送顺序:先确保子模块的 commit 已推到 timeTableFix.git,再推 mainPage 的 gitlink,否则别人 clone mainPage 时拉不到子模块对应 commit。 + +## 移除子模块集成(仅移除 mainPage 页签,不影响 timeTableFix 本身) + +```bash +cd mainPage +git submodule deinit -f third_party/timeTableFix +git rm third_party/timeTableFix +git commit -m "chore: 移除 timeTableFix 子模块集成" +``` + +同时删 `src/modules/timetable/` 文件夹即移除页签。timeTableFix 独立仓库与部署不受影响。 + +## 独立访问 + +timeTableFix 独立 app 可经 Apache `/ttf/` 反代单独访问(`https://zikai.wang/ttf/`),与 mainPage 组件集成互不冲突。反代配置: + +```apache +ProxyPass /ttf/ http://127.0.0.1:8888/ +ProxyPassReverse /ttf/ http://127.0.0.1:8888/ +```