Загрузка данных
import os
import tkinter as tk
from tkinter import messagebox, ttk
# ------------------------------------
import pandas as pd
from openpyxl import Workbook
from openpyxl.utils.dataframe import dataframe_to_rows
# --- ИСПРАВЛЕННЫЙ ИМПОРТ ---
# Теперь мы импортируем обе необходимые функции из базы данных
from modules.database_module import list_groups, list_indicators
def create_excel_template(groups_codes, output_filename):
"""
Функция создаёт шаблон Excel-файла для заданных групп и сохраняет его.
Все необходимые данные подгружаются за один проход без повторных запросов.
"""
wb = Workbook()
# Загружаем группы и их индикаторы со связями EAGER loading,
# чтобы избежать обращения к БД при обращении к .group или .matrices
all_groups_with_data = list_groups()
for group_code in groups_codes:
try:
# Ищем группу в уже загруженном списке
group = next((g for g in all_groups_with_data if g.code == group_code), None)
# Проверяем наличие группы и её индикаторов
indicators_list = getattr(group, 'indicators', []) if group else []
if not indicators_list:
continue
sheet_title = f"{group.name}"
ws = wb.create_sheet(title=sheet_title)
# --- ЗАГОЛОВКИ ТАБЛИЦЫ ---
ws.cell(row=1, column=1, value="№ п/п")
ws.cell(row=1, column=2, value="Показатель")
ws.cell(row=1, column=3, value="Код")
# --- ЗАПОЛНЯЕМ ТАБЛИЦУ ПОКАЗАТЕЛЕЙ ---
for idx, ind in enumerate(indicators_list):
ws.cell(row=idx + 2, column=1, value=str(idx + 1))
ws.cell(row=idx + 2, column=2, value=ind.name)
ws.cell(row=idx + 2, column=3, value=ind.code)
# --- ПОДГОТОВКА К СОЗДАНИЮ МАТРИЦЫ ---
start_col = 4
matrix_start_row = 1
for col_idx, label in enumerate([ind.code for ind in indicators_list]):
ws.cell(row=matrix_start_row, column=start_col + col_idx, value=label)
matrix_size = len(indicators_list)
# --- СОЗДАЕМ СЛОВАРЬ ДЛЯ БЫСТРОГО ПОИСКА ЗНАЧЕНИЙ ИЗ БАЗЫ ---
matrix_data_dict = {}
if group and hasattr(group, 'indicators') and group.indicators:
for ind in group.indicators: # Проходим по индикаторам конкретной группы
if hasattr(ind, 'matrices'):
for entry in ind.matrices: # Берём матрицы конкретного индикатора
matrix_data_dict[(entry.row, entry.col)] = entry.value
# --- ЗАПОЛНЯЕМ ЯЧЕЙКИ МАТРИЦЫ ДАННЫМИ ИЗ БАЗЫ ---
for r_idx in range(matrix_size):
for c_idx in range(matrix_size):
db_value = matrix_data_dict.get((r_idx, c_idx))
target_cell = ws.cell(
row=matrix_start_row + r_idx + 1,
column=start_col + c_idx
)
if db_value is not None:
target_cell.value = float(db_value)
elif r_idx == c_idx:
target_cell.value = 1.0
else:
target_cell.value = ""
except Exception as e:
print(f"Ошибка при обработке группы '{group_code}': {e}")
if "Sheet" in wb.sheetnames:
del wb["Sheet"]
wb.save(output_filename)
class ExportMatrixWindow(tk.Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.title("Создание файла для эксперта")
self.geometry("450x200")
main_frame = ttk.Frame(self)
main_frame.pack(padx=10, pady=10, fill="both", expand=True)
self.groups = []
self.selected_groups = []
self.num_experts = tk.IntVar()
tk.Label(main_frame, text="Группа:").grid(row=0, column=0, sticky="w")
self.group_var = tk.StringVar()
self.combobox = ttk.Combobox(
main_frame, textvariable=self.group_var, state="readonly"
)
self.combobox.grid(row=0, column=1, padx=(5, 10), sticky="ew")
self.refresh_groups()
add_group_btn = ttk.Button(
main_frame, text="Добавить группу", command=self.add_group
)
add_group_btn.grid(row=0, column=2, padx=(0, 10), sticky="e")
tk.Label(main_frame, text="Выбранные группы:").grid(row=1, column=0, sticky="w")
self.selected_groups_text = tk.Text(main_frame, width=30, height=4)
self.selected_groups_text.grid(
row=1, column=1, columnspan=2, pady=(5, 10), sticky="ew"
)
tk.Label(main_frame, text="Количество экспертов:").grid(
row=2, column=0, sticky="w"
)
self.experts_count_entry = ttk.Entry(main_frame, textvariable=self.num_experts)
self.experts_count_entry.grid(row=2, column=1, sticky="w")
remove_group_btn = ttk.Button(
main_frame, text="Удалить группу", command=self.remove_group
)
remove_group_btn.grid(row=2, column=2, sticky="e")
export_btn = ttk.Button(
main_frame, text="Экспортировать в Excel", command=self.export_to_excel
)
export_btn.grid(row=3, column=1, pady=(10, 0))
def refresh_groups(self):
self.groups = [grp.name for grp in list_groups()]
self.combobox.config(values=self.groups)
def add_group(self):
group_name = self.group_var.get()
if group_name and group_name.strip():
self.selected_groups.append(group_name)
self.selected_groups_text.insert(tk.END, f"{group_name}\n")
def remove_group(self):
if len(self.selected_groups) > 0:
last_group = self.selected_groups.pop(-1)
current_text = self.selected_groups_text.get("1.0", tk.END).strip()
updated_text = "\n".join(
line for line in current_text.split("\n") if line != last_group
)
self.selected_groups_text.delete("1.0", tk.END)
self.selected_groups_text.insert(tk.END, updated_text)
def export_to_excel(self):
"""Логика экспорта в Excel (ИСПРАВЛЕННАЯ ВЕРСИЯ)."""
selected_group_names = (
self.selected_groups_text.get("1.0", tk.END).strip().split("\n")
)
# Составляем список кодов групп на основе выбранных названий
groups_codes = []
all_db_groups = list_groups()
for name in selected_group_names:
if name:
group = next((g for g in all_db_groups if g.name == name), None)
if group:
groups_codes.append(group.code)
if not groups_codes:
messagebox.showwarning("Предупреждение", "Не выбрано ни одной группы.")
return
try:
num_experts = int(self.num_experts.get())
if num_experts <= 0:
raise ValueError
except Exception:
messagebox.showerror(
"Ошибка", "Количество экспертов должно быть положительным числом."
)
return
experts_folder = os.path.join(os.path.dirname(__file__), "..", "experts")
os.makedirs(experts_folder, exist_ok=True)
for expert_num in range(1, num_experts + 1):
output_filename = os.path.join(experts_folder, f"Эксперт_{expert_num}.xlsx")
create_excel_template(groups_codes, output_filename)
messagebox.showinfo(
title="Экспорт завершён",
message=f"Успешно создано {num_experts} файлов экспертов.\n\nРасположение файлов:\n{experts_folder}",
)