Commit Graph

1 Commits

Author SHA1 Message Date
weicw-dshsa 2ae3710a82 fix: 修复任务奖金为 NULL 导致业绩统计接口空指针
小程序 pages/performance/index 请求的 /yxe-user-task/userRank 与
/yxe-task/data 同时返回 {"code":1,"error":"java.lang.NullPointerException"},
页面完成进度与人员排行榜全部空白。

根因:yxe_task.reward 允许为 NULL,历史数据中存在 NULL 记录(本机库
id=663)。两个接口在累加奖金时写作 BigDecimal.ZERO.add(task.getReward()),
BigDecimal.add(null) 直接抛 NPE。userRank 不传 name 时会遍历全部用户,
任何一人名下有该脏任务,整个排行榜即整体失败。

改动分读、写两侧:

读侧(不再因脏数据报错):
- YxeTaskController#data、#userRank 对 reward 做 null 兜底(nullToZero)
- 顺带把 userTask.getStatus().equals(2) / getLoginUser().getCanAuth().equals(1)
  改为 Integer.valueOf(x).equals(...),避免字段为 NULL 时拆箱再抛 NPE
  (sys_user.can_auth 列本身可空,属同类隐患)
- userRank 过滤 task_id 为 NULL 的用户任务,并去重后批量查任务

写侧(不再产生新的 NULL):
- save / saveBatch 在新增时把缺失的 reward 兜底为 0
- update / updateBatch **刻意不补**,并在代码注释中写明原因:
  二者走 MyBatis-Plus 默认 NOT_NULL 部分更新语义,字段为 null 表示
  “本次不修改该字段”。管理端普通任务的 reward 由产品奖励自动汇总,
  产品行可能为空导致该字段整个缺失;若在此兜底为 0,一次普通编辑
  就会把任务原有奖金静默清零,直接影响用户实得收益。
  该风险已有专门护栏测试 updateMustNotDefaultRewardToZero 覆盖
  (注入错误修法后该测试转红:expected:<null> but was:<0>)。

回归测试 TaskRewardNullSafetyTest 共 8 例,覆盖读侧两接口的 NULL 容忍、
task_id 为 NULL 不阻断排行榜、以及新增侧补默认值、更新侧必须保持 null。
已验证:回退主修后 3 例转红(save/saveBatch/data),update 护栏保持绿色。

业务影响评估(补 0 安全):
- 库中已有 67 条 reward=0 的任务,其中 6 条已完整走通接单→提交→审核→
  income 落库 0.00,说明“奖金为 0”本就是系统接受的正常语义
- 审核结算处 income = reward == null ? ZERO : reward,服务端本就把 NULL 当 0,
  补 0 不改变任何用户实得金额
- 小程序端 12 个源文件逐一排查,无任何依赖 reward 为 null 的分支判断

SQL: fix_task_reward_null_npe_2026-10-11.sql(幂等,本次未执行)
2026-10-11 20:20:03 +08:00