feat: автоподбор применимости показателей критериев значимости по сфере
- dictionaries/criteria_applicability.json: для каждой сферы перечень применимых показателей ПП РФ № 127, построен из признаков значимости Распоряжения ПРФ № 360-р (например: ОПК → только 13 оборонзаказ, показатель 1 «ущерб жизни и здоровью» не применим; банки → только 10; связь → только 4) - окно ПП 127: неприменимые для сферы показатели блокируются и помечаются серым «(не применим для сферы)», исключаются из расчёта категории; если применимых показателей для сферы нет — категория «без категории»
This commit is contained in:
@@ -0,0 +1,162 @@
|
|||||||
|
{
|
||||||
|
"Здравоохранение": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Наука": [
|
||||||
|
"1",
|
||||||
|
"11",
|
||||||
|
"13",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9"
|
||||||
|
],
|
||||||
|
"Транспорт": [
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"3"
|
||||||
|
],
|
||||||
|
"Связь": [
|
||||||
|
"4"
|
||||||
|
],
|
||||||
|
"Энергетика": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Государственная регистрация прав": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Банковская сфера и финансовый рынок": [
|
||||||
|
"10"
|
||||||
|
],
|
||||||
|
"Топливно-энергетический комплекс": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Атомная энергетика": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Оборонная промышленность": [
|
||||||
|
"13"
|
||||||
|
],
|
||||||
|
"Ракетно-космическая промышленность": [
|
||||||
|
"10"
|
||||||
|
],
|
||||||
|
"Горнодобывающая промышленность": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Металлургическая промышленность": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Химическая промышленность": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
],
|
||||||
|
"Иная сфера деятельности": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
"10",
|
||||||
|
"11",
|
||||||
|
"12",
|
||||||
|
"13",
|
||||||
|
"14"
|
||||||
|
]
|
||||||
|
}
|
||||||
+44
-7
@@ -1831,6 +1831,18 @@ class DokoGenApp:
|
|||||||
messagebox.showerror("Ошибка", f"Не удалось загрузить таблицу ПП 127: {e}")
|
messagebox.showerror("Ошибка", f"Не удалось загрузить таблицу ПП 127: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Применимость показателей по сфере объекта (Распоряжение ПРФ № 360-р)
|
||||||
|
applicable = None # None = все показатели применимы
|
||||||
|
try:
|
||||||
|
_app_path = os.path.join(os.path.dirname(__file__), 'dictionaries', 'criteria_applicability.json')
|
||||||
|
with open(_app_path, encoding='utf-8') as _f:
|
||||||
|
_app = _json.load(_f)
|
||||||
|
_sphere = self.is_sphere_combo.get() if hasattr(self, 'is_sphere_combo') else ''
|
||||||
|
if _sphere and _sphere in _app:
|
||||||
|
applicable = set(_app[_sphere])
|
||||||
|
except Exception:
|
||||||
|
applicable = None
|
||||||
|
|
||||||
dialog = tk.Toplevel(self.root)
|
dialog = tk.Toplevel(self.root)
|
||||||
dialog.title("Показатели критериев значимости (ПП РФ № 127)")
|
dialog.title("Показатели критериев значимости (ПП РФ № 127)")
|
||||||
dialog.geometry("980x700")
|
dialog.geometry("980x700")
|
||||||
@@ -1855,10 +1867,16 @@ class DokoGenApp:
|
|||||||
"объектов критической информационной инфраструктуры РФ» (приложение). "
|
"объектов критической информационной инфраструктуры РФ» (приложение). "
|
||||||
"По каждому показателю выберите значение, которому соответствует объект. "
|
"По каждому показателю выберите значение, которому соответствует объект. "
|
||||||
"Категория определяется по наивысшей из выбранных.",
|
"Категория определяется по наивысшей из выбранных.",
|
||||||
foreground='gray', wraplength=920, justify=tk.LEFT).pack(anchor=tk.W, pady=(0, 8))
|
foreground='gray', wraplength=920, justify=tk.LEFT).pack(anchor=tk.W, pady=(0, 4))
|
||||||
|
if applicable is not None:
|
||||||
|
_sphere_txt = self.is_sphere_combo.get() if hasattr(self, 'is_sphere_combo') else ''
|
||||||
|
ttk.Label(body, text=f"Сфера объекта: «{_sphere_txt}». Показатели, не применимые для этой сферы "
|
||||||
|
f"(по Распоряжению ПРФ № 360-р), отмечены серым и исключены из расчёта.",
|
||||||
|
foreground='#1a6e1a', wraplength=920, justify=tk.LEFT).pack(anchor=tk.W, pady=(0, 8))
|
||||||
|
|
||||||
rows = [] # (num, name, values{III:..,II:..,I:..}, var)
|
rows = [] # (num, name, values{III:..,II:..,I:..}, var, applicable)
|
||||||
|
|
||||||
|
import re as _re
|
||||||
for crit in criteria:
|
for crit in criteria:
|
||||||
grp = ttk.LabelFrame(body, text=crit.get('criteria', ''), padding=6)
|
grp = ttk.LabelFrame(body, text=crit.get('criteria', ''), padding=6)
|
||||||
grp.pack(fill=tk.X, pady=4)
|
grp.pack(fill=tk.X, pady=4)
|
||||||
@@ -1866,12 +1884,18 @@ class DokoGenApp:
|
|||||||
num = ind.get('num', '')
|
num = ind.get('num', '')
|
||||||
name = ind.get('name', '')
|
name = ind.get('name', '')
|
||||||
values = ind.get('values', {})
|
values = ind.get('values', {})
|
||||||
|
# Группа показателя: '1'→'1', '2а'→'2', '10.1'→'10', '13б'→'13'
|
||||||
|
m = _re.match(r'(\d+)', num)
|
||||||
|
grp_num = m.group(1) if m else num
|
||||||
|
applicable_here = applicable is None or grp_num in applicable
|
||||||
row = ttk.Frame(grp)
|
row = ttk.Frame(grp)
|
||||||
row.pack(fill=tk.X, pady=2)
|
row.pack(fill=tk.X, pady=2)
|
||||||
# Номер показателя
|
# Номер показателя
|
||||||
ttk.Label(row, text=num, width=4, font=('Arial', 9, 'bold')).pack(side=tk.LEFT)
|
lbl_num = ttk.Label(row, text=num, width=4, font=('Arial', 9, 'bold'))
|
||||||
|
lbl_num.pack(side=tk.LEFT)
|
||||||
# Текст показателя
|
# Текст показателя
|
||||||
ttk.Label(row, text=name, wraplength=640, justify=tk.LEFT).pack(side=tk.LEFT)
|
lbl_name = ttk.Label(row, text=name, wraplength=640, justify=tk.LEFT)
|
||||||
|
lbl_name.pack(side=tk.LEFT)
|
||||||
# Выбор значения (категория)
|
# Выбор значения (категория)
|
||||||
var = tk.StringVar(value='')
|
var = tk.StringVar(value='')
|
||||||
options = ['']
|
options = ['']
|
||||||
@@ -1882,7 +1906,15 @@ class DokoGenApp:
|
|||||||
combo = ttk.Combobox(row, textvariable=var, state='readonly', width=34,
|
combo = ttk.Combobox(row, textvariable=var, state='readonly', width=34,
|
||||||
values=options)
|
values=options)
|
||||||
combo.pack(side=tk.RIGHT, padx=6)
|
combo.pack(side=tk.RIGHT, padx=6)
|
||||||
rows.append((num, name, values, var))
|
if not applicable_here:
|
||||||
|
# Показатель не применим для сферы объекта — блокируем
|
||||||
|
combo.config(state='disabled')
|
||||||
|
lbl_num.config(foreground='gray')
|
||||||
|
lbl_name.config(foreground='gray')
|
||||||
|
if hasattr(lbl_name, 'config'):
|
||||||
|
pass
|
||||||
|
lbl_name.config(text=name + ' (не применим для сферы)')
|
||||||
|
rows.append((num, name, values, var, applicable_here))
|
||||||
|
|
||||||
# Обоснование
|
# Обоснование
|
||||||
ttk.Label(body, text="Обоснование полученных значений:", font=('Arial', 9, 'bold')).pack(
|
ttk.Label(body, text="Обоснование полученных значений:", font=('Arial', 9, 'bold')).pack(
|
||||||
@@ -1898,9 +1930,11 @@ class DokoGenApp:
|
|||||||
result_lbl.pack(anchor=tk.W, pady=(6, 0))
|
result_lbl.pack(anchor=tk.W, pady=(6, 0))
|
||||||
|
|
||||||
def _selected():
|
def _selected():
|
||||||
"""Список выбранных: [(num, name, категория, значение)]."""
|
"""Список выбранных: [(num, name, категория, значение)] — только применимые показатели."""
|
||||||
out = []
|
out = []
|
||||||
for num, name, values, var in rows:
|
for num, name, values, var, applicable_here in rows:
|
||||||
|
if not applicable_here:
|
||||||
|
continue
|
||||||
s = var.get().strip()
|
s = var.get().strip()
|
||||||
if not s:
|
if not s:
|
||||||
continue
|
continue
|
||||||
@@ -1923,6 +1957,9 @@ class DokoGenApp:
|
|||||||
def _calc():
|
def _calc():
|
||||||
selected = _selected()
|
selected = _selected()
|
||||||
if not selected:
|
if not selected:
|
||||||
|
if applicable is not None and not any(a for _, _, _, _, a in rows):
|
||||||
|
result_lbl.config(text="Категория значимости: без категории (для этой сферы нет применимых показателей)")
|
||||||
|
else:
|
||||||
result_lbl.config(text="Категория значимости: — (ничего не выбрано)")
|
result_lbl.config(text="Категория значимости: — (ничего не выбрано)")
|
||||||
return
|
return
|
||||||
cat = _calc_category(selected)
|
cat = _calc_category(selected)
|
||||||
|
|||||||
Reference in New Issue
Block a user