Files
hzdyjs/docs/问题解决方案/学生考核申请ID精度丢失修复报告.md
T
2025-08-21 16:24:34 +08:00

7.2 KiB

学生考核申请ID精度丢失修复报告

问题描述

错误现象

在学生考核申请界面保存时,ID等字段丢失精度,导致存到数据库都为 1958180338534527000,后几位都是 000。

问题分析

  1. 根本原因: JavaScript 大整数精度丢失问题

    • JavaScript 的 Number.MAX_SAFE_INTEGER 为 9007199254740991
    • 雪花ID通常超过这个范围,导致精度丢失
    • 使用 parseInt() 转换大整数字符串时,超出安全范围的数字会被截断
  2. 问题位置: safeConvertId 函数

    • 原函数使用 parseInt() 将字符串ID转换为数字
    • 对于大整数(如雪花ID),转换后精度丢失
  3. 影响范围: 所有ID字段

    • id: 主键ID
    • studentId: 学生ID
    • collegeId: 学院ID
    • majorId: 专业ID
    • classId: 班级ID
    • scheduleId: 考核计划ID

修复方案

1. 修复 safeConvertId 函数

文件: web/src/views/xskh/assessmentApplication/AssessmentApplicationForm.vue

修复前:

const safeConvertId = (id: string | number | undefined): number | undefined => {
  if (id === undefined || id === null) return undefined;
  if (typeof id === 'number') return id;
  if (typeof id === 'string') {
    // 对于大整数,使用parseInt而不是Number,并检查是否超出安全范围
    const num = parseInt(id, 10);
    if (isNaN(num)) return undefined;
    // 检查是否超出JavaScript安全整数范围
    if (num > Number.MAX_SAFE_INTEGER) {
      console.warn('ID超出JavaScript安全整数范围,可能导致精度丢失:', id);
    }
    return num;
  }
  return undefined;
};

修复后:

const safeConvertId = (id: string | number | undefined): string | undefined => {
  if (id === undefined || id === null) return undefined;
  // 始终将ID转换为字符串,避免JavaScript大整数精度丢失
  return String(id);
};

2. 修复要点

2.1 类型安全

  • 返回类型: 从 number | undefined 改为 string | undefined
  • 处理逻辑: 始终使用 String() 转换,保持原始精度
  • 兼容性: 后端API支持 string | number 类型,无需修改

2.2 精度保持

  • 字符串转换: 使用 String() 而不是 parseInt()
  • 精度完整: 保持雪花ID的完整精度
  • 无截断: 避免大整数被截断为 000

2.3 项目一致性

  • 标准做法: 与项目中其他模块的处理方式保持一致
  • 最佳实践: 参考项目中已有的成功案例

技术原理

JavaScript 大整数精度问题

1. 安全整数范围

Number.MAX_SAFE_INTEGER = 9007199254740991  // 2^53 - 1
Number.MIN_SAFE_INTEGER = -9007199254740991 // -(2^53 - 1)

2. 雪花ID特点

  • 长度: 通常为19位数字
  • 范围: 远超JavaScript安全整数范围
  • 精度: 需要保持完整精度

3. 转换对比

// 错误的转换方式(精度丢失)
const bigId = "1958180338534527123";
const wrongResult = parseInt(bigId); // 1958180338534527000 (精度丢失)

// 正确的转换方式(保持精度)
const correctResult = String(bigId); // "1958180338534527123" (完整精度)

后端支持

1. API接口支持

// 所有ID参数都支持 string | number 类型
export function getAssessmentApplication(id: string | number) {
  return request({
    url: '/assessment/application/' + id,
    method: 'get'
  });
}

2. 类型定义支持

export interface XskhAssessmentApplicationApprovalBo {
  id?: string | number;
  studentId?: string | number;
  collegeId?: string | number;
  majorId?: string | number;
  classId?: string | number;
  scheduleId?: string | number;
  // ... 其他字段
}

3. 后端处理

  • Spring Boot: 自动处理字符串到Long的转换
  • MyBatis-Plus: 支持字符串类型的ID参数
  • 数据库: bigint类型可以正确处理字符串输入

验证测试

1. 功能测试

1.1 新增申请测试

  • 测试步骤:
    1. 打开学生考核申请界面
    2. 选择考核计划
    3. 填写申请信息
    4. 点击保存
  • 预期结果: ID字段保持完整精度,数据库记录正确

1.2 编辑申请测试

  • 测试步骤:
    1. 打开已有申请记录
    2. 修改申请信息
    3. 点击保存
  • 预期结果: ID字段保持完整精度,更新成功

1.3 提交申请测试

  • 测试步骤:
    1. 打开申请记录
    2. 点击提交
  • 预期结果: ID字段保持完整精度,提交成功

2. 数据验证

2.1 前端数据验证

// 验证ID精度
const testId = "1958180338534527123";
const convertedId = safeConvertId(testId);
console.log('转换前:', testId);
console.log('转换后:', convertedId);
console.log('精度保持:', testId === convertedId); // 应该为 true

2.2 后端数据验证

-- 查询保存的记录,验证ID精度
SELECT id, student_id, college_id, major_id, class_id, schedule_id 
FROM xskh_assessment_application_approval 
WHERE id = '1958180338534527123';

3. 边界测试

3.1 大整数测试

  • 测试数据: 19位雪花ID
  • 预期结果: 完整精度保持

3.2 小整数测试

  • 测试数据: 普通整数ID
  • 预期结果: 正常转换

3.3 空值测试

  • 测试数据: undefined, null
  • 预期结果: 返回 undefined

影响范围

1. 直接影响

  • ✅ 学生考核申请模块: 修复完成
  • ✅ ID精度保持: 所有ID字段完整精度
  • ✅ 数据一致性: 前后端数据一致

2. 间接影响

  • ✅ API接口: 无需修改,已支持字符串类型
  • ✅ 数据库: 无需修改,bigint类型支持字符串输入
  • ✅ 其他模块: 无影响

3. 兼容性

  • ✅ 向后兼容: 不影响现有功能
  • ✅ 向前兼容: 支持新的ID格式
  • ✅ 跨平台: 所有平台一致

最佳实践总结

1. 大整数处理原则

// ✅ 正确做法:保持字符串类型
const safeConvertId = (id: string | number | undefined): string | undefined => {
  if (id === undefined || id === null) return undefined;
  return String(id);
};

// ❌ 错误做法:转换为数字类型
const wrongConvertId = (id: string | number | undefined): number | undefined => {
  return parseInt(String(id), 10); // 可能导致精度丢失
};

2. 项目统一规范

  • ID字段: 始终使用 string | number 类型
  • 转换函数: 保持字符串格式,避免数字转换
  • API接口: 支持字符串类型参数
  • 类型定义: 明确定义支持的类型

3. 测试验证

  • 功能测试: 验证保存、编辑、提交功能
  • 数据验证: 检查数据库记录精度
  • 边界测试: 测试各种ID格式
  • 兼容性测试: 确保向后兼容

总结

通过本次修复,成功解决了学生考核申请界面ID精度丢失的问题:

  1. 问题根除: 修复了JavaScript大整数精度丢失的根本原因
  2. 精度保持: 所有ID字段现在保持完整精度
  3. 数据一致: 前后端数据完全一致
  4. 标准统一: 与项目其他模块的处理方式保持一致
  5. 向后兼容: 不影响现有功能和数据

修复方案简单有效,符合项目的最佳实践,为后续类似问题提供了标准解决方案。