Improve GUI: clean report display with copy functionality
This commit is contained in:
188
src/gui.py
188
src/gui.py
@@ -19,136 +19,13 @@ from src.database import DailyLogsDatabase
|
||||
from src.report import DailyReportGenerator
|
||||
|
||||
|
||||
class ReportFrame(ttk.LabelFrame):
|
||||
"""日报显示框架"""
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent, text="日报预览", padding="10")
|
||||
self.parent = parent
|
||||
self._create_widgets()
|
||||
|
||||
def _create_widgets(self):
|
||||
"""创建组件"""
|
||||
# 日期标题
|
||||
self.date_label = ttk.Label(self, text="--月--日", font=('SimHei', 14, 'bold'))
|
||||
self.date_label.pack(pady=(0, 10))
|
||||
|
||||
# 船次信息表格
|
||||
self.ships_frame = ttk.Frame(self)
|
||||
self.ships_frame.pack(fill=tk.X, pady=5)
|
||||
|
||||
# 统计信息
|
||||
self.stats_frame = ttk.Frame(self)
|
||||
self.stats_frame.pack(fill=tk.X, pady=10)
|
||||
|
||||
# 人员信息
|
||||
self.personnel_frame = ttk.Frame(self)
|
||||
self.personnel_frame.pack(fill=tk.X, pady=10)
|
||||
|
||||
def display_report(self, report_text: str, date: str):
|
||||
"""显示日报"""
|
||||
# 解析日报内容
|
||||
lines = report_text.strip().split('\n')
|
||||
|
||||
# 更新日期
|
||||
self.date_label.config(text=f"{date[5:7]}月{date[8:10]}日")
|
||||
|
||||
# 清空旧数据
|
||||
for widget in self.ships_frame.winfo_children():
|
||||
widget.destroy()
|
||||
for widget in self.stats_frame.winfo_children():
|
||||
widget.destroy()
|
||||
for widget in self.personnel_frame.winfo_children():
|
||||
widget.destroy()
|
||||
|
||||
# 解析并显示各部分
|
||||
current_section = None
|
||||
ships_data = []
|
||||
stats_data = {}
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
if line.startswith('日期:'):
|
||||
continue
|
||||
elif line.startswith('船名:'):
|
||||
current_section = 'ships'
|
||||
ships_data.append({'name': line.replace('船名:', '').strip(), 'teu': None})
|
||||
elif line.startswith('作业量:'):
|
||||
if ships_data:
|
||||
ships_data[-1]['teu'] = line.replace('作业量:', '').replace('TEU', '').strip()
|
||||
elif line.startswith('当日实际作业量:'):
|
||||
stats_data['daily_total'] = line.replace('当日实际作业量:', '').replace('TEU', '').strip()
|
||||
elif line.startswith('当月计划作业量:'):
|
||||
stats_data['monthly_plan'] = line.replace('当月计划作业量:', '').replace('TEU', '').replace(' (用天数*300TEU)', '').strip()
|
||||
elif line.startswith('当月实际作业量:'):
|
||||
stats_data['monthly_actual'] = line.replace('当月实际作业量:', '').replace('TEU', '').strip()
|
||||
elif line.startswith('当月完成比例:'):
|
||||
stats_data['completion'] = line.replace('当月完成比例:', '').replace('%', '').strip()
|
||||
elif '白班人员' in line:
|
||||
stats_data['day_shift'] = line.split(':')[1].strip() if ':' in line else ''
|
||||
elif '夜班人员' in line:
|
||||
stats_data['night_shift'] = line.split(':')[1].strip() if ':' in line else ''
|
||||
elif '值班手机' in line:
|
||||
stats_data['phone'] = line.split(':')[1].strip() if ':' in line else ''
|
||||
|
||||
# 显示船次信息
|
||||
if ships_data:
|
||||
ttk.Label(self.ships_frame, text="船次信息", font=('', 10, 'bold')).pack(anchor=tk.W)
|
||||
for ship in ships_data:
|
||||
ship_frame = ttk.Frame(self.ships_frame)
|
||||
ship_frame.pack(fill=tk.X, pady=2)
|
||||
ttk.Label(ship_frame, text=f"🚢 {ship['name']}", foreground='#1976D2').pack(side=tk.LEFT)
|
||||
ttk.Label(ship_frame, text=f"{ship['teu']} TEU", font=('', 10, 'bold'), foreground='#388E3C').pack(side=tk.RIGHT)
|
||||
|
||||
# 显示统计信息
|
||||
if stats_data:
|
||||
ttk.Label(self.stats_frame, text="统计信息", font=('', 10, 'bold')).pack(anchor=tk.W)
|
||||
|
||||
stats_grid = ttk.Frame(self.stats_frame)
|
||||
stats_grid.pack(fill=tk.X, pady=5)
|
||||
|
||||
# 第一行
|
||||
ttk.Label(stats_grid, text="当日作业:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
|
||||
ttk.Label(stats_grid, text=f"{stats_data.get('daily_total', '0')} TEU", foreground='#388E3C', font=('', 10, 'bold')).grid(row=0, column=1, sticky=tk.W)
|
||||
|
||||
ttk.Label(stats_grid, text="月计划:").grid(row=0, column=2, sticky=tk.W, padx=(20, 10))
|
||||
ttk.Label(stats_grid, text=f"{stats_data.get('monthly_plan', '0')} TEU").grid(row=0, column=3, sticky=tk.W)
|
||||
|
||||
# 第二行
|
||||
ttk.Label(stats_grid, text="月实际:").grid(row=1, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
|
||||
ttk.Label(stats_grid, text=f"{stats_data.get('monthly_actual', '0')} TEU", foreground='#388E3C', font=('', 10, 'bold')).grid(row=1, column=1, sticky=tk.W, pady=(5, 0))
|
||||
|
||||
ttk.Label(stats_grid, text="完成率:").grid(row=1, column=2, sticky=tk.W, padx=(20, 10), pady=(5, 0))
|
||||
completion = float(stats_data.get('completion', 0))
|
||||
color = '#388E3C' if completion >= 100 else '#FF9800' if completion >= 80 else '#F44336'
|
||||
ttk.Label(stats_grid, text=f"{stats_data.get('completion', '0')}%", foreground=color, font=('', 10, 'bold')).grid(row=1, column=3, sticky=tk.W, pady=(5, 0))
|
||||
|
||||
# 显示人员信息
|
||||
ttk.Label(self.personnel_frame, text="班次人员", font=('', 10, 'bold')).pack(anchor=tk.W)
|
||||
|
||||
personnel_grid = ttk.Frame(self.personnel_frame)
|
||||
personnel_grid.pack(fill=tk.X, pady=5)
|
||||
|
||||
ttk.Label(personnel_grid, text="☀️ 白班:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
|
||||
ttk.Label(personnel_grid, text=stats_data.get('day_shift', '-')).grid(row=0, column=1, sticky=tk.W)
|
||||
|
||||
ttk.Label(personnel_grid, text="🌙 夜班:").grid(row=1, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
|
||||
ttk.Label(personnel_grid, text=stats_data.get('night_shift', '-')).grid(row=1, column=1, sticky=tk.W, pady=(5, 0))
|
||||
|
||||
ttk.Label(personnel_grid, text="📞 值班:").grid(row=2, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
|
||||
ttk.Label(personnel_grid, text=stats_data.get('phone', '-'), foreground='#1976D2').grid(row=2, column=1, sticky=tk.W, pady=(5, 0))
|
||||
|
||||
|
||||
class OrbitInGUI:
|
||||
"""码头作业日志管理工具 GUI"""
|
||||
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title("码头作业日志管理工具 - OrbitIn")
|
||||
self.root.geometry("900x650")
|
||||
self.root.geometry("900x700")
|
||||
self.root.resizable(True, True)
|
||||
|
||||
# 设置样式
|
||||
@@ -172,7 +49,7 @@ class OrbitInGUI:
|
||||
# 获取数据按钮
|
||||
btn_fetch = ttk.Button(
|
||||
left_frame,
|
||||
text="📥 获取并处理数据",
|
||||
text="获取并处理数据",
|
||||
command=self.fetch_data,
|
||||
width=20
|
||||
)
|
||||
@@ -180,7 +57,7 @@ class OrbitInGUI:
|
||||
|
||||
btn_fetch_debug = ttk.Button(
|
||||
left_frame,
|
||||
text="📥 获取 (Debug模式)",
|
||||
text="获取 (Debug模式)",
|
||||
command=self.fetch_debug,
|
||||
width=20
|
||||
)
|
||||
@@ -201,7 +78,7 @@ class OrbitInGUI:
|
||||
|
||||
btn_report = ttk.Button(
|
||||
left_frame,
|
||||
text="📊 生成日报",
|
||||
text="生成日报",
|
||||
command=self.generate_report,
|
||||
width=20
|
||||
)
|
||||
@@ -209,7 +86,7 @@ class OrbitInGUI:
|
||||
|
||||
btn_report_today = ttk.Button(
|
||||
left_frame,
|
||||
text="📊 今日日报",
|
||||
text="今日日报",
|
||||
command=self.generate_today_report,
|
||||
width=20
|
||||
)
|
||||
@@ -236,7 +113,7 @@ class OrbitInGUI:
|
||||
|
||||
btn_unaccounted = ttk.Button(
|
||||
left_frame,
|
||||
text="➕ 添加",
|
||||
text="添加",
|
||||
command=self.add_unaccounted,
|
||||
width=20
|
||||
)
|
||||
@@ -248,7 +125,7 @@ class OrbitInGUI:
|
||||
# 数据库统计
|
||||
btn_stats = ttk.Button(
|
||||
left_frame,
|
||||
text="📈 数据库统计",
|
||||
text="数据库统计",
|
||||
command=self.show_stats,
|
||||
width=20
|
||||
)
|
||||
@@ -257,7 +134,7 @@ class OrbitInGUI:
|
||||
# 清空输出按钮
|
||||
btn_clear = ttk.Button(
|
||||
left_frame,
|
||||
text="🗑️ 清空输出",
|
||||
text="清空输出",
|
||||
command=self.clear_output,
|
||||
width=20
|
||||
)
|
||||
@@ -270,9 +147,25 @@ class OrbitInGUI:
|
||||
status_label = ttk.Label(right_frame, textvariable=self.status_var)
|
||||
status_label.pack(anchor=tk.W)
|
||||
|
||||
# 日报显示框架
|
||||
self.report_frame = ReportFrame(right_frame)
|
||||
self.report_frame.pack(fill=tk.X, pady=(5, 10))
|
||||
# 日报完整内容(可复制)
|
||||
ttk.Label(right_frame, text="日报内容 (可复制):").pack(anchor=tk.W, pady=(5, 0))
|
||||
|
||||
# 完整日报文本框(可编辑和复制)
|
||||
self.report_text = scrolledtext.ScrolledText(
|
||||
right_frame,
|
||||
wrap=tk.WORD,
|
||||
font=('SimHei', 10),
|
||||
bg='white',
|
||||
height=18
|
||||
)
|
||||
self.report_text.pack(fill=tk.X, pady=(5, 10))
|
||||
|
||||
# 按钮栏
|
||||
btn_bar = ttk.Frame(right_frame)
|
||||
btn_bar.pack(fill=tk.X, pady=(0, 10))
|
||||
|
||||
ttk.Button(btn_bar, text="复制日报", command=self.copy_report).pack(side=tk.LEFT, padx=(0, 5))
|
||||
ttk.Button(btn_bar, text="复制全部", command=self.copy_all).pack(side=tk.LEFT)
|
||||
|
||||
# 输出文本框
|
||||
ttk.Label(right_frame, text="日志输出:").pack(anchor=tk.W)
|
||||
@@ -281,12 +174,13 @@ class OrbitInGUI:
|
||||
wrap=tk.WORD,
|
||||
font=('Consolas', 9),
|
||||
bg='#f5f5f5',
|
||||
height=10
|
||||
height=8
|
||||
)
|
||||
self.output_text.pack(fill=tk.BOTH, expand=True, pady=(5, 0))
|
||||
|
||||
# 绑定快捷键
|
||||
self.root.bind('<Control-Return>', lambda e: self.fetch_data())
|
||||
self.root.bind('<Control-c>', lambda e: self.copy_report() if self.report_text.focus_get() else None)
|
||||
|
||||
# 初始消息
|
||||
self.log_message("码头作业日志管理工具 - OrbitIn")
|
||||
@@ -299,7 +193,7 @@ class OrbitInGUI:
|
||||
def log_message(self, message, is_error=False):
|
||||
"""输出日志消息"""
|
||||
timestamp = datetime.now().strftime('%H:%M:%S')
|
||||
prefix = "❌" if is_error else "📝"
|
||||
prefix = "[ERROR]" if is_error else "[INFO]"
|
||||
self.output_text.insert(tk.END, f"[{timestamp}] {prefix} {message}\n")
|
||||
self.output_text.see(tk.END)
|
||||
self.root.update()
|
||||
@@ -314,6 +208,21 @@ class OrbitInGUI:
|
||||
self.status_var.set(status)
|
||||
self.root.update()
|
||||
|
||||
def copy_report(self):
|
||||
"""复制日报内容"""
|
||||
self.report_text.tag_add(tk.SEL, "1.0", tk.END)
|
||||
self.report_text.event_generate("<<Copy>>")
|
||||
self.report_text.tag_remove(tk.SEL, "1.0", tk.END)
|
||||
self.log_message("日报已复制到剪贴板")
|
||||
|
||||
def copy_all(self):
|
||||
"""复制完整内容"""
|
||||
content = self.report_text.get("1.0", tk.END).strip()
|
||||
if content:
|
||||
self.root.clipboard_clear()
|
||||
self.root.clipboard_append(content)
|
||||
self.log_message("完整日报已复制到剪贴板")
|
||||
|
||||
def fetch_data(self):
|
||||
"""获取并处理数据"""
|
||||
self.set_status("正在获取数据...")
|
||||
@@ -446,15 +355,16 @@ class OrbitInGUI:
|
||||
report = g.generate_report(date)
|
||||
g.close()
|
||||
|
||||
# 在日报文本框中显示(可复制)
|
||||
self.report_text.delete("1.0", tk.END)
|
||||
self.report_text.insert("1.0", report)
|
||||
|
||||
# 在日志中显示原始内容
|
||||
self.log_message("")
|
||||
self.log_message("=" * 40)
|
||||
self.log_message(report)
|
||||
self.log_message("=" * 40)
|
||||
|
||||
# 在可视化区域显示
|
||||
self.report_frame.display_report(report, date)
|
||||
|
||||
self.set_status("完成")
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user