# Site Attendance - User Guide

> **module**: site-attendance
> **doc_type**: UserGuide
> **status**: Active
> **last_verified**: 2026-04-17

面向前台管理员和员工的精简使用指南。

---

## 两种使用形态

| 场景 | 入口 | 代表配置 |
|------|------|---------|
| 单家公司一个办公地 | 独立 QR（永久或定时轮换）| `accessMode=SIGNED`，不开共享 |
| 多家公司共用办公地 | 一个分诊 QR → 选公司 → 各自签到页 | 开共享 + 配合作伙伴 |

---

## 1. 管理员：签到点列表

侧栏 → **Site Attendance** → **Checkpoints**

![Admin list](./assets/v15-01-admin-list.png)

---

## 2. 管理员：新建签到点

右上 **Create Checkpoint**。关键字段分五组：

![Create page](./assets/v15-02-create.png)

| 区块 | 要点 |
|------|------|
| **Basic Information** | 名称 / 时区 / 地址（地图点选） |
| **Location Validation** | `Skip` / `ALLOW_WITH_FLAG` / `STRICT_BLOCK` |
| **Access Settings** | Allow check-in without login（免登录兜底） |
| **Access mode**（v1.5） | `Public`（兼容静态 QR）/ `Signed`（推荐，防截图流传）|
| **QR rotation**（v1.5，仅 Signed）| `Permanent` / `Scheduled`（默认 1h + 120s 宽限）|
| **Shared check-in**（v1.5） | 多公司共用办公地时开启；填 Company ID（`ff`/`aixc` 等短标识）+ Company name |

**合作伙伴**：保存后回到**编辑页**添加。`Target URL` 的 hostname 必须在运维白名单中，否则报 `PARTNER_TARGETURL_HOST_NOT_ALLOWED`。

---

## 3. 管理员：签到点详情

![Detail page](./assets/v15-03-detail.png)

三卡片 + 签到记录表：

- **QR 卡片（智能）**
  - `Public` + 非共享 → QR 编码直达签到页，可打印
  - `Signed`（或共享）→ **"Display page" QR**，管理员要在前台 iPad / 大屏打开此 URL 作为动态 QR 展示
- **Today's Summary** — 今日签到/签退人数
- **Configuration** — 时区、地址、策略等
- **Attendance Events** — 按日期/用户/类型筛选，可 CSV 导出

---

## 4. 前台部署：动态大屏

在前台 iPad / 屏幕打开 **Display page URL**（详情页可复制/打开），页面黑底自动展示当前有效 QR，按整点自动刷新。

![Display page](./assets/v15-04-display.png)

员工扫这个屏上的 QR 即可。**无需人工干预**。

---

## 5. 员工：普通签到（单家公司）

扫前台 QR → 签到页 → 点中央圆形按钮：

- **已登录**：直接签到 → 按钮变 `Check Out`
- **未登录**：弹窗二选一
  - `Log in to continue` — 跳 SSO 登录，成功后自动回签到页（带 ticket）
  - `Continue without login` — 搜姓名/邮箱/工号 → 选中自己 → 签到
- 同一天可多次 `Check-in → Check-out` 循环（外勤、午休场景）

---

## 6. 员工：共享签到（多公司）

![Dispatch page](./assets/v15-05-dispatch.png)

1. 扫前台共享 QR → 进入 **Select your company** 页
2. 每张卡片：公司名 + 签到点名称
3. 点自己公司：
   - 自家 → 同域跳自家签到页
   - 伙伴 → 跨域跳对方 workspace
4. 首次选完后 **localStorage 记住**，下次扫码自动跳（不重新展示）
5. 选错了点签到页右上角 **← Switch company** 回分诊页重选：

![Signin with Switch company button](./assets/v15-06-signin.png)

**切换公司的时效约束**：`Switch company` 按钮携带原始 QR token 回跳；token 在 1h+宽限期内有效，过期后回到分诊页会显示"二维码无效"，必须重新扫前台当前 QR。**这样防止保存 URL 长期滥用**。

---

## 常见问答

**Q1. 已打印的静态 QR 切到 `Signed` 模式后还能扫吗？**
不能。`Signed` 需要服务端签发的 URL，旧静态 QR 会报"请通过前台二维码签到"。切换前把前台大屏准备好。

**Q2. 用 iPhone 自带相机扫码后没保留登录状态？**

iOS 相机扫码会沿用 Safari 上次的浏览模式；如果上次是无痕标签页，扫到的链接也会落在无痕标签里 → `localStorage` 关页就丢 → 下次再扫又要重新登录。

**正确姿势**：相机识别二维码后，预览框出现链接 → **不要直接点黄色横幅**，而是点 **预览框右下角** 的「**在 Safari 中打开**」（中文）/「**Open in Safari**」（英文）按钮，跳转到默认 Safari 主进程后登录态可以长期保留。

> **English**: When you scan the QR with iPhone's built-in Camera, the link may open in a Private tab (iOS uses your last Safari mode). In Private tabs, login state is wiped when the tab closes. To fix: after the Camera detects the code, look at the bottom-right of the preview card and tap **"Open in Safari"** instead of the yellow banner. This jumps to the main Safari process where login persists.

其它扫码工具（微信扫一扫、钉钉扫码、QQ 扫一扫等）会在各自 app 内置浏览器中打开，**localStorage 跟系统 Safari/Chrome 完全隔离**。所以也保留不住登录状态，需要在右上角菜单选「在浏览器打开」。

> **English**: Other scanners (WeChat, DingTalk, QQ, Alipay) open links in their in-app webview, which has its own `localStorage` separate from system Safari/Chrome. To preserve login, tap the menu (⋯) and choose "Open in default browser".

**Q2. 二维码被拍到微信群，第二天还能用吗？**
不能。`Signed` + 1 小时轮换下，旧 token 最多 1h+宽限期（默认 120s）后失效。

**Q3. 员工扫码后看到"二维码已过期"？**
让他回前台大屏重新扫最新的 QR。大屏按整点自动刷新。

**Q4. 跨公司签到时我的 FF 账号会同步到 AIxC 吗？**
不会。跨域签到页发现 AIxC 端未登录 → 弹 `Log in to continue / Continue without login`。无 AIxC 账号可走免登录。v1.5 不做跨域 SSO。

**Q5. 保存 Partner 时报 `PARTNER_TARGETURL_HOST_NOT_ALLOWED`？**
目标 URL 的域名不在运维白名单（env `SHARED_CHECKIN_ALLOWED_HOSTS`）里。联系运维把对方 workspace 的 hostname 加进去，**生产和 UAT 两侧都要改**。

**Q6. 两家公司签到突然互签不了？**
自查：① 两侧 `SHARED_CHECKIN_SECRET` 同值；② 白名单两侧都含对方 hostname；③ 两侧服务健康；④ 证书未过期。

---

## 管理员排查清单

| 现象 | 检查 |
|------|------|
| 新建 checkpoint 转圈 | Console 常见 `CHECKPOINT_SHARED_COMPANY_MISSING`（开了共享但没填 Company ID / Name） |
| 员工反馈"请通过前台二维码签到" | 是否 `Signed` 模式；员工是否扫的旧静态 QR 而不是大屏当前 QR |
| 员工反馈"二维码已过期" | 前台大屏是否在线；让员工重扫 |
| 大屏 QR 转圈 | checkpoint `isActive=true`；网络可达；浏览器 Console |
| 分诊页只有一家选项 | 编辑页是否已添加 Partner 且 `isActive=true` |

