2026-09-22-guide-popup-config-design.md 11 KB

弹窗引导页配置化管理设计文档

日期:2026-09-22 状态:✅ 已确认 - 可进入实现阶段 需求来源:用户确认弹窗引导页需实现配置化管理,支持管理员配置弹出条件与内容


一、背景与目标

现状问题

  • OnboardingGuide.vue 的 PARENT_STEPS / CHILD_STEPS 为硬编码
  • 触发条件仅依赖 _onboardingDone 本地标记(首次登录仅弹一次)
  • 内容无法动态调整,无法支持 A/B 测试或按场景定制

设计目标

  1. 配置化管理:管理员可通过 Web 后台配置弹窗内容、触发条件、样式
  2. 条件驱动:支持按角色、页面路径、行为触发、时间窗口等多种条件
  3. 用户消费追踪:记录每个用户的消费状态,避免重复弹出
  4. 数据看板:统计曝光、点击、完成率,支持效果分析
  5. 向后兼容:保留旧 _onboardingDone 逻辑,新配置逐步替代

二、数据库设计

2.1 表结构

guide_popup(引导弹窗配置表)

字段 类型 说明
id BIGINT PK 主键
slug VARCHAR(64) UNIQUE 唯一标识,如 parent_first_login
title VARCHAR(128) 弹窗标题(可空,仅副标题时为空)
description TEXT 主描述文案(支持换行)
icon VARCHAR(256) 图标:emoji 或图片 URL
icon_type TINYINT 图标类型:0=emoji 1=图片
theme_color VARCHAR(20) 主题色,如 #FF8C42
btn_text VARCHAR(64) 按钮文案
btn_action VARCHAR(256) 点击跳转路径(空=关闭)
status TINYINT 0=禁用 1=启用
sort_order INT 同类型排序优先级
created_at DATETIME 创建时间
updated_at DATETIME 更新时间

guide_popup_step(步骤表)

字段 类型 说明
id BIGINT PK 主键
popup_id BIGINT FK 关联 guide_popup.id
step_order INT 步骤顺序
title VARCHAR(128) 步骤标题
desc TEXT 步骤描述
icon VARCHAR(256) 步骤图标
icon_type TINYINT 图标类型
is_intro TINYINT 是否为开场身份定义页(特殊样式)
btn_text VARCHAR(64) 本步骤按钮文案
btn_action VARCHAR(256) 最后一步跳转链接
created_at DATETIME 创建时间

guide_popup_trigger(触发条件表)

字段 类型 说明
id BIGINT PK 主键
popup_id BIGINT FK 关联 guide_popup.id
trigger_type VARCHAR(32) page_enter/task_complete/assessment_done/first_login/daily_active/role_change
target_page VARCHAR(128) 目标页面路径(trigger_type=page_enter 时使用)
target_action VARCHAR(128) 触发行为标识(trigger_type=task_complete 时使用)
min_role VARCHAR(32) 最低角色要求:parent/child/teacher
extra_config JSON 扩展条件:{"days":30,"streak":7}
created_at DATETIME 创建时间

guide_popup_log(用户消费记录表)

字段 类型 说明
id BIGINT PK 主键
popup_id BIGINT FK 关联 guide_popup.id
user_id BIGINT 用户 ID
member_id BIGINT NULL family_members.id(可空)
role VARCHAR(32) 弹出时所在角色
consumed_at DATETIME 消费时间
button_clicked TINYINT 是否点击了按钮

2.2 索引设计

  • guide_popup: INDEX idx_status_sort (status, sort_order)
  • guide_popup_step: INDEX idx_popup_order (popup_id, step_order)
  • guide_popup_log: INDEX idx_user_popup (user_id, popup_id), INDEX idx_consume_time (consumed_at)

三、后端 API 设计

3.1 用户端接口

POST /api/guide/popup/list

功能:查询当前用户应展示的激活弹窗列表

请求:无参数(从 JWT 自动解析 userId/role)

响应示例:

{
  "code": 200,
  "data": [
    {
      "id": 1,
      "slug": "parent_first_login",
      "title": "欢迎使用浠艾福",
      "description": "身·智·富·行·心,全家健康一站式管理",
      "icon": "🌏",
      "iconType": 0,
      "themeColor": "#FF8C42",
      "btnText": "开始体验",
      "btnAction": "/pages/assessment/plan",
      "steps": [
        { "stepOrder": 0, "icon": "🌏", "title": "身·主动健康", "desc": "精准营养推荐,从根源调理体质", "isIntro": true },
        { "stepOrder": 1, "icon": "⚡", "title": "智·赋能未来", "desc": "专业心智测评,看清能力与短板", "isIntro": false }
      ]
    }
  ]
}

业务逻辑:

  1. 从 JWT 获取 userId + role
  2. 查询所有 status=1 的 guide_popup
  3. 按 trigger_type 匹配当前用户状态
  4. 排除 guide_popup_log 中已消费且 button_clicked=false 的记录
  5. 按 sort_order 排序返回

POST /api/guide/popup/trigger

功能:上报触发行为

请求体:

{ "action": "task_complete", "taskId": 123 }

响应:

{ "code": 200, "data": { "shouldShow": true, "popups": [...] } }

POST /api/guide/popup/consume

功能:消费弹窗(点击/关闭)

请求体:

{ "popupId": 1, "buttonClicked": true }

响应:

{ "code": 200, "data": true }

3.2 管理端接口

方法 路径 说明
POST /api/admin/guide/popup/list 列表(分页/筛选 status/slug)
POST /api/admin/guide/popup/create 创建(含触发条件+步骤)
POST /api/admin/guide/popup/update 更新(全量覆盖步骤和条件)
POST /api/admin/guide/popup/status 启用/禁用(toggle)
POST /api/admin/guide/popup/delete 软删除
POST /api/admin/guide/popup/stats 数据看板

stats 响应示例:

{
  "code": 200,
  "data": {
    "totalViews": 1234,
    "totalClicks": 567,
    "completionRate": "45.9%",
    "avgDuration": "3.2s",
    "trendByHour": [
      { "hour": "08:00", "views": 120, "clicks": 45 },
      { "hour": "09:00", "views": 200, "clicks": 88 }
    ]
  }
}

四、前端组件设计

4.1 新增组件:ConfigurableGuide.vue

位置:components/ConfigurableGuide.vue

Props:

props: {
  popup: {
    type: Object,
    required: true,
    // { id, slug, title, description, icon, iconType, themeColor, btnText, btnAction, steps }
  },
  mode: {
    type: String,
    default: 'modal'  // 'modal' | 'sheet' | 'banner'
  }
}

功能:

  • 根据 steps 数组决定渲染模式(单步 vs 多步向导)
  • icon_type=0 渲染 emoji,=1 渲染 image 组件
  • theme_color 动态绑定样式
  • 按钮点击 → 调用 /api/guide/popup/consume + 跳转
  • 关闭 → 仅调用 consume(buttonClicked=false)
  • 步骤导航支持左右滑动(多步场景)

生命周期:

  • mounted:调用 /api/guide/popup/list 拉取激活配置
  • 弹窗展示时上报曝光(可选,通过 /trigger 接口)

4.2 页面接入

pages/index-home/index.vue

  • 替换 _maybeShowOnboardingGuide() 中的硬编码逻辑
  • 改为调用 GET /api/guide/popup/list(实际为 POST 无参)
  • 根据返回的 slug 决定渲染哪个弹窗
  • 保留 _onboardingDone 兼容逻辑:若已消费则不展示新弹窗

pages/home-pages/child-index.vue

  • 类似接入,支持子端专属配置

4.3 Web 管理端页面

views/admin/GuidePopupConfig.vue

  • 列表页:表格展示所有配置(启用/禁用/预览/编辑/删除)
  • 编辑抽屉:表单输入 title/description/icon 等字段
  • 步骤管理:可动态增删步骤
  • 触发条件:选择 trigger_type + 填写目标值

views/admin/GuidePopupStats.vue

  • 统计卡片:总曝光/总点击/完成率/平均停留时长
  • 趋势图:按小时/天聚合的曝光+点击曲线
  • 分弹窗对比:各 slug 的独立统计

五、实现顺序

Phase 1: 后端基础(P0)

1. DatabaseInitializer 新增 4 张表迁移
2. 实体类:GuidePopup, GuidePopupStep, GuidePopupTrigger, GuidePopupLog
3. Mapper 接口 + XML(如需)
4. Service: GuidePopupService(CRUD + 匹配逻辑)
5. Controller: GuidePopupController(用户端 3 接口)
6. Controller: AdminGuidePopupController(管理端 6 接口)

Phase 2: 前端组件(P1)

1. components/ConfigurableGuide.vue
2. pages/index-home/index.vue 接入
3. pages/home-pages/child-index.vue 接入

Phase 3: 管理端(P1)

1. views/admin/GuidePopupConfig.vue
2. views/admin/GuidePopupStats.vue
3. 路由注册(cfc-web/src/router/)
4. API 封装(cfc-web/src/api/)

Phase 4: 收尾(P2)

1. DatabaseInitializer 写入种子数据(现有 PARENT_STEPS 作为 seed)
2. 兼容验证:旧 OnboardingGuide.vue 逻辑保留
3. 文档更新(API_REFERENCE.md)

六、约束与约定

后端

  • 遵循项目规范:统一 @PostMapping,禁止 @GetMapping/@PutMapping/@DeleteMapping
  • 实体:@TableName + @TableId(type = IdType.AUTO)
  • DI:@Resource,字段名匹配 Bean Name
  • 响应:Result<T> 统一包装
  • 迁移:通过 DatabaseInitializer.runMigrations() 幂等执行

前端(小程序)

  • Vue 2 Options API,禁止 Composition API
  • 禁止可选链 ?.,用 && 替代
  • 禁止 :key 表达式,用方法调用
  • 时间格式统一 ISO 8601,前端格式化
  • API 调用去重:遵循 AGENTS.md 规则

前端(Web 管理端)

  • Vue 2 + Element UI
  • 页面路由注册到 src/router/index.js
  • API 封装到 src/api/ 目录

七、验收标准

  1. 功能验收:

    • 管理端可创建/编辑/启用/禁用弹窗配置
    • 可配置多步骤向导
    • 可设置触发条件(页面/行为/角色)
    • 用户端按条件展示弹窗,消费后不再重复
  2. 数据验收:

    • 统计接口返回正确曝光/点击/完成率
    • 分时段趋势数据准确
  3. 兼容性验收:

    • 旧 OnboardingGuide.vue 逻辑不受影响
    • 旧 _onboardingDone 标记仍有效
    • 种子数据写入后小程序首次加载正常
  4. 质量验收:

    • 后端 mvn compile 无错误
    • 前端 node scripts/audit-duplicate-api-calls.js 无新增 ERROR
    • 所有新增代码通过 Java 检查清单(无类型错误、无异常吞没)

八、风险与应对

风险 影响 应对
触发条件逻辑复杂导致匹配效率低 性能问题 缓存激活配置到 Redis,本地匹配
管理端页面交互复杂 开发周期长 简化 UI,先实现核心功能
历史数据迁移 用户消费记录丢失 旧 _onboardingDone 逻辑保留,新旧并存过渡期
多端一致性问题 用户体验不一致 先小程序后 Web,统一设计 Token

设计状态:✅ 已确认,可进入实现阶段