# 邀请分享卡片 + 自动登录设计方案 **日期:** 2026-05-25 **状态:** 已审批 ## 问题 1. 家长修改孩子手机号后,孩子用新手机号登录仍提示需要注册,而非直接进入孩子端。 2. 家庭内各成员(孩子、其他家长、成长规划师)之间缺少便捷的邀请绑定机制。 ## 方案概述 通过微信小程序原生分享卡片(Forward Message),携带加密邀请参数。接收方点击卡片进入小程序,后端根据邀请码类型自动处理注册/登录/绑定。三种邀请卡片分别对应不同的业务场景和入口。 ## 三种邀请卡片 | 类型 | type 值 | 入口页面 | 生成条件 | 接收方行为 | |------|---------|----------|----------|------------| | 邀请孩子 | `child` | 孩子管理 → 每个孩子旁的「邀请」按钮 | 该孩子已在家庭中,有手机号 | 获取手机号 → 匹配 → 自动注册/登录 → 进入孩子端 | | 邀请家人 | `family` | 我的页面 → 「邀请家人」按钮 | 用户已有家庭 | 获取手机号 → 匹配 → 加入家庭 → 登录 | | 邀请规划师 | `guide` | 成长档案管理 → 「邀请规划师」按钮 | 用户已有家庭 | 打开规划师注册页 → 绑定家庭 | ## 分享卡片形式 使用微信小程序原生 `wx.shareAppMessage` 分享卡片,卡片信息包含: - 标题(如:「xxx 邀请你加入家庭」) - 分享图(静态图) - 路径带参数 `?invite_code=xxx` 接收方打开小程序时,`App.onLaunch` / `Page.onLoad` 可获取 `invite_code` 参数。 ## 邀请码设计 后端生成统一的邀请码,前缀标识类型 + 随机码: 示例:`CHILD_a1b2c3`、`FAMILY_d4e5f6`、`GUIDE_g7h8i9` 每个邀请码含: - `type`:业务类型(child/family/guide) - `ref_id`:关联 ID(childId / familyId) - `code`:唯一邀请码字符串 - `created_at`:创建时间 - `expires_at`:过期时间(24小时) - `used`:是否已使用 ## 后端接口 ### 1. 生成邀请码 ``` POST /api/user/invite-card/generate Request: { type: "child"|"family"|"guide", refId: childId|familyId|familyId } Response: { code: "CHILD_a1b2c3", expiresAt: "2026-05-26T12:00:00" } ``` ### 2. 接受邀请(自动注册/登录) ``` POST /api/user/invite-card/accept Request: { code: "CHILD_a1b2c3", encryptedData: "", iv: "", phone?: "139..." } Response: { token, userId, role, familyId, ... } ``` 流程: 1. 解析 code → 获取 type + refId 2. 如果是 child 类型 → 从 refId 获取孩子信息(含手机号) 3. 获取用户手机号(优先从微信加密数据解析,测试环境直接传 phone) 4. 匹配手机号与该家庭预留的手机号 5. 若手机号匹配: - 已有账号 → 直接登录 - 无账号 → 自动注册(用该手机号创建用户)→ 绑定到家庭 → 返回 token 6. 失败返回错误信息 ### 3. 验证邀请码(用于页面展示) ``` POST /api/user/invite-card/verify Request: { code: "CHILD_a1b2c3" } Response: { type: "child", nickname: "小明", familyName: "张三家庭" } ``` ## 数据库 ### invite_card 表(新表) ```sql CREATE TABLE invite_card ( id BIGINT AUTO_INCREMENT PRIMARY KEY, type VARCHAR(20) NOT NULL COMMENT 'child/family/guide', code VARCHAR(64) NOT NULL UNIQUE COMMENT '邀请码', ref_id BIGINT NOT NULL COMMENT '关联ID(childId/familyId)', creator_id BIGINT NOT NULL COMMENT '创建人', expires_at DATETIME NOT NULL COMMENT '过期时间', used TINYINT DEFAULT 0 COMMENT '是否已使用', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_code (code), INDEX idx_ref_type (ref_id, type) ) COMMENT='邀请卡片'; ``` ## 前端改动 ### 三个入口按钮 | 页面 | 添加内容 | |------|----------| | `pages/profile/children.vue` | 每个孩子卡片右下角加「邀请」按钮 → 生成 child 类型卡片 → `wx.shareAppMessage` | | `pages/profile/profile.vue` | 菜单列表加「邀请家人」→ 生成 family 类型卡片 | | `pages/growth/index.vue` | 加「邀请规划师」按钮 → 生成 guide 类型卡片 | ### 分享卡片触发 使用 `button open-type="share"` 触发分享,在 `onShareAppMessage` 中设置: ```javascript onShareAppMessage() { return { title: 'xxx 邀请你加入家庭', path: '/pages/login/login?invite_code=CHILD_a1b2c3', imageUrl: '/static/invite-card.png' } } ``` ### 登录页处理邀请参数 `login.vue` 的 `onLoad` 中检测 `invite_code`: ```javascript onLoad(options) { if (options.invite_code) { this.inviteCode = options.invite_code } } ``` ### 接受邀请流程 1. 用户打开卡片 → 进入登录页 2. 登录页检测到 `invite_code` 3. 用户点击「微信一键登录」(获取手机号) 4. 前端调 `acceptInviteCard(code, encryptedData, iv)` 5. 后端处理 → 返回 token → 前端保存并跳转到对应首页 ## 约束 - 邀请码有效期 24 小时 - 每个孩子/家庭只能有一个未使用的邀请码(生成新码时自动失效旧码) - 孩子场景下,手机号必须与该家庭预留的手机号匹配 - 不匹配或已过期 → 提示错误 - 不需要用户协议弹窗(邀请场景自动注册视为已同意)