import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import sqlite3
from datetime import datetime
import pandas as pd
from tkcalendar import DateEntry
class LoginWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("用户登录")
self.geometry("300x200")
self.conn = sqlite3.connect('power_projects.db')
self.create_user_table()
self.username_var = tk.StringVar()
self.password_var = tk.StringVar()
ttk.Label(self, text="用户名:").pack(pady=10)
ttk.Entry(self, textvariable=self.username_var).pack(pady=5)
ttk.Label(self, text="密码:").pack(pady=10)
ttk.Entry(self, textvariable=self.password_var, show="*").pack(pady=5)
ttk.Button(self, text="登录", command=self.login).pack(pady=20)
def create_user_table(self):
cursor = self.conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
role TEXT NOT NULL
)''')
cursor.execute('''INSERT OR IGNORE INTO users
(username, password, role)
VALUES (?, ?, ?)''',
('admin', 'admin123', 'admin'))
self.conn.commit()
def login(self):
username = self.username_var.get()
password = self.password_var.get()
cursor = self.conn.cursor()
cursor.execute("SELECT role FROM users WHERE username=? AND password=?",
(username, password))
result = cursor.fetchone()
if result:
self.destroy()
root = tk.Tk()
app = ProjectManagementApp(root, result[0])
root.mainloop()
else:
messagebox.showerror("登录失败", "用户名或密码错误")
class ProjectManagementApp:
def __init__(self, root, role):
self.root = root
self.root.title("电力工程管理系统")
self.root.geometry("1400x800")
self.role = role
self.conn = sqlite3.connect('power_projects.db')
self.create_tables()
self.create_widgets()
self.load_initial_data()
def create_tables(self):
cursor = self.conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS projects (
序号 INTEGER PRIMARY KEY AUTOINCREMENT,
项目名称 TEXT NOT NULL UNIQUE,
甲方 TEXT,
项目类型 TEXT,
金额 REAL,
开始时间 TEXT
)''')
cursor.execute('''CREATE TABLE IF NOT EXISTS work_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
日期 TEXT,
固定工作内容 TEXT,
目标时机 TEXT,
完成情况 TEXT,
费用类型 TEXT,
费用金额 REAL
)''')
self.conn.commit()
def create_widgets(self):
self.notebook = ttk.Notebook(self.root)
self.project_frame = ttk.Frame(self.notebook)
self._create_project_tree()
self.log_frame = ttk.Frame(self.notebook)
self._create_log_tree()
self.notebook.add(self.project_frame, text="项目明细")
self.notebook.add(self.log_frame, text="工作日志")
self.notebook.pack(expand=True, fill=tk.BOTH)
toolbar = ttk.Frame(self.root)
toolbar.pack(side=tk.TOP, fill=tk.X)
ttk.Button(toolbar, text="导入Excel", command=self.import_excel).pack(side=tk.LEFT, padx=5)
ttk.Button(toolbar, text="导出Excel", command=self.export_excel).pack(side=tk.LEFT, padx=5)
if self.role == 'admin':
ttk.Button(toolbar, text="新增项目", command=self.add_project).pack(side=tk.LEFT, padx=5)
ttk.Button(toolbar, text="编辑项目", command=self.edit_project).pack(side=tk.LEFT, padx=5)
ttk.Button(toolbar, text="删除项目", command=self.delete_project).pack(side=tk.LEFT, padx=5)
ttk.Button(toolbar, text="新增日志", command=self.add_log).pack(side=tk.LEFT, padx=5)
ttk.Button(toolbar, text="删除日志", command=self.delete_log).pack(side=tk.LEFT, padx=5)
def _create_project_tree(self):
columns = ("序号", "项目名称", "甲方", "项目类型", "金额", "开始时间")
self.project_tree = ttk.Treeview(self.project_frame, columns=columns, show="headings")
col_width = {"序号":80, "项目名称":200, "甲方":150, "项目类型":100, "金额":100, "开始时间":120}
for col in columns:
self.project_tree.heading(col, text=col)
self.project_tree.column(col, width=col_width[col])
yscroll = ttk.Scrollbar(self.project_frame, orient=tk.VERTICAL, command=self.project_tree.yview)
self.project_tree.configure(yscrollcommand=yscroll.set)
self.project_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
yscroll.pack(side=tk.RIGHT, fill=tk.Y)
def _create_log_tree(self):
columns = ("id", "日期", "固定工作内容", "目标时机", "完成情况", "费用类型", "费用金额")
self.log_tree = ttk.Treeview(self.log_frame, columns=columns, show="headings")
col_width = {"id":0, "日期":120, "固定工作内容":250, "目标时机":100,
"完成情况":100, "费用类型":150, "费用金额":100}
for col in columns:
self.log_tree.heading(col, text=col)
self.log_tree.column(col, width=col_width[col])
if col == "id":
self.log_tree.column(col, stretch=tk.NO, minwidth=0, width=0)
yscroll = ttk.Scrollbar(self.log_frame, orient=tk.VERTICAL, command=self.log_tree.yview)
self.log_tree.configure(yscrollcommand=yscroll.set)
self.log_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
yscroll.pack(side=tk.RIGHT, fill=tk.Y)
def load_initial_data(self):
self.project_tree.delete(*self.project_tree.get_children())
cursor = self.conn.cursor()
cursor.execute("SELECT 序号,项目名称,甲方,项目类型,金额,开始时间 FROM projects")
for row in cursor.fetchall():
self.project_tree.insert("", tk.END, values=row)
self.log_tree.delete(*self.log_tree.get_children())
cursor.execute("SELECT id,日期,固定工作内容,目标时机,完成情况,费用类型,费用金额 FROM work_logs")
for row in cursor.fetchall():
self.log_tree.insert("", tk.END, values=row)
def add_project(self):
ProjectDialog(self.root, self.conn, self.load_initial_data)
def delete_project(self):
selected = self.project_tree.selection()
if not selected:
messagebox.showwarning("提示", "请先选择要删除的项目")
return
project_id = self.project_tree.item(selected)["values"][0]
if messagebox.askyesno("确认删除", "确定要删除这个项目吗?"):
try:
self.conn.cursor().execute("DELETE FROM projects WHERE 序号=?", (project_id,))
self.conn.commit()
self.load_initial_data()
except Exception as e:
messagebox.showerror("删除失败", str(e))
def add_log(self):
LogDialog(self.root, self.conn, self.load_initial_data)
def delete_log(self):
selected = self.log_tree.selection()
if not selected:
messagebox.showwarning("提示", "请先选择要删除的日志")
return
log_id = self.log_tree.item(selected)["values"][0]
if messagebox.askyesno("确认删除", "确定要删除这条日志吗?"):
try:
self.conn.cursor().execute("DELETE FROM work_logs WHERE id=?", (log_id,))
self.conn.commit()
self.load_initial_data()
except Exception as e:
messagebox.showerror("删除失败", str(e))
def import_excel(self):
file_path = filedialog.askopenfilename(filetypes=[("Excel文件", "*.xlsx")])
if file_path:
try:
df = pd.read_excel(file_path)
df.to_sql("projects", self.conn, if_exists="append", index=False)
self.load_initial_data()
messagebox.showinfo("导入成功", "数据已成功导入!")
except Exception as e:
messagebox.showerror("导入失败", str(e))
def export_excel(self):
file_path = filedialog.asksaveasfilename(defaultextension=".xlsx")
if file_path:
try:
df = pd.read_sql("SELECT * FROM projects", self.conn)
df.to_excel(file_path, index=False)
messagebox.showinfo("导出成功", "数据已成功导出!")
except Exception as e:
messagebox.showerror("导出失败", str(e))
class ProjectDialog(tk.Toplevel):
def __init__(self, parent, conn, callback, project_id=None):
super().__init__(parent)
self.conn = conn
self.callback = callback
self.project_id = project_id
self.title("编辑项目" if project_id else "新建项目")
self.geometry("600x400")
self.create_widgets()
if project_id:
self.load_data()
def create_widgets(self):
fields = [
("项目名称", "entry"),
("甲方", "entry"),
("项目类型", "combobox", ["配电网", "输变电", "新能源"]),
("金额", "entry"),
("开始时间", "calendar")
]
self.entries = {}
for row, (label, widget_type, *options) in enumerate(fields):
ttk.Label(self, text=label+":").grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
if widget_type == "entry":
entry = ttk.Entry(self)
entry.grid(row=row, column=1, padx=5, pady=5)
self.entries[label] = entry
elif widget_type == "combobox":
cb = ttk.Combobox(self, values=options[0])
cb.grid(row=row, column=1, padx=5, pady=5)
self.entries[label] = cb
elif widget_type == "calendar":
cal = DateEntry(self, date_pattern='yyyy-mm-dd')
cal.grid(row=row, column=1, padx=5, pady=5)
self.entries[label] = cal
btn_frame = ttk.Frame(self)
btn_frame.grid(row=len(fields)+1, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="保存", command=self.save).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="取消", command=self.destroy).pack(side=tk.LEFT, padx=5)
def save(self):
data = {
"项目名称": self.entries["项目名称"].get(),
"甲方": self.entries["甲方"].get(),
"项目类型": self.entries["项目类型"].get(),
"金额": float(self.entries["金额"].get()),
"开始时间": self.entries["开始时间"].get_date().strftime("%Y-%m-%d")
}
try:
cursor = self.conn.cursor()
if self.project_id:
cursor.execute('''UPDATE projects SET
项目名称=?, 甲方=?, 项目类型=?, 金额=?, 开始时间=?
WHERE 序号=?''', (*data.values(), self.project_id))
else:
cursor.execute('''INSERT INTO projects
(项目名称, 甲方, 项目类型, 金额, 开始时间)
VALUES (?,?,?,?,?)''', tuple(data.values()))
self.conn.commit()
self.callback()
self.destroy()
except Exception as e:
messagebox.showerror("保存失败", str(e))
class LogDialog(tk.Toplevel):
def __init__(self, parent, conn, callback, log_id=None):
super().__init__(parent)
self.conn = conn
self.callback = callback
self.log_id = log_id
self.title("编辑日志" if log_id else "新建日志")
self.geometry("600x400")
self.create_widgets()
if log_id:
self.load_data()
def create_widgets(self):
fields = [
("日期", "calendar"),
("固定工作内容", "entry"),
("目标时机", "calendar"),
("完成情况", "combobox", ["已完成", "进行中", "未开始"]),
("费用类型", "combobox", ["差旅费", "材料费", "设备费"]),
("费用金额", "entry")
]
self.entries = {}
for row, (label, widget_type, *options) in enumerate(fields):
ttk.Label(self, text=label+":").grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
if widget_type == "entry":
entry = ttk.Entry(self)
entry.grid(row=row, column=1, padx=5, pady=5)
self.entries[label] = entry
elif widget_type == "combobox":
cb = ttk.Combobox(self, values=options[0])
cb.grid(row=row, column=1, padx=5, pady=5)
self.entries[label] = cb
elif widget_type == "calendar":
cal = DateEntry(self, date_pattern='yyyy-mm-dd')
cal.grid(row=row, column=1, padx=5, pady=5)
self.entries[label] = cal
btn_frame = ttk.Frame(self)
btn_frame.grid(row=len(fields)+1, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="保存", command=self.save).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="取消", command=self.destroy).pack(side=tk.LEFT, padx=5)
def save(self):
data = {
"日期": self.entries["日期"].get_date().strftime("%Y-%m-%d"),
"固定工作内容": self.entries["固定工作内容"].get(),
"目标时机": self.entries["目标时机"].get_date().strftime("%Y-%m-%d"),
"完成情况": self.entries["完成情况"].get(),
"费用类型": self.entries["费用类型"].get(),
"费用金额": float(self.entries["费用金额"].get() or 0)
}
try:
cursor = self.conn.cursor()
if self.log_id:
cursor.execute('''UPDATE work_logs SET
日期=?, 固定工作内容=?, 目标时机=?, 完成情况=?, 费用类型=?, 费用金额=?
WHERE id=?''', (*data.values(), self.log_id))
else:
cursor.execute('''INSERT INTO work_logs
(日期, 固定工作内容, 目标时机, 完成情况, 费用类型, 费用金额)
VALUES (?,?,?,?,?,?)''', tuple(data.values()))
self.conn.commit()
self.callback()
self.destroy()
except Exception as e:
messagebox.showerror("保存失败", str(e))
if __name__ == "__main__":
login_app = LoginWindow()
login_app.mainloop()