# 会议出勤 — 使用指南

> **module**: meeting-attendance
> **doc_type**: UserGuide
> **status**: Active
> **owner**: FFOA Team
> **audience**: 会议管理员 / 会议组织者 / 普通员工 / 访客 / 领导
> **upstream_docs**: 01-prd.md, 04-state-machine.md, 05-ui-interaction-spec.md, 07-api.md
> **last_verified**: 2026-05-11

---

## 目录

1. [系统概览](#1-系统概览)
2. [核心概念](#2-核心概念)
3. [角色与职责](#3-角色与职责)
4. [Part 1 — 给员工：日常签到](#4-part-1--给员工日常签到)
5. [Part 2 — 给会议管理员：会议与名单管理](#5-part-2--给会议管理员会议与名单管理)
6. [Part 3 — Outlook 同步与纳管](#6-part-3--outlook-同步与纳管)
7. [Part 4 — 报表与审计](#7-part-4--报表与审计)
8. [Part 5 — 议程与资料上传](#8-part-5--议程与资料上传)
9. [常见问题（FAQ）](#9-常见问题-faq)

---

## 1. 系统概览

会议出勤系统迁移自原线上系统，**保留全部功能**，并接入 FFOA 统一登录与权限。v1.2 主要增量：

- **Outlook 单向同步**：Outlook 日历事件自动同步成本地会议，管理员手动纳管
- **签到方式校验**：会议 / 系列两层开关，按"工作地 vs 会议地点"自动派生允许的签到方式（线上 / 线下），扫错码或未配地点会拒签

**核心业务规则**（必记）：

- 会议**开始前 15 分钟**开放签到
- 会议**开始后 8 分钟**判迟到
- 同设备每场会议**只允许签到一次**，同用户可更新
- **访客扫码免登录保留**，但必须在参会名单内
- 参会名单**仅允许系统用户**，不接受自由填姓名 / 邮箱

---

## 2. 核心概念

| 概念 | 说明 |
|------|------|
| **Meeting** | 一场会议实例。状态 4 态：`SCHEDULED` / `IN_PROGRESS` / `COMPLETED` / `CANCELLED`，由系统按时间自动流转 |
| **MeetingSeries** | 系列会议（如每周例会）。一次配置自动衍生多场 Meeting |
| **Template** | 会议模板。常用配置一次保存，开会时一键套用 |
| **Attendance** | 出勤记录。状态：`NOT_CHECKED_IN` / `ON_SITE` / `ONLINE` / `LATE` / `ABSENT` 等 |
| **二维码** | 每场会议生成线上 + 线下两套二维码（用于签到方式校验区分） |
| **OutlookBinding** | Outlook 候选会议被管理员纳管后建立的绑定关系 |
| **graphEventId** | Outlook 事件 ID，全局唯一绑定 |
| **本地维护标识** | 一旦本地修改了纳管会议的标题 / 时间 / 地点 / 参会人，会议转"本地维护"，Outlook 不再覆盖 |
| **签到方式校验** | 开关开启后系统按"用户工作地 vs 会议地点"派生允许方式；扫错码或地点未配置均拒签 |
| **city（工作地 / 会议地点）** | 自动补全数据源 `GET /cities/suggestions`；为空则签到方式校验无法启用 |

---

## 3. 角色与职责

| 角色 | 职责 | 典型操作 |
|------|------|------|
| **Administrator**（系统管理员） | 全局管理 | 跨邮箱查看所有已绑定会议、权限调整 |
| **MeetingManager**（会议管理员） | 会议与参会人管理 | 创建会议、导入参会名单、查看全量报表、Outlook 纳管 |
| **Leader**（领导） | 关注出勤 | 看出勤报表与排名 |
| **Employee**（普通员工） | 参会签到 | 扫码签到、查看个人会议 |
| **Guest**（访客） | 免登录签到 | 扫码签到（必须在参会名单内） |

**关键权限点**：

| 权限码 | 控制 |
|------|------|
| `meeting:read` | 查看会议 |
| `meeting:manage` | 创建 / 修改 / 取消会议 |
| `meeting:report` | 查看出勤报表 |
| `meeting:outlook:bind` | Outlook 纳管 / 接管 |
| `meeting:audit:read` | 查看会议审计日志 |

---

## 4. Part 1 — 给员工：日常签到

### 4.1 已登录签到

1. 打开会议邀请收到的链接 / 扫码
2. 系统识别你是已登录用户 → 直接展示签到页
3. 点"签到" → 系统记录时间、设备、签到方式

### 4.2 访客（免登录）签到

1. 扫码进入访客签到页 `/meetingattendance/checkin/guest`
2. 填写姓名 / 邮箱（必须在参会名单内）
3. 提交 → 系统匹配名单后记录签到

⚠️ 不在参会名单的访客无法签到，需要会议管理员先把你加进名单。

### 4.3 签到方式校验下的拒签提示

| 拒签原因 | 提示 | 处理 |
|------|------|------|
| 扫了线上码但你被安排线下 | "该会议只允许线下签到" | 现场扫线下码 |
| 扫了线下码但你被安排线上 | "该会议只允许线上签到" | 用线上码 |
| 你的工作地未配置 | "工作地未配置，无法识别签到方式" | 联系管理员补工作地 |
| 会议地点未配置 | "会议地点未配置，无法识别签到方式" | 让会议组织者补会议地点 |

### 4.4 签到状态查看

`/meetingattendance/dashboard` → 个人会议卡片显示：

- `ON_SITE` / `ONLINE` — 已签到
- `LATE` — 迟到签到（会议开始 8 分钟后）
- `NOT_CHECKED_IN` — 未签到
- `ABSENT` — 会议结束后未签到自动判缺席

---

## 5. Part 2 — 给会议管理员：会议与名单管理

### 5.1 入口总览

| 页面 | 路由 | 用途 |
|------|------|------|
| 仪表盘 | `/meetingattendance/dashboard` | 会议总览 |
| 会议列表 | `/meetingattendance/meetings` | 所有会议管理 |
| 会议创建 | `/meetingattendance/meetings/create` | 新建会议 |
| 会议详情 | `/meetingattendance/meetings/:id` | 详情 + 参会人 + 签到情况 |
| 会议二维码 | `/meetingattendance/meetings/:id/qr` | 双二维码展示 / 打印 |
| 系列会议 | `/meetingattendance/series` | 系列管理 + 默认参会人 |
| 模板管理 | `/meetingattendance/templates` | 会议模板 |
| 用户管理 | `/meetingattendance/users` | 用户查看（跳转组织架构维护） |

### 5.2 创建会议

1. 进入"会议创建"
2. 必填：标题、起止时间、会议地点（启用签到方式校验时必填）
3. 选模板（可选）
4. 添加参会人（仅可选系统用户）
5. 提交 → 系统生成线上 + 线下两个二维码

### 5.3 创建系列会议

1. "系列会议" → 新建
2. 配置周期（每周 X / 每月 X 号 / 工作日）+ 起止时间
3. 配置默认参会人（每行可选签到方式：线下 / 线上 / 跟随工作地）
4. 系统自动衍生未来 N 期 Meeting；可单期排除

### 5.4 启用签到方式校验

**前置**：用户的工作地、会议地点都需要先在组织架构 / 会议详情里填好。

1. 会议详情或系列详情 → 打开"签到方式校验"开关
2. 系统提示 guard：未配 city 的用户列表 / 会议地点是否设置
3. 通过后开关生效

**临时调整**：单场会议可在详情页加备注覆盖默认；调整次数会写到报表"调整次数"列。

### 5.5 删除参会人

仅可删除**尚未产生出勤记录**的参会人。若该用户已有签到时间、状态 ≠ `NOT_CHECKED_IN`、或有人工出勤调整痕迹，系统会阻止并给提示。

### 5.6 取消会议

`SCHEDULED` / `IN_PROGRESS` 状态都可取消（含进行中的中途取消）。取消是 `CANCELLED` 终态，不可恢复。

### 5.7 批量标记缺席

会议完成后未签到的参会人 → 在会议详情可批量标记 `ABSENT`，用于报表准确性。

---

## 6. Part 3 — Outlook 同步与纳管

### 6.1 同步策略

**单向同步**：Outlook → 本地，不反向。混合策略 = Webhook 订阅 + Delta 增量 + 定时对账兜底。

### 6.2 入口

| 页面 | 路由 | 用途 |
|------|------|------|
| 同步中心 | `/meetingattendance/integrations/outlook` | 候选会议筛选 + 纳管 / 接管 + 同步历史 |
| 跨邮箱总览（Admin） | `/meetingattendance/integrations/outlook/bindings-all` | 跨邮箱看所有已绑定会议 |

### 6.3 候选会议怎么来

- 管理员首次进入同步中心，系统自动用当前管理员邮箱建立源邮箱绑定（无感知）
- 候选列表仅展示**与当前管理员邮箱相关**的 Outlook 事件
- 历史边界：仅接管 **2025-11-01 及之后**的会议
- 首次进入页时如邮箱无同步游标，**异步初始化候选快照**，页面会显示 "数据初始化中"

### 6.4 纳管

- **单次会议**：直接生成本地会议
- **seriesMaster**：仅生成系列锚点，实例由 occurrence/exception 自动同步生成
- **已结束的 seriesMaster**：拒绝纳管（明确提示"该系列已结束，无后续实例"）
- **唯一绑定约束**：同一 `graphEventId` 只能存在一个 active 绑定

### 6.5 接管

具备 Administrator / MeetingManager 权限的用户可对已绑定会议**强制接管**：

1. 找到目标绑定
2. 点"接管" → 当前绑定人和源邮箱切换为操作人
3. 写一条审计事件

### 6.6 同步边界

- 绑定创建 / 接管后**仅同步 syncFrom（绑定时刻）之后**的未进行实例；历史实例不自动回补
- 单次会议被本地修改（标题 / 时间 / 地点 / 状态 / 参会人）→ 转"本地维护"，**Outlook 不再覆盖**
- 详情页明确提示：「该会议已进行本地修改，已停止从 Outlook 自动同步」

### 6.7 历史系列处理

历史系列**不自动改 Outlook 数据**。上线后由管理员按迁移操作文档手工把"本系统历史系列"结束时间截断到当天之前，再由纳管的 Outlook 会议生成后续实例。

### 6.8 差异审计（v1.2）

每次同步保留：

- Outlook 官方源版本（含 `lastModifiedDateTime` + 原始 payload）
- 结构化差异摘要（`title` / `start/end` / `location` / `isCancelled` / `organizer` / `attendees`）
- 参会人三类口径计数：graph attendees / internal matched / required attendees

管理员查看绑定同步历史时可直接看到每次同步的官方源更新时间、变化字段、关键差异——**无需人工对比原始 JSON**。

---

## 7. Part 4 — 报表与审计

### 7.1 报表

`/meetingattendance/reports` — 出勤报表

- 单场报表：本场签到 / 迟到 / 缺席分布
- 系列报表：跨期出勤率、排名
- v1.2 新增列：**允许签到方式**、**调整次数**

### 7.2 审计日志

`/meetingattendance/audit-logs` — 会议模块专用审计

记录关键操作：会议创建 / 修改 / 取消、参会人增删、签到方式开关、Outlook 纳管 / 接管 / 本地维护转换、批量标缺席等。

⚠️ 与平台 audit-system 是**独立日志**（专注会议域），但底层接 `@Auditable` 装饰器，最终也写主审计。

---

## 8. Part 5 — 议程与资料上传

议程能力让会议管理员把会议结构化拆成"段 + 项"，并把每一项的资料准备工作派给具体员工。员工提前上传，所有参会人会前查看，会中扫码即用。

### 8.1 给会议管理员

#### 8.1.1 编辑议程

1. 进入会议详情页 → 点「编辑议程」（仅管理员 / creator 可见）
2. 跳到议程编辑页 `/meetingattendance/[meetingId]/agenda/edit`
3. 左列是议程 tree（段 → 项），右列是当前选中项的编辑表单
4. 操作：
   - 「加段」→ 输入段标题
   - 「加项」→ 在选中段下创建议程项，填标题 / 描述 / 时长（分钟）/ 主讲人 / 分类
   - 拖手柄调段或项顺序
5. 改动**即时保存**——无需点「保存」总按钮
6. 改完返回会议详情，议程段刷新最新结构

> 会议进入 `COMPLETED` 或 `CANCELLED` 后**仍允许修改议程**（满足会后补主讲人 / 补资料场景），前端会弹 warning「该会议已结束/取消，是否仍要修改议程？」让你确认；所有改动写审计（含 `agendaModifiedAfterMeetingEnd: true` flag）。

#### 8.1.2 分配上传任务

1. 议程编辑页或会议详情议程段，点议程项「分配任务」
2. 弹窗内多选员工 + 可选填截止时间
3. 确认后每位被指派人收到一条 `PENDING` 任务，会出现在他们的「我的待办」里
4. 议程项卡片徽章会显示「PENDING N / UPLOADED M」实时统计

**规则**：

- 同一员工对同一议程项**同时只能有一个未完成任务**——如已有 PENDING，重复分配会被拒
- 截止时间可空，仅作为提醒不影响任务有效性
- 上传完成会自动 flip 任务到 `UPLOADED`，**不需要员工手动「标记完成」**
- 想取消任务，PATCH 即可（CANCELLED 与 UPLOADED 均为终态，不可回退；如需"返工"重新分配新任务）

#### 8.1.3 删除议程项的连带影响

议程编辑页删除议程项时，系统会先弹警告：「将连带删除该项的 N 个附件 + M 个待办任务（30 天内可联系 admin 恢复，之后物理清理）」。确认后议程项 / 附件 / 上传任务**全部软删**（`deletedAt` 标记），员工的待办列表自动剔除该任务（不会报错）。

> 议程项是资源根，附件与任务无独立生命周期。软删后 30 天内 admin 可帮助恢复；之后由 cron 物理清理 + unlink 底层文件。

#### 8.1.4 上传会议级资料

议程段顶部「上传会议资料」按钮（仅管理员可见）用于上传不挂在具体议程项上的会议公用资料。

### 8.2 给员工

#### 8.2.1 查看待办

1. 顶部菜单 / 用户菜单进入「我的待办」`/meetingattendance/my-tasks`
2. 默认显示 PENDING 任务列表（可切「全部 / 已完成」筛选）
3. 每张卡片包含：会议标题 / 议程项标题 / 截止时间 / 分配人 / 「去上传」按钮

#### 8.2.2 上传资料

1. 点任务卡片 → 跳到会议详情议程项位置
2. 点议程项「上传资料」→ 弹文件上传组件
3. 拖拽 / 点选文件——**单文件 ≤ 200MB，文件类型必须在允许列表内**
4. 文件队列内每个文件独立进度条；全部完成弹窗自动关闭
5. 上传成功后该任务变 `UPLOADED`，自动从待办列表移除

**前端先校验**——文件过大或类型不允许会**直接拦截不发请求**，看到这两条提示：

- 「文件超过 200MB，请压缩后再上传」
- 「不支持的文件类型」

> 上传成功只挂在议程项上，跟「分配给你的那条任务」松耦合——别人也能并行上传到同议程项。

### 8.3 给所有参会人

#### 8.3.1 查看议程

会议详情页议程段：

- 段标题 + 议程项（折叠展示）
- 议程项展开后看到描述、时长、主讲人、分类、附件列表
- 仅参会人可查看附件；非参会人没有访问权

#### 8.3.2 下载附件

议程项展开后，点附件文件名即可下载。大文件采用流式下载，浏览器直接保存。

### 8.4 常见错误提示

| 提示 | 含义 | 处理 |
|---|---|---|
| 文件超过 200MB，请压缩后再上传 | 单文件大小超限 | 压缩或拆分后重传 |
| 不支持的文件类型 | mimeType 不在允许列表 | 转格式（PDF / Office / 图片等常见格式） |
| 该上传任务不属于你 | 你点的「上传」按钮对应任务被指派给别人 | 找你自己的任务卡片 |
| 仅会议管理员可编辑议程 | 非管理员 / 非 creator 触发编辑 | 联系会议组织者 |
| 仅本人或管理员可删除 | 你不是这附件的上传人也不是 manager | 找上传人或管理员处理 |
| 议程项不存在或已删除 | 任务跳转目标已被删除 | 待办列表会自动刷新 |

---

## 9. 常见问题（FAQ）

### Q1：扫码后页面说"不在参会名单"，但我应该参会

联系会议管理员，让他在会议详情把你加进参会名单。

### Q2：访客可以填任意姓名签到吗？

不行。访客签到必须输入与参会名单内一致的姓名 + 邮箱才能通过。

### Q3：会议开始 9 分钟我才签到，为什么是迟到不是缺席？

迟到判定线是开始后 8 分钟，缺席是会议结束后未签到。9 分钟在会议中段属于迟到正常。

### Q4：Outlook 会议被取消了，本地会议状态变什么？

`CANCELLED`。同步任务把 Outlook 的取消 / 删除统一映射为本地 `CANCELLED`，并记录同步原因（内部元数据，不改对外状态枚举）。

### Q5：我在本地改了会议标题，Outlook 那边后续改的会同步过来吗？

**不会**。会议转"本地维护"后停止接受 Outlook 覆盖，避免冲突。详情页会明确提示锁定时间和操作人。

### Q6：签到方式校验对 Outlook 同步会议生效吗？

生效。无论会议来源，开关和派生逻辑一致。前提是会议地点 + 用户工作地都已配置。

### Q7：我能跨邮箱看所有已绑定会议吗？

仅 Administrator 可见。入口：`/meetingattendance/integrations/outlook/bindings-all`。

### Q8：同一台设备能给多个人签到吗？

不能。同设备每场会议只允许一次签到（同用户可更新）。强签到方式校验 + 设备指纹是反作弊的关键设计。

### Q9：双语支持？

支持。本模块视觉允许保留原系统风格（非 Lark 风格）以降低迁移改动量，但所有文案接入 i18n。

### Q10：我把议程项删了，被分配的员工会不会一直看到一个跳不动的待办？

不会。议程项删除会**连带软删**其全部附件 + 上传任务（`deletedAt` 标记），员工待办列表会自动刷新（默认 `WHERE deletedAt IS NULL` 过滤），看不到失效任务。30 天内 admin 可帮助恢复；之后由 cron 物理清理 + unlink 底层文件。极少数情况员工正好在跳转中遇到，会被 toast 提示「议程项已删除」。

### Q11：员工上传完后才发现选错文件，能撤回吗？

可以——上传人本人 / 管理员都能在议程项附件行点「删除附件」。删除附件不会回退任务状态（任务一旦 `UPLOADED` 即终态），如果还要让该员工补上传，**重新分配一个新任务**即可。

---

## 关联文档

- [01-prd.md](01-prd.md) — 完整 PRD（含 v1.2 Outlook 同步与签到方式校验全部规则）
- [02-user-journey.md](02-user-journey.md) — 用户场景
- [04-state-machine.md](04-state-machine.md) — Meeting + Attendance 状态机
- [05-ui-interaction-spec.md](05-ui-interaction-spec.md) — UI 交互规范
- [07-api.md](07-api.md) — API 文档
- [audit-system 使用指南](../audit-system/11-user-guide.md) — 主审计系统
