日期:2026-09-22 状态:✅ 已确认 - 可进入实现阶段 需求来源:用户确认弹窗引导页需实现配置化管理,支持管理员配置弹出条件与内容
OnboardingGuide.vue 的 PARENT_STEPS / CHILD_STEPS 为硬编码_onboardingDone 本地标记(首次登录仅弹一次)_onboardingDone 逻辑,新配置逐步替代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 | 是否点击了按钮 |
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)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 }
]
}
]
}
业务逻辑:
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 }
| 方法 | 路径 | 说明 |
|---|---|---|
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 }
]
}
}
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 + 跳转生命周期:
mounted:调用 /api/guide/popup/list 拉取激活配置/trigger 接口)pages/index-home/index.vue_maybeShowOnboardingGuide() 中的硬编码逻辑GET /api/guide/popup/list(实际为 POST 无参)slug 决定渲染哪个弹窗_onboardingDone 兼容逻辑:若已消费则不展示新弹窗pages/home-pages/child-index.vueviews/admin/GuidePopupConfig.vueviews/admin/GuidePopupStats.vue1. DatabaseInitializer 新增 4 张表迁移
2. 实体类:GuidePopup, GuidePopupStep, GuidePopupTrigger, GuidePopupLog
3. Mapper 接口 + XML(如需)
4. Service: GuidePopupService(CRUD + 匹配逻辑)
5. Controller: GuidePopupController(用户端 3 接口)
6. Controller: AdminGuidePopupController(管理端 6 接口)
1. components/ConfigurableGuide.vue
2. pages/index-home/index.vue 接入
3. pages/home-pages/child-index.vue 接入
1. views/admin/GuidePopupConfig.vue
2. views/admin/GuidePopupStats.vue
3. 路由注册(cfc-web/src/router/)
4. API 封装(cfc-web/src/api/)
1. DatabaseInitializer 写入种子数据(现有 PARENT_STEPS 作为 seed)
2. 兼容验证:旧 OnboardingGuide.vue 逻辑保留
3. 文档更新(API_REFERENCE.md)
@PostMapping,禁止 @GetMapping/@PutMapping/@DeleteMapping@TableName + @TableId(type = IdType.AUTO)@Resource,字段名匹配 Bean NameResult<T> 统一包装DatabaseInitializer.runMigrations() 幂等执行?.,用 && 替代:key 表达式,用方法调用src/router/index.jssrc/api/ 目录功能验收:
数据验收:
兼容性验收:
_onboardingDone 标记仍有效质量验收:
mvn compile 无错误node scripts/audit-duplicate-api-calls.js 无新增 ERROR| 风险 | 影响 | 应对 |
|---|---|---|
| 触发条件逻辑复杂导致匹配效率低 | 性能问题 | 缓存激活配置到 Redis,本地匹配 |
| 管理端页面交互复杂 | 开发周期长 | 简化 UI,先实现核心功能 |
| 历史数据迁移 | 用户消费记录丢失 | 旧 _onboardingDone 逻辑保留,新旧并存过渡期 |
| 多端一致性问题 | 用户体验不一致 | 先小程序后 Web,统一设计 Token |
设计状态:✅ 已确认,可进入实现阶段