From aae66dcca1bb4604a6bf071d16af0c2b1e21cdd0 Mon Sep 17 00:00:00 2001 From: prog1764 Date: Tue, 4 Aug 2026 16:56:51 +0400 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B2=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA?= =?UTF-8?q?=D0=B0=20=C2=AB=D0=9F=D0=9E=C2=BB=20=E2=80=94=20=D1=81=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=20=D0=9E=D0=A1/=D0=B0=D0=BF?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D0=B0=D1=82=D0=BD=D1=8B=D1=85=20=D1=81=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D1=81=D1=82=D0=B2/=D0=BF=D1=80=D0=B8=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D0=B4=D0=BD=D1=8B=D1=85=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=BC=20+=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=BE=D0=BA=D0=BD=D0=BE=20=D1=80=D0=B5=D0=B4=D0=B0?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - словари: hw_sw.json, os_sw.json, app_sw.json - кнопка «📚 Из словаря» у каждого списка ПО (мультивыбор) - большое окно добавления/редактирования позиции (560x220, многострочное) --- dokogen/dictionaries/app_sw.json | 16 +++++++ dokogen/dictionaries/hw_sw.json | 16 +++++++ dokogen/dictionaries/os_sw.json | 15 +++++++ dokogen/ui.py | 73 +++++++++++++++++++++++++++----- 4 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 dokogen/dictionaries/app_sw.json create mode 100644 dokogen/dictionaries/hw_sw.json create mode 100644 dokogen/dictionaries/os_sw.json diff --git a/dokogen/dictionaries/app_sw.json b/dokogen/dictionaries/app_sw.json new file mode 100644 index 0000000..e43a91b --- /dev/null +++ b/dokogen/dictionaries/app_sw.json @@ -0,0 +1,16 @@ +[ + "Microsoft Office (уточнить версию)", + "LibreOffice", + "OpenOffice", + "1С:Предприятие 8.3 (уточнить конфигурацию)", + "Контур.Экстерн", + "СБИС", + "Kaspersky Endpoint Security", + "Kaspersky Security Center", + "Почтовый клиент (уточнить)", + "Браузер (уточнить)", + "СЭД (уточнить систему)", + "АРМ оператора (уточнить)", + "СКУД ПО (уточнить)", + "Видеонаблюдение ПО (уточнить)" +] diff --git a/dokogen/dictionaries/hw_sw.json b/dokogen/dictionaries/hw_sw.json new file mode 100644 index 0000000..1c52c42 --- /dev/null +++ b/dokogen/dictionaries/hw_sw.json @@ -0,0 +1,16 @@ +[ + "Сервер (уточнить модель)", + "АРМ пользователя (уточнить конфигурацию)", + "Ноутбук (уточнить модель)", + "Коммутатор (уточнить модель)", + "Маршрутизатор (уточнить модель)", + "Межсетевой экран (уточнить модель)", + "Видеорегистратор (уточнить модель)", + "Видеокамера (уточнить модель)", + "Контроллер доступа СКУД (уточнить модель)", + "Шлагбаум (уточнить модель)", + "Турникет (уточнить модель)", + "Сетевое хранилище (NAS) (уточнить модель)", + "Беспроводная точка доступа (уточнить модель)", + "ИБП (уточнить модель)" +] diff --git a/dokogen/dictionaries/os_sw.json b/dokogen/dictionaries/os_sw.json new file mode 100644 index 0000000..ea8c544 --- /dev/null +++ b/dokogen/dictionaries/os_sw.json @@ -0,0 +1,15 @@ +[ + "Windows 10 Pro 64bit", + "Windows 11 Pro", + "Windows Server 2019", + "Windows Server 2022", + "Astra Linux Special Edition", + "РЕД ОС", + "Альт Рабочая станция", + "Альт Сервер", + "Ubuntu Server", + "CentOS", + "Debian", + "MS-DOS (для АРМ специального назначения)", + "Android (для планшетов/КПК)" +] diff --git a/dokogen/ui.py b/dokogen/ui.py index bfdbb9c..42bf218 100644 --- a/dokogen/ui.py +++ b/dokogen/ui.py @@ -916,11 +916,11 @@ class DokoGenApp: sw_frame.pack(fill=tk.BOTH, expand=True) sw_fields = [ - ("ПО и аппаратные средства (модели, производители, количество):", "is_hw_sw_listbox"), - ("Операционные системы:", "is_os_sw_listbox"), - ("Прикладные программы (MS Office, OpenOffice и пр.):", "is_app_sw_listbox"), + ("ПО и аппаратные средства (модели, производители, количество):", "is_hw_sw_listbox", "hw_sw.json"), + ("Операционные системы:", "is_os_sw_listbox", "os_sw.json"), + ("Прикладные программы (MS Office, OpenOffice и пр.):", "is_app_sw_listbox", "app_sw.json"), ] - for i, (label, attr) in enumerate(sw_fields): + for i, (label, attr, dict_name) in enumerate(sw_fields): row = i * 2 ttk.Label(sw_frame, text=label).grid(row=row, column=0, sticky=tk.W, pady=(4, 0)) box = tk.Listbox(sw_frame, height=4, exportselection=False) @@ -936,6 +936,8 @@ class DokoGenApp: command=lambda a=attr: self._del_sw_item(getattr(self, a))).pack(fill=tk.X, pady=1) ttk.Button(btn, text="✏️ Редактировать", command=lambda a=attr: self._edit_sw_item(getattr(self, a))).pack(fill=tk.X, pady=1) + ttk.Button(btn, text="📚 Из словаря", + command=lambda a=attr, d=dict_name: self._select_sw_from_dict(getattr(self, a), d)).pack(fill=tk.X, pady=1) setattr(self, attr, box) sw_frame.columnconfigure(0, weight=1) @@ -1564,11 +1566,61 @@ class DokoGenApp: if item: self.defense_tools_listbox.insert(tk.END, item) + def _select_sw_from_dict(self, listbox, dict_name): + """Выбор позиций из словаря (JSON) — можно несколько.""" + import json + dict_path = os.path.join(os.path.dirname(__file__), 'dictionaries', dict_name) + try: + with open(dict_path, 'r', encoding='utf-8') as f: + items = json.load(f) + title = "Выбор из словаря" + self._select_from_dialog(title, items, listbox) + except Exception as e: + messagebox.showerror("Ошибка", f"Не удалось загрузить словарь: {e}") + + def _sw_dialog(self, title, initial=""): + """Большое окно для ввода/редактирования позиции ПО.""" + dialog = tk.Toplevel(self.root) + dialog.title(title) + dialog.geometry("560x220") + dialog.transient(self.root) + dialog.grab_set() + dialog.resizable(True, True) + + frame = ttk.Frame(dialog, padding=10) + frame.pack(fill=tk.BOTH, expand=True) + + ttk.Label(frame, text="Текст позиции:").pack(anchor=tk.W) + txt = tk.Text(frame, width=70, height=6, wrap=tk.WORD) + txt.pack(fill=tk.BOTH, expand=True, pady=5) + txt.insert('1.0', initial) + txt.focus_set() + + result = {} + + def _ok(): + result['val'] = txt.get('1.0', 'end-1c').strip() + dialog.destroy() + + def _cancel(): + result['val'] = None + dialog.destroy() + + btn_frame = ttk.Frame(frame) + btn_frame.pack(fill=tk.X) + ttk.Button(btn_frame, text="✅ ОК", command=_ok).pack(side=tk.RIGHT, padx=2) + ttk.Button(btn_frame, text="Отмена", command=_cancel).pack(side=tk.RIGHT, padx=2) + + dialog.bind('', lambda e: _ok()) + dialog.bind('', lambda e: _cancel()) + dialog.wait_window() + return result.get('val') + def _add_sw_item(self, listbox): - """Добавить строку в список ПО.""" - item = simpledialog.askstring("Добавить", "Введите позицию:") + """Добавить строку в список ПО (большое окно).""" + item = self._sw_dialog("Добавить позицию") if item: - listbox.insert(tk.END, item.strip()) + listbox.insert(tk.END, item) def _del_sw_item(self, listbox): """Удалить выбранную строку из списка ПО.""" @@ -1577,17 +1629,16 @@ class DokoGenApp: listbox.delete(sel[0]) def _edit_sw_item(self, listbox): - """Редактировать выбранную строку списка ПО.""" + """Редактировать выбранную строку списка ПО (большое окно).""" sel = listbox.curselection() if not sel: messagebox.showinfo("Редактировать", "Сначала выберите позицию в списке") return current = listbox.get(sel[0]) - item = simpledialog.askstring("Редактировать", "Измените позицию:", - initialvalue=current) + item = self._sw_dialog("Редактировать позицию", initial=current) if item is not None: listbox.delete(sel[0]) - listbox.insert(sel[0], item.strip()) + listbox.insert(sel[0], item) def _add_user_to_is(self): user = simpledialog.askstring("Добавить пользователя", "Введите ФИО или должность:")