xiangqinxiaochengxu/需求补充计划.md
taiyi a8e6edf296 更新功能修改完版本提交:
功能需求:活动分享与嘉宾匹配系统
1. 活动分享入口
每个活动配置独立的分享链接和二维码,支持扫码或点击链接进入小程序。
2. 用户绑定流程
用户通过分享链接/二维码打开小程序,填写个人信息并绑定至对应活动。
若用户曾参与过历史活动,系统自动复用其历史信息并完成绑定,无需重复填写。
绑定成功后,在活动正式开始前,用户无法查看其他参与者的信息。
3. 信息可见性规则
活动开始前:仅允许查看自己的信息,其他用户信息不可见。
活动开始后:开放本活动内异性嘉宾资料查看与匹配,其他活动的用户信息完全隔离,不可见。
资料展示:男嘉宾、女嘉宾资料分开展示,用户仅可浏览异性嘉宾信息。
4. 嘉宾选择规则
每位用户最多可选择 3 位心仪嘉宾。
确认提交后不可再新增选择,但支持修改或撤销已选嘉宾。
管理员可设置匹配截止时间,到达截止时间后系统自动锁定,禁止任何修改。
5. 匹配判定规则
双向互选:若双方恰好互选,则判定为匹配成功,双方均可查看匹配结果。
多向匹配:用户同时与多位嘉宾匹配成功,全部同时展示。
单向选择:A选择B但B未选择A,A可在"谁选了我"页面看到B。
6. 用户页面说明
异性嘉宾列表:展示所有异性嘉宾资料,支持选择/取消选择。
我的选择:展示当前已选的3位嘉宾,支持修改/撤销(截止前)。
谁选了我:展示所有选择了自己的嘉宾(无论自己是否选择了对方)。
匹配成功:展示所有双向互选的匹配对象,支持查看对方完整资料。
2026-05-17 10:23:02 +08:00

749 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 需求补充计划
## 一、文档目标
本文档用于补充“活动分享与嘉宾匹配系统”的详细设计方案,并结合当前项目实际代码结构,明确以下内容:
- 在保留现有“小程序滑动选择页面”的前提下,如何完成活动内匹配能力改造
- 当前系统与目标需求之间的差距
- 建议的数据结构、接口设计、页面设计与权限规则
- 需要修改的后端、管理端、小程序文件范围
- 推荐实施顺序与风险提示
## 二、当前系统现状总结
当前项目由三部分组成:
- 后端:`backend`
- 管理后台:`admin-web`
- 微信小程序:`miniprogram`
当前已经具备的基础能力:
- 微信登录与用户体系
- 用户全局资料维护
- 活动创建、发布、报名
- 活动报名关系记录
- 基础匹配能力
- 小程序滑动选择页
当前关键代码位置:
- 活动模型:`backend/app/models/activity.py`
- 用户模型:`backend/app/models/user.py`
- 活动报名模型:`backend/app/models/registration.py`
- 匹配模型:`backend/app/models/match.py`
- 活动服务:`backend/app/services/activity_service.py`
- 匹配服务:`backend/app/services/match_service.py`
- 小程序活动详情页:`miniprogram/pages/activity-detail`
- 小程序滑动匹配页:`miniprogram/pages/match`
- 小程序我的匹配页:`miniprogram/pages/my-matches`
- 管理后台活动管理:`admin-web/src/views/activities`
## 三、本次需求的核心目标
本次不是新增一个完全独立的陌生系统,而是在现有“活动 + 用户 + 匹配”的基础上,完成“活动内隔离的嘉宾互选系统”。
必须满足的核心目标如下:
1. 每个活动有独立分享入口,可通过链接或二维码进入。
2. 用户通过分享入口进入后,绑定到该活动。
3. 如用户已有历史资料,则自动复用,无需重复填写。
4. 活动开始前,用户不能查看其他参与者信息。
5. 活动开始后,只能查看本活动内异性嘉宾资料。
6. 每位用户最多选择 3 位嘉宾。
7. 截止时间前允许调整或撤销,截止时间后锁定。
8. 支持查看“我的选择”“谁选了我”“匹配成功”。
9. 匹配结果必须按活动隔离,不能与其他活动串数据。
10. 保留现有滑动选择页,作为活动内异性嘉宾浏览与选择入口。
## 四、保留滑动选择页的设计结论
### 4.1 保留原则
现有页面 `miniprogram/pages/match` 可以保留,不建议推倒重做。
保留内容包括:
- 滑卡式浏览体验
- 左滑跳过、右滑选择的交互模型
- 页面主体样式和卡片信息展示结构
- 当前活动模式下的页面入口结构
### 4.2 改造原则
保留页面,不代表保留现有活动匹配的数据逻辑。
需要改造的是:
- 页面背后的数据来源
- 活动模式下的权限判断
- 选择次数限制
- 截止锁定规则
- 活动隔离逻辑
- 配套页面的数据结构
### 4.3 滑动页在新系统中的定位
建议将滑动选择页定义为:
- “活动内异性嘉宾浏览页”
- “我的选择”的新增入口
- 活动开始后才可进入
建议交互规则如下:
- 左滑:跳过当前嘉宾,不产生选择关系
- 右滑:将该嘉宾加入“我的选择”
- 不在滑动页执行撤销
- 撤销和修改在“我的选择”页处理
这样可以最大程度保留现有体验,同时降低交互混乱和实现复杂度。
## 五、当前系统与需求之间的差距
### 5.1 活动分享入口缺失
当前活动系统只有活动列表和活动详情,没有活动独立分享标识,也没有二维码或分享 token 的模型支持。
缺口:
- 活动无独立分享 token
- 无分享链接生成逻辑
- 无分享二维码数据字段
- 无“通过分享入口进入活动”的后端接口
### 5.2 报名绑定逻辑不完整
当前已经有 `registrations` 表作为用户报名活动关系,但现有流程更偏向用户主动进入活动后点击报名,不是“通过分享入口进入并自动绑定”的闭环。
缺口:
- 缺少分享入口触发的绑定流程
- 缺少“资料不完整时先补资料再自动绑定”的回流逻辑
### 5.3 活动开始前的信息隔离未满足
当前活动详情页存在已报名用户预览能力,会展示其他参与者的信息预览。
这与新需求冲突:
- 活动开始前只能看自己
- 不能看其他参与者
### 5.4 现有匹配不是活动隔离
当前 `match_likes` 表没有 `activity_id`,无法保证选择关系只属于某一场活动。
这会造成以下问题:
- A 活动中的选择影响 B 活动
- “谁选了我”可能出现其他活动的人
- “匹配成功”可能跨活动串联
### 5.5 现有匹配结果页不适合正式活动玩法
当前“我的匹配”页面里混用了服务端数据和本地缓存记录,且详情页存在演示数据兜底逻辑。
正式活动系统不能继续依赖这些临时逻辑。
## 六、总体设计方案
本次建议采用“保留前端滑动页,新增活动内匹配子系统”的设计。
设计原则:
- 用户资料继续使用全局 `users`
- 活动绑定继续使用 `registrations`
- 活动内嘉宾选择单独建模
- 活动内匹配接口独立建设
- 不强行复用现有全局匹配表承载新规则
一句话总结:
“用户还是全局的,资料还是复用的,但选择关系必须是活动内独立的。”
## 七、数据结构设计建议
### 7.1 `activities` 表新增字段
建议为活动表新增以下字段:
- `share_token`
- 用途:每个活动独立分享标识
- 要求:唯一
- `match_deadline`
- 用途:管理员设置匹配截止时间
- `selection_limit`
- 用途:每个活动最多可选人数
- 默认值3
- `share_qr_url`
- 用途:保存二维码图片地址
- 可选字段
### 7.2 保留 `registrations` 表作为活动绑定关系
现有 `registrations` 表可以继续承担以下职责:
- 用户是否已绑定活动
- 用户是否有效参与该活动
- 活动内可见性判断基础
如需增强,可考虑新增字段:
- `bind_source`
- 值示例:`share_link`、`qrcode`、`manual`
- `bound_at`
- 用途:记录绑定时间
这部分属于增强项,不是第一优先级。
### 7.3 新增活动内嘉宾选择表
建议新增表:`activity_guest_choices`
字段建议如下:
- `id`
- `activity_id`
- `from_user_id`
- `to_user_id`
- `status`
- 建议取值:`active`、`cancelled`
- `created_at`
- `updated_at`
唯一约束建议:
- `(activity_id, from_user_id, to_user_id)`
此表承担的职责:
- 记录我在某个活动中选了谁
- 支持撤销选择
- 支持重新选择
- 为“谁选了我”提供基础数据
- 为“双向互选”实时计算提供基础数据
### 7.4 是否保留现有 `match_likes` / `matches`
建议:
- 保留现有表,避免影响旧功能
- 新活动匹配逻辑不要继续依赖旧表
原因:
- 旧表是全局匹配逻辑
- 新需求是活动内隔离逻辑
- 两者的约束不同,直接混用风险高
## 八、权限与可见性规则设计
### 8.1 活动开始前
用户进入活动后:
- 可查看自己的资料和绑定状态
- 不可查看其他参与者列表
- 不可进入嘉宾选择页
- 不可查看“谁选了我”
- 不可查看“匹配成功”
系统返回建议:
- `can_view_candidates = false`
- `can_match = false`
- `stage = before_start`
### 8.2 活动开始后且截止前
用户在满足以下条件后,可进行匹配:
- 已登录
- 已绑定当前活动
- 当前活动已开始
- 当前时间未超过匹配截止时间
- 用户资料有效
此阶段允许:
- 浏览本活动内异性嘉宾
- 右滑选择
- 查看我的选择
- 撤销或修改我的选择
- 查看谁选了我
- 查看匹配成功
### 8.3 匹配截止后
系统自动锁定:
- 不允许新增选择
- 不允许撤销选择
- 不允许修改选择
但可以继续查看:
- 我的选择
- 谁选了我
- 匹配成功
系统返回建议:
- `can_choose = false`
- `can_modify_choice = false`
- `stage = matching_closed`
### 8.4 跨活动隔离
任何与活动匹配相关的数据查询都必须带 `activity_id` 维度。
包括:
- 候选人列表
- 我的选择
- 谁选了我
- 双向互选列表
- 匹配详情
不能出现以下情况:
- 来自其他活动的用户被展示
- 其他活动的选择记录进入当前活动
- 跨活动的匹配结果互相污染
## 九、用户流程设计
### 9.1 分享入口流程
流程建议如下:
1. 用户通过分享链接或二维码进入小程序。
2. 系统识别 `share_token` 或活动参数。
3. 若用户未登录,先静默登录。
4. 根据分享标识查询活动。
5. 若用户已存在历史资料,则直接读取全局资料。
6. 若资料完整,则执行活动绑定。
7. 若资料不完整,则跳转资料完善页。
8. 资料保存成功后返回活动并自动绑定。
### 9.2 活动开始前流程
用户进入活动详情后:
- 看到活动信息
- 看到自己已绑定状态
- 看到“活动未开始,暂不可查看嘉宾信息”的提示
### 9.3 活动开始后流程
用户进入活动详情后:
- 点击“进入匹配”
- 跳转至保留的滑动选择页
- 系统只加载本活动内异性嘉宾
- 右滑即加入“我的选择”
### 9.4 我的选择流程
用户可以查看:
- 当前已选择的嘉宾
- 已用名额和剩余额度
截止前允许:
- 撤销已选嘉宾
- 从滑动页继续新增其他人
### 9.5 谁选了我流程
用户可以查看:
- 所有选择了自己的嘉宾
- 无论自己是否选择对方,都可在这里看到
但资料展示需按权限控制,避免提前暴露过多隐私。
### 9.6 匹配成功流程
当双方互为 `active` 选择时:
- 判定为匹配成功
- 在“匹配成功”页展示
- 支持查看对方完整资料
## 十、页面设计建议
### 10.1 活动详情页
页面:`miniprogram/pages/activity-detail`
需要新增或调整的内容:
- 支持从分享入口进入活动
- 显示绑定状态
- 显示活动阶段
- 显示匹配截止时间
- 活动开始前不显示他人预览
- 活动开始后显示“进入匹配”
建议移除或关闭:
- 当前 `registered_preview` 的展示
### 10.2 滑动选择页
页面:`miniprogram/pages/match`
保留页面,调整活动模式下的数据来源和文案。
建议增强内容:
- 页面顶部显示当前活动标题
- 显示“剩余可选人数”
- 显示匹配截止时间
- 显示快速入口:
- 我的选择
- 谁选了我
- 匹配成功
页面职责:
- 只负责浏览与新增选择
- 不负责撤销选择
### 10.3 我的匹配页
页面:`miniprogram/pages/my-matches`
建议重构为活动内结果页,可使用 tab 结构:
- 我的选择
- 谁选了我
- 匹配成功
说明:
- 不建议继续保留本地缓存兜底记录
- 必须全部以服务端真实活动数据为准
### 10.4 匹配详情页
页面:`miniprogram/pages/match-detail`
建议职责调整为:
- 仅用于查看双向互选成功对象的完整资料
需要移除:
- 演示数据 fallback
- 与正式逻辑无关的本地假数据
## 十一、后端接口设计建议
建议新增活动内匹配接口,而不是继续挤在现有全局 `/matches` 下。
### 11.1 活动分享与绑定
- `GET /activities/share/{share_token}`
- 根据分享 token 获取活动信息
- `POST /activities/{activity_id}/bind`
- 用户绑定到活动
### 11.2 活动匹配状态
- `GET /activities/{activity_id}/match-state`
- 返回活动阶段、是否可查看、是否可选择、剩余额度等
建议返回字段:
- `activity_id`
- `stage`
- `is_bound`
- `can_view_candidates`
- `can_choose`
- `can_modify_choice`
- `selection_limit`
- `selected_count`
- `remaining_count`
- `match_deadline`
### 11.3 候选人列表
- `GET /activities/{activity_id}/candidates`
- 获取当前活动内异性候选人
查询原则:
- 只查本活动已绑定用户
- 只查异性
- 不查自己
- 不查已撤销无效记录
- 已选过的人可按产品需要决定是否继续显示
### 11.4 选择与撤销
- `POST /activities/{activity_id}/choices`
- 新增选择
- `DELETE /activities/{activity_id}/choices/{target_user_id}`
- 撤销选择
### 11.5 我的选择
- `GET /activities/{activity_id}/my-choices`
### 11.6 谁选了我
- `GET /activities/{activity_id}/liked-me`
### 11.7 匹配成功
- `GET /activities/{activity_id}/mutual-matches`
### 11.8 匹配详情
- `GET /activities/{activity_id}/matches/{target_user_id}/detail`
说明:
- 只有在当前活动中双方互选成功时,才允许查看完整资料
## 十二、后端代码改造范围
### 12.1 需要修改的现有文件
- `backend/app/models/activity.py`
- `backend/app/models/__init__.py`
- `backend/app/services/activity_service.py`
- `backend/app/routers/activities.py`
- `backend/app/schemas/activity.py`
- `backend/app/routers/__init__.py`
### 12.2 建议新增的文件
- `backend/app/models/activity_guest_choice.py`
- `backend/app/services/activity_match_service.py`
- `backend/app/schemas/activity_match.py`
- `backend/app/routers/activity_matches.py`
- `backend/alembic/versions/新增活动内选择表与活动分享字段.py`
### 12.3 需要谨慎处理的旧文件
- `backend/app/models/match.py`
- `backend/app/services/match_service.py`
- `backend/app/routers/matches.py`
建议:
- 暂不强改旧全局匹配逻辑
- 新活动逻辑独立建设
- 等新活动功能稳定后,再决定是否合并或下线旧逻辑
## 十三、管理后台改造范围
### 13.1 需要修改的页面
- `admin-web/src/views/activities/ActivityCreateView.vue`
- `admin-web/src/views/activities/ActivitiesView.vue`
### 13.2 需要新增的活动配置项
- 分享 token 展示
- 分享链接展示
- 二维码展示
- 匹配截止时间
- 选择上限
### 13.3 后台列表建议新增展示内容
- 匹配截止时间
- 分享链接复制按钮
- 二维码预览或下载
- 活动内已选择人数统计
- 活动内匹配成功人数统计
### 13.4 可选增强项
可额外增加活动匹配详情页,供管理员查看:
- 本活动所有用户选择关系
- 谁选了谁
- 双向互选结果
- 男女参与情况
## 十四、小程序改造范围
### 14.1 需要修改的页面
- `miniprogram/pages/activity-detail`
- `miniprogram/pages/match`
- `miniprogram/pages/my-matches`
- `miniprogram/pages/match-detail`
- `miniprogram/pages/profile-edit`
### 14.2 可能需要修改的公共文件
- `miniprogram/app.js`
- `miniprogram/app.json`
- `miniprogram/utils/request.js`
### 14.3 小程序重点调整项
#### 活动详情页
- 支持分享入口参数
- 开始前不显示其他人
- 显示活动阶段和进入匹配入口
#### 滑动页
- 保留 UI
- 活动模式下切换到新接口
- 增加剩余额度和快捷入口
#### 我的匹配页
- 改造成活动内结果聚合页
- 不再依赖本地临时缓存
#### 详情页
- 只看双向匹配成功对象的完整资料
#### 资料页
- 支持“完善资料后自动返回活动并绑定”
## 十五、推荐开发顺序
建议按以下顺序实施。
### 第一阶段:数据层改造
- 活动表新增分享与截止字段
- 新增活动内嘉宾选择表
- 补充迁移脚本
### 第二阶段:后端接口改造
- 活动分享接口
- 活动绑定接口
- 活动匹配状态接口
- 候选人、选择、撤销、结果查询接口
### 第三阶段:管理后台改造
- 活动创建与编辑支持新字段
- 活动列表展示分享入口和截止时间
### 第四阶段:小程序活动详情与分享流程
- 分享进入活动
- 资料补全回流
- 活动开始前提示逻辑
### 第五阶段:小程序滑动页接入活动新逻辑
- 保留滑卡交互
- 改为调用活动内候选人接口
- 加入剩余额度和状态展示
### 第六阶段:结果页与详情页改造
- 我的选择
- 谁选了我
- 匹配成功
- 完整资料查看
## 十六、风险与注意事项
### 16.1 不建议直接复用旧全局匹配表
如果强行复用:
- 容易跨活动串数据
- 条件判断会越来越复杂
- 后期维护成本高
### 16.2 不建议在滑动页同时承担“新增”和“撤销”
如果在滑动页里也做撤销:
- 用户认知会混乱
- 页面状态管理复杂
- 容易和“我的选择”页职责冲突
### 16.3 活动开始前的隐私控制必须后端强校验
不能只在前端隐藏按钮。
所有涉及:
- 查看候选人
- 查看谁选了我
- 查看匹配成功
- 查看完整资料
都必须由后端校验:
- 活动是否已开始
- 用户是否已绑定
- 是否处于允许查看阶段
### 16.4 旧“我的匹配”本地缓存逻辑建议逐步清理
原因:
- 正式业务不应依赖前端伪记录
- 多活动场景下本地缓存容易污染数据判断
## 十七、最终方案结论
本次需求最合适的实施方案是:
- 保留现有滑动选择页作为活动内异性嘉宾浏览入口
- 用户资料继续全局复用
- 活动绑定继续复用 `registrations`
- 活动内选择关系单独建模
- 活动内匹配接口独立实现
- 活动开始前严格隐藏他人信息
- 截止时间前允许修改,截止后统一锁定
这套方案的优点:
- 最大程度保留现有前端体验
- 改造边界清晰
- 数据隔离正确
- 后续扩展成本更低
## 十八、建议下一步输出物
基于本计划,下一步建议继续补充以下文档或内容:
1. 数据库变更清单
2. 后端 API 详细定义
3. 小程序页面字段与按钮清单
4. 管理后台字段改造清单
5. 按文件拆分的开发任务表