feat: окно «Показатели критериев значимости» по таблице ПП РФ № 127
- кнопка «📋 Заполнить по таблице ПП № 127» в вкладке «Безопасность» - окно 860x640 со скроллом: 5 критериев (социальная, политическая, экономическая, экологическая, оборонная), 12 показателей, у каждого выбор значения 1-4 с описанием шкалы - объединены показатели и обоснование в одном окне (общее поле) - «🧮 Рассчитать категорию»: по максимальному баллу → 1/2/3/без категории (4→1-я, 3→2-я, 2→3-я), результат пишется в категорию значимости объекта - «💾 Сохранить»: заполняет список показателей и обоснование - словарь criteria_127.json (формулировки можно править файлом)
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
[
|
||||
{
|
||||
"criteria": "Социальная значимость",
|
||||
"indicators": [
|
||||
{
|
||||
"name": "Количество пользователей объекта КИИ, которым может быть причинён ущерб",
|
||||
"scale": {
|
||||
"4": "более 5 млн человек",
|
||||
"3": "от 1 до 5 млн человек",
|
||||
"2": "от 100 тыс. до 1 млн человек",
|
||||
"1": "менее 100 тыс. человек"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Доля пользователей объекта КИИ, которым может быть причинён ущерб, от общего числа пользователей",
|
||||
"scale": {
|
||||
"4": "более 20%",
|
||||
"3": "от 10% до 20%",
|
||||
"2": "от 5% до 10%",
|
||||
"1": "менее 5%"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Продолжительность нарушения безопасности объекта КИИ, которое может привести к причинению ущерба",
|
||||
"scale": {
|
||||
"4": "более 72 часов",
|
||||
"3": "от 24 до 72 часов",
|
||||
"2": "от 1 до 24 часов",
|
||||
"1": "менее 1 часа"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"criteria": "Политическая значимость",
|
||||
"indicators": [
|
||||
{
|
||||
"name": "Значимость объекта КИИ для обеспечения обороноспособности страны, безопасности государства и правопорядка",
|
||||
"scale": {
|
||||
"4": "критическая значимость",
|
||||
"3": "высокая значимость",
|
||||
"2": "средняя значимость",
|
||||
"1": "низкая значимость"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Международная значимость объекта КИИ (используется при реализации международных договоров и соглашений)",
|
||||
"scale": {
|
||||
"4": "международное значение",
|
||||
"3": "федеральное значение",
|
||||
"2": "региональное значение",
|
||||
"1": "местное значение"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"criteria": "Экономическая значимость",
|
||||
"indicators": [
|
||||
{
|
||||
"name": "Размер возможного прямого ущерба в результате нарушения безопасности объекта КИИ",
|
||||
"scale": {
|
||||
"4": "более 5 млрд рублей",
|
||||
"3": "от 1 до 5 млрд рублей",
|
||||
"2": "от 100 млн до 1 млрд рублей",
|
||||
"1": "менее 100 млн рублей"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Размер возможного косвенного ущерба (упущенная выгода, затраты на восстановление)",
|
||||
"scale": {
|
||||
"4": "более 10 млрд рублей",
|
||||
"3": "от 1 до 10 млрд рублей",
|
||||
"2": "от 100 млн до 1 млрд рублей",
|
||||
"1": "менее 100 млн рублей"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Влияние нарушения безопасности объекта КИИ на экономическую безопасность государства",
|
||||
"scale": {
|
||||
"4": "критическое влияние",
|
||||
"3": "высокое влияние",
|
||||
"2": "среднее влияние",
|
||||
"1": "низкое влияние"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"criteria": "Экологическая значимость",
|
||||
"indicators": [
|
||||
{
|
||||
"name": "Площадь территории, на которой может быть оказано негативное воздействие на окружающую среду",
|
||||
"scale": {
|
||||
"4": "более 1000 кв. км",
|
||||
"3": "от 100 до 1000 кв. км",
|
||||
"2": "от 10 до 100 кв. км",
|
||||
"1": "менее 10 кв. км"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Возможность нанесения ущерба объектам животного и растительного мира, водным объектам",
|
||||
"scale": {
|
||||
"4": "необратимый ущерб экосистемам",
|
||||
"3": "значительный ущерб",
|
||||
"2": "умеренный ущерб",
|
||||
"1": "незначительный ущерб"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"criteria": "Значимость для обороны страны, безопасности государства и правопорядка",
|
||||
"indicators": [
|
||||
{
|
||||
"name": "Влияние нарушения безопасности объекта КИИ на обороноспособность страны",
|
||||
"scale": {
|
||||
"4": "критическое влияние",
|
||||
"3": "высокое влияние",
|
||||
"2": "среднее влияние",
|
||||
"1": "низкое влияние"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Влияние нарушения безопасности объекта КИИ на безопасность государства и правопорядок",
|
||||
"scale": {
|
||||
"4": "критическое влияние",
|
||||
"3": "высокое влияние",
|
||||
"2": "среднее влияние",
|
||||
"1": "низкое влияние"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
+134
@@ -1038,6 +1038,8 @@ class DokoGenApp:
|
||||
'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",
|
||||
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, "Организационные меры:",
|
||||
@@ -1733,6 +1735,138 @@ class DokoGenApp:
|
||||
if user:
|
||||
self.users_listbox.insert(tk.END, user)
|
||||
|
||||
def _open_criteria_127_dialog(self):
|
||||
"""Окно заполнения показателей критериев значимости по таблице ПП РФ № 127.
|
||||
|
||||
Показатели и обоснование объединены в одном окне:
|
||||
для каждого показателя выбирается значение (1-4), внизу — общее обоснование.
|
||||
По максимальному баллу автоматически рассчитывается категория значимости:
|
||||
4 → 1-я, 3 → 2-я, 2 → 3-я, иначе «без категории».
|
||||
"""
|
||||
import json as _json
|
||||
dict_path = os.path.join(os.path.dirname(__file__), 'dictionaries', 'criteria_127.json')
|
||||
try:
|
||||
with open(dict_path, encoding='utf-8') as f:
|
||||
criteria = _json.load(f)
|
||||
except Exception as e:
|
||||
messagebox.showerror("Ошибка", f"Не удалось загрузить таблицу ПП 127: {e}")
|
||||
return
|
||||
|
||||
dialog = tk.Toplevel(self.root)
|
||||
dialog.title("Показатели критериев значимости (ПП РФ № 127)")
|
||||
dialog.geometry("860x640")
|
||||
dialog.transient(self.root)
|
||||
dialog.grab_set()
|
||||
|
||||
outer = ttk.Frame(dialog, padding=8)
|
||||
outer.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
canvas = tk.Canvas(outer, highlightthickness=0)
|
||||
scrollbar = ttk.Scrollbar(outer, orient=tk.VERTICAL, command=canvas.yview)
|
||||
body = ttk.Frame(canvas)
|
||||
body.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
|
||||
canvas.create_window((0, 0), window=body, 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)
|
||||
|
||||
ttk.Label(body, text="Показатели критериев значимости объекта КИИ (ПП РФ № 127)",
|
||||
font=('Arial', 10, 'bold')).pack(anchor=tk.W, pady=(0, 4))
|
||||
ttk.Label(body, text="По каждому показателю выберите значение от 1 до 4 "
|
||||
"(4 — максимальная значимость). Категория рассчитывается автоматически.",
|
||||
foreground='gray', wraplength=780).pack(anchor=tk.W, pady=(0, 8))
|
||||
|
||||
# Текущие значения из listbox (чтобы предзаполнить, если уже заполнено)
|
||||
cur_values = set()
|
||||
if hasattr(self, 'is_criteria_values_listbox'):
|
||||
for i in range(self.is_criteria_values_listbox.size()):
|
||||
cur_values.add(str(self.is_criteria_values_listbox.get(i)))
|
||||
|
||||
rows = [] # (критерий, показатель, scale, var)
|
||||
for crit in criteria:
|
||||
grp = ttk.LabelFrame(body, text=crit.get('criteria', ''), padding=6)
|
||||
grp.pack(fill=tk.X, pady=4)
|
||||
for ind in crit.get('indicators', []):
|
||||
name = ind.get('name', '')
|
||||
scale = ind.get('scale', {})
|
||||
row = ttk.Frame(grp)
|
||||
row.pack(fill=tk.X, pady=2)
|
||||
ttk.Label(row, text=name, wraplength=520, justify=tk.LEFT).pack(side=tk.LEFT)
|
||||
var = tk.StringVar(value='')
|
||||
combo = ttk.Combobox(row, textvariable=var, state='readonly', width=6,
|
||||
values=['', '1', '2', '3', '4'])
|
||||
combo.pack(side=tk.RIGHT, padx=6)
|
||||
rows.append((crit.get('criteria', ''), name, scale, var))
|
||||
|
||||
ttk.Label(body, text="Обоснование полученных значений:", font=('Arial', 9, 'bold')).pack(
|
||||
anchor=tk.W, pady=(10, 2))
|
||||
justify_txt = tk.Text(body, width=90, height=5, wrap=tk.WORD)
|
||||
justify_txt.pack(fill=tk.X, pady=(0, 6))
|
||||
# предзаполнить обоснование из listbox, если есть
|
||||
if hasattr(self, 'is_criteria_justification_listbox') and self.is_criteria_justification_listbox.size():
|
||||
justify_txt.insert('1.0', '\n'.join(
|
||||
self.is_criteria_justification_listbox.get(i)
|
||||
for i in range(self.is_criteria_justification_listbox.size())))
|
||||
|
||||
result_lbl = ttk.Label(body, text="Категория значимости: —", font=('Arial', 10, 'bold'))
|
||||
result_lbl.pack(anchor=tk.W, pady=(6, 0))
|
||||
|
||||
def _calc():
|
||||
vals = []
|
||||
for crit_name, ind_name, scale, var in rows:
|
||||
v = var.get().strip()
|
||||
if v:
|
||||
desc = scale.get(v, '')
|
||||
vals.append(f"{crit_name}: {ind_name} — {v}" + (f" ({desc})" if desc else ""))
|
||||
if vals:
|
||||
self.is_criteria_values_listbox.delete(0, tk.END)
|
||||
for line in vals:
|
||||
self.is_criteria_values_listbox.insert(tk.END, line)
|
||||
# Категория по максимальному баллу
|
||||
nums = [int(var.get()) for _, _, _, var in rows if var.get().strip().isdigit()]
|
||||
if nums:
|
||||
mx = max(nums)
|
||||
cat = {4: '1', 3: '2', 2: '3'}.get(mx, 'без категории')
|
||||
result_lbl.config(text=f"Категория значимости: {cat} (макс. балл {mx})")
|
||||
else:
|
||||
result_lbl.config(text="Категория значимости: — (ничего не выбрано)")
|
||||
|
||||
def _save():
|
||||
vals = []
|
||||
for crit_name, ind_name, scale, var in rows:
|
||||
v = var.get().strip()
|
||||
if v:
|
||||
desc = scale.get(v, '')
|
||||
vals.append(f"{crit_name}: {ind_name} — {v}" + (f" ({desc})" if desc else ""))
|
||||
if hasattr(self, 'is_criteria_values_listbox'):
|
||||
self.is_criteria_values_listbox.delete(0, tk.END)
|
||||
for line in vals:
|
||||
self.is_criteria_values_listbox.insert(tk.END, line)
|
||||
# Обоснование
|
||||
j = justify_txt.get('1.0', 'end-1c').strip()
|
||||
if hasattr(self, 'is_criteria_justification_listbox'):
|
||||
self.is_criteria_justification_listbox.delete(0, tk.END)
|
||||
for line in j.split('\n'):
|
||||
if line.strip():
|
||||
self.is_criteria_justification_listbox.insert(tk.END, line.strip())
|
||||
# Категория → в поле категории объекта
|
||||
nums = [int(var.get()) for _, _, _, var in rows if var.get().strip().isdigit()]
|
||||
if nums:
|
||||
mx = max(nums)
|
||||
cat = {4: '1', 3: '2', 2: '3'}.get(mx, 'без категории')
|
||||
if hasattr(self, 'is_category_var'):
|
||||
self.is_category_var.set(cat)
|
||||
self.log(f"📋 Показатели критериев значимости сохранены ({len(vals)} шт.)")
|
||||
dialog.destroy()
|
||||
|
||||
btn_frame = ttk.Frame(body)
|
||||
btn_frame.pack(fill=tk.X, pady=(8, 0))
|
||||
ttk.Button(btn_frame, text="🧮 Рассчитать категорию", command=_calc).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(btn_frame, text="💾 Сохранить", command=_save).pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(btn_frame, text="Отмена", command=dialog.destroy).pack(side=tk.LEFT, padx=2)
|
||||
|
||||
dialog.wait_window()
|
||||
|
||||
def _download_fstec_threats(self):
|
||||
"""Скачать перечень угроз с сайта ФСТЭК (БДУ) и обновить список."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user