|
|
@@ -0,0 +1,317 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+<meta charset="UTF-8" />
|
|
|
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
+<title>活动管理实现 vs 需求差异调研报告</title>
|
|
|
+<style>
|
|
|
+ :root {
|
|
|
+ --bg: #ffffff; --fg: #1f2933; --muted: #647082; --line: #e3e8ef;
|
|
|
+ --brand: #1565c0; --brand-bg: #e8f1fb;
|
|
|
+ --red: #c62828; --red-bg: #fdecea; --red-line:#f5c6c0;
|
|
|
+ --amber: #b26a00; --amber-bg: #fff4e0; --amber-line:#f3d79a;
|
|
|
+ --green: #2e7d32; --green-bg: #e9f6ea; --green-line:#bfe3c2;
|
|
|
+ }
|
|
|
+ * { box-sizing: border-box; }
|
|
|
+ body { font-family: "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
|
|
|
+ color: var(--fg); background: #f6f8fb; margin: 0; line-height: 1.65; }
|
|
|
+ .wrap { max-width: 1080px; margin: 0 auto; padding: 32px 28px 64px; }
|
|
|
+ header { border-bottom: 3px solid var(--brand); padding-bottom: 16px; margin-bottom: 8px; }
|
|
|
+ h1 { font-size: 26px; margin: 0 0 6px; color: var(--brand); }
|
|
|
+ .sub { color: var(--muted); font-size: 14px; }
|
|
|
+ h2 { font-size: 19px; margin: 36px 0 12px; padding-left: 10px; border-left: 4px solid var(--brand); }
|
|
|
+ h3 { font-size: 16px; margin: 22px 0 8px; color: var(--fg); }
|
|
|
+ p { margin: 8px 0; }
|
|
|
+ table { width: 100%; border-collapse: collapse; margin: 12px 0 18px; background: var(--bg);
|
|
|
+ font-size: 14px; box-shadow: 0 1px 3px rgba(0,0,0,.05); }
|
|
|
+ th, td { border: 1px solid var(--line); padding: 9px 11px; text-align: left; vertical-align: top; }
|
|
|
+ th { background: var(--brand-bg); color: var(--brand); font-weight: 600; }
|
|
|
+ tr:nth-child(even) td { background: #fbfcfe; }
|
|
|
+ code { background: #eef1f6; padding: 1px 5px; border-radius: 4px; font-size: 12.5px; color:#283593; }
|
|
|
+ .sev { display: inline-block; font-weight: 700; padding: 2px 9px; border-radius: 999px; font-size: 12px; }
|
|
|
+ .s-high { color: var(--red); background: var(--red-bg); border:1px solid var(--red-line); }
|
|
|
+ .s-mid { color: var(--amber); background: var(--amber-bg); border:1px solid var(--amber-line); }
|
|
|
+ .s-low { color: var(--green); background: var(--green-bg); border:1px solid var(--green-line); }
|
|
|
+ .card { border: 1px solid var(--line); border-radius: 10px; padding: 16px 18px; background: var(--bg); margin: 14px 0; }
|
|
|
+ .gap { border-left: 4px solid var(--red); }
|
|
|
+ .note { border-left: 4px solid var(--amber); }
|
|
|
+ .ok { border-left: 4px solid var(--green); }
|
|
|
+ ul { margin: 8px 0 8px 4px; padding-left: 20px; }
|
|
|
+ li { margin: 5px 0; }
|
|
|
+ .tag { font-size: 12px; color: var(--muted); background:#eef1f6; padding:1px 7px; border-radius:5px; margin-right:4px;}
|
|
|
+ .verdict { background: var(--brand-bg); border:1px solid #b9d4f3; border-radius:10px; padding:16px 20px; margin:18px 0; font-size:15px;}
|
|
|
+ .verdict b { color: var(--brand); }
|
|
|
+ footer { margin-top: 40px; color: var(--muted); font-size: 12.5px; border-top:1px solid var(--line); padding-top:12px;}
|
|
|
+ .matrix td:first-child { font-weight: 600; white-space: nowrap; }
|
|
|
+</style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+<div class="wrap">
|
|
|
+<header>
|
|
|
+ <h1>活动管理「实现 vs 需求」差异调研报告</h1>
|
|
|
+ <div class="sub">调研日期:2026-10-22 | 项目:浠艾福 CFC(cfc-backend)| 主线:主活动(activities)全流程</div>
|
|
|
+</header>
|
|
|
+
|
|
|
+<div class="verdict">
|
|
|
+ <b>总体结论:</b>活动管理的<b>主链路(创建→发布→报名→签到→评价)已基本打通</b>,付费报名+微信支付、报名审核、积分/能量/CF 发放、评价与资料上传均已落地。
|
|
|
+ 但与流程需求之间存在 <b>4 项高危差异</b>(名额失控、取消报名主路径断裂且无退款、签到审核字段失效)与 <b>多项一致性/完整性缺口</b>;
|
|
|
+ 并且系统里<b>并存三套互不相通的活动子系统</b>,是后续维护与需求对齐的最大隐患。建议优先修复 🔴 高危项,再处理 🟡 一致性问题。
|
|
|
+</div>
|
|
|
+
|
|
|
+<h2>一、调研依据与范围</h2>
|
|
|
+<div class="card">
|
|
|
+ <p><b>需求侧(事实源):</b></p>
|
|
|
+ <ul>
|
|
|
+ <li><code>docs/flows/activity-flow.md</code> —— 用户使用流程图,定义了创建、发布(含审核)、报名、取消报名、报名审批、签到、评价的端到端流程与 24 个端点。</li>
|
|
|
+ <li><code>docs/superpowers/specs/2026-06-09-article-activity-publishing-design.md</code>、<code>2026-08-01-activity-registration-upgrade-design.md</code>、<code>2026-07-31-activity-registration-form-design.md</code>、<code>2026-10-07-activity-share-referral-design.md</code>、<code>2026-10-17-activity-poster-template-design.md</code>、<code>2026-10-22-activity-registration-roster.md</code> —— 围绕发布与报名的增强规格。</li>
|
|
|
+ </ul>
|
|
|
+ <p><b>实现侧:</b><code>cfc-backend</code> 的 <code>controller/ActivityController</code>、<code>controller/admin/AdminActivity*</code>、<code>controller/ActivityOrderController</code>、<code>service/ActivityService</code>、<code>ActivityRegistrationService</code>、<code>ActivityOrderService</code>、<code>ActivityFeedbackService</code>、<code>ActivityMaterialService</code> 等及其实体/Mapper。</p>
|
|
|
+ <p class="note" style="margin-top:10px;"><b>范围说明:</b>本报告"活动管理"指流程图中的<b>主活动(activities)</b>。系统另含「规划师活动(guide_activities)」与「商品履约活动(activity_provisions)」两套独立子系统,见第五节。</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+<h2>二、六环节逐一对比</h2>
|
|
|
+
|
|
|
+<h3>① 创建</h3>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:110px">维度</th><th>需求要点</th><th>实现情况</th><th>差异 / 缺口</th><th>严重度</th></tr>
|
|
|
+ <tr>
|
|
|
+ <td>创建入口</td>
|
|
|
+ <td>管理后台/规划师端可创建,含标题、描述、封面、分类、地点、日期、最大人数、价格等字段</td>
|
|
|
+ <td><code>ActivityService.create</code>(:153) 强制 <code>draft</code>、<code>currentParticipants=0</code>;规划师端 <code>GuideActivityService.createActivity</code></td>
|
|
|
+ <td>主活动<b>无管理后台"新建"端点</b>(AdminActivityController 只有审核/列表),只能 C 端带 activity_admin 角色创建,职责割裂</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>字段校验</td>
|
|
|
+ <td>表单级字段约束(价格、时间、名额等)</td>
|
|
|
+ <td><code>create</code>/<code>update</code>(:163) 仅校验存在性,业务字段几乎零校验(价格/时间/名额/维度均可空)</td>
|
|
|
+ <td>合法性完全依赖前端,后端不兜底</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>海报模板</td>
|
|
|
+ <td>—</td>
|
|
|
+ <td><code>ActivityPosterTemplateService</code> 含启用/停用、配色、JSON 校验</td>
|
|
|
+ <td>已实现,且超出基础需求</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h3>② 发布</h3>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:110px">维度</th><th>需求要点</th><th>实现情况</th><th>差异 / 缺口</th><th>严重度</th></tr>
|
|
|
+ <tr>
|
|
|
+ <td>发布范式</td>
|
|
|
+ <td>流程图中存在「C端直发 publish」与「管理端审核流」两条路径</td>
|
|
|
+ <td><code>ActivityService.publish</code>(:173) 仅 <code>draft→published</code>,<b>不校验维度</b>;<code>ActivityAdminService.auditActivity</code> 审核流强制<b>五维权重合计=100%</b></td>
|
|
|
+ <td><b>两套发布范式不一致</b>:同一条数据可绕过审核直接 published,也可走审核,状态机存在歧义</td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>审核/撤回</td>
|
|
|
+ <td>提交审核 → 通过/驳回 → 撤回/转草稿</td>
|
|
|
+ <td><code>submitForReview</code> / <code>auditActivity</code> / <code>withdraw</code> / <code>reDraft</code> 均已实现,含五维权重落库</td>
|
|
|
+ <td>功能完整</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>自动结束</td>
|
|
|
+ <td>活动到期自动结束</td>
|
|
|
+ <td><code>autoEndExpiredActivities</code>(:402) 仅当 <code>list/detail</code> 被调用时触发,且 <code>endTime</code> 早于"当前-7天"才转 ended</td>
|
|
|
+ <td><b>弱实现</b>:非定时任务、延迟 7 天才结束;活动过期后若无人查询仍显示进行中</td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>标签/推荐</td>
|
|
|
+ <td>—</td>
|
|
|
+ <td>审核时 <code>ActivityTagService</code> AI 自动打标(失败静默降级),<code>getRelatedActivitiesByTags</code> 相关推荐</td>
|
|
|
+ <td>已实现,超出基础需求</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h3>③ 报名</h3>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:110px">维度</th><th>需求要点</th><th>实现情况</th><th>差异 / 缺口</th><th>严重度</th></tr>
|
|
|
+ <tr>
|
|
|
+ <td>名额控制</td>
|
|
|
+ <td>"最大人数 / 名额",隐含报名应受名额限制、满员截止</td>
|
|
|
+ <td><code>register</code>(:75)、<code>batchRegister</code>(:39)、<code>checkRegistrationGate</code>(:318) 仅校验 published / 是否需要报名 / 截止时间 / 付费闸门,<b>从不读 maxParticipants</b></td>
|
|
|
+ <td><b>🔴 名额失控</b>:允许超额报名,无任何阻塞逻辑;<code>maxParticipants</code> 仅用于"剩余名额"展示(<code>getRegistrationRoster</code> :225 用 <code>Math.max(0,…)</code> 兜底)</td>
|
|
|
+ <td><span class="sev s-high">高</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>免费报名</td>
|
|
|
+ <td>提交报名 → 待审核(pending) → 管理员通过</td>
|
|
|
+ <td><code>register</code> 写 <code>pending</code>;管理员 <code>approve</code>(:105)/<code>reject</code>(:121) 仅 pending 可审</td>
|
|
|
+ <td>流程完整;但免费活动报名后<b>必须管理员审核</b>才能签到,付费活动支付即 auto-approved,体验不一致</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>付费报名</td>
|
|
|
+ <td>—(需求未细化收费)</td>
|
|
|
+ <td><code>ActivityOrderService</code>:订单→微信预支付→回调→写 approved 全链路,金额=0 时免支付直接通过</td>
|
|
|
+ <td>已实现且完整(含回调解密)</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>计数口径</td>
|
|
|
+ <td>当前参与人数</td>
|
|
|
+ <td><code>currentParticipants</code> 只在<b>签到时 +1</b>(见⑤),并非报名人数</td>
|
|
|
+ <td><b>语义错位</b>:与 <code>maxParticipants</code> 不是同一口径,满员判断失真</td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h3>④ 取消报名</h3>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:110px">维度</th><th>需求要点</th><th>实现情况</th><th>差异 / 缺口</th><th>严重度</th></tr>
|
|
|
+ <tr>
|
|
|
+ <td>可取消状态</td>
|
|
|
+ <td>用户应能取消自己的报名</td>
|
|
|
+ <td><code>cancel</code>(:97) 用 <code>findRegistration(...,"pending")</code> 过滤</td>
|
|
|
+ <td><b>🔴 主路径断裂</b>:已审核通过(approved)/已支付报名无法取消,调用即返回"报名记录不存在"</td>
|
|
|
+ <td><span class="sev s-high">高</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>退款/回滚</td>
|
|
|
+ <td>取消应释放名额、付费应退款</td>
|
|
|
+ <td>取消仅改状态;主活动无支付绑定、无退款逻辑;名额/计数均无回滚</td>
|
|
|
+ <td><b>🔴 无退款、无名额回滚</b>(付费活动取消无退款;退款逻辑仅存在于商品履约支线 ActivityProvisionService.cancel)</td>
|
|
|
+ <td><span class="sev s-high">高</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>取消记录</td>
|
|
|
+ <td>—</td>
|
|
|
+ <td>无"取消原因/取消时间"字段</td>
|
|
|
+ <td>可观测性弱</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h3>⑤ 签到</h3>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:110px">维度</th><th>需求要点</th><th>实现情况</th><th>差异 / 缺口</th><th>严重度</th></tr>
|
|
|
+ <tr>
|
|
|
+ <td>签到主流程</td>
|
|
|
+ <td>扫码/按钮签到,发放积分、扣能量(未报名)、更新参与人数、发放五维能量</td>
|
|
|
+ <td><code>ActivityService.checkin</code>(:198) 完整:时间窗校验、本人/同家庭代签、未报名能量惩罚、去重、建 Task(completed)、加积分、写 PointsLog、发能量、发 CF 值</td>
|
|
|
+ <td>功能完整,超出基础需求</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>审核签到</td>
|
|
|
+ <td>实体含 <code>requireCheckinReview</code>(签到需审核)</td>
|
|
|
+ <td><code>checkin</code> 逻辑<b>从不读取</b>该字段,一律直接 <code>Task.status="completed"</code></td>
|
|
|
+ <td><b>🔴 虚假字段</b>:配置项形同虚设,无任何"待审核"中间态</td>
|
|
|
+ <td><span class="sev s-high">高</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>强制报名</td>
|
|
|
+ <td>先报名后签到</td>
|
|
|
+ <td>除 <code>requireRegistration=1</code> 且未通过审核时拒绝外,并未阻止未报名者签到(无手机号孩子可代签)</td>
|
|
|
+ <td>与"先报名后签到"假设不符,但属业务取舍</td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>平行签到机制</td>
|
|
|
+ <td>—</td>
|
|
|
+ <td>商品履约 <code>activity_provisions</code> 另有一套签到/核销(provision→signIn→complete),与主活动 Task 签到互不关联</td>
|
|
|
+ <td>同一活动可能两种签到并存,统计口径混乱(见第五节)</td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h3>⑥ 活动总结</h3>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:110px">维度</th><th>需求要点</th><th>实现情况</th><th>差异 / 缺口</th><th>严重度</th></tr>
|
|
|
+ <tr>
|
|
|
+ <td>评价</td>
|
|
|
+ <td>流程阶段七"活动评价":提交评分/评论、查看评价列表、我的评价</td>
|
|
|
+ <td><code>ActivityFeedbackService.submit</code>(:20) 直接 insert,无去重、无"是否已结束/已报名/已签到"门槛;任何人可评;<code>status</code> 恒 0 无意义</td>
|
|
|
+ <td>基础可用但<b>无门槛、无去重、状态字段无效</b></td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>总结资料</td>
|
|
|
+ <td>—(需求未定义"活动总结"独立阶段)</td>
|
|
|
+ <td><code>ActivityMaterialService.upload</code>(:26) 限定 <code>status=published</code> 且 <code>now.after(endTime)</code>,即结束后才能上传资料</td>
|
|
|
+ <td>已实现"结束后的资料上传"</td>
|
|
|
+ <td><span class="sev s-low">低</span></td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td>聚合/AI 总结</td>
|
|
|
+ <td>用户表述中的"活动总结"隐含<b>参与数据汇总 / 复盘报告</b></td>
|
|
|
+ <td><b>无任何服务端聚合、AI 总结文本生成或参与数据汇总报告</b>。<code>ActivityDTO</code> 注释声明了 <code>summarizing</code>/总结中展示态,但 <code>applyDisplayState</code>(:527) <b>从不产出该值</b>(死代码)</td>
|
|
|
+ <td><b>🟡 需求未定义 + 实现未落地</b>:若业务需要"自动总结",目前完全缺失;DTO 里的"总结中"标签前端若依赖将无法命中</td>
|
|
|
+ <td><span class="sev s-mid">中</span></td>
|
|
|
+ </tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h2>三、差异汇总(按严重度)</h2>
|
|
|
+<table class="matrix">
|
|
|
+ <tr><th>级别</th><th>差异项</th><th>影响</th></tr>
|
|
|
+ <tr><td><span class="sev s-high">高</span></td><td>名额(quota)报名时不校验,允许超额报名</td><td>满员控制失效,可能超售;业务正确性风险</td></tr>
|
|
|
+ <tr><td><span class="sev s-high">高</span></td><td>取消报名仅支持 pending,已通过/已支付报名无法取消</td><td>用户正常"报名后取消"主路径断裂</td></tr>
|
|
|
+ <tr><td><span class="sev s-high">高</span></td><td>取消报名无退款、无名额/计数回滚</td><td>付费活动取消无退款,财务与名额失准</td></tr>
|
|
|
+ <tr><td><span class="sev s-high">高</span></td><td>签到审核字段 requireCheckinReview 形同虚设</td><td>配置项不产生任何效果,误导运营</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">中</span></td><td>两套发布范式不一致(直发不校验维度 vs 审核强制权重100%)</td><td>状态机歧义、数据质量参差</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">中</span></td><td>currentParticipants 语义错位(实为签到计数)</td><td>满员/参与统计失真</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">中</span></td><td>评价无门槛、无去重、status 恒 0</td><td>刷评/误评无防护</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">中</span></td><td>活动总结无聚合/AI 生成;DTO summarizing 死值</td><td>"总结"能力缺失,前端标签失效</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">中</span></td><td>过期自动结束弱实现(查询触发+延迟7天)</td><td>过期活动未及时结束</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">中</span></td><td>未报名者仍可签到(除需审核场景)</td><td>与"先报名后签到"假设不符</td></tr>
|
|
|
+ <tr><td><span class="sev s-low">低</span></td><td>三套活动体系并存且互不相通(见第五节)</td><td>架构/维护风险</td></tr>
|
|
|
+ <tr><td><span class="sev s-low">低</span></td><td>主活动无管理后台"新建"入口</td><td>职责割裂</td></tr>
|
|
|
+ <tr><td><span class="sev s-low">低</span></td><td>创建接口零字段校验</td><td>依赖前端兜底</td></tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<h2>四、关键缺口详解</h2>
|
|
|
+
|
|
|
+<div class="card gap">
|
|
|
+ <h3 style="margin-top:4px">🔴 名额失控(最严重)</h3>
|
|
|
+ <p>报名入口 <code>register</code> / <code>batchRegister</code> 与闸门 <code>checkRegistrationGate</code> 均未对 <code>maxParticipants</code> 做判断。系统只在"报名情况"接口用 <code>max - approvedCount</code> 计算剩余名额并 <code>Math.max(0, …)</code> 兜底——意味着即使报名人数远超上限,剩余名额只显示 0,但<b>报名依旧成功</b>。对线下有场地/物料限制的活动,这是直接业务风险。</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+<div class="card gap">
|
|
|
+ <h3 style="margin-top:4px">🔴 取消报名主路径断裂 + 无退款</h3>
|
|
|
+ <p><code>cancel</code> 用 <code>findRegistration(activityId, memberId, userId, "pending")</code> 限定只查 pending。而免费活动需管理员 approve、付费活动支付成功即 auto-approved——两者到达"可签到"状态后都不再是 pending,因此用户在前端点"取消报名"会收到"报名记录不存在"。此外,主活动报名与支付(ActivityOrder)之间缺乏取消→退款的回路,付费用户取消后无退款。</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+<div class="card gap">
|
|
|
+ <h3 style="margin-top:4px">🔴 签到审核字段失效</h3>
|
|
|
+ <p>实体 <code>Activity</code> 设计了 <code>requireCheckinReview</code>(是否需要审核签到),但 <code>checkin</code> 全程未读取该字段,签到一律直接生成 <code>Task.status="completed"</code>。运营在后台开启"签到需审核"后不会得到任何预期行为。</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+<h2>五、架构风险提示:三套互不相通的活动子系统</h2>
|
|
|
+<div class="card note">
|
|
|
+ <p>当前后端并存三条"活动"数据/流程线,做需求对照时切勿混为一谈:</p>
|
|
|
+ <ul>
|
|
|
+ <li><b>主活动 activities</b>:C 端活动中心,承载本报告六环节(报名/签到/评价)。状态机 <code>draft/pending/rejected/published/withdrawn/ended</code>。</li>
|
|
|
+ <li><b>规划师活动 guide_activities</b>:规划师端,仅 create/update/publish/cancel/delete,<b>不参与报名/签到/评价</b>,状态机 <code>draft/published/cancelled/completed</code>,与主活动字段、状态完全独立。</li>
|
|
|
+ <li><b>商品履约活动 activity_provisions</b>:挂在 product_orders 上,"购买活动商品→核销码→签到→完成→退款",状态机 <code>unprovisioned→provisioned→signed_in→completed</code>,与主活动报名/签到<b>平行且互不相通</b>。</li>
|
|
|
+ </ul>
|
|
|
+ <p>其中"规划师活动"与"主活动"的报名/签到/评价能力无法复用;"商品履约签到"与"主活动 Task 签到"是两套独立的签到实现。这意味着同一业务概念(活动、报名、签到)在代码里有多套定义,需求对齐与后续迭代成本显著。</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+<h2>六、修复优先级建议</h2>
|
|
|
+<table>
|
|
|
+ <tr><th style="width:60px">优先级</th><th>事项</th><th>建议动作</th></tr>
|
|
|
+ <tr><td><span class="sev s-high">P0</span></td><td>名额校验</td><td>在 <code>register/batchRegister</code> 中于写入前校验 <code>approvedCount < maxParticipants</code>(含并发悲观锁/唯一约束),满员返回"名额已满"</td></tr>
|
|
|
+ <tr><td><span class="sev s-high">P0</span></td><td>取消报名链路</td><td><code>cancel</code> 支持 approved 状态;对付费活动联动 <code>ActivityOrderService</code> 走退款;回滚名额计数</td></tr>
|
|
|
+ <tr><td><span class="sev s-high">P0</span></td><td>签到审核字段</td><td>若保留该能力则在 <code>checkin</code> 读取 <code>requireCheckinReview</code> 生成待审核 Task;否则从实体/后台配置中移除,避免误导</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">P1</span></td><td>currentParticipants 口径</td><td>拆分为"报名人数"与"签到人数"两个字段,或统一以 approved 计数,消除语义错位</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">P1</span></td><td>发布范式统一</td><td>明确"直发"与"审核流"的适用场景,统一维度/权重校验规则,避免状态歧义</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">P1</span></td><td>活动总结能力</td><td>若业务需要"总结",补充服务端聚合(参与率/签到率/评价汇总)或 AI 总结,并接线 DTO 的 summarizing 态;否则清理死代码</td></tr>
|
|
|
+ <tr><td><span class="sev s-mid">P1</span></td><td>评价门槛</td><td>评价前校验"已报名且已签到",并去重(每 child 一条)</td></tr>
|
|
|
+ <tr><td><span class="sev s-low">P2</span></td><td>自动结束</td><td>改为定时任务(如每日 cron),消除"查询才触发"与 7 天延迟</td></tr>
|
|
|
+ <tr><td><span class="sev s-low">P2</span></td><td>子系统整合决策</td><td>明确主活动 / 规划师活动 / 商品履约三者边界,决定是否需要统一活动内核,避免长期分裂</td></tr>
|
|
|
+</table>
|
|
|
+
|
|
|
+<footer>
|
|
|
+ 本报告基于代码静态核查(已逐行核验 register / cancel / checkin / applyDisplayState / autoEndExpiredActivities 等关键方法)与 <code>docs/flows/activity-flow.md</code> 流程需求对照生成。
|
|
|
+ 差异判定以"流程需求隐含约束"与"代码实际行为"为准;标注 🔴 的项建议在上线前优先修复。
|
|
|
+</footer>
|
|
|
+</div>
|
|
|
+</body>
|
|
|
+</html>
|