/
severin_i
/
Tech_pause
Обзор
Документация
Войти
/
severin_i
/
Tech_pause
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
app.py
349 строк
14 KB
severin
Первая версия. Приложение собирает инфу из ПУЖЦ, вытаскивает нужное и оформляет в виде таблицы. Можно копировать, вставлять куда надо
28 апр 2026, 12:13
28 апр 2026, 12:13
5957229
Код
Авторство
О чём код?
import json import tkinter as tk from tkinter import filedialog, messagebox from tkinter import ttk from datetime import datetime from pathlib import Path class JSONProcessorApp: def __init__(self, root): self.root = root self.root.title("JSON File Processor - RFC Reports") self.root.geometry("1400x800") # Main frame main_frame = ttk.Frame(root, padding="10") main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # Button to load JSON file self.load_button = ttk.Button( main_frame, text="Загрузить JSON файл", command=self.load_json_file ) self.load_button.grid(row=0, column=0, pady=10) # Label to show file path self.file_label = ttk.Label(main_frame, text="Файл не выбран") self.file_label.grid(row=0, column=1, padx=10) # Notebook for tabs self.notebook = ttk.Notebook(main_frame) self.notebook.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10) # Configure grid weights main_frame.columnconfigure(0, weight=1) main_frame.columnconfigure(1, weight=1) main_frame.rowconfigure(1, weight=1) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.data = None self.tables_data = {} def load_json_file(self): """Load and process JSON file""" file_path = filedialog.askopenfilename( title="Выберите JSON файл", filetypes=[("JSON files", "*.json"), ("All files", "*.*")] ) if file_path: self.file_label.config(text=f"Загружен: {Path(file_path).name}") try: with open(file_path, 'r', encoding='utf-8') as file: self.data = json.load(file) self.process_data() messagebox.showinfo("Успех", "Файл успешно загружен и обработан!") except Exception as e: messagebox.showerror("Ошибка", f"Ошибка при загрузке файла: {str(e)}") def process_data(self): """Process JSON data and create tables""" # Clear existing tabs for tab in self.notebook.tabs(): self.notebook.forget(tab) # Table 5: Перечень установленных версий ППО table5_data = self.create_table5_data() self.tables_data['Таблица 5'] = table5_data self.create_table_tab(table5_data, "Таблица 5 - Перечень установленных версий ППО") # Table 6: Работы по администированию table6_data = self.create_table6_data() self.tables_data['Таблица 6'] = table6_data self.create_table_tab(table6_data, "Таблица 6 - Работы по администированию") # Table 9: Список запланированных технологических пауз table9_data = self.create_table9_data() self.tables_data['Таблица 9'] = table9_data self.create_table_tab(table9_data, "Таблица 9 - Список запланированных технологических пауз") def extract_date_from_startTechPause(self, date_str): """Extract YYYYMMDD from startTechPause field""" try: dt = datetime.fromisoformat(date_str.replace('Z', '+00:00')) return dt.strftime("%Y%m%d") except: return "" def extract_date_from_createdDate(self, date_str): """Extract DD.MM.YYYY from createdDate field""" try: dt = datetime.fromisoformat(date_str.replace('Z', '+00:00')) return dt.strftime("%d.%m.%Y") except: return "" def format_datetime_for_display(self, date_str): """Format datetime to DD.MM.YYYY HH:MM""" try: dt = datetime.fromisoformat(date_str.replace('Z', '+00:00')) return dt.strftime("%d.%m.%Y %H:%M") except: return date_str def calculate_duration_hours(self, start_str, end_str): """Calculate duration in hours between two datetime strings""" try: start = datetime.fromisoformat(start_str.replace('Z', '+00:00')) end = datetime.fromisoformat(end_str.replace('Z', '+00:00')) duration = (end - start).total_seconds() / 3600 # Return without units, remove .0 if decimal part is 0 if duration == int(duration): return str(int(duration)) else: return f"{duration:.2f}".rstrip('0').rstrip('.') except: return "0" def calculate_duration_minutes(self, start_str, end_str): """Calculate duration in minutes between two datetime strings""" try: start = datetime.fromisoformat(start_str.replace('Z', '+00:00')) end = datetime.fromisoformat(end_str.replace('Z', '+00:00')) duration = (end - start).total_seconds() / 60 # Return without units, remove .0 if decimal part is 0 if duration == int(duration): return str(int(duration)) else: return f"{duration:.2f}".rstrip('0').rstrip('.') except: return "0" def get_subsystem_name(self, function_field): """Convert function field to subsystem name""" if "ПФК_ВГФК" in function_field: return "ПФК ВГФК" elif "ПФК_АП" in function_field: return "ПФК АП" else: return function_field def create_table5_data(self): """Create data for Table 5""" filtered_data = [item for item in self.data if item.get('rfcType') == 'ППО'] # Sort by keyNum filtered_data.sort(key=lambda x: x.get('keyNum', '')) table_data = [] for idx, item in enumerate(filtered_data, start=1): duration_hours = self.calculate_duration_hours( item.get('startTechPause', ''), item.get('endTechPause', '') ) version = self.extract_date_from_startTechPause(item.get('startTechPause', '')) table_data.append({ '№': idx, 'RFC': item.get('keyNum', ''), 'Подсистема': self.get_subsystem_name(item.get('function', '')), 'Статус': item.get('status', ''), 'Версия': version, 'Длительность': duration_hours }) return table_data def create_table6_data(self): """Create data for Table 6""" filtered_data = [item for item in self.data if item.get('rfcType') == 'БПО'] # Sort by keyNum filtered_data.sort(key=lambda x: x.get('keyNum', '')) table_data = [] for idx, item in enumerate(filtered_data, start=1): duration_hours = self.calculate_duration_hours( item.get('startTechPause', ''), item.get('endTechPause', '') ) date_created = self.extract_date_from_createdDate(item.get('createdDate', '')) table_data.append({ '№': idx, 'Описание работ': item.get('workReasonsDescr', ''), '№ Заявки': item.get('keyNum', ''), 'Дата': date_created, 'Группа назначения': 'ЦА Группа поддержки ППО ПФК', 'Статус': item.get('status', ''), 'SLA Нарушено': 'Нет', 'Длительность (ч)': duration_hours }) return table_data def create_table9_data(self): """Create data for Table 9""" table_data = [] for item in self.data: duration_minutes = self.calculate_duration_minutes( item.get('startTechPause', ''), item.get('endTechPause', '') ) table_data.append({ 'RFC': item.get('keyNum', ''), 'Начало технологической паузы': self.format_datetime_for_display(item.get('startTechPause', '')), 'Окончание технологической паузы': self.format_datetime_for_display(item.get('endTechPause', '')), 'Длительность (мин)': duration_minutes }) # Sort by RFC table_data.sort(key=lambda x: x.get('RFC', '')) return table_data def copy_selection(self, tree, event=None): """Copy selected cells to clipboard as tab-separated text""" selected_items = tree.selection() if not selected_items: return # Get all columns columns = tree['columns'] # Build clipboard data clipboard_data = [] # Add header headers = [tree.heading(col)['text'] for col in columns] clipboard_data.append('\t'.join(headers)) # Add data rows for item in selected_items: values = tree.item(item)['values'] # Convert all values to string and handle None str_values = [str(v) if v is not None else '' for v in values] clipboard_data.append('\t'.join(str_values)) # Copy to clipboard self.root.clipboard_clear() self.root.clipboard_append('\n'.join(clipboard_data)) # Optional: Show brief feedback self.root.title(f"Скопировано {len(selected_items)} строк") self.root.after(2000, lambda: self.root.title("JSON File Processor - RFC Reports")) def create_table_tab(self, data, title): """Create a tab with a table from the data""" if not data: tab = ttk.Frame(self.notebook) self.notebook.add(tab, text=title[:30]) label = ttk.Label(tab, text="Нет данных для отображения", font=('Arial', 12)) label.pack(expand=True, fill='both', padx=20, pady=20) return # Create frame for the tab tab = ttk.Frame(self.notebook) self.notebook.add(tab, text=title[:40]) # Create frame for treeview and scrollbars tree_frame = ttk.Frame(tab) tree_frame.pack(fill='both', expand=True, padx=5, pady=5) # Create scrollbars vsb = ttk.Scrollbar(tree_frame, orient="vertical") hsb = ttk.Scrollbar(tree_frame, orient="horizontal") # Create treeview columns = list(data[0].keys()) tree = ttk.Treeview(tree_frame, columns=columns, show='headings', yscrollcommand=vsb.set, xscrollcommand=hsb.set) vsb.config(command=tree.yview) hsb.config(command=tree.xview) # Configure columns for col in columns: tree.heading(col, text=col) # Set column width based on content max_width = len(col) * 10 for row in data: cell_value = str(row.get(col, '')) max_width = max(max_width, len(cell_value) * 8) tree.column(col, width=min(max_width, 300), minwidth=50) # Insert data for row in data: values = [row.get(col, '') for col in columns] tree.insert('', 'end', values=values) # Bind copy event tree.bind('<Control-c>', lambda e: self.copy_selection(tree)) tree.bind('<Control-C>', lambda e: self.copy_selection(tree)) # Add right-click context menu for copy context_menu = tk.Menu(tree, tearoff=0) context_menu.add_command(label="Копировать", command=lambda: self.copy_selection(tree)) def show_context_menu(event): # Select the row under cursor if not already selected item = tree.identify_row(event.y) if item: tree.selection_set(item) context_menu.post(event.x_root, event.y_root) tree.bind('<Button-3>', show_context_menu) # Pack elements tree.grid(row=0, column=0, sticky='nsew') vsb.grid(row=0, column=1, sticky='ns') hsb.grid(row=1, column=0, sticky='ew') tree_frame.grid_rowconfigure(0, weight=1) tree_frame.grid_columnconfigure(0, weight=1) # Add info frame with controls info_frame = ttk.Frame(tab) info_frame.pack(fill='x', pady=5) # Total rows counter info_label = ttk.Label(info_frame, text=f"Всего записей: {len(data)}", font=('Arial', 10, 'italic')) info_label.pack(side='left', padx=10) # Select all button select_all_btn = ttk.Button(info_frame, text="Выделить всё", command=lambda: tree.selection_set(tree.get_children())) select_all_btn.pack(side='left', padx=5) # Copy button copy_btn = ttk.Button(info_frame, text="Копировать выделенное (Ctrl+C)", command=lambda: self.copy_selection(tree)) copy_btn.pack(side='left', padx=5) # Instruction label instruction_label = ttk.Label(info_frame, text="Совет: Для копирования выделите строки мышью и нажмите Ctrl+C или используйте кнопки", font=('Arial', 8), foreground='gray') instruction_label.pack(side='right', padx=10) def main(): root = tk.Tk() app = JSONProcessorApp(root) root.mainloop() if __name__ == "__main__": main()