# 绩效管理模块 — 业务流程测试编排

> **module**: performance
> **doc_type**: E2ESpec
> **status**: Active
> **owner**: FFOA 开发团队
> **upstream_docs**: 01-prd.md, 02-user-journey.md, 09-test-scenarios.md
> **last_verified**: 2026-03-20

---

## 测试环境

L2 MCP E2E **必须运行在独立测试环境**，不得指向开发环境（dev DB）。

### 环境配置

> 测试环境配置（地址、端口、数据库凭据）由统一环境文档提供，参见 `testing/backend/docs/TEST_ENV_CONFIG.md`。
> 以下仅列出启动方式和校验项。

### 启动方式

```bash
# 一键准备（确保测试 DB → 重建 schema + 种子 → 启动测试栈）
bash testing/scripts/run-e2e.sh

# 测试完成后停止
bash testing/scripts/stop-e2e-stack.sh
```

测试账号及密码由种子脚本（`org-seed.ts`）自动创建，具体凭据参见 `testing/backend/docs/TEST_ENV_CONFIG.md`。

---

## 执行规范

### 鉴权

- 首次登录后保存 `storageState`
- 不在每个流程重复走登录 UI，除非该流程专门验证登录态或权限

### 元素定位

- 优先使用 accessibility tree（role/name）
- 不依赖 `data-testid`
- 输入组件优先使用可见文本和标签定位

### 断言要求

- 每个流程至少包含页面级断言和结果级断言
- 提交、发布、状态流转后必须断言回显或列表变化
- 权限场景必须断言“看不到”或“被拒绝”

### 测试账号

> 账号详细信息（用户名、密码、角色、组织）参见 `testing/backend/docs/TEST_ENV_CONFIG.md`。以下仅列出各流程使用的角色分工：

| 账号 | 流程中的角色 | 备注 |
|------|------------|------|
| `itadmin` | HR / 管理员 | 周期管理、配置、结果发布、报表 |
| `test.dev1` | 员工 | KPI 填写、自评、结果确认 |
| `test.lead1` | 经理 | KPI 审批、经理评估、360 填写 |
| `test.mgr1` | 部门经理 | 备用管理角色 |
| `test.robot1` | 员工 | 机器人研发销售 | 用于空数据与隔离验证 |

---

## 流程 1：初始化周期（P0）

**角色**: `itadmin`
**目标**: 创建等级配置 → 创建周期 → 发布周期
**前置状态**: 无
**输出状态**: 存在一个 GOAL_SETTING 周期 `cycleName = "E2E测试Q3"`，组织为 `车辆研发销售`

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 1.1 | 登录 `itadmin`，导航到 `/performance/admin` | — | 侧栏"管理"分组可见：配置概览、周期管理、等级配置 |
| 1.2 | 进入 `/performance/settings/grades`，点击"创建配置" | `{name: "E2E等级", grades: [{code:"S",name:"卓越",min:90,max:100}, {code:"A",name:"优秀",min:80,max:89}, {code:"B",name:"良好",min:70,max:79}, {code:"C",name:"待改进",min:60,max:69}, {code:"D",name:"不合格",min:0,max:59}]}` | 列表出现"E2E等级"，5 个等级行 |
| 1.3 | 进入 `/performance/cycles`，点击"创建周期" | `{name: "E2E测试Q3", type: "季度", organization: "车辆研发销售", startDate: "2026-07-01", endDate: "2026-09-30", gradeConfig: "E2E等级"}` | 列表出现"E2E测试Q3"，状态标签为"草稿" |
| 1.4 | 找到"E2E测试Q3"，点击操作菜单中的"发布" | 确认对话框点击"确认" | 状态标签从"草稿"变为"目标设定中" |

### 1.4 补充：状态推进交互模式

> 周期列表中每行有操作按钮（三点菜单或直接按钮），包含"发布"/"推进"等操作。
> 点击后弹出确认对话框，确认后状态标签更新。
> **断言方式**：刷新页面或等待列表自动更新，验证状态标签文本变化。

---

## 流程 2：员工填写并提交 KPI（P0）

**角色**: `test.dev1`
**前置状态**: 流程 1 输出 — "E2E测试Q3" 处于 GOAL_SETTING
**输出状态**: `test.dev1` 有 3 条 KPI，总权重 100%，状态为 SUBMITTED

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 2.1 | 切换角色登录 `test.dev1`，进入 `/performance/kpi` | — | 页面显示当前周期"E2E测试Q3"，可见"新增 KPI"按钮 |
| 2.2a | 点击"新增 KPI"，填写第 1 条 | `{name: "提升代码质量", weight: 40, description: "减少 bug 率 30%", targetValue: "bug率<5%"}` | 列表新增一行，权重显示 40% |
| 2.2b | 点击"新增 KPI"，填写第 2 条 | `{name: "完成技术方案", weight: 30, description: "输出 3 份技术方案", targetValue: "3份"}` | 列表 2 行，总权重显示 70% |
| 2.2c | 点击"新增 KPI"，填写第 3 条 | `{name: "团队知识分享", weight: 30, description: "每月 1 次分享", targetValue: "3次"}` | 列表 3 行，总权重显示 100%（绿色） |
| 2.3 | 点击"提交全部" | 确认对话框点击"确认" | 3 条 KPI 状态变为"待审批"，提交按钮消失或变为 disabled |

### 2.2 补充：KPI 新增表单字段

> 表单通常为对话框或内联表单，包含：名称（textbox）、权重（number input）、描述（textarea）、目标值（textbox）。
> 权重汇总在页面上实时计算显示。
> **关键断言**：权重未达 100% 时提交按钮可能 disabled。

---

## 流程 3：依赖确认（P1）

**角色**: `test.dev1` → `test.lead1`
**前置状态**: 流程 1 输出的 GOAL_SETTING 周期
**输出状态**: 依赖已确认

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 3.1 | `test.dev1` 点击"新增 KPI"，填写名称"跨团队对接"、权重 20，在依赖人选择器中选择 test.lead1 | 名称: 跨团队对接, 权重: 20, 依赖人: test.lead1 | 依赖状态显示"待确认" |
| 3.2 | 尝试直接提交全部 KPI | — | 提交被阻断，提示"有未确认的依赖" |
| 3.3 | 切换到 `test.lead1`，进入 `/performance/kpi` 处理依赖 | — | 可见待确认记录 |
| 3.4 | 确认依赖 | — | 发起人侧显示"已确认" |

---

## 流程 4：经理审批 KPI（P0）

**角色**: `test.lead1`
**前置状态**: 流程 2 输出 — `test.dev1` 有 3 条 SUBMITTED 的 KPI
**输出状态**: `test.dev1` 的 KPI 状态为 APPROVED

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 4.1 | 切换角色登录 `test.lead1`，进入 `/performance/kpi/team` | — | 下属列表中可见 `test.dev1`，状态为"待审批" |
| 4.2 | 点击 `test.dev1` 展开或进入详情 | — | 可见 3 条 KPI（提升代码质量 / 完成技术方案 / 团队知识分享），每条状态为"待审批" |
| 4.3 | 点击"全部通过"或逐条点击"通过" | — | 所有 KPI 状态变为"已通过"，`test.dev1` 行的状态变为"已通过" |

### 4.3 补充：审批交互

> 团队 KPI 页面可能有两种审批方式：逐条通过（每行有通过/驳回按钮）或批量通过（页面顶部全选 + 通过）。
> 驳回时需填写原因。通过一般无需额外输入。

---

## 流程 5：空数据与组织隔离（P0）

**角色**: `test.robot1`
**前置状态**: 流程 1 在"车辆研发销售"创建了周期（注意：种子数据可能为所有组织创建了周期）
**输出状态**: 无（只读验证）

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 5.1 | 切换角色登录 `test.robot1`，进入 `/performance` | — | 页面正常加载，不报错。若种子有该组织周期，显示数据；若无则显示空态 |
| 5.2 | 进入 `/performance/kpi` | — | 页面正常加载，不持续 loading。无 KPI 时显示空态提示 |
| 5.3 | 进入 `/performance/360` | — | 显示"暂无待完成的评估任务"或类似空态 |
| 5.4 | 检查侧栏 | — | **不可见"管理"分组**（配置概览、周期管理、等级配置等管理菜单对 Employee 隐藏） |
| 5.5 | 直接访问 `/performance/admin` | — | 被拒绝或重定向（不显示管理内容） |

---

## 流程 6：KPI 自评与经理评分（P0）

**角色**: `itadmin` → `test.dev1` → `test.lead1`
**前置状态**: 流程 4 输出 — KPI 已通过审批
**输出状态**: `test.dev1` 有自评分数，`test.lead1` 有经理评分，最终分数已计算

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 6.1a | 切换到 `itadmin`，进入 `/performance/cycles` | — | 找到"E2E测试Q3"，状态为"目标设定中" |
| 6.1b | 推进周期到 IN_PROGRESS | 操作菜单 → "推进" → 确认 | 状态变为"执行中" |
| 6.1c | 推进周期到 EVALUATING | 操作菜单 → "推进" → 确认 | 状态变为"评估中" |
| 6.2a | 切换到 `test.dev1`，进入 `/performance/kpi` | — | 每条 KPI 出现"自评"入口（按钮或链接） |
| 6.2b | 对第 1 条 KPI 填写自评 | `{score: 85, comment: "完成度良好，bug率降低25%"}` | 自评分数 85 回显在该 KPI 行 |
| 6.2c | 对第 2、3 条 KPI 填写自评 | `{score: 90, comment: "超额完成"}, {score: 80, comment: "按计划完成"}` | 3 条 KPI 均有自评分数 |
| 6.3a | 切换到 `test.lead1`，进入 `/performance/kpi/team` | — | `test.dev1` 行显示"待评分"状态 |
| 6.3b | 打开 `test.dev1` 的 KPI，填写经理评分 | `{kpi1: {score: 82, comment: "达标"}, kpi2: {score: 88, comment: "优秀"}, kpi3: {score: 78, comment: "一般"}}` | 每条 KPI 显示经理评分，加权总分自动计算 |

---

## 流程 7：360 评估（P1）

**角色**: `itadmin` → `test.lead1`
**前置状态**: 流程 6 已进入评估阶段
**输出状态**: 一条 360 评估已完成

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 7.1 | `itadmin` 在 `/performance/settings/360-templates` 点击新增，填写模板名称"E2E通用模板"，添加 3 个评估维度：专业能力(40%)、协作沟通(30%)、创新能力(30%) | 模板名称: E2E通用模板, 新增 3 个维度 | 模板出现在列表中 |
| 7.2 | `itadmin` 在 `/performance/360` 点击创建评估，选择被评人 test.dev1、模板"E2E通用模板"、评估人 test.lead1 | 被评人: test.dev1, 模板: E2E通用模板, 评估人: test.lead1 | 评估记录生成，状态为"进行中" |
| 7.3 | `test.lead1` 打开 `/performance/360`，对"专业能力"打分 85，对"协作沟通"打分 80，对"创新能力"打分 75，填写评语"整体表现良好" | 对 3 个维度逐一打分，填写评语 | 提交成功，任务消失或状态变为已完成 |
| 7.4 | `itadmin` 打开 360 评估详情 | — | 可见统计结果和平均分 |

---

## 流程 8：校准（P0）

**角色**: `itadmin`
**前置状态**: 流程 6 输出 — 评估阶段已完成
**输出状态**: 校准完成，至少 1 名员工等级被调整

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 8.1 | 在 `/performance/cycles` 推进周期到 CALIBRATING | 操作菜单 → "推进" → 确认 | 状态变为"校准中" |
| 8.2 | 进入 `/performance/calibration`，选择周期"E2E测试Q3" | — | 校准概览加载，可见员工列表、当前等级、等级分布图 |
| 8.3 | 找到 `test.dev1`，点击"调整等级" | `{newGradeCode: "S", reason: "跨部门贡献突出"}` | 等级列变为"S"，调整日志新增一条 |

---

## 流程 9：发布结果并员工确认（P0）

**角色**: `itadmin` → `test.dev1`
**前置状态**: 流程 8 输出 — 校准完成
**输出状态**: 结果已发布，`test.dev1` 已确认

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 9.1 | 在 `/performance/cycles` 推进周期到 CONFIRMING | 操作菜单 → "推进" → 确认 | 状态变为"结果确认中" |
| 9.2 | 进入 `/performance/results/admin`，选择"E2E测试Q3" | — | 结果列表显示员工、等级、分数。统计面板显示总人数 |
| 9.3 | 点击"发布全部"或逐个发布 | 确认对话框 | 结果状态变为"已发布" |
| 9.4 | 切换到 `test.dev1`，进入 `/performance` 或结果页面 | — | 可见自己的等级（S）和分数 |
| 9.5 | 点击"确认"按钮 | — | 确认状态变为"已确认"，按钮变为"已确认"或消失 |

---

## 流程 10：统计分析与权限（P1）

**角色**: `itadmin` → `test.dev1`
**前置状态**: 至少已有一轮已发布的结果
**输出状态**: 无（只读验证）

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 10.1 | `itadmin` 进入 `/performance/analytics` | — | 报表页面加载，可见图表/指标（部门报表默认） |
| 10.2 | 切换到公司报表视图（如有 tab 或筛选） | — | 公司维度数据可见 |
| 10.3 | 切换到 `test.dev1`，检查侧栏 | — | 无"统计分析"菜单（或访问被拒绝） |

---

## 流程 11：KPI 驳回与修改（P1）

**角色**: `test.lead1` → `test.dev1` → `test.lead1`
**前置状态**: 流程 2 输出 — `test.dev1` 有待审批的 KPI
**输出状态**: KPI 经驳回→修改→重新提交→重新审批，最终状态为 APPROVED

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 11.1 | `test.lead1` 进入 `/performance/kpi/team`，找到 `test.dev1` 的某条 KPI | — | KPI 状态为"待审批" |
| 11.2 | 点击"驳回"，填写驳回原因 | `{reason: "目标值不够量化，请改为可衡量指标"}` | KPI 状态变为"已驳回"，驳回原因回显 |
| 11.3 | 切换到 `test.dev1`，进入 `/performance/kpi` | — | 被驳回的 KPI 显示"已驳回"状态和驳回原因 |
| 11.4 | 修改该 KPI | `{targetValue: "bug率<3%, 代码审查覆盖率>80%"}` | 修改保存成功 |
| 11.5 | 重新提交 | — | 状态变为"待审批" |
| 11.6 | 切换到 `test.lead1`，审批通过 | — | 状态变为"已通过" |

---

## 流程 12：结果申诉（P1）

**角色**: `test.dev1` → `itadmin`
**前置状态**: 流程 9 输出 — 结果已发布
**输出状态**: 申诉已提交并处理

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 12.1 | `test.dev1` 进入绩效结果页面 | — | 可见自己的等级，可见"申诉"按钮 |
| 12.2 | 点击"申诉" | `{reason: "经理评分与实际完成情况不符，Q2 bug率已降至2%"}` | 申诉状态显示"已申诉"，申诉原因回显 |
| 12.3 | 切换到 `itadmin`，进入 `/performance/results/admin` | — | 可见 `test.dev1` 的申诉标记 |
| 12.4 | 处理申诉（如有处理入口） | `{response: "已复核，维持原等级"}` | 申诉状态变为"已处理" |

---

## 流程 13：战略目标（P1）

**角色**: `itadmin`
**前置状态**: 至少有一个活跃周期
**输出状态**: 存在战略目标且已分配到部门/员工

| 步骤 | 操作 | 输入数据 | 断言 |
|------|------|---------|------|
| 13.1 | 进入 `/performance/strategic-objectives` | — | 页面正常加载，可见战略目标列表（可能为空） |
| 13.2 | 点击"创建目标" | `{name: "提升产品质量", description: "全年 bug 率降低 50%", year: 2026}` | 目标出现在列表中 |
| 13.3 | 点击目标，分配到部门或员工 | `{assignTo: "车辆研发销售"}` | 分配记录显示 |

---

## 执行优先级

| 流程 | 优先级 | 覆盖的功能 |
|------|--------|-----------|
| 1 初始化周期 | P0 | 等级配置、周期创建、发布 |
| 2 员工填写并提交 KPI | P0 | KPI 创建、权重计算、提交 |
| 4 经理审批 KPI | P0 | 团队 KPI、审批通过 |
| 5 空数据与组织隔离 | P0 | 空态、权限隔离 |
| 6 KPI 自评与经理评分 | P0 | 状态推进、自评、经理评分 |
| 8 校准 | P0 | 校准概览、等级调整 |
| 9 发布结果并员工确认 | P0 | 结果发布、员工确认 |
| 3 依赖确认 | P1 | KPI 依赖阻断与确认 |
| 7 360 评估 | P1 | 模板、发起、填写、汇总 |
| 10 统计分析与权限 | P1 | 报表、权限隔离 |
| 11 KPI 驳回与修改 | P1 | 驳回→修改→重新提交 |
| 12 结果申诉 | P1 | 申诉提交与处理 |
| 13 战略目标 | P1 | 目标创建、分配 |

### 功能覆盖矩阵

| 前端页面 | 对应流程 | 覆盖状态 |
|---------|---------|---------|
| `/performance` (概览) | 1, 5, 9 | ✅ |
| `/performance/admin` (配置概览) | 1 | ✅ |
| `/performance/settings/grades` (等级配置) | 1 | ✅ |
| `/performance/cycles` (周期管理) | 1, 6, 8, 9 | ✅ |
| `/performance/kpi` (我的 KPI) | 2, 6 | ✅ |
| `/performance/kpi/team` (团队 KPI) | 4, 6, 11 | ✅ |
| `/performance/360` (360 评估) | 5, 7 | ✅ |
| `/performance/settings/360-templates` (360 模板) | 7 | ✅ |
| `/performance/calibration` (校准概览) | 8 | ✅ |
| `/performance/calibration/[id]` (校准会话详情) | — | ⚠️ 校准列表页未链接到会话详情，暂不纳入 E2E |
| `/performance/results/admin` (结果管理) | 9, 12 | ✅ |
| `/performance/analytics` (统计分析) | 10 | ✅ |
| `/performance/strategic-objectives` (战略目标) | 13 | ✅ |

> **备注**：整体评语（overall-eval-comment）的保存和读取已在 09-test-scenarios TC-EVAL-009/010/011 中作为 P0 API 场景覆盖，当前不纳入 E2E 编排。

---

## 报告输出

测试完成后输出到：

`testing/reports/performance-{YYYY-MM-DD}-e2e-report.md`

---

**创建时间**: 2026-01-14
**更新时间**: 2026-03-20
**状态**: Active
**版本**: v8.2
