From baa355fa8ba02438158f912e4d73dc7d931de6a6 Mon Sep 17 00:00:00 2001 From: wdh-home <243823965@qq.com> Date: Thu, 23 Apr 2026 21:46:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-04-22-profile-page-static-design.md | 213 -- ...3-frontend-static-page-migration-design.md | 255 --- ...atic-page-migration-implementation-plan.md | 1744 ----------------- AGENTS.md | 4 +- 4 files changed, 1 insertion(+), 2215 deletions(-) delete mode 100644 .ai-specs/coding-specs/2026-04-22-profile-page-static-design.md delete mode 100644 .ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-design.md delete mode 100644 .ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-implementation-plan.md diff --git a/.ai-specs/coding-specs/2026-04-22-profile-page-static-design.md b/.ai-specs/coding-specs/2026-04-22-profile-page-static-design.md deleted file mode 100644 index 586e17a..0000000 --- a/.ai-specs/coding-specs/2026-04-22-profile-page-static-design.md +++ /dev/null @@ -1,213 +0,0 @@ -# `pages/profile/index` 未登录态静态页面设计 - -## 文档元信息 - -- 日期:`2026-04-22` -- 目标页面:`pages/profile/index` -- 设计范围:`结构复刻 + 纯静态展示 + 未登录态` -- 关联文档:`AGENTS.md`、`README.md` - -## 目标 - -在不引入接口、store、页面跳转和新增组件的前提下,将 `pages/profile/index` 从占位页升级为一个可直接展示的个人中心静态页面。页面目标是复刻参考图的区块结构和信息层级,同时沿用仓库现有暖色、卡片化视觉语言,避免做截图级像素还原。 - -## 范围与非目标 - -### 本次范围 - -- 仅修改 `pages/profile/index.js`、`pages/profile/index.wxml`、`pages/profile/index.wxss` -- 页面首屏固定为未登录态 -- 页面包含 5 个区块:用户卡片、会员引导卡片、学习资产四宫格、最近记录空状态、其它功能列表 -- 页面内容使用静态 `data` 驱动 -- 按微信原生小程序常规写法实现,不新增通用组件 - -### 非目标 - -- 不接入 `stores/modules/session.js` -- 不调用 `services/api/*` 或 `services/request/index.js` -- 不新增图标图片资源、不新增字体资源 -- 不接按钮点击、页面跳转、分享能力、登录能力 -- 不处理已登录态、真实记录列表、真实资产计数 - -## 方案选择 - -### 备选方案 - -1. 页面内一次性落地 -2. 先抽资产区和列表行为局部组件 -3. 强行复用现有 `components/base/app-button` 与 `components/biz/entry-card` - -### 最终选择 - -采用“页面内一次性落地”方案。 - -选择原因: - -- 当前目标是静态结构复刻,范围小,直接写在页面内更短更稳 -- 现有组件与目标结构不贴合,强复用会增加样式扭曲和模板复杂度 -- 通过结构化 `data` 和分区 class 命名,后续仍可平滑抽组件,不会锁死实现 - -## 页面结构 - -页面按纵向信息流组织,顺序固定如下: - -1. 用户卡片 -2. 会员引导卡片 -3. 学习资产四宫格 -4. 最近记录 -5. 其它功能 - -各区块关系如下: - -```mermaid -flowchart TD - PAGE["profile-page 页面根容器"] --> USER["用户卡片
头像占位 / 登录文案 / 设置入口占位"] - PAGE --> VIP["会员引导卡片
图标占位 / 说明文案 / CTA 按钮占位"] - PAGE --> ASSET["学习资产四宫格
我的笔记 / 我的书架 / 我的收藏 / 浏览历史"] - PAGE --> RECENT["最近记录卡片
标题 + 空状态文案"] - PAGE --> MORE["其它功能列表
意见反馈 / 分享 APP / 关于我们 / 设置"] -``` - -## 数据模型 - -页面 `data` 只承载静态展示信息,建议按 5 组对象/数组组织: - -```js -{ - userCard: { - avatarText: '?', - title: '点击登录', - subtitle: '登录后查看你的学习资产', - settingsText: '设' - }, - vipCard: { - icon: '会员', - title: '开通会员', - subtitle: '解锁更多学习资料、AI 仪表与阅读辅助能力', - actionText: '成为会员' - }, - assetItems: [ - { key: 'notes', icon: '记', title: '我的笔记', count: 0 }, - { key: 'bookshelf', icon: '架', title: '我的书架', count: 0 }, - { key: 'favorites', icon: '藏', title: '我的收藏', count: 0 }, - { key: 'history', icon: '史', title: '浏览历史', count: 0 } - ], - recentRecord: { - title: '最近记录', - emptyTitle: '还没有回访记录', - emptyDescription: '去典籍阅读或 AI 页完成一次学习,记录会出现在这里。' - }, - moreItems: [ - { key: 'feedback', title: '意见反馈' }, - { key: 'share', title: '分享 APP' }, - { key: 'about', title: '关于我们' }, - { key: 'settings', title: '设置' } - ] -} -``` - -约束: - -- `assetItems` 和 `moreItems` 必须使用 `wx:for` -- `key` 只用于渲染稳定性和后续扩展,不在本次承担业务逻辑 -- 所有文本先静态写入 `data`,避免模板中散落魔法字符串 - -## WXML 结构边界 - -WXML 只保留三级边界: - -- 页面根:`profile-page` -- 区块卡片:`section-card` -- 区块内部局部结构:`profile-header`、`vip-banner`、`asset-grid`、`recent-panel`、`menu-list` - -结构要求: - -- 顶部用户卡片和会员卡片为独立卡片,不合并 -- 资产区一行固定 4 列,每项包含图标容器、标题、数字 -- 最近记录固定为空状态,不渲染列表分支 -- 其它功能为纵向列表,每一行使用“左文案 + 右箭头占位”的标准结构 - -## 样式策略 - -页面视觉遵循“结构复刻,风格贴合仓库”的原则。 - -### 页面级 - -- 延续当前项目已有的米白到浅金渐变背景 -- 保持主内容纵向滚动,顶部和底部有稳定安全边距 - -### 卡片级 - -- 统一使用浅底、圆角、大留白、轻阴影 -- 卡片间距与首页的 `section-card` 节奏接近 -- 避免复杂装饰、绝对定位角标和图片背景 - -### 文本级 - -- 区块标题延续首页的 `Songti` / serif 风格 -- 正文、副文案、数字采用更轻的系统字体层级 -- 用户卡片标题突出,辅助说明弱化 - -### 图标级 - -- 本次不新增图片资源 -- 头像、会员、四宫格图标、右箭头均用字符或简单容器占位 -- 图标容器风格统一,避免每块都出现不同视觉语言 - -## 行为与数据流 - -本页当前没有真实行为流,只保留静态展示结构。 - -```mermaid -flowchart LR - DATA["Page data 静态对象"] --> WXML["WXML 区块渲染"] - WXML --> WXSS["WXSS 卡片与布局样式"] - WXSS --> UI["未登录态个人中心静态页面"] -``` - -约束: - -- 不出现 `onLoad` 拉取数据逻辑 -- 不出现 `wx.navigateTo`、`wx.switchTab`、`wx.login`、`wx.getUserProfile` -- 不出现依赖外部状态的分支渲染 - -## 错误处理与边界 - -由于本次没有网络请求和真实交互,错误处理重点放在布局稳定性: - -- `assetItems` 固定为 4 项;若后续数量变化,需要单独评估布局是否仍保持 4 列 -- 文案长度以当前中文文案为基准,样式需避免一行被异常挤压 -- 图标占位必须在没有外部资源时也能稳定渲染 -- 页面在微信常规设备宽度下不能出现卡片溢出、四宫格换行错位、列表箭头挤压 - -## 测试与验收 - -本次设计对应的最小验证范围: - -1. 页面整体包含 5 个区块,顺序与设计一致 -2. 学习资产区稳定为一行 4 列 -3. 最近记录展示为空状态,不出现列表分支 -4. 其它功能区展示 4 行静态入口 -5. 改动范围仅限 `pages/profile/index.*`,不新增业务组件、不接 API / store - -若补测试,优先补: - -- 页面 `data` 结构渲染测试 -- 四宫格与功能列表项数量断言 -- 关键标题文案存在性断言 - -## 实施边界 - -实施顺序固定为: - -1. 重写 `pages/profile/index.js` 中的静态数据 -2. 重写 `pages/profile/index.wxml` 的区块结构 -3. 重写 `pages/profile/index.wxss` 的整体布局与卡片样式 -4. 回查 `app.json` 中 `pages/profile/index` 路由已存在,无需新增注册 - -禁止事项: - -- 不提前抽新组件 -- 不顺手接登录态 -- 不顺手接页面跳转 -- 不为“以后可能要用”增加额外抽象 diff --git a/.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-design.md b/.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-design.md deleted file mode 100644 index ade8e15..0000000 --- a/.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-design.md +++ /dev/null @@ -1,255 +0,0 @@ -# `frontend` 老项目静态页面迁移设计 - -## 文档元信息 - -- 日期:`2026-04-23` -- 目标仓库:`xuanzhi-wx` -- 参考来源:`D:\Code3\wdp\xuanzhi\frontend` -- 设计范围:`静态页面复刻 + 可点击导航 + 基础前端交互` -- 关联文档:`AGENTS.md`、`README.md`、`.ai-specs/coding-specs/2026-04-22-profile-page-static-design.md` - -## 目标 - -在不复刻旧项目接口、数据结构、状态管理、工程组织和业务逻辑的前提下,将 `frontend` 项目中的主要页面形态迁移到当前微信原生小程序仓库,形成一套: - -- 保持当前 `4 tab` 结构不变 -- 页面都能看得到并点得到 -- 只依赖静态 `data` 和页面内交互 -- 与当前项目目录职责一致 - -的静态 UI/UX 壳层。 - -## 范围与非目标 - -### 本次范围 - -- 完善现有主包页面:`pages/home/index`、`pages/library/index`、`pages/ai/index`、`pages/profile/index`、`pages/login/index` -- 新增分包页面: - - `packages/tcm/pages/*` - - `packages/mingli/pages/*` - - `packages/learning/pages/*` -- 补齐从主包 `tab` 页进入新增分包页的静态导航入口 -- 在页面内保留纯前端交互: - - 切换 - - 输入 - - 弹层 - - 抽屉 - - 静态结果展示 -- 新增纯静态数据与路由映射工具,服务页面渲染 - -### 非目标 - -- 不接入 `services/api/*` -- 不复用旧项目的 `services/*`、`stores/*`、`composables/*`、`utils/*workflow*` -- 不保留旧项目的 `bookId / recordId / passageId` 真实业务语义 -- 不实现真实登录、历史、搜索、收藏、书架、阅读进度、AI 回答、八字排盘 -- 不复制旧项目的页面目录命名和信息架构问题 -- 不新增底部 `tab` - -## 页面归属与路由设计 - -### 总体原则 - -- 主包继续承担 `tab` 与公共入口职责 -- 新增业务页优先进入分包 -- 已经存在的主包页面只做增强,不重复新建第二套首页或第二套我的页 - -### 主包保留页面 - -| 路由 | 角色 | 本次定位 | -|:---|:---|:---| -| `pages/home/index` | 首页 tab | 总入口页,承接中医域、易学域、学习中心入口 | -| `pages/library/index` | 典籍 tab | 保留中医书城主体,补易学阁入口 | -| `pages/ai/index` | AI tab | 保留中医 AI 主体,补命理解读和相关深入口 | -| `pages/profile/index` | 我的 tab | 复刻静态个人页,并补学习中心、资产、历史等入口 | -| `pages/login/index` | 登录页 | 改成纯静态登录展示页,不保留 mock 会话逻辑 | - -### 中医分包 - -| 路由 | 对应旧页 | 定位 | -|:---|:---|:---| -| `packages/tcm/pages/ai-history/index` | `src/pages/tcm/ai-history/index.vue` | AI 历史静态页 | -| `packages/tcm/pages/assets/index` | `src/pages/tcm/assets/index.vue` | 学习资产静态页 | -| `packages/tcm/pages/bianzheng/index` | `src/pages/tcm/bianzheng/index.vue` | 辨证分析静态页 | -| `packages/tcm/pages/book-detail/index` | `src/pages/tcm/book-detail/index.vue` | 典籍详情静态页 | -| `packages/tcm/pages/search-books/index` | `src/pages/tcm/search-books/index.vue` | 搜索静态页 | -| `packages/tcm/pages/section/index` | `src/pages/tcm/section/index.vue` | 阅读页静态壳 | -| `packages/tcm/pages/placeholder/index` | `src/pages/tcm/placeholder/index.vue` | 占位说明页 | - -### 易学分包 - -| 路由 | 对应旧页 | 定位 | -|:---|:---|:---| -| `packages/mingli/pages/hall/index` | `src/pages/mingli/books/index.vue` | 易学阁首页,重新命名为 `hall` | -| `packages/mingli/pages/bazi/index` | `src/pages/bazi/index.vue` | 八字排盘静态页 | -| `packages/mingli/pages/book-detail/index` | `src/pages/mingli/book-detail/index.vue` | 易学典籍详情静态页 | -| `packages/mingli/pages/search-books/index` | `src/pages/mingli/search-books/index.vue` | 易学搜索静态页 | -| `packages/mingli/pages/section/index` | `src/pages/mingli/section/index.vue` | 易学阅读静态页 | -| `packages/mingli/pages/interpret/index` | `src/pages/mingli/interpret/index.vue` | 命理解读静态页 | - -### 学习中心分包 - -| 路由 | 对应旧页 | 定位 | -|:---|:---|:---| -| `packages/learning/pages/center/index` | `src/pages/learning/index.vue` | 学习中心聚合页 | - -### 导航要求 - -- 保持当前 `4 tab` 不变 -- 所有新增页面必须能从现有可见入口进入 -- 页面间只保留静态跳转链路,不建立真实业务流 - -```mermaid -flowchart TD - HOME["pages/home/index"] --> TCM_BOOK_DETAIL["packages/tcm/pages/book-detail/index"] - HOME --> TCM_SECTION["packages/tcm/pages/section/index"] - HOME --> MINGLI_HALL["packages/mingli/pages/hall/index"] - HOME --> BAZI["packages/mingli/pages/bazi/index"] - HOME --> LEARNING["packages/learning/pages/center/index"] - - LIBRARY["pages/library/index"] --> TCM_SEARCH["packages/tcm/pages/search-books/index"] - LIBRARY --> MINGLI_HALL - - AI["pages/ai/index"] --> TCM_AI_HISTORY["packages/tcm/pages/ai-history/index"] - AI --> TCM_BIANZHENG["packages/tcm/pages/bianzheng/index"] - AI --> MINGLI_INTERPRET["packages/mingli/pages/interpret/index"] - - PROFILE["pages/profile/index"] --> TCM_ASSETS["packages/tcm/pages/assets/index"] - PROFILE --> TCM_AI_HISTORY - PROFILE --> LEARNING - PROFILE --> TCM_PLACEHOLDER["packages/tcm/pages/placeholder/index"] -``` - -## 静态数据与最小复用层 - -### 目标 - -定义当前项目自己的静态展示模型,只为支撑页面渲染,不兼容旧项目业务模型。 - -### 允许新增的静态工具 - -| 路径 | 职责 | -|:---|:---| -| `utils/static-ux/route-map.js` | 维护页面跳转路径常量 | -| `utils/static-ux/shared.js` | 维护纯静态数据克隆、场景选择等无状态工具 | -| `utils/static-ux/tcm.js` | 维护中医域静态页面数据工厂 | -| `utils/static-ux/mingli.js` | 维护易学域与八字域静态页面数据工厂 | -| `utils/static-ux/learning.js` | 维护学习中心聚合页静态数据工厂 | - -### 允许抽取的公共层级 - -- 少量全局视觉 token 放入 `app.wxss` -- 只抽纯静态、无业务含义的复用 -- 页面结构优先在页面内落地,避免过早抽组件 - -### 禁止抽取的层级 - -- `services/api/*` -- `services/request/*` -- `stores/*` -- 旧项目的 `domain-*`、`standalone-storage*`、`workflow*`、`composables/*` -- 与后端 response contract 强绑定的 model、mapper、adapter - -### 静态数据模型约束 - -- 页面只消费最小展示字段 -- 字段名按当前项目需要重新定义 -- 同一视觉卡片可以和旧项目使用不同字段名 -- 所有展示数据都由当前仓库内静态工厂返回 - -推荐数据形态: - -```js -{ - card: { key, title, subtitle, icon, actionText }, - book: { key, title, subtitle, coverText, tags }, - section: { key, title, children }, - historyItem: { key, label, title, subtitle, meta }, - formPreset: { title, fields, examples, buttonText }, - resultPreset: { title, summary, highlights }, - baziPreset: { profile, pillars, summary, highlights } -} -``` - -## 交互边界 - -### 允许保留的前端交互 - -- 页面跳转 -- tab / segment / 分类切换 -- 输入框、textarea、选项选中态 -- 抽屉、弹层、目录展开 -- 静态结果卡显示与隐藏 -- `wx.showToast` 占位提示 - -### 明确禁止的交互 - -- 真实登录态判断 -- mock session 写入 -- 本地持久化历史、收藏、书架、笔记 -- 按真实 ID 请求详情 -- 真实搜索过滤 -- 真实阅读器分页逻辑 -- 真实 AI 输出和引用结构 -- 真实八字计算或记录管理 - -### 参数策略 - -参数只允许承担静态场景切换,不承担业务身份标识。 - -允许的参数示例: - -- `kind=notes|bookshelf|favorites|history` -- `mode=qa|analysis|constitution` -- `domain=tcm|mingli` -- `scene=default|empty|result` - -禁止继续沿用的旧式业务参数语义: - -- `bookId` -- `recordId` -- `passageId` - -如果某个页面确实需要多个视觉场景,应使用当前项目自定义的轻量参数,例如: - -- `scene=classic-a` -- `scene=record-preview` - -## 视觉风格约束 - -- `tcm` 域沿用当前项目暖金、米白、浅棕的卡片化风格 -- `mingli / bazi` 域保留偏红棕的区分,但统一到当前小程序样式体系 -- 同域页面的标题、卡片、按钮、背景节奏必须一致 -- 不做截图级像素还原,优先保证结构、层级、节奏、交互反馈一致 -- 不擅自重做当前项目已经确定的 tab 结构和全局视觉方向 - -## 实施边界 - -### 实施顺序 - -1. 更新 `app.json` 注册分包与页面路由 -2. 搭建 `utils/static-ux/*` 静态数据层 -3. 完善主包 4 个 tab 页和登录页的入口与静态结构 -4. 落地 `tcm` 分包静态页 -5. 落地 `mingli` 分包静态页 -6. 落地 `learning` 分包静态页 -7. 回查路由、入口、样式一致性与文档登记 - -### 禁止事项 - -- 不把旧项目目录整体照搬到当前仓库 -- 不为了复刻 UI 顺手补接口或 store -- 不为了“以后可能会接后端”先设计复杂状态层 -- 不新建第二套首页、第二套我的页、第二套主导航 - -## 验收标准 - -1. 当前项目保留 `4 tab` 结构不变 -2. `frontend` 目标页面在当前仓库都有静态对应页 -3. 当前已经存在的主包页只做增强,不重复建页 -4. 所有新增页面都能从可见入口点进去 -5. 页面内主要操作都有静态反馈、切换或跳转结果 -6. 实现过程中不新增 API、request、store 依赖 -7. 实现过程中不复刻旧项目数据结构、工具链和目录组织 -8. `AGENTS.md` 的 `.ai-specs` 文档登记与本设计保持同步 - diff --git a/.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-implementation-plan.md b/.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-implementation-plan.md deleted file mode 100644 index 7d0e555..0000000 --- a/.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-implementation-plan.md +++ /dev/null @@ -1,1744 +0,0 @@ -# Frontend Static Page Migration Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** 在保持当前 `4 tab` 不变的前提下,把 `D:\Code3\wdp\xuanzhi\frontend` 的主要页面迁移为当前小程序仓库中的静态页面体系,做到页面可见、可点、可切换,但不接 API、store、旧数据结构和真实业务逻辑。 - -**Architecture:** 先在 `app.json` 中注册 `tcm / mingli / learning` 分包,再建立 `utils/static-ux/*` 纯静态数据层,随后按“主包页 -> tcm 分包 -> mingli + learning 分包”的顺序落地页面。所有页面 `index.js` 统一暴露 `create*PageData` 工厂函数,Jest 直接验证页面数据和事件处理,页面间只通过当前仓库自定义的静态参数做场景切换。 - -**Tech Stack:** 微信原生小程序、JavaScript、WXML、WXSS、Jest、TDesign(仅限当前仓库已存在组件) - ---- - -## File Structure - -- Modify: `app.json` -- Modify: `app.wxss` -- Create: `utils/static-ux/route-map.js` -- Create: `utils/static-ux/shared.js` -- Create: `utils/static-ux/tcm.js` -- Create: `utils/static-ux/mingli.js` -- Create: `utils/static-ux/learning.js` -- Modify: `pages/home/index.js` -- Modify: `pages/home/index.wxml` -- Modify: `pages/home/index.wxss` -- Modify: `pages/library/index.js` -- Modify: `pages/library/index.wxml` -- Modify: `pages/library/index.wxss` -- Modify: `pages/ai/index.js` -- Modify: `pages/ai/index.wxml` -- Modify: `pages/ai/index.wxss` -- Modify: `pages/profile/index.js` -- Modify: `pages/profile/index.wxml` -- Modify: `pages/profile/index.wxss` -- Modify: `pages/login/index.js` -- Modify: `pages/login/index.wxml` -- Modify: `pages/login/index.wxss` -- Create: `packages/tcm/pages/ai-history/index.js` -- Create: `packages/tcm/pages/ai-history/index.json` -- Create: `packages/tcm/pages/ai-history/index.wxml` -- Create: `packages/tcm/pages/ai-history/index.wxss` -- Create: `packages/tcm/pages/assets/index.js` -- Create: `packages/tcm/pages/assets/index.json` -- Create: `packages/tcm/pages/assets/index.wxml` -- Create: `packages/tcm/pages/assets/index.wxss` -- Create: `packages/tcm/pages/bianzheng/index.js` -- Create: `packages/tcm/pages/bianzheng/index.json` -- Create: `packages/tcm/pages/bianzheng/index.wxml` -- Create: `packages/tcm/pages/bianzheng/index.wxss` -- Create: `packages/tcm/pages/book-detail/index.js` -- Create: `packages/tcm/pages/book-detail/index.json` -- Create: `packages/tcm/pages/book-detail/index.wxml` -- Create: `packages/tcm/pages/book-detail/index.wxss` -- Create: `packages/tcm/pages/search-books/index.js` -- Create: `packages/tcm/pages/search-books/index.json` -- Create: `packages/tcm/pages/search-books/index.wxml` -- Create: `packages/tcm/pages/search-books/index.wxss` -- Create: `packages/tcm/pages/section/index.js` -- Create: `packages/tcm/pages/section/index.json` -- Create: `packages/tcm/pages/section/index.wxml` -- Create: `packages/tcm/pages/section/index.wxss` -- Create: `packages/tcm/pages/placeholder/index.js` -- Create: `packages/tcm/pages/placeholder/index.json` -- Create: `packages/tcm/pages/placeholder/index.wxml` -- Create: `packages/tcm/pages/placeholder/index.wxss` -- Create: `packages/mingli/pages/hall/index.js` -- Create: `packages/mingli/pages/hall/index.json` -- Create: `packages/mingli/pages/hall/index.wxml` -- Create: `packages/mingli/pages/hall/index.wxss` -- Create: `packages/mingli/pages/bazi/index.js` -- Create: `packages/mingli/pages/bazi/index.json` -- Create: `packages/mingli/pages/bazi/index.wxml` -- Create: `packages/mingli/pages/bazi/index.wxss` -- Create: `packages/mingli/pages/book-detail/index.js` -- Create: `packages/mingli/pages/book-detail/index.json` -- Create: `packages/mingli/pages/book-detail/index.wxml` -- Create: `packages/mingli/pages/book-detail/index.wxss` -- Create: `packages/mingli/pages/search-books/index.js` -- Create: `packages/mingli/pages/search-books/index.json` -- Create: `packages/mingli/pages/search-books/index.wxml` -- Create: `packages/mingli/pages/search-books/index.wxss` -- Create: `packages/mingli/pages/section/index.js` -- Create: `packages/mingli/pages/section/index.json` -- Create: `packages/mingli/pages/section/index.wxml` -- Create: `packages/mingli/pages/section/index.wxss` -- Create: `packages/mingli/pages/interpret/index.js` -- Create: `packages/mingli/pages/interpret/index.json` -- Create: `packages/mingli/pages/interpret/index.wxml` -- Create: `packages/mingli/pages/interpret/index.wxss` -- Create: `packages/learning/pages/center/index.js` -- Create: `packages/learning/pages/center/index.json` -- Create: `packages/learning/pages/center/index.wxml` -- Create: `packages/learning/pages/center/index.wxss` -- Create: `tests/static-ux-route-map.test.js` -- Create: `tests/static-ux-domain-data.test.js` -- Create: `tests/profile-page.test.js` -- Create: `tests/profile-page-render.test.js` -- Create: `tests/login-page.test.js` -- Create: `tests/login-page-render.test.js` -- Create: `tests/tcm-support-pages.test.js` -- Create: `tests/tcm-reading-pages.test.js` -- Create: `tests/mingli-learning-pages.test.js` -- Modify: `tests/project-config.test.js` -- Modify: `tests/home-page.test.js` -- Modify: `tests/home-page-render.test.js` -- Modify: `tests/library-page.test.js` -- Modify: `tests/library-page-render.test.js` -- Modify: `tests/ai-page.test.js` -- Modify: `tests/ai-page-render.test.js` - -## Execution Notes - -- 工作区已经存在与本计划无关的改动;每一步只 `git add` 本任务涉及的文件。 -- 页面参数只允许使用 `scene / mode / kind / domain / keyword` 这类静态场景参数,不允许恢复 `bookId / recordId / passageId` 的真实业务语义。 -- 现有页面测试已经约束 `pages/home/index.wxss` 不能使用 `display: grid`、`gap:`、`width: fit-content`,实现时必须继续遵守。 - -### Task 1: Register Subpackages And Static UX Foundation - -**Files:** -- Modify: `app.json` -- Modify: `tests/project-config.test.js` -- Create: `utils/static-ux/route-map.js` -- Create: `utils/static-ux/shared.js` -- Create: `utils/static-ux/tcm.js` -- Create: `utils/static-ux/mingli.js` -- Create: `utils/static-ux/learning.js` -- Create: `tests/static-ux-route-map.test.js` -- Create: `tests/static-ux-domain-data.test.js` - -- [ ] **Step 1: Write the failing route and data-factory tests** - -```js -// tests/static-ux-route-map.test.js -const { ROUTES } = require('../utils/static-ux/route-map') - -describe('static route map', () => { - test('exposes full route paths for all static migration pages', () => { - expect(ROUTES.tabs.home).toBe('/pages/home/index') - expect(ROUTES.tcm.aiHistory).toBe('/packages/tcm/pages/ai-history/index') - expect(ROUTES.tcm.section).toBe('/packages/tcm/pages/section/index') - expect(ROUTES.mingli.hall).toBe('/packages/mingli/pages/hall/index') - expect(ROUTES.mingli.interpret).toBe('/packages/mingli/pages/interpret/index') - expect(ROUTES.learning.center).toBe('/packages/learning/pages/center/index') - }) -}) -``` - -```js -// tests/static-ux-domain-data.test.js -const { - createTcmHomeHubCards, - createTcmAssetPageData -} = require('../utils/static-ux/tcm') -const { - createMingliHallPageData, - createBaziPageData -} = require('../utils/static-ux/mingli') -const { createLearningCenterPageData } = require('../utils/static-ux/learning') - -describe('static domain factories', () => { - test('returns scene-safe static data for tcm, mingli and learning domains', () => { - expect(createTcmHomeHubCards()).toEqual( - expect.arrayContaining([ - expect.objectContaining({ key: 'tcm-library', title: '中医馆' }), - expect.objectContaining({ key: 'mingli-hall', title: '易学阁' }) - ]) - ) - expect(createTcmAssetPageData('notes')).toEqual( - expect.objectContaining({ - title: '学习资产', - activeKind: 'notes' - }) - ) - expect(createMingliHallPageData()).toEqual( - expect.objectContaining({ - title: '易学阁' - }) - ) - expect(createBaziPageData('result')).toEqual( - expect.objectContaining({ - title: '八字排盘', - scene: 'result' - }) - ) - expect(createLearningCenterPageData()).toEqual( - expect.objectContaining({ - title: '学习中心' - }) - ) - }) -}) -``` - -```js -// tests/project-config.test.js -test('registers static migration subpackages in app config', () => { - const appConfig = readJson('app.json') - - expect(appConfig.subPackages).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - root: 'packages/tcm', - pages: expect.arrayContaining([ - 'pages/ai-history/index', - 'pages/assets/index', - 'pages/bianzheng/index', - 'pages/book-detail/index', - 'pages/search-books/index', - 'pages/section/index', - 'pages/placeholder/index' - ]) - }), - expect.objectContaining({ - root: 'packages/mingli', - pages: expect.arrayContaining([ - 'pages/hall/index', - 'pages/bazi/index', - 'pages/book-detail/index', - 'pages/search-books/index', - 'pages/section/index', - 'pages/interpret/index' - ]) - }), - expect.objectContaining({ - root: 'packages/learning', - pages: ['pages/center/index'] - }) - ]) - ) -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/project-config.test.js tests/static-ux-route-map.test.js tests/static-ux-domain-data.test.js` - -Expected: FAIL with `Cannot find module '../utils/static-ux/route-map'` and missing `packages/tcm` / `packages/mingli` / `packages/learning` registration assertions. - -- [ ] **Step 3: Write the minimal subpackage and static-ux implementation** - -```js -// utils/static-ux/route-map.js -const ROUTES = Object.freeze({ - tabs: { - home: '/pages/home/index', - library: '/pages/library/index', - ai: '/pages/ai/index', - profile: '/pages/profile/index', - login: '/pages/login/index' - }, - tcm: { - aiHistory: '/packages/tcm/pages/ai-history/index', - assets: '/packages/tcm/pages/assets/index', - bianzheng: '/packages/tcm/pages/bianzheng/index', - bookDetail: '/packages/tcm/pages/book-detail/index', - searchBooks: '/packages/tcm/pages/search-books/index', - section: '/packages/tcm/pages/section/index', - placeholder: '/packages/tcm/pages/placeholder/index' - }, - mingli: { - hall: '/packages/mingli/pages/hall/index', - bazi: '/packages/mingli/pages/bazi/index', - bookDetail: '/packages/mingli/pages/book-detail/index', - searchBooks: '/packages/mingli/pages/search-books/index', - section: '/packages/mingli/pages/section/index', - interpret: '/packages/mingli/pages/interpret/index' - }, - learning: { - center: '/packages/learning/pages/center/index' - } -}) - -module.exports = { - ROUTES -} -``` - -```js -// utils/static-ux/shared.js -function cloneItem(item) { - return { ...item } -} - -function cloneList(items) { - return items.map(cloneItem) -} - -function resolveScene(rawScene, allowedScenes, fallbackScene) { - return allowedScenes.includes(rawScene) ? rawScene : fallbackScene -} - -function resolveKind(rawKind, allowedKinds, fallbackKind) { - return allowedKinds.includes(rawKind) ? rawKind : fallbackKind -} - -module.exports = { - cloneItem, - cloneList, - resolveScene, - resolveKind -} -``` - -```js -// utils/static-ux/tcm.js -const { cloneList, resolveKind } = require('./shared') -const { ROUTES } = require('./route-map') - -const TCM_HOME_HUB_CARDS = Object.freeze([ - { key: 'tcm-library', title: '中医馆', subtitle: '典籍与目录', route: ROUTES.tabs.library, badge: 'TCM' }, - { key: 'mingli-hall', title: '易学阁', subtitle: '命理与经典', route: ROUTES.mingli.hall, badge: 'NEW' }, - { key: 'bazi', title: '八字排盘', subtitle: '静态排盘结果', route: ROUTES.mingli.bazi, badge: 'BETA' }, - { key: 'learning-center', title: '学习中心', subtitle: '继续学习与回顾', route: ROUTES.learning.center, badge: 'GO' } -]) - -const TCM_ASSET_SURFACES = Object.freeze({ - notes: { title: '学习资产', activeKind: 'notes', kinds: ['notes', 'bookshelf', 'favorites', 'history'] }, - bookshelf: { title: '学习资产', activeKind: 'bookshelf', kinds: ['notes', 'bookshelf', 'favorites', 'history'] }, - favorites: { title: '学习资产', activeKind: 'favorites', kinds: ['notes', 'bookshelf', 'favorites', 'history'] }, - history: { title: '学习资产', activeKind: 'history', kinds: ['notes', 'bookshelf', 'favorites', 'history'] } -}) - -function createTcmHomeHubCards() { - return cloneList(TCM_HOME_HUB_CARDS) -} - -function createTcmAssetPageData(rawKind) { - const activeKind = resolveKind(rawKind, ['notes', 'bookshelf', 'favorites', 'history'], 'notes') - return { - ...TCM_ASSET_SURFACES[activeKind], - cards: createTcmHomeHubCards() - } -} - -module.exports = { - createTcmHomeHubCards, - createTcmAssetPageData -} -``` - -```js -// utils/static-ux/mingli.js -const { cloneList, resolveScene } = require('./shared') -const { ROUTES } = require('./route-map') - -const MINGLI_QUICK_CARDS = Object.freeze([ - { key: 'hall', title: '易学阁', subtitle: '总览入口', route: ROUTES.mingli.hall, icon: '阁' }, - { key: 'bazi', title: '八字排盘', subtitle: '静态排盘结果', route: ROUTES.mingli.bazi, icon: '盘' }, - { key: 'interpret', title: '命理解读', subtitle: '问题与解读', route: ROUTES.mingli.interpret, icon: '解' } -]) - -function createMingliHallPageData() { - return { - title: '易学阁', - quickCards: cloneList(MINGLI_QUICK_CARDS) - } -} - -function createBaziPageData(rawScene) { - const scene = resolveScene(rawScene, ['default', 'result'], 'default') - return { - title: '八字排盘', - scene, - quickCards: cloneList(MINGLI_QUICK_CARDS) - } -} - -module.exports = { - createMingliHallPageData, - createBaziPageData -} -``` - -```js -// utils/static-ux/learning.js -function createLearningCenterPageData() { - return { - title: '学习中心', - summaryCards: [ - { key: 'qa', value: 8, label: '问答' }, - { key: 'analysis', value: 5, label: '辨证' }, - { key: 'interpret', value: 6, label: '解读' }, - { key: 'bazi', value: 4, label: '排盘' } - ] - } -} - -module.exports = { - createLearningCenterPageData -} -``` - -```json -// app.json -{ - "subPackages": [ - { - "root": "packages/demo", - "pages": ["pages/workbench/index"] - }, - { - "root": "packages/tcm", - "pages": [ - "pages/ai-history/index", - "pages/assets/index", - "pages/bianzheng/index", - "pages/book-detail/index", - "pages/search-books/index", - "pages/section/index", - "pages/placeholder/index" - ] - }, - { - "root": "packages/mingli", - "pages": [ - "pages/hall/index", - "pages/bazi/index", - "pages/book-detail/index", - "pages/search-books/index", - "pages/section/index", - "pages/interpret/index" - ] - }, - { - "root": "packages/learning", - "pages": ["pages/center/index"] - } - ] -} -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/project-config.test.js tests/static-ux-route-map.test.js tests/static-ux-domain-data.test.js` - -Expected: PASS, with the new route map and subpackage assertions green. - -- [ ] **Step 5: Commit** - -```bash -git add app.json utils/static-ux/route-map.js utils/static-ux/shared.js utils/static-ux/tcm.js utils/static-ux/mingli.js utils/static-ux/learning.js tests/project-config.test.js tests/static-ux-route-map.test.js tests/static-ux-domain-data.test.js -git commit -m "feat: add static page route foundation" -``` - -### Task 2: Enhance Home Page As The Global Portal - -**Files:** -- Modify: `app.wxss` -- Modify: `pages/home/index.js` -- Modify: `pages/home/index.wxml` -- Modify: `pages/home/index.wxss` -- Modify: `tests/home-page.test.js` -- Modify: `tests/home-page-render.test.js` - -- [ ] **Step 1: Write the failing home-page portal tests** - -```js -// tests/home-page.test.js -test('adds direct portal cards for tcm, mingli, bazi and learning routes', () => { - let capturedPageConfig - - global.Page = config => { - capturedPageConfig = config - } - - const homePageModule = require('../pages/home/index') - const pageData = homePageModule.createHomePageData() - - expect(pageData.portalTitle).toBe('学习入口') - expect(pageData.portalCards).toEqual([ - expect.objectContaining({ key: 'tcm-library', title: '中医馆' }), - expect.objectContaining({ key: 'mingli-hall', title: '易学阁' }), - expect.objectContaining({ key: 'bazi', title: '八字排盘' }), - expect.objectContaining({ key: 'learning-center', title: '学习中心' }) - ]) - - global.wx = { - navigateTo: jest.fn() - } - - capturedPageConfig.handlePortalTap({ - currentTarget: { - dataset: { - route: '/packages/mingli/pages/hall/index' - } - } - }) - - expect(global.wx.navigateTo).toHaveBeenCalledWith({ - url: '/packages/mingli/pages/hall/index' - }) -}) -``` - -```js -// tests/home-page-render.test.js -test('renders the portal section without forbidden grid or gap styles', () => { - const wxml = fs.readFileSync(path.join(process.cwd(), 'pages/home/index.wxml'), 'utf8') - const wxss = fs.readFileSync(path.join(process.cwd(), 'pages/home/index.wxss'), 'utf8') - - expect(wxml).toContain('{{portalTitle}}') - expect(wxml).toContain('portal-grid') - expect(wxml).toContain('bindtap="handlePortalTap"') - expect(wxss).toContain('.portal-grid') - expect(wxss).toContain('.portal-card') - expect(wxss).not.toContain('display: grid') - expect(wxss).not.toContain('gap:') -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/home-page.test.js tests/home-page-render.test.js` - -Expected: FAIL because `portalTitle`, `portalCards`, `handlePortalTap`, `.portal-grid`, and `.portal-card` do not exist yet. - -- [ ] **Step 3: Write the home portal implementation** - -```js -// pages/home/index.js -const { createTcmHomeHubCards } = require('../../utils/static-ux/tcm') - -function showNavigate(route) { - if (typeof wx?.navigateTo === 'function') { - wx.navigateTo({ url: route }) - } -} - -function createHomePageData() { - return { - brandName: '玄知中医', - greeting: '晚上好', - subtitle: '今天想学点什么?从典籍、工具或养生主题开始。', - searchPlaceholder: '搜索典籍、术语、AI问答...', - searchBadge: 'AI', - portalTitle: '学习入口', - portalCards: createTcmHomeHubCards(), - encyclopediaTitle: '中医百科', - encyclopediaCards: [ - { key: 'classic', icon: '书', title: '经典书城' }, - { key: 'meridian', icon: '穴', title: '经络穴位', status: '待开放' }, - { key: 'disease', icon: '病', title: '疾病百科', status: '待开放' } - ], - toolsTitle: '学习工具', - toolCards: [ - { key: 'qa', icon: '问', title: 'AI问答' }, - { key: 'formula', icon: '方', title: '方剂笔记' }, - { key: 'constitution', icon: '诊', title: '体质诊断' }, - { key: 'wellness', icon: '养', title: '智能饮片' } - ], - wellnessTitle: '养生调理', - wellnessCards: [ - { key: 'constitution-check', icon: '🧬', title: 'AI体质检测', status: '待开放' }, - { key: 'medicated-diet', icon: '🍲', title: '药膳', status: '待开放' }, - { key: 'ingredient', icon: '🥬', title: '食材', status: '待开放' } - ], - classicsTitle: '热门典籍', - classicsActionText: '进入书城', - classicsBooks: [ - { key: 'huangdi-neijing-suwen', coverText: '黄', title: '黄帝内经素问' }, - { key: 'shang-han-lun', coverText: '伤', title: '伤寒论' }, - { key: 'wen-bing-tiao-bian', coverText: '温', title: '温病条辨' }, - { key: 'bencao-gangmu-bieming-lu', coverText: '本', title: '本草纲目别名录' } - ] - } -} - -Page({ - data: createHomePageData(), - - handlePortalTap(event) { - showNavigate(event.currentTarget.dataset.route) - } -}) - -module.exports = { - createHomePageData -} -``` - -```xml - - - {{portalTitle}} - - - {{item.badge}} - {{item.title}} - {{item.subtitle}} - - - -``` - -```css -/* pages/home/index.wxss */ -.portal-grid { - margin-top: 16rpx; - overflow: hidden; -} - -.portal-card { - float: left; - width: 48%; - min-height: 156rpx; - margin-right: 4%; - margin-bottom: 16rpx; - padding: 18rpx; - border-radius: 24rpx; - background: linear-gradient(180deg, rgba(255, 252, 246, 0.98), rgba(245, 236, 221, 0.92)); - border: 1rpx solid rgba(118, 83, 42, 0.08); -} - -.portal-card:nth-child(2n) { - margin-right: 0; -} - -.portal-card__badge { - display: inline-block; - padding: 6rpx 14rpx; - border-radius: 999rpx; - background: rgba(111, 66, 22, 0.08); - color: #8f5c1f; - font-size: 18rpx; -} - -.portal-card__title { - display: block; - margin-top: 16rpx; - font-size: 30rpx; - font-weight: 700; - color: #2c2419; -} - -.portal-card__subtitle { - display: block; - margin-top: 8rpx; - font-size: 22rpx; - line-height: 1.6; - color: #7b6b57; -} -``` - -```css -/* app.wxss */ -.xz-page--warm { - min-height: 100vh; - background: linear-gradient(180deg, #f8edd6 0%, #f9f0de 24%, #f6ead4 100%); -} - -.xz-page--mingli { - min-height: 100vh; - background: linear-gradient(180deg, #fbf6f3 0%, #f4ebe6 100%); -} - -.xz-card { - border-radius: 28rpx; - border: 1rpx solid rgba(84, 58, 29, 0.08); - box-shadow: 0 16rpx 36rpx rgba(84, 58, 29, 0.06); -} -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/home-page.test.js tests/home-page-render.test.js` - -Expected: PASS, with `portalTitle`, `portalCards`, and `handlePortalTap` verified. - -- [ ] **Step 5: Commit** - -```bash -git add app.wxss pages/home/index.js pages/home/index.wxml pages/home/index.wxss tests/home-page.test.js tests/home-page-render.test.js -git commit -m "feat: add global portal section to home page" -``` - -### Task 3: Bridge Library And AI Tabs To New Static Domains - -**Files:** -- Modify: `pages/library/index.js` -- Modify: `pages/library/index.wxml` -- Modify: `pages/library/index.wxss` -- Modify: `pages/ai/index.js` -- Modify: `pages/ai/index.wxml` -- Modify: `pages/ai/index.wxss` -- Modify: `tests/library-page.test.js` -- Modify: `tests/library-page-render.test.js` -- Modify: `tests/ai-page.test.js` -- Modify: `tests/ai-page-render.test.js` - -- [ ] **Step 1: Write the failing bridge-entry tests** - -```js -// tests/library-page.test.js -test('adds a visible mingli-hall bridge entry to the library tab', () => { - let capturedPageConfig - - global.Page = config => { - capturedPageConfig = config - } - - global.wx = { - navigateTo: jest.fn(), - showToast: jest.fn() - } - - const libraryPageModule = require('../pages/library/index') - const pageData = libraryPageModule.createLibraryPageData() - - expect(pageData.domainBridge).toEqual( - expect.objectContaining({ - title: '进入易学阁', - route: '/packages/mingli/pages/hall/index' - }) - ) - - capturedPageConfig.handleDomainBridgeTap() - - expect(global.wx.navigateTo).toHaveBeenCalledWith({ - url: '/packages/mingli/pages/hall/index' - }) -}) -``` - -```js -// tests/ai-page.test.js -test('adds a visible interpret entry and routes history to the tcm history page', () => { - let capturedPageConfig - - global.Page = config => { - capturedPageConfig = config - } - - global.wx = { - navigateTo: jest.fn(), - showToast: jest.fn() - } - - const aiPageModule = require('../pages/ai/index') - const pageData = aiPageModule.createAiPageData() - - expect(pageData.secondaryEntries).toEqual( - expect.arrayContaining([ - expect.objectContaining({ key: 'ai-history', title: 'AI历史' }), - expect.objectContaining({ key: 'mingli-interpret', title: '命理解读' }) - ]) - ) - - capturedPageConfig.handleHistoryTap() - capturedPageConfig.handleSecondaryEntryTap({ - currentTarget: { - dataset: { - route: '/packages/mingli/pages/interpret/index' - } - } - }) - - expect(global.wx.navigateTo).toHaveBeenNthCalledWith(1, { - url: '/packages/tcm/pages/ai-history/index' - }) - expect(global.wx.navigateTo).toHaveBeenNthCalledWith(2, { - url: '/packages/mingli/pages/interpret/index' - }) -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/library-page.test.js tests/library-page-render.test.js tests/ai-page.test.js tests/ai-page-render.test.js` - -Expected: FAIL because `domainBridge`, `handleDomainBridgeTap`, `secondaryEntries`, and new navigation handlers are not implemented. - -- [ ] **Step 3: Write the bridge-entry implementation** - -```js -// pages/library/index.js -const { ROUTES } = require('../../utils/static-ux/route-map') -// 继续复用当前文件里已经存在的 LIBRARY_CATEGORIES / getBooksByCategory / getCategoryById - -function createLibraryPageData(categoryId) { - const activeCategory = getCategoryById(categoryId) - - return { - title: '典籍', - searchButtonText: '搜索', - domainBridge: { - title: '进入易学阁', - subtitle: '查看命理经典与八字相关静态页面', - route: ROUTES.mingli.hall - }, - categories: LIBRARY_CATEGORIES.map(item => ({ ...item })), - activeCategoryId: activeCategory.id, - currentCategoryName: activeCategory.name, - visibleBooks: getBooksByCategory(activeCategory.id) - } -} - -Page({ - data: createLibraryPageData(), - - handleDomainBridgeTap() { - wx.navigateTo({ - url: ROUTES.mingli.hall - }) - } -}) -``` - -```xml - - - {{domainBridge.title}} - {{domainBridge.subtitle}} - -``` - -```css -/* pages/library/index.wxss */ -.library-page__bridge { - margin-bottom: 18rpx; - padding: 20rpx 24rpx; - border-radius: 24rpx; - background: rgba(255, 250, 242, 0.94); - border: 1rpx solid rgba(118, 83, 42, 0.08); -} -``` - -```js -// pages/ai/index.js -const { ROUTES } = require('../../utils/static-ux/route-map') -// 继续复用当前文件里已经存在的 AI_PAGE_BLUEPRINT / createPanelByKey - -function createAiPageData() { - return { - title: 'AI助手', - historyText: '历史', - disclaimerText: AI_PAGE_BLUEPRINT.disclaimerText, - secondaryEntries: [ - { key: 'ai-history', title: 'AI历史', route: ROUTES.tcm.aiHistory }, - { key: 'mingli-interpret', title: '命理解读', route: ROUTES.mingli.interpret } - ], - activeTabKey: 'qa', - tabs: AI_PAGE_BLUEPRINT.tabs.map(item => ({ ...item })), - currentPanel: createPanelByKey('qa') - } -} - -Page({ - data: createAiPageData(), - - handleHistoryTap() { - wx.navigateTo({ - url: ROUTES.tcm.aiHistory - }) - }, - - handleSecondaryEntryTap(event) { - wx.navigateTo({ - url: event.currentTarget.dataset.route - }) - } -}) -``` - -```xml - - - - {{item.title}} - - -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/library-page.test.js tests/library-page-render.test.js tests/ai-page.test.js tests/ai-page-render.test.js` - -Expected: PASS, with the new bridge entries and `wx.navigateTo` calls green. - -- [ ] **Step 5: Commit** - -```bash -git add pages/library/index.js pages/library/index.wxml pages/library/index.wxss pages/ai/index.js pages/ai/index.wxml pages/ai/index.wxss tests/library-page.test.js tests/library-page-render.test.js tests/ai-page.test.js tests/ai-page-render.test.js -git commit -m "feat: connect library and ai tabs to static domain pages" -``` - -### Task 4: Replace Profile And Login Placeholders With Static UX Pages - -**Files:** -- Modify: `pages/profile/index.js` -- Modify: `pages/profile/index.wxml` -- Modify: `pages/profile/index.wxss` -- Modify: `pages/login/index.js` -- Modify: `pages/login/index.wxml` -- Modify: `pages/login/index.wxss` -- Create: `tests/profile-page.test.js` -- Create: `tests/profile-page-render.test.js` -- Create: `tests/login-page.test.js` -- Create: `tests/login-page-render.test.js` - -- [ ] **Step 1: Write the failing profile and login tests** - -```js -// tests/profile-page.test.js -describe('profile page', () => { - afterEach(() => { - delete global.Page - delete global.wx - jest.resetModules() - }) - - test('exposes static profile sections and navigable shortcuts', () => { - let capturedPageConfig - - global.Page = config => { - capturedPageConfig = config - } - - global.wx = { - navigateTo: jest.fn() - } - - const profilePageModule = require('../pages/profile/index') - const pageData = profilePageModule.createProfilePageData() - - expect(pageData.userCard.title).toBe('点击登录') - expect(pageData.assetItems).toHaveLength(4) - expect(pageData.moreItems).toEqual( - expect.arrayContaining([ - expect.objectContaining({ key: 'learning-center', title: '学习中心' }), - expect.objectContaining({ key: 'ai-history', title: 'AI历史' }) - ]) - ) - - capturedPageConfig.handleMoreTap({ - currentTarget: { - dataset: { - route: '/packages/learning/pages/center/index' - } - } - }) - - expect(global.wx.navigateTo).toHaveBeenCalledWith({ - url: '/packages/learning/pages/center/index' - }) - }) -}) -``` - -```js -// tests/login-page.test.js -const fs = require('fs') -const path = require('path') - -describe('login page', () => { - afterEach(() => { - delete global.Page - jest.resetModules() - }) - - test('renders a static login surface without session-store wiring', () => { - let capturedPageConfig - - global.Page = config => { - capturedPageConfig = config - } - - const loginPageModule = require('../pages/login/index') - const pageData = loginPageModule.createLoginPageData() - const source = fs.readFileSync(path.join(process.cwd(), 'pages/login/index.js'), 'utf8') - - expect(pageData.title).toBe('欢迎来到玄志') - expect(pageData.actions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ key: 'wechat', title: '微信授权登录' }), - expect.objectContaining({ key: 'browse', title: '先看看静态页面' }) - ]) - ) - expect(source).not.toContain('sessionStore') - expect(source).not.toContain('handleMockLogin') - }) -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/profile-page.test.js tests/profile-page-render.test.js tests/login-page.test.js tests/login-page-render.test.js` - -Expected: FAIL because `pages/profile/index.js` does not export `createProfilePageData`, `pages/login/index.js` still depends on session logic, and the new render assertions are missing. - -- [ ] **Step 3: Write the static profile and login implementation** - -```js -// pages/profile/index.js -const { ROUTES } = require('../../utils/static-ux/route-map') - -function createProfilePageData() { - return { - userCard: { - avatarText: '?', - title: '点击登录', - subtitle: '登录后查看你的学习资产' - }, - assetItems: [ - { key: 'notes', title: '我的笔记', count: 0, route: `${ROUTES.tcm.assets}?kind=notes` }, - { key: 'bookshelf', title: '我的书架', count: 0, route: `${ROUTES.tcm.assets}?kind=bookshelf` }, - { key: 'favorites', title: '我的收藏', count: 0, route: `${ROUTES.tcm.assets}?kind=favorites` }, - { key: 'history', title: '浏览历史', count: 0, route: `${ROUTES.tcm.assets}?kind=history` } - ], - moreItems: [ - { key: 'learning-center', title: '学习中心', route: ROUTES.learning.center }, - { key: 'ai-history', title: 'AI历史', route: ROUTES.tcm.aiHistory }, - { key: 'placeholder-about', title: '关于我们', route: `${ROUTES.tcm.placeholder}?kind=about` }, - { key: 'placeholder-settings', title: '设置', route: `${ROUTES.tcm.placeholder}?kind=settings` } - ] - } -} - -Page({ - data: createProfilePageData(), - - handleAssetTap(event) { - wx.navigateTo({ url: event.currentTarget.dataset.route }) - }, - - handleMoreTap(event) { - wx.navigateTo({ url: event.currentTarget.dataset.route }) - } -}) - -module.exports = { - createProfilePageData -} -``` - -```js -// pages/login/index.js -const { ROUTES } = require('../../utils/static-ux/route-map') - -function createLoginPageData() { - return { - title: '欢迎来到玄志', - subtitle: '当前阶段先提供静态登录页,后续再接入新的认证方案。', - actions: [ - { key: 'wechat', title: '微信授权登录', type: 'toast' }, - { key: 'browse', title: '先看看静态页面', type: 'route', route: ROUTES.tabs.home } - ] - } -} - -function showComingSoon() { - if (typeof wx?.showToast === 'function') { - wx.showToast({ - title: '登录功能建设中', - icon: 'none' - }) - } -} - -Page({ - data: createLoginPageData(), - - handleActionTap(event) { - const { actionType, route } = event.currentTarget.dataset - - if (actionType === 'route') { - wx.switchTab({ url: route }) - return - } - - showComingSoon() - } -}) - -module.exports = { - createLoginPageData -} -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/profile-page.test.js tests/profile-page-render.test.js tests/login-page.test.js tests/login-page-render.test.js` - -Expected: PASS, with `profile` shortcut routes and `login` static action data confirmed. - -- [ ] **Step 5: Commit** - -```bash -git add pages/profile/index.js pages/profile/index.wxml pages/profile/index.wxss pages/login/index.js pages/login/index.wxml pages/login/index.wxss tests/profile-page.test.js tests/profile-page-render.test.js tests/login-page.test.js tests/login-page-render.test.js -git commit -m "feat: add static profile and login pages" -``` - -### Task 5: Build TCM Support Pages - -**Files:** -- Create: `packages/tcm/pages/ai-history/index.js` -- Create: `packages/tcm/pages/ai-history/index.json` -- Create: `packages/tcm/pages/ai-history/index.wxml` -- Create: `packages/tcm/pages/ai-history/index.wxss` -- Create: `packages/tcm/pages/assets/index.js` -- Create: `packages/tcm/pages/assets/index.json` -- Create: `packages/tcm/pages/assets/index.wxml` -- Create: `packages/tcm/pages/assets/index.wxss` -- Create: `packages/tcm/pages/bianzheng/index.js` -- Create: `packages/tcm/pages/bianzheng/index.json` -- Create: `packages/tcm/pages/bianzheng/index.wxml` -- Create: `packages/tcm/pages/bianzheng/index.wxss` -- Create: `packages/tcm/pages/placeholder/index.js` -- Create: `packages/tcm/pages/placeholder/index.json` -- Create: `packages/tcm/pages/placeholder/index.wxml` -- Create: `packages/tcm/pages/placeholder/index.wxss` -- Create: `tests/tcm-support-pages.test.js` - -- [ ] **Step 1: Write the failing TCM support-page tests** - -```js -// tests/tcm-support-pages.test.js -describe('tcm support pages', () => { - afterEach(() => { - delete global.Page - delete global.wx - jest.resetModules() - }) - - test('assets page switches by static kind and keeps route-only navigation', () => { - let capturedPageConfig - - global.Page = config => { - capturedPageConfig = config - } - - const assetsPageModule = require('../packages/tcm/pages/assets/index') - const pageData = assetsPageModule.createTcmAssetsPageData('favorites') - - expect(pageData.activeKind).toBe('favorites') - expect(pageData.title).toBe('学习资产') - expect(pageData.filterItems).toHaveLength(4) - }) - - test('ai history, bianzheng and placeholder pages expose scene-driven static data', () => { - global.Page = () => {} - - const aiHistoryModule = require('../packages/tcm/pages/ai-history/index') - const bianzhengModule = require('../packages/tcm/pages/bianzheng/index') - const placeholderModule = require('../packages/tcm/pages/placeholder/index') - - expect(aiHistoryModule.createTcmAiHistoryPageData('empty')).toEqual( - expect.objectContaining({ scene: 'empty', title: 'AI对话历史' }) - ) - expect(bianzhengModule.createTcmBianzhengPageData('result')).toEqual( - expect.objectContaining({ scene: 'result', title: '辨证分析' }) - ) - expect(placeholderModule.createTcmPlaceholderPageData('membership')).toEqual( - expect.objectContaining({ kind: 'membership' }) - ) - }) -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/tcm-support-pages.test.js` - -Expected: FAIL because the `packages/tcm/pages/*` modules and `create*PageData` exports do not exist yet. - -- [ ] **Step 3: Write the TCM support pages** - -```js -// packages/tcm/pages/assets/index.js -const { createTcmAssetPageData } = require('../../../../utils/static-ux/tcm') -const { resolveKind } = require('../../../../utils/static-ux/shared') - -function createTcmAssetsPageData(rawKind) { - const data = createTcmAssetPageData(rawKind) - - return { - ...data, - filterItems: data.kinds.map(kind => ({ - key: kind, - label: kind === 'notes' ? '笔记' : kind === 'bookshelf' ? '书架' : kind === 'favorites' ? '收藏' : '历史', - route: `/packages/tcm/pages/assets/index?kind=${kind}` - })) - } -} - -Page({ - data: createTcmAssetsPageData('notes'), - - onLoad(options) { - this.setData(createTcmAssetsPageData(resolveKind(options.kind, ['notes', 'bookshelf', 'favorites', 'history'], 'notes'))) - } -}) - -module.exports = { - createTcmAssetsPageData -} -``` - -```js -// packages/tcm/pages/ai-history/index.js -const { resolveScene } = require('../../../../utils/static-ux/shared') - -function createTcmAiHistoryPageData(rawScene) { - const scene = resolveScene(rawScene, ['default', 'empty'], 'default') - - return { - title: 'AI对话历史', - scene, - groups: - scene === 'empty' - ? [] - : [ - { key: 'today', label: '今天', items: [{ key: 'qa-1', title: '什么是阴阳?', summary: '从阴阳对待看基础结构。' }] } - ] - } -} - -Page({ - data: createTcmAiHistoryPageData('default'), - - onLoad(options) { - this.setData(createTcmAiHistoryPageData(options.scene)) - } -}) - -module.exports = { - createTcmAiHistoryPageData -} -``` - -```js -// packages/tcm/pages/bianzheng/index.js -const { resolveScene } = require('../../../../utils/static-ux/shared') - -function createTcmBianzhengPageData(rawScene) { - const scene = resolveScene(rawScene, ['default', 'result'], 'default') - - return { - title: '辨证分析', - scene, - form: { - mainSymptoms: '', - tongue: '', - pulse: '', - constitution: '', - duration: '' - }, - result: - scene === 'result' - ? { - title: '学习型辨证结果', - summary: '以脾虚湿困作为静态展示结果,后续接真实逻辑时再替换。' - } - : null - } -} - -Page({ - data: createTcmBianzhengPageData('default'), - - onLoad(options) { - this.setData(createTcmBianzhengPageData(options.scene)) - }, - - handleSubmitTap() { - this.setData(createTcmBianzhengPageData('result')) - } -}) - -module.exports = { - createTcmBianzhengPageData -} -``` - -```js -// packages/tcm/pages/placeholder/index.js -function createTcmPlaceholderPageData(kind) { - const activeKind = ['membership', 'feedback', 'share', 'about', 'settings'].includes(kind) - ? kind - : 'about' - - return { - title: activeKind === 'membership' ? '开通会员' : activeKind === 'feedback' ? '意见反馈' : activeKind === 'share' ? '分享 APP' : activeKind === 'settings' ? '设置' : '关于我们', - kind: activeKind, - tips: [ - '本页当前只承接静态展示。', - '后续接入真实逻辑时保持当前页面信息层级。', - '不要把旧项目流程直接迁移过来。' - ] - } -} - -Page({ - data: createTcmPlaceholderPageData('about'), - - onLoad(options) { - this.setData(createTcmPlaceholderPageData(options.kind)) - } -}) - -module.exports = { - createTcmPlaceholderPageData -} -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/tcm-support-pages.test.js` - -Expected: PASS, with `scene` / `kind`-driven static data verified and no service layer required. - -- [ ] **Step 5: Commit** - -```bash -git add packages/tcm/pages/ai-history packages/tcm/pages/assets packages/tcm/pages/bianzheng packages/tcm/pages/placeholder tests/tcm-support-pages.test.js -git commit -m "feat: add tcm support pages" -``` - -### Task 6: Build TCM Reading, Search And Detail Pages - -**Files:** -- Create: `packages/tcm/pages/book-detail/index.js` -- Create: `packages/tcm/pages/book-detail/index.json` -- Create: `packages/tcm/pages/book-detail/index.wxml` -- Create: `packages/tcm/pages/book-detail/index.wxss` -- Create: `packages/tcm/pages/search-books/index.js` -- Create: `packages/tcm/pages/search-books/index.json` -- Create: `packages/tcm/pages/search-books/index.wxml` -- Create: `packages/tcm/pages/search-books/index.wxss` -- Create: `packages/tcm/pages/section/index.js` -- Create: `packages/tcm/pages/section/index.json` -- Create: `packages/tcm/pages/section/index.wxml` -- Create: `packages/tcm/pages/section/index.wxss` -- Create: `tests/tcm-reading-pages.test.js` - -- [ ] **Step 1: Write the failing TCM reading-page tests** - -```js -// tests/tcm-reading-pages.test.js -describe('tcm reading pages', () => { - afterEach(() => { - delete global.Page - delete global.wx - jest.resetModules() - }) - - test('book detail, search and section pages use static scenes instead of business ids', () => { - global.Page = () => {} - - const bookDetailModule = require('../packages/tcm/pages/book-detail/index') - const searchModule = require('../packages/tcm/pages/search-books/index') - const sectionModule = require('../packages/tcm/pages/section/index') - - expect(bookDetailModule.createTcmBookDetailPageData('classic-a')).toEqual( - expect.objectContaining({ scene: 'classic-a', title: '典籍详情' }) - ) - expect(searchModule.createTcmSearchBooksPageData('keyword-demo')).toEqual( - expect.objectContaining({ keyword: 'keyword-demo', title: '搜索典籍' }) - ) - expect(sectionModule.createTcmSectionPageData('reader-a')).toEqual( - expect.objectContaining({ scene: 'reader-a', title: '典籍阅读' }) - ) - }) -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/tcm-reading-pages.test.js` - -Expected: FAIL because the three reading-page modules do not exist yet. - -- [ ] **Step 3: Write the TCM reading-page implementation** - -```js -// packages/tcm/pages/book-detail/index.js -const { resolveScene } = require('../../../../utils/static-ux/shared') - -function createTcmBookDetailPageData(rawScene) { - const scene = resolveScene(rawScene, ['classic-a', 'classic-b'], 'classic-a') - - return { - title: '典籍详情', - scene, - book: { - title: scene === 'classic-a' ? '黄帝内经素问' : '伤寒论', - subtitle: '传世中医典籍 · 学习阅读入口' - }, - catalog: [ - { key: 'chapter-1', title: '上古天真论', children: ['节录一', '节录二'] }, - { key: 'chapter-2', title: '四气调神大论', children: ['节录一', '节录二'] } - ] - } -} - -Page({ - data: createTcmBookDetailPageData('classic-a'), - - onLoad(options) { - this.setData(createTcmBookDetailPageData(options.scene)) - } -}) - -module.exports = { - createTcmBookDetailPageData -} -``` - -```js -// packages/tcm/pages/search-books/index.js -function createTcmSearchBooksPageData(keyword) { - return { - title: '搜索典籍', - keyword: keyword || '', - history: ['黄帝内经', '伤寒论', '温病条辨'], - results: - keyword && keyword.trim() - ? [ - { key: 'result-1', title: '黄帝内经素问', subtitle: '书名命中' }, - { key: 'result-2', title: '黄帝内经灵枢', subtitle: '相关结果' } - ] - : [] - } -} - -Page({ - data: createTcmSearchBooksPageData(''), - - onLoad(options) { - this.setData(createTcmSearchBooksPageData(options.keyword || options.q)) - } -}) - -module.exports = { - createTcmSearchBooksPageData -} -``` - -```js -// packages/tcm/pages/section/index.js -const { resolveScene } = require('../../../../utils/static-ux/shared') - -function createTcmSectionPageData(rawScene) { - const scene = resolveScene(rawScene, ['reader-a', 'reader-b'], 'reader-a') - - return { - title: '典籍阅读', - scene, - toolbarVisible: false, - settings: { - fontScale: 1, - lineMode: 'normal', - bgMode: 'default' - }, - passages: - scene === 'reader-a' - ? ['上古之人,其知道者,法于阴阳,和于术数。', '食饮有节,起居有常,不妄作劳。'] - : ['伤寒者,太阳病也。', '太阳之为病,脉浮,头项强痛而恶寒。'] - } -} - -Page({ - data: createTcmSectionPageData('reader-a'), - - onLoad(options) { - this.setData(createTcmSectionPageData(options.scene)) - }, - - handleToolbarToggle() { - this.setData({ - toolbarVisible: !this.data.toolbarVisible - }) - } -}) - -module.exports = { - createTcmSectionPageData -} -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/tcm-reading-pages.test.js` - -Expected: PASS, with `scene`-based page data and reader toggles confirmed. - -- [ ] **Step 5: Commit** - -```bash -git add packages/tcm/pages/book-detail packages/tcm/pages/search-books packages/tcm/pages/section tests/tcm-reading-pages.test.js -git commit -m "feat: add tcm reading and search pages" -``` - -### Task 7: Build Mingli Domain And Learning Center Pages - -**Files:** -- Create: `packages/mingli/pages/hall/index.js` -- Create: `packages/mingli/pages/hall/index.json` -- Create: `packages/mingli/pages/hall/index.wxml` -- Create: `packages/mingli/pages/hall/index.wxss` -- Create: `packages/mingli/pages/bazi/index.js` -- Create: `packages/mingli/pages/bazi/index.json` -- Create: `packages/mingli/pages/bazi/index.wxml` -- Create: `packages/mingli/pages/bazi/index.wxss` -- Create: `packages/mingli/pages/book-detail/index.js` -- Create: `packages/mingli/pages/book-detail/index.json` -- Create: `packages/mingli/pages/book-detail/index.wxml` -- Create: `packages/mingli/pages/book-detail/index.wxss` -- Create: `packages/mingli/pages/search-books/index.js` -- Create: `packages/mingli/pages/search-books/index.json` -- Create: `packages/mingli/pages/search-books/index.wxml` -- Create: `packages/mingli/pages/search-books/index.wxss` -- Create: `packages/mingli/pages/section/index.js` -- Create: `packages/mingli/pages/section/index.json` -- Create: `packages/mingli/pages/section/index.wxml` -- Create: `packages/mingli/pages/section/index.wxss` -- Create: `packages/mingli/pages/interpret/index.js` -- Create: `packages/mingli/pages/interpret/index.json` -- Create: `packages/mingli/pages/interpret/index.wxml` -- Create: `packages/mingli/pages/interpret/index.wxss` -- Create: `packages/learning/pages/center/index.js` -- Create: `packages/learning/pages/center/index.json` -- Create: `packages/learning/pages/center/index.wxml` -- Create: `packages/learning/pages/center/index.wxss` -- Create: `tests/mingli-learning-pages.test.js` - -- [ ] **Step 1: Write the failing mingli and learning tests** - -```js -// tests/mingli-learning-pages.test.js -describe('mingli and learning pages', () => { - afterEach(() => { - delete global.Page - delete global.wx - jest.resetModules() - }) - - test('hall, bazi, interpret and learning center pages expose static route-first surfaces', () => { - global.Page = () => {} - - const hallModule = require('../packages/mingli/pages/hall/index') - const baziModule = require('../packages/mingli/pages/bazi/index') - const interpretModule = require('../packages/mingli/pages/interpret/index') - const learningModule = require('../packages/learning/pages/center/index') - - expect(hallModule.createMingliHallPageData()).toEqual( - expect.objectContaining({ title: '易学阁' }) - ) - expect(baziModule.createMingliBaziPageData('result')).toEqual( - expect.objectContaining({ scene: 'result', title: '八字排盘' }) - ) - expect(interpretModule.createMingliInterpretPageData('result')).toEqual( - expect.objectContaining({ scene: 'result', title: '命理解读' }) - ) - expect(learningModule.createLearningCenterPageData()).toEqual( - expect.objectContaining({ title: '学习中心' }) - ) - }) -}) -``` - -- [ ] **Step 2: Run the targeted tests to verify they fail** - -Run: `npm test -- tests/mingli-learning-pages.test.js` - -Expected: FAIL because the mingli and learning page modules do not exist yet. - -- [ ] **Step 3: Write the mingli and learning implementation** - -```js -// packages/mingli/pages/hall/index.js -const { createMingliHallPageData } = require('../../../../utils/static-ux/mingli') - -Page({ - data: createMingliHallPageData() -}) - -module.exports = { - createMingliHallPageData -} -``` - -```js -// packages/mingli/pages/bazi/index.js -const { resolveScene } = require('../../../../utils/static-ux/shared') - -function createMingliBaziPageData(rawScene) { - const scene = resolveScene(rawScene, ['default', 'result'], 'default') - - return { - title: '八字排盘', - scene, - form: { - name: '张三', - gender: '男', - birthDate: '1990-01-01', - birthTime: '08:30' - }, - result: - scene === 'result' - ? { - pillars: [ - { key: 'year', label: '年柱', value: '庚午' }, - { key: 'month', label: '月柱', value: '戊寅' }, - { key: 'day', label: '日柱', value: '甲辰' }, - { key: 'time', label: '时柱', value: '丁卯' } - ] - } - : null - } -} - -Page({ - data: createMingliBaziPageData('default'), - - onLoad(options) { - this.setData(createMingliBaziPageData(options.scene)) - }, - - handleSubmitTap() { - this.setData(createMingliBaziPageData('result')) - } -}) - -module.exports = { - createMingliBaziPageData -} -``` - -```js -// packages/mingli/pages/interpret/index.js -const { resolveScene } = require('../../../../utils/static-ux/shared') - -function createMingliInterpretPageData(rawScene) { - const scene = resolveScene(rawScene, ['default', 'result'], 'default') - - return { - title: '命理解读', - scene, - question: '', - result: - scene === 'result' - ? { - title: '学习型解读', - summary: '围绕日主与经典段落给出静态说明。' - } - : null - } -} - -Page({ - data: createMingliInterpretPageData('default'), - - onLoad(options) { - this.setData(createMingliInterpretPageData(options.scene)) - }, - - handleSubmitTap() { - this.setData(createMingliInterpretPageData('result')) - } -}) - -module.exports = { - createMingliInterpretPageData -} -``` - -```js -// packages/learning/pages/center/index.js -const { createLearningCenterPageData } = require('../../../../utils/static-ux/learning') - -Page({ - data: createLearningCenterPageData() -}) - -module.exports = { - createLearningCenterPageData -} -``` - -- [ ] **Step 4: Run the targeted tests to verify they pass** - -Run: `npm test -- tests/mingli-learning-pages.test.js` - -Expected: PASS, with the mingli and learning pages exposed as static route-first surfaces. - -- [ ] **Step 5: Commit** - -```bash -git add packages/mingli packages/learning tests/mingli-learning-pages.test.js -git commit -m "feat: add mingli and learning static pages" -``` - -### Task 8: Full Verification And Integration Sweep - -**Files:** -- Modify: any files required to fix failing tests or lint issues from prior tasks -- Test: all touched files under `pages/`, `packages/`, `utils/static-ux/`, `tests/`, `app.json`, `app.wxss` - -- [ ] **Step 1: Run the focused render and data suites** - -Run: `npm test -- tests/home-page.test.js tests/home-page-render.test.js tests/library-page.test.js tests/library-page-render.test.js tests/ai-page.test.js tests/ai-page-render.test.js tests/profile-page.test.js tests/profile-page-render.test.js tests/login-page.test.js tests/login-page-render.test.js tests/tcm-support-pages.test.js tests/tcm-reading-pages.test.js tests/mingli-learning-pages.test.js tests/static-ux-route-map.test.js tests/static-ux-domain-data.test.js tests/project-config.test.js` - -Expected: PASS with all migration-related tests green. - -- [ ] **Step 2: Run the full repository test suite** - -Run: `npm test` - -Expected: PASS with zero failing Jest suites. - -- [ ] **Step 3: Run the repository linter** - -Run: `npm run lint` - -Expected: exit code `0` and no lint errors. - -- [ ] **Step 4: Perform the route and manual UX checklist** - -```text -1. 打开首页,确认能看到并点击进入:中医馆、易学阁、八字排盘、学习中心。 -2. 打开典籍 tab,确认能进入中医搜索页和易学阁入口。 -3. 打开 AI tab,确认历史按钮进入中医 AI 历史页,命理解读入口可达。 -4. 打开我的 tab,确认资产、AI 历史、学习中心、占位说明页都可达。 -5. 打开 tcm 和 mingli 页,确认没有真实登录、接口、store、mock session 逻辑。 -6. 检查所有页面参数都只使用 scene / mode / kind / keyword 这类静态参数。 -``` - -- [ ] **Step 5: Create the final feature commit** - -```bash -git add app.json app.wxss pages/home pages/library pages/ai pages/profile pages/login packages/tcm packages/mingli packages/learning utils/static-ux tests/static-ux-route-map.test.js tests/static-ux-domain-data.test.js tests/home-page.test.js tests/home-page-render.test.js tests/library-page.test.js tests/library-page-render.test.js tests/ai-page.test.js tests/ai-page-render.test.js tests/profile-page.test.js tests/profile-page-render.test.js tests/login-page.test.js tests/login-page-render.test.js tests/tcm-support-pages.test.js tests/tcm-reading-pages.test.js tests/mingli-learning-pages.test.js tests/project-config.test.js -git commit -m "feat: migrate frontend static pages into miniprogram" -``` diff --git a/AGENTS.md b/AGENTS.md index 71d2dfd..31964a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -107,9 +107,7 @@ flowchart LR | 路径 | 用途 | 说明 | |:---|:---|:---| -| `.ai-specs/coding-specs/2026-04-22-profile-page-static-design.md` | `pages/profile/index` 未登录态静态页面设计 | 涉及本页结构复刻、静态数据组织、样式边界与验收范围时必读 | -| `.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-design.md` | `frontend` 老项目静态页面迁移设计 | 涉及旧项目页面迁移、分包归属、静态数据边界、导航与交互约束时必读 | -| `.ai-specs/coding-specs/2026-04-23-frontend-static-page-migration-implementation-plan.md` | `frontend` 老项目静态页面迁移实施计划 | 涉及实现顺序、文件落点、测试策略和分任务执行时必读 | + ### 后端接口文档 D:\Code3\wdp\xuanzhi-service\.worktrees\feat-xuanzhi-service\server\.ai-specs\doc-dict 字典参考