【发布时间】:2021-05-14 10:22:17
【问题描述】:
我有一组工作时间,并且想要生成一个建议轮班列表,所有这些都基于当前的“现在”时间并回溯到过去。
例如小时模板:
$templateShifts = collect([
(object)[
"id" => 1,
"from_day" => 1, // mon
"from_time" => "09:00:00",
"until_day" => 1,
"until_time" => "12:00:00",
],
(object)[
"id" => 2,
"from_day" => 1, // mon
"from_time" => "13:00:00",
"until_day" => 1,
"until_time" => "17:00:00",
],
(object)[
"id" => 3,
"from_day" => 2, // tue
"from_time" => "09:00:00",
"until_day" => 2,
"until_time" => "17:00:00",
],
(object)[
"id" => 4,
"from_day" => 4, // thur
"from_time" => "09:00:00",
"until_day" => 4,
"until_time" => "17:00:00",
],
(object)[
"id" => 5,
"from_day" => 5, // fri
"from_time" => "09:00:00",
"until_day" => 5,
"until_time" => "17:00:00",
]
]);
如果今天是星期四(1 月 4 日),它应该以相反的顺序列出日期:
- 周四 09:00 - 17:00(1 月 4 日)
- 周二 09:00 - 17:00(1 月 2 日)
- 周一 13:00 - 17:00(1 月 1 日)
- 周一 09:00 - 12:00(1 月 1 日)
- 周五 09:00 - 17:00(12 月 31 日)
- 周四 09:00 - 17:00(12 月 30 日)
- 等
这段代码感觉很糟糕,但我找不到在不复制代码的情况下重复收集循环的方法。
// Paging
$total_count = 1000;
$on_page = 30;
$page = $request->get('page') ?: 1;
$skip = $on_page * ($page - 1);
// Find closest match in the past from now
$date = now();
$year = $date->year;
$weekNo = $date->weekOfYear;
$shifts = collect();
// Decrement week no
if ($skip) {
$weekNo -= $skip;
// Change year till positive weekNo
while ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo += $date->isoWeeksInYear;
}
}
// First page
if (!$skip) {
// First search for shift today
$firstShiftIndex = $templateShifts->search(function ($item, $key) use ($date) {
return $item->from_day == $date->format('N') && $item->from_time <= $date->format('H:i:s');
});
$currentWeekNo = false;
if ($firstShiftIndex === false) {
// Loop back from today till find a matching day
for ($i = 1; $i <= 7; $i++) {
$date = $date->clone()->subDays(1);
$firstShiftIndex = $templateShifts->search(function ($item, $key) use ($date) {
return $item->from_day == $date->format('N');
});
if ($firstShiftIndex !== false) {
$year = $date->year;
$weekNo = $date->weekOfYear;
break;
}
}
}
$templateShifts->slice($firstShiftIndex)->each(function ($item, $key) use ($shifts, $date, $year, $weekNo) {
$shift_from = $date->clone()->setISODate($year, $weekNo, $item->from_day);
list($hour, $minutes) = explode(':', $item->from_time);
$shift_from->setTime($hour, $minutes);
// Crosses into next week/maybe year too
if ($item->until_day < $item->from_day) {
$weekNo++;
if ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo = $date->isoWeeksInYear;
}
}
$shift_until = $date->clone()->setISODate($year, $weekNo, $item->until_day);
list($hour, $minutes) = explode(':', $item->until_time);
$shift_until->setTime($hour, $minutes);
if ($shift_from->toDateString() == $shift_until->toDateString()) {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('H:i');
} else {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('D H:i');
}
$shifts->push([
'id' => $item->id,
'text' => $name
]);
});
}
//
for($i=0; $i < $on_page; $i++) {
--$weekNo;
if ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo = $date->isoWeeksInYear;
}
$templateShifts->each(function ($item, $key) use ($shifts, $date, $year, $weekNo) {
$shift_from = $date->clone()->setISODate($year, $weekNo, $item->from_day);
list($hour, $minutes) = explode(':', $item->from_time);
$shift_from->setTime($hour, $minutes);
// Crosses into next week/maybe year too
if ($item->until_day < $item->from_day) {
$weekNo++;
if ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo = $date->isoWeeksInYear;
}
}
$shift_until = $date->clone()->setISODate($year, $weekNo, $item->until_day);
list($hour, $minutes) = explode(':', $item->until_time);
$shift_until->setTime($hour, $minutes);
if ($shift_from->toDateString() == $shift_until->toDateString()) {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('H:i');
} else {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('D H:i');
}
$shifts->push([
'id' => $item->id,
'text' => $name
]);
});
}
【问题讨论】:
-
我没看错,这是一个可行的解决方案,而您正在寻求改进?
-
是的,我已经用我的最新编辑更新了问题,我认为它工作正常。
-
如果您只想重构/优化工作代码,Code Review 将是更好的选择。
-
如果这是我,并且 hours 模板对象是轻量级的,我会在一个循环中将
$templateShifts复制到一个巨大的数组中,直到它至少包含$total_count项,然后调用array_sliceat最后确保它的大小正好是$total_count。根据您的样本数据和快速测试,这会占用 35KB 的内存,完全值得。然后你只需应用标准的分页逻辑。如果 hours 模板不是轻量级的,我仍然可能会创建一个 DTO 并这样做,但我也讨厌使用基于日期的逻辑,并且愿意尽可能作弊。