feat: вкладка «Безопасность» — вложенные подвкладки (нормальное отображение)
Вместо тесной двухколоночной раскладки — ряд подвкладок: 1) Основные данные — модель нарушителя (категория, уровень Н1-Н4, виды) + кнопки «⚡ Автозаполнить» и «🤖 Проверить безопасность через ИИ» 2) Угрозы — панель действий (⬇️ ФСТЭК / ⚙️ программа / 🤖 ИИ / ⚖️ сравнить) + большой список угроз на всю ширину 3) Инциденты и критерии — инциденты, показатели критериев, кнопка «📋 ПП № 127», обоснование 4) Орг. и тех. меры — оба списка с нормальной высотой Все виджеты и маппинги сохранены (is_*_listbox/combo на месте)
This commit is contained in:
+77
-56
@@ -1003,41 +1003,27 @@ class DokoGenApp:
|
||||
sw_frame.columnconfigure(0, weight=1)
|
||||
|
||||
# ===== Вкладка «Безопасность» =====
|
||||
# ===== Вкладка «Безопасность» — с вложенными подвкладками =====
|
||||
sec_tab = ttk.Frame(nb2)
|
||||
nb2.add(sec_tab, text="Безопасность")
|
||||
sec_frame = ttk.Frame(sec_tab, padding=6)
|
||||
sec_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# --- Панель действий (сверху, всегда видна) ---
|
||||
sec_actions = ttk.Frame(sec_frame)
|
||||
sec_actions.pack(fill=tk.X, pady=(0, 6))
|
||||
ttk.Button(sec_actions, text="⚡ Автозаполнить",
|
||||
command=self._auto_fill_security_click).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(sec_actions, text="⬇️ Загрузить угрозы ФСТЭК",
|
||||
command=self._download_fstec_threats).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(sec_actions, text="⚙️ Подобрать угрозы (программа)",
|
||||
command=self._suggest_threats_program_click).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(sec_actions, text="🤖 Подобрать угрозы (ИИ)",
|
||||
command=self._suggest_threats_ai_click).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(sec_actions, text="⚖️ Сравнить",
|
||||
command=self._compare_threats).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(sec_actions, text="🤖 Проверить безопасность через ИИ",
|
||||
command=self._check_security_ai).pack(side=tk.LEFT, padx=2)
|
||||
self._threats_date_label = ttk.Label(sec_actions, text="", foreground='gray')
|
||||
self._threats_date_label.pack(side=tk.LEFT, padx=8)
|
||||
nb_sec = ttk.Notebook(sec_frame)
|
||||
nb_sec.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# --- Две колонки: слева нарушитель+угрозы, справа остальное ---
|
||||
sec_cols = ttk.Frame(sec_frame)
|
||||
sec_cols.pack(fill=tk.BOTH, expand=True)
|
||||
sec_left = ttk.Frame(sec_cols)
|
||||
sec_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 6))
|
||||
sec_right = ttk.Frame(sec_cols)
|
||||
sec_right.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
# --- Подвкладка 1: Основные данные (нарушитель + автозаполнение) ---
|
||||
sec_main = ttk.Frame(nb_sec, padding=8)
|
||||
nb_sec.add(sec_main, text="Основные данные")
|
||||
|
||||
# ===== Левая колонка =====
|
||||
ttk.Label(sec_left, text="Категория нарушителя:").pack(anchor=tk.W)
|
||||
self.is_attacker_category_combo = ttk.Combobox(sec_left, state='readonly')
|
||||
self.is_attacker_category_combo.pack(fill=tk.X, pady=(2, 2))
|
||||
ttk.Label(sec_main, text="Модель нарушителя (Методика ФСТЭК от 05.02.2021):",
|
||||
font=('Arial', 10, 'bold')).pack(anchor=tk.W, pady=(0, 4))
|
||||
|
||||
row1 = ttk.Frame(sec_main)
|
||||
row1.pack(fill=tk.X, pady=3)
|
||||
ttk.Label(row1, text="Категория нарушителя:", width=26).pack(side=tk.LEFT)
|
||||
self.is_attacker_category_combo = ttk.Combobox(row1, state='readonly', width=50)
|
||||
self.is_attacker_category_combo.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
try:
|
||||
import json as _json
|
||||
_ac = os.path.join(os.path.dirname(__file__), 'dictionaries', 'attacker_categories.json')
|
||||
@@ -1047,9 +1033,11 @@ class DokoGenApp:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ttk.Label(sec_left, text="Уровень возможностей нарушителя:").pack(anchor=tk.W)
|
||||
self.is_attacker_level_combo = ttk.Combobox(sec_left, state='readonly')
|
||||
self.is_attacker_level_combo.pack(fill=tk.X, pady=(2, 2))
|
||||
row2 = ttk.Frame(sec_main)
|
||||
row2.pack(fill=tk.X, pady=3)
|
||||
ttk.Label(row2, text="Уровень возможностей нарушителя:", width=26).pack(side=tk.LEFT)
|
||||
self.is_attacker_level_combo = ttk.Combobox(row2, state='readonly', width=50)
|
||||
self.is_attacker_level_combo.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
try:
|
||||
import json as _json
|
||||
_al = os.path.join(os.path.dirname(__file__), 'dictionaries', 'attacker_levels.json')
|
||||
@@ -1060,10 +1048,10 @@ class DokoGenApp:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ttk.Label(sec_left, text="Виды нарушителей:").pack(anchor=tk.W)
|
||||
sec_at_row = ttk.Frame(sec_left)
|
||||
sec_at_row.pack(fill=tk.X, pady=(2, 4))
|
||||
self.is_attacker_types_listbox = tk.Listbox(sec_at_row, height=3, exportselection=False)
|
||||
ttk.Label(sec_main, text="Виды нарушителей:").pack(anchor=tk.W, pady=(6, 2))
|
||||
sec_at_row = ttk.Frame(sec_main)
|
||||
sec_at_row.pack(fill=tk.BOTH, expand=True)
|
||||
self.is_attacker_types_listbox = tk.Listbox(sec_at_row, height=6, exportselection=False)
|
||||
self.is_attacker_types_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
sec_at_btn = ttk.Frame(sec_at_row)
|
||||
sec_at_btn.pack(side=tk.RIGHT, padx=(4, 0))
|
||||
@@ -1072,19 +1060,48 @@ class DokoGenApp:
|
||||
ttk.Button(sec_at_btn, text="📚", width=3,
|
||||
command=lambda: self._select_sw_from_dict(self.is_attacker_types_listbox, 'attacker_types.json')).pack(pady=1)
|
||||
|
||||
ttk.Label(sec_left, text="Основные угрозы БИ:").pack(anchor=tk.W)
|
||||
sec_thr_row = ttk.Frame(sec_left)
|
||||
sec_thr_row.pack(fill=tk.BOTH, expand=True, pady=(2, 4))
|
||||
self.is_threats_listbox = tk.Listbox(sec_thr_row, height=7, exportselection=False)
|
||||
sec_main_btns = ttk.Frame(sec_main)
|
||||
sec_main_btns.pack(fill=tk.X, pady=(8, 0))
|
||||
ttk.Button(sec_main_btns, text="⚡ Автозаполнить (нарушитель, угрозы, меры)",
|
||||
command=self._auto_fill_security_click).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(sec_main_btns, text="🤖 Проверить безопасность через ИИ",
|
||||
command=self._check_security_ai).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Label(sec_main_btns,
|
||||
text="Подбор по данным объекта — как рекомендация, оператор подтверждает.",
|
||||
foreground='gray').pack(side=tk.LEFT, padx=8)
|
||||
|
||||
# --- Подвкладка 2: Угрозы ---
|
||||
sec_threats = ttk.Frame(nb_sec, padding=8)
|
||||
nb_sec.add(sec_threats, text="Угрозы")
|
||||
|
||||
thr_actions = ttk.Frame(sec_threats)
|
||||
thr_actions.pack(fill=tk.X, pady=(0, 6))
|
||||
ttk.Button(thr_actions, text="⬇️ Загрузить угрозы ФСТЭК",
|
||||
command=self._download_fstec_threats).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(thr_actions, text="⚙️ Подобрать (программа)",
|
||||
command=self._suggest_threats_program_click).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(thr_actions, text="🤖 Подобрать (ИИ)",
|
||||
command=self._suggest_threats_ai_click).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(thr_actions, text="⚖️ Сравнить программа ↔ ИИ",
|
||||
command=self._compare_threats).pack(side=tk.LEFT, padx=2)
|
||||
self._threats_date_label = ttk.Label(thr_actions, text="", foreground='gray')
|
||||
self._threats_date_label.pack(side=tk.LEFT, padx=8)
|
||||
|
||||
thr_row = ttk.Frame(sec_threats)
|
||||
thr_row.pack(fill=tk.BOTH, expand=True)
|
||||
self.is_threats_listbox = tk.Listbox(thr_row, height=10, exportselection=False)
|
||||
self.is_threats_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
sec_thr_btn = ttk.Frame(sec_thr_row)
|
||||
sec_thr_btn.pack(side=tk.RIGHT, padx=(4, 0))
|
||||
ttk.Button(sec_thr_btn, text="- Удалить",
|
||||
thr_btn = ttk.Frame(thr_row)
|
||||
thr_btn.pack(side=tk.RIGHT, padx=(4, 0))
|
||||
ttk.Button(thr_btn, text="- Удалить",
|
||||
command=lambda: self._del_sw_item(self.is_threats_listbox)).pack(fill=tk.X, pady=1)
|
||||
ttk.Button(sec_thr_btn, text="📚 Из словаря",
|
||||
ttk.Button(thr_btn, text="📚 Из словаря",
|
||||
command=lambda: self._select_sw_from_dict(self.is_threats_listbox, 'threats_fstec.json')).pack(fill=tk.X, pady=1)
|
||||
|
||||
# ===== Правая колонка =====
|
||||
# --- Подвкладка 3: Инциденты и критерии ---
|
||||
sec_inc = ttk.Frame(nb_sec, padding=8)
|
||||
nb_sec.add(sec_inc, text="Инциденты и критерии")
|
||||
|
||||
def _sec_row(parent, label, attr, dict_name=None, height=2, allow_add=False):
|
||||
"""Ряд: label + listbox + кнопки (+/-/✏️/📚)."""
|
||||
ttk.Label(parent, text=label).pack(anchor=tk.W)
|
||||
@@ -1096,7 +1113,6 @@ class DokoGenApp:
|
||||
btns = ttk.Frame(row)
|
||||
btns.pack(side=tk.RIGHT, padx=(4, 0))
|
||||
if allow_add or not dict_name:
|
||||
# ручное добавление: если разрешено или нет словаря
|
||||
ttk.Button(btns, text="+", width=2,
|
||||
command=lambda l=lb: self._add_sw_item(l)).pack(pady=1)
|
||||
ttk.Button(btns, text="-", width=2,
|
||||
@@ -1107,18 +1123,23 @@ class DokoGenApp:
|
||||
ttk.Button(btns, text="📚", width=3,
|
||||
command=lambda l=lb, d=dict_name: self._select_sw_from_dict(l, d)).pack(pady=1)
|
||||
|
||||
_sec_row(sec_right, "Типы компьютерных инцидентов:",
|
||||
'is_incidents_listbox', 'incidents.json', height=2)
|
||||
_sec_row(sec_right, "Показатели критериев значимости:",
|
||||
'is_criteria_values_listbox', 'criteria_indicators.json', height=2)
|
||||
ttk.Button(sec_right, text="📋 Заполнить по таблице ПП № 127",
|
||||
_sec_row(sec_inc, "Типы компьютерных инцидентов:",
|
||||
'is_incidents_listbox', 'incidents.json', height=3)
|
||||
_sec_row(sec_inc, "Показатели критериев значимости:",
|
||||
'is_criteria_values_listbox', 'criteria_indicators.json', height=3)
|
||||
ttk.Button(sec_inc, text="📋 Заполнить по таблице ПП № 127",
|
||||
command=self._open_criteria_127_dialog).pack(anchor=tk.W, pady=(0, 4))
|
||||
_sec_row(sec_right, "Обоснование значений показателей:",
|
||||
'is_criteria_justification_listbox', None, height=2)
|
||||
_sec_row(sec_right, "Организационные меры:",
|
||||
'is_org_measures_listbox', 'org_measures.json', height=2, allow_add=True)
|
||||
_sec_row(sec_right, "Технические меры:",
|
||||
'is_tech_measures_listbox', 'tech_measures.json', height=2, allow_add=True)
|
||||
_sec_row(sec_inc, "Обоснование значений показателей:",
|
||||
'is_criteria_justification_listbox', None, height=3)
|
||||
|
||||
# --- Подвкладка 4: Организационные и технические меры ---
|
||||
sec_meas = ttk.Frame(nb_sec, padding=8)
|
||||
nb_sec.add(sec_meas, text="Орг. и тех. меры")
|
||||
|
||||
_sec_row(sec_meas, "Организационные меры:",
|
||||
'is_org_measures_listbox', 'org_measures.json', height=5, allow_add=True)
|
||||
_sec_row(sec_meas, "Технические меры:",
|
||||
'is_tech_measures_listbox', 'tech_measures.json', height=5, allow_add=True)
|
||||
|
||||
# ===== Вкладка «Средства защиты» =====
|
||||
def_tab = ttk.Frame(nb2)
|
||||
|
||||
Reference in New Issue
Block a user