From 07f0800b7375a0b00617d45acf5724d8d1bdc8b1 Mon Sep 17 00:00:00 2001 From: prog1764 Date: Tue, 4 Aug 2026 20:22:38 +0400 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=B1=D0=BE=D1=80=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20=D0=BF=D0=BE=D0=BA=D0=B0?= =?UTF-8?q?=D0=B7=D0=B0=D1=82=D0=B5=D0=BB=D0=B5=D0=B9=20=D0=BA=D1=80=D0=B8?= =?UTF-8?q?=D1=82=D0=B5=D1=80=D0=B8=D0=B5=D0=B2=20=D0=B7=D0=BD=D0=B0=D1=87?= =?UTF-8?q?=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20=D0=BF=D0=BE=20=D1=81?= =?UTF-8?q?=D1=84=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dictionaries/criteria_applicability.json: для каждой сферы перечень применимых показателей ПП РФ № 127, построен из признаков значимости Распоряжения ПРФ № 360-р (например: ОПК → только 13 оборонзаказ, показатель 1 «ущерб жизни и здоровью» не применим; банки → только 10; связь → только 4) - окно ПП 127: неприменимые для сферы показатели блокируются и помечаются серым «(не применим для сферы)», исключаются из расчёта категории; если применимых показателей для сферы нет — категория «без категории» --- .../dictionaries/criteria_applicability.json | 162 ++++++++++++++++++ dokogen/ui.py | 53 +++++- 2 files changed, 207 insertions(+), 8 deletions(-) create mode 100644 dokogen/dictionaries/criteria_applicability.json diff --git a/dokogen/dictionaries/criteria_applicability.json b/dokogen/dictionaries/criteria_applicability.json new file mode 100644 index 0000000..df03c68 --- /dev/null +++ b/dokogen/dictionaries/criteria_applicability.json @@ -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" + ] +} \ No newline at end of file diff --git a/dokogen/ui.py b/dokogen/ui.py index 47bd3d5..8236a69 100644 --- a/dokogen/ui.py +++ b/dokogen/ui.py @@ -1831,6 +1831,18 @@ class DokoGenApp: messagebox.showerror("Ошибка", f"Не удалось загрузить таблицу ПП 127: {e}") 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.title("Показатели критериев значимости (ПП РФ № 127)") 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: grp = ttk.LabelFrame(body, text=crit.get('criteria', ''), padding=6) grp.pack(fill=tk.X, pady=4) @@ -1866,12 +1884,18 @@ class DokoGenApp: num = ind.get('num', '') name = ind.get('name', '') 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.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='') options = [''] @@ -1882,7 +1906,15 @@ class DokoGenApp: combo = ttk.Combobox(row, textvariable=var, state='readonly', width=34, values=options) 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( @@ -1898,9 +1930,11 @@ class DokoGenApp: result_lbl.pack(anchor=tk.W, pady=(6, 0)) def _selected(): - """Список выбранных: [(num, name, категория, значение)].""" + """Список выбранных: [(num, name, категория, значение)] — только применимые показатели.""" 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() if not s: continue @@ -1923,7 +1957,10 @@ class DokoGenApp: def _calc(): selected = _selected() if not selected: - result_lbl.config(text="Категория значимости: — (ничего не выбрано)") + if applicable is not None and not any(a for _, _, _, _, a in rows): + result_lbl.config(text="Категория значимости: без категории (для этой сферы нет применимых показателей)") + else: + result_lbl.config(text="Категория значимости: — (ничего не выбрано)") return cat = _calc_category(selected) result_lbl.config(text=f"Категория значимости: {cat} (выбрано показателей: {len(selected)})")