# 11 月晨跑打卡 · 跑到哪儿打到哪儿

> 活页公开模板 `sample-geo-checkin` · 场景: 报名 · 投票 · 接龙 · 行业: 个人家庭 / 企业内部 / 教育培训
> 任何人、任何 Agent 都可以读、照着改，不需要账号。示例内容均为虚构。
> 真页面: https://getlivepage.com/s/JeUt-FCLfLhj · 详情: https://getlivepage.com/examples/sample-geo-checkin

## 这是什么

打卡足迹 · 在哪儿打的卡、几点打的，一眼看全

## 什么时候用

不限地点、只想记下「谁、几点、在哪儿」的打卡：每日跑步 / 健身打卡、活动签到、外勤签到、旅行足迹。读者点一下，平台定位后让他从附近地点里选一个，打卡墙只显示地点名和时间，不显示具体位置；署名可以用微信头像昵称，也可以自己填。必须到某个点才算（集合点 200 米内）时，同一份给定位字段加 fence 即可。只收报名选 sample-event-signup；一条路线逐站盖章选 sample-checkin-map；只要天数不要地点的打卡选 sample-fitness-challenge。

## 用户对助手说的原话

帮我做一个跑团 11 月每日跑步打卡页，发成一个网页链接，大家每天跑完在哪儿都能用微信打开点一下：页头一行跑团名和「11 月每日打卡」，大标题「跑到哪儿，打到哪儿」，一句说明；首屏是一摞圆形邮戳，每个邮戳印着一次打卡的地点名、时间和名字，最新的在最前面居中、旧的从两边露出来，下面用大号粗数字写共几人次打卡、几个地方；接着一行三格说明打卡会记录什么（地点名：附近地点任选；打卡时间；名字：微信头像昵称或自己填），再一句「只记地点名，不记具体位置」；然后让读者选怎么署名：两张上下排的选项卡，默认选填名字，「用微信头像昵称打卡」（写明微信里会跳一次授权、电脑上会出二维码用手机微信扫一下，点了才去授权），或「填个名字打卡」（带输入框）；一个很大的「打卡」按钮，点了用定位打卡（不限位置，读者从附近地点里选一个），成功后弹一张带「已打卡」印章的票根（地点名、日期时间、名字）；没给定位权限、取消、要用微信身份等情况都用一句人话说怎么办。再往下是打卡墙：按日期分组、时间倒序，每行头像、名字、地点名、时间，先显示 8 条可展开；然后「大家常在这些地方跑」列出次数最多的几个地点；最后几条打卡规则。手机竖屏为主，邮戳区压矮一点，手机第一屏就要看到打卡按钮；电脑上左边邮戳和打卡、右边打卡墙。

如果你还没有活页连接器（MCP），先读 https://getlivepage.com/for-agents.md ，照里面的说明接入，或不登录直接发布。

## 照着做一份

1. 读入口文件 https://getlivepage.com/examples/sample-geo-checkin/source/index.html（它引用的其他文件见下方列表）。
2. 保留结构、版式和交互，把内容**全部**换成用户自己的；模板里的公司、人名、数字都是虚构的，一样都别留。
3. 交付一个自包含的单文件 HTML：样式写在页面里，不引外部字体 / 脚本 / CDN；手机 375 宽和电脑 1440 宽都要好看，模板有暗色就保留暗色。
4. 要发成微信里能打开、改了链接不变的网页：接入活页（https://getlivepage.com/for-agents.md）后发布；没有账号也可以让用户在 https://getlivepage.com/quick 上传这个文件。
5. 没有活页工具、但能发 HTTPS 请求：把做好的 HTML 以 Content-Type: text/html POST 到 https://getlivepage.com/api/quick?client=template-sample-geo-checkin ，返回预览链接、7 天分享与认领链接（登录后保留、链接不变）。

## 页面结构

- 打卡
- 打卡墙
- 常去的地方
- 怎么算一次

## 文件（公开，纯文本）

- https://getlivepage.com/examples/sample-geo-checkin/source/index.html（入口）

## 发成活页之后还能做的

- 定位打卡记录模式：平台先说明要位置做什么，再定位、让读者选附近地点，页面拿不到坐标，表里只落地点名
- 署名二选一：微信头像昵称（点了才授权）或自填名字，打卡墙读回头像昵称 / 名字、地点与时间
- 同一链接更新不变：要限定到某个点只改表单设置（加 fence），页面不重发

## 发之前要备好

- 数据表 checkins（列 name / loc，append_open=true，identity=wechat_optional）：先 set_data 建空表；再 set_form 加字段 name（text，max 12）和 loc（type=location，不传 fence = 不限位置、读者选附近地点，require_identity=false）。要限定到某个点才算，给 loc 加 fence={lat,lng,radius_m,name}（GCJ-02，20–5000 米）；要每人只打一次，改 identity=wechat、per_reader=one 并去掉 require_identity=false
- 页面脚本里的 SAMPLE 是示例打卡行，发自己的打卡前改成 []

## 模板说明（README）

虚构的「青岚湖晨跑团」11 月每日打卡：每天跑完在哪儿都能点一下，打卡墙记下谁、几点、在哪个地点打的卡。
跑团、人名、地点都是编的，示例内容均为虚构。

## 演示哪个特色

**定位打卡的记录模式：不限位置，只记「在哪儿打的卡」——读者从附近地点里选一个，表里只落地点名，没有坐标。**

- 记忆点是首屏那摞圆形邮戳：每个邮戳印着一次打卡的地点名、时间和名字，最新的在最前面。下面一行三格写清「打卡会记录什么」
  （地点名 · 打卡时间 · 名字），再一句「只记地点名，不记你的具体位置」——读者点之前就知道会留下什么。
- 署名二选一（事前引导）：
  - 「用微信头像昵称打卡」：写明「微信里会跳一次授权；电脑上会出个二维码，用手机微信扫一下」，读者点了这一项（或点打卡）才调 `space.me.request()`；
    拿到后显示「将以『昵称』打卡」和头像。取消授权也能看页，并提示可以改用填名字。
  - 「填个名字打卡」：不用授权，打卡墙显示填的名字。
- 打卡流程：`const r = await space.location({ table: 'checkins' })` —— 平台先弹事前说明（要位置做什么、存什么），读者点「开始定位」才问权限，
  定位后弹「选择打卡地点」（附近地点列表，可搜，缺省最近的）；回 `{ ticket, mode: 'record', place: { name, area } | null, … }` ⇒
  `space.data.append('checkins', { name, loc: r.ticket })`。成功后弹一张带「已打卡」印章的票根（地点名、日期时间、名字）。
- 每种失败都有一句人话：`cancelled`（读者在平台面板里点了「先不打卡」）· `location_denied` · `accuracy_too_low` · `reader_identity_required`
  （作者把字段改成要微信身份时，切到微信那一项并给按钮）· `outside_window` · `reader_already_submitted` · `out_of_range`（加了 fence 时）·
  `location_ticket_invalid` · `append_closed` · `preview` · 超时。
- 打卡墙读 `fetch('./_data/checkins.json')`：`loc` 那一格就是地点名（查不到地点时是「位置已记录」），时间取 `_at`；
  有 `_by` 用微信头像昵称（头像只认 `/_rid/avatar/`），没有就用自填的 `name`。按日期分组、时间倒序，先显示 8 条；自己那一行（`_mine`）标「我」，
  刷新后票根还在。下面「大家常在这些地方跑」按地点名数次数。
- 脚本里的 `SAMPLE` 是 15 条示例打卡行，模板里打开时邮戳和打卡墙不空；活数据接在一起排。

## 改哪里变成我的

| 位置 | 改什么 |
|---|---|
| 页头 `.org` / `h1` / `.lede` | 团体名与这次打卡的名字、一句说明 |
| `.records` | 「打卡会记录什么」三格；改了表的列就跟着改 |
| 署名选项 `.ways` | 只要微信身份就删掉「填个名字打卡」那一项；只要名字就删掉微信那一项 |
| 票根 `.ticket` | `.t1` 那行抬头 |
| 脚本顶部 | **`SAMPLE` 改成 `[]`** |
| `.rules` | 怎么算一次（天数、奖励） |
| 页脚 | 平台标志与名称（逐字照抄）+ 一句适用场景；发自己的打卡时整段删掉 |
| `manifest.json` | `title` / `share.title` / `share.desc`（微信卡片上的字） |

换成活动签到、外勤签到、旅行足迹都一样：改文案和抬头，邮戳、署名引导、打卡墙原样用。

## 怎么发出去

先发页面（`publish_file`），再建表、加定位字段，最后分享：

```
set_data proposal_id=<id> table="checkins" revision=0 rows=[] columns=["name","loc"]
         append_open=true identity="wechat_optional" identity_visibility="all"
set_form proposal_id=<id> table="checkins" title="打卡" fields=[
  {"key":"name","label":"名字","type":"text","max":12},
  {"key":"loc","label":"打卡地点","type":"location","require_identity":false}
]
set_visibility proposal_id=<id> visibility="public"   # 拿到链接的人都能打开；只给群里看也可以用 passcode
```

- **不传 `fence` = 不限位置**（记录模式）：读者从附近地点里选一个，那一格存地点名，读者面看不到坐标。
- `identity="wechat_optional"`：授权了微信的人那一行带 `_by`（头像昵称），没授权的照样能交、用自填名字。
  这种表**不加** `per_reader`（每天都能打卡；`one` 也只对授权的人生效）。
- 进阶（可选）——**限定到某个点才算**：给 `loc` 加 `"fence":{"lat":<纬度>,"lng":<经度>,"radius_m":200,"name":"南门石桥"}`
  （GCJ-02，腾讯 / 高德地图上取的点；半径 20–5000 米，室外 100–300 米较稳），可再加 `"window":{"start":"…+08:00","end":"…+08:00"}` 限定时间段。
  超出范围时页面会说还差多少米。要「每人只算一次、必须实名」：表改 `identity="wechat" per_reader="one"`，字段去掉 `require_identity:false`，页面删掉「填个名字」那一项。
- 看谁打了卡：`list_data_rows table=checkins`（每行地点名、`_at`；作者还能看到 `_loc_area` / `_loc_place_id`）。
  结束打卡：`set_data table="checkins" revision=<当前> append_open=false`（页面会说「打卡已经关了」）。
