# 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" ```