跳转到内容

活动与报名

查看 Markdown

协会在管理后台中发布的活动,以与会员卡相同的原则通过 API 提供:headless 文案(标题、摘要、markdown 描述、图片、地点、日期、链接)以及每种报名类型的实时余量——但绝不包括谁报了名。用语沿用意大利第三部门的习惯:称为报名(iscrizione),有金额时称为参与费(contributo)。

visibility 谁能看到 谁能报名
members_only(默认) 只有持会员令牌或协会自己客户端的令牌时可见 持有效会员卡的会员
public 任何人,无需登录:GET /v1/aps/{slug}/events 会员,以及——当报名类型不要求会员卡时——嘉宾

公开活动会向您网站的访客展示活动文案和各报名类型的剩余名额;仅限会员的活动只在登录后出现。

公开页面,无需登录
import { publicApi } from '@vimine/sdk';
const api = publicApi();
const { items } = await api.events.list('your-slug', { filter: 'upcoming' });
const event = await api.events.get('your-slug', 'jazz-night');
使用 Vimine 登录之后(包括仅限会员的活动)
const { items } = await vimine.events.list(); // events:read
const event = await vimine.events.get('jazz-night');

每个活动都带有 registration_types[]:amount(0 = 免费)、currency、remaining(剩余名额,null = 不限)、open,以及在未开放时的 reason(sold_out、registration_not_open、registration_closed)。status 为 published、completed(日期已过)或 cancelled。

无需编写代码:<vimine-events> 元素会渲染活动列表和报名按钮。

公开活动也能触达非会员:这正是一个人决定入会的时刻。协会在 Vimine 上的入会页面会带着该活动打开,当事人一步即可入会并预约名额:

https://app.vimine.network/enroll/your-slug?event=jazz-night
同一地址,在您的代码中生成
import { eventEnrollUrl } from '@vimine/sdk/elements';
const url = eventEnrollUrl('https://app.vimine.network', 'your-slug', 'jazz-night', 'en');

名额的结果取决于会员资格所处的阶段,页面会告诉当事人:

会员资格 名额
立即生效(免费会员卡,无需审批) 若活动报名免费,则已确认
等待审批或会费 对于仅限会员的报名:名额保留至会员卡生效,届时若报名免费则自动确认。对于向所有人开放的报名:立即确认,与非会员相同
活动报名需要支付参与费 名额保留至协会设定的期限:协会记录参与费后即确认
电子邮箱地址尚未确认 不保留任何名额:当事人通过邮件中的链接确认地址时才申请名额,并会收到一封邮件告知结果

已经是会员的人也使用同一个页面:登录后点一个按钮即可预约,无需填写任何内容(&signin=1 会立即打开登录)。这只适用于已发布且尚未举行的 public 活动:如果是其他任何 slug,该页面就是普通的入会页面。

Vimine 上的活动公开页面(/agenda/your-slug/jazz-night)和 <vimine-events> 已经向访客提供了这一入口:“加入协会并预约”。

在显示按钮之前,先询问 API 该会员能否报名——响应会说明不能报名的原因:

const { can_register, types } = await vimine.events.eligibility('jazz-night');
// types[i].reasons: membership_required, membership_not_active, membership_not_yet_valid, sold_out, max_per_user, registration_closed, …

然后为其报名(registrations:write):

const reg = await vimine.registrations.create('jazz-night', { registration_type: types[0].uid, note: '我和姐姐一起来' });
if (reg.status === 'confirmed') drawQr(reg.token); // 免费类型:已确认,二维码已就绪
if (reg.status === 'reserved') show(reg.payment_instructions); // 需付参与费:名额保留至付款为止
  • 免费类型会立即确认并返回 token:即会员在入场时出示的二维码内容(请您自行绘制,使用您喜欢的库)。
  • 需付参与费的类型会保留名额(reserved_until),并返回协会的付款说明;秘书处记录参与费后予以确认——会员会收到一封电子邮件,此后 vimine.registrations.get(id) 就会带有 token。银行卡支付将通过 Stripe 提供。
  • 如果会员的会员卡仍在等待生效,报名会保持 reserved,并在会员卡生效时自动确认。
  • 422 not_eligible 会在 errors[] 中带有与报名资格查询相同的原因。

会员的报名:vimine.registrations.list({ filter: 'upcoming' });在活动的取消期限内(开始前 registration.cancellation_hours 小时)取消:vimine.registrations.cancel(id)——超过期限则返回 409 window_closed。

嘉宾(公开活动)

章节“嘉宾(公开活动)”

没有 Vimine 账户的访客可以从您的服务器(机密客户端,registrations:write)报名参加公开活动,前提是报名类型不要求会员卡:

server
await srv.registrations.guest('jazz-night', { email, first_name, last_name, registration_type });
// → 始终为 { status: 'accepted' }

不会创建任何账户。嘉宾会收到一封带确认链接(有效期 24 小时)的电子邮件,链接指向 Vimine 上的活动页面:免费类型会在那里确认名额并立即显示二维码;需付参与费的类型则保留名额,并显示付款说明。如果您希望自己托管确认页面,请用 api.confirmRegistration(token) 使用链接中的令牌。

名额一经确认——免费类型立即确认,其他情况在记录参与费后确认——嘉宾会收到第二封电子邮件,内含他专属的链接:它会打开显示入场二维码的活动页面,在活动结束之前一直有效(活动改期后仍然有效)。嘉宾没有个人中心:链接就是他的名额,而不是二维码本身(转发的邮件并不等于名额)。如果您自己托管该页面,请用 api.viewRegistration(token) 读取名额(SDK 自 0.3.2 起)。

响应始终是 202 { status: 'accepted' }:API 从不透露某个地址是否已经报名。报名资格问题(sold_out,或仅限会员的类型返回 membership_required)返回 422。

报名二维码和会员卡一样,是一个签名令牌:同一个扫码器、同一个调用都能接受它。

server(闸机、扫码器、服务台)
const r = await srv.checkins.create(scannedToken);
if (r.kind === 'registration') {
// r.verdict: valid | already_checked_in | not_confirmed | cancelled | event_cancelled | membership_invalid
// r.first:首次通行时为 true;类型要求会员卡时带有 r.membership_verdict
}

公开核验接口也能回答报名令牌:GET /v1/verify/{token} → { status, kind: 'registration', event: { slug, starts_at } },不含个人数据。

某个活动的报名——id、状态、类型、会员资格、入场登记,不含个人数据——通过 srv.registrations.listForEvent(slug, { status, limit, cursor }) 获取(registrations:read,适用于支持 API 列表的套餐)。姓名只保留在协会的管理后台中。