feat: вкладка «ПО» — многострочные поля (списки построчно, как в опроснике)
- hw_sw/os_sw/app_sw теперь tk.Text с прокруткой вместо однострочного Entry - импортёр сохраняет переносы строк (_clean_multiline), а не схлопывает в одну строку - _collect_is/_on_is_select поддержка Text-виджетов
This commit is contained in:
+21
-9
@@ -330,6 +330,14 @@ def _import_187_is_list(wb, data, settings, log_fn):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _clean_multiline(text):
|
||||||
|
"""Чистит многострочное значение, сохраняя переносы строк."""
|
||||||
|
if text is None:
|
||||||
|
return ''
|
||||||
|
s = str(text).replace('\r\n', '\n').replace('\r', '\n')
|
||||||
|
lines = [ln.strip() for ln in s.split('\n')]
|
||||||
|
return '\n'.join(ln for ln in lines if ln)
|
||||||
|
|
||||||
def _split_entries(text):
|
def _split_entries(text):
|
||||||
"""Разбивает список средств защиты на ОТДЕЛЬНЫЕ программы.
|
"""Разбивает список средств защиты на ОТДЕЛЬНЫЕ программы.
|
||||||
|
|
||||||
@@ -445,22 +453,26 @@ def _import_187_is_list(wb, data, settings, log_fn):
|
|||||||
if _set(field_lower, 'net_method', val_b):
|
if _set(field_lower, 'net_method', val_b):
|
||||||
log_fn(f" Способ взаимодействия: {val_b[:60]}")
|
log_fn(f" Способ взаимодействия: {val_b[:60]}")
|
||||||
continue
|
continue
|
||||||
# --- ПО и аппаратные средства ---
|
# --- ПО и аппаратные средства (сохраняем переносы строк) ---
|
||||||
if 'наименования программно-аппаратных средств' in field_lower:
|
if 'наименования программно-аппаратных средств' in field_lower:
|
||||||
if _set(field_lower, 'hw_sw', val_b):
|
if raw_b and 'выбрать' not in field_lower and not _is_hint(raw_b):
|
||||||
log_fn(f" ПО/аппаратные средства: {val_b[:60]}")
|
is_obj['hw_sw'] = _clean_multiline(raw_b)
|
||||||
|
log_fn(f" ПО/аппаратные средства: {str(raw_b)[:60]}")
|
||||||
continue
|
continue
|
||||||
if 'операционная' in field_lower and 'система' in field_lower:
|
if 'операционная' in field_lower and 'система' in field_lower:
|
||||||
if _set(field_lower, 'os_sw', val_b):
|
if raw_b and 'выбрать' not in field_lower and not _is_hint(raw_b):
|
||||||
log_fn(f" ОС: {val_b[:60]}")
|
is_obj['os_sw'] = _clean_multiline(raw_b)
|
||||||
|
log_fn(f" ОС: {str(raw_b)[:60]}")
|
||||||
continue
|
continue
|
||||||
if 'прикладные программы' in field_lower:
|
if 'прикладные программы' in field_lower:
|
||||||
if _set(field_lower, 'app_sw', val_b):
|
if raw_b and 'выбрать' not in field_lower and not _is_hint(raw_b):
|
||||||
log_fn(f" Прикладные программы: {val_b[:60]}")
|
is_obj['app_sw'] = _clean_multiline(raw_b)
|
||||||
|
log_fn(f" Прикладные программы: {str(raw_b)[:60]}")
|
||||||
continue
|
continue
|
||||||
if 'общесистемн' in field_lower:
|
if 'общесистемн' in field_lower:
|
||||||
if _set(field_lower, 'os_sw', val_b):
|
if raw_b and 'выбрать' not in field_lower and not _is_hint(raw_b):
|
||||||
log_fn(f" Общесистемное ПО: {val_b[:60]}")
|
is_obj['os_sw'] = _clean_multiline(raw_b)
|
||||||
|
log_fn(f" Общесистемное ПО: {str(raw_b)[:60]}")
|
||||||
continue
|
continue
|
||||||
# --- Безопасность / 236 приказ ---
|
# --- Безопасность / 236 приказ ---
|
||||||
if 'категория нарушителя' in field_lower:
|
if 'категория нарушителя' in field_lower:
|
||||||
|
|||||||
+18
-9
@@ -920,16 +920,19 @@ class DokoGenApp:
|
|||||||
sw_frame.pack(fill=tk.BOTH, expand=True)
|
sw_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
sw_fields = [
|
sw_fields = [
|
||||||
("ПО и аппаратные средства (модели, производители, количество):", "is_hw_sw_entry"),
|
("ПО и аппаратные средства (модели, производители, количество):", "is_hw_sw_entry", 5),
|
||||||
("Операционные системы:", "is_os_sw_entry"),
|
("Операционные системы:", "is_os_sw_entry", 3),
|
||||||
("Прикладные программы (MS Office, OpenOffice и пр.):", "is_app_sw_entry"),
|
("Прикладные программы (MS Office, OpenOffice и пр.):", "is_app_sw_entry", 4),
|
||||||
]
|
]
|
||||||
for i, (label, attr) in enumerate(sw_fields):
|
for i, (label, attr, height) in enumerate(sw_fields):
|
||||||
ttk.Label(sw_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
|
ttk.Label(sw_frame, text=label).grid(row=i * 2, column=0, sticky=tk.W, pady=(4, 0))
|
||||||
entry = ttk.Entry(sw_frame, width=70)
|
txt = tk.Text(sw_frame, width=70, height=height, wrap=tk.WORD)
|
||||||
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
|
txt.grid(row=i * 2 + 1, column=0, columnspan=2, padx=8, sticky=tk.EW, pady=1)
|
||||||
setattr(self, attr, entry)
|
sb = ttk.Scrollbar(sw_frame, orient=tk.VERTICAL, command=txt.yview)
|
||||||
sw_frame.columnconfigure(1, weight=1)
|
sb.grid(row=i * 2 + 1, column=2, sticky=tk.NS)
|
||||||
|
txt.configure(yscrollcommand=sb.set)
|
||||||
|
setattr(self, attr, txt)
|
||||||
|
sw_frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
# ===== Вкладка «Безопасность (236)» =====
|
# ===== Вкладка «Безопасность (236)» =====
|
||||||
sec_tab = ttk.Frame(nb2)
|
sec_tab = ttk.Frame(nb2)
|
||||||
@@ -1228,6 +1231,9 @@ class DokoGenApp:
|
|||||||
]:
|
]:
|
||||||
w = getattr(self, attr, None)
|
w = getattr(self, attr, None)
|
||||||
if w is not None:
|
if w is not None:
|
||||||
|
if isinstance(w, tk.Text):
|
||||||
|
setattr(isys, model_field, w.get('1.0', 'end-1c').strip())
|
||||||
|
else:
|
||||||
setattr(isys, model_field, w.get().strip())
|
setattr(isys, model_field, w.get().strip())
|
||||||
# Списки
|
# Списки
|
||||||
isys.defense_tools_list = list(self.defense_tools_listbox.get(0, tk.END))
|
isys.defense_tools_list = list(self.defense_tools_listbox.get(0, tk.END))
|
||||||
@@ -1460,6 +1466,9 @@ class DokoGenApp:
|
|||||||
val = getattr(isys, model_field, '') or ''
|
val = getattr(isys, model_field, '') or ''
|
||||||
if isinstance(w, ttk.Combobox):
|
if isinstance(w, ttk.Combobox):
|
||||||
w.set(val)
|
w.set(val)
|
||||||
|
elif isinstance(w, tk.Text):
|
||||||
|
w.delete('1.0', tk.END)
|
||||||
|
w.insert('1.0', val)
|
||||||
else:
|
else:
|
||||||
w.delete(0, tk.END)
|
w.delete(0, tk.END)
|
||||||
w.insert(0, val)
|
w.insert(0, val)
|
||||||
|
|||||||
Reference in New Issue
Block a user