/
azerchaii
/
module3
Обзор
Документация
Войти
/
azerchaii
/
module3
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
IK_module3.py
334 строки
14 KB
admin
первая вариация проекта + тесты работы с таблицами ворд
24 апр 2025, 22:06
24 апр 2025, 22:06
f00701b
Код
Авторство
О чём код?
import os import json import shutil import pandas as pd import tkinter as tk from tkinter import filedialog, messagebox, ttk from docx import Document from datetime import datetime CONFIG_FILE = "config.json" # Загрузка конфигурации (пути к папкам и Excel-файл) def load_config(): if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, "r", encoding="utf-8") as f: return json.load(f) else: return {"template_folder": "", "output_parent_folder": "", "excel_filepath": ""} def save_config(): with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(config, f, indent=4, ensure_ascii=False) config = load_config() excluded_templates = {} # словарь: имя файла -> True/False (False - исключить) df = None excel_filepath = "" # --- Функции для работы с Excel --- def select_excel_file(): global df, excel_filepath filepath = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx;*.xls")]) if filepath: entry_excel.delete(0, tk.END) entry_excel.insert(0, filepath) config["excel_filepath"] = filepath save_config() excel_filepath = filepath load_excel_data(filepath) def load_excel_data(filepath): global df, excel_filepath excel_filepath = filepath try: df = pd.read_excel(filepath, dtype=str).fillna("-") listbox_rows.delete(0, tk.END) combo_existing['values'] = [] # обновим список для автозаполнения for index, row in df.iterrows(): row_text = f"Строка {index + 1}: {', '.join(row.astype(str))[:50]}..." listbox_rows.insert(tk.END, row_text) # Заполним combobox автозаполнения (например, краткое представление записи) values = [f"Строка {i + 1}" for i in range(len(df))] combo_existing['values'] = values except Exception as e: messagebox.showerror("Ошибка", f"Не удалось загрузить файл: {e}") # --- Функции для обработки Word-файлов --- def replace_text_in_paragraphs(paragraphs, replacements): for paragraph in paragraphs: for key, value in replacements.items(): placeholder = f"<{key}>" if placeholder in paragraph.text: paragraph.text = paragraph.text.replace(placeholder, str(value)) def replace_text_in_tables(tables, replacements): for table in tables: for row in table.rows: for cell in row.cells: for key, value in replacements.items(): placeholder = f"<{key}>" if placeholder in cell.text: cell.text = cell.text.replace(placeholder, str(value)) def process_documents(): global df if df is None: messagebox.showerror("Ошибка", "Сначала выберите Excel-файл") return # Определяем, какие записи обрабатывать rows_to_process = [] if var_process_all.get(): rows_to_process = list(range(len(df))) else: selected_indices = listbox_rows.curselection() if not selected_indices: messagebox.showerror("Ошибка", "Выберите одну или несколько строк из списка или отметьте 'Обработать все записи Excel'") return rows_to_process = selected_indices # Проверяем пути для шаблонов и сохранения template_folder = config.get("template_folder") if not template_folder or not os.path.exists(template_folder): messagebox.showerror("Ошибка", "Выберите папку с шаблонными Word-файлами в Настройках") return output_parent_folder = config.get("output_parent_folder") if not output_parent_folder or not os.path.exists(output_parent_folder): messagebox.showerror("Ошибка", "Выберите общую папку для сохранения обработок в Настройках") return # Создаем подпапку для данной обработки внутри общей папки output_folder = os.path.join(output_parent_folder, f"Documents_{datetime.now().strftime('%Y%m%d_%H%M%S')}") os.makedirs(output_folder, exist_ok=True) try: for row_index in rows_to_process: selected_row = df.iloc[row_index] replacements = dict(selected_row) # Для каждого файла в папке шаблонов, если он не исключён, производим обработку for filename in os.listdir(template_folder): if filename.endswith(".docx"): # Если файл отмечен как исключенный – пропускаем if filename in template_vars and not template_vars[filename].get(): continue doc_path = os.path.join(template_folder, filename) doc = Document(doc_path) replace_text_in_paragraphs(doc.paragraphs, replacements) replace_text_in_tables(doc.tables, replacements) # Создаем подпапку для данной строки внутри output_folder row_output_folder = os.path.join(output_folder, f"Row_{row_index + 1}") os.makedirs(row_output_folder, exist_ok=True) new_doc_path = os.path.join(row_output_folder, filename) doc.save(new_doc_path) messagebox.showinfo("Готово", f"Документы сохранены в {output_folder}") except Exception as e: messagebox.showerror("Ошибка", f"Не удалось обработать файлы: {e}") # --- Функции для настроек шаблонов и путей --- def select_template_folder(): path = filedialog.askdirectory() if path: config["template_folder"] = path entry_template.delete(0, tk.END) entry_template.insert(0, path) save_config() load_template_files() def select_output_parent_folder(): path = filedialog.askdirectory() if path: config["output_parent_folder"] = path entry_output.delete(0, tk.END) entry_output.insert(0, path) save_config() def load_template_files(): global template_vars # Очистка предыдущего списка for widget in frame_template_files.winfo_children(): widget.destroy() template_vars = {} folder = config.get("template_folder") if folder and os.path.exists(folder): files = [f for f in os.listdir(folder) if f.endswith(".docx")] for f in files: var = tk.BooleanVar(value=True) cb = tk.Checkbutton(frame_template_files, text=f, variable=var) cb.pack(anchor="w") template_vars[f] = var # --- Функции для добавления/редактирования записей в Excel --- def add_manual_entry(): if df is None: messagebox.showerror("Ошибка", "Сначала загрузите Excel-файл") return new_window = tk.Toplevel(root) new_window.title("Добавить новую запись") # Фрейм с автозаполнением frame_autofill = tk.Frame(new_window) frame_autofill.pack(pady=5) tk.Label(frame_autofill, text="Выбрать существующую запись для автозаполнения:").pack(side=tk.LEFT) combo = ttk.Combobox(frame_autofill, values=[f"Строка {i + 1}" for i in range(len(df))], state="readonly") combo.pack(side=tk.LEFT, padx=5) # Фрейм для ввода данных canvas = tk.Canvas(new_window, width=600) scrollbar = tk.Scrollbar(new_window, orient="vertical", command=canvas.yview) scrollable_frame = tk.Frame(canvas) scrollable_frame.bind( "<Configure>", lambda e: canvas.configure( scrollregion=canvas.bbox("all") ) ) canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set) canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y") entries = {} for i, column in enumerate(df.columns): tk.Label(scrollable_frame, text=column).grid(row=i, column=0, sticky="w", padx=5, pady=2) entry = tk.Entry(scrollable_frame, width=60) # увеличение ширины в 2 раза entry.grid(row=i, column=1, padx=5, pady=2) entries[column] = entry def autofill_record(event): sel = combo.get() if sel: # Получаем номер строки из выбранного значения index = int(sel.split()[1]) - 1 record = df.iloc[index] for col, entry in entries.items(): entry.delete(0, tk.END) entry.insert(0, record.get(col, "")) combo.bind("<<ComboboxSelected>>", autofill_record) def save_entry(): new_data = {col: entry.get() if entry.get() else "-" for col, entry in entries.items()} # Добавляем новую строку в DataFrame и сохраняем global df df = df._append(new_data, ignore_index=True) try: df.to_excel(excel_filepath, index=False) listbox_rows.insert(tk.END, f"Новая строка {len(df)}: {', '.join(new_data.values())[:50]}...") except Exception as e: messagebox.showerror("Ошибка", f"Не удалось сохранить запись в Excel: {e}") new_window.destroy() btn_save = tk.Button(new_window, text="Сохранить", command=save_entry) btn_save.pack(pady=10) # --- UI --- root = tk.Tk() root.title("Обработка документов") notebook = ttk.Notebook(root) notebook.pack(expand=True, fill="both") # Вкладка "Из Excel" frame_excel = tk.Frame(notebook) notebook.add(frame_excel, text="Из Excel") frame_top = tk.Frame(frame_excel) frame_top.pack(pady=10) btn_select_excel = tk.Button(frame_top, text="Выбрать Excel", command=select_excel_file) btn_select_excel.pack(side=tk.LEFT) # Увеличенное поле ввода (ширина увеличена) entry_excel = tk.Entry(frame_top, width=100) entry_excel.pack(side=tk.LEFT, padx=5) # Чекбокс для обработки всех записей var_process_all = tk.BooleanVar() chk_all = tk.Checkbutton(frame_excel, text="Обработать все записи Excel", variable=var_process_all) chk_all.pack(pady=5) # Listbox с возможностью множественного выбора (selectmode=MULTIPLE) listbox_rows = tk.Listbox(frame_excel, width=120, height=10, selectmode=tk.MULTIPLE) listbox_rows.pack(pady=10) btn_process = tk.Button(frame_excel, text="Обработать документы", command=process_documents) btn_process.pack(pady=10) # Вкладка "Новая запись" frame_new_entry = tk.Frame(notebook) notebook.add(frame_new_entry, text="Новая запись") btn_add_entry = tk.Button(frame_new_entry, text="Добавить новую запись", command=add_manual_entry) btn_add_entry.pack(pady=20) # Дополнительный combobox для автозаполнения (отображается в основной вкладке "Новая запись") tk.Label(frame_new_entry, text="Автозаполнение из существующей записи:").pack(pady=5) combo_existing = ttk.Combobox(frame_new_entry, state="readonly") combo_existing.pack(pady=5) # Вкладка "Настройки" frame_settings = tk.Frame(notebook) notebook.add(frame_settings, text="Настройки") # Поле для выбора папки с шаблонами frm_temp = tk.Frame(frame_settings) frm_temp.pack(fill="x", pady=5, padx=5) tk.Label(frm_temp, text="Папка с шаблонными Word-файлами:").pack(side=tk.LEFT) entry_template = tk.Entry(frm_temp, width=80) entry_template.pack(side=tk.LEFT, padx=5) btn_template = tk.Button(frm_temp, text="Выбрать папку", command=select_template_folder) btn_template.pack(side=tk.LEFT) # Поле для выбора общей папки для сохранения frm_output = tk.Frame(frame_settings) frm_output.pack(fill="x", pady=5, padx=5) tk.Label(frm_output, text="Общая папка для сохранения обработок:").pack(side=tk.LEFT) entry_output = tk.Entry(frm_output, width=80) entry_output.pack(side=tk.LEFT, padx=5) btn_output = tk.Button(frm_output, text="Выбрать папку", command=select_output_parent_folder) btn_output.pack(side=tk.LEFT) # Фрейм для списка шаблонов с чекбоксами (исключение отдельных файлов) frm_templates = tk.Frame(frame_settings) frm_templates.pack(fill="both", expand=True, padx=5, pady=5) tk.Label(frm_templates, text="Выберите шаблоны для обработки (отметьте для обработки):").pack(anchor="w") frame_template_files = tk.Frame(frm_templates) frame_template_files.pack(fill="both", expand=True) btn_refresh_templates = tk.Button(frame_settings, text="Обновить список шаблонов", command=load_template_files) btn_refresh_templates.pack(pady=5) # При запуске заполним поля из конфигурации if config.get("template_folder"): entry_template.insert(0, config["template_folder"]) load_template_files() if config.get("output_parent_folder"): entry_output.insert(0, config["output_parent_folder"]) if config.get("excel_filepath"): entry_excel.insert(0, config["excel_filepath"]) load_excel_data(config["excel_filepath"]) root.mainloop()