diff --git a/docs/deployment.md b/docs/deployment.md index 446d84a..f034f84 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -8,16 +8,15 @@ zPDF_package 功能涉及三个项目协同:**zMainPage**(父站,Vue3 静 浏览器 -> Apache(:80) ├── 静态文件 /var/www/html (zMainPage 构建产物:主页 + 页签) └── 反代 /api/ -> zTools2(127.0.0.1:6867) - ├── /api/pdf PDF 转换页面(iframe 嵌入源) ├── /api/pdf/* PDF 转换 API(cookie 用户) ├── /api/pdf-admin PDF 管理页(Basic Auth) ├── /api/static/pdf* 前端静态资源 └── MySQL(3306) + uploads/ ``` -PDF 页签 = zMainPage 用 iframe 嵌入 zTools2 的 `/api/pdf` 页面(**同源相对路径**,cookie 第一方生效,与环境无关)。 +PDF 页签 = zMainPage 构建期 import zPDF_package 的 `App.vue` 作为组件(非 iframe),经同源 fetch 调用 zTools2 的 `/api/pdf/*` REST API(**同源相对路径**,cookie 第一方生效,与环境无关)。 -> **路由约定**:zTools2 所有入口(页面 / 静态 / 探针 / WS / API)统一挂在 `/api/` 下,反代与 vite proxy 只需一条 `/api/` 规则。前端 iframe 与 fetch 一律用同源相对路径(`/api/pdf`、`/api/health` 等),自动指向**当前环境**的 zTools2,无需区分 dev/prod,也不会误打到其它环境域名。详见 zTools2 README「路由约定」。 +> **路由约定**:zTools2 所有入口(页面 / 静态 / 探针 / WS / API)统一挂在 `/api/` 下,反代与 vite proxy 只需一条 `/api/` 规则。前端(无论是 iframe 嵌入页还是组件 fetch API)一律用同源相对路径(`/api/pdf/jobs`、`/api/health` 等),自动指向**当前环境**的 zTools2,无需区分 dev/prod,也不会误打到其它环境域名。详见 zTools2 README「路由约定」。 --- @@ -34,7 +33,9 @@ cd zTools2 # 或:python -m uvicorn app.main:app --host 127.0.0.1 --port 6867 ``` -访问:http://127.0.0.1:6867/api/pdf(PDF 页面)、http://127.0.0.1:6867/docs(API 文档)。 +访问:http://127.0.0.1:6867/api/pdf-admin(PDF 管理页)、http://127.0.0.1:6867/docs(API 文档)。 + +> 用户侧 PDF 页面由 zMainPage 的 zPDF_package 组件提供(构建期 import),zTools2 仅提供 `/api/pdf/*` REST API 与 `/api/pdf-admin` 管理页。 ### 2. zPDF_package 前端独立运行 @@ -57,7 +58,7 @@ npm install npm run dev # http://localhost:5173 ``` -> 独立模式下 PDF 页签的 iframe 用同源相对路径 `/api/pdf`,经 vite proxy 转发到本地 zTools2(127.0.0.1:6867)。如需指向其它环境的 zTools2,改 `src/config/app.config.js` 的 `pdf.baseUrl` 为该环境地址(含协议与域名)后重新 `npm run dev`,或设 `VITE_API_BASE` 环境变量。 +> 独立模式下 PDF 页签的 zPDF_package 组件经同源相对路径 `/api/pdf/*` 调用 zTools2,经 vite proxy 转发到本地 zTools2(127.0.0.1:6867)。如需指向其它环境的 zTools2,改 `src/config/app.config.js` 的 `pdf.baseUrl` 为该环境地址(含协议与域名)后重新 `npm run dev`,或设 `VITE_API_BASE` 环境变量。 --- @@ -77,7 +78,7 @@ cd zMainPage 3. 配置 Apache vhost(`/etc/apache2/sites-available/zmainpage.conf`)反代 `/api/` 到 `127.0.0.1:6867`(含 WebSocket,靠 proxy_wstunnel 透传 `/api/ws`) 4. 重启 zTools2(除非 `--no-restart`) -部署后访问 http://localhost/ 即主页,PDF 页签 iframe 同源加载 `/api/pdf`。 +部署后访问 http://localhost/ 即主页,PDF 页签渲染 zPDF_package 组件并经同源 fetch 调用 `/api/pdf/*`。 > 已有 HTTPS vhost 时:`deploy.sh` 不会覆盖(仅首次写入)。手动在现有 vhost 加 `ProxyPass /api/ http://127.0.0.1:6867/api/` 一条规则即可(需 `a2enmod proxy_wstunnel` 以支持 WebSocket)。 diff --git a/docs/submodule-zPDF_package.md b/docs/submodule-zPDF_package.md index a5b7738..50a6a16 100644 --- a/docs/submodule-zPDF_package.md +++ b/docs/submodule-zPDF_package.md @@ -4,11 +4,13 @@ zPDF_package(PDF 转换前端)作为 **git submodule** 被 mainPage 引入 ## 集成方式 -mainPage 侧的 `src/modules/pdf/Pdf.vue` 用 **iframe** 嵌入 zTools2 托管的 `/pdf` 页面(`https://f.zikai.wang/pdf`),套 `PageShell` 统一容器与标题,并持有 KeepAlive 匹配名 `defineOptions({ name: 'pdf' })`。 +mainPage 侧的 `src/modules/pdf/Pdf.vue` 包装器 import 子模块的 `src/App.vue` 作为组件,套 `PageShell` 统一容器与标题,并持有 KeepAlive 匹配名 `defineOptions({ name: 'pdf' })`。 -- **iframe 同源嵌入**(非组件 import):PDF 转换有后端依赖(zTools2 的 `/api/pdf/*`),iframe 嵌入使页面与 API 同源(均在 `f.zikai.wang`),用户 cookie(`zk_pdf`)第一方自然生效,无需给 zTools2 加 CORS,不受第三方 cookie 限制。与白板页签的嵌入方式一致。 -- 页签带 `requiresAlive: healthUrl('pdf')`,zTools2 不可达时隐藏页签并卸载组件;直链进入则显示降级提示与「在新标签页打开」。 -- zPDF_package 源码作为 submodule 管理,其 `npm run build` 产物部署到 zTools2 托管。mainPage 构建不编译子模块(iframe 集成,非构建期组件集成)。 +- 子模块 `App.vue` 保持纯净(不持 name、不依赖宿主),可独立 `npm run build` / `npm test` / 部署。 +- **构建期集成(非 iframe)**,共享 mainPage 的构建与 KeepAlive 缓存。前后端分离:UI/交互在 zPDF_package,能力由 zTools2 的 `/api/pdf/*` REST API 提供。 +- 子模块样式已隔离(scoped + `zpdf-` 前缀类名),全局重置仅在独立 app 的 `main.js` 加载,不污染宿主。 +- 页签带 `requiresAlive: healthUrl('pdf')`,zTools2 不可达时隐藏页签并卸载组件。 +- **认证**:用户身份凭 httpOnly cookie(`zk_pdf`,samesite=lax)标识。该 cookie 在首次 `POST /api/pdf/jobs`(上传)的响应里种下,与页面路由无关。组件经同源 fetch 调用 `/api/pdf/*`,反代使 `/api/` 与主页同源,cookie 自动携带,无需 CORS。 ## 克隆(含子模块) @@ -36,7 +38,7 @@ npm run build # 重新构建 main git push # 推送 mainPage(gitlink) ``` -> 推送顺序:先确保子模块的 commit 已推到 zPDF_package.git,再推 mainPage 的 gitlink。 +> 推送顺序:先确保子模块的 commit 已推到 zPDF_package.git,再推 mainPage 的 gitlink,否则别人 clone mainPage 时拉不到子模块对应 commit。 ## 移除子模块集成(仅移除 mainPage 页签,不影响 zPDF_package 本身) @@ -53,10 +55,10 @@ git commit -m "chore: 移除 zPDF_package 子模块集成" | 维度 | timeTableFix / z449 | zPDF_package | |------|---------------------|--------------| -| 集成方式 | 构建期组件 import(共享构建/KeepAlive) | iframe 嵌入 zTools2 托管页 | +| 集成方式 | 构建期组件 import(共享构建/KeepAlive) | 构建期组件 import(共享构建/KeepAlive) | | 后端依赖 | 无(纯前端) | 有(zTools2 `/api/pdf/*`) | -| 同源/CORS | 不涉及 | 同源(f.zikai.wang),无需 CORS | -| cookie | 不涉及 | 第一方 httpOnly cookie 自然生效 | -| mainPage 是否编译子模块 | 是(import .vue) | 否(iframe) | +| 同源/CORS | 不涉及 | 同源经反代,无需 CORS | +| cookie | 不涉及 | httpOnly `zk_pdf`,同源自动携带(首次上传种下) | +| mainPage 是否编译子模块 | 是(import .vue) | 是(import .vue) | -> zPDF_package 仍作为 submodule 管理源码,便于独立开发/测试/升级;其构建产物部署到 zTools2,mainPage 经 iframe 引用 zTools2 的 `/pdf`。 +> 三个子项目(timeTableFix / z449 / zPDF_package)均采用构建期组件 import 集成,无 iframe。zPDF_package 额外依赖 zTools2 后端 API,页签带存活探针。 diff --git a/src/config/app.config.js b/src/config/app.config.js index e2e00aa..6ab7d7f 100644 --- a/src/config/app.config.js +++ b/src/config/app.config.js @@ -2,8 +2,8 @@ // 模块按需 import { appConfig } 使用,改 URL 只改这里即可(需重新 build)。 // 每个服务项都带默认值,避免缺失字段导致渲染崩溃。 // -// 路由约定:zTools2 所有入口(页面/静态/探针/WS/API)统一挂在 /api/ 下, -// iframe 与 fetch 一律用**同源相对路径**(/api/pdf、/api/health 等)。 +// 路由约定:zTools2 所有入口(API/静态/探针/WS)统一挂在 /api/ 下, +// fetch 与探针一律用**同源相对路径**(/api/pdf/jobs、/api/health 等)。 // 无论是 vite dev(server.proxy 转发 /api 到本地 zTools2)、还是任意部署环境 // (Apache/Nginx 反代 /api 到当前环境的 zTools2),同源相对路径都自动指向 // **当前环境**的服务,无需区分 dev/prod,也不会误打到其它环境域名。 @@ -26,14 +26,12 @@ export const appConfig = { // 探测超时(毫秒) healthTimeoutMs: 4000 }, - // PDF 转换服务(zTools2 托管的 /api/pdf 页面,iframe 同源嵌入) + // PDF 转换服务(zTools2 提供 /api/pdf/* REST API;zPDF_package 组件同源 fetch 调用) pdf: { // 服务根地址(含协议与域名);默认空串 = 同源相对路径 baseUrl: BASE_URL, // 存活探针路径;周期探测,挂掉则隐藏页签并卸载组件 healthPath: '/api/health', - // PDF 转换页面路径 - pagePath: '/api/pdf', // 探测超时(毫秒) healthTimeoutMs: 4000 } diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index db6586a..446faae 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -20,10 +20,8 @@ export default { openExternal: 'Open in new tab', boardId: 'Board ID', switch: 'Switch' - }, - pdf: { - openExternal: 'Open in new tab' } // Mobile-game copy is provided by the z449 submodule's own i18n; // mainPage keeps only tabs.mobileGame. Locale syncs to z449 via :locale prop. + // PDF tab copy is provided by the zPDF_package submodule's own i18n; mainPage keeps only tabs.pdf. } diff --git a/src/i18n/locales/zh-CN.js b/src/i18n/locales/zh-CN.js index a9ef496..f73359b 100644 --- a/src/i18n/locales/zh-CN.js +++ b/src/i18n/locales/zh-CN.js @@ -19,10 +19,8 @@ export default { openExternal: '在新标签页打开', boardId: '白板 ID', switch: '切换' - }, - pdf: { - openExternal: '在新标签页打开' } // 注:移动游戏项目(mobile-game)的文案由子模块 z449 自有 i18n 提供, // mainPage 仅保留 tabs.mobileGame 页签标题。切换语言时经 :locale prop 同步给 z449。 + // PDF 转换页签的文案由子模块 zPDF_package 自有 i18n 提供,mainPage 仅保留 tabs.pdf。 } diff --git a/src/modules/pdf/Pdf.vue b/src/modules/pdf/Pdf.vue index 71c7c0c..b1f9154 100644 --- a/src/modules/pdf/Pdf.vue +++ b/src/modules/pdf/Pdf.vue @@ -1,138 +1,47 @@