# 商品赠送会员功能设计 - **日期**: 2026-08-03 - **状态**: 已确认(方案 B:独立赠送规则表) - **关联**: 商品购买 → 支付成功 → 自动赠送对应级别会员 ## 1. 需求背景 运营希望指定某几个商品,用户**原价购买**后赠送会员,不同商品赠送**不同级别**的会员(如商品 A 送 FAMILY、商品 B 送 PREMIUM)。 ### 已确认业务规则 | 决策点 | 结论 | |--------|------| | 赠送级别 | 任意有效等级(从 `membership_levels` 表下拉选择,过滤 FREE) | | 时长 | 不送时长,送级别;有效期按该级别年费周期(默认 365 天) | | 赠送对象 | **家庭创建者**(`users.member_level` 权威字段,与现有开通流程一致,全家共享) | | 已有会员 | 家庭已有**同级或更高级**有效会员时不送;无会员或等级更低则送(升级) | | 原价判定 | 无折扣无抵扣:`pointsUsed == 0 && couponId == null && discountAmount 为空` | | 退款 | 本期不回收会员(与测评额度逻辑一致) | ## 2. 数据模型 ### 新表 `product_gift_rules` ```sql CREATE TABLE IF NOT EXISTS product_gift_rules ( id BIGINT AUTO_INCREMENT PRIMARY KEY, product_id BIGINT NOT NULL COMMENT '关联products表', level_code VARCHAR(50) NOT NULL COMMENT '赠送会员等级编码(FAMILY/PREMIUM...)', status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_product_level (product_id, level_code), INDEX idx_product_id (product_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠送会员规则'; ``` - 与 `assessment_products`(测评商品扩展表)完全同构:一商品一规则(UNIQUE 约束),`status` 支持随时停用赠品活动而不动商品。 - **新增后端文件**: - `entity/ProductGiftRule.java` — MyBatis-Plus 实体(`@TableName("product_gift_rules")`) - `mapper/ProductGiftRuleMapper.java` — Mapper - `service/ProductGiftRuleService.java` — 规则查询/保存/停用(`@Resource` 注入,遵循项目 DI 规范) - **迁移**:`DatabaseInitializer.runMigrations()` 添加建表语句(幂等 `CREATE TABLE IF NOT EXISTS` + log.info),并同步 `schema.sql`。 - **管理端接口**: - `POST /api/admin/product-gift-rule/save`(productId, levelCode, status)— 新增/更新规则 - 查询随商品详情接口返回(见 §4) ## 3. 赠送触发(后端) ### 收口点:`ProductOrderService.handlePaymentSuccess(orderNo, transactionId)` 在现有"测评商品发放额度"逻辑之后追加赠送会员逻辑(两者模式完全一致,失败仅记日志、不阻塞支付流程): ``` 支付成功 → 查 product_gift_rules(productId 匹配 && status=1) → 校验"原价购买":order.pointsUsed==0 && order.couponId==null && (order.discountAmount==null || order.discountAmount==0) → 调 membershipService.grantMembershipByGift(...) → 异常捕获:log.error,不抛错 ``` ### 新方法:`MembershipService.grantMembershipByGift` 仿照 `processPaymentCallback` 核心(写 FamilyMembership + 更新 users + 写升级记录),差异点: | 项目 | 行为 | |------|------| | 参数 | `(familyId, userId, levelCode, sourceOrderNo, transactionId)` | | 目标用户 | 家庭创建者(查 family.creatorId;与现有流程一致) | | 前置校验 | 家庭创建者无有效会员,或有效等级**低于**赠送等级(等级高低按 `membership_levels.id` 排序)→ 否则跳过 | | 有效期 | 按级别年费周期:默认 `+365 天`(沿用 `upgradeToFamily` 的 365 天常量逻辑) | | 订阅记录 | 插入 `family_memberships`(paymentStatus 沿用现有 'paid' 值,不引入新枚举) | | 升级记录 | `member_upgrade_records.upgrade_type = 'gift'`(新增类型) | | 佣金 | **跳过**佣金结算(赠送非销售) | ### 等级高低比较 `membership_levels` 表按 `id` 自增顺序即等级从低到高(FREE < FAMILY < PREMIUM < PROVIDER)。比较逻辑: ``` 当前等级 = getMemberLevel(userId)(校验过期,返回 FREE 视为无有效会员) 当前等级 id >= 赠送等级 id → 跳过不送 否则 → 赠送(升级) ``` ## 4. 商品详情展示 - `ProductService` 详情组装时查询 `product_gift_rules`(status=1),将 `giftRule.levelCode` + 等级名附带进详情 DTO。 - 小程序 `pages/discover-detail/product-detail/product-detail.vue` 显示"购买即送 XX 会员"徽标(等级名来自 membership_levels 或前端映射)。 ## 5. 管理端配置(cfc-web) `ProductEdit.vue` 新增"赠送会员"区块: - 等级下拉:数据来自 `POST /api/membership/levels`,过滤 `FREE`,显示 level_name - 启用开关:控制 `status`(1=启用 0=停用) - 保存:调 `POST /api/admin/product-gift-rule/save` ## 6. 边界情况 | 场景 | 行为 | |------|------| | 家庭已有同级/更高级会员 | 不送(订单正常完成) | | 家庭无会员 / 等级更低 | 赠送(低等级则升级) | | 用积分/优惠券/折扣购买 | 不送(非原价) | | 赠品规则停用(status=0) | 不送 | | 赠送失败(异常) | 记日志,支付流程不受影响 | | 退款 | 本期不回收会员(与测评额度逻辑一致) | ## 7. 验证 - 后端:`mvn clean compile` 通过(项目规范) - 前端:`npm run build:mp-weixin` 构建通过;cfc-web 构建通过 - 部署:`mvn clean package -DskipTests`(部署脚本命令)通过 ## 8. 涉及文件清单 ### 后端(cfc-backend) - 新增 `entity/ProductGiftRule.java` - 新增 `mapper/ProductGiftRuleMapper.java` - 新增 `service/ProductGiftRuleService.java` - 修改 `config/DatabaseInitializer.java`(建表迁移) - 修改 `resources/schema.sql`(同步建表) - 修改 `service/ProductOrderService.java`(handlePaymentSuccess 追加赠送逻辑) - 修改 `service/MembershipService.java`(新增 grantMembershipByGift) - 新增/修改 `controller/admin/` 规则管理接口 - 修改 `service/ProductService.java`(详情附带 giftRule) ### 前端(cfc-frontend) - 修改 `pages/discover-detail/product-detail/product-detail.vue`(赠送徽标) ### 管理端(cfc-web) - 修改 `src/views/admin/ProductEdit.vue`(赠送会员区块) - 修改 `src/api/` 或对应 API 封装(save 规则接口)