feat: вкладка «Бумажные документы» + импорт из опросника
- Новая вкладка: название документа + место хранения, добавить/удалить
- Импорт из опросника: «Названия документов» (строка 61) и «Место
хранения» (строка 62) → цикл {{paper_documents}} ({{document}}/{{storage}})
- Сохранение/автосохранение/генерация собирают данные вкладки
- Загрузка файла проекта восстанавливает список документов
This commit is contained in:
+129
@@ -116,6 +116,7 @@ class DokoGenApp:
|
||||
self._build_is_tab()
|
||||
self._build_commission_tab()
|
||||
self._build_users_tab()
|
||||
self._build_paper_tab()
|
||||
self._build_generation_tab()
|
||||
self._build_log_tab()
|
||||
|
||||
@@ -548,6 +549,102 @@ class DokoGenApp:
|
||||
if emp['position'] or emp['fio']:
|
||||
self.model.employees_access.append(emp)
|
||||
|
||||
# ---------- ВКЛАДКА "БУМАЖНЫЕ ДОКУМЕНТЫ" ----------
|
||||
def _build_paper_tab(self):
|
||||
tab = ttk.Frame(self.notebook)
|
||||
self.notebook.add(tab, text="Бумажные документы")
|
||||
|
||||
canvas = tk.Canvas(tab, highlightthickness=0)
|
||||
scrollbar = ttk.Scrollbar(tab, orient=tk.VERTICAL, command=canvas.yview)
|
||||
scrollable = ttk.Frame(canvas)
|
||||
scrollable.bind("<Configure>",
|
||||
lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
|
||||
canvas.create_window((0, 0), window=scrollable, anchor="nw")
|
||||
canvas.configure(yscrollcommand=scrollbar.set)
|
||||
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
|
||||
frame = ttk.Frame(scrollable, padding=10)
|
||||
frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
ttk.Label(frame, text="Бумажные носители ПДн (документы)",
|
||||
font=('Arial', 11, 'bold')).pack(anchor=tk.W, pady=(0, 10))
|
||||
|
||||
# Заголовки
|
||||
header = ttk.Frame(frame)
|
||||
header.pack(fill=tk.X)
|
||||
for w, col in [(45, "Название документа"), (45, "Место хранения")]:
|
||||
ttk.Label(header, text=col, font=('', 9, 'bold'),
|
||||
width=w, anchor=tk.W).pack(side=tk.LEFT, padx=2)
|
||||
|
||||
self._paper_frame = ttk.Frame(frame)
|
||||
self._paper_frame.pack(fill=tk.X, pady=5)
|
||||
|
||||
btn_frame = ttk.Frame(frame)
|
||||
btn_frame.pack(fill=tk.X, pady=5)
|
||||
ttk.Button(btn_frame, text="+ Добавить документ",
|
||||
command=self._add_paper_row_ui).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(btn_frame, text="- Удалить выбранный",
|
||||
command=self._delete_paper_selected).pack(side=tk.LEFT, padx=2)
|
||||
|
||||
self._paper_count_label = ttk.Label(frame, text="Добавлено: 0")
|
||||
self._paper_count_label.pack(anchor=tk.W, pady=5)
|
||||
|
||||
self._paper_entries = []
|
||||
# Загрузка существующих
|
||||
for p in self.model.paper_documents_list:
|
||||
self._add_paper_row(p.name, p.storage)
|
||||
self._update_paper_count()
|
||||
|
||||
def _add_paper_row(self, name="", storage=""):
|
||||
"""Добавляет одну строку документа."""
|
||||
row = ttk.Frame(self._paper_frame)
|
||||
row.pack(fill=tk.X, pady=2)
|
||||
|
||||
name_entry = ttk.Entry(row, width=45)
|
||||
name_entry.insert(0, name)
|
||||
name_entry.pack(side=tk.LEFT, padx=2)
|
||||
|
||||
storage_entry = ttk.Entry(row, width=45)
|
||||
storage_entry.insert(0, storage)
|
||||
storage_entry.pack(side=tk.LEFT, padx=2)
|
||||
|
||||
del_btn = ttk.Button(row, text="✖", width=3,
|
||||
command=lambda: self._delete_paper_row(row))
|
||||
del_btn.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
self._paper_entries.append((row, name_entry, storage_entry))
|
||||
self._update_paper_count()
|
||||
|
||||
def _add_paper_row_ui(self):
|
||||
self._add_paper_row()
|
||||
|
||||
def _delete_paper_row(self, row_frame):
|
||||
self._paper_entries = [e for e in self._paper_entries if e[0] != row_frame]
|
||||
row_frame.destroy()
|
||||
self._update_paper_count()
|
||||
|
||||
def _delete_paper_selected(self):
|
||||
if self._paper_entries:
|
||||
row_frame = self._paper_entries[-1][0]
|
||||
self._delete_paper_row(row_frame)
|
||||
|
||||
def _update_paper_count(self):
|
||||
count = len(self._paper_entries)
|
||||
if hasattr(self, '_paper_count_label'):
|
||||
self._paper_count_label.config(text=f"Добавлено: {count}")
|
||||
|
||||
def _collect_paper_documents(self):
|
||||
"""Собирает данные бумажных документов из GUI в модель."""
|
||||
self.model.paper_documents_list.clear()
|
||||
for row, name_e, storage_e in self._paper_entries:
|
||||
name = name_e.get().strip()
|
||||
storage = storage_e.get().strip()
|
||||
if name or storage:
|
||||
self.model.paper_documents_list.append(
|
||||
PaperDocument(name=name, storage=storage)
|
||||
)
|
||||
|
||||
# ---------- ВКЛАДКА "ГЕНЕРАЦИЯ" ----------
|
||||
def _build_generation_tab(self):
|
||||
tab = ttk.Frame(self.notebook)
|
||||
@@ -710,6 +807,15 @@ class DokoGenApp:
|
||||
)
|
||||
self._update_emp_count()
|
||||
|
||||
# Бумажные документы
|
||||
if hasattr(self, '_paper_entries'):
|
||||
for row_frame, _, _ in self._paper_entries:
|
||||
row_frame.destroy()
|
||||
self._paper_entries.clear()
|
||||
for p in c.paper_documents_list:
|
||||
self._add_paper_row(p.name, p.storage)
|
||||
self._update_paper_count()
|
||||
|
||||
# Шаблоны
|
||||
self._on_templates_changed()
|
||||
|
||||
@@ -1163,6 +1269,7 @@ class DokoGenApp:
|
||||
self._collect_commission()
|
||||
self._collect_is()
|
||||
self._collect_employees()
|
||||
self._collect_paper_documents()
|
||||
|
||||
# Проверка
|
||||
if not self._validate_before_generate():
|
||||
@@ -1446,6 +1553,26 @@ class DokoGenApp:
|
||||
)
|
||||
self._update_emp_count()
|
||||
|
||||
# Бумажные документы (из «Названия документов» / «Место хранения»)
|
||||
if data.get('paperDocuments'):
|
||||
self.model.paper_documents_list.clear()
|
||||
names = [n.strip() for n in data['paperDocuments'].replace('\n', ';').split(';') if n.strip()]
|
||||
storages = [s.strip() for s in (data.get('paperStorage') or '').replace('\n', ';').split(';') if s.strip()]
|
||||
for i, name in enumerate(names):
|
||||
storage = storages[i] if i < len(storages) else (storages[0] if storages else '')
|
||||
self.model.paper_documents_list.append(
|
||||
PaperDocument(name=name, storage=storage)
|
||||
)
|
||||
# Обновляем GUI
|
||||
if hasattr(self, '_paper_entries'):
|
||||
for row_frame, _, _ in self._paper_entries:
|
||||
row_frame.destroy()
|
||||
self._paper_entries.clear()
|
||||
for p in self.model.paper_documents_list:
|
||||
self._add_paper_row(p.name, p.storage)
|
||||
self._update_paper_count()
|
||||
self.log(f" Бумажные документы: {len(self.model.paper_documents_list)} шт.")
|
||||
|
||||
self.log("✅ Импорт применён")
|
||||
self.root.after(0, _apply)
|
||||
|
||||
@@ -1490,6 +1617,7 @@ class DokoGenApp:
|
||||
self._collect_commission()
|
||||
self._collect_is()
|
||||
self._collect_employees()
|
||||
self._collect_paper_documents()
|
||||
try:
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.model.to_dict(), f, ensure_ascii=False, indent=2)
|
||||
@@ -1515,6 +1643,7 @@ class DokoGenApp:
|
||||
self._collect_commission()
|
||||
self._collect_is()
|
||||
self._collect_employees()
|
||||
self._collect_paper_documents()
|
||||
try:
|
||||
os.makedirs(os.path.dirname(self._autosave_path), exist_ok=True)
|
||||
with open(self._autosave_path, 'w', encoding='utf-8') as f:
|
||||
|
||||
Reference in New Issue
Block a user