本文目录导读:

在PHP项目中配置循环排班周期规则,可以采用以下几种常见的实现方案:
基础数据库设计
轮班规则表 (shift_rules)
CREATE TABLE shift_rules (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) COMMENT '规则名称',
cycle_type ENUM('daily', 'weekly', 'monthly', 'custom') COMMENT '周期类型',
cycle_days INT COMMENT '循环天数',
start_date DATE COMMENT '生效日期',
end_date DATE COMMENT '失效日期',
status TINYINT DEFAULT 1 COMMENT '状态 1:启用 0:禁用',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
轮班明细表 (shift_details)
CREATE TABLE shift_details (
id INT PRIMARY KEY AUTO_INCREMENT,
rule_id INT,
day_number INT COMMENT '第几天(从1开始)',
shift_type ENUM('morning', 'afternoon', 'night', 'rest') COMMENT '班次类型',
start_time TIME,
end_time TIME,
sort_order INT DEFAULT 0,
FOREIGN KEY (rule_id) REFERENCES shift_rules(id)
);
PHP核心实现类
<?php
namespace App\Services;
class CycleShiftService
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
/**
* 获取指定日期范围内的排班
*/
public function getShiftSchedule($ruleId, $startDate, $endDate)
{
$rule = $this->getRule($ruleId);
if (!$rule) {
throw new \Exception('规则不存在');
}
// 获取轮班模式
$pattern = $this->getShiftPattern($ruleId);
// 计算排班
$schedule = [];
$currentDate = new \DateTime($startDate);
$endDateTime = new \DateTime($endDate);
while ($currentDate <= $endDateTime) {
$dayNumber = $this->calculateCycleDayNumber($currentDate, $rule);
$shift = $this->getShiftForDay($pattern, $dayNumber);
$schedule[] = [
'date' => $currentDate->format('Y-m-d'),
'day_of_week' => $currentDate->format('w'),
'shift' => $shift
];
$currentDate->modify('+1 day');
}
return $schedule;
}
/**
* 计算循环天数
*/
private function calculateCycleDayNumber(\DateTime $date, $rule)
{
$startDate = new \DateTime($rule['start_date']);
$interval = $startDate->diff($date);
$totalDays = $interval->days;
if ($rule['cycle_type'] === 'weekly') {
// 每周循环
return ($date->format('w') + 1) % 7 + 1;
} elseif ($rule['cycle_type'] === 'daily') {
// 日循环
return 1;
} else {
// 自定义天数循环
return ($totalDays % $rule['cycle_days']) + 1;
}
}
/**
* 获取某天的班次
*/
private function getShiftForDay($pattern, $dayNumber)
{
foreach ($pattern as $shift) {
if ($shift['day_number'] === $dayNumber) {
return $shift;
}
}
return null;
}
/**
* 获取轮班模式
*/
private function getShiftPattern($ruleId)
{
$stmt = $this->db->prepare(
"SELECT * FROM shift_details WHERE rule_id = ? ORDER BY day_number, sort_order"
);
$stmt->execute([$ruleId]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
/**
* 获取规则
*/
private function getRule($ruleId)
{
$stmt = $this->db->prepare(
"SELECT * FROM shift_rules WHERE id = ? AND status = 1"
);
$stmt->execute([$ruleId]);
return $stmt->fetch(\PDO::FETCH_ASSOC);
}
}
常见轮班模式配置示例
<?php
class ShiftPatternConfig
{
/**
* 三班倒(早中晚)
* 模式:早-中-晚-休
*/
public static function getThreeShiftPattern()
{
return [
['day_number' => 1, 'shift' => 'morning', 'start_time' => '08:00', 'end_time' => '16:00'],
['day_number' => 2, 'shift' => 'afternoon', 'start_time' => '16:00', 'end_time' => '00:00'],
['day_number' => 3, 'shift' => 'night', 'start_time' => '00:00', 'end_time' => '08:00'],
['day_number' => 4, 'shift' => 'rest', 'start_time' => null, 'end_time' => null],
];
}
/**
* 两班倒(白班-夜班-休)
*/
public static function getTwoShiftPattern()
{
return [
['day_number' => 1, 'shift' => 'day', 'start_time' => '08:00', 'end_time' => '20:00'],
['day_number' => 2, 'shift' => 'night', 'start_time' => '20:00', 'end_time' => '08:00'],
['day_number' => 3, 'shift' => 'rest', 'start_time' => null, 'end_time' => null],
];
}
}
高级功能实现
节假日跳过功能
public function skipHolidays($schedule, $holidays)
{
return array_map(function($item) use ($holidays) {
if (isset($holidays[$item['date']])) {
$item['shift'] = 'rest';
$item['is_holiday'] = true;
}
return $item;
}, $schedule);
}
人员轮换分配
public function assignStaffToShift($schedule, $staffList, $shiftRule)
{
$assignments = [];
$currentStaffIndex = 0;
foreach ($schedule as $day) {
if ($day['shift'] === 'rest') {
continue;
}
$staff = $staffList[$currentStaffIndex % count($staffList)];
$assignments[] = [
'date' => $day['date'],
'shift' => $day['shift'],
'staff_id' => $staff['id'],
'staff_name' => $staff['name']
];
$currentStaffIndex++;
}
return $assignments;
}
数据验证规则
public function validateShiftRule($data)
{
$rules = [
'name' => 'required|string|max:100',
'cycle_type' => 'required|in:daily,weekly,monthly,custom',
'cycle_days' => 'required_if:cycle_type,custom|integer|min:1|max:365',
'start_date' => 'required|date',
'pattern' => 'required|array|min:1'
];
// 验证调换模式完整性
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
return ['error' => $validator->errors()];
}
return ['success' => true];
}
使用示例
// 初始化服务
$shiftService = new CycleShiftService($db);
// 创建轮班规则
$ruleId = 1;
$startDate = '2024-01-01';
$endDate = '2024-01-31';
// 获取排班表
$schedule = $shiftService->getShiftSchedule($ruleId, $startDate, $endDate);
// 跳过节假日
$holidays = ['2024-01-01' => '元旦', '2024-02-10' => '春节'];
$schedule = $shiftService->skipHolidays($schedule, $holidays);
// 打印排班表
foreach ($schedule as $day) {
echo "{$day['date']} - {$day['shift']}\n";
}
这个方案提供了灵活的循环排班配置,支持多种循环周期(日/周/月/自定义),并包含节假日处理、人员分配等扩展功能。