Python pyqt+flask做一个简单实用的自动排班系统

这是一个基于Flask和PyQt的排班系统,可以将Web界面嵌入到桌面应用程序中。

系统界面:

功能特点:

  • 读取员工信息和现有排班表

  • 自动生成排班表

  • 美观的Web界面

  • 独立的桌面应用程序

整体架构:

系统采用前后端分离的架构设计,通过 PyQt5 的 WebEngine 组件将 Web 界面嵌入到桌面应用中。

├── 桌面应用层 (PyQt5)

│ └── WebEngine 视图

├── Web 层 (Flask)

│ ├── 路由控制

│ └── 业务逻辑

└── 数据层

├── CSV 数据文件

└── Excel 导出

核心模块:

主程序模块 (main.py)

  • 负责初始化 PyQt5 应用
  • 集成 Flask 服务器
  • 管理主窗口和 Web 视图

后端服务模块 (app.py)

  • 提供 RESTful API
  • 处理排班算法
  • 管理数据导入导出

前端界面模块 (templates/index.html)

  • 员工列表管理
  • 排班表显示
  • 用户交互处理

核心代码:main.py

python 复制代码
import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
from flask import Flask
import threading
import os

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("排班系统")
        self.setGeometry(100, 100, 1200, 800)
        
        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        
        # 创建Web视图
        self.web_view = QWebEngineView()
        layout.addWidget(self.web_view)
        
        # 启动Flask服务器
        self.start_flask_server()
        
        # 等待服务器启动后加载页面
        time.sleep(1)  # 给服务器一点启动时间
        self.web_view.setUrl(QUrl("http://127.0.0.1:3863"))
        
    def start_flask_server(self):
        # 在新线程中启动Flask服务器
        threading.Thread(target=self.run_flask, daemon=True).start()
        
    def run_flask(self):
        from app import app
        app.run(host='127.0.0.1', port=3863)

def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main() 

核心代码:app.py

python 复制代码
from flask import Flask, render_template, request, jsonify, send_file
import pandas as pd
from datetime import datetime, timedelta
import calendar
import json
import numpy as np
import os

app = Flask(__name__)

# 班次定义
SHIFTS = {
    '白班': 'D',
    '晚班': 'N',
    '休息': 'R'
}

# 读取员工数据
def load_employee_data():
    try:
        df = pd.read_csv('Employee.csv', encoding='utf-8')
        # 只返回员工姓名列
        return pd.DataFrame({'name': df["Employee'sName"]})
    except Exception as e:
        print(f"Error loading employee data: {e}")
        return pd.DataFrame({'name': []})

# 读取排班表
def load_schedule():
    try:
        df = pd.read_excel('客户服务部排班表20250301-20250331.xls')
        return df
    except Exception as e:
        print(f"Error loading schedule: {e}")
        return pd.DataFrame()

def get_month_calendar(year, month):
    cal = calendar.monthcalendar(year, month)
    return cal

def generate_monthly_schedule(employees, year, month):
    num_days = calendar.monthrange(year, month)[1]
    num_employees = len(employees)
    
    # 将employees列表转换为numpy数组
    employees_array = np.array(employees)
    
    # 创建排班表
    schedule = pd.DataFrame(index=employees, columns=range(1, num_days + 1))
    schedule.fillna('R', inplace=True)  # 默认全部休息
    
    # 为每一天分配班次
    for day in range(1, num_days + 1):
        # 确保每天有足够的白班和晚班
        day_employees = employees_array.copy()
        np.random.shuffle(day_employees)
        
        # 分配白班(约40%的员工)
        day_shifts = int(num_employees * 0.4)
        schedule.loc[day_employees[:day_shifts], day] = 'D'
        
        # 分配晚班(约30%的员工)
        night_shifts = int(num_employees * 0.3)
        schedule.loc[day_employees[day_shifts:day_shifts+night_shifts], day] = 'N'
    
    # 确保每周至少休息两天
    for employee in employees:
        for week in range(0, num_days, 7):
            week_schedule = schedule.loc[employee, week+1:min(week+7, num_days)]
            rest_days = (week_schedule == 'R').sum()
            if rest_days < 2:
                work_days = list(week_schedule[week_schedule != 'R'].index)
                if work_days:  # 确保有工作日可以调整
                    np.random.shuffle(work_days)
                    for i in range(min(2-rest_days, len(work_days))):
                        schedule.loc[employee, work_days[i]] = 'R'
    
    return schedule

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/api/employees')
def get_employees():
    df = load_employee_data()
    return jsonify(df.to_dict('records'))

@app.route('/api/calendar/<int:year>/<int:month>')
def get_calendar(year, month):
    cal = get_month_calendar(year, month)
    return jsonify(cal)

@app.route('/api/generate_schedule', methods=['POST'])
def generate_schedule():
    try:
        data = request.get_json()
        year = data.get('year', 2025)
        month = data.get('month', 1)
        selected_employees = data.get('employees', [])
        
        if not selected_employees:
            return jsonify({"status": "error", "message": "请选择员工"})
            
        schedule = generate_monthly_schedule(selected_employees, year, month)
        
        # 将DataFrame转换为字典格式
        schedule_dict = {}
        for employee in selected_employees:
            schedule_dict[employee] = schedule.loc[employee].to_dict()
            
        return jsonify({
            "status": "success",
            "schedule": schedule_dict,
            "message": "排班表生成成功"
        })
    except Exception as e:
        return jsonify({"status": "error", "message": str(e)})

@app.route('/api/export_schedule', methods=['POST'])
def export_schedule():
    try:
        data = request.get_json()
        year = data.get('year', 2025)
        month = data.get('month', 1)
        schedule_data = data.get('schedule', {})
        
        # 创建新的排班表
        df = pd.DataFrame.from_dict(schedule_data, orient='index')
        
        # 设置列名为日期
        df.columns = [str(i) for i in range(1, len(df.columns) + 1)]
        
        # 重置索引,将员工名称作为一列
        df.reset_index(inplace=True)
        df.rename(columns={'index': '姓名'}, inplace=True)
        
        # 保存文件
        output_file = f'客户服务部排班表{year}{month:02d}01-{year}{month:02d}{calendar.monthrange(year, month)[1]}.xlsx'
        
        # 使用 openpyxl 引擎保存为 xlsx 格式
        df.to_excel(output_file, index=False, engine='openpyxl')
        
        # 返回文件下载路径
        return send_file(
            output_file,
            as_attachment=True,
            download_name=output_file,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
    except Exception as e:
        print(f"Export error: {str(e)}")  # 添加错误日志
        return jsonify({"status": "error", "message": f"导出失败: {str(e)}"})

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=3863, debug=True) 
相关推荐
立志成为大牛的小牛1 小时前
数据结构——二十六、邻接表(王道408)
开发语言·数据结构·c++·学习·程序人生
祈祷苍天赐我java之术1 小时前
Redis 数据类型与使用场景
java·开发语言·前端·redis·分布式·spring·bootstrap
Gitpchy1 小时前
Day 20 奇异值SVD分解
python·机器学习
MediaTea2 小时前
Python 第三方库:matplotlib(科学绘图与数据可视化)
开发语言·python·信息可视化·matplotlib
草莓熊Lotso2 小时前
C++ 方向 Web 自动化测试入门指南:从概念到 Selenium 实战
前端·c++·python·selenium
JS.Huang2 小时前
【JavaScript】原生函数
开发语言·javascript·ecmascript
我是李武涯2 小时前
PyTorch Dataloader工作原理 之 default collate_fn操作
pytorch·python·深度学习
CoderCodingNo3 小时前
【GESP】C++五级考试大纲知识点梳理, (5) 算法复杂度估算(多项式、对数)
开发语言·c++·算法
Kratzdisteln3 小时前
【Python】绘制椭圆眼睛跟随鼠标交互算法配图详解
python·数学·numpy·pillow·matplotlib·仿射变换
maxruan3 小时前
PyTorch学习
人工智能·pytorch·python·学习