# 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`
未来课次打卡记录严格隔离,不得进入任何当前历史统计。 | `TrainAnalysisMapper.xml` 所有考勤聚合统一条件 `l.start_time <= CURRENT_TIMESTAMP` | **C07 关闭**:消除 Dashboard 状态分布泄漏 46 条未来课次打卡记录缺陷。 | | **应到基准集 (Expected Attendance Universe)** | `STARTED_LESSONS × PLAN_COURSES × ELIGIBLE_ENROLLMENTS LEFT JOIN CHECKIN`
由计划已开课次与计划参训学员关系形成应到基准,不得由打卡流水作为驱动表。 | 共享查询基准 `expectedAttendanceBase` / `filteredAttendanceConditions` | **C08 关闭**:消除异常 Top 10 仅从打卡流水统计导致未打卡学员不可见缺陷。 | | **显式缺勤 vs 未签到** | - **显式缺勤 (Explicit Absence)**:打卡流水存在且 `attendance_status = 0`。
- **未签到 (No Checkin)**:无打卡流水行(`checkin_id IS NULL`)。
两者在状态分布、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`。
确保正常、迟到、早退、请假、明确缺勤、未签到均落入课次排课日期。 | `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 | 基础驱动集 | 正常出勤 | 异常考勤构成 | 未签到 (无打卡) | 未来课次防护 | | :--- | :--- | :---: | :--- | :---: | :---: | | **管理驾驶舱 状态分布**
`/train/analysis/dashboard/charts` | 已开始课次 × 班级学员 | 正常出勤 (`1`) | 迟到(`2`)、早退(`3`)、请假(`4`)、缺勤(`0`) | 未签到 (`NO_CHECKIN`) | 隔离(0 泄漏) | | **管理驾驶舱 30天走势**
`/train/analysis/dashboard/charts` | 已开始课次 × 班级学员 | 正常人次 (`1`) | 异常人次 (`0,2,3,4,NO_CHECKIN`) | 计入异常人次 | 隔离(0 泄漏) | | **考勤专题 状态构成**
`/train/analysis/attendance/charts` | 已开始课次 × 班级学员 | 正常出勤 (`1`) | 迟到(`2`)、早退(`3`)、请假(`4`)、缺勤(`0`) | 未签到 (`NO_CHECKIN`) | 隔离(0 泄漏) | | **考勤专题 每日趋势**
`/train/analysis/attendance/charts` | 已开始课次 × 班级学员 | 正常人次 (`1`) | 异常人次 (`0,2,3,4,NO_CHECKIN`) | 计入异常人次 | 隔离(0 泄漏) | | **考勤异常 Top 10**
`/train/analysis/attendance/charts` | 已开始课次 × 班级学员 | 不参与排行 | 缺勤(`absentCount`)、迟到(`lateCount`)、早退(`earlyLeaveCount`)、请假(`leaveCount`) | 未签到 (`noCheckinCount`) | 隔离(0 泄漏) | | **学员 360 画像 考勤卡片**
`/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`,无重复打卡键。