소스 검색

test(e2e): 新增健康营养师流程测试 + E2E场景矩阵文档

Xiaogang Liao 2 달 전
부모
커밋
9f8ca9c

+ 295 - 0
tests/E2E-TEST-SCENARIOS.md

@@ -0,0 +1,295 @@
+# E2E 测试场景矩阵 — 角色 × 功能 × 场景
+
+**版本**: v2.0(新增健康营养师角色)
+**更新**: 2026-07-04
+**覆盖**: 6角色 × 19功能域 × 90+场景
+
+---
+
+## 一、角色权限总览
+
+| 角色 | 说明 | vendor_type | 核心能力 |
+|------|------|-------------|---------|
+| `parent` | 家长 | — | 家庭管理、任务、积分、测评、购买 |
+| `child` | 孩子 | — | 任务执行、打卡、心愿、游戏 |
+| `teacher` | 成长规划师 | `planner` | 绑定家庭、下发任务、录入测评 |
+| `nutritionist` | 健康营养师 | `nutritionist` ⬅️ 新增 | 营养评估、食谱管理、饮食指导 |
+| `vendor` | 供应商 | `product_supplier` / `activity_provider` / `consultant` | 商品/活动管理 |
+| `admin` | 管理员 | — | 全系统管理 |
+
+---
+
+## 二、健康营养师(Nutritionist)场景矩阵 ⬅️ 新增
+
+> **定位**:专注于"身"维度的专业服务商,为家庭提供精准营养指导
+
+| 场景ID | 用户故事 | API端点 | 优先级 | 测试文件 |
+|--------|---------|---------|--------|---------|
+| US-NUTR-01 | 查看家庭营养档案 | `POST /api/nutrition/profile/get` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-02 | 保存营养偏好 | `POST /api/nutrition/profile/save` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-03 | 添加饮食记录 | `POST /api/diet/record/create` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-04 | 查看饮食记录列表 | `POST /api/diet/record/list` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-05 | 分析营养摄入 | `POST /api/nutrition/analyze` | P1 | nutritionist-flow.spec.js |
+| US-NUTR-06 | 创建食谱 | `POST /api/admin/recipes/create` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-07 | 管理食谱库 | `POST /api/admin/recipes/*` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-08 | 查看应季食材 | `POST /api/admin/seasonal/list` | P1 | nutritionist-flow.spec.js |
+| US-NUTR-09 | 获取饮食推荐 | `POST /api/meal/recommend` | P0 | nutritionist-flow.spec.js |
+| US-NUTR-10 | 绑定家庭 | `POST /api/bind/accept` | P0 | nutritionist-flow.spec.js |
+
+---
+
+## 三、按角色的场景矩阵
+
+### 3.1 家长(Parent)场景
+
+#### 家庭管理(UC-01)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-FAM-01 | 添加家庭成员 | P0 | family-member-management.spec.js | ✅ 完成 |
+| US-FAM-02 | 查看家庭成员列表 | P0 | family-member-management.spec.js | ✅ 完成 |
+| US-FAM-03 | 切换孩子视图 | P0 | family-member-management.spec.js | ✅ 完成 |
+| US-FAM-04 | 移除家庭成员 | P0 | family-member-management.spec.js | ✅ 完成 |
+| US-FAM-05 | 获取关系类型字典 | P0 | family-member-management.spec.js | ✅ 完成 |
+| US-FAM-06 | 生成/使用家庭邀请码 | P1 | — | 📋 需补充 |
+| US-FAM-07 | 编辑家庭成员关系 | P1 | — | 📋 需补充 |
+
+#### 任务管理(UC-02)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-TASK-01 | 创建任务 | P0 | daily-checkin-streak.spec.js | ⚠️ 部分 |
+| US-TASK-04 | 审核任务 | P0 | — | 📋 需补充 |
+| US-TASK-05 | 查看待审核列表 | P0 | — | 📋 需补充 |
+| US-TASK-06 | 查看任务历史 | P1 | — | 📋 需补充 |
+| US-TASK-08 | 家长任务 | P1 | — | 📋 需补充 |
+
+#### 心愿管理(UC-03)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-WISH-01 | 孩子创建心愿 | P0 | wish-exchange-flow.spec.js | ✅ 完成 |
+| US-WISH-02 | 家长定价心愿 | P0 | wish-exchange-flow.spec.js | ✅ 完成 |
+| US-WISH-03 | 家长拒绝心愿 | P1 | — | 📋 需补充 |
+| US-WISH-04 | 孩子申请兑换 | P0 | wish-exchange-flow.spec.js | ✅ 完成 |
+| US-WISH-05 | 家长审批兑换 | P0 | wish-exchange-flow.spec.js | ✅ 完成 |
+
+#### 积分系统(UC-04)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-POINTS-01 | 查看积分余额 | P0 | points-system.spec.js | ✅ 新增 |
+| US-POINTS-02 | 查看积分流水 | P0 | points-system.spec.js | ✅ 新增 |
+| US-POINTS-03 | 手动调整积分 | P1 | points-system.spec.js | ✅ 新增 |
+| US-POINTS-04 | 按分类查看流水 | P2 | points-system.spec.js | ✅ 新增 |
+
+#### 测评流程(UC-07)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-ASSESS-01 | 创建测评订单 | P0 | assessment-order-flow.spec.js | ✅ 完成 |
+| US-ASSESS-02 | 支付测评订单 | P0 | assessment-order-flow.spec.js | ✅ 完成 |
+| US-ASSESS-03 | 查看订单详情 | P1 | — | 📋 需补充 |
+| US-ASSESS-04 | 取消测评订单 | P1 | — | 📋 需补充 |
+| US-ASSESS-05 | 申请退款 | P1 | — | 📋 需补充 |
+| US-ASSESS-08 | 查看测评结果 | P0 | assessment-order-flow.spec.js | ✅ 完成 |
+
+#### 成长档案(UC-08)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-GROWTH-01 | 创建成长档案 | P0 | growth-record-sync.spec.js | ✅ 完成 |
+| US-GROWTH-02 | 上传PDF解析 | P0 | — | 📋 需补充 |
+| US-GROWTH-04 | 查看档案列表 | P0 | growth-record-sync.spec.js | ✅ 完成 |
+| US-GROWTH-05 | 补充记录 | P1 | — | 📋 需补充 |
+
+#### 文章管理(UC-09)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-ARTICLE-07 | 浏览文章列表 | P0 | article-management.spec.js | ✅ 新增 |
+| US-ARTICLE-08 | 查看文章详情 | P0 | article-management.spec.js | ✅ 新增 |
+| US-ARTICLE-09 | 每日成长贴士 | P1 | — | 📋 需补充 |
+
+#### 活动报名(UC-10)
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-ACT-03 | 浏览活动 | P0 | activity-registration.spec.js | ✅ 新增 |
+| US-ACT-04 | 报名活动 | P0 | activity-registration.spec.js | ✅ 新增 |
+| US-ACT-05 | 取消报名 | P1 | activity-registration.spec.js | ✅ 新增 |
+| US-ACT-07 | 查看我的报名 | P1 | — | 📋 需补充 |
+
+---
+
+### 3.2 孩子(Child)场景
+
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-TASK-02 | 查看今日任务 | P0 | mini-games-full.spec.js | ✅ 新增 |
+| US-TASK-03 | 完成任务 | P0 | — | 📋 需补充 |
+| US-WISH-01 | 创建心愿 | P0 | wish-exchange-flow.spec.js | ✅ 完成 |
+| US-CHECKIN-01 | 健康打卡 | P0 | daily-checkin-streak.spec.js | ✅ 完成 |
+| US-ENERGY-01 | 查看能量总览 | P0 | energy-system.spec.js | ⚠️ 部分 |
+| US-GAME-01 | 舒尔特方格 | P1 | mini-games-full.spec.js | ✅ 新增 |
+| US-GAME-02 | 猜数字 | P1 | mini-games-full.spec.js | ✅ 新增 |
+| US-GAME-03 | 数独 | P1 | mini-games-full.spec.js | ✅ 新增 |
+
+---
+
+### 3.3 健康营养师(Nutritionist)场景 ⬅️ 新增
+
+| 场景ID | 用户故事 | 优先级 | 测试文件 |
+|--------|---------|--------|---------|
+| US-NUTR-01~10 | 营养档案/饮食记录/食谱/推荐/绑定 | P0~P1 | nutritionist-flow.spec.js |
+
+---
+
+### 3.4 管理员(Admin)场景
+
+| 场景ID | 用户故事 | 优先级 | 测试文件 | 状态 |
+|--------|---------|--------|---------|------|
+| US-ARTICLE-01 | 创建文章 | P0 | article-management.spec.js | ✅ 新增 |
+| US-ARTICLE-02 | 发布文章 | P0 | article-management.spec.js | ✅ 新增 |
+| US-ACT-01 | 创建活动 | P0 | activity-registration.spec.js | ✅ 新增 |
+| US-ACT-02 | 发布活动 | P0 | activity-registration.spec.js | ✅ 新增 |
+| US-ADMIN-01 | 创建用户 | P0 | admin-panel.spec.js | ✅ 新增 |
+| US-ADMIN-02 | 用户列表 | P0 | admin-panel.spec.js | ✅ 新增 |
+| US-ADMIN-05 | 数据看板 | P1 | admin-panel.spec.js | ✅ 新增 |
+| US-ENERGYRULE-01~04 | 能量规则CRUD | P1 | energy-rules-config.spec.js | ✅ 新增 |
+| US-GUIDE-02 | 审核规划师 | P0 | admin-panel.spec.js | ⚠️ 部分 |
+| US-VENDOR-03 | 审核供应商 | P0 | vendor-onboarding.spec.js | ✅ 新增 |
+
+---
+
+## 四、E2E 测试文件清单
+
+| 文件 | 覆盖场景数 | 状态 |
+|------|-----------|------|
+| assessment-order-flow.spec.js | 7 | ✅ 完成 |
+| family-member-management.spec.js | 9 | ✅ 完成 |
+| wish-exchange-flow.spec.js | 9 | ⚠️ 需补充孩子侧 |
+| planner-bind-invite.spec.js | 7 | ⚠️ 需补充管理员审核 |
+| growth-record-sync.spec.js | 6 | ✅ 完成 |
+| energy-system.spec.js | 6 | ⚠️ 需补充维度配置 |
+| product-purchase.spec.js | 9 | ⚠️ 需补充供应商入驻 |
+| daily-checkin-streak.spec.js | 8 | ⚠️ 需补充补打卡 |
+| mini-games-playwright.spec.js | 部分 | ⚠️ 需补充完整流程 |
+| **nutritionist-flow.spec.js** | 10 | 🆕 新增 |
+| **article-management.spec.js** | 5 | 🆕 新增 |
+| **activity-registration.spec.js** | 4 | 🆕 新增 |
+| **points-system.spec.js** | 4 | 🆕 新增 |
+| **admin-panel.spec.js** | 5 | 🆕 新增 |
+| **vendor-onboarding.spec.js** | 3 | 🆕 新增 |
+| **energy-rules-config.spec.js** | 4 | 🆕 新增 |
+| **membership-system.spec.js** | 3 | 🆕 新增 |
+| **contact-management.spec.js** | 4 | 🆕 新增 |
+| **mini-games-full.spec.js** | 5 | 🆕 新增 |
+
+**总计**: 20个测试文件,100+场景
+
+---
+
+## 五、缺失场景清单(按优先级)
+
+### 高优先级(P0)
+- [ ] 管理员审核文章发布
+- [ ] 管理员审核报名
+- [ ] 能量规则配置完整
+- [ ] 健康营养师10场景
+
+### 中优先级(P1)
+- [ ] 供应商入驻完整流程
+- [ ] 会员购买/试用
+- [ ] 小游戏完整流程
+- [ ] 补打卡场景
+- [ ] 批量任务操作
+
+### 低优先级(P2)
+- [ ] 联系人管理
+- [ ] 数据导出
+- [ ] 邀请码使用
+
+---
+
+## 六、测试账号
+
+| 角色 | 手机号 | userId | 说明 |
+|------|--------|--------|------|
+| 管理员 | 13800138000 | 7 | Web管理端全权限 |
+| 家长 | 13701366188 | 8 | 有家庭/孩子 |
+| 供应商 | 13800138001 | 81069 | vendor_status=pending |
+| 营养师 | 待创建 | 待分配 | vendor_type=nutritionist |
+
+---
+
+## 七、测试环境
+
+- **后端**: `http://localhost:9082`
+- **前端**: `http://localhost:8080`
+- **环境**: 开发环境(development)
+
+---
+
+## 八、运行指南
+
+```bash
+# 运行所有E2E测试
+npx playwright test tests/e2e/
+
+# 运行特定测试文件
+npx playwright test tests/e2e/nutritionist-flow.spec.js
+
+# 运行带UI模式
+npx playwright test tests/e2e/ --headed
+
+# 运行特定标签
+npx playwright test tests/e2e/ --grep "场景1"
+
+# 生成HTML报告
+npx playwright test tests/e2e/ --reporter=html
+```
+
+---
+
+## 九、CSS选择器参考
+
+### 通用选择器
+```css
+.submit-btn      /* 提交按钮 */
+.confirm-btn      /* 确认按钮 */
+.success-tip      /* 成功提示 */
+.error-tip        /* 错误提示 */
+.toast-success     /* Toast成功 */
+```
+
+### 页面容器
+```css
+.assessment-apply-page  /* 测评申请页 */
+.nutrition-profile-page /* 营养偏好页 */
+.meal-record-page       /* 饮食记录页 */
+.article-list           /* 文章列表 */
+.activity-list          /* 活动列表 */
+```
+
+### 表单元素
+```css
+input[name="xxx"]      /* 输入框 */
+select[name="xxx"]      /* 选择器 */
+textarea[name="xxx"]    /* 文本域 */
+.child-picker           /* 孩子选择器 */
+```
+
+---
+
+## 十、Milestone标记规范
+
+```javascript
+// 每个关键里程碑用以下注释标记:
+// ========== Then:Milestone-1 ========
+// ========== Then:Milestone-2 ========
+// ...
+```
+
+---
+
+## 十一、更新日志
+
+### v2.0 (2026-07-04)
+- ✅ 新增健康营养师(Nutritionist)角色
+- ✅ 新增10个营养师场景(US-NUTR-01~10)
+- ✅ 新增9个E2E测试文件
+- ✅ 新增场景矩阵文档
+- ⚠️ 待补充现有测试文件的缺失场景

+ 168 - 0
tests/e2e/activity-registration.spec.js

@@ -0,0 +1,168 @@
+/**
+ * ================================================================
+ * 场景:活动报名全流程 E2E 测试
+ * ================================================================
+ * 用户故事:
+ *   - 管理员:创建/发布活动,审核报名
+ *   - 家长/孩子:浏览活动,报名/取消报名
+ *
+ * 流程步骤:
+ *   1. 管理员创建并发布活动
+ *   2. 家长浏览活动并报名
+ *   3. 管理员审核报名
+ *   4. 家长取消报名
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 活动发布成功
+ *   - [Milestone-2] 报名成功
+ *   - [Milestone-3] 审核成功
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/activity-registration.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】活动报名全流程', () => {
+
+  // ===== 场景1:管理员创建并发布活动 =====
+
+  test('[场景1] 管理员创建并发布活动 - 期望发布成功', async ({ page }) => {
+    // ========== Given:管理员进入活动管理页 ==========
+    await page.goto('/#/pages/admin/activity-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建活动 ==========
+    const createBtn = page.locator('.create-btn, .add-activity-btn');
+    if (await createBtn.isVisible()) {
+      await createBtn.click();
+    } else {
+      await page.goto('/#/pages/admin/activity-create');
+      await page.waitForLoadState('networkidle');
+    }
+
+    await page.waitForSelector('.activity-form, .create-form', { timeout: 5000 });
+
+    // 填写活动名称
+    const titleInput = page.locator('input[name="title"], .title-input');
+    if (await titleInput.isVisible()) {
+      await titleInput.fill('测试活动_' + Date.now());
+    }
+
+    // 填写活动描述
+    const descInput = page.locator('textarea[name="description"], .desc-input');
+    if (await descInput.isVisible()) {
+      await descInput.fill('这是一个测试活动,描述活动的具体内容。');
+    }
+
+    // 填写地点
+    const locationInput = page.locator('input[name="location"], .location-input');
+    if (await locationInput.isVisible()) {
+      await locationInput.fill('线上活动');
+    }
+
+    // 填写人数上限
+    const maxInput = page.locator('input[name="maxParticipants"], .max-input');
+    if (await maxInput.isVisible()) {
+      await maxInput.fill('50');
+    }
+
+    // 发布活动
+    await page.click('.publish-btn, .submit-btn');
+
+    // ========== Then:Milestone-1 - 发布成功 ========
+    await page.waitForSelector('.success-tip, .publish-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .publish-success').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景2:家长浏览活动并报名 =====
+
+  test('[场景2] 家长浏览活动并报名 - 期望报名成功', async ({ page }) => {
+    // ========== Given:家长进入活动列表页 ==========
+    await page.goto('/#/pages/discover-detail/activity-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:浏览并选择活动 ==========
+    await page.waitForSelector('.activity-item, .activity-card', { timeout: 10000 });
+
+    // 点击第一个活动
+    await page.locator('.activity-item').first().click();
+
+    // 等待活动详情加载
+    await page.waitForSelector('.activity-detail, .detail-content', { timeout: 5000 });
+
+    // 点击报名按钮
+    const registerBtn = page.locator('.register-btn, .sign-up-btn, .apply-btn');
+    if (await registerBtn.isVisible()) {
+      await registerBtn.click();
+    }
+
+    // 选择孩子
+    const childSelect = page.locator('.child-picker, .select-child');
+    if (await childSelect.isVisible()) {
+      await childSelect.click();
+      await page.waitForSelector('.child-option', { timeout: 3000 });
+      await page.locator('.child-option').first().click();
+    }
+
+    // 确认报名
+    await page.click('.confirm-btn, .submit-btn');
+
+    // ========== Then:Milestone-2 - 报名成功 ========
+    await page.waitForSelector('.success-tip, .register-success, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .register-success').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:管理员审核报名 =====
+
+  test('[场景3] 管理员审核报名 - 期望审核成功', async ({ page }) => {
+    // ========== Given:管理员进入报名管理页 ==========
+    await page.goto('/#/pages/admin/registration-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:审核报名 ==========
+    await page.waitForSelector('.registration-item, .apply-item', { timeout: 10000 });
+
+    const approveBtn = page.locator('.approve-btn, .pass-btn').first();
+    if (await approveBtn.isVisible()) {
+      await approveBtn.click();
+    }
+
+    // ========== Then:Milestone-3 - 审核成功 ========
+    await page.waitForTimeout(500);
+
+    // 验证状态变化
+    const statusTag = page.locator('.status-tag, .registration-status');
+    if (await statusTag.isVisible()) {
+      const statusText = await statusTag.textContent();
+      expect(statusText).toMatch(/已通过|approved/i);
+    }
+  });
+
+  // ===== 场景4:家长取消报名 =====
+
+  test('[场景4] 家长取消报名 - 期望取消成功', async ({ page }) => {
+    // ========== Given:家长进入我的报名页 ==========
+    await page.goto('/#/pages/profile/my-activities');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:取消报名 ==========
+    await page.waitForSelector('.registration-item, .my-activity', { timeout: 10000 });
+
+    const cancelBtn = page.locator('.cancel-btn, .cancel-registration').first();
+    if (await cancelBtn.isVisible()) {
+      await cancelBtn.click();
+    }
+
+    // 确认取消
+    const confirmBtn = page.locator('.van-dialog__confirm, .dialog-confirm');
+    if (await confirmBtn.isVisible()) {
+      await confirmBtn.click();
+    }
+
+    // ========== Then:取消成功 ========
+    await page.waitForSelector('.cancel-success, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.cancel-success, .toast-success').isVisible()).toBeTruthy();
+  });
+
+});

+ 162 - 0
tests/e2e/admin-panel.spec.js

@@ -0,0 +1,162 @@
+/**
+ * ================================================================
+ * 场景:后台管理全流程 E2E 测试
+ * ================================================================
+ * 用户故事:管理员进行用户管理、数据看板、能量规则配置等
+ *
+ * 流程步骤:
+ *   1. 管理员创建用户
+ *   2. 管理员查看用户列表
+ *   3. 管理员查看数据看板
+ *   4. 能量规则CRUD
+ *   5. 系统健康检查
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 用户创建成功
+ *   - [Milestone-2] 规则管理成功
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/admin-panel.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】后台管理全流程', () => {
+
+  // ===== 场景1:管理员创建用户 =====
+
+  test('[场景1] 管理员创建用户 - 期望创建成功', async ({ page }) => {
+    // ========== Given:管理员进入用户管理页 ==========
+    await page.goto('/#/pages/admin/user-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建用户 ==========
+    const createBtn = page.locator('.create-btn, .add-user-btn');
+    if (await createBtn.isVisible()) {
+      await createBtn.click();
+    } else {
+      await page.goto('/#/pages/admin/user-create');
+      await page.waitForLoadState('networkidle');
+    }
+
+    await page.waitForSelector('.user-form, .create-form', { timeout: 5000 });
+
+    // 填写用户信息
+    const phoneInput = page.locator('input[name="phone"], .phone-input');
+    if (await phoneInput.isVisible()) {
+      await phoneInput.fill('138' + String(Date.now()).slice(-8));
+    }
+
+    const nameInput = page.locator('input[name="nickname"], .name-input');
+    if (await nameInput.isVisible()) {
+      await nameInput.fill('测试用户_' + Date.now());
+    }
+
+    // 选择角色
+    const roleSelect = page.locator('.role-picker, select[name="role"]');
+    if (await roleSelect.isVisible()) {
+      await roleSelect.selectOption('parent');
+    }
+
+    // 提交
+    await page.click('.submit-btn, .save-btn');
+
+    // ========== Then:Milestone-1 - 创建成功 ========
+    await page.waitForSelector('.success-tip, .create-success, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .create-success').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景2:管理员查看用户列表 =====
+
+  test('[场景2] 管理员查看用户列表 - 期望返回分页列表', async ({ page }) => {
+    // ========== Given:管理员进入用户列表页 ==========
+    await page.goto('/#/pages/admin/user-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看列表 ==========
+    await page.waitForSelector('.user-list, .user-item', { timeout: 10000 });
+
+    // ========== Then:返回用户列表 ========
+    const userItems = page.locator('.user-item, .user-row');
+    const count = await userItems.count();
+
+    expect(count).toBeGreaterThan(0);
+  });
+
+  // ===== 场景3:管理员查看数据看板 =====
+
+  test('[场景3] 管理员查看数据看板 - 期望返回统计数据', async ({ page }) => {
+    // ========== Given:管理员进入看板页 ==========
+    await page.goto('/#/pages/admin/dashboard');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看看板 ==========
+    await page.waitForSelector('.dashboard-card, .stat-card, .data-overview', { timeout: 10000 });
+
+    // ========== Then:返回统计数据 ========
+    const statCards = page.locator('.stat-card, .dashboard-card');
+    const count = await statCards.count();
+
+    expect(count).toBeGreaterThan(0);
+  });
+
+  // ===== 场景4:能量规则CRUD =====
+
+  test('[场景4] 能量规则CRUD - 期望规则管理成功', async ({ page }) => {
+    // ========== Given:管理员进入能量规则页 ==========
+    await page.goto('/#/pages/admin/energy-rules');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建规则 ==========
+    const createBtn = page.locator('.create-btn, .add-rule-btn');
+    if (await createBtn.isVisible()) {
+      await createBtn.click();
+    } else {
+      await page.goto('/#/pages/admin/energy-rule-create');
+      await page.waitForLoadState('networkidle');
+    }
+
+    await page.waitForSelector('.rule-form', { timeout: 5000 });
+
+    // 填写规则信息
+    const nameInput = page.locator('input[name="name"], .rule-name-input');
+    if (await nameInput.isVisible()) {
+      await nameInput.fill('测试规则_' + Date.now());
+    }
+
+    const valueInput = page.locator('input[name="energyValue"], .value-input');
+    if (await valueInput.isVisible()) {
+      await valueInput.fill('5');
+    }
+
+    await page.click('.submit-btn, .save-btn');
+
+    // ========== Then:Milestone-2 - 规则创建成功 ========
+    await page.waitForSelector('.success-tip, .rule-created', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .rule-created').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景5:系统健康检查 =====
+
+  test('[场景5] 系统健康检查 - 期望返回健康状态', async ({ page }) => {
+    // ========== Given:管理员进入健康检查页 ==========
+    await page.goto('/#/pages/admin/health-check');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:执行检查 ==========
+    const checkBtn = page.locator('.check-btn, .run-check-btn');
+    if (await checkBtn.isVisible()) {
+      await checkBtn.click();
+    }
+
+    // ========== Then:返回健康状态 ========
+    await page.waitForSelector('.health-status, .check-result', { timeout: 15000 });
+
+    const statusBadge = page.locator('.status-badge, .health-badge');
+    if (await statusBadge.isVisible()) {
+      const statusText = await statusBadge.textContent();
+      expect(statusText).toBeTruthy();
+    }
+  });
+
+});

+ 185 - 0
tests/e2e/article-management.spec.js

@@ -0,0 +1,185 @@
+/**
+ * ================================================================
+ * 场景:文章管理全流程 E2E 测试
+ * ================================================================
+ * 用户故事:
+ *   - 管理员:创建/发布/编辑/删除/精选文章
+ *   - 用户:浏览文章列表,查看文章详情,获取每日贴士
+ *
+ * 流程步骤:
+ *   1. 管理员创建文章并发布
+ *   2. 管理员管理文章分类
+ *   3. 管理员设置精选文章
+ *   4. 用户浏览文章列表
+ *   5. 用户查看文章详情
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 文章发布成功
+ *   - [Milestone-2] 文章精选设置成功
+ *   - [Milestone-3] 用户成功浏览文章
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/article-management.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】文章管理全流程', () => {
+
+  // ===== 场景1:管理员创建并发布文章 =====
+
+  test('[场景1] 管理员创建并发布文章 - 期望发布成功', async ({ page }) => {
+    // ========== Given:管理员进入文章管理页面 ==========
+    await page.goto('/#/pages/admin/article-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建并发布文章 ==========
+    const createBtn = page.locator('.create-btn, .add-article-btn');
+    if (await createBtn.isVisible()) {
+      await createBtn.click();
+    } else {
+      await page.goto('/#/pages/admin/article-create');
+      await page.waitForLoadState('networkidle');
+    }
+
+    await page.waitForSelector('.article-form, .create-form', { timeout: 5000 });
+
+    // 填写标题
+    const titleInput = page.locator('input[name="title"], .title-input');
+    if (await titleInput.isVisible()) {
+      await titleInput.fill('测试文章_' + Date.now());
+    }
+
+    // 填写摘要
+    const summaryInput = page.locator('textarea[name="summary"], .summary-input');
+    if (await summaryInput.isVisible()) {
+      await summaryInput.fill('这是文章摘要内容,描述文章的核心要点。');
+    }
+
+    // 填写内容
+    const contentInput = page.locator('textarea[name="content"], .content-input');
+    if (await contentInput.isVisible()) {
+      await contentInput.fill('这是文章的正文内容,包含详细的信息和说明。');
+    }
+
+    // 选择分类
+    const categorySelect = page.locator('.category-picker, select[name="category"]');
+    if (await categorySelect.isVisible()) {
+      await categorySelect.click();
+      await page.waitForSelector('.option-item', { timeout: 3000 });
+      await page.locator('.option-item').first().click();
+    }
+
+    // 发布文章
+    await page.click('.publish-btn, .submit-btn');
+
+    // ========== Then:Milestone-1 - 发布成功 ========
+    await page.waitForSelector('.success-tip, .publish-success, .toast-success', { timeout: 10000 });
+    const successTip = page.locator('.success-tip, .publish-success');
+    expect(await successTip.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景2:管理员管理文章分类 =====
+
+  test('[场景2] 管理员管理文章分类 - 期望分类创建成功', async ({ page }) => {
+    // ========== Given:管理员进入分类管理页面 ==========
+    await page.goto('/#/pages/admin/category-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建新分类 ==========
+    const addBtn = page.locator('.add-btn, .create-category-btn');
+    if (await addBtn.isVisible()) {
+      await addBtn.click();
+    }
+
+    await page.waitForSelector('.category-form, .create-form', { timeout: 5000 });
+
+    const nameInput = page.locator('input[name="name"], .category-name-input');
+    if (await nameInput.isVisible()) {
+      await nameInput.fill('测试分类_' + Date.now());
+    }
+
+    await page.click('.submit-btn, .save-btn');
+
+    // ========== Then:分类创建成功 ========
+    await page.waitForSelector('.success-tip, .create-success', { timeout: 10000 });
+    const successTip = page.locator('.success-tip, .create-success');
+    expect(await successTip.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:管理员设置精选文章 =====
+
+  test('[场景3] 管理员设置精选文章 - 期望精选状态切换成功', async ({ page }) => {
+    // ========== Given:管理员进入文章列表 ==========
+    await page.goto('/#/pages/admin/article-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:设置精选 ==========
+    await page.waitForSelector('.article-item', { timeout: 10000 });
+    const firstArticle = page.locator('.article-item').first();
+
+    const featuredBtn = firstArticle.locator('.featured-btn, .toggle-featured');
+    if (await featuredBtn.isVisible()) {
+      await featuredBtn.click();
+    }
+
+    // ========== Then:Milestone-2 - 精选设置成功 ========
+    await page.waitForTimeout(500);
+
+    // 验证精选标识变化
+    const featuredTag = firstArticle.locator('.featured-tag, .is-featured');
+    const isFeatured = await featuredTag.isVisible();
+    expect(isFeatured).toBeTruthy();
+  });
+
+  // ===== 场景4:用户浏览文章列表 =====
+
+  test('[场景4] 用户浏览文章列表 - 期望返回已发布文章', async ({ page }) => {
+    // ========== Given:用户进入文章列表页 ==========
+    await page.goto('/#/pages/mind/articles');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:浏览文章列表 ==========
+    await page.waitForSelector('.article-list, .article-item', { timeout: 10000 });
+
+    // ========== Then:Milestone-3 - 返回文章列表 ========
+    const articleItems = page.locator('.article-item, .article-card');
+    const count = await articleItems.count();
+
+    expect(count).toBeGreaterThan(0);
+
+    // 验证文章包含标题
+    const firstArticle = articleItems.first();
+    const title = firstArticle.locator('.article-title, .title');
+    if (await title.isVisible()) {
+      const titleText = await title.textContent();
+      expect(titleText.length).toBeGreaterThan(0);
+    }
+  });
+
+  // ===== 场景5:用户查看文章详情 =====
+
+  test('[场景5] 用户查看文章详情 - 期望返回完整文章内容', async ({ page }) => {
+    // ========== Given:用户进入文章详情页 ==========
+    await page.goto('/#/pages/mind/articles');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:点击文章查看详情 ==========
+    await page.waitForSelector('.article-item', { timeout: 10000 });
+    await page.locator('.article-item').first().click();
+
+    // ========== Then:返回完整文章详情 ========
+    await page.waitForSelector('.article-detail, .detail-content, .article-content', { timeout: 10000 });
+
+    const detailContent = page.locator('.article-detail, .detail-content');
+    expect(await detailContent.isVisible()).toBeTruthy();
+
+    // 验证包含正文内容
+    const articleBody = page.locator('.article-body, .content');
+    if (await articleBody.isVisible()) {
+      const bodyText = await articleBody.textContent();
+      expect(bodyText.length).toBeGreaterThan(0);
+    }
+  });
+
+});

+ 162 - 0
tests/e2e/contact-management.spec.js

@@ -0,0 +1,162 @@
+/**
+ * ================================================================
+ * 场景:联系人管理全流程 E2E 测试
+ * ================================================================
+ * 用户故事:家长管理社会联系人(朋友/同事/合作伙伴)
+ *
+ * 流程步骤:
+ *   1. 创建联系人
+ *   2. 通讯录导入
+ *   3. 记录互动
+ *   4. 编辑/删除联系人
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 联系人创建成功
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/contact-management.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】联系人管理全流程', () => {
+
+  // ===== 场景1:创建联系人 =====
+
+  test('[场景1] 创建联系人 - 期望创建成功', async ({ page }) => {
+    // ========== Given:进入联系人页 ==========
+    await page.goto('/#/pages/action/contact-detail');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建联系人 ==========
+    const addBtn = page.locator('.add-btn, .add-contact-btn');
+    if (await addBtn.isVisible()) {
+      await addBtn.click();
+    }
+
+    await page.waitForSelector('.contact-form', { timeout: 5000 });
+
+    // 填写姓名
+    const nameInput = page.locator('input[name="name"], .name-input');
+    if (await nameInput.isVisible()) {
+      await nameInput.fill('测试联系人_' + Date.now());
+    }
+
+    // 填写手机号
+    const phoneInput = page.locator('input[name="phone"], .phone-input');
+    if (await phoneInput.isVisible()) {
+      await phoneInput.fill('138' + String(Date.now()).slice(-8));
+    }
+
+    // 选择关系类型
+    const relationSelect = page.locator('.relation-picker, select[name="relationshipType"]');
+    if (await relationSelect.isVisible()) {
+      await relationSelect.selectOption('friend');
+    }
+
+    // 提交
+    await page.click('.submit-btn, .save-btn');
+
+    // ========== Then:Milestone-1 - 创建成功 ========
+    await page.waitForSelector('.success-tip, .contact-added, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .contact-added').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景2:通讯录导入 =====
+
+  test('[场景2] 通讯录导入 - 期望导入成功', async ({ page }) => {
+    // ========== Given:进入联系人导入页 ==========
+    await page.goto('/#/pages/action/contact-import');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:导入通讯录 ==========
+    const importBtn = page.locator('.import-btn, .import-contacts-btn');
+    if (await importBtn.isVisible()) {
+      await importBtn.click();
+    }
+
+    // 选择导入方式
+    const selectBtn = page.locator('.select-contacts-btn');
+    if (await selectBtn.isVisible()) {
+      await selectBtn.click();
+    }
+
+    // 选择要导入的联系人
+    await page.waitForSelector('.contact-item', { timeout: 5000 });
+    await page.locator('.contact-item').first().click();
+
+    // 确认导入
+    await page.click('.confirm-import-btn, .submit-btn');
+
+    // ========== Then:导入成功 ========
+    await page.waitForSelector('.success-tip, .import-success, .toast-success', { timeout: 15000 });
+    expect(await page.locator('.success-tip, .import-success').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:记录互动 =====
+
+  test('[场景3] 记录互动 - 期望记录成功', async ({ page }) => {
+    // ========== Given:进入联系人详情 ==========
+    await page.goto('/#/pages/action/contact-detail');
+    await page.waitForLoadState('networkidle');
+
+    // 选择一个联系人
+    await page.waitForSelector('.contact-item', { timeout: 5000 });
+    await page.locator('.contact-item').first().click();
+
+    // ========== When:记录互动 ==========
+    const interactBtn = page.locator('.interact-btn, .add-interaction');
+    if (await interactBtn.isVisible()) {
+      await interactBtn.click();
+    }
+
+    await page.waitForSelector('.interaction-form', { timeout: 5000 });
+
+    // 填写互动内容
+    const noteInput = page.locator('textarea[name="note"], .note-input');
+    if (await noteInput.isVisible()) {
+      await noteInput.fill('今天一起吃饭,讨论了合作事宜。');
+    }
+
+    await page.click('.submit-btn, .save-btn');
+
+    // ========== Then:记录成功 ========
+    await page.waitForSelector('.success-tip, .interaction-added', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .interaction-added').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景4:编辑/删除联系人 =====
+
+  test('[场景4] 编辑/删除联系人 - 期望操作成功', async ({ page }) => {
+    // ========== Given:进入联系人列表 ==========
+    await page.goto('/#/pages/action/contact-detail');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:编辑联系人 ==========
+    await page.waitForSelector('.contact-item', { timeout: 5000 });
+
+    const firstContact = page.locator('.contact-item').first();
+    const editBtn = firstContact.locator('.edit-btn');
+
+    if (await editBtn.isVisible()) {
+      await editBtn.click();
+    } else {
+      await firstContact.click();
+    }
+
+    await page.waitForSelector('.edit-form, .contact-form', { timeout: 5000 });
+
+    // 修改姓名
+    const nameInput = page.locator('input[name="name"], .name-input');
+    if (await nameInput.isVisible()) {
+      await nameInput.fill('已更新联系人_' + Date.now());
+    }
+
+    await page.click('.save-btn, .submit-btn');
+
+    // ========== Then:操作成功 ========
+    await page.waitForSelector('.success-tip, .update-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .update-success').isVisible()).toBeTruthy();
+  });
+
+});

+ 147 - 0
tests/e2e/energy-rules-config.spec.js

@@ -0,0 +1,147 @@
+/**
+ * ================================================================
+ * 场景:能量规则配置全流程 E2E 测试
+ * ================================================================
+ * 用户故事:管理员配置五维能量发放规则
+ *
+ * 流程步骤:
+ *   1. 查看能量规则列表
+ *   2. 创建新规则
+ *   3. 启用/禁用规则
+ *   4. 编辑/删除规则
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 返回规则列表
+ *   - [Milestone-2] 规则管理成功
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/energy-rules-config.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】能量规则配置全流程', () => {
+
+  // ===== 场景1:查看能量规则列表 =====
+
+  test('[场景1] 查看能量规则列表 - 期望返回规则列表', async ({ page }) => {
+    // ========== Given:管理员进入能量规则页 ==========
+    await page.goto('/#/pages/admin/energy-rules');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看规则列表 ==========
+    await page.waitForSelector('.rule-list, .energy-rule-list', { timeout: 10000 });
+
+    // ========== Then:Milestone-1 - 返回规则列表 ========
+    const ruleItems = page.locator('.rule-item, .energy-rule');
+    const count = await ruleItems.count();
+
+    expect(count).toBeGreaterThan(0);
+
+    // 验证规则包含维度信息
+    const firstRule = ruleItems.first();
+    const dimensionTag = firstRule.locator('.dimension-tag, .rule-type');
+    if (await dimensionTag.isVisible()) {
+      const tagText = await dimensionTag.textContent();
+      expect(tagText).toBeTruthy();
+    }
+  });
+
+  // ===== 场景2:创建能量规则 =====
+
+  test('[场景2] 创建能量规则 - 期望规则创建成功', async ({ page }) => {
+    // ========== Given:管理员进入创建规则页 ==========
+    await page.goto('/#/pages/admin/energy-rule-create');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:创建规则 ==========
+    await page.waitForSelector('.rule-form', { timeout: 5000 });
+
+    // 选择维度
+    const dimensionSelect = page.locator('.dimension-picker, select[name="dimension"]');
+    if (await dimensionSelect.isVisible()) {
+      await dimensionSelect.selectOption('body');
+    }
+
+    // 选择事件类型
+    const eventSelect = page.locator('.event-picker, select[name="eventType"]');
+    if (await eventSelect.isVisible()) {
+      await eventSelect.selectOption('checkin');
+    }
+
+    // 输入能量值
+    const valueInput = page.locator('input[name="energyValue"], .value-input');
+    if (await valueInput.isVisible()) {
+      await valueInput.fill('5');
+    }
+
+    // 提交
+    await page.click('.submit-btn, .save-btn');
+
+    // ========== Then:Milestone-2 - 创建成功 ========
+    await page.waitForSelector('.success-tip, .rule-created', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .rule-created').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:启用/禁用规则 =====
+
+  test('[场景3] 启用/禁用规则 - 期望状态切换成功', async ({ page }) => {
+    // ========== Given:管理员进入规则页 ==========
+    await page.goto('/#/pages/admin/energy-rules');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:切换规则状态 ==========
+    await page.waitForSelector('.rule-item', { timeout: 10000 });
+
+    const toggleBtn = page.locator('.toggle-btn, .rule-toggle').first();
+    if (await toggleBtn.isVisible()) {
+      await toggleBtn.click();
+    }
+
+    // ========== Then:状态切换成功 ========
+    await page.waitForTimeout(500);
+
+    // 验证状态变化
+    const statusTag = page.locator('.status-tag, .rule-status').first();
+    if (await statusTag.isVisible()) {
+      const statusText = await statusTag.textContent();
+      expect(statusText).toBeTruthy();
+    }
+  });
+
+  // ===== 场景4:编辑/删除规则 =====
+
+  test('[场景4] 编辑/删除规则 - 期望操作成功', async ({ page }) => {
+    // ========== Given:管理员进入规则页 ==========
+    await page.goto('/#/pages/admin/energy-rules');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:编辑规则 ==========
+    await page.waitForSelector('.rule-item', { timeout: 10000 });
+
+    const firstRule = page.locator('.rule-item').first();
+    const editBtn = firstRule.locator('.edit-btn');
+
+    if (await editBtn.isVisible()) {
+      await editBtn.click();
+    } else {
+      await firstRule.click();
+    }
+
+    await page.waitForSelector('.edit-form, .rule-form', { timeout: 5000 });
+
+    // 修改能量值
+    const valueInput = page.locator('input[name="energyValue"], .value-input');
+    if (await valueInput.isVisible()) {
+      await valueInput.fill('10');
+    }
+
+    // 保存
+    await page.click('.save-btn, .submit-btn');
+
+    // ========== Then:操作成功 ========
+    await page.waitForSelector('.success-tip, .update-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .update-success').isVisible()).toBeTruthy();
+  });
+
+});

+ 102 - 0
tests/e2e/membership-system.spec.js

@@ -0,0 +1,102 @@
+/**
+ * ================================================================
+ * 场景:会员体系全流程 E2E 测试
+ * ================================================================
+ * 用户故事:用户购买/试用会员,管理员配置会员费用
+ *
+ * 流程步骤:
+ *   1. 查看会员等级
+ *   2. 购买会员
+ *   3. 领取试用会员
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 会员激活成功
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/membership-system.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】会员体系全流程', () => {
+
+  // ===== 场景1:查看会员等级 =====
+
+  test('[场景1] 查看会员等级 - 期望返回等级列表', async ({ page }) => {
+    // ========== Given:用户进入会员页 ==========
+    await page.goto('/#/pages/profile/membership');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看会员等级 ==========
+    await page.waitForSelector('.level-list, .membership-card', { timeout: 10000 });
+
+    // ========== Then:返回等级列表 ========
+    const levelCards = page.locator('.level-card, .membership-level');
+    const count = await levelCards.count();
+
+    expect(count).toBeGreaterThan(0);
+
+    // 验证包含权益信息
+    const firstCard = levelCards.first();
+    const benefitTag = firstCard.locator('.benefit-tag, .benefit');
+    if (await benefitTag.isVisible()) {
+      const benefitText = await benefitTag.textContent();
+      expect(benefitText).toBeTruthy();
+    }
+  });
+
+  // ===== 场景2:购买会员 =====
+
+  test('[场景2] 购买会员 - 期望会员激活', async ({ page }) => {
+    // ========== Given:用户选择会员等级 ==========
+    await page.goto('/#/pages/profile/membership');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:购买会员 ==========
+    await page.waitForSelector('.level-card', { timeout: 10000 });
+
+    // 点击购买按钮
+    const buyBtn = page.locator('.buy-btn, .purchase-btn').first();
+    if (await buyBtn.isVisible()) {
+      await buyBtn.click();
+    }
+
+    // 选择支付方式
+    const payMethod = page.locator('.pay-method:has-text("微信")');
+    if (await payMethod.isVisible()) {
+      await payMethod.click();
+    }
+
+    // 确认支付
+    await page.click('.confirm-btn, .pay-btn');
+
+    // ========== Then:Milestone-1 - 会员激活 ========
+    await page.waitForSelector('.success-tip, .activate-success, .toast-success', { timeout: 15000 });
+    expect(await page.locator('.success-tip, .activate-success').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:领取试用会员 =====
+
+  test('[场景3] 领取试用会员 - 期望试用激活', async ({ page }) => {
+    // ========== Given:用户进入会员页 ==========
+    await page.goto('/#/pages/profile/membership');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:领取试用 ==========
+    const trialBtn = page.locator('.trial-btn, .free-trial-btn');
+    if (await trialBtn.isVisible()) {
+      await trialBtn.click();
+    }
+
+    // 确认领取
+    const confirmBtn = page.locator('.van-dialog__confirm, .dialog-confirm');
+    if (await confirmBtn.isVisible()) {
+      await confirmBtn.click();
+    }
+
+    // ========== Then:试用激活 ========
+    await page.waitForSelector('.success-tip, .trial-success, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .trial-success').isVisible()).toBeTruthy();
+  });
+
+});

+ 163 - 0
tests/e2e/mini-games-full.spec.js

@@ -0,0 +1,163 @@
+/**
+ * ================================================================
+ * 场景:小游戏完整流程 E2E 测试
+ * ================================================================
+ * 用户故事:孩子完成小游戏任务(舒尔特方格/猜数字/数独)
+ *
+ * 流程步骤:
+ *   1. 查看可选小游戏
+ *   2. 完成舒尔特方格
+ *   3. 完成猜数字
+ *   4. 完成数独
+ *   5. 进行认知训练
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 游戏1完成
+ *   - [Milestone-2] 认知训练完成
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/mini-games-full.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】小游戏完整流程', () => {
+
+  // ===== 场景1:查看可选小游戏 =====
+
+  test('[场景1] 查看可选小游戏 - 期望返回游戏列表', async ({ page }) => {
+    // ========== Given:创建任务时 ==========
+    await page.goto('/#/pages/tasks/create-task');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:选择小游戏类型 ==========
+    const gameSelect = page.locator('.minigame-picker, .game-type-select');
+    if (await gameSelect.isVisible()) {
+      await gameSelect.click();
+    }
+
+    // ========== Then:返回游戏列表 ========
+    await page.waitForSelector('.game-option, .minigame-item', { timeout: 5000 });
+
+    const gameOptions = page.locator('.game-option, .minigame-item');
+    const count = await gameOptions.count();
+
+    expect(count).toBeGreaterThan(0);
+  });
+
+  // ===== 场景2:完成舒尔特方格 =====
+
+  test('[场景2] 完成舒尔特方格 - 期望游戏完成', async ({ page }) => {
+    // ========== Given:进入舒尔特方格游戏 ==========
+    await page.goto('/#/pages/games/schulte');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:完成游戏 ==========
+    await page.waitForSelector('.schulte-grid, .game-grid', { timeout: 5000 });
+
+    // 获取所有格子并按顺序点击
+    const cells = page.locator('.grid-cell, .cell');
+    const count = await cells.count();
+
+    // 按数字顺序点击(假设数字从1开始显示)
+    for (let i = 0; i < Math.min(count, 9); i++) {
+      await cells.nth(i).click();
+      await page.waitForTimeout(100);
+    }
+
+    // ========== Then:Milestone-1 - 游戏完成 ========
+    await page.waitForSelector('.game-complete, .result-card', { timeout: 10000 });
+
+    const resultCard = page.locator('.game-complete, .result-card');
+    expect(await resultCard.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:完成猜数字 =====
+
+  test('[场景3] 完成猜数字 - 期望游戏完成', async ({ page }) => {
+    // ========== Given:进入猜数字游戏 ==========
+    await page.goto('/#/pages/games/1a2b');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:进行游戏 ==========
+    await page.waitForSelector('.guess-input, .input-area', { timeout: 5000 });
+
+    // 输入猜测
+    const input = page.locator('.guess-input, .number-input');
+    if (await input.isVisible()) {
+      await input.fill('1234');
+    }
+
+    // 提交猜测
+    const submitBtn = page.locator('.submit-btn, .guess-btn');
+    if (await submitBtn.isVisible()) {
+      await submitBtn.click();
+    }
+
+    // ========== Then:返回猜测结果 ========
+    await page.waitForSelector('.result-hint, .guess-result', { timeout: 5000 });
+
+    const resultHint = page.locator('.result-hint, .guess-result');
+    expect(await resultHint.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景4:完成数独 =====
+
+  test('[场景4] 完成数独 - 期望游戏完成', async ({ page }) => {
+    // ========== Given:进入数独游戏 ==========
+    await page.goto('/#/pages/games/sudoku');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:进行游戏 ==========
+    await page.waitForSelector('.sudoku-grid, .game-board', { timeout: 5000 });
+
+    // 点击一个空格
+    const emptyCell = page.locator('.cell.empty, .cell:not(.fixed)').first();
+    if (await emptyCell.isVisible()) {
+      await emptyCell.click();
+    }
+
+    // 选择数字
+    const numBtn = page.locator('.num-btn:has-text("1")').first();
+    if (await numBtn.isVisible()) {
+      await numBtn.click();
+    }
+
+    // ========== Then:数字填入 ========
+    await page.waitForTimeout(500);
+
+    const filledCell = page.locator('.cell.filled');
+    const hasFilled = await filledCell.count() > 0;
+    expect(hasFilled).toBeTruthy();
+  });
+
+  // ===== 场景5:进行认知训练 =====
+
+  test('[场景5] 进行认知训练 - 期望训练记录生成', async ({ page }) => {
+    // ========== Given:进入智维度 ==========
+    await page.goto('/#/pages/wisdom/training-hub');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:开始训练 ==========
+    const startBtn = page.locator('.start-btn, .start-training');
+    if (await startBtn.isVisible()) {
+      await startBtn.click();
+    }
+
+    // 等待训练开始
+    await page.waitForSelector('.training-content, .quiz-area', { timeout: 5000 });
+
+    // 完成一道题目
+    const answerBtn = page.locator('.answer-btn, .option').first();
+    if (await answerBtn.isVisible()) {
+      await answerBtn.click();
+    }
+
+    // ========== Then:Milestone-2 - 训练记录生成 ========
+    await page.waitForSelector('.training-complete, .result-saved', { timeout: 10000 });
+
+    const completeTip = page.locator('.training-complete, .result-saved');
+    expect(await completeTip.isVisible()).toBeTruthy();
+  });
+
+});

+ 437 - 0
tests/e2e/nutritionist-flow.spec.js

@@ -0,0 +1,437 @@
+/**
+ * ================================================================
+ * 场景:健康营养师全流程 E2E 测试
+ * ================================================================
+ * 用户故事:作为健康营养师,我希望能家庭提供专业的营养指导服务,
+ *           以便帮助家庭成员建立健康的饮食习惯。
+ *
+ * 流程步骤:
+ *   1. 营养师登录系统,查看营养偏好
+ *   2. 营养师更新家庭营养档案(口味/预算/烹饪能力)
+ *   3. 营养师添加家庭成员的饮食记录
+ *   4. 营养师查看饮食记录列表和分析报告
+ *   5. 营养师创建和管理食谱
+ *   6. 营养师查看应季食材
+ *   7. 营养师绑定家庭,开始服务
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 营养师成功获取家庭营养档案
+ *   - [Milestone-2] 营养偏好更新成功
+ *   - [Milestone-3] 饮食记录添加成功
+ *   - [Milestone-4] 食谱创建成功
+ *   - [Milestone-5] 家庭绑定关系建立
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/nutritionist-flow.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】健康营养师全流程', () => {
+
+  // ===== 场景1:营养师登录并查看营养偏好 =====
+
+  /**
+   * 场景:营养师登录后,查看家庭的营养档案
+   * 角色:健康营养师
+   * 触发条件:营养师进入营养偏好页面
+   */
+  test('[场景1] 营养师查看家庭营养档案 - 期望返回完整营养信息', async ({ page }) => {
+    // ========== Given:营养师已登录,进入营养偏好页面 ==========
+    await page.goto('/#/pages/body/nutrition-profile');
+    await page.waitForLoadState('networkidle');
+
+    // 验证页面加载成功
+    await expect(page.locator('.nutrition-profile-page')).toBeVisible({ timeout: 10000 });
+
+    // ========== When:获取营养档案 ==========
+    // 等待营养信息加载
+    await page.waitForSelector('.profile-card, .nutrition-info', { timeout: 10000 });
+
+    // ========== Then:Milestone-1 - 返回完整营养档案 ========
+    const profileCard = page.locator('.profile-card, .nutrition-info');
+    if (await profileCard.isVisible()) {
+      // 验证包含关键信息
+      const profileText = await profileCard.textContent();
+      expect(profileText.length).toBeGreaterThan(0);
+    }
+
+    // 验证口味偏好存在
+    const tastePrefs = page.locator('.taste-prefs, .family-taste');
+    if (await tastePrefs.isVisible()) {
+      const tasteText = await tastePrefs.textContent();
+      expect(tasteText).toBeTruthy();
+    }
+  });
+
+  // ===== 场景2:营养师更新营养偏好 =====
+
+  /**
+   * 场景:营养师根据家庭情况更新营养偏好设置
+   * 角色:健康营养师
+   * 触发条件:营养师编辑营养偏好
+   */
+  test('[场景2] 营养师更新营养偏好 - 期望保存成功', async ({ page }) => {
+    // ========== Given:营养师进入营养偏好编辑页 ==========
+    await page.goto('/#/pages/body/nutrition-profile');
+    await page.waitForLoadState('networkidle');
+
+    // ========== Step 1:点击编辑按钮 ==========
+    const editBtn = page.locator('.edit-btn, .btn-edit, .edit-profile');
+    if (await editBtn.isVisible()) {
+      await editBtn.click();
+      await page.waitForSelector('.edit-form, .profile-form', { timeout: 5000 });
+    }
+
+    // ========== Step 2:更新口味偏好 ==========
+    const tasteInput = page.locator('input[name="familyTastePreferences"], .taste-input');
+    if (await tasteInput.isVisible()) {
+      await tasteInput.fill('清淡少盐,多蔬菜水果');
+    }
+
+    // ========== Step 3:更新烹饪能力 ==========
+    const cookingSelect = page.locator('.cooking-ability-select, select[name="cookingAbility"]');
+    if (await cookingSelect.isVisible()) {
+      await cookingSelect.selectOption('intermediate');
+    }
+
+    // ========== Step 4:更新月度预算 ==========
+    const budgetInput = page.locator('input[name="budgetMonthly"], .budget-input');
+    if (await budgetInput.isVisible()) {
+      await budgetInput.fill('3000');
+    }
+
+    // ========== When:保存修改 ==========
+    await page.click('.save-btn, .confirm-btn, .submit-btn');
+
+    // ========== Then:Milestone-2 - 保存成功 ========
+    await page.waitForSelector('.success-tip, .save-success, .toast-success', { timeout: 10000 });
+
+    const successTip = page.locator('.success-tip, .save-success, .toast-success');
+    expect(await successTip.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景3:营养师添加饮食记录 =====
+
+  /**
+   * 场景:营养师为家庭成员记录一餐的饮食情况
+   * 角色:健康营养师
+   * 触发条件:营养师进入饮食记录页面并添加记录
+   */
+  test('[场景3] 营养师添加饮食记录 - 期望记录添加成功', async ({ page }) => {
+    // ========== Given:营养师进入饮食记录页面 ==========
+    await page.goto('/#/pages/body/meal-record');
+    await page.waitForLoadState('networkidle');
+
+    // 验证页面加载
+    await expect(page.locator('.meal-record-page')).toBeVisible({ timeout: 10000 });
+
+    // ========== Step 1:选择餐次类型 ==========
+    const breakfastBtn = page.locator('.meal-type-btn:has-text("早餐"), .meal-type:has-text("早餐")');
+    if (await breakfastBtn.isVisible()) {
+      await breakfastBtn.click();
+    }
+
+    // ========== Step 2:输入食物名称 ==========
+    const foodInput = page.locator('input[name="foodName"], .food-name-input');
+    if (await foodInput.isVisible()) {
+      await foodInput.fill('全麦面包 + 牛奶 + 鸡蛋');
+    }
+
+    // ========== Step 3:输入食物份量 ==========
+    const amountInput = page.locator('input[name="foodAmount"], .amount-input');
+    if (await amountInput.isVisible()) {
+      await amountInput.fill('100g + 250ml + 1个');
+    }
+
+    // ========== Step 4:输入营养信息 ==========
+    const caloriesInput = page.locator('input[name="calories"], .calories-input');
+    if (await caloriesInput.isVisible()) {
+      await caloriesInput.fill('350');
+    }
+
+    const proteinInput = page.locator('input[name="protein"], .protein-input');
+    if (await proteinInput.isVisible()) {
+      await proteinInput.fill('15');
+    }
+
+    // ========== When:提交记录 ==========
+    await page.click('.submit-btn, .add-btn, .save-btn');
+
+    // ========== Then:Milestone-3 - 记录添加成功 ========
+    await page.waitForSelector('.success-tip, .record-added, .toast-success', { timeout: 10000 });
+
+    const successTip = page.locator('.success-tip, .record-added, .toast-success');
+    expect(await successTip.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景4:营养师查看饮食记录列表 =====
+
+  /**
+   * 场景:营养师查看家庭成员最近的饮食记录
+   * 角色:健康营养师
+   * 触发条件:营养师需要分析家庭饮食结构
+   */
+  test('[场景4] 营养师查看饮食记录列表 - 期望返回记录列表', async ({ page }) => {
+    // ========== Given:营养师进入饮食记录页面 ==========
+    await page.goto('/#/pages/body/meal-record');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看记录列表 ==========
+    await page.waitForSelector('.record-list, .meal-list, .diet-records', { timeout: 10000 });
+
+    // ========== Then:返回饮食记录列表 ========
+    const recordItems = page.locator('.record-item, .meal-item, .diet-record');
+    const count = await recordItems.count();
+
+    expect(count).toBeGreaterThanOrEqual(0);
+
+    // 验证记录包含日期信息
+    if (count > 0) {
+      const firstRecord = recordItems.first();
+      expect(await firstRecord.isVisible()).toBeTruthy();
+    }
+  });
+
+  // ===== 场景5:营养师分析营养摄入 =====
+
+  /**
+   * 场景:营养师分析家庭成员的营养摄入情况
+   * 角色:健康营养师
+   * 触发条件:需要生成营养分析报告
+   */
+  test('[场景5] 营养师分析营养摄入 - 期望返回分析报告', async ({ page }) => {
+    // ========== Given:营养师进入营养分析页面 ==========
+    await page.goto('/#/pages/body/nutrition-analysis');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:生成分析报告 ==========
+    const analyzeBtn = page.locator('.analyze-btn, .generate-report-btn');
+    if (await analyzeBtn.isVisible()) {
+      await analyzeBtn.click();
+    }
+
+    // ========== Then:返回分析结果 ========
+    await page.waitForSelector('.analysis-result, .nutrition-report, .report-card', { timeout: 15000 });
+
+    const reportCard = page.locator('.analysis-result, .nutrition-report, .report-card');
+    expect(await reportCard.isVisible()).toBeTruthy();
+
+    // 验证包含营养素分析
+    const nutrients = page.locator('.nutrient-item, .macro-item');
+    if (await nutrients.first().isVisible()) {
+      const nutrientCount = await nutrients.count();
+      expect(nutrientCount).toBeGreaterThan(0);
+    }
+  });
+
+  // ===== 场景6:营养师创建食谱 =====
+
+  /**
+   * 场景:营养师为家庭创建健康食谱
+   * 角色:健康营养师
+   * 触发条件:营养师进入食谱管理页面
+   */
+  test('[场景6] 营养师创建食谱 - 期望食谱创建成功', async ({ page }) => {
+    // ========== Given:营养师进入食谱管理页面 ==========
+    await page.goto('/#/pages/body/recipe-recommend');
+    await page.waitForLoadState('networkidle');
+
+    // ========== Step 1:点击创建食谱 ==========
+    const createBtn = page.locator('.create-btn, .add-recipe-btn, .create-recipe');
+    if (await createBtn.isVisible()) {
+      await createBtn.click();
+    } else {
+      // 直接进入创建页
+      await page.goto('/#/pages/body/recipe-create');
+      await page.waitForLoadState('networkidle');
+    }
+
+    await page.waitForSelector('.recipe-form, .create-form', { timeout: 5000 });
+
+    // ========== Step 2:填写食谱信息 ==========
+    const nameInput = page.locator('input[name="name"], .recipe-name-input');
+    if (await nameInput.isVisible()) {
+      await nameInput.fill('营养早餐套餐_' + Date.now());
+    }
+
+    const ingredientsInput = page.locator('textarea[name="ingredients"], .ingredients-input');
+    if (await ingredientsInput.isVisible()) {
+      await ingredientsInput.fill('全麦面包2片、牛奶200ml、鸡蛋1个、水果100g');
+    }
+
+    const methodInput = page.locator('textarea[name="method"], .method-input');
+    if (await methodInput.isVisible()) {
+      await methodInput.fill('1. 鸡蛋煮熟切片\n2. 面包烤至微黄\n3. 倒入牛奶\n4. 摆盘水果');
+    }
+
+    // ========== Step 3:填写营养信息 ==========
+    const caloriesInput = page.locator('input[name="calories"], .calories-input');
+    if (await caloriesInput.isVisible()) {
+      await caloriesInput.fill('420');
+    }
+
+    const proteinInput = page.locator('input[name="protein"], .protein-input');
+    if (await proteinInput.isVisible()) {
+      await proteinInput.fill('18');
+    }
+
+    // ========== When:提交食谱 ==========
+    await page.click('.submit-btn, .save-btn, .publish-btn');
+
+    // ========== Then:Milestone-4 - 食谱创建成功 ========
+    await page.waitForSelector('.success-tip, .recipe-created, .toast-success', { timeout: 10000 });
+
+    const successTip = page.locator('.success-tip, .recipe-created, .toast-success');
+    expect(await successTip.isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景7:营养师管理食谱库 =====
+
+  /**
+   * 场景:营养师编辑或删除已有食谱
+   * 角色:健康营养师
+   * 触发条件:食谱需要更新或清理
+   */
+  test('[场景7] 营养师管理食谱库 - 期望食谱更新/删除成功', async ({ page }) => {
+    // ========== Given:营养师进入食谱列表页面 ==========
+    await page.goto('/#/pages/body/recipe-list');
+    await page.waitForLoadState('networkidle');
+
+    // ========== Step 1:找到要编辑的食谱 ==========
+    await page.waitForSelector('.recipe-item, .recipe-card', { timeout: 10000 });
+
+    const recipeItem = page.locator('.recipe-item, .recipe-card').first();
+    if (await recipeItem.isVisible()) {
+      // 点击编辑
+      const editBtn = recipeItem.locator('.edit-btn, .btn-edit');
+      if (await editBtn.isVisible()) {
+        await editBtn.click();
+      } else {
+        await recipeItem.click();
+      }
+
+      await page.waitForSelector('.edit-form, .recipe-form', { timeout: 5000 });
+
+      // ========== Step 2:修改食谱 ==========
+      const nameInput = page.locator('input[name="name"], .recipe-name-input');
+      if (await nameInput.isVisible()) {
+        const newName = '已更新食谱_' + Date.now();
+        await nameInput.fill(newName);
+      }
+
+      // ========== When:保存修改 ==========
+      await page.click('.save-btn, .confirm-btn');
+      await page.waitForSelector('.success-tip, .update-success', { timeout: 10000 });
+
+      const successTip = page.locator('.success-tip, .update-success');
+      expect(await successTip.isVisible()).toBeTruthy();
+    }
+  });
+
+  // ===== 场景8:营养师查看应季食材 =====
+
+  /**
+   * 场景:营养师查看当前季节的推荐食材
+   * 角色:健康营养师
+   * 触发条件:需要制定应季菜单
+   */
+  test('[场景8] 营养师查看应季食材 - 期望返回应季食材列表', async ({ page }) => {
+    // ========== Given:营养师进入应季食材页面 ==========
+    await page.goto('/#/pages/body/seasonal-foods');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看应季食材 ==========
+    await page.waitForSelector('.seasonal-list, .food-list, .seasonal-foods', { timeout: 10000 });
+
+    // ========== Then:返回应季食材列表 ========
+    const foodItems = page.locator('.food-item, .seasonal-item');
+    const count = await foodItems.count();
+
+    expect(count).toBeGreaterThanOrEqual(0);
+
+    if (count > 0) {
+      // 验证包含食材名称
+      const firstItem = foodItems.first();
+      expect(await firstItem.isVisible()).toBeTruthy();
+
+      // 验证包含季节标识
+      const seasonTag = page.locator('.season-tag, .month-tag');
+      if (await seasonTag.first().isVisible()) {
+        const tagText = await seasonTag.first().textContent();
+        expect(tagText).toBeTruthy();
+      }
+    }
+  });
+
+  // ===== 场景9:营养师获取饮食推荐 =====
+
+  /**
+   * 场景:营养师根据家庭偏好获取饮食推荐
+   * 角色:健康营养师
+   * 触发条件:需要为家庭推荐合适的三餐
+   */
+  test('[场景9] 营养师获取饮食推荐 - 期望返回个性化推荐', async ({ page }) => {
+    // ========== Given:营养师进入饮食推荐页面 ==========
+    await page.goto('/#/pages/meal/recommend');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:获取推荐 ==========
+    await page.waitForSelector('.recommend-list, .meal-recommend, .recommend-cards', { timeout: 10000 });
+
+    // ========== Then:返回推荐列表 ========
+    const recommendCards = page.locator('.recommend-card, .meal-item, .recommend-item');
+    const count = await recommendCards.count();
+
+    expect(count).toBeGreaterThan(0);
+
+    // 验证推荐包含营养信息
+    const firstCard = recommendCards.first();
+    expect(await firstCard.isVisible()).toBeTruthy();
+
+    const nutritionInfo = page.locator('.nutrition-tag, .calories-tag');
+    if (await nutritionInfo.first().isVisible()) {
+      const tagText = await nutritionInfo.first().textContent();
+      expect(tagText).toBeTruthy();
+    }
+  });
+
+  // ===== 场景10:营养师绑定家庭 =====
+
+  /**
+   * 场景:营养师接受家庭邀请,建立服务关系
+   * 角色:健康营养师
+   * 触发条件:家长向营养师发送邀请
+   */
+  test('[场景10] 营养师绑定家庭 - 期望绑定成功', async ({ page }) => {
+    // ========== Given:营养师收到绑定邀请 ==========
+    await page.goto('/#/pages/invite/join');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:接受绑定邀请 ==========
+    const acceptBtn = page.locator('.accept-btn, .confirm-bind-btn, .accept-invite');
+    if (await acceptBtn.isVisible()) {
+      await acceptBtn.click();
+    }
+
+    // 等待确认弹窗
+    const confirmDialog = page.locator('.van-dialog, .confirm-dialog');
+    if (await confirmDialog.isVisible()) {
+      const confirmBtn = page.locator('.van-dialog__confirm, .dialog-confirm-btn');
+      if (await confirmBtn.isVisible()) {
+        await confirmBtn.click();
+      }
+    }
+
+    // ========== Then:Milestone-5 - 绑定成功 ========
+    await page.waitForSelector('.bind-success, .success-tip, .toast-success', { timeout: 10000 });
+
+    // 验证绑定关系建立
+    const bindIndicator = page.locator('.bind-status, .relation-status');
+    if (await bindIndicator.isVisible()) {
+      const statusText = await bindIndicator.textContent();
+      expect(statusText).toMatch(/已绑定|服务中|active/i);
+    }
+  });
+
+});

+ 143 - 0
tests/e2e/points-system.spec.js

@@ -0,0 +1,143 @@
+/**
+ * ================================================================
+ * 场景:积分系统全流程 E2E 测试
+ * ================================================================
+ * 用户故事:
+ *   - 家长/孩子:查看积分余额、积分流水
+ *   - 家长:手动调整孩子积分
+ *
+ * 流程步骤:
+ *   1. 查看积分余额
+ *   2. 查看积分流水
+ *   3. 按分类查看流水
+ *   4. 手动调整积分
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 返回积分余额
+ *   - [Milestone-2] 积分调整成功
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/points-system.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】积分系统全流程', () => {
+
+  // ===== 场景1:查看积分余额 =====
+
+  test('[场景1] 查看积分余额 - 期望返回余额信息', async ({ page }) => {
+    // ========== Given:进入积分页面 ==========
+    await page.goto('/#/pages/profile/points');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看余额 ==========
+    await page.waitForSelector('.points-card, .balance-card', { timeout: 10000 });
+
+    // ========== Then:Milestone-1 - 返回余额 ========
+    const balanceCard = page.locator('.balance-card, .points-balance');
+    if (await balanceCard.isVisible()) {
+      const balanceText = await balanceCard.textContent();
+      expect(balanceText).toBeTruthy();
+    }
+
+    // 验证积分数值显示
+    const pointsValue = page.locator('.points-value, .balance-num');
+    if (await pointsValue.isVisible()) {
+      const valueText = await pointsValue.textContent();
+      expect(valueText).toMatch(/\d+/);
+    }
+  });
+
+  // ===== 场景2:查看积分流水 =====
+
+  test('[场景2] 查看积分流水 - 期望返回流水列表', async ({ page }) => {
+    // ========== Given:进入积分流水页 ==========
+    await page.goto('/#/pages/profile/points-detail');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看流水 ==========
+    await page.waitForSelector('.flow-list, .points-log, .transaction-list', { timeout: 10000 });
+
+    // ========== Then:返回流水列表 ========
+    const flowItems = page.locator('.flow-item, .log-item, .transaction-item');
+    const count = await flowItems.count();
+
+    expect(count).toBeGreaterThanOrEqual(0);
+
+    if (count > 0) {
+      // 验证流水包含关键信息
+      const firstItem = flowItems.first();
+      expect(await firstItem.isVisible()).toBeTruthy();
+
+      // 验证包含金额信息
+      const amountTag = firstItem.locator('.amount, .points-change');
+      if (await amountTag.isVisible()) {
+        const amountText = await amountTag.textContent();
+        expect(amountText).toBeTruthy();
+      }
+    }
+  });
+
+  // ===== 场景3:按分类查看流水 =====
+
+  test('[场景3] 按分类查看流水 - 期望返回筛选后流水', async ({ page }) => {
+    // ========== Given:进入积分流水页 ==========
+    await page.goto('/#/pages/profile/points-detail');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:选择分类筛选 ==========
+    const categoryPicker = page.locator('.category-picker, .filter-btn');
+    if (await categoryPicker.isVisible()) {
+      await categoryPicker.click();
+      await page.waitForSelector('.option-item, .filter-option', { timeout: 3000 });
+      await page.locator('.option-item').nth(1).click();
+    }
+
+    // ========== Then:返回筛选后流水 ========
+    await page.waitForTimeout(500);
+
+    const flowItems = page.locator('.flow-item, .log-item');
+    const count = await flowItems.count();
+
+    // 验证筛选生效(可能有0条或多条)
+    expect(count).toBeGreaterThanOrEqual(0);
+  });
+
+  // ===== 场景4:家长手动调整积分 =====
+
+  test('[场景4] 家长手动调整积分 - 期望调整成功', async ({ page }) => {
+    // ========== Given:进入积分调整页 ==========
+    await page.goto('/#/pages/profile/points-adjust');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:调整积分 ==========
+    // 选择孩子
+    const childSelect = page.locator('.child-picker');
+    if (await childSelect.isVisible()) {
+      await childSelect.click();
+      await page.waitForSelector('.child-option', { timeout: 3000 });
+      await page.locator('.child-option').first().click();
+    }
+
+    // 输入调整值
+    const amountInput = page.locator('input[name="amount"], .amount-input');
+    if (await amountInput.isVisible()) {
+      await amountInput.fill('10');
+    }
+
+    // 输入原因
+    const reasonInput = page.locator('textarea[name="reason"], .reason-input');
+    if (await reasonInput.isVisible()) {
+      await reasonInput.fill('表现优秀,额外奖励');
+    }
+
+    // 提交
+    await page.click('.submit-btn, .adjust-btn');
+
+    // ========== Then:Milestone-2 - 调整成功 ========
+    await page.waitForSelector('.success-tip, .adjust-success, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .adjust-success').isVisible()).toBeTruthy();
+  });
+
+});

+ 100 - 0
tests/e2e/vendor-onboarding.spec.js

@@ -0,0 +1,100 @@
+/**
+ * ================================================================
+ * 场景:供应商入驻全流程 E2E 测试
+ * ================================================================
+ * 用户故事:供应商申请入驻,管理员审核
+ *
+ * 流程步骤:
+ *   1. 供应商提交入驻申请
+ *   2. 供应商查看入驻状态
+ *   3. 管理员审核供应商
+ *
+ * 关键里程碑:
+ *   - [Milestone-1] 申请提交成功
+ *   - [Milestone-2] 审核完成
+ * ================================================================
+ *
+ * 运行:npx playwright test tests/e2e/vendor-onboarding.spec.js
+ */
+
+const { test, expect } = require('@playwright/test');
+
+test.describe('【场景流程】供应商入驻全流程', () => {
+
+  // ===== 场景1:供应商提交入驻申请 =====
+
+  test('[场景1] 供应商提交入驻申请 - 期望申请成功', async ({ page }) => {
+    // ========== Given:供应商进入入驻申请页 ==========
+    await page.goto('/#/pages/profile/vendor-apply');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:填写并提交申请 ==========
+    await page.waitForSelector('.apply-form, .vendor-form', { timeout: 5000 });
+
+    // 选择服务商类型
+    const typeSelect = page.locator('.type-picker, select[name="vendorType"]');
+    if (await typeSelect.isVisible()) {
+      await typeSelect.selectOption('product_supplier');
+    }
+
+    // 填写资质说明
+    const infoInput = page.locator('textarea[name="vendorInfo"], .info-input');
+    if (await infoInput.isVisible()) {
+      await infoInput.fill('我们是专业的商品供应商,提供优质的家庭用品。');
+    }
+
+    // 提交申请
+    await page.click('.submit-btn, .apply-btn');
+
+    // ========== Then:Milestone-1 - 申请成功 ========
+    await page.waitForSelector('.success-tip, .apply-success, .toast-success', { timeout: 10000 });
+    expect(await page.locator('.success-tip, .apply-success').isVisible()).toBeTruthy();
+  });
+
+  // ===== 场景2:供应商查看入驻状态 =====
+
+  test('[场景2] 供应商查看入驻状态 - 期望返回当前状态', async ({ page }) => {
+    // ========== Given:供应商进入状态查询页 ==========
+    await page.goto('/#/pages/profile/vendor-status');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:查看状态 ==========
+    await page.waitForSelector('.status-card, .vendor-status', { timeout: 10000 });
+
+    // ========== Then:返回状态信息 ========
+    const statusCard = page.locator('.status-card, .status-info');
+    if (await statusCard.isVisible()) {
+      const statusText = await statusCard.textContent();
+      expect(statusText).toBeTruthy();
+    }
+  });
+
+  // ===== 场景3:管理员审核供应商 =====
+
+  test('[场景3] 管理员审核供应商 - 期望审核成功', async ({ page }) => {
+    // ========== Given:管理员进入供应商审核页 ==========
+    await page.goto('/#/pages/admin/vendor-review');
+    await page.waitForLoadState('networkidle');
+
+    // ========== When:审核供应商 ==========
+    await page.waitForSelector('.vendor-item, .vendor-row', { timeout: 10000 });
+
+    const pendingItem = page.locator('.vendor-item').first();
+    const approveBtn = pendingItem.locator('.approve-btn, .pass-btn');
+
+    if (await approveBtn.isVisible()) {
+      await approveBtn.click();
+    }
+
+    // ========== Then:Milestone-2 - 审核成功 ========
+    await page.waitForTimeout(500);
+
+    // 验证状态变化
+    const statusTag = pendingItem.locator('.status-tag');
+    if (await statusTag.isVisible()) {
+      const statusText = await statusTag.textContent();
+      expect(statusText).toMatch(/已通过|approved/i);
+    }
+  });
+
+});