diff --git a/src/gui.py b/src/gui.py index ea70313..b8a315b 100644 --- a/src/gui.py +++ b/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('', lambda e: self.fetch_data()) + self.root.bind('', 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("<>") + 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: