feat: логи, фикс табов, справка с инструкциями
1) Логи: все действия пишутся в dokogen.log (импорт, генерация, обращения к Морфер/DaData/ИИ с ответами), кнопка «Экспорт логов» на вкладке «Лог» 2) Табы: при пересборке параграфа табуляция сохраняется как <w:tab/> (раньше Word «съедал» табы между «_____» и датой) 3) Справка: инструкция пользователя (циклы, программа), инструкция администратора (словари, API-ключи, лимиты), справочник переменных, пустой опросник Excel — всё скачивается в Word/Excel
This commit is contained in:
+26
-10
@@ -461,10 +461,31 @@ def _apply_highlight_color(run_el, color: str):
|
||||
rpr.append(hl)
|
||||
|
||||
|
||||
def _add_run_with_tabs(para, text, style_source=None):
|
||||
"""Добавляет run с текстом, сохраняя табуляцию как <w:tab/>.
|
||||
|
||||
python-docx add_run('\t') вставляет символ таба в w:t, который Word
|
||||
может «съесть». Поэтому разбиваем текст по '\t' и вставляем
|
||||
настоящие элементы табуляции.
|
||||
"""
|
||||
parts = str(text).split('\t')
|
||||
for i, part in enumerate(parts):
|
||||
if part:
|
||||
run = para.add_run(part)
|
||||
if style_source is not None:
|
||||
_copy_run_style(style_source, run)
|
||||
if i < len(parts) - 1:
|
||||
run = para.add_run()
|
||||
if style_source is not None:
|
||||
_copy_run_style(style_source, run)
|
||||
run.add_tab()
|
||||
|
||||
|
||||
def _replace_text_in_para(para, replacements: Dict[str, str]) -> bool:
|
||||
"""Заменяет {{var}} в параграфе. Возвращает True, если были замены.
|
||||
|
||||
Значения «—» (незаполненная информация) подсвечиваются жёлтым маркером.
|
||||
Табуляция в параграфе сохраняется (<w:tab/>).
|
||||
"""
|
||||
full = para.text
|
||||
matches = list(VAR_PATTERN.finditer(full))
|
||||
@@ -483,9 +504,7 @@ def _replace_text_in_para(para, replacements: Dict[str, str]) -> bool:
|
||||
continue
|
||||
# текст до переменной
|
||||
if m.start() > pos:
|
||||
run = para.add_run(full[pos:m.start()])
|
||||
if first is not None:
|
||||
_copy_run_style(first, run)
|
||||
_add_run_with_tabs(para, full[pos:m.start()], first)
|
||||
# значение переменной
|
||||
val_str = str(val)
|
||||
run = para.add_run(val_str)
|
||||
@@ -497,9 +516,7 @@ def _replace_text_in_para(para, replacements: Dict[str, str]) -> bool:
|
||||
pos = m.end()
|
||||
# хвост после последней переменной
|
||||
if pos < len(full):
|
||||
run = para.add_run(full[pos:])
|
||||
if first is not None:
|
||||
_copy_run_style(first, run)
|
||||
_add_run_with_tabs(para, full[pos:], first)
|
||||
return changed
|
||||
|
||||
|
||||
@@ -566,21 +583,20 @@ def _highlight_unmatched(doc):
|
||||
return
|
||||
|
||||
# Пересобираем параграф: обычный текст и переменные отдельными run'ами,
|
||||
# переменные — с красным маркером. Сохраняем стиль первого run.
|
||||
# переменные — с красным маркером. Сохраняем стиль первого run и табы.
|
||||
first = para.runs[0] if para.runs else None
|
||||
para.clear()
|
||||
pos = 0
|
||||
for m in matches:
|
||||
if m.start() > pos:
|
||||
run = para.add_run(full[pos:m.start()])
|
||||
if first is not None:
|
||||
_copy_run_style(first, run)
|
||||
_add_run_with_tabs(para, full[pos:m.start()], first)
|
||||
run = para.add_run(m.group(0))
|
||||
if first is not None:
|
||||
_copy_run_style(first, run)
|
||||
_apply_highlight(run._element)
|
||||
pos = m.end()
|
||||
if pos < len(full):
|
||||
_add_run_with_tabs(para, full[pos:], first)
|
||||
run = para.add_run(full[pos:])
|
||||
if first is not None:
|
||||
_copy_run_style(first, run)
|
||||
|
||||
Reference in New Issue
Block a user