fix(sync): 班级人数与辅导员不再被空值覆盖,人数按名册兜底
开放平台对 2025 级起的班级不返回 BJRS,对 2026 级连 FDYH 都不返回, 而 batchUpsert 用 VALUES() 直写这两列,每晚同步都会把人工补录的辅导员和 学生人数刷成 NULL;新生班级的人数因此一直空着,班级管理页首屏(2026 级) 两列全空。 - ClassInfoMapper.xml: counselor_name / student_count 改为 COALESCE(VALUES(x), x),平台有值仍以平台为准,给空时保留存量 - 新增 refreshStudentCountFromRoster:学生同步结束时按 gxmu_student 全量在册统计(不过滤 status,与平台 BJRS 口径一致)回填人数, 只补「为空或 0」的班级,名册里没学生的班级不动 - StudentSyncHandler: 学生段写完后调用兜底 开发库已用同一语句回填 728 个班级。
This commit is contained in:
@@ -26,4 +26,15 @@ public interface ClassInfoMapper extends BaseMapper<ClassInfo> {
|
||||
*/
|
||||
int batchUpsert(@Param("list") List<ClassInfo> list);
|
||||
|
||||
/**
|
||||
* 按学生名册回填班级人数(学生同步末尾调用)。
|
||||
*
|
||||
* <p>平台 BJRS 对新生班级返回空,只能本地按 {@code gxmu_student.class_id} 统计兜底。
|
||||
* 只补为空或 0 的班级,平台有值时不覆盖。
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @return 更新行数
|
||||
*/
|
||||
int refreshStudentCountFromRoster(@Param("tenantId") int tenantId);
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
ON DUPLICATE KEY UPDATE 里只列「平台权威字段」(docs/adr/0005):
|
||||
sort_number / counselor_phone 属人工维护,同步不触碰;create_time 不重复刷新。
|
||||
幂等键是 uk_gxmu_class_code(tenant_id, class_code)。
|
||||
|
||||
counselor_name / student_count 用 COALESCE 保住存量:平台对 2025 级起的班级
|
||||
不返回 BJRS、对 2026 级连 FDYH 都不返回(实测 2026-09-15 那批 1584 条里
|
||||
2025 级 148 条全无人数、2026 级 152 条两项全空)。若照旧写 VALUES(),
|
||||
每晚同步都会把这些列刷成 NULL,人工补录的辅导员和学生人数也就一并清掉了。
|
||||
平台有值时仍以平台为准,只有平台给空才保留原值。
|
||||
-->
|
||||
<insert id="batchUpsert">
|
||||
INSERT INTO gxmu_class (
|
||||
@@ -26,12 +32,40 @@
|
||||
class_name = VALUES(class_name),
|
||||
college_id = VALUES(college_id),
|
||||
grade_year = VALUES(grade_year),
|
||||
counselor_name = VALUES(counselor_name),
|
||||
student_count = VALUES(student_count),
|
||||
counselor_name = COALESCE(VALUES(counselor_name), counselor_name),
|
||||
student_count = COALESCE(VALUES(student_count), student_count),
|
||||
status = VALUES(status),
|
||||
remark = VALUES(remark),
|
||||
update_time = VALUES(update_time),
|
||||
deleted = VALUES(deleted)
|
||||
</insert>
|
||||
|
||||
<!--
|
||||
按学生名册回填班级人数。
|
||||
|
||||
平台的 BJRS(班级人数) 是教务口径,实测与「本班在册学生数」基本吻合
|
||||
(2020-2024 级逐班比对,平均误差 0.5~2.7 人),但新生班级一律返回空。
|
||||
学生同步写完后用它兜底:只补「为空或 0」的班级,平台有值时不覆盖,
|
||||
名册里查不到学生(s.n 为空)的班级也不动,避免每次同步都刷 update_time。
|
||||
-->
|
||||
<update id="refreshStudentCountFromRoster">
|
||||
UPDATE gxmu_class c
|
||||
LEFT JOIN (
|
||||
SELECT class_id, COUNT(*) AS n
|
||||
FROM gxmu_student
|
||||
WHERE tenant_id = #{tenantId}
|
||||
AND deleted = 0
|
||||
AND class_id IS NOT NULL
|
||||
GROUP BY class_id
|
||||
) s ON s.class_id = c.id
|
||||
SET c.student_count = s.n,
|
||||
c.update_time = NOW()
|
||||
WHERE c.tenant_id = #{tenantId}
|
||||
AND c.deleted = 0
|
||||
AND c.class_code IS NOT NULL
|
||||
AND (c.student_count IS NULL OR c.student_count = 0)
|
||||
AND s.n IS NOT NULL
|
||||
AND s.n > 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -165,6 +165,22 @@ public class SyncSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按学生名册回填班级人数。
|
||||
*
|
||||
* <p>平台的 BJRS 对 2025 级起的班级一律返回空(实测 2025 级 148 个班全空),
|
||||
* 只能拿刚写完的名册按 class_id 统计兜底,否则班级管理页的学生人数永远为空。
|
||||
*
|
||||
* @return 更新行数
|
||||
*/
|
||||
public int refreshClassStudentCounts() {
|
||||
int updated = classInfoMapper.refreshStudentCountFromRoster(OpenplatSyncConstants.TENANT_ID);
|
||||
if (updated > 0) {
|
||||
logger.warn("班级人数回填: 平台未给出人数的 {} 个班级已按学生名册补上", updated);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分批写入部门
|
||||
*/
|
||||
|
||||
@@ -111,6 +111,8 @@ public class StudentSyncHandler {
|
||||
|
||||
int deactivated = support.deactivateMissingStudents(existingHash.keySet(), incoming);
|
||||
result.setSkipCount(deactivated);
|
||||
// 班级同步(本批更早执行)拿到的 BJRS 对新生班级一律为空,这里按刚写完的名册补上
|
||||
support.refreshClassStudentCounts();
|
||||
logger.warn("学生同步完成: 平台 {} 人, 实际写入 {} 行, 未变更跳过 {} 行, 停用 {} 行, 失败 {} 条",
|
||||
merged.size(), changed.size(), merged.size() - changed.size(),
|
||||
deactivated, result.getFailCount());
|
||||
|
||||
Reference in New Issue
Block a user