/
valuevvik
/
wbAnalytics
Обзор
Документация
Войти
/
valuevvik
/
wbAnalytics
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
tkinter_app.py
273 строки
12 KB
valuevvik
initial commit
05 дек 2025, 17:36
05 дек 2025, 17:36
f514336
Код
Авторство
О чём код?
import tkinter as tk from tkinter import ttk, filedialog, messagebox import threading import os from datetime import datetime, timedelta # from config.settings import settings from services.storage_service import StorageReportService from storage.excel_manager import ExcelManager from models.wb_models import ReportType class WBReportApp: def __init__(self, root): self.root = root self.root.title("WB Analytics - Генератор отчетов") self.root.geometry("650x500") self.excel_manager = ExcelManager() self.current_service = None self.create_widgets() def create_widgets(self): main_frame = ttk.Frame(self.root, padding="10") main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # Тип отчета (НОВОЕ ПОЛЕ) ttk.Label(main_frame, text="Тип отчета:").grid(row=0, column=0, sticky=tk.W, pady=5) self.report_type_var = tk.StringVar(value=ReportType.STORAGE.value) report_types = [report_type.value for report_type in ReportType] self.report_type_combo = ttk.Combobox( main_frame, textvariable=self.report_type_var, values=report_types, state="readonly", width=30 ) self.report_type_combo.grid(row=0, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5) self.report_type_combo.bind('<<ComboboxSelected>>', self.on_report_type_change) # API ключ (теперь защищенный) # ttk.Label(main_frame, text="API ключ:").grid(row=1, column=0, sticky=tk.W, pady=5) # self.api_key_status = ttk.Label( # main_frame, # text="✅ Ключ загружен из защищенного файла", # width=50, # foreground="green" # ) # self.api_key_status.grid(row=1, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5) ttk.Label(main_frame, text="API ключ:").grid(row=1, column=0, sticky=tk.W, pady=5) # Поле ввода для API ключа self.api_key_entry = ttk.Entry( main_frame, width=50, show="*" # Скрывает вводимые символы (опционально) ) self.api_key_entry.grid(row=1, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5) # Даты ttk.Label(main_frame, text="Дата с:").grid(row=2, column=0, sticky=tk.W, pady=5) self.date_from_var = tk.StringVar() self.date_from_entry = ttk.Entry(main_frame, textvariable=self.date_from_var, width=20) self.date_from_entry.grid(row=2, column=1, sticky=tk.W, pady=5) ttk.Label(main_frame, text="Дата по:").grid(row=3, column=0, sticky=tk.W, pady=5) self.date_to_var = tk.StringVar() self.date_to_entry = ttk.Entry(main_frame, textvariable=self.date_to_var, width=20) self.date_to_entry.grid(row=3, column=1, sticky=tk.W, pady=5) # Установить даты по умолчанию default_date_to = datetime.now().strftime("%Y-%m-%d") default_date_from = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d") self.date_from_var.set(default_date_from) self.date_to_var.set(default_date_to) # Режим сохранения ttk.Label(main_frame, text="Режим сохранения:").grid(row=4, column=0, sticky=tk.W, pady=5) self.save_mode_var = tk.StringVar(value="new") ttk.Radiobutton(main_frame, text="Новый файл", variable=self.save_mode_var, value="new", command=self.toggle_save_mode).grid(row=4, column=1, sticky=tk.W) ttk.Radiobutton(main_frame, text="Добавить в файл", variable=self.save_mode_var, value="append", command=self.toggle_save_mode).grid(row=4, column=2, sticky=tk.W) # Файл для сохранения ttk.Label(main_frame, text="Файл для сохранения:").grid(row=5, column=0, sticky=tk.W, pady=5) self.file_path_var = tk.StringVar() self.file_path_entry = ttk.Entry(main_frame, textvariable=self.file_path_var, width=50) self.file_path_entry.grid(row=5, column=1, sticky=(tk.W, tk.E), pady=5) self.file_path_var.set("отчет_платное_хранение.xlsx") ttk.Button(main_frame, text="Обзор", command=self.browse_file).grid(row=5, column=2, padx=5) # Кнопки запуска button_frame = ttk.Frame(main_frame) button_frame.grid(row=6, column=0, columnspan=3, pady=20) self.run_button = ttk.Button( button_frame, text="Сгенерировать отчет", command=self.run_report ) self.run_button.pack(side=tk.LEFT, padx=5) # Прогресс self.progress = ttk.Progressbar(main_frame, mode='indeterminate') self.progress.grid(row=7, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5) # Лог ttk.Label(main_frame, text="Лог выполнения:").grid(row=8, column=0, sticky=tk.W, pady=5) self.log_text = tk.Text(main_frame, height=12, width=70) self.log_text.grid(row=9, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5) scrollbar = ttk.Scrollbar(main_frame, orient="vertical", command=self.log_text.yview) scrollbar.grid(row=9, column=3, sticky=(tk.N, tk.S)) self.log_text.configure(yscrollcommand=scrollbar.set) # Настройка растягивания main_frame.columnconfigure(1, weight=1) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) def on_report_type_change(self, event): """Обновляет интерфейс при смене типа отчета""" report_type = self.report_type_var.get() self.log(f"Выбран тип отчета: {report_type}") # Обновляем имя файла по умолчанию if report_type == ReportType.STORAGE.value: self.file_path_var.set("отчет_платное_хранение.xlsx") elif report_type == ReportType.SALES.value: self.file_path_var.set("отчет_продажи.xlsx") elif report_type == ReportType.ORDERS.value: self.file_path_var.set("отчет_заказы.xlsx") def toggle_save_mode(self): if self.save_mode_var.get() == "append": self.file_path_var.set("") self.log('🔁 Выбран режим: "Добавить данные в файл"') else: if not self.file_path_var.get(): self.on_report_type_change(None) self.log('📄 Выбран режим: "Новый файл"') def browse_file(self): if self.save_mode_var.get() == "append": filename = filedialog.askopenfilename( defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")] ) else: filename = filedialog.asksaveasfilename( defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")] ) if filename: self.file_path_var.set(filename) def log(self, message): self.log_text.insert(tk.END, f"{datetime.now().strftime('%H:%M:%S')} - {message}\n") self.log_text.see(tk.END) self.root.update_idletasks() def run_report(self): if not self.date_from_var.get() or not self.date_to_var.get(): messagebox.showerror("Ошибка", "Введите даты") return if not self.file_path_var.get(): messagebox.showerror("Ошибка", "Выберите файл для сохранения") return thread = threading.Thread(target=self.generate_report) thread.daemon = True thread.start() def generate_report(self): try: self.run_button.config(state='disabled') self.progress.start() self.log_text.delete(1.0, tk.END) report_type = self.report_type_var.get() self.log(f"🚀 Начало генерации отчета: {report_type}") # Выбор сервиса в зависимости от типа отчета if report_type == ReportType.STORAGE.value: self.current_service = StorageReportService(self.api_key_entry.get()) df = self.current_service.generate_report( self.date_from_var.get(), self.date_to_var.get(), log_callback=self.log ) else: # TODO: Добавить другие сервисы self.log(f"❌ Отчет '{report_type}' пока не реализован") messagebox.showwarning("В разработке", f"Отчет '{report_type}' находится в разработке") return # Сохраняем в Excel if report_type == ReportType.STORAGE.value: success = self.save_storage_report(df) else: success = self.excel_manager.save_to_excel( df, self.file_path_var.get(), self.save_mode_var.get(), log_callback=self.log ) if success: self.log("✅ Отчет успешно сохранен!") messagebox.showinfo("Успех", "Отчет успешно сгенерирован и сохранен!") else: self.log("❌ Ошибка при сохранении отчета") messagebox.showerror("Ошибка", "Не удалось сохранить отчет") except Exception as e: self.log(f"💥 Критическая ошибка: {str(e)}") messagebox.showerror("Ошибка", f"Произошла ошибка: {str(e)}") finally: self.progress.stop() self.run_button.config(state='normal') def save_storage_report(self, df): """Специфичная логика сохранения для отчета по хранению""" if self.save_mode_var.get() == "append" and os.path.exists(self.file_path_var.get()): self.log("🔁 Режим добавления данных...") try: existing_df = self.excel_manager.read_existing_data( self.file_path_var.get(), log_callback=self.log ) filtered_df = self.current_service.filter_new_data( existing_df, df, log_callback=self.log ) if len(filtered_df) > 0: success = self.excel_manager._append_to_excel( filtered_df, self.file_path_var.get(), log_callback=self.log ) if success: self.log(f"✅ Данные успешно добавлены в файл: {self.file_path_var.get()}") return True else: self.log("❌ Ошибка при добавлении данных в файл") return False else: self.log("ℹ️ Нет новых данных для добавления") return True except Exception as e: self.log(f"❌ Ошибка при чтении существующего файла: {str(e)}") return self.excel_manager._create_new_excel( df, self.file_path_var.get(), log_callback=self.log ) else: return self.excel_manager._create_new_excel( df, self.file_path_var.get(), log_callback=self.log )