feat: вкладка «ПО» — словари ОС/аппаратных средств/прикладных программ + большое окно редактирования

- словари: hw_sw.json, os_sw.json, app_sw.json
- кнопка «📚 Из словаря» у каждого списка ПО (мультивыбор)
- большое окно добавления/редактирования позиции (560x220, многострочное)
This commit is contained in:
2026-08-04 16:56:51 +04:00
parent ba2a02d1cd
commit aae66dcca1
4 changed files with 109 additions and 11 deletions
+16
View File
@@ -0,0 +1,16 @@
[
"Microsoft Office (уточнить версию)",
"LibreOffice",
"OpenOffice",
"1С:Предприятие 8.3 (уточнить конфигурацию)",
"Контур.Экстерн",
"СБИС",
"Kaspersky Endpoint Security",
"Kaspersky Security Center",
"Почтовый клиент (уточнить)",
"Браузер (уточнить)",
"СЭД (уточнить систему)",
"АРМ оператора (уточнить)",
"СКУД ПО (уточнить)",
"Видеонаблюдение ПО (уточнить)"
]
+16
View File
@@ -0,0 +1,16 @@
[
"Сервер (уточнить модель)",
"АРМ пользователя (уточнить конфигурацию)",
"Ноутбук (уточнить модель)",
"Коммутатор (уточнить модель)",
"Маршрутизатор (уточнить модель)",
"Межсетевой экран (уточнить модель)",
"Видеорегистратор (уточнить модель)",
"Видеокамера (уточнить модель)",
"Контроллер доступа СКУД (уточнить модель)",
"Шлагбаум (уточнить модель)",
"Турникет (уточнить модель)",
"Сетевое хранилище (NAS) (уточнить модель)",
"Беспроводная точка доступа (уточнить модель)",
"ИБП (уточнить модель)"
]
+15
View File
@@ -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 (для планшетов/КПК)"
]
+62 -11
View File
@@ -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('<Return>', lambda e: _ok())
dialog.bind('<Escape>', 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("Добавить пользователя", "Введите ФИО или должность:")