# 需求补充计划 ## 一、文档目标 本文档用于补充“活动分享与嘉宾匹配系统”的详细设计方案,并结合当前项目实际代码结构,明确以下内容: - 在保留现有“小程序滑动选择页面”的前提下,如何完成活动内匹配能力改造 - 当前系统与目标需求之间的差距 - 建议的数据结构、接口设计、页面设计与权限规则 - 需要修改的后端、管理端、小程序文件范围 - 推荐实施顺序与风险提示 ## 二、当前系统现状总结 当前项目由三部分组成: - 后端:`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. 按文件拆分的开发任务表