diff --git a/dokogen/ui.py b/dokogen/ui.py index b0a4c2d..a0c7173 100644 --- a/dokogen/ui.py +++ b/dokogen/ui.py @@ -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("", + 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: