2026-08-01-activity-registration-upgrade-design.md 12 KB

活动模块升级设计(报名状态 / 付费 / 状态机 / 签到身份 / 审核发布 / 总结资料)

日期: 2026-08-01 状态: 设计定稿 v1(需求逐项确认完成) 前置文档: 2026-07-31-activity-registration-form-design.md(报名表单,已实施)


1. 概述

活动模块 7 项需求改造,覆盖报名体验、收费模型、状态机、签到身份校验与普通用户发布审核流程。核心变化:

  1. 活动卡片显示报名状态(此前硬编码「进行中」)
  2. 报名弹窗删除重复的取消/确认按钮(uni-app 内置 <modal> 自带按钮与插槽按钮重复)
  3. 报名时间窗口:新增「报名截止时间」字段,活动发布即开放报名,截止后停止
  4. 付费报名:先支付后报名;双费用为 0 时直接报名成功
  5. 签到身份校验:有手机号孩子只能本人签到;无手机号孩子家长可代签(校验家庭关系 + 报名记录)
  6. 收费模型升级:孩子/家长双收费 × 会员/非会员双价格(4 个费用字段)
  7. 卡片状态机:报名中 / 已报名 / 进行中 / 已签到 / 总结中 / 已结束

补充(用户确认):普通用户也可发布活动,但必须经管理员审核后才能正式发布;活动结束后进入「总结中」,发布人可上传活动资料、参与者可点评,手动结束或 7 天未结束自动结束。

2. 需求与决策记录

# 需求 决策
1 「已经报过名的未显示」 根因:卡片硬编码「进行中」,后端 list 不返回当前用户报名状态 → 卡片显示报名状态(displayStatus)
2 报名弹窗重复确认/取消按钮 删除 uni-app 内置 <modal> 底部「确定/取消」按钮,改自定义 view 遮罩弹窗(三个弹窗统一改造:报名 / 签到惩罚 / 评价)
3 报名时间窗口 新增 registration_deadline 字段,仅按截止时间控制(发布即开放);签到仅活动进行中;按钮缩小
4 付费报名 先支付后报名;双费用均为 0 → 直接报名成功
5 签到身份 有手机号孩子 → 只能本人签到;无手机号孩子 → 家长可代签(校验家庭关系 + 该孩子 approved 报名记录)
6 收费模型 活动级 child_fee / parent_fee × 会员/非会员 → 4 个费用字段(会员价可免费=0),替代 price / memberPrice
7 状态机 报名中 / 已报名 / 进行中 / 已签到 / 总结中 / 已结束(已结束不在列表,历史记录可查)
8 发布人范围 普通用户可创建活动(draft)→ 提交审核(pending)→ 管理员审核(approved=published / rejected=驳回+原因)→ 驳回可 re-draft 修改再提交
9 总结中阶段 活动结束后自动进入「总结中」:发布人上传活动资料(图片/PDF/链接,多条,时间排序);参与者(已签到)可点评;发布人手动「结束」或 7 天未结束自动结束 → 已结束
10 未报名签到 保留现逻辑:扣能量(energy_penalty_unregistered)放行

3. 状态机

3.1 发布状态(activities.status,后端落库)

draftpending(提交审核)→ published(审核通过)/ rejected(驳回)→ withdrawn(撤回)→ ended(结束)

  • publish(draft 直接发布)仅保留给 admin/activity_admin 直发;普通用户走 submit-reviewaudit
  • 现有审核接口已具备:/api/admin/activity/submit-review/audit/re-draft/withdraw/review

3.2 展示状态(displayStatus,卡片用,按用户视角计算)

优先级自上而下(单个活动只命中一个):

优先级 displayStatus 条件 displayLabel
1 ended status = ended 已结束(列表过滤,不在活动列表,历史可查)
2 summarizing status = publishednow > endTime 总结中(发布人可传资料,参与者可点评)
3 checked_in 当前用户该活动存在签到记录 已签到
4 ongoing startTime <= now <= endTime 进行中
5 registered 当前用户存在 approved 报名记录 已报名
6 pending_start now > registration_deadline(未报名) 待开始
7 open now <= registration_deadline(未报名) 报名中
  • 计算输入:activity.status / startTime / endTime / registration_deadline + 当前用户 userId 的报名与签到状态
  • 7 天自动结束:status = publishednow > endTime + 7 天 → 惰性更新 status = ended(list 查询时批量处理,无需定时任务)

3.3 报名状态(registrationStatus,详情页用)

not_registered / registered(approved)/ pending(报名审核中)/ rejected(被拒)/ cancelled / checked_in

4. 数据库设计

4.1 activities 表新增 6 列(迁移 142)

列名 类型 说明
registration_deadline DATETIME NULL 报名截止时间(NULL=不限制,默认=活动开始时间)
child_fee INT DEFAULT 0 孩子·非会员价(分)
child_member_fee INT DEFAULT 0 孩子·会员价(分),0=免费
parent_fee INT DEFAULT 0 家长·非会员价(分)
parent_member_fee INT DEFAULT 0 家长·会员价(分),0=免费
creator_id BIGINT NULL 创建人 userId(普通用户发布者),admin 创建可为空
  • price / member_price 字段废弃不再使用(保留列不删,避免破坏历史数据)

4.2 新表 activity_orders(迁移 143)— 活动报名订单

列名 类型 说明
id BIGINT PK AUTO 主键
order_no VARCHAR(64) UNIQUE 订单号(ACT + 时间戳 + 随机)
activity_id BIGINT 活动 ID
user_id BIGINT 下单人 userId
total_amount INT 实付金额(分)
registrants_json TEXT 报名人快照 JSON([{name, phone, childId, type: child/parent, fee}]
status VARCHAR(20) pending / paid / cancelled
transaction_id VARCHAR(64) NULL 微信支付单号
paid_at DATETIME NULL 支付时间
created_at DATETIME 创建时间
  • 支付成功回调 → status = paid + 写 activity_registrations 报名记录(同一事务/回调幂等:order_no 唯一,已处理直接返回成功)

4.3 新表 activity_materials(迁移 144)— 活动总结资料

列名 类型 说明
id BIGINT PK AUTO 主键
activity_id BIGINT 活动 ID
title VARCHAR(200) NULL 标题
file_url VARCHAR(500) 文件地址(图片/PDF/外链 URL)
file_type VARCHAR(20) image / pdf / link
created_at DATETIME 创建时间
  • 仅发布人(creator 或 admin/activity_admin)可上传/删除;活动进入「总结中」后开放
  • 列表按 created_at 倒序(最新在前)

5. 后端 API 设计

5.1 改动接口

接口 变更
POST /api/activity/create 放开普通用户(parent 可创建,status=draft,记录 creatorId);admin/activity_admin 行为不变
POST /api/activity/update 同上放开;仅创建人/admin 可改
POST /api/activity/list 返回 displayStatus / displayLabel / registrationStatus(按当前 userId);过滤 ended;惰性处理 7 天自动结束
POST /api/activity/detail 返回 displayStatus / displayLabel / registrationStatus / 4 个费用字段 / registrationDeadline / 资料列表 materials
POST /api/activity/register 校验 registration_deadline;手机号可选(无手机号孩子允许报名);付费活动必须先有已支付订单(校验 activity_orders
POST /api/activity/checkin 时间窗校验(仅活动进行中);身份校验:有手机号孩子=本人签,无手机号孩子=家长代签(家庭关系 + 该孩子 approved 报名)
POST /api/activity/end 保持(手动结束),admin/activity_admin/创建人可结束
POST /api/activity/submit-review 普通用户提交审核:draft → pending(仅创建人/admin 可提交自己的活动)——复用 ActivityAdminService.submitForReview 能力,需加 creatorId 校验

5.2 新接口

接口 说明
POST /api/activity/order/create 创建活动报名订单:入参 {activityId, registrants:[{name, phone, childId}]};校验截止时间/名额/重复报名;按下单人会员等级(MembershipService.getMemberLevel,FAMILY/PROVIDER=会员)选择费用;总额=Σ(人数×单价);0 元直接走报名成功不建订单
POST /api/activity/order/pay PaymentService.createWechatPrepay 返回 wechatPayParams
POST /api/activity/order/handlePaymentSuccess 前端支付成功回调:幂等置 paid + 写报名记录(仿照 ProductOrderController.handlePaymentSuccess
POST /api/activity/order/notify 微信支付异步通知:复用 PaymentService.handleWechatNotify加入 JwtInterceptor 公开白名单
POST /api/activity/order/status 查询订单状态(支付页轮询/回调兜底)
POST /api/activity/material/upload 上传资料(仅发布人,总结中阶段)
POST /api/activity/material/list 资料列表(按 activityId,倒序)
POST /api/activity/material/delete 删除资料(仅发布人)
  • 费用计算复用现有会员判定:ActivityDTO.from(activity, isGuest, memberLevel) 已有会员价格解析先例,新逻辑按下单人 memberLevel 取对应 4 个字段
  • 回调幂等:order_no 唯一索引,status=paid 直接返回成功

6. 小程序前端改动

6.1 activity-detail.vue(核心改造)

  • 弹窗改造:报名 / 签到惩罚 / 评价三个 <modal> → 自定义 view 遮罩弹窗(去掉内置「确定/取消」按钮,保留插槽内自定义操作按钮);报名弹窗底部「确认报名」按钮缩小
  • 报名截止报名截止: MM-DD HH:mm(用 registrationDeadline,不再误用 endTime
  • 付费流程:点击报名 → 若费用合计 > 0 → order/create → 支付页/requestPayment → 成功回调 → 刷新为已报名;合计 = 0 → 直接 register 成功
  • 费用展示:孩子价 / 家长价(区分会员与非会员),当前用户为会员时展示会员价(含「会员免费」)
  • 手机号可选:报名表单手机号非必填;无手机号孩子可报名
  • 总结中displayStatus=summarizing 时展示资料区(发布人可上传/删除,参与者可查看)+ 评价入口(已签到者)
  • 签到按钮:仅 ongoing 显示;签到后显示已签到

6.2 index.vue

  • 卡片状态改用后端 displayLabel(删除硬编码「进行中」)
  • 管理 tab:「发布」按钮 → 普通用户调 submit-review(提交审核),admin/activity_admin 保留直发
  • 列表自动过滤已结束活动

6.3 create.vue

  • 新增字段:报名截止时间、孩子非会员价、孩子会员价、家长非会员价、家长会员价(单位:元,前端转分)
  • 发布人角色放开(普通用户可进入创建页)

7. Web 管理端改动

7.1 ActivityEdit.vue

  • 新增:报名截止时间 + 4 个费用字段(孩子费/孩子会员费/家长费/家长会员费,单位元)
  • 价格展示不再使用 price / memberPrice

7.2 审核流(已存在,无需大改)

  • ActivityReview.vue 已支持审核(approved/rejected+原因);普通用户提交审核后进入待审核列表

8. 验收标准

  • 卡片显示真实状态(报名中/已报名/进行中/已签到/总结中),不再硬编码
  • 报名弹窗无重复取消/确认按钮,报名按钮缩小
  • 超过报名截止时间无法报名;签到仅活动进行中可操作
  • 付费活动:未支付无法报名;支付成功后自动报名成功;免费活动直接报名
  • 有手机号孩子不能家长代签;无手机号孩子家长可代签(需家庭关系+报名记录)
  • 会员看到会员价(可免费),非会员看到非会员价
  • 活动结束进入「总结中」:发布人可传资料(图片/PDF/链接多条)、参与者可点评;手动结束或 7 天自动结束
  • 普通用户可创建活动并提交审核,管理员审核通过后正式发布
  • mvn clean compile 通过;迁移幂等可重复执行