文档分析:记录考勤统计口径与待确认业务定义

This commit is contained in:
wangzhibiao committed 2026-09-21 21:44:03 +08:00
1 parent 330a7ab1f8
commit b716e55ac7
2 files changed
+73 -1

No files matched your search

+2 -1
View File
@@ -29,6 +29,7 @@
1. **学员档案批量导入模版**:确认标准 Excel 表头字段口径与必填项;
2. **现场报到主交互设备**:确认是一期现场电脑人工点击确认,还是外接读卡器或扫码枪;
3. **住宿分配颗粒度**:确认一期排宿精确到具体房间号,还是必须精确到固定床位编号;
4. **学员请假与门禁权限保留策略**:确认请假期间是否保留宿舍进出权限(当前系统默认策略:保留进门权限)。
4. **学员请假与门禁权限保留策略**:确认请假期间是否保留宿舍进出权限(当前系统默认策略:保留进门权限);
5. **考勤统计口径与分母待确认项**:确认请假是否计入出勤率分母、请假是否计入异常排行、待报到学员应到课次起算规则等(详见 [考勤统计语义与指标口径规范](07-analytics-attendance-semantics.md))。
👉 详细确认清单请查阅:[甲方需求确认清单 (P0/P1/P2)](../requirements/甲方需求确认清单.md)。
@@ -0,0 +1,71 @@
# 07. 考勤统计语义与指标口径规范 (Attendance Analytics Semantics)
> **版本**:V1.0 (Package C 闭环基线)
> **更新日期**:2026-09-21
> **适用模块**:管理驾驶舱 (Dashboard)、考勤专题分析 (Attendance Analytics)、学员 360 画像 (Student360)、考勤异常 Top 10
> **核心原则**:统一底层 Expected Attendance Universe 聚合语义,严格隔离未来课次,严格区分缺勤与未签到,技术语义守恒闭环。
---
## 1. 冻结技术语义 (Frozen Technical Semantics)
| 技术语义项 | 规范定义 | 技术落地点 | 解决问题 |
| :--- | :--- | :--- | :--- |
| **已开始课次 (Started Lesson)** | `lesson.start_time <= CURRENT_TIMESTAMP`<br>未来课次打卡记录严格隔离,不得进入任何当前历史统计。 | `TrainAnalysisMapper.xml` 所有考勤聚合统一条件 `l.start_time <= CURRENT_TIMESTAMP` | **C07 关闭**:消除 Dashboard 状态分布泄漏 46 条未来课次打卡记录缺陷。 |
| **应到基准集 (Expected Attendance Universe)** | `STARTED_LESSONS × PLAN_COURSES × ELIGIBLE_ENROLLMENTS LEFT JOIN CHECKIN`<br>由计划已开课次与计划参训学员关系形成应到基准,不得由打卡流水作为驱动表。 | 共享查询基准 `expectedAttendanceBase` / `filteredAttendanceConditions` | **C08 关闭**:消除异常 Top 10 仅从打卡流水统计导致未打卡学员不可见缺陷。 |
| **显式缺勤 vs 未签到** | - **显式缺勤 (Explicit Absence)**:打卡流水存在且 `attendance_status = 0`。<br>- **未签到 (No Checkin)**:无打卡流水行(`checkin_id IS NULL`)。<br>两者在状态分布、Top 10、学员画像中严格互斥,不得隐式混淆。 | 状态派生:`CASE WHEN c.checkin_id IS NULL THEN 'NO_CHECKIN' ELSE CAST(c.attendance_status AS VARCHAR) END` | 杜绝将无流水学员擅自改写为 status=0,客观反映教务未核验状态。 |
| **趋势时间轴 (Trend Time Axis)** | 每日考勤打卡走势时间轴必须锚定 `lesson.start_time`,严禁锚定 `sign_in_time`。<br>确保正常、迟到、早退、请假、明确缺勤、未签到均落入课次排课日期。 | `TO_CHAR(l.start_time, 'YYYY-MM-DD') AS stat_date` 统一分组 | **C06 关闭**:消除因 `sign_in_time IS NULL` 导致缺勤/请假/未签到无法进入走势的缺陷。 |
| **状态分布守恒律** | `EXPECTED_PERSON_TIMES = NORMAL + LATE + EARLY + LEAVE + EXPLICIT_ABSENCE + NO_CHECKIN` | Dashboard 与 Attendance 共享 `buildStatusDistribution` | 全局与专题分析在无筛选或相同筛选条件下统计口径严格 1:1 相等。 |
| **走势守恒律** | 筛选范围内各日期走势累加 `SUM(normal_count + abnormal_count)` 严格等于该范围内的 `EXPECTED_PERSON_TIMES`。 | `selectFilteredDailyTrend` | 走势无漏项、无未来虚假漂移。 |
---
## 2. 待确认业务定义清单 (Business Definitions Pending Confirmation)
以下规则由于缺乏业务需求权威定论或底层数据表时序字段支撑,代码中均以策略开关或明确常量集中隔离,**严禁作为已定案的最终甲方规则**:
### 2.1 PENDING-01: 待报到参训学员的应到基准 (`WAITING_ENROLLMENT_EXPECTED_POLICY`)
- **状态**:`BUSINESS_DEFINITION_REQUIRED`
- **问题说明**:学员参训记录为 `status=0`(待报到)且无报到核验流水时,是否从该培训班开班的第一节课起就计入应到基准分母。
- **当前处理**:V1 默认不以 `EXISTS(train_class_report)` 过滤应到集合,确保未到场报到人员可进入缺勤/未签到统计;待甲方确认是否仅针对开班前已完成报名审核的名单起算。
### 2.2 PENDING-02: 考勤请假是否计入出勤率分母 (`LEAVE_DENOMINATOR_POLICY`)
- **状态**:`BUSINESS_DEFINITION_REQUIRED`
- **问题说明**:学员在某课次拥有 `attendance_status=4`(请假)流水时,该人次是否从出勤率分母(应到人次)中扣除,还是保留在分母但计为非正常出勤。
- **当前处理**:当前系统出勤率公式为 `正常出勤人次 / 应到总人次`(请假保留在分母,但非正常)。页面与 API 返回均携带 `metricDefinitionNotice = BUSINESS_METRIC_DEFINITION_PENDING_CONFIRMATION` 声明。
### 2.3 PENDING-03: 放弃参训学员的历史课次有效性 (`ABANDON_HISTORICAL_POLICY`)
- **状态**:`BUSINESS_DEFINITION_REQUIRED`
- **问题说明**:学员参训状态为 `status=3`(放弃)时,由于 `train_enrollment` 表无状态变更生效时间区间(`HISTORICAL_ENROLLMENT_ELIGIBILITY_EXACT = NO`),无法精准切分放弃前与放弃后的课次。
- **当前处理**:当前统计按所属计划完整名单统计,不利用当前最终状态逆向重写历史;待建立学员流转审计历史表后重构精确时间切片。
### 2.4 PENDING-04: 请假是否计入考勤异常排行 (`LEAVE_COUNTS_AS_ABNORMAL`)
- **状态**:`BUSINESS_DEFINITION_PENDING_CONFIRMATION`
- **问题说明**:请假属于审批合规事项,部分管理制度认为请假不属于“违规异常考勤”,不应计入 Top 10 预警排行榜。
- **当前处理**:集中在 `TrainAnalysisServiceImpl.LEAVE_COUNTS_AS_ABNORMAL_DEFAULT = true`(当前预览保持系统现有计入异常口径),并通过 `AttendanceFilterDto.includeLeaveAsAbnormal` 支持单点无缝切换,未散落硬编码。
---
## 3. 跨模块考勤统计语义对齐矩阵
| 功能界面 / API | 基础驱动集 | 正常出勤 | 异常考勤构成 | 未签到 (无打卡) | 未来课次防护 |
| :--- | :--- | :---: | :--- | :---: | :---: |
| **管理驾驶舱 状态分布**<br>`/train/analysis/dashboard/charts` | 已开始课次 × 班级学员 | 正常出勤 (`1`) | 迟到(`2`)、早退(`3`)、请假(`4`)、缺勤(`0`) | 未签到 (`NO_CHECKIN`) | 隔离(0 泄漏) |
| **管理驾驶舱 30天走势**<br>`/train/analysis/dashboard/charts` | 已开始课次 × 班级学员 | 正常人次 (`1`) | 异常人次 (`0,2,3,4,NO_CHECKIN`) | 计入异常人次 | 隔离(0 泄漏) |
| **考勤专题 状态构成**<br>`/train/analysis/attendance/charts` | 已开始课次 × 班级学员 | 正常出勤 (`1`) | 迟到(`2`)、早退(`3`)、请假(`4`)、缺勤(`0`) | 未签到 (`NO_CHECKIN`) | 隔离(0 泄漏) |
| **考勤专题 每日趋势**<br>`/train/analysis/attendance/charts` | 已开始课次 × 班级学员 | 正常人次 (`1`) | 异常人次 (`0,2,3,4,NO_CHECKIN`) | 计入异常人次 | 隔离(0 泄漏) |
| **考勤异常 Top 10**<br>`/train/analysis/attendance/charts` | 已开始课次 × 班级学员 | 不参与排行 | 缺勤(`absentCount`)、迟到(`lateCount`)、早退(`earlyLeaveCount`)、请假(`leaveCount`) | 未签到 (`noCheckinCount`) | 隔离(0 泄漏) |
| **学员 360 画像 考勤卡片**<br>`/train/analysis/portrait/student-360/{id}` | 该学员所属计划已开始课次 | 正常出勤 (`normalCount`) | 迟到、早退、请假、明确缺勤 | 未签到 (`noCheckinCount`) | 隔离(0 泄漏) |
---
## 4. 数据库只读验证事实 (Kingbase QA Live Snapshot)
在 `railwaysystem_integrated_qa_20260916` 数据库实例上的只读验证结果:
- 课次总数:118,其中已开始课次:1(Lesson 90),未来课次:117。
- 考勤打卡记录总数:77,其中已开始课次打卡:31,未来课次打卡:46。
- 已开始课次应到人次:31,打卡匹配人次:31,未签到人次:0。
- 31 人次考勤分布:正常 31,迟到 0,早退 0,请假 0,缺勤 0,未签到 0。
- 守恒断言:`EXPECTED_PERSON_TIMES (31) = NORMAL (31) + ABNORMAL (0)`,`PASS`。
- 未来打卡泄漏:`FUTURE_LESSON_ANALYTICS_LEAK_COUNT = 0`,`PASS`。
- `DUPLICATE_CHECKIN_KEY_COUNT = 0`,无重复打卡键。