1.系统概述
本研究开发了一套基于Python编程语言构建的控制台员工管理系统。该系统遵循面向对象编程(Object-Oriented Programming, OOP)的设计原则,实现了员工信息的全面管理功能。具体而言,系统支持员工信息的增删改查等操作。同时,该系统具备数据持久化能力,能够将员工信息长期存储于本地文件或数据库中,从而保障数据的安全性与稳定性,便于用户随时进行信息调用和管理。通过该系统,企业能够有效地实现员工信息的集中化管理与维护,进而提高人力资源管理的效率。
2.功能特点
1.员工信息管理(添加、删除、修改、查询)
2.多种查询方式(按ID、按姓名、按部门)
3.数据持久化(使用JSON文件存储)
4.简单的用户界面
import json
import os
class Employee:
"""员工类"""
def __init__(self, emp_id, name, department, position, salary):
self.emp_id = emp_id
self.name = name
self.department = department
self.position = position
self.salary = salary
def __str__(self):
return f"ID: {self.emp_id}, 姓名: {self.name}, 部门: {self.department}, 职位: {self.position}, 薪资: {self.salary}"
class EmployeeManagementSystem:
"""员工管理系统"""
def __init__(self, data_file='employees.json'):
self.data_file = data_file
self.employees = []
self.load_data()
def load_data(self):
"""加载员工数据"""
if os.path.exists(self.data_file):
with open(self.data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.employees = [Employee(**emp) for emp in data]
def save_data(self):
"""保存员工数据"""
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump([emp.__dict__ for emp in self.employees], f, ensure_ascii=False, indent=2)
def add_employee(self):
"""添加员工"""
print("\n--- 添加员工 ---")
emp_id = input("请输入员工ID: ")
# 检查ID是否已存在
if any(emp.emp_id == emp_id for emp in self.employees):
print("错误: 该ID已存在!")
return
name = input("请输入姓名: ")
department = input("请输入部门: ")
position = input("请输入职位: ")
salary = input("请输入薪资: ")
try:
salary = float(salary)
except ValueError:
print("错误: 薪资必须是数字!")
return
new_emp = Employee(emp_id, name, department, position, salary)
self.employees.append(new_emp)
self.save_data()
print(f"员工 {name} 添加成功!")
def delete_employee(self):
"""删除员工"""
print("\n--- 删除员工 ---")
emp_id = input("请输入要删除的员工ID: ")
for i, emp in enumerate(self.employees):
if emp.emp_id == emp_id:
self.employees.pop(i)
self.save_data()
print(f"员工 {emp.name} 已删除!")
return
print("错误: 未找到该员工!")
def update_employee(self):
"""修改员工信息"""
print("\n--- 修改员工信息 ---")
emp_id = input("请输入要修改的员工ID: ")
for emp in self.employees:
if emp.emp_id == emp_id:
print("当前信息:")
print(emp)
name = input(f"请输入新姓名 ({emp.name}): ") or emp.name
department = input(f"请输入新部门 ({emp.department}): ") or emp.department
position = input(f"请输入新职位 ({emp.position}): ") or emp.position
salary = input(f"请输入新薪资 ({emp.salary}): ") or emp.salary
try:
salary = float(salary)
except ValueError:
print("错误: 薪资必须是数字!")
return
emp.name = name
emp.department = department
emp.position = position
emp.salary = salary
self.save_data()
print("员工信息更新成功!")
return
print("错误: 未找到该员工!")
def query_employee(self):
"""查询员工信息"""
print("\n--- 查询员工 ---")
print("1. 按ID查询")
print("2. 按姓名查询")
print("3. 按部门查询")
print("4. 显示所有员工")
choice = input("请选择查询方式: ")
if choice == '1':
emp_id = input("请输入员工ID: ")
found = [emp for emp in self.employees if emp.emp_id == emp_id]
elif choice == '2':
name = input("请输入员工姓名: ")
found = [emp for emp in self.employees if name.lower() in emp.name.lower()]
elif choice == '3':
department = input("请输入部门名称: ")
found = [emp for emp in self.employees if department.lower() in emp.department.lower()]
elif choice == '4':
found = self.employees
else:
print("无效选择!")
return
if not found:
print("未找到匹配的员工!")
else:
print("\n查询结果:")
for emp in found:
print(emp)
def show_menu(self):
"""显示菜单"""
while True:
print("\n=== 员工管理系统 ===")
print("1. 添加员工")
print("2. 删除员工")
print("3. 修改员工信息")
print("4. 查询员工信息")
print("5. 退出系统")
choice = input("请选择操作: ")
if choice == '1':
self.add_employee()
elif choice == '2':
self.delete_employee()
elif choice == '3':
self.update_employee()
elif choice == '4':
self.query_employee()
elif choice == '5':
print("感谢使用员工管理系统!")
break
else:
print("无效选择,请重新输入!")
# 启动系统
if __name__ == "__main__":
system = EmployeeManagementSystem()
system.show_menu()
3.使用说明
1.将代码保存为employee_management.py
2.运行程序: python employee_management.py
3.按照菜单提示进行操作
4.扩展建议
1.员工考勤管理功能扩展代码
下面是为员工管理系统添加考勤管理功能的扩展代码,该扩展代码涵盖了多个关键功能模块,包括但不限于考勤记录的详细录入与更新、考勤数据的综合统计与分析,以及考勤信息的便捷查询与展示功能。通过这些功能模块的集成,系统能够更加全面地管理和监控员工的考勤情况,从而提升企业的人力资源管理效率和准确性。
import datetime
from collections import defaultdict
class Attendance:
"""考勤记录类"""
def __init__(self, emp_id, date, check_in=None, check_out=None, status="正常"):
self.emp_id = emp_id
self.date = date # 格式: YYYY-MM-DD
self.check_in = check_in # 格式: HH:MM
self.check_out = check_out
self.status = status # 正常/迟到/早退/缺勤
def __str__(self):
return f"员工ID: {self.emp_id}, 日期: {self.date}, 上班: {self.check_in}, 下班: {self.check_out}, 状态: {self.status}"
class EmployeeManagementSystemWithAttendance(EmployeeManagementSystem):
"""带考勤功能的员工管理系统"""
def __init__(self, data_file='employees.json', attendance_file='attendance.json'):
super().__init__(data_file)
self.attendance_file = attendance_file
self.attendance_records = []
self.load_attendance_data()
def load_attendance_data(self):
"""加载考勤数据"""
if os.path.exists(self.attendance_file):
with open(self.attendance_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.attendance_records = [Attendance(**record) for record in data]
def save_attendance_data(self):
"""保存考勤数据"""
with open(self.attendance_file, 'w', encoding='utf-8') as f:
json.dump([record.__dict__ for record in self.attendance_records], f, ensure_ascii=False, indent=2)
def record_check_in(self):
"""记录上班打卡"""
emp_id = input("请输入员工ID: ")
# 验证员工是否存在
if not any(emp.emp_id == emp_id for emp in self.employees):
print("错误: 员工不存在!")
return
today = datetime.date.today().strftime("%Y-%m-%d")
current_time = datetime.datetime.now().strftime("%H:%M")
# 检查是否已打卡
for record in self.attendance_records:
if record.emp_id == emp_id and record.date == today:
if record.check_in:
print("错误: 该员工今天已打卡!")
return
record.check_in = current_time
# 判断是否迟到(假设9:00前不算迟到)
if current_time > "09:00":
record.status = "迟到"
self.save_attendance_data()
print(f"员工 {emp_id} 上班打卡成功! 时间: {current_time}")
return
# 如果没有当天记录,创建新记录
new_record = Attendance(emp_id, today, check_in=current_time)
if current_time > "09:00":
new_record.status = "迟到"
self.attendance_records.append(new_record)
self.save_attendance_data()
print(f"员工 {emp_id} 上班打卡成功! 时间: {current_time}")
def record_check_out(self):
"""记录下班打卡"""
emp_id = input("请输入员工ID: ")
# 验证员工是否存在
if not any(emp.emp_id == emp_id for emp in self.employees):
print("错误: 员工不存在!")
return
today = datetime.date.today().strftime("%Y-%m-%d")
current_time = datetime.datetime.now().strftime("%H:%M")
# 查找当天记录
for record in self.attendance_records:
if record.emp_id == emp_id and record.date == today:
if record.check_out:
print("错误: 该员工今天已下班打卡!")
return
record.check_out = current_time
# 判断是否早退(假设18:00前下班算早退)
if current_time < "18:00":
if record.status == "迟到":
record.status = "迟到+早退"
else:
record.status = "早退"
self.save_attendance_data()
print(f"员工 {emp_id} 下班打卡成功! 时间: {current_time}")
return
# 如果没有当天记录,创建新记录(视为缺勤上午)
new_record = Attendance(emp_id, today, check_out=current_time, status="缺勤(上午)")
if current_time < "18:00":
new_record.status += "+早退"
self.attendance_records.append(new_record)
self.save_attendance_data()
print(f"员工 {emp_id} 下班打卡成功! 时间: {current_time}")
def query_attendance(self):
"""查询考勤记录"""
print("\n--- 考勤查询 ---")
print("1. 按员工查询")
print("2. 按日期查询")
print("3. 按状态查询")
print("4. 显示所有考勤记录")
choice = input("请选择查询方式: ")
if choice == '1':
emp_id = input("请输入员工ID: ")
found = [record for record in self.attendance_records if record.emp_id == emp_id]
elif choice == '2':
date = input("请输入日期(YYYY-MM-DD): ")
found = [record for record in self.attendance_records if record.date == date]
elif choice == '3':
status = input("请输入状态(正常/迟到/早退/缺勤): ")
found = [record for record in self.attendance_records if status in record.status]
elif choice == '4':
found = self.attendance_records
else:
print("无效选择!")
return
if not found:
print("未找到匹配的考勤记录!")
else:
print("\n考勤记录:")
for record in found:
print(record)
def attendance_statistics(self):
"""考勤统计"""
print("\n--- 考勤统计 ---")
print("1. 员工月度考勤统计")
print("2. 部门考勤统计")
print("3. 公司整体考勤统计")
choice = input("请选择统计方式: ")
if choice == '1':
emp_id = input("请输入员工ID: ")
month = input("请输入月份(YYYY-MM): ")
records = [r for r in self.attendance_records
if r.emp_id == emp_id and r.date.startswith(month)]
if not records:
print("该员工本月无考勤记录!")
return
stats = defaultdict(int)
for record in records:
stats[record.status] += 1
print(f"\n员工 {emp_id} {month} 考勤统计:")
for status, count in stats.items():
print(f"{status}: {count}次")
print(f"总计: {len(records)}天")
elif choice == '2':
department = input("请输入部门名称: ")
month = input("请输入月份(YYYY-MM): ")
# 获取部门所有员工ID
emp_ids = [emp.emp_id for emp in self.employees
if emp.department == department]
if not emp_ids:
print("该部门无员工!")
return
records = [r for r in self.attendance_records
if r.emp_id in emp_ids and r.date.startswith(month)]
if not records:
print("该部门本月无考勤记录!")
return
stats = defaultdict(int)
for record in records:
stats[record.status] += 1
print(f"\n{department}部门 {month} 考勤统计:")
for status, count in sorted(stats.items()):
print(f"{status}: {count}次")
print(f"总计: {len(records)}人次")
elif choice == '3':
month = input("请输入月份(YYYY-MM): ")
records = [r for r in self.attendance_records
if r.date.startswith(month)]
if not records:
print("本月无考勤记录!")
return
stats = defaultdict(int)
for record in records:
stats[record.status] += 1
print(f"\n公司整体 {month} 考勤统计:")
for status, count in sorted(stats.items()):
print(f"{status}: {count}次")
print(f"总计: {len(records)}人次")
else:
print("无效选择!")
def show_menu(self):
"""显示扩展菜单"""
while True:
print("\n=== 员工管理系统(带考勤功能) ===")
print("1. 员工信息管理")
print("2. 考勤管理")
print("3. 退出系统")
main_choice = input("请选择主菜单: ")
if main_choice == '1':
super().show_menu()
elif main_choice == '2':
print("\n--- 考勤管理 ---")
print("1. 上班打卡")
print("2. 下班打卡")
print("3. 考勤查询")
print("4. 考勤统计")
sub_choice = input("请选择操作: ")
if sub_choice == '1':
self.record_check_in()
elif sub_choice == '2':
self.record_check_out()
elif sub_choice == '3':
self.query_attendance()
elif sub_choice == '4':
self.attendance_statistics()
else:
print("无效选择!")
elif main_choice == '3':
print("感谢使用员工管理系统!")
break
else:
print("无效选择,请重新输入!")
# 启动带考勤功能的系统
if __name__ == "__main__":
system = EmployeeManagementSystemWithAttendance()
system.show_menu()
员工管理系统数据统计分析功能扩展
下面是为员工管理系统精心添加的一系列数据统计分析功能,这些功能涵盖了多个关键领域,旨在全面提升管理效率和决策精准度。具体而言,包括了对员工结构进行深入细致的分析,以便更好地了解企业的人力资源配置情况;对薪资数据进行全面系统的分析,帮助管理层掌握薪酬分布和成本控制;以及对考勤数据进行综合多维的分析,从而准确评估员工的工作状态和出勤情况,为优化管理策略提供有力支持。
class EmployeeManagementSystemWithStats(EmployeeManagementSystemWithAttendance):
"""带统计分析功能的员工管理系统"""
def show_statistics_menu(self):
"""显示统计分析菜单"""
while True:
print("\n=== 数据统计分析 ===")
print("1. 员工结构分析")
print("2. 薪资分析")
print("3. 考勤综合分析")
print("4. 返回主菜单")
choice = input("请选择分析类型: ")
if choice == '1':
self.employee_structure_analysis()
elif choice == '2':
self.salary_analysis()
elif choice == '3':
self.attendance_comprehensive_analysis()
elif choice == '4':
break
else:
print("无效选择!")
def employee_structure_analysis(self):
"""员工结构分析"""
print("\n--- 员工结构分析 ---")
# 部门分布
dept_dist = defaultdict(int)
for emp in self.employees:
dept_dist[emp.department] += 1
print("\n按部门分布:")
for dept, count in sorted(dept_dist.items()):
print(f"{dept}: {count}人 ({count/len(self.employees):.1%})")
# 职位分布
position_dist = defaultdict(int)
for emp in self.employees:
position_dist[emp.position] += 1
print("\n按职位分布:")
for position, count in sorted(position_dist.items()):
print(f"{position}: {count}人")
# 年龄结构(假设从ID中提取年龄)
age_groups = {"20-29":0, "30-39":0, "40-49":0, "50+":0}
for emp in self.employees:
birth_year = int(emp.emp_id[:2]) # 假设ID前两位是出生年份
age = datetime.datetime.now().year - (1900 + birth_year)
if 20 <= age < 30:
age_groups["20-29"] += 1
elif 30 <= age < 40:
age_groups["30-39"] += 1
elif 40 <= age < 50:
age_groups["40-49"] += 1
else:
age_groups["50+"] += 1
print("\n按年龄分布:")
for group, count in age_groups.items():
print(f"{group}岁: {count}人")
def salary_analysis(self):
"""薪资分析"""
if not self.employees:
print("没有员工数据!")
return
print("\n--- 薪资分析 ---")
salaries = [emp.salary for emp in self.employees]
avg_salary = sum(salaries) / len(salaries)
max_salary = max(salaries)
min_salary = min(salaries)
print(f"\n整体薪资情况:")
print(f"平均薪资: {avg_salary:.2f}元")
print(f"最高薪资: {max_salary:.2f}元")
print(f"最低薪资: {min_salary:.2f}元")
# 部门薪资分析
dept_salaries = defaultdict(list)
for emp in self.employees:
dept_salaries[emp.department].append(emp.salary)
print("\n各部门薪资情况:")
for dept, sal_list in sorted(dept_salaries.items()):
avg = sum(sal_list) / len(sal_list)
print(f"{dept}: 平均{avg:.2f}元 (人数:{len(sal_list)})")
# 薪资区间分布
ranges = [(0,5000), (5000,10000), (10000,15000),
(15000,20000), (20000,30000), (30000,float('inf'))]
range_names = ["5k以下", "5k-10k", "10k-15k", "15k-20k", "20k-30k", "30k以上"]
salary_dist = [0] * len(ranges)
for salary in salaries:
for i, (low, high) in enumerate(ranges):
if low <= salary < high:
salary_dist[i] += 1
break
print("\n薪资区间分布:")
for name, count in zip(range_names, salary_dist):
print(f"{name}: {count}人")
def attendance_comprehensive_analysis(self):
"""考勤综合分析"""
if not self.attendance_records:
print("没有考勤数据!")
return
print("\n--- 考勤综合分析 ---")
# 总体考勤情况
status_dist = defaultdict(int)
for record in self.attendance_records:
status_dist[record.status] += 1
total_records = len(self.attendance_records)
print("\n整体考勤情况:")
for status, count in sorted(status_dist.items()):
print(f"{status}: {count}次 ({count/total_records:.1%})")
# 月度趋势分析
month_records = defaultdict(list)
for record in self.attendance_records:
month = record.date[:7] # 提取年月
month_records[month].append(record)
print("\n月度考勤趋势:")
for month, records in sorted(month_records.items()):
late_count = sum(1 for r in records if "迟到" in r.status)
leave_early = sum(1 for r in records if "早退" in r.status)
absent = sum(1 for r in records if "缺勤" in r.status)
print(f"{month}: 迟到{late_count}次, 早退{leave_early}次, 缺勤{absent}次")
# 部门考勤对比
dept_stats = defaultdict(lambda: defaultdict(int))
emp_dept = {emp.emp_id: emp.department for emp in self.employees}
for record in self.attendance_records:
if record.emp_id in emp_dept:
dept = emp_dept[record.emp_id]
dept_stats[dept]["total"] += 1
if "迟到" in record.status:
dept_stats[dept]["late"] += 1
if "早退" in record.status:
dept_stats[dept]["leave_early"] += 1
if "缺勤" in record.status:
dept_stats[dept]["absent"] += 1
print("\n各部门考勤对比:")
for dept, stats in sorted(dept_stats.items()):
total = stats["total"]
print(f"{dept}部门:")
print(f" 迟到率: {stats['late']/total:.1%}")
print(f" 早退率: {stats['leave_early']/total:.1%}")
print(f" 缺勤率: {stats['absent']/total:.1%}")
def show_menu(self):
"""显示完整菜单"""
while True:
print("\n=== 员工管理系统(完整版) ===")
print("1. 员工信息管理")
print("2. 考勤管理")
print("3. 数据统计分析")
print("4. 退出系统")
main_choice = input("请选择主菜单: ")
if main_choice == '1':
super().show_menu()
elif main_choice == '2':
# 调用父类的考勤管理菜单
super(EmployeeManagementSystemWithAttendance, self).show_menu()
elif main_choice == '3':
self.show_statistics_menu()
elif main_choice == '4':
print("感谢使用员工管理系统!")
break
else:
print("无效选择,请重新输入!")
# 启动带统计分析功能的系统
if __name__ == "__main__":
system = EmployeeManagementSystemWithStats()
system.show_menu()
员工管理系统GUI版本 (基于Tkinter)
下面是一个利用Python的标准库Tkinter所开发的图形用户界面(GUI)版本的员工管理系统。该系统不仅涵盖了全面的员工管理功能,还集成了详尽的考勤管理模块,能够高效地处理员工的各项信息及考勤记录,确保企业人力资源管理的规范化和便捷化。
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
from datetime import datetime
import json
import os
class EmployeeGUISystem:
def __init__(self, root):
self.root = root
self.root.title("员工管理系统 GUI版")
self.root.geometry("1000x700")
# 数据文件
self.emp_file = "employees_gui.json"
self.att_file = "attendance_gui.json"
# 加载数据
self.employees = self.load_data(self.emp_file)
self.attendance = self.load_data(self.att_file)
# 创建主界面
self.create_main_interface()
# 默认显示员工管理标签页
self.show_employee_tab()
def load_data(self, filename):
"""加载JSON数据"""
if os.path.exists(filename):
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_data(self, data, filename):
"""保存数据到JSON文件"""
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def create_main_interface(self):
"""创建主界面"""
# 顶部菜单栏
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
# 文件菜单
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="导出数据", command=self.export_data)
file_menu.add_separator()
file_menu.add_command(label="退出", command=self.root.quit)
menubar.add_cascade(label="文件", menu=file_menu)
# 标签页控件
self.tab_control = ttk.Notebook(self.root)
# 创建各个标签页
self.employee_tab = ttk.Frame(self.tab_control)
self.attendance_tab = ttk.Frame(self.tab_control)
self.stats_tab = ttk.Frame(self.tab_control)
self.tab_control.add(self.employee_tab, text='员工管理')
self.tab_control.add(self.attendance_tab, text='考勤管理')
self.tab_control.add(self.stats_tab, text='统计分析')
self.tab_control.pack(expand=1, fill="both")
# 绑定标签页切换事件
self.tab_control.bind("<<NotebookTabChanged>>", self.on_tab_changed)
def on_tab_changed(self, event):
"""标签页切换事件处理"""
selected_tab = event.widget.tab('current')['text']
if selected_tab == "员工管理":
self.show_employee_tab()
elif selected_tab == "考勤管理":
self.show_attendance_tab()
elif selected_tab == "统计分析":
self.show_stats_tab()
def show_employee_tab(self):
"""显示员工管理标签页"""
# 清除旧内容
for widget in self.employee_tab.winfo_children():
widget.destroy()
# 顶部按钮区域
btn_frame = ttk.Frame(self.employee_tab)
btn_frame.pack(pady=10)
ttk.Button(btn_frame, text="添加员工", command=self.add_employee_dialog).grid(row=0, column=0, padx=5)
ttk.Button(btn_frame, text="编辑员工", command=self.edit_employee_dialog).grid(row=0, column=1, padx=5)
ttk.Button(btn_frame, text="删除员工", command=self.delete_employee).grid(row=0, column=2, padx=5)
ttk.Button(btn_frame, text="刷新列表", command=self.show_employee_tab).grid(row=0, column=3, padx=5)
# 搜索区域
search_frame = ttk.Frame(self.employee_tab)
search_frame.pack(pady=5)
ttk.Label(search_frame, text="搜索:").grid(row=0, column=0)
self.emp_search_var = tk.StringVar()
ttk.Entry(search_frame, textvariable=self.emp_search_var, width=30).grid(row=0, column=1, padx=5)
ttk.Button(search_frame, text="搜索", command=self.search_employees).grid(row=0, column=2)
ttk.Button(search_frame, text="重置", command=self.reset_search).grid(row=0, column=3)
# 员工表格
columns = ("ID", "姓名", "部门", "职位", "薪资")
self.employee_tree = ttk.Treeview(
self.employee_tab, columns=columns, show="headings", height=20
)
# 设置列属性
col_widths = [80, 120, 150, 150, 100]
for col, width in zip(columns, col_widths):
self.employee_tree.heading(col, text=col)
self.employee_tree.column(col, width=width, anchor='center')
self.employee_tree.pack(fill="both", expand=True)
# 添加滚动条
scrollbar = ttk.Scrollbar(self.employee_tree, orient="vertical", command=self.employee_tree.yview)
self.employee_tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
# 填充数据
self.populate_employee_tree()
def populate_employee_tree(self, employees=None):
"""填充员工表格数据"""
# 清空现有数据
for item in self.employee_tree.get_children():
self.employee_tree.delete(item)
# 显示所有员工或过滤后的员工
employees_to_show = employees if employees else self.employees
for emp in employees_to_show:
self.employee_tree.insert("", "end", values=(
emp.get("emp_id", ""),
emp.get("name", ""),
emp.get("department", ""),
emp.get("position", ""),
f"{emp.get('salary', 0):.2f}"
))
def search_employees(self):
"""搜索员工"""
keyword = self.emp_search_var.get().lower()
if not keyword:
self.populate_employee_tree()
return
filtered = [
emp for emp in self.employees
if (keyword in emp.get("name", "").lower() or
keyword in emp.get("department", "").lower() or
keyword in emp.get("position", "").lower() or
keyword in emp.get("emp_id", "").lower())
]
self.populate_employee_tree(filtered)
def reset_search(self):
"""重置搜索"""
self.emp_search_var.set("")
self.populate_employee_tree()
def add_employee_dialog(self):
"""添加员工对话框"""
dialog = tk.Toplevel(self.root)
dialog.title("添加新员工")
dialog.geometry("400x300")
dialog.resizable(False, False)
# 表单字段
ttk.Label(dialog, text="员工ID:").grid(row=0, column=0, padx=10, pady=5, sticky="e")
emp_id_entry = ttk.Entry(dialog)
emp_id_entry.grid(row=0, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="姓名:").grid(row=1, column=0, padx=10, pady=5, sticky="e")
name_entry = ttk.Entry(dialog)
name_entry.grid(row=1, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="部门:").grid(row=2, column=0, padx=10, pady=5, sticky="e")
dept_entry = ttk.Entry(dialog)
dept_entry.grid(row=2, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="职位:").grid(row=3, column=0, padx=10, pady=5, sticky="e")
position_entry = ttk.Entry(dialog)
position_entry.grid(row=3, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="薪资:").grid(row=4, column=0, padx=10, pady=5, sticky="e")
salary_entry = ttk.Entry(dialog)
salary_entry.grid(row=4, column=1, padx=10, pady=5, sticky="w")
def save_employee():
"""保存员工信息"""
emp_id = emp_id_entry.get()
name = name_entry.get()
department = dept_entry.get()
position = position_entry.get()
try:
salary = float(salary_entry.get())
except ValueError:
messagebox.showerror("错误", "薪资必须是数字")
return
# 验证ID是否已存在
if any(emp["emp_id"] == emp_id for emp in self.employees):
messagebox.showerror("错误", "该员工ID已存在")
return
# 添加新员工
new_emp = {
"emp_id": emp_id,
"name": name,
"department": department,
"position": position,
"salary": salary
}
self.employees.append(new_emp)
self.save_data(self.employees, self.emp_file)
messagebox.showinfo("成功", "员工添加成功")
dialog.destroy()
self.show_employee_tab()
# 按钮区域
btn_frame = ttk.Frame(dialog)
btn_frame.grid(row=5, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="保存", command=save_employee).pack(side="left", padx=10)
ttk.Button(btn_frame, text="取消", command=dialog.destroy).pack(side="left", padx=10)
def edit_employee_dialog(self):
"""编辑员工对话框"""
selected = self.employee_tree.selection()
if not selected:
messagebox.showwarning("警告", "请先选择要编辑的员工")
return
# 获取选中员工的数据
item = self.employee_tree.item(selected[0])
emp_id = item['values'][0]
# 查找员工完整信息
employee = next((emp for emp in self.employees if emp["emp_id"] == emp_id), None)
if not employee:
messagebox.showerror("错误", "未找到该员工")
return
dialog = tk.Toplevel(self.root)
dialog.title("编辑员工信息")
dialog.geometry("400x300")
dialog.resizable(False, False)
# 表单字段(带原始数据)
ttk.Label(dialog, text="员工ID:").grid(row=0, column=0, padx=10, pady=5, sticky="e")
emp_id_label = ttk.Label(dialog, text=employee["emp_id"])
emp_id_label.grid(row=0, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="姓名:").grid(row=1, column=0, padx=10, pady=5, sticky="e")
name_entry = ttk.Entry(dialog)
name_entry.insert(0, employee["name"])
name_entry.grid(row=1, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="部门:").grid(row=2, column=0, padx=10, pady=5, sticky="e")
dept_entry = ttk.Entry(dialog)
dept_entry.insert(0, employee["department"])
dept_entry.grid(row=2, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="职位:").grid(row=3, column=0, padx=10, pady=5, sticky="e")
position_entry = ttk.Entry(dialog)
position_entry.insert(0, employee["position"])
position_entry.grid(row=3, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="薪资:").grid(row=4, column=0, padx=10, pady=5, sticky="e")
salary_entry = ttk.Entry(dialog)
salary_entry.insert(0, str(employee["salary"]))
salary_entry.grid(row=4, column=1, padx=10, pady=5, sticky="w")
def update_employee():
"""更新员工信息"""
employee["name"] = name_entry.get()
employee["department"] = dept_entry.get()
employee["position"] = position_entry.get()
try:
employee["salary"] = float(salary_entry.get())
except ValueError:
messagebox.showerror("错误", "薪资必须是数字")
return
self.save_data(self.employees, self.emp_file)
messagebox.showinfo("成功", "员工信息已更新")
dialog.destroy()
self.show_employee_tab()
# 按钮区域
btn_frame = ttk.Frame(dialog)
btn_frame.grid(row=5, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="更新", command=update_employee).pack(side="left", padx=10)
ttk.Button(btn_frame, text="取消", command=dialog.destroy).pack(side="left", padx=10)
def delete_employee(self):
"""删除员工"""
selected = self.employee_tree.selection()
if not selected:
messagebox.showwarning("警告", "请先选择要删除的员工")
return
item = self.employee_tree.item(selected[0])
emp_id, name = item['values'][0], item['values'][1]
if not messagebox.askyesno("确认", f"确定要删除员工 {name} (ID: {emp_id}) 吗?"):
return
# 删除员工
self.employees = [emp for emp in self.employees if emp["emp_id"] != emp_id]
self.save_data(self.employees, self.emp_file)
# 删除相关考勤记录
self.attendance = [rec for rec in self.attendance if rec.get("emp_id") != emp_id]
self.save_data(self.attendance, self.att_file)
messagebox.showinfo("成功", "员工已删除")
self.show_employee_tab()
def show_attendance_tab(self):
"""显示考勤管理标签页"""
# 清除旧内容
for widget in self.attendance_tab.winfo_children():
widget.destroy()
# 顶部按钮区域
btn_frame = ttk.Frame(self.attendance_tab)
btn_frame.pack(pady=10)
ttk.Button(btn_frame, text="上班打卡", command=self.record_check_in).grid(row=0, column=0, padx=5)
ttk.Button(btn_frame, text="下班打卡", command=self.record_check_out).grid(row=0, column=1, padx=5)
ttk.Button(btn_frame, text="添加记录", command=self.add_attendance_record).grid(row=0, column=2, padx=5)
ttk.Button(btn_frame, text="刷新列表", command=self.show_attendance_tab).grid(row=0, column=3, padx=5)
# 搜索和过滤区域
filter_frame = ttk.Frame(self.attendance_tab)
filter_frame.pack(pady=5)
ttk.Label(filter_frame, text="员工ID:").grid(row=0, column=0)
self.att_emp_id_var = tk.StringVar()
ttk.Entry(filter_frame, textvariable=self.att_emp_id_var, width=15).grid(row=0, column=1, padx=5)
ttk.Label(filter_frame, text="日期:").grid(row=0, column=2)
self.att_date_var = tk.StringVar()
ttk.Entry(filter_frame, textvariable=self.att_date_var, width=15).grid(row=0, column=3, padx=5)
ttk.Button(filter_frame, text="筛选", command=self.filter_attendance).grid(row=0, column=4, padx=5)
ttk.Button(filter_frame, text="重置", command=self.reset_attendance_filter).grid(row=0, column=5, padx=5)
# 考勤表格
columns = ("ID", "姓名", "日期", "上班时间", "下班时间", "状态")
self.attendance_tree = ttk.Treeview(
self.attendance_tab, columns=columns, show="headings", height=20
)
# 设置列属性
col_widths = [80, 100, 100, 100, 100, 120]
for col, width in zip(columns, col_widths):
self.attendance_tree.heading(col, text=col)
self.attendance_tree.column(col, width=width, anchor='center')
self.attendance_tree.pack(fill="both", expand=True)
# 添加滚动条
scrollbar = ttk.Scrollbar(self.attendance_tree, orient="vertical", command=self.attendance_tree.yview)
self.attendance_tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
# 填充数据
self.populate_attendance_tree()
def populate_attendance_tree(self, records=None):
"""填充考勤表格数据"""
# 清空现有数据
for item in self.attendance_tree.get_children():
self.attendance_tree.delete(item)
# 获取员工姓名映射
emp_name_map = {emp["emp_id"]: emp["name"] for emp in self.employees}
# 显示所有记录或过滤后的记录
records_to_show = records if records else self.attendance
for rec in records_to_show:
emp_id = rec.get("emp_id", "")
self.attendance_tree.insert("", "end", values=(
emp_id,
emp_name_map.get(emp_id, "未知"),
rec.get("date", ""),
rec.get("check_in", "-"),
rec.get("check_out", "-"),
rec.get("status", "未知")
))
def filter_attendance(self):
"""筛选考勤记录"""
emp_id = self.att_emp_id_var.get()
date = self.att_date_var.get()
filtered = []
for rec in self.attendance:
match_emp = not emp_id or rec.get("emp_id", "") == emp_id
match_date = not date or rec.get("date", "").startswith(date)
if match_emp and match_date:
filtered.append(rec)
self.populate_attendance_tree(filtered)
def reset_attendance_filter(self):
"""重置考勤筛选"""
self.att_emp_id_var.set("")
self.att_date_var.set("")
self.populate_attendance_tree()
def record_check_in(self):
"""上班打卡"""
emp_id = simpledialog.askstring("上班打卡", "请输入员工ID:")
if not emp_id:
return
# 验证员工是否存在
if not any(emp["emp_id"] == emp_id for emp in self.employees):
messagebox.showerror("错误", "员工不存在")
return
today = datetime.now().strftime("%Y-%m-%d")
current_time = datetime.now().strftime("%H:%M")
status = "正常" if current_time <= "09:00" else "迟到"
# 检查是否已有当天记录
for rec in self.attendance:
if rec["emp_id"] == emp_id and rec["date"] == today:
if "check_in" in rec:
messagebox.showerror("错误", "该员工今天已上班打卡")
return
rec["check_in"] = current_time
rec["status"] = status
break
else:
# 新记录
new_rec = {
"emp_id": emp_id,
"date": today,
"check_in": current_time,
"status": status
}
self.attendance.append(new_rec)
self.save_data(self.attendance, self.att_file)
messagebox.showinfo("成功", f"员工 {emp_id} 上班打卡成功\n时间: {current_time}")
self.show_attendance_tab()
def record_check_out(self):
"""下班打卡"""
emp_id = simpledialog.askstring("下班打卡", "请输入员工ID:")
if not emp_id:
return
# 验证员工是否存在
if not any(emp["emp_id"] == emp_id for emp in self.employees):
messagebox.showerror("错误", "员工不存在")
return
today = datetime.now().strftime("%Y-%m-%d")
current_time = datetime.now().strftime("%H:%M")
# 查找当天记录
for rec in self.attendance:
if rec["emp_id"] == emp_id and rec["date"] == today:
if "check_out" in rec:
messagebox.showerror("错误", "该员工今天已下班打卡")
return
rec["check_out"] = current_time
# 更新状态
if current_time < "18:00":
if rec["status"] == "迟到":
rec["status"] = "迟到+早退"
else:
rec["status"] = "早退"
break
else:
# 没有上班记录,只有下班记录
new_rec = {
"emp_id": emp_id,
"date": today,
"check_out": current_time,
"status": "缺勤(上午)"
}
if current_time < "18:00":
new_rec["status"] += "+早退"
self.attendance.append(new_rec)
self.save_data(self.attendance, self.att_file)
messagebox.showinfo("成功", f"员工 {emp_id} 下班打卡成功\n时间: {current_time}")
self.show_attendance_tab()
def add_attendance_record(self):
"""手动添加考勤记录"""
dialog = tk.Toplevel(self.root)
dialog.title("添加考勤记录")
dialog.geometry("400x300")
# 表单字段
ttk.Label(dialog, text="员工ID:").grid(row=0, column=0, padx=10, pady=5, sticky="e")
emp_id_entry = ttk.Entry(dialog)
emp_id_entry.grid(row=0, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="日期(YYYY-MM-DD):").grid(row=1, column=0, padx=10, pady=5, sticky="e")
date_entry = ttk.Entry(dialog)
date_entry.grid(row=1, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="上班时间(HH:MM):").grid(row=2, column=0, padx=10, pady=5, sticky="e")
check_in_entry = ttk.Entry(dialog)
check_in_entry.grid(row=2, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="下班时间(HH:MM):").grid(row=3, column=0, padx=10, pady=5, sticky="e")
check_out_entry = ttk.Entry(dialog)
check_out_entry.grid(row=3, column=1, padx=10, pady=5, sticky="w")
ttk.Label(dialog, text="状态:").grid(row=4, column=0, padx=10, pady=5, sticky="e")
status_entry = ttk.Combobox(dialog, values=["正常", "迟到", "早退", "缺勤", "迟到+早退", "缺勤(上午)"])
status_entry.grid(row=4, column=1, padx=10, pady=5, sticky="w")
status_entry.set("正常")
def save_record():
"""保存考勤记录"""
emp_id = emp_id_entry.get()
date = date_entry.get()
check_in = check_in_entry.get() or None
check_out = check_out_entry.get() or None
status = status_entry.get()
# 验证员工是否存在
if not any(emp["emp_id"] == emp_id for emp in self.employees):
messagebox.showerror("错误", "员工不存在")
return
# 验证日期格式
try:
datetime.strptime(date, "%Y-%m-%d")
except ValueError:
messagebox.showerror("错误", "日期格式不正确,应为YYYY-MM-DD")
return
# 验证时间格式
if check_in:
try:
datetime.strptime(check_in, "%H:%M")
except ValueError:
messagebox.showerror("错误", "上班时间格式不正确,应为HH:MM")
return
if check_out:
try:
datetime.strptime(check_out, "%H:%M")
except ValueError:
messagebox.showerror("错误", "下班时间格式不正确,应为HH:MM")
return
# 检查是否已有当天记录
for rec in self.attendance:
if rec["emp_id"] == emp_id and rec["date"] == date:
messagebox.showerror("错误", "该员工当天已有考勤记录")
return
# 添加新记录
new_rec = {
"emp_id": emp_id,
"date": date,
"check_in": check_in,
"check_out": check_out,
"status": status
}
self.attendance.append(new_rec)
self.save_data(self.attendance, self.att_file)
messagebox.showinfo("成功", "考勤记录已添加")
dialog.destroy()
self.show_attendance_tab()
# 按钮区域
btn_frame = ttk.Frame(dialog)
btn_frame.grid(row=5, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="保存", command=save_record).pack(side="left", padx=10)
ttk.Button(btn_frame, text="取消", command=dialog.destroy).pack(side="left", padx=10)
def show_stats_tab(self):
"""显示统计分析标签页"""
# 清除旧内容
for widget in self.stats_tab.winfo_children():
widget.destroy()
# 创建标签页内的子标签
stats_notebook = ttk.Notebook(self.stats_tab)
# 创建各个子标签页
emp_stats_tab = ttk.Frame(stats_notebook)
salary_stats_tab = ttk.Frame(stats_notebook)
att_stats_tab = ttk.Frame(stats_notebook)
stats_notebook.add(emp_stats_tab, text='员工结构')
stats_notebook.add(salary_stats_tab, text='薪资分析')
stats_notebook.add(att_stats_tab, text='考勤统计')
stats_notebook.pack(expand=1, fill="both")
# 填充员工结构分析标签页
self.populate_emp_stats_tab(emp_stats_tab)
# 填充薪资分析标签页
self.populate_salary_stats_tab(salary_stats_tab)
# 填充考勤统计标签页
self.populate_att_stats_tab(att_stats_tab)
def populate_emp_stats_tab(self, tab):
"""填充员工结构分析标签页"""
# 部门分布
dept_frame = ttk.LabelFrame(tab, text="部门分布")
dept_frame.pack(fill="x", padx=10, pady=5)
dept_dist = defaultdict(int)
for emp in self.employees:
dept_dist[emp["department"]] += 1
for dept, count in sorted(dept_dist.items()):
ttk.Label(dept_frame, text=f"{dept}: {count}人 ({count/len(self.employees):.1%})").pack(anchor="w")
# 职位分布
position_frame = ttk.LabelFrame(tab, text="职位分布")
position_frame.pack(fill="x", padx=10, pady=5)
position_dist = defaultdict(int)
for emp in self.employees:
position_dist[emp["position"]] += 1
for position, count in sorted(position_dist.items()):
ttk.Label(position_frame, text=f"{position}: {count}人").pack(anchor="w")
def populate_salary_stats_tab(self, tab):
"""填充薪资分析标签页"""
if not self.employees:
ttk.Label(tab, text="没有员工数据").pack()
return
salaries = [emp["salary"] for emp in self.employees]
avg_salary = sum(salaries) / len(salaries)
max_salary = max(salaries)
min_salary = min(salaries)
# 整体统计
overall_frame = ttk.LabelFrame(tab, text="整体薪资统计")
overall_frame.pack(fill="x", padx=10, pady=5)
ttk.Label(overall_frame, text=f"平均薪资: {avg_salary:.2f}元").pack(anchor="w")
ttk.Label(overall_frame, text=f"最高薪资: {max_salary:.2f}元").pack(anchor="w")
ttk.Label(overall_frame, text=f"最低薪资: {min_salary:.2f}元").pack(anchor="w")
# 部门统计
dept_frame = ttk.LabelFrame(tab, text="部门薪资统计")
dept_frame.pack(fill="x", padx=10, pady=5)
dept_salaries = defaultdict(list)
for emp in self.employees:
dept_salaries[emp["department"]].append(emp["salary"])
for dept, sal_list in sorted(dept_salaries.items()):
avg = sum(sal_list) / len(sal_list)
ttk.Label(dept_frame, text=f"{dept}: 平均{avg:.2f}元 (人数:{len(sal_list)})").pack(anchor="w")
def populate_att_stats_tab(self, tab):
"""填充考勤统计标签页"""
if not self.attendance:
ttk.Label(tab, text="没有考勤数据").pack()
return
# 总体统计
overall_frame = ttk.LabelFrame(tab, text="整体考勤情况")
overall_frame.pack(fill="x", padx=10, pady=5)
status_dist = defaultdict(int)
for rec in self.attendance:
status_dist[rec["status"]] += 1
total = len(self.attendance)
for status, count in sorted(status_dist.items()):
ttk.Label(overall_frame, text=f"{status}: {count}次 ({count/total:.1%})").pack(anchor="w")
# 月度统计
month_frame = ttk.LabelFrame(tab, text="月度考勤趋势")
month_frame.pack(fill="x", padx=10, pady=5)
month_stats = defaultdict(lambda: defaultdict(int))
for rec in self.attendance:
month = rec["date"][:7] # 提取年月
month_stats[month]["total"] += 1
if "迟到" in rec["status"]:
month_stats[month]["late"] += 1
if "早退" in rec["status"]:
month_stats[month]["leave_early"] += 1
if "缺勤" in rec["status"]:
month_stats[month]["absent"] += 1
for month, stats in sorted(month_stats.items()):
ttk.Label(month_frame,
text=f"{month}: 迟到{stats['late']}次, 早退{stats['leave_early']}次, 缺勤{stats['absent']}次").pack(anchor="w")
def export_data(self):
"""导出数据"""
# 这里可以实现导出Excel或其他格式的功能
messagebox.showinfo("提示", "导出功能将在后续版本实现")
# 启动GUI应用
if __name__ == "__main__":
root = tk.Tk()
app = EmployeeGUISystem(root)
root.mainloop()
员工管理系统 - 带用户登录和权限管理功能的GUI版本
下面是在原有GUI系统基础上增加了用户登录和权限管理功能的完整代码实现下面是在原有GUI系统基础上增加了用户登录和权限管理功能的完整代码实现v下面是在原有GUI系统基础上增加了用户登录和权限管理功能的完整代码实现:
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
from datetime import datetime
import json
import os
import hashlib
from collections import defaultdict
class User:
"""用户类"""
def __init__(self, username, password_hash, role="user"):
self.username = username
self.password_hash = password_hash
self.role = role # admin/user
def verify_password(self, password):
"""验证密码"""
return self.password_hash == self.hash_password(password)
@staticmethod
def hash_password(password):
"""密码哈希处理"""
return hashlib.sha256(password.encode()).hexdigest()
class AuthSystem:
"""认证系统"""
def __init__(self, users_file="users.json"):
self.users_file = users_file
self.users = self.load_users()
self.current_user = None
def load_users(self):
"""加载用户数据"""
if os.path.exists(self.users_file):
with open(self.users_file, 'r', encoding='utf-8') as f:
users_data = json.load(f)
return {user['username']: User(user['username'], user['password_hash'], user.get('role', 'user'))
for user in users_data}
return {}
def save_users(self):
"""保存用户数据"""
users_data = [{'username': user.username,
'password_hash': user.password_hash,
'role': user.role}
for user in self.users.values()]
with open(self.users_file, 'w', encoding='utf-8') as f:
json.dump(users_data, f, ensure_ascii=False, indent=2)
def register(self, username, password, role="user"):
"""注册新用户"""
if username in self.users:
return False, "用户名已存在"
if len(password) < 6:
return False, "密码长度至少6位"
password_hash = User.hash_password(password)
self.users[username] = User(username, password_hash, role)
self.save_users()
return True, "注册成功"
def login(self, username, password):
"""用户登录"""
user = self.users.get(username)
if not user:
return False, "用户不存在"
if not user.verify_password(password):
return False, "密码错误"
self.current_user = user
return True, "登录成功"
def logout(self):
"""用户登出"""
self.current_user = None
def is_admin(self):
"""检查当前用户是否是管理员"""
return self.current_user and self.current_user.role == "admin"
class EmployeeGUISystemWithAuth:
def __init__(self, root):
self.root = root
self.root.title("员工管理系统 - 请登录")
self.root.geometry("500x300")
# 认证系统
self.auth = AuthSystem()
# 数据文件
self.emp_file = "employees_gui.json"
self.att_file = "attendance_gui.json"
# 加载数据
self.employees = self.load_data(self.emp_file)
self.attendance = self.load_data(self.att_file)
# 显示登录界面
self.show_login_interface()
def load_data(self, filename):
"""加载JSON数据"""
if os.path.exists(filename):
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_data(self, data, filename):
"""保存数据到JSON文件"""
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def show_login_interface(self):
"""显示登录界面"""
# 清除旧内容
for widget in self.root.winfo_children():
widget.destroy()
self.root.geometry("500x300")
# 登录表单
login_frame = ttk.Frame(self.root, padding="20")
login_frame.pack(expand=True)
ttk.Label(login_frame, text="员工管理系统", font=('Arial', 16)).grid(row=0, column=0, columnspan=2, pady=10)
ttk.Label(login_frame, text="用户名:").grid(row=1, column=0, pady=5, sticky="e")
self.username_var = tk.StringVar()
ttk.Entry(login_frame, textvariable=self.username_var).grid(row=1, column=1, pady=5)
ttk.Label(login_frame, text="密码:").grid(row=2, column=0, pady=5, sticky="e")
self.password_var = tk.StringVar()
ttk.Entry(login_frame, textvariable=self.password_var, show="*").grid(row=2, column=1, pady=5)
btn_frame = ttk.Frame(login_frame)
btn_frame.grid(row=3, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="登录", command=self.handle_login).pack(side="left", padx=10)
ttk.Button(btn_frame, text="注册", command=self.show_register_dialog).pack(side="left", padx=10)
# 如果是管理员,显示初始化按钮
if not self.auth.users:
ttk.Button(login_frame, text="初始化管理员账户",
command=self.init_admin_account).grid(row=4, column=0, columnspan=2, pady=10)
def init_admin_account(self):
"""初始化管理员账户"""
dialog = tk.Toplevel(self.root)
dialog.title("初始化管理员账户")
dialog.geometry("400x250")
ttk.Label(dialog, text="设置管理员账户", font=('Arial', 12)).pack(pady=10)
ttk.Label(dialog, text="用户名:").pack()
admin_user_entry = ttk.Entry(dialog)
admin_user_entry.pack(pady=5)
ttk.Label(dialog, text="密码:").pack()
admin_pass_entry = ttk.Entry(dialog, show="*")
admin_pass_entry.pack(pady=5)
ttk.Label(dialog, text="确认密码:").pack()
admin_pass_confirm_entry = ttk.Entry(dialog, show="*")
admin_pass_confirm_entry.pack(pady=5)
def create_admin():
username = admin_user_entry.get()
password = admin_pass_entry.get()
confirm = admin_pass_confirm_entry.get()
if not username or not password:
messagebox.showerror("错误", "用户名和密码不能为空")
return
if password != confirm:
messagebox.showerror("错误", "两次输入的密码不一致")
return
success, msg = self.auth.register(username, password, "admin")
messagebox.showinfo("提示", msg)
if success:
dialog.destroy()
ttk.Button(dialog, text="创建", command=create_admin).pack(pady=10)
def show_register_dialog(self):
"""显示注册对话框"""
dialog = tk.Toplevel(self.root)
dialog.title("注册新用户")
dialog.geometry("400x250")
ttk.Label(dialog, text="注册新账户", font=('Arial', 12)).pack(pady=10)
ttk.Label(dialog, text="用户名:").pack()
new_user_entry = ttk.Entry(dialog)
new_user_entry.pack(pady=5)
ttk.Label(dialog, text="密码(至少6位):").pack()
new_pass_entry = ttk.Entry(dialog, show="*")
new_pass_entry.pack(pady=5)
ttk.Label(dialog, text="确认密码:").pack()
new_pass_confirm_entry = ttk.Entry(dialog, show="*")
new_pass_confirm_entry.pack(pady=5)
def register_user():
username = new_user_entry.get()
password = new_pass_entry.get()
confirm = new_pass_confirm_entry.get()
if not username or not password:
messagebox.showerror("错误", "用户名和密码不能为空")
return
if password != confirm:
messagebox.showerror("错误", "两次输入的密码不一致")
return
success, msg = self.auth.register(username, password)
messagebox.showinfo("提示", msg)
if success:
dialog.destroy()
ttk.Button(dialog, text="注册", command=register_user).pack(pady=10)
def handle_login(self):
"""处理登录"""
username = self.username_var.get()
password = self.password_var.get()
if not username or not password:
messagebox.showerror("错误", "用户名和密码不能为空")
return
success, msg = self.auth.login(username, password)
messagebox.showinfo("提示", msg)
if success:
self.show_main_interface()
def show_main_interface(self):
"""显示主界面"""
# 清除旧内容
for widget in self.root.winfo_children():
widget.destroy()
self.root.title(f"员工管理系统 - 当前用户: {self.auth.current_user.username}")
self.root.geometry("1000x700")
# 顶部菜单栏
menubar = tk.Menu(self.root)
# 文件菜单
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="导出数据", command=self.export_data)
# 用户菜单
user_menu = tk.Menu(menubar, tearoff=0)
user_menu.add_command(label="修改密码", command=self.change_password)
user_menu.add_separator()
user_menu.add_command(label="退出登录", command=self.logout)
# 管理员菜单
if self.auth.is_admin():
admin_menu = tk.Menu(menubar, tearoff=0)
admin_menu.add_command(label="用户管理", command=self.manage_users)
menubar.add_cascade(label="管理员", menu=admin_menu)
menubar.add_cascade(label="文件", menu=file_menu)
menubar.add_cascade(label="用户", menu=user_menu)
self.root.config(menu=menubar)
# 标签页控件
self.tab_control = ttk.Notebook(self.root)
# 创建各个标签页
self.employee_tab = ttk.Frame(self.tab_control)
self.attendance_tab = ttk.Frame(self.tab_control)
self.stats_tab = ttk.Frame(self.tab_control)
self.tab_control.add(self.employee_tab, text='员工管理')
self.tab_control.add(self.attendance_tab, text='考勤管理')
self.tab_control.add(self.stats_tab, text='统计分析')
self.tab_control.pack(expand=1, fill="both")
# 绑定标签页切换事件
self.tab_control.bind("<<NotebookTabChanged>>", self.on_tab_changed)
# 默认显示员工管理标签页
self.show_employee_tab()
def change_password(self):
"""修改密码"""
dialog = tk.Toplevel(self.root)
dialog.title("修改密码")
dialog.geometry("400x250")
ttk.Label(dialog, text="修改密码", font=('Arial', 12)).pack(pady=10)
ttk.Label(dialog, text="当前密码:").pack()
current_pass_entry = ttk.Entry(dialog, show="*")
current_pass_entry.pack(pady=5)
ttk.Label(dialog, text="新密码:").pack()
new_pass_entry = ttk.Entry(dialog, show="*")
new_pass_entry.pack(pady=5)
ttk.Label(dialog, text="确认新密码:").pack()
confirm_pass_entry = ttk.Entry(dialog, show="*")
confirm_pass_entry.pack(pady=5)
def update_password():
current_pass = current_pass_entry.get()
new_pass = new_pass_entry.get()
confirm_pass = confirm_pass_entry.get()
if not self.auth.current_user.verify_password(current_pass):
messagebox.showerror("错误", "当前密码不正确")
return
if new_pass != confirm_pass:
messagebox.showerror("错误", "两次输入的新密码不一致")
return
if len(new_pass) < 6:
messagebox.showerror("错误", "密码长度至少6位")
return
# 更新密码
self.auth.current_user.password_hash = User.hash_password(new_pass)
self.auth.save_users()
messagebox.showinfo("成功", "密码修改成功")
dialog.destroy()
ttk.Button(dialog, text="确认修改", command=update_password).pack(pady=10)
def manage_users(self):
"""用户管理(仅管理员)"""
if not self.auth.is_admin():
return
dialog = tk.Toplevel(self.root)
dialog.title("用户管理")
dialog.geometry("600x400")
# 用户列表
columns = ("用户名", "角色")
user_tree = ttk.Treeview(dialog, columns=columns, show="headings", height=15)
for col in columns:
user_tree.heading(col, text=col)
user_tree.column(col, width=200, anchor='center')
user_tree.pack(fill="both", expand=True, padx=10, pady=10)
# 填充用户数据
for user in self.auth.users.values():
user_tree.insert("", "end", values=(user.username, user.role))
# 操作按钮
btn_frame = ttk.Frame(dialog)
btn_frame.pack(pady=10)
ttk.Button(btn_frame, text="添加用户", command=lambda: self.add_user_dialog(dialog)).pack(side="left", padx=5)
ttk.Button(btn_frame, text="删除用户",
command=lambda: self.delete_user(user_tree, dialog)).pack(side="left", padx=5)
ttk.Button(btn_frame, text="设为管理员",
command=lambda: self.change_user_role(user_tree, "admin", dialog)).pack(side="left", padx=5)
ttk.Button(btn_frame, text="设为普通用户",
command=lambda: self.change_user_role(user_tree, "user", dialog)).pack(side="left", padx=5)
ttk.Button(btn_frame, text="关闭", command=dialog.destroy).pack(side="left", padx=5)
def add_user_dialog(self, parent):
"""添加用户对话框"""
dialog = tk.Toplevel(parent)
dialog.title("添加用户")
dialog.geometry("400x250")
ttk.Label(dialog, text="添加新用户", font=('Arial', 12)).pack(pady=10)
ttk.Label(dialog, text="用户名:").pack()
new_user_entry = ttk.Entry(dialog)
new_user_entry.pack(pady=5)
ttk.Label(dialog, text="密码(至少6位):").pack()
new_pass_entry = ttk.Entry(dialog, show="*")
new_pass_entry.pack(pady=5)
ttk.Label(dialog, text="确认密码:").pack()
new_pass_confirm_entry = ttk.Entry(dialog, show="*")
new_pass_confirm_entry.pack(pady=5)
role_var = tk.StringVar(value="user")
ttk.Checkbutton(dialog, text="设为管理员", variable=role_var,
onvalue="admin", offvalue="user").pack(pady=5)
def add_user():
username = new_user_entry.get()
password = new_pass_entry.get()
confirm = new_pass_confirm_entry.get()
role = role_var.get()
if not username or not password:
messagebox.showerror("错误", "用户名和密码不能为空")
return
if password != confirm:
messagebox.showerror("错误", "两次输入的密码不一致")
return
success, msg = self.auth.register(username, password, role)
messagebox.showinfo("提示", msg)
if success:
dialog.destroy()
self.manage_users() # 刷新用户列表
ttk.Button(dialog, text="添加", command=add_user).pack(pady=10)
def delete_user(self, user_tree, parent):
"""删除用户"""
selected = user_tree.selection()
if not selected:
messagebox.showwarning("警告", "请先选择要删除的用户")
return
item = user_tree.item(selected[0])
username = item['values'][0]
if username == self.auth.current_user.username:
messagebox.showerror("错误", "不能删除当前登录的用户")
return
if not messagebox.askyesno("确认", f"确定要删除用户 {username} 吗?"):
return
del self.auth.users[username]
self.auth.save_users()
messagebox.showinfo("成功", "用户已删除")
self.manage_users() # 刷新用户列表
def change_user_role(self, user_tree, new_role, parent):
"""修改用户角色"""
selected = user_tree.selection()
if not selected:
messagebox.showwarning("警告", "请先选择用户")
return
item = user_tree.item(selected[0])
username = item['values'][0]
if username == self.auth.current_user.username:
messagebox.showerror("错误", "不能修改当前登录用户的角色")
return
user = self.auth.users[username]
user.role = new_role
self.auth.save_users()
messagebox.showinfo("成功", f"用户 {username} 角色已更新为 {new_role}")
self.manage_users() # 刷新用户列表
def logout(self):
"""用户登出"""
self.auth.logout()
self.show_login_interface()
# 以下是原有员工管理、考勤管理和统计分析功能的实现
# 与之前版本相同,只是增加了权限检查
# 例如:
def on_tab_changed(self, event):
"""标签页切换事件处理"""
selected_tab = event.widget.tab('current')['text']
if selected_tab == "员工管理":
self.show_employee_tab()
elif selected_tab == "考勤管理":
self.show_attendance_tab()
elif selected_tab == "统计分析":
self.show_stats_tab()
def show_employee_tab(self):
"""显示员工管理标签页"""
# 清除旧内容
for widget in self.employee_tab.winfo_children():
widget.destroy()
# 顶部按钮区域
btn_frame = ttk.Frame(self.employee_tab)
btn_frame.pack(pady=10)
# 根据权限显示不同按钮
if self.auth.is_admin():
ttk.Button(btn_frame, text="添加员工", command=self.add_employee_dialog).grid(row=0, column=0, padx=5)
ttk.Button(btn_frame, text="编辑员工", command=self.edit_employee_dialog).grid(row=0, column=1, padx=5)
ttk.Button(btn_frame, text="删除员工", command=self.delete_employee).grid(row=0, column=2, padx=5)
ttk.Button(btn_frame, text="刷新列表", command=self.show_employee_tab).grid(row=0, column=3, padx=5)
# 搜索区域
search_frame = ttk.Frame(self.employee_tab)
search_frame.pack(pady=5)
ttk.Label(search_frame, text="搜索:").grid(row=0, column=0)
self.emp_search_var = tk.StringVar()
ttk.Entry(search_frame, textvariable=self.emp_search_var, width=30).grid(row=0, column=1, padx=5)
ttk.Button(search_frame, text="搜索", command=self.search_employees).grid(row=0, column=2)
ttk.Button(search_frame, text="重置", command=self.reset_search).grid(row=0, column=3)
# 员工表格
columns = ("ID", "姓名", "部门", "职位", "薪资")
self.employee_tree = ttk.Treeview(
self.employee_tab, columns=columns, show="headings", height=20
)
# 设置列属性
col_widths = [80, 120, 150, 150, 100]
for col, width in zip(columns, col_widths):
self.employee_tree.heading(col, text=col)
self.employee_tree.column(col, width=width, anchor='center')
self.employee_tree.pack(fill="both", expand=True)
# 添加滚动条
scrollbar = ttk.Scrollbar(self.employee_tree, orient="vertical", command=self.employee_tree.yview)
self.employee_tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
# 填充数据
self.populate_employee_tree()
# 其他原有方法(add_employee_dialog, edit_employee_dialog等)保持不变
# 只需在适当位置添加权限检查,例如:
def delete_employee(self):
"""删除员工"""
if not self.auth.is_admin():
messagebox.showerror("权限不足", "只有管理员可以删除员工")
return
selected = self.employee_tree.selection()
if not selected:
messagebox.showwarning("警告", "请先选择要删除的员工")
return
# 其余删除逻辑与之前相同...
# 考勤管理和统计分析功能的实现也类似
# 可以根据需要限制某些功能只对管理员开放
def export_data(self):
"""导出数据"""
if not self.auth.is_admin():
messagebox.showerror("权限不足", "只有管理员可以导出数据")
return
# 导出数据的具体实现
messagebox.showinfo("提示", "导出功能将在后续版本实现")
# 启动GUI应用
if __name__ == "__main__":
root = tk.Tk()
app = EmployeeGUISystemWithAuth(root)
root.mainloop()
数据存储格式
系统使用JSON格式存储数据,示例数据如下:
[
{
"emp_id": "1001",
"name": "张三",
"department": "技术部",
"position": "工程师",
"salary": 15000.0
},
{
"emp_id": "1002",
"name": "李四",
"department": "人事部",
"position": "经理",
"salary": 18000.0
}
]