# 戒烟/抽烟记录小程序:时序图 以下时序图使用 Mermaid(在支持 Mermaid 的 Markdown 渲染器中可直接预览)。 ## 1) 登录与鉴权(获取 Bearer Token) ```mermaid sequenceDiagram autonumber participant MP as 小程序(前端) participant API as 后端API(Gin) participant WX as 微信 jscode2session participant DB as MySQL participant Redis as Redis(可选) MP->>WX: wx.login() 获取 code MP->>API: POST /api/v1/auth/login {mini_program_id, code, ...可选资料} API->>DB: 读取 mini_programs(app_id/app_secret) API->>WX: code 换取 openid/session_key API->>DB: upsert users(mini_program_id+open_id) alt 启用 Redis session cache API->>Redis: 写入 session_key -> user 缓存 end API-->>MP: {session_key} 作为后续 Authorization: Bearer ``` ## 2) 首次进入:基础信息补全(Profile) ```mermaid sequenceDiagram autonumber participant MP as 小程序(前端) participant API as 后端API participant DB as MySQL MP->>API: GET /api/v1/smoke/profile (Bearer) API->>DB: 查询 fa_smoke_user_profile(uid) API-->>MP: exists/is_completed/baseline_interval_minutes/作息等 alt 需要补全 MP->>API: POST /api/v1/smoke/profile {...基础烟量/动机/动力/作息...} API->>DB: upsert fa_smoke_user_profile(uid) API-->>MP: 返回最新 profile + baseline_interval_minutes end ``` ## 3) 记录抽烟 / 记录“忍住” ```mermaid sequenceDiagram autonumber participant MP as 小程序(前端) participant API as 后端API participant DB as MySQL alt 实际抽烟 MP->>API: POST /api/v1/smoke/logs {smoke_at?, remark?, level?, num?} (Bearer) API->>DB: INSERT fa_smoke_log(uid, smoke_time, smoke_at, remark, level, num) API-->>MP: 返回记录 else 想抽但忍住 MP->>API: POST /api/v1/smoke/logs/resisted {smoke_at?, remark?} (Bearer) API->>DB: INSERT fa_smoke_log(uid, ..., level=0, num=0) API-->>MP: 返回记录(用于列表展示) end ``` ## 4) 首页:获取“下次抽烟记录时间”(默认 + AI 自动切换) 说明:统一使用 `GET /api/v1/smoke/next_smoke_time`。 ```mermaid sequenceDiagram autonumber participant MP as 小程序(前端) participant API as 后端API participant DB as MySQL MP->>API: GET /api/v1/smoke/next_smoke_time?date=today&mode=auto (Bearer) API->>DB: 查 fa_smoke_ai_advice(type=next_smoke_time, advice_date=today) 是否存在 alt 已存在 AI 建议且 time_nodes 非空 API->>DB: 查 fa_smoke_ai_next_smoke(ai_advice_id) 取 not_before/suggested/nodes API-->>MP: source=ai + 时间节点 + advice + default(兜底信息) else 不存在 AI 建议 API->>DB: 查 fa_smoke_user_profile(uid) 取 baseline_interval/作息 API->>DB: 查 fa_smoke_log 取最后一次实际抽烟 + 最近7天忍住次数 API-->>MP: source=default + default.next_smoke_at end ``` ## 5) 生成 AI “下次抽烟时间节点”(需要每日广告解锁) 说明:前端先“看广告解锁”,再用 `mode=ai` 生成当天/明天的 AI 时间节点;生成结果缓存“一天一份”。 ```mermaid sequenceDiagram autonumber participant MP as 小程序(前端) participant API as 后端API participant DB as MySQL participant AI as AI Provider(OpenAI-compatible) MP->>API: POST /api/v1/smoke/ai/advice_unlocks {date: "YYYY-MM-DD"} (Bearer) API->>DB: upsert fa_smoke_ai_advice_unlocks(uid, unlock_date=date) API-->>MP: unlocked=true MP->>API: GET /api/v1/smoke/next_smoke_time?date=YYYY-MM-DD&mode=ai (Bearer) API->>DB: 校验是否解锁(或会员) alt 未解锁 API-->>MP: 403 需要观看广告解锁 else 已解锁 API->>DB: 读取最近3天 fa_smoke_log(含忍住) + profile + 默认策略 API->>AI: /chat/completions(严格JSON输出) API->>DB: 写 fa_smoke_ai_advice(type=next_smoke_time, advice_date=date, ...) API->>DB: 写 fa_smoke_ai_next_smoke(每个时间点一条:not_before/suggested/node) API-->>MP: source=ai + 时间节点 end ``` ## 6) 每日 AI 戒烟建议(会员/广告解锁) ```mermaid sequenceDiagram autonumber participant MP as 小程序(前端) participant API as 后端API participant DB as MySQL participant AI as AI Provider(OpenAI-compatible) MP->>API: GET /api/v1/smoke/ai/advice?date=YYYY-MM-DD (Bearer) API->>DB: 查 fa_smoke_ai_advice(type=daily_advice, advice_date=date) 是否已缓存 alt 已缓存 API-->>MP: advice else 未缓存 API->>DB: 校验会员或广告解锁(unlock_date=date) alt 未解锁/非会员 API-->>MP: 403 need vip_or_ad else 已解锁/会员 API->>DB: 读取当天 fa_smoke_log(节点/总量) API->>AI: /chat/completions 生成建议 API->>DB: 写 fa_smoke_ai_advice(type=daily_advice,...) API-->>MP: advice end end ```