PHP 怎么排班通知

wen PHP项目 3

本文目录导读:

PHP 怎么排班通知

  1. 方案一:简单轮班制(最基础)
  2. 方案二:数据库驱动排班系统
  3. 方案三:高级智能排班(带规则约束)
  4. 方案四:发送通知的完整实现
  5. 使用示例
  6. 推荐使用第三方案例

我来给你介绍几种 PHP 排班通知的实现方案,根据你的需求复杂度来选择:

简单轮班制(最基础)

<?php
class SimpleShiftScheduler {
    private $employees = ['张三', '李四', '王五', '赵六'];
    private $shifts = ['早班', '中班', '晚班'];
    public function generateWeeklySchedule($startDate) {
        $schedule = [];
        $shiftIndex = 0;
        $employeeIndex = 0;
        for ($i = 0; $i < 7; $i++) {
            $date = date('Y-m-d', strtotime("$startDate + $i days"));
            $schedule[$date] = [
                'employee' => $this->employees[$employeeIndex % count($this->employees)],
                'shift' => $this->shifts[$shiftIndex % count($this->shifts)]
            ];
            $shiftIndex++;
            $employeeIndex = (int)($shiftIndex / 2);
        }
        return $schedule;
    }
}

数据库驱动排班系统

<?php
class DatabaseScheduler {
    private $pdo;
    public function __construct($pdo) {
        $this->pdo = $pdo;
    }
    // 生成排班表
    public function generateSchedule($startDate, $endDate, $shiftPattern = [0,1,2,0,1,2]) {
        $sql = "INSERT INTO schedules (employee_id, shift_date, shift_type, created_at) VALUES (?, ?, ?, NOW())";
        $stmt = $this->pdo->prepare($sql);
        $employees = $this->getAvailableEmployees();
        $currentDate = $startDate;
        while ($currentDate <= $endDate) {
            foreach ($employees as $key => $employee) {
                $shiftIndex = date('N', strtotime($currentDate)) - 1;
                $shiftType = $this->getShiftType($employee['id'], $currentDate);
                // 检查是否有请假或不可用
                if (!$this->isEmployeeAvailable($employee['id'], $currentDate)) {
                    continue;
                }
                // 分配班次
                $stmt->execute([
                    $employee['id'],
                    $currentDate,
                    $shiftType
                ]);
            }
            $currentDate = date('Y-m-d', strtotime($currentDate . ' +1 day'));
        }
        return $this->getSchedule($startDate, $endDate);
    }
    // 发送排班通知
    public function sendScheduleNotification($scheduleId) {
        $schedule = $this->getScheduleById($scheduleId);
        if (!$schedule) {
            return ['success' => false, 'message' => '排班记录不存在'];
        }
        // 获取员工联系方式
        $employee = $this->getEmployeeContact($schedule['employee_id']);
        // 发送短信通知
        $smsResult = $this->sendSMSNotification(
            $employee['phone'],
            "您的排班通知:{$schedule['shift_date']} {$schedule['shift_type']},请准时到岗"
        );
        // 发送邮件通知(可选)
        if (!empty($employee['email'])) {
            $this->sendEmailNotification(
                $employee['email'],
                '排班通知',
                $this->formatEmailContent($schedule)
            );
        }
        return ['success' => true];
    }
    // 批量发送通知
    public function sendBulkNotifications($date) {
        $schedules = $this->getSchedulesByDate($date);
        $results = [];
        foreach ($schedules as $schedule) {
            $results[] = [
                'employee' => $schedule['employee_name'],
                'result' => $this->sendScheduleNotification($schedule['id'])
            ];
        }
        return $results;
    }
    private function sendSMSNotification($phone, $message) {
        // 使用短信服务商API,如阿里云、腾讯云等
        $api = new SmsService();
        return $api->send($phone, $message);
    }
    private function sendEmailNotification($email, $subject, $content) {
        // 使用PHP Mailer或第三方邮件服务
        $mail = new PHPMailer();
        $mail->addAddress($email);
        $mail->Subject = $subject;
        $mail->Body = $content;
        return $mail->send();
    }
}

高级智能排班(带规则约束)

<?php
class SmartScheduler {
    private $rules = [];
    private $employeeAvailability = [];
    // 添加排班规则
    public function addRule($ruleName, $callback) {
        $this->rules[$ruleName] = $callback;
    }
    // 设置员工可用时间
    public function setEmployeeAvailability($employeeId, $availability) {
        $this->employeeAvailability[$employeeId] = $availability;
    }
    // 生成最优排班方案
    public function generateOptimalSchedule($startDate, $days, $shiftsPerDay) {
        $schedule = [];
        $allEmployees = $this->getAllEmployees();
        for ($i = 0; $i < $days; $i++) {
            $date = date('Y-m-d', strtotime("$startDate + $i days"));
            $dailySchedule = [];
            for ($shift = 0; $shift < $shiftsPerDay; $shift++) {
                $candidates = $this->findCandidates($date, $shift, $allEmployees);
                if ($candidates) {
                    // 按优先级选择最佳人选
                    $selected = $this->selectBestCandidate($candidates, [
                        'date' => $date,
                        'shift' => $shift,
                        'schedule' => $schedule
                    ]);
                    $dailySchedule[] = [
                        'date' => $date,
                        'shift' => $shift,
                        'employee' => $selected,
                        'status' => 'confirmed'
                    ];
                }
            }
            $schedule[] = $dailySchedule;
        }
        return $schedule;
    }
    private function findCandidates($date, $shift, $employees) {
        $candidates = [];
        foreach ($employees as $employee) {
            // 检查员工是否可用
            if (!$this->isAvailable($employee['id'], $date, $shift)) {
                continue;
            }
            // 检查连续工作天数
            if ($this->hasOverwork($employee['id'], $date)) {
                continue;
            }
            // 计算推荐分数
            $score = $this->calculateScore($employee, $date, $shift);
            $candidates[] = array_merge($employee, ['score' => $score]);
        }
        // 按分数排序
        usort($candidates, function($a, $b) {
            return $b['score'] <=> $a['score'];
        });
        return $candidates;
    }
    private function calculateScore($employee, $date, $shift) {
        $score = 100; // 基础分
        // 根据历史出勤率加分
        $attendanceRate = $this->getAttendanceRate($employee['id']);
        $score += $attendanceRate * 10;
        // 技能匹配加分
        if ($this->hasRequiredSkill($employee['id'], $shift)) {
            $score += 20;
        }
        // 连续工作扣分
        $consecutiveDays = $this->getConsecutiveWorkDays($employee['id']);
        $score -= $consecutiveDays * 5;
        // 加班扣分
        if ($this->isOvertime($employee['id'], $date)) {
            $score -= 15;
        }
        // 员工偏好加分
        $preference = $this->getShiftPreference($employee['id']);
        if ($preference == $shift) {
            $score += 10;
        }
        return $score;
    }
    private function isAvailable($employeeId, $date, $shift) {
        // 检查员工是否被设置为不可用
        if (!isset($this->employeeAvailability[$employeeId])) {
            return true;
        }
        $availability = $this->employeeAvailability[$employeeId];
        $dayOfWeek = date('N', strtotime($date));
        return isset($availability[$dayOfWeek][$shift]) 
            && $availability[$dayOfWeek][$shift] === true;
    }
}

发送通知的完整实现

<?php
class ScheduleNotifier {
    private $scheduleData;
    public function __construct($scheduleData) {
        $this->scheduleData = $scheduleData;
    }
    public function notifyViaMultipleChannels() {
        $notifications = [];
        foreach ($this->scheduleData as $schedule) {
            $channels = $this->getPreferredChannels($schedule['employee_id']);
            foreach ($channels as $channel) {
                $result = $this->sendViaChannel($channel, $schedule);
                $notifications[] = [
                    'employee' => $schedule['employee_name'],
                    'channel' => $channel,
                    'status' => $result ? 'success' : 'failed',
                    'timestamp' => date('Y-m-d H:i:s')
                ];
            }
        }
        return $notifications;
    }
    private function sendViaChannel($channel, $schedule) {
        $message = $this->formatScheduleMessage($schedule);
        switch ($channel) {
            case 'wechat':
                return $this->sendWechatMessage($schedule['wechat_id'], $message);
            case 'sms':
                return $this->sendSMS($schedule['phone'], $message);
            case 'email':
                return $this->sendEmail($schedule['email'], '排班通知', $message);
            case 'app_notification':
                return $this->sendAppNotification($schedule['user_id'], $message);
            default:
                return false;
        }
    }
    private function formatScheduleMessage($schedule) {
        return sprintf(
            "【排班通知】%s\n员工:%s\n班次:%s\n时间:%s-%s\n备注:%s\n请准时到岗,如有问题请提前联系管理人员。",
            $schedule['shift_date'],
            $schedule['employee_name'],
            $schedule['shift_type'],
            $schedule['start_time'],
            $schedule['end_time'],
            $schedule['remarks'] ?? '无'
        );
    }
    // 微信通知(通过企业微信/公众号)
    private function sendWechatMessage($openId, $message) {
        $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
        $data = [
            'touser' => $openId,
            'template_id' => 'YOUR_TEMPLATE_ID',
            'data' => [
                'content' => ['value' => $message]
            ]
        ];
        return $this->curlPost($url, json_encode($data));
    }
    // 手机短信
    private function sendSMS($phone, $message) {
        // 使用阿里云短信或腾讯云短信
        $config = [
            'access_key' => 'YOUR_ACCESS_KEY',
            'secret' => 'YOUR_SECRET',
            'sign_name' => '你的签名',
            'template_code' => 'SMS_12345678'
        ];
        $sms = new AliyunSms();
        return $sms->send($phone, $message, $config);
    }
    // 邮件通知
    private function sendEmail($to, $subject, $content) {
        $mail = new PHPMailer();
        $mail->isSMTP();
        $mail->Host = 'smtp.example.com';
        $mail->SMTPAuth = true;
        $mail->Username = 'your-email@example.com';
        $mail->Password = 'your-password';
        $mail->setFrom('from@example.com', '排班系统');
        $mail->addAddress($to);
        $mail->Subject = $subject;
        $mail->Body = $content;
        return $mail->send();
    }
    // APP推送(使用极光推送等)
    private function sendAppNotification($userId, $message) {
        $jpush = new JPush('app_key', 'master_secret');
        return $jpush->push()
            ->setPlatform('ios', 'android')
            ->addAlias($userId)
            ->setNotificationAlert($message)
            ->send();
    }
}

使用示例

<?php
// 初始化排班系统
$scheduler = new SmartScheduler();
// 设置规则
$scheduler->addRule('max_consecutive_days', function($employeeId) {
    // 最多连续工作5天
    return $this->getConsecutiveWorkDays($employeeId) < 5;
});
// 设置员工可用时间
$scheduler->setEmployeeAvailability(1, [
    1 => [true, true, true],    // 周一所有班次
    2 => [true, false, true],   // 周二中班不排
    // ...
]);
// 生成下周排班
$startDate = date('Y-m-d', strtotime('next Monday'));
$schedule = $scheduler->generateOptimalSchedule($startDate, 7, 3);
// 发送通知
$notifier = new ScheduleNotifier($schedule);
$results = $notifier->notifyViaMultipleChannels();
// 记录日志
foreach ($results as $result) {
    echo "通知 {$result['employee']} 成功,渠道:{$result['channel']}\n";
}

推荐使用第三方案例

如果你不想从零开发,可以查看这些开源项目:

  1. SimpleSchedule - 轻量级排班系统
  2. ShiftScheduler - 支持多种班次类型
  3. SmartRota - 智能排班+通知

需要完整项目代码或者有其他功能需求(比如请假管理、调班申请等),我可以帮你进一步完善!

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