CUJ 总览
| CUJ |
优先级 |
描述 |
触发点 |
业务价值 |
E2E 测试状态 |
| E-CUJ-1 |
P0 |
每日打卡签到/签退 |
员工到达工作地点 |
薪资准确性、考勤追踪 |
已覆盖 |
| E-CUJ-2 |
P0 |
查看我的排班 |
员工查看每周排班 |
团队协调 |
已覆盖 |
| E-CUJ-3 |
P0 |
登录认证 + PIN 设置 |
首次登录或会话过期 |
安全门控 |
已覆盖 |
| E-CUJ-4 |
P1 |
我的服务与预约 |
员工查看分配的服务 |
服务交付、小费/评价追踪 |
已覆盖 |
| E-CUJ-5 |
P1 |
换班与请假申请 |
员工需要调整排班 |
灵活性、减少缺勤 |
已覆盖 |
| E-CUJ-6 |
P1 |
团队聊天与消息 |
员工需要与团队沟通 |
团队协作、减少沟通失误 |
已覆盖 |
| E-CUJ-7 |
P2 |
查看公告 |
管理层发布公告 |
信息传达、制度合规 |
已覆盖 |
| E-CUJ-8 |
P2 |
查看报表(仅限管理员) |
管理员需要绩效数据 |
数据驱动决策、绩效监控 |
已覆盖 |
| E-CUJ-9 |
P2 |
个人资料与设置 |
员工管理个人资料/通知 |
自助服务、通知控制 |
已覆盖 |
E-CUJ-1: 每日打卡签到/签退 P0
用户流程
flowchart TD
A["首页"] --> B["打卡页签"]
B --> C{"当前状态"}
C -->|"未签到"| D["签到按钮"]
C -->|"已签到"| E["签退 / 休息按钮"]
D --> F["提交签到"]
F --> G["成功: 状态更新"]
E --> H["签退 / 开始休息"]
H --> I["状态更新"]
B --> J["查看考勤记录"]
J --> K["补卡申请"]
K --> L["提交补卡"]
BDD 场景
场景 1.1: 签到
Given 员工已登录且尚未签到
When 员工点击打卡页签
Then 显示"签到"按钮
When 员工点击"签到"
Then 创建一条签到记录
And 状态变更为"已签到"
And 出现"签退"和"休息"按钮
场景 1.2: 签退
Given 员工已签到
When 员工点击"签退"
Then 签退时间被记录
And 状态变更为"未签到"
And 计算总工作时长
场景 1.3: 查看考勤记录
Given 员工在当前薪资周期内有打卡记录
When 员工导航到 个人资料 > 考勤记录
Then 显示所有考勤条目
And 每条记录显示日期、签到/签退时间和总工时
场景 1.4: 补卡申请
Given 员工有一次漏打卡记录
When 员工导航到 个人资料 > 考勤记录 > 补卡申请
And 输入缺失的日期、时间和原因
And 提交申请
Then 补卡申请显示为"待审批"状态
And 申请已发送给管理层审批
测试文件:
integration_test/t03_time_clock_test.dart (4 个场景)
integration_test/t12_clock_deep_test.dart (6 个场景)
E-CUJ-2: 查看我的排班 P0
用户流程
flowchart TD
A["首页"] --> B["排班页签"]
B --> C["本周视图"]
C --> D["每日班次卡片"]
D --> E{"操作"}
E --> F["查看上一周"]
E --> G["查看下一周"]
E --> H["切换团队视图"]
F --> C
G --> C
H --> I["团队排班表格"]
BDD 场景
场景 2.1: 查看每周排班
Given 员工已登录
And 员工本周被分配了 3 个班次
When 员工点击排班页签
Then 显示本周日程(周一至周日)
And 每天显示班次时间段或"休息日"
And 今天的日期高亮显示
场景 2.2: 切换周次
Given 员工正在查看本周排班
When 员工点击下一周箭头
Then 排班切换到下一周
When 员工点击上一周箭头
Then 排班切换到上一周
测试文件:
integration_test/t05_schedule_view_test.dart (3 个场景)
integration_test/t17_schedule_deep_test.dart (5 个场景)
E-CUJ-3: 登录认证 + PIN 设置 P0
用户流程
flowchart TD
A["启动 App"] --> B["启动页"]
B --> C{"有会话?"}
C -->|"否"| D["登录页"]
C -->|"是"| E{"有 PIN?"}
E -->|"否"| F["PIN 设置页"]
E -->|"是"| G["PIN 输入页"]
D --> H["输入邮箱/密码"]
H --> I["API: POST /auth/employee/login"]
I --> J{"成功?"}
J -->|"是"| K["将 JWT 存入 SecureStorage"]
K --> F
F --> L["创建 4 位 PIN"]
L --> M["确认 PIN"]
M --> N["将 PIN 存入数据库"]
N --> O["跳转到首页"]
G --> P["输入 PIN"]
P --> Q{"PIN 正确?"}
Q -->|"是"| O
Q -->|"否"| R["显示错误"]
BDD 场景
场景 3.1: 首次登录 + PIN 设置
Given 员工从未登录过
When 员工启动 App
Then 显示登录页面
When 员工输入有效的邮箱和密码
And 点击"登录"
Then JWT 令牌存入 SecureStorage
And 显示 PIN 设置页面
When 员工输入 4 位 PIN 并确认
Then PIN 存入数据库
And 员工跳转到首页
场景 3.2: 再次登录 - PIN 验证
Given 员工已设置过 PIN
And 存有有效的 JWT
When 员工启动 App
Then 显示 PIN 输入页面
When 员工输入正确的 PIN
Then 员工直接跳转到首页
测试文件:
integration_test/t01_auth_flow_test.dart (真实后端, 2 个场景)
integration_test/mock/t01_auth_flow_test.dart (Mock API, 2 个场景)
integration_test/mock/t02_pin_setup_test.dart (Mock API, 3 个场景)
E-CUJ-4: 我的服务与预约 P1
用户流程
flowchart TD
A["首页"] --> B["我的服务页签"]
B --> C["服务列表"]
C --> D{"筛选/搜索"}
D --> E["按状态筛选"]
D --> F["按服务名搜索"]
C --> G["点击服务卡片"]
G --> H["服务详情页"]
H --> I{"操作"}
I --> J["查看客户信息"]
I --> K["提交小费"]
I --> L["查看评价"]
K --> M["输入小费金额"]
M --> N["保存小费"]
BDD 场景
场景 4.1: 查看服务列表
Given 员工已登录
And 员工今日有 5 个分配的服务
When 员工点击"我的服务"页签
Then 列表中显示全部 5 个服务
And 每张卡片显示服务名称、客户姓名、时间和状态
场景 4.2: 提交小费
Given 员工正在查看一个已完成服务的详情
When 员工点击"小费"区域
And 输入小费金额 $15.00
And 点击"保存"
Then 小费已记录
And 显示成功提示
测试文件:
integration_test/t04_my_services_test.dart (3 个场景)
integration_test/t13_service_detail_test.dart (4 个场景)
integration_test/t14_review_tip_flow_test.dart (4 个场景)
integration_test/t16_services_filter_test.dart (3 个场景)
E-CUJ-5: 换班与请假申请 P1
用户流程
flowchart TD
A["排班页签"] --> B["换班/请假按钮"]
B --> C["申请列表"]
C --> D{"申请类型"}
D --> E["创建换班申请"]
D --> F["创建请假申请"]
E --> G["选择要换的班次"]
G --> H["选择目标员工"]
H --> I["输入原因"]
I --> J["提交换班申请"]
J --> K["状态: 待处理"]
F --> L["选择日期范围"]
L --> M["输入请假原因"]
M --> N["提交请假申请"]
N --> O["状态: 待审批"]
BDD 场景
场景 5.1: 创建换班申请
Given 员工在周三有一个班次
When 员工导航到 排班 > 换班/请假
And 点击"创建换班申请"
And 选择周三的班次
And 选择一位同事
And 输入原因"需要去看诊"
And 提交申请
Then 换班申请显示为"待处理"状态
场景 5.2: 创建请假申请
Given 员工希望请假
When 员工导航到 排班 > 换班/请假
And 点击"创建请假申请"
And 选择开始日期(12月20日)和结束日期(12月22日)
And 输入原因"家庭旅行"
And 提交申请
Then 请假申请显示为"待审批"状态
测试文件:
integration_test/t08_swap_leave_test.dart (4 个场景)
integration_test/t15_swap_leave_create_test.dart (5 个场景)
E-CUJ-6: 团队聊天与消息 P1
用户流程
flowchart TD
A["首页"] --> B["消息页签"]
B --> C["会话列表"]
C --> D["点击会话"]
D --> E["聊天页 - 实时 WebSocket"]
E --> F{"操作"}
F --> G["发送消息"]
F --> H["查看输入中指示器"]
F --> I["菜单: 静音/退出"]
C --> J["浮动按钮: 新建聊天"]
J --> K["选择成员"]
K --> L["创建单聊或群聊"]
B --> M["公告图标"]
M --> N["公告页面"]
BDD 场景
场景 6.1: 查看会话列表
Given 员工已登录且有现有会话
When 员工点击消息页签
Then 显示带有未读角标的会话列表
And 每个会话显示最后一条消息预览和时间戳
场景 6.2: 在聊天中发送消息
Given 员工在一个聊天会话中
When 员工输入一条消息并点击发送
Then 消息以气泡形式显示在右侧
And 接收方通过 WebSocket 实时收到消息
场景 6.3: 创建新的群聊
Given 员工点击新建聊天按钮
When 员工选择 3 位团队成员
And 输入群组名称"早班团队"
And 输入第一条消息"早上好团队!"
And 点击"创建群聊"
Then 创建一个新的群组会话
And 员工被重定向到聊天页面
场景 6.4: 静音/退出会话
Given 员工在聊天页面中
When 员工点击静音图标
Then 会话被静音(不再收到推送通知)
When 员工从菜单选择"退出会话"
Then 显示确认弹窗
And 确认后,员工被重定向到消息列表
测试文件:
integration_test/t06_messages_chat_test.dart (5 个场景)
integration_test/t11_chat_realtime_test.dart (3 个场景)
E-CUJ-7: 查看公告 P2
用户流程
flowchart TD
A["消息页签"] --> B["公告图标"]
B --> C["公告页面"]
C --> D["带优先级标识的列表"]
D --> E{"优先级"}
E -->|"紧急"| F["红色角标"]
E -->|"重要"| G["黄色角标"]
E -->|"普通"| H["无角标"]
D --> I["点击公告"]
I --> J["底部弹窗: 完整内容"]
J --> K["自动标记为已读"]
C --> L["下拉刷新"]
BDD 场景
场景 7.1: 查看公告列表
Given 管理层已发布 5 条公告(2 条紧急, 3 条普通)
When 员工打开公告页面
Then 显示全部 5 条公告
And 紧急公告显示红色"紧急"角标
And 未读公告标题加粗并带有指示点
场景 7.2: 阅读公告详情
Given 有一条未读公告"排班变更通知"
When 员工点击该公告卡片
Then 底部弹窗显示完整内容
And 公告自动标记为已读
And 未读计数减少 1
测试文件:
integration_test/t09_announcements_test.dart (4 个场景)
integration_test/t19_announcements_deep_test.dart (6 个场景)
E-CUJ-8: 查看报表 — 仅限管理员 P2
注意: 报表页签仅对 manager 及以上角色可见(manager, super_admin, platform_superadmin)
用户流程
flowchart TD
A["报表页签"] --> B{"角色检查"}
B -->|"管理员+"| C["报表类型选择"]
B -->|"普通员工"| D["页签隐藏"]
C --> E["KPI 仪表板"]
C --> F["经营报表"]
C --> G["销售报表"]
C --> H["员工绩效"]
E --> I["报表数据页"]
F --> I
G --> I
H --> I
I --> J["长按复制数据"]
BDD 场景
场景 8.1: 访问报表(管理员)
Given 员工以具备对应权限与范围(scope)的账号登录
When 员工点击报表页签
Then 显示 4 种报表类型: KPI、经营、销售、员工绩效
场景 8.2: 查看 KPI 仪表板
Given 用户已登录并拥有对应功能所需权限与范围(scope),在报表页面
When 用户点击"KPI 仪表板"
Then KPI 数据加载并显示
And 数据显示字段数和条目数
场景 8.3: 普通员工不可见报表
Given 员工以无对应权限的普通账号登录
Then 底部导航栏中不显示报表页签
测试文件:
integration_test/t07_reports_test.dart (6 个场景)
E-CUJ-9: 个人资料与设置 P2
用户流程
flowchart TD
A["个人资料页签"] --> B["设置页面"]
B --> C["个人资料卡片"]
C --> D["头像、姓名、邮箱、角色"]
B --> E{"功能区域"}
E --> F["工作: 考勤记录 / 工资单"]
E --> G["偏好: 通知 / 语言"]
E --> H["关于: 关于 App / 隐私政策"]
E --> I["退出登录"]
G --> J["通知子页面"]
J --> K["渠道开关: Push/邮件/短信"]
K --> L["内容开关: 预约/排班/系统/营销"]
L --> M["注册推送令牌"]
M --> N["保存设置"]
I --> O["确认弹窗"]
O --> P["清除会话令牌"]
P --> Q["跳转到登录页"]
BDD 场景
场景 9.1: 查看个人资料
Given 员工已登录
When 员工点击个人资料页签
Then 资料卡片显示头像、姓名、邮箱和角色标签
场景 9.2: 管理通知偏好
Given 员工在设置页面
When 员工点击"通知"
Then 通知设置页显示渠道开关(Push/邮件/短信)
And 内容偏好开关(预约/排班/系统/营销)
When 员工关闭 Push 通知并保存
Then 设置已持久化
场景 9.3: 退出登录流程
Given 员工在设置页面
When 员工点击"退出登录"
Then 显示确认弹窗
When 员工确认
Then 员工被重定向到登录页面
And 会话令牌已清除
测试文件:
integration_test/t10_settings_profile_test.dart (6 个场景)
integration_test/t18_settings_deep_test.dart (7 个场景)
覆盖率总览
| CUJ |
E2E 测试 |
Widget 测试 |
单元测试 |
状态 |
| E-CUJ-1 每日打卡签到/签退 |
t03 (4), t12 (6) |
3 个 Widget 测试 |
8 个单元测试 |
完整 |
| E-CUJ-2 查看我的排班 |
t05 (3), t17 (5) |
2 个 Widget 测试 |
5 个单元测试 |
完整 |
| E-CUJ-3 登录认证 + PIN 设置 |
t01 (2), mock/t01 (2), mock/t02 (3) |
4 个 Widget 测试 |
12 个单元测试 |
完整 |
| E-CUJ-4 我的服务与预约 |
t04 (3), t13 (4), t14 (4), t16 (3) |
5 个 Widget 测试 |
7 个单元测试 |
完整 |
| E-CUJ-5 换班与请假申请 |
t08 (4), t15 (5) |
3 个 Widget 测试 |
6 个单元测试 |
完整 |
| E-CUJ-6 团队聊天与消息 |
t06 (5), t11 (3) |
4 个 Widget 测试 |
10 个单元测试 |
完整 |
| E-CUJ-7 查看公告 |
t09 (4), t19 (6) |
2 个 Widget 测试 |
4 个单元测试 |
完整 |
| E-CUJ-8 查看报表(仅限管理员) |
t07 (6) |
2 个 Widget 测试 |
3 个单元测试 |
完整 |
| E-CUJ-9 个人资料与设置 |
t10 (6), t18 (7) |
5 个 Widget 测试 |
8 个单元测试 |
完整 |
关键洞察:
- 全部 9 个 CUJ 均具有完整的 E2E 测试覆盖(24 个测试文件中的 37+ 测试场景)
- P0/P1 CUJ 优先获得最深度覆盖(每个 10+ 场景)
- 仅限管理员的功能(E-CUJ-8)包含基于角色的可见性测试
- 实时功能(聊天、公告)通过 WebSocket 集成测试覆盖
- 安全门控(E-CUJ-3)同时包含 Mock 和真实后端测试
- 测试总计: 37+ E2E 场景 + 30+ Widget 测试 + 63+ 单元测试