
本文介绍如何基于预定义的最近7个月时间序列,动态向药品配送记录(dispatch)数组中插入 quantity: 0 的占位项,确保最终数组严格按时间顺序包含全部目标月份,解决因数据缺失导致的统计或图表渲染异常问题。
本文介绍如何基于预定义的最近7个月时间序列,动态向药品配送记录(dispatch)数组中插入 `quantity: 0` 的占位项,确保最终数组严格按时间顺序包含全部目标月份,解决因数据缺失导致的统计或图表渲染异常问题。
在药品分发、库存统计或患者用药追踪等业务场景中,常需按连续月份展示每月发放量。但原始 API 响应中的 dispatch 数组往往只包含实际有发货记录的月份,导致时间序列不完整(例如缺少 2022-5),影响前端图表渲染或聚合计算。此时,需将一个标准月份参考列表(如最近7个月)与现有 dispatch 数据比对,并为缺失月份自动插入 {"quantity": 0} 占位对象。
核心逻辑分为三步:
- 遍历标准月份列表(months);
- 检查每个 period 是否已存在于当前患者的 dispatch 数组中;
- 若不存在,则构造新对象并插入,最后按 period 字符串升序重排序,保证时间连续性与可读性。
以下是 PHP 实现代码(兼容 PHP 7.4+,含详细注释):
// 假设 $data 是原始响应 JSON 解码后的对象(stdClass)
// $monthsData 是包含最近7个月信息的 stdClass 对象
foreach ($monthsData->months as $targetMonth) {
foreach ($data->records as &$record) {
// 使用 array_filter 检查是否存在匹配 period 的 dispatch 条目
$existing = array_filter($record->dispatch, function($item) use ($targetMonth) {
return $item->period === $targetMonth->period;
});
// 若未找到匹配项,则插入 quantity=0 的占位记录
if (empty($existing)) {
// 从 period 字符串解析 month 和 year(更健壮,避免 date() 依赖时区)
[$year, $month] = explode('-', $targetMonth->period);
$record->dispatch[] = (object)[
'month' => (int)$month,
'year' => (int)$year,
'quantity'=> 0,
'period' => $targetMonth->period
];
}
}
// 注意:此处需在内层循环外对每个 record 的 dispatch 单独排序
// 否则多次插入可能导致顺序混乱
foreach ($data->records as &$record) {
usort($record->dispatch, function($a, $b) {
return strcmp($a->period, $b->period); // 字典序升序,适用于 YYYY-M 格式
});
}
}✅ 关键注意事项:
- 不要在 foreach 中直接修改被遍历的数组索引:usort() 应在所有插入操作完成后统一执行,否则可能因数组长度变化引发不可预期行为;
- period 字段格式必须严格一致(如 "2022-5" 而非 "2022-05"),否则字符串比对会失败——建议在数据源侧统一格式,或在比对前标准化(如 sprintf('%d-%d', $y, $m));
- 若需支持多患者并发处理,建议封装为独立函数,避免变量污染;
- 生产环境推荐使用 DateTimeImmutable 替代 strtotime() 进行日期解析,提升可维护性与时区安全性。
最终输出的 dispatch 数组将严格按 period 升序排列,且完整覆盖 months 中定义的所有时间段,每个条目均含 month、year、quantity 和 period 四个字段,可直接用于前端时间序列图表或导出报表。

















