PHP项目轮班规则如何配置循环排班周期规则

wen PHP项目 24

本文目录导读:

PHP项目轮班规则如何配置循环排班周期规则

  1. 基础数据库设计
  2. PHP核心实现类
  3. 常见轮班模式配置示例
  4. 高级功能实现
  5. 数据验证规则
  6. 使用示例

在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";
}

这个方案提供了灵活的循环排班配置,支持多种循环周期(日/周/月/自定义),并包含节假日处理、人员分配等扩展功能。

抱歉,评论功能暂时关闭!