兩種排課方式:
固定每周的固定時間上課(例:共上20節(jié),每周六、周日早上8點-10點上課。假如今天周六凌晨1點,那么排課也需要從今天開始)總共上幾個周,每周上課時間比較個性化(例:共上三周,第一周周一周二早上8點-10點上課;第二周周三周四下午8點-10點上課;第三周周日中午11點-12點上課。)
第一種排課比較好實現(xiàn),簡要代碼如下:
/**
* 生成日期列表
*
* @param int $startDate 開始日期 時間戳格式
* @param array $timeList 課時計劃列表
[
{
"start_at": "09:09", //開課時間
"end_at": "10:09", //結(jié)束時間
"week_at": 1 //周幾
},
{
"start_at": "12:09", //開課時間
"end_at": "13:09", //結(jié)束時間
"week_at": 1 //周幾
},
{
"start_at": "09:09",
"end_at": "10:09",
"week_at": 5
}
]
* @param int $amount 課時計劃數(shù)量
* @param int $skipHoliday 跳過節(jié)假日
*
* @return array
*/
public function generateDateList($startDate, $timeList, $amount, $skipHoliday = 0)
{
// 計算開始日期是周幾
$startDateWeek = intval(date('N', $startDate));
//規(guī)范化課時數(shù)據(jù) week_at 做key的三維數(shù)組
foreach ($timeList as $item) {
$weekAt = $item['week_at'];
array_splice($item, 0, 0, $weekAt);
$key = array_shift($item);
$weeksTime[$key][] = $item;
$item = null;
}
unset($timeList);
if (empty($weeksTime)) {
$this->addError('課時計劃數(shù)據(jù)為空');
return false;
}
//設(shè)置跳過假期,獲取開始日期之后的節(jié)假日
if ($skipHoliday) {
$holiday = new Holiday();
$holidayData = $holiday->getHolidayList($startDate);
$holiday = null;
unset($holiday);
}
$nowTime = time();
$list = array();
for ($weekStartTime = $startDate, $count = 0; $count $amount; $weekStartTime += 86400 * 7) {
//$currentWeek :周幾
foreach ($weeksTime as $currentWeek => $weekTime) {
foreach ($weekTime as $time) {
//算出對應(yīng)的日期時間戳
$currentDateTime = $weekStartTime + (($startDateWeek = $currentWeek ? ($currentWeek - $startDateWeek) : (7 - $startDateWeek + $currentWeek)) * 86400);
//對應(yīng)的日期 = 開始時間 + ((開始時間對應(yīng)周 = 數(shù)據(jù)對應(yīng)的周幾 ? (數(shù)據(jù)對應(yīng)的周幾 - 開始時間對應(yīng)周) :(7 - 開始時間對應(yīng)周 + 數(shù)據(jù)對應(yīng)的周幾)) * 86400)
//假期跳過排課
if ($skipHoliday !empty($holidayData)) {
$startUnix = $currentDateTime + $time['start_at'] * 3600; //開始時間
$endUnix = $currentDateTime + $time['end_at'] * 3600; //結(jié)束時間
$skip = false;
//選擇跳過節(jié)假日,且節(jié)假日與當(dāng)前課程時間有重疊跳過
foreach ($holidayData as $item) {
if (($item['start_at'] $endUnix $item['end_at'] > $startUnix) || ($item['start_at'] === $startUnix $item['end_at'] === $endUnix)) {
$skip = true;
continue;
}
}
if ($skip) {
continue;
}
}
$currentDate = date('Y/m/d', $currentDateTime);
$startAt = strtotime($currentDate . $time['start_at'] . ':00');
$endAt = strtotime($currentDate . $time['end_at'] . ':00');
if($startAt $nowTime || $endAt $nowTime){
$this->addError('上課時間不能小于當(dāng)前時間');
return false;
}
$list[] = [
'date_at' => $currentDateTime, //日期
'week_at' => $currentWeek, //周幾
'start_at' => $startAt,
'end_at' => $endAt
];
$count++;
if ($count >= $amount) {
break 3;
}
}
}
}
$weeksTime = null;
unset($weeksTime);
return $list;
}
(例子,只用來展示數(shù)據(jù)結(jié)構(gòu))假如總共5節(jié)課時,從6-25日開始排課,每周一、周六上課:
(例子,只用來展示數(shù)據(jù)結(jié)構(gòu))排課結(jié)果為:
第二種排課方式稍微麻煩一點,簡要代碼如下:
/**
* 生成日期列表
*
* @param int $startDate 開始日期 時間戳格式
* @param array $taskList 任務(wù)列表
[
{
"start_at": "09:09", //開始上課時間
"end_at": "10:09", //結(jié)束時間
"week_at": 1, //周幾
"week_number": 1 //第幾周
},
{
"start_at": "09:09",
"end_at": "10:09",
"week_at": 2,
"week_number": 1
},
{
"start_at": "09:09",
"end_at": "10:09",
"week_at": 1,
"week_number": 3
}
]
*
* @return array
*/
public function generateDateList($startDate, $taskList)
{
// 計算開始日期是周幾
$startDateWeek = intval(date('N', $startDate));
$list = [];
$nowTime = time();
$weekSign = $week = 0;
foreach($taskList as $key => $task){
if($task['week_number'] > $weekSign $task['week_number'] != $week){
$weekSign = $task['week_number'] - $week;
}
//計算每條數(shù)據(jù)對應(yīng)的日期 $key == 0:確定第一周第一節(jié)課是在本周還是下一周
if($key == 0 || $task['week_number'] == $week){
if($task['week'] >= $startDateWeek){
$task['date_at'] = $startDate +
(($weekSign - 1) * 7 + ($task['week'] - $startDateWeek)) * 86400;
}else{
$task['date_at'] = $startDate +
(($weekSign) * 7 - ($startDateWeek - $task['week'])) * 86400;
}
}else{
if($task['week'] > $startDateWeek){
$task['date_at'] = $startDate +
(($weekSign) * 7 + ($task['week'] - $startDateWeek)) * 86400;
}else{
$task['date_at'] = $startDate +
(($weekSign) * 7 - ($startDateWeek - $task['week'])) * 86400;
}
}
$startDateWeek = intval(date('N', $task['date_at']));
$week = $task['week_number'];
$startDate = $task['date_at'];
$dateAt = date('Y/m/d', $task['date_at']);
$startAt = strtotime($dateAt . '00:00:00');
if($task['start_at']){
$startAt = strtotime($dateAt . $task['start_at'] . ':00');
}
$endAt = strtotime($dateAt . '23:59:59');
if($task['end_at']){
$endAt = strtotime($dateAt . $task['end_at'] . ':00');
}
if($startAt $nowTime || $endAt $nowTime){
$this->addError('上課時間不能小于當(dāng)前時間');
return false;
}
$task['start_at'] = $startAt;
$task['end_at'] = $endAt;
//生成課時數(shù)據(jù)
$list[] = [
'date_at' => $task['date_at'],
'week_at' => $task['week'],
'start_at' => $startAt,
'end_at' => $endAt
];
}
return $list;
}
(例子,只用來展示數(shù)據(jù)結(jié)構(gòu))排課數(shù)據(jù):
(例子,只用來展示數(shù)據(jù)結(jié)構(gòu)) 排課結(jié)果:
到此這篇關(guān)于PHP實現(xiàn)兩種排課方式的文章就介紹到這了,更多相關(guān)PHP實現(xiàn)排課內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- 詳細分析PHP7與PHP5區(qū)別
- php生成用戶密碼的兩種方式
- php類中static與self的使用區(qū)別淺析
- php如何用PDO操作大數(shù)據(jù)對象
- php使用workman框架實現(xiàn)socket服務(wù)以及連接客戶端