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) 
相关推荐
我命由我123457 小时前
智能助手通用问答边界
人工智能·python·学习·ai·学习方法·ai编程·智能体
Angeldream1237 小时前
第 4 章 医学影像预处理
图像处理·人工智能·python·医学影像·医学影像处理
Web3&Basketball7 小时前
实测Gemini4Argon:ERQA 87%登顶长程任务榜
数据库·python·大模型·多模态·gemini·长上下文·推理优化
把我格子衫拿来7 小时前
医学影像重采样:spacing 改了,为什么模型位置也跟着错了?
python·dicom·医学影像·simpleitk·重采样
打工仔折腾 AI8 小时前
用 Dashlet 把极空间 NAS 服务入口整理成统一导航首页的实践
java·开发语言·人工智能·后端·python·rpc·ai agent 实战
wuyk5558 小时前
PyQt6-第05讲-QtDesigner工作流与ui文件
python·ui·pyqt
MATLAB代码顾问8 小时前
Simulink PI 参数扫描与批量仿真完整 MATLAB 代码
开发语言·matlab
Want5958 小时前
Python跳动的爱心②
开发语言·python·数学建模
田里的水稻8 小时前
PyTorch_TensorBoard展示
人工智能·pytorch·python·深度学习·神经网络
张张123y8 小时前
后端第九课:部署上线(把你的 FastAPI 后端真正跑起来给别人用)
python·docker·部署·fastapi