RSVP 模块
一个免费的"你会出席吗?"问题,支持容量上限和候补名单——相当于商品模块付费门票库存上限的免费对应版本,适用于只需要统计人数、不涉及付费的活动。
工作原理
一个未开启携带宾客功能的 RSVP,其行为与投票的单选投票完全一致:"是"与"否"渲染为与投票选项相同的、由 buildChipGroup 生成的链接优先型选项按钮对。确认动作发生在托管的实时预览上(或在客户端支持的情况下,直接通过邮件内的表单提交完成),然后才会记录任何内容,因此企业安全扫描器预取链接不会导致计数虚增。
开启允许携带宾客只会改变"是"这一个回复选项:一个普通的 GET 链接无法像真实的表单字段那样提供选项,因此宾客人数会变成一个只能在实时预览中使用的动态 <form><select> 控件。这与作业模块的文本/链接答案需要依赖实时预览来承载固定链接无法表达的内容是同一原理。"是(选择宾客人数)"在二级/三级回退层级中会渲染为一个直接指向实时预览本身的普通链接,而不是直接指向 /act。不带宾客的"是"(0 位宾客,或宾客功能被完全禁用)无论如何都仍会直接到达 /act,作为普通的一次点击链接——只有选择宾客人数这一步才需要用到实时预览。
容量核算发生在一次 Firestore 事务内部,该事务同时完成逐位收件人的去重检查。与商品模块的结账流程不同——那里只是重新执行一次 .count() 查询,并在罕见的超卖竞态下退款——RSVP 没有类似退款的兜底机制来应对超出容量的响应。因此决策与写入必须在同一个原子操作内完成,而不是拆成两个可能被竞态打断的独立步骤。将容量设置为大于 0 的值后,一旦已确认的 RSVP 加上宾客人数将超过该上限,该响应会被记录为候补而非已确认,收件人看到的将是你设置的候补消息,而不是通用的感谢语。
"否"的回复始终被记录为已拒绝,不会与容量做任何比对。容量为 0 表示不限,这与商品模块库存字段使用的"0 表示未设置"是同一约定。匿名响应(没有收件人令牌——例如来自导出的 HTML 文件并粘贴进第三方 ESP 的情况)会完全跳过去重检查,因为没有收件人可供关联。但它仍会经过同一个容量事务,因此即便是匿名的大量涌入,也无法突破候补名单的容量边界;只有逐人的重复检测在这条路径上不可用。
如果项目配置了截止日期或响应数量上限(参见调查生命周期),已关闭的 RSVP 会将两个选项按钮都替换为不可点击的灰色版本,并在实时预览上附加一条"本调查已关闭"的提示。
可配置字段:
- 问题——默认为"Will you attend?"。
- 容量(0 表示不限)。
- 允许携带宾客——为"是"添加一个宾客人数选择器。
- 每次 RSVP 最多携带的宾客数(若已开启携带宾客)——限定选择器的范围(1–20)。
- 候补消息——当容量已满时,替代普通感谢语显示的内容。
- 卡片的背景色、内边距、边框与圆角半径。
- 问题颜色/字号,以及"是/否"按钮的颜色/背景覆盖设置。
每一次 RSVP 都会汇总为已确认/已拒绝/候补人数,以及宾客总数,直接写入项目的 rsvpBlocks 汇总数据桶,而不是经过其他模块都使用的通用响应递增路径。这是一个刻意的例外,因为已确认与候补的判定必须与计数本身发生在同一个事务内。
示例
Subject
Will you join us?
"活动"项目用途在新建项目时会自带一个 RSVP 模块,与会议链接、活动场地和添加到日历一起出现。为限量场地设置一个容量上限,模块就能自动处理候补名单,无需任何额外配置——参见活动与网络研讨会。俱乐部可以用同一个模块处理选拔赛或客场之旅的有限名额,容量设置能在无需人工统计的情况下确保人数如实——参见体育队伍与俱乐部。一场完全没有场地容量限制的免费社区聚会,只需把容量保持为 0,单纯利用 RSVP 获取可靠的人数统计,而无需任何容量限制。
静态回退效果是什么样子
<div id="em-rsvp-1" style="margin:12px 0;background-color:transparent">
<p style="margin:0 0 10px;font-weight:600;font-size:16px;color:#111827">Will you attend?</p>
<div>
<span class="kn-fallback">
<a href="https://mailinapp.com/v/eyJhbGci.../act?blockId=rsvp-1&blockType=rsvp&action=rsvp&response=yes"
style="display:inline-block;margin:0 6px 6px 0;padding:8px 14px;border:1px solid #d1d5db;
border-radius:6px;background-color:#ffffff;color:#111827;font-size:14px;text-decoration:none">
Yes
</a>
<a href="https://mailinapp.com/v/eyJhbGci.../act?blockId=rsvp-1&blockType=rsvp&action=rsvp&response=no"
style="display:inline-block;margin:0 6px 6px 0;padding:8px 14px;border:1px solid #d1d5db;
border-radius:6px;background-color:#ffffff;color:#111827;font-size:14px;text-decoration:none">
No
</a>
</span>
</div>
</div>
这是不带宾客选项的二级回退层级:指向 /v/[token]/act 的普通链接,形式与投票的选项按钮完全相同,在邮件内表单未渲染的地方均可见。