如何写一个脚本自动生成排班表

wen 实用脚本 2

本文目录导读:

如何写一个脚本自动生成排班表

  1. 基础排班表生成器
  2. 简易版本(适合快速使用)
  3. 使用说明
  4. 扩展建议

我来帮你创建一个自动生成排班表的Python脚本,以下是一个功能完善的示例:

基础排班表生成器

import pandas as pd
import random
from datetime import datetime, timedelta
from typing import List, Dict
class ShiftScheduler:
    def __init__(self, employees: List[str], shifts: Dict[str, int]):
        """
        初始化排班器
        :param employees: 员工名单
        :param shifts: 班次配置,如 {"早班": 2, "中班": 2, "晚班": 1}
        """
        self.employees = employees
        self.shifts = shifts
        self.schedule = {}
    def generate_monthly_schedule(self, year: int, month: int) -> pd.DataFrame:
        """生成月度排班表"""
        # 获取月份的天数
        start_date = datetime(year, month, 1)
        if month == 12:
            end_date = datetime(year + 1, 1, 1)
        else:
            end_date = datetime(year, month + 1, 1)
        days_in_month = (end_date - start_date).days
        schedule_data = []
        # 为每一天分配班次
        for day in range(1, days_in_month + 1):
            date = datetime(year, month, day)
            daily_schedule = self._generate_daily_schedule(date)
            schedule_data.append(daily_schedule)
        # 创建DataFrame
        df = pd.DataFrame(schedule_data)
        df['日期'] = [f"{month}/{day}" for day in range(1, days_in_month + 1)]
        df['星期'] = [self._get_weekday(datetime(year, month, day)) for day in range(1, days_in_month + 1)]
        return df
    def _generate_daily_schedule(self, date: datetime) -> Dict:
        """生成单日排班"""
        daily = {}
        # 检查是否为周末
        is_weekend = date.weekday() >= 5
        for shift_name, count in self.shifts.items():
            available_employees = self._get_available_employees(date, shift_name)
            if len(available_employees) >= count:
                # 随机选择需要的员工数
                selected = random.sample(available_employees, count)
                daily[shift_name] = ', '.join(selected)
            else:
                # 如果可用员工不足,使用所有可用员工
                daily[shift_name] = ', '.join(available_employees)
        return daily
    def _get_available_employees(self, date: datetime, shift_name: str) -> List[str]:
        """获取可用员工列表"""
        available = []
        for emp in self.employees:
            # 这里可以添加更多约束条件
            # 连续工作不超过X天,同一天不能同时安排多个班次等
            if not self._is_already_scheduled(date, emp, shift_name):
                available.append(emp)
        return available
    def _is_already_scheduled(self, date: datetime, employee: str, shift_name: str) -> bool:
        """检查员工是否已经被安排"""
        # 简化的检查逻辑,实际应用需要更复杂的检查
        try:
            current_date_str = f"{date.month}/{date.day}"
            if current_date_str in self.schedule:
                daily = self.schedule[current_date_str]
                for shift, workers in daily.items():
                    if shift != shift_name and employee in workers:
                        return True
        except:
            pass
        return False
    def _get_weekday(self, date: datetime) -> str:
        """获取星期几的中文名称"""
        weekdays = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
        return weekdays[date.weekday()]
    def save_to_excel(self, df: pd.DataFrame, filename: str):
        """保存为Excel文件"""
        with pd.ExcelWriter(filename, engine='openpyxl') as writer:
            df.to_excel(writer, sheet_name='排班表', index=False)
            # 调整格式
            worksheet = writer.sheets['排班表']
            # 设置列宽
            for column in df.columns:
                column_width = max(len(str(column)) * 2, 15)
                col_idx = df.columns.get_loc(column) + 1
                worksheet.column_dimensions[chr(64 + col_idx)].width = column_width
            # 设置标题行样式
            for cell in worksheet[1]:
                cell.font = pd.io.formats.excel.ExcelFormatter.bold()
                cell.alignment = pd.io.formats.excel.ExcelFormatter.center()
class AdvancedScheduler(ShiftScheduler):
    """高级排班器,包含更多约束条件"""
    def __init__(self, employees, shifts, constraints=None):
        super().__init__(employees, shifts)
        self.constraints = constraints or {}
        self.work_history = {emp: [] for emp in employees}
    def generate_balanced_schedule(self, year: int, month: int) -> pd.DataFrame:
        """生成平衡的排班表,确保工作量公平"""
        # 获取月份的天数
        start_date = datetime(year, month, 1)
        if month == 12:
            end_date = datetime(year + 1, 1, 1)
        else:
            end_date = datetime(year, month + 1, 1)
        days_in_month = (end_date - start_date).days
        schedule_data = []
        # 初始化员工工作量统计
        workload = {emp: 0 for emp in self.employees}
        for day in range(1, days_in_month + 1):
            date = datetime(year, month, day)
            daily_schedule = self._generate_balanced_daily_schedule(date, workload)
            schedule_data.append(daily_schedule)
        df = pd.DataFrame(schedule_data)
        df['日期'] = [f"{month}/{day}" for day in range(1, days_in_month + 1)]
        df['星期'] = [self._get_weekday(datetime(year, month, day)) for day in range(1, days_in_month + 1)]
        return df
    def _generate_balanced_daily_schedule(self, date, workload):
        """生成平衡的单日排班"""
        daily = {}
        is_weekend = date.weekday() >= 5
        # 按工作量排序,工作量少的优先选择
        sorted_employees = sorted(self.employees, key=lambda x: workload[x])
        for shift_name, count in self.shifts.items():
            selected = []
            for emp in sorted_employees:
                if len(selected) >= count:
                    break
                if self._can_work(emp, date, shift_name):
                    selected.append(emp)
                    workload[emp] += 1
            daily[shift_name] = ', '.join(selected) if selected else '无人'
        return daily
    def _can_work(self, employee, date, shift_name):
        """检查员工是否可以工作"""
        # 检查连班限制
        if self.constraints.get('max_consecutive_days'):
            recent_work = self.work_history[employee][-self.constraints['max_consecutive_days']:]
            if len(recent_work) >= self.constraints['max_consecutive_days']:
                if all(day == date - timedelta(days=i) for i, day in enumerate(recent_work)):
                    return False
        # 检查总工作量限制
        if self.constraints.get('max_work_days_per_month'):
            pass  # 将在主方法中处理
        # 更新工作历史
        self.work_history[employee].append(date)
        return True
# 使用示例
def main():
    # 配置参数
    employees = ['张三', '李四', '王五', '赵六', '钱七', '孙八']
    shifts = {
        '早班 (08:00-16:00)': 2,
        '中班 (14:00-22:00)': 2, 
        '晚班 (22:00-08:00)': 1
    }
    # 创建排班器
    scheduler = AdvancedScheduler(
        employees, 
        shifts,
        constraints={
            'max_consecutive_days': 3,  # 最多连续工作3天
            'max_work_days_per_month': 22  # 每月最多工作22天
        }
    )
    # 生成2024年1月的排班表
    schedule_df = scheduler.generate_balanced_schedule(2024, 1)
    # 显示排班表
    print("排班表预览:")
    print(schedule_df.head(10))
    # 保存到Excel
    scheduler.save_to_excel(schedule_df, '排班表_2024年1月.xlsx')
    print("排班表已保存到 '排班表_2024年1月.xlsx'")
if __name__ == "__main__":
    # 安装依赖
    # pip install pandas openpyxl
    # 如果需要生成随机种子来复现结果
    random.seed(42)  # 设置随机种子,确保每次运行结果一致
    main()

简易版本(适合快速使用)

import random
from datetime import datetime, timedelta
def simple_schedule():
    # 基本配置
    employees = ['张三', '李四', '王五', '赵六']
    shifts = ['早班', '中班', '晚班']
    # 获取当前月份的天数
    now = datetime.now()
    days_in_month = 30  # 简化为30天
    # 生成排班表
    schedule = {}
    for day in range(1, days_in_month + 1):
        # 随机分配班次
        random.shuffle(employees)  # 打乱员工顺序
        daily = {
            '早班': employees[0],
            '中班': employees[1], 
            '晚班': employees[2] if len(employees) > 2 else employees[0]
        }
        schedule[day] = daily
    # 输出排班表
    print("简易排班表")
    print("=" * 50)
    for day, shifts in schedule.items():
        print(f"第{day:2d}天 | 早班: {shifts['早班']} | 中班: {shifts['中班']} | 晚班: {shifts['晚班']}")
if __name__ == "__main__":
    simple_schedule()

使用说明

  1. 安装依赖

    pip install pandas openpyxl
  2. 自定义配置

    • 修改 employees 数组为你的员工名单
    • 调整 shifts 字典配置班次和每班所需人数
    • 可选的约束条件如最大连续工作天数
  3. 运行脚本

    python shift_scheduler.py

扩展建议

你可以根据实际需求添加更多功能:

  • 员工偏好设置(如某些员工不能上夜班)
  • 法定节假日特殊安排
  • 输出HTML格式的排班表
  • 自动发送邮件通知
  • 支持Web界面操作

这个脚本可以作为基础模板,根据实际情况进行修改和扩展。

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