Files
sub2api/docs/superpowers/work-logs/2026-04-23-portal-frontend-revamp.md
mini 92ffcb81e4
Some checks failed
continuous-integration/drone/push Build is passing
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
docs(work-log): 门户前端调整工作记录(多语言 + Pricing + Nav 重构 + 内容清理)
2026-05-03 00:00:36 +08:00

166 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 门户前端调整工作记录
**时间窗口**2026-04-19 2026-04-23
**范围**sub2api 项目前端门户页(公开访问的 5 页Landing / Docs / Login / Register / Pricing
**目标**:完成多语言切换、新增 Pricing 页、消除导航栏抖动、清理对外不应展示的技术细节
---
## 阶段一:门户多语言 + Pricing 页
**问题**:门户 4 页Landing / Docs / Login-narrative / Register-narrative当时是 fidelity-port 自 Claude Design zip 的,约 100+ 处中文硬编码在 template 里。Pricing 页未实现。i18n 框架(`vue-i18n`)虽然到位,但门户页基本没用上。
**做了什么**
1. 新建 `components/puro/PuroLocaleSwitcher.vue` —— 深色科技风的语言切换器,复用 `setLocale()` 核心,与 puro.css 设计 token 对齐(区别于 admin 用的 `LocaleSwitcher.vue`
2. 抽取 4 页所有中文到 i18n key`landing.*``docs.*``auth.narrative.*` 命名空间),同步生成英文翻译;总计约 130 个 leaf key
3. 新增 `/pricing` 路由 + `views/pricing/PricingView.vue`(约 500 行)+ `components/puro/PricingCalculator.vue` 子组件
4. Pricing 页从一开始就 i18n-native约 100 个 key含 4 档定价 tier、cost calculator、12 工具 grid、10 FAQ、final CTA
5. 关键决策(写进 spec 锁定):
- 定价数字使用 zip 的 `$9.9 / $29.9 / $99` 作为占位,配 `// preview · 最终定价以开售为准` 标签
- 未实现的功能priority scheduling、zero-log mode`SOON` 灰标签,不删除展示
- Binding 卡片暂指 `/register`;联系商务用 `mailto:contact@puro.im`
- Cost calculator 算法照搬 zip JS`puro = official × 0.3`),配 `// estimated · 以实际计费为准` 标签
- 移除 zip 中的 `注册送 $5 测试积分` 文案Stage 1 决策)
**执行方式**subagent-driven-developmentPlan 文件 `docs/superpowers/plans/2026-04-20-portal-i18n-pricing.md`10 个任务3 个 subagent 实现 + 1 次回归修复)
**已合并 PR**#2 → main `77bb69b2`
---
## 阶段二Nav 抖动修复
**问题**:用户报告点击导航栏「产品/定价/文档」切换时元素位置发生轻微抖动。
**根因分析**
第一直觉是 active class 引起的字体 weight 变化。grep CSS 后发现并非如此 —— `.active` 只改 color 不影响布局。
真正原因是:当前 Landing/Docs/Pricing 三个 View **各自在 template 里写了一份完整的 nav**包括按钮文案。Vue Router 切换路由时销毁整棵 view 组件树(含 nav重新挂载下一个。虽然视觉上"看似同一个 nav",实际是三份独立拷贝被替换。
进一步发现两份拷贝间有差异:
- Docs 的注册 CTA 文案是 `注册`2 字符Landing/Pricing 是 `免费试用 →`5+1 字符)—— 按钮宽度不同
- Docs 的英文 `Product`单数vs 其他两页的 `Products`(复数)
- Pricing 的「定价」用 `<a href="#" class="active">` —— 点击会 scroll to top 且 URL 改成 `/pricing#`
**做了什么**(分两步):
**步骤 1短期** —— 文案统一:把三份 nav 的内容对齐到完全一致
- `docs.nav.signup`: `注册``免费试用 →`
- `docs.nav.products` (en): `Product``Products`
- PricingView 的 `<a href="#">``<router-link to="/pricing">`
- commit `779005e1`
**步骤 2结构性修复** —— 抽 `PortalLayout`
- 新建 `components/layout/PortalLayout.vue` —— 包含 nav + `<router-view />` + footer
- 路由改为嵌套结构:`/``/docs``/pricing` 作为 PortalLayout 的子路由
- 三个 View 删掉各自的 nav / footer / `bg-glow` / `.puro-page` 包装
- 新增 `portal.nav.*` i18n 命名空间,删除原来的 `landing.nav.*` / `docs.nav.*` / `pricing.nav.*` 三份重复
- `router-link``active-class="active"` prop 替代硬编码 class
- `scrollBehavior` 加上 hash 锚点跳转(`offset 80px` 绕 sticky nav
- commit `e7f3fe5b`
**结果**:路由切换时 Nav 不再卸载重挂真·SPA 行为。
**已合并 PR**#3 → main `291e3bfe`
---
## 阶段三:对外内容清理
**Pass 1删除 iShare 引用**
- 用户要求:项目目前定位是独立运营,不要在前端展示 iShare 相关字样
- 影响:`docs.sections.getKey.note` 一个 key"未来通过 iShare 入口开放订阅购买"+ DocsView 对应的 `<p class="note">`
- commit `623a7518`PR #4 → main `5c4b2980`
**Pass 2移除 footer 技术细节**
- 用户要求:不要透露项目技术开发细节
- 删除:`更新日志` 链接(指向 Gitea commits`git.puro.im` 链接、`GitHub ↗` 链接、`fork of Wei-Shaw/sub2api` 字样
- footer-meta 简化为 `© 2026 puro.im`
- 同步删除 `linkChangelog` i18n key
- commit `2b6b5fc6`PR #5 → main `8be87883`
---
## 关键文件清单
新增:
- `frontend/src/components/puro/PuroLocaleSwitcher.vue`
- `frontend/src/components/puro/PricingCalculator.vue`
- `frontend/src/components/layout/PortalLayout.vue`
- `frontend/src/views/pricing/PricingView.vue`
修改(重点):
- `frontend/src/router/index.ts` —— 加 `/pricing`、嵌套路由、scrollBehavior
- `frontend/src/i18n/locales/{zh,en}.ts` —— 新增 portal/landing/docs/pricing/auth.narrative 命名空间
- `frontend/src/views/{landing,docs,pricing}/*View.vue` —— 全量 i18n 化 + 移除各自 nav/footer
- `frontend/src/views/auth/{Login,Register}View.vue` —— narrative slot i18n 化
- `frontend/src/components/layout/AuthLayout.vue` —— 添加右上角语言切换器槽位
---
## commit / PR 索引
| 阶段 | commit | 描述 |
|---|---|---|
| 一 | `e711a203` | feat(i18n): add PuroLocaleSwitcher |
| 一 | `63288818` | mount switcher in Landing/Docs/AuthLayout |
| 一 | `fc7e2767` | landing i18n keys + EN |
| 一 | `73b39807` | docs + auth narrative i18n |
| 一 | `13bdd8f8` | restore dashboard link in models.note |
| 一 | `b989c503` | PricingView + calculator |
| 一 | `77bb69b2` | **Merge PR #2** → main |
| 二 | `779005e1` | unify signup CTA |
| 二 | `e7f3fe5b` | extract PortalLayout |
| 二 | `291e3bfe` | **Merge PR #3** → main |
| 三 | `623a7518` | remove iShare mention |
| 三 | `5c4b2980` | **Merge PR #4** → main |
| 三 | `2b6b5fc6` | footer remove tech details |
| 三 | `8be87883` | **Merge PR #5** → main |
---
## 部署链路
每次 merge 到 main 后:
1. Gitea webhook 触发 Drone CI
2. Drone 运行 docker build + 推镜像
3. VPS 上 docker compose 拉取新镜像 + 重启
4. 总耗时约 35 分钟
每次部署完成的验证手段curl
1.`https://ai.puro.im/` 主 HTML对比 `/assets/index-*.js` 文件名 hash 是否变化Vite 内容寻址)
2. fetch 新 chunk grep 关键字符串确认新代码上线
3. 5 个门户路由全部 200
---
## 遗留事项 / 下次可继续
**门户层面**
1. 浏览器实测 nav 持久化无抖动(用户已确认部署,肉眼验证待做)
2. 翻译效果打磨(用户浏览后发现的不自然处随时改)
3. Pricing 数字 / 功能列表定稿(从 preview 转正式)
4. 后端 `SOON` 标记的功能落地zero-log mode、priority scheduling
5. Pricing FAQ 中的 24 小时上线新模型 等承诺类文案核实
**Admin / User 页面(之前搁置的两个决策)**
- 决策 1Admin reskin 深度A 全局换肤 / B 深度 port 两页 / C 全量重写)
- 决策 2User-facing 页面 vs Admin 页面优先级
- 推荐路径Phase 2.1 全局换肤 → 2.2 user pages → 2.3 admin pages
**仓库卫生**
- `backend/config.prod.yaml``backend/sub2api-linux``LOCAL_SETUP_NOTES.md` 在某次意外的 `git add -A` 中被提交到 main。
- 用户判断:因 Gitea 是私有的,先不处理;仅要求前端层面不展示敏感信息(已通过 footer 清理实现)。
- 建议:下次添加配置 / 二进制类文件前,往 `.gitignore` 补规则(`backend/config.*.yaml``backend/sub2api-*` 等),避免再次误提。
---
## 经验教训
1. **不要 `git add -A`** —— 主 worktree 里有累积的本地文件(生产配置、二进制、笔记),一次性 stage 会把这些都带进 commit。后续都用 `git add <具体文件>`
2. **设计稿里的 nav = 3 份独立 HTML** ≠ Vue 应该 3 份独立 template —— port 设计稿到 SPA 时要把跨页共享的部分nav、footer、layout shell一开始就抽到 layout 组件。
3. **Subagent 报告"我做完了"≠ 真的做对了** —— `73b39807` 提交里 subagent 静默删掉了 `<router-link>` 退化成纯文本。事后 grep 读 commit diff 才发现。下次 subagent 处理 i18n 抽取时prompt 里要明确"原始 HTML 标签如 `<a>`/`<code>`/`<router-link>` 必须保留,使用 `<i18n-t>` 命名 slot"。
4. **fidelity port 优先靠 `<i18n-t>` + 命名 slot不要把带行内标签的句子拍平成纯文本** —— 这点已经写进下次的 i18n 提示模板中。