# ДП «Таблица» — справочник настроек

Полный перечень настроек ДП «Таблица»: где хранится каждая настройка, что она делает и какие есть ограничения.

## Настройки таблицы (ExtParamTableCommonSettings)

Карточка ДП «Таблица» открывается на вкладке «Основные настройки» — общие поля параметра: имя, тип «Таблица», модуль, пример содержимого, регулярное выражение проверки и режим Excel. Опции, специфичные для таблицы, вынесены на вкладку «Дополнительные настройки»; ключевой столбец и настройки множественного выбора — на вкладку «Настройки множественного выбора», а часть опций лежит на своей рабочей вкладке — переключатель автосохранения строки находится на вкладке секций, рядом с настройкой, от которой он зависит (см. раздел «Секции столбцов»).

Администратор попадает в эти настройки и прямо из карточки задачи: правый клик по названию ДП «Таблица» открывает контекстное меню с единственным пунктом «Настройки», который ведёт на страницу настроек ДП категории с подставленным фильтром по этому параметру. Пользователю без прав администратора меню на названии не показывается. Правый клик внутри самой таблицы это меню не вызывает — там работают собственные меню строк и ячеек.

![Вкладка «Основные настройки» ДП «Таблица»: имя, тип, модуль, пример содержимого, регулярное выражение, режим Excel](https://help.1forma.ru/help-images/ext-params/dp_edit_more_table-main--00.png)

Вкладка «Дополнительные настройки» в админке ДП.

![Вкладка «Дополнительные настройки» ДП «Таблица»: режим отображения, экспорт/импорт, файловый провайдер, автосохранение, секции, ширина](https://help.1forma.ru/help-images/ext-params/table_common_settings.png)

| Настройка | Поле БД | Тип | Что делает | Ограничения |
|----------------|---------|-----|-----------|-------------|
| Ключевой столбец | `KeyColumnId` | int FK → ExtParamTableSettings | Столбец для сопоставления строк при импорте и для множественного выбора | Допустимые типы: Текст, Число, Дата, Дата-время, Деньги, Телефон, Lookup, Выпадающий список, RowID. Без ключевого столбца импорт = полная перезапись |
| Использовать RowID как ключ | `UseRowIdAsKeyColumn` | bit | При импорте строки сопоставляются по порядковому номеру | |
| Отображать как | `DisplayMode` | int | Режим: 0 = Таблица, 1 = Ссылка. Динамический набор полей — отдельный флаг `DisplayAsDynamicSetOfFields` (bit) | В режиме «Ссылка» адрес клика проверяется по общему списку разрешённых схем: веб-адрес открывается в модальном окне, `mailto:`, `tel:` и `e1c:` передаются системному обработчику, схемы вне списка не открываются |
| Максимальная высота (px) | `TableMaxHeight` | int | Макс высота области строк; при превышении — вертикальный скролл. По умолчанию высота строк подстраивается автоматически под содержимое ячеек (учитываются переносы текста, превью изображений, кнопки управления). Минимальная высота строки — 150px. При большом числе строк включается постраничное отображение с серверной подгрузкой данных. Предусмотрена кнопка раскрытия таблицы в модальное окно. | |
| Кол-во строк на странице | `RowsPerPage` | int | Размер страницы при постраничном отображении в карточке задачи (МТФ); 0 — без пагинации, все строки. На отдельном экране ДП-таблицы (маршрут `/spa/noframe/extparam/{id}`) настройка не применяется: таблица всегда показывает все строки сразу | |
| Разрешить экспорт | `ExportEnabled` | bit | Иконка экспорта в правом верхнем углу таблицы | Экспортируются только столбцы с включённым ExportEnabled |
| Разрешить импорт | `ImportEnabled` | bit | Иконка импорта в правом верхнем углу таблицы | Импортируются только столбцы с включённым ImportEnabled; без ключевого столбца — полная перезапись |
| Загружать файлы в момент вкладывания | `UploadWhenFileAttach` | bit | Файл загружается в БД сразу при выборе, а не при сохранении таблицы | |
| Число параллельных загрузок | `NumberOfParallelDownloads` | int | Количество одновременных загрузок файлов | |
| Файловый провайдер | `FileProviderId` | int FK → FileProviders | Провайдер хранения файлов для файловых колонок | Учитывается только при ручном изменении, смарт-действии «Скачать файл» и Lua. Другие смарт-действия используют провайдер по умолчанию |
| Сохранять строку после редактирования (автосохранение) | `AutosaveEnabled` | bit | После Add/Delete/Edit строка сохраняется автоматически; кнопка «Сохранить» скрыта. Переключатель находится на вкладке секций, над списком секций, а не на «Дополнительных настройках». При выключенном автосохранении несохранённые правки таблицы не мешают другим действиям в той же карточке задачи: смена другого дополнительного параметра и добавление комментария не показывают диалог сохранения таблицы, правки остаются. Диалог показывается при попытке покинуть карточку задачи | Tab/Enter не сбрасывает выделение ячейки |
| Создавать строки в модальном окне | `AddNewRowModal` | bit | При нажатии «+» открывается модальное окно для ввода значений. В колонке «Выпадающий список» при раскрытии списка фокус сразу переходит в строку поиска — значения можно фильтровать с клавиатуры | |
| Включить секции столбцов | `IsSectionsEnabled` | bit | Включает группировку колонок в секции | Работает в обоих режимах сохранения — и при автосохранении, и при сохранении по кнопке |
| Режим ширины по умолчанию | `TableWidthDefault` | int | 0 = По умолчанию, 1 = По размеру экрана, 2 = По содержимому, 3 = По содержимому и заголовкам | |
| Скрыть кнопку добавления строк | `HideAddRowsButton` | bit | Кнопка «+» скрыта; строки можно добавлять только через множественный выбор | |
| Показать колонку с порядковым номером | `ShowRowNumbers` | bit | В таблице показывается колонка с порядковым номером строки. По умолчанию выключено: нумерация — отдельная колонка, которую включает администратор категории | |
| Скрыть номера строк | `HideRowNumbers` | bit | Скрывает служебную колонку с номерами строк в таблице | Нумерация продолжает считаться и приходит в данных строки — настройка влияет только на показ колонки |
| Запретить перемещение строк | `DisableRowReorder` | bit | Запрещает менять порядок строк: и пункты меню строки, и перетаскивание отклоняются с ошибкой. Запрещает и вставку строки на позицию: если в сохранении пришла позиция (строка-якорь и «выше/ниже»), сохранение отклоняется с ошибкой, строки при этом не меняются | На добавление без позиции, удаление, импорт и экспорт строк не влияет |
| Табличный вид иерархии множественного выбора | `IsHierarchyMultiselect` | bit | В окне множественного выбора показывает иерархическое дерево вместо плоского списка (если ключевой столбец ссылается на иерархический Lookup). Сортировка и группировка в режиме дерева недоступны, фильтрация работает. Выбор накапливается поверх поиска по дереву, раскрытия ветвей и перехода по уровням: счётчик «Выбрано» считает выбранные конечные элементы, а папки при запрете их выбора в таблицу не переносятся. Дерево раскрывается до уже выбранных строк; если ничего не выбрано — открывается только корневой уровень | Требует иерархического Lookup в ключевом столбце |
| Хранить html представление | `StoreHtmlPresentation` | bit | Сохранение HTML-представления в GZip для отображения в списке задач категории | Без этого флага значение не пишется в ExtParamValues.ExtParamValueGZip. **Ограничение размера:** HTML-снимок ограничен 6900 байт; строки, не поместившиеся в лимит, тихо отбрасываются без предупреждения. Фактическое количество строк в снимке может быть меньше `RowsToRender`. Данные в таблице сохраняются полностью — ограничение касается только отображения в списке задач категории и Excel-экспорта оттуда. В карточке задачи все строки отображаются корректно. |
| Режим Excel | `IsExcelMode` | bit | Включает Excel-подобное поведение таблицы: копирование блоков ячеек, поведение Enter/Tab как в Excel. Табличный параметр в этом режиме становится **листом книги категории** — см. «Книга листов категории» | Не включается у табличного параметра, привязанного больше чем к одной категории: сохранение настроек возвращает ошибку «Табличный доп. параметр в режиме Excel уже привязан к другой категории и не может быть листом двух книг», и флаг не меняется |
| Столбец для множественного выбора | `MultiselectColumnId` | int FK → ExtParamTableSettings | Ключевой Lookup-столбец для режима множественного выбора. Задаётся на вкладке «Настройки множественного выбора», в поле «Ключевой столбец»; пока столбец не выбран, там же показано предупреждение «Не выбран ключевой столбец» | Тип столбца = Lookup |
| Переносить заголовки по строкам | `HeaderWrap` | bit | Длинные заголовки столбцов и секций переносятся по строкам в пределах ширины колонки, шапка становится выше | По умолчанию выключено. Заголовок занимает не больше трёх строк, полный текст — в подсказке |
| Режим сравнения версий | `ComparisonMode` | tinyint | 0 = Выключено (по умолчанию), 1 = Последнее редактирование, 2 = Конкретная версия. Включает подсветку отклонений в столбцах, где задан тип сравнения — см. «Сравнение с эталоном» ниже | Работает только в новой таблице ДП. Смена режима удаляет накопленный эталон по всему ДП |

**Перенос заголовков и высота таблицы.** При включённой настройке «Переносить заголовки по строкам» высота области строк считается по фактической высоте шапки и высотам отрисованных строк, поэтому высокая шапка не отнимает место у данных: пока строки помещаются, вертикальной прокрутки нет, а при переполнении включаются прокрутка и подгрузка строк с сервера.

**Номера строк.** Слева у таблицы есть служебная колонка с номерами строк — как в Excel: номер показывает место строки в таблице и не меняется ни при фильтрации, ни при сортировке, ни при переходе на другую страницу. Удаление строки пропуска не оставляет — следующие строки сдвигаются на освободившийся номер. Настройка «Скрыть номера строк» убирает колонку с экрана, но сам номер продолжает считаться и приходит в данных строки. Настройка «Запретить перемещение строк» убирает возможность менять порядок: перемещение пунктами меню и перетаскиванием отклоняется с ошибкой. Обе настройки по умолчанию выключены — у таблиц, которым их не задавали, колонка номеров показывается, а порядок строк меняется как раньше.

**Ячейка в конце строки зависит от доступности перемещения.** Действия строки живут в её правом конце: когда порядок строк менять можно, там меню «⋯» с перемещением, вставкой строки выше и ниже и удалением; когда перемещение недоступно — из-за сортировки, группировки, запрета перемещения в настройках таблицы, режима только для чтения, формы новой задачи или сквозного ДП без задачи-источника, — но удалять строки можно, на месте меню стоит корзинка, и клик по ней помечает строку на удаление. Доступность перемещения считает одна функция, поэтому пункты меню и перетаскивание строки за номер включаются и выключаются одновременно.

При режиме «Отображать как» = динамический набор полей (`DisplayAsDynamicSetOfFields`) таблица показывается не сеткой, а набором полей: каждая строка выводится отдельным блоком со своими подписями столбцов, строки добавляются кнопкой «Добавить строку». Сигнал об изменении таблицы обрабатывается в обоих режимах показа: и сетка, и набор полей перечитывают данные без обновления страницы, в том числе когда таблицу меняет правило автоматизации, действие или второй экземпляр того же параметра в другой вкладке группы блоков.

**Отмена сохранения смарт-пакетом.** Если на этой таблице настроено действие «Отменить» на событиях «Перед сменой ДП» или «Перед сохранением значений в строке ДП Таблица», нажатие «Сохранить» в режиме «динамический набор полей» показывает окно с текстом причины из действия: остаются «Ок» и «Копировать», кнопки «Создать задачу в техподдержку» нет, значения строки не сохраняются. При включённом автосохранении окна нет — отмена проходит молча. Режим показа и автосохранение задаются в общих настройках таблицы.

![ДП «Таблица» в виде набора полей: каждая строка — блок с подписями столбцов и кнопкой «Добавить строку»](https://help.1forma.ru/help-images/ext-params/table_like_fields.png)

## Книга листов категории

Табличные дополнительные параметры категории с включённым режимом Excel (`IsExcelMode`) образуют **книгу листов** — набор листов одной табличной области, между которыми работают формулы со ссылкой на другой лист (например, `Лист2!c5r3`). Книга — не файл и не отдельная сущность: книга — это сама категория, а её листы — табличные параметры категории в режиме Excel. Содержимое книги у каждой задачи своё, состав и порядок листов общие на категорию.

- **Состав книги** — все табличные параметры категории с включённым режимом Excel. Табличные параметры без режима Excel и параметры других типов в книгу не входят и работают как прежде: такой параметр по-прежнему можно привязать к нескольким категориям.
- **Порядок листов** совпадает с порядком полей на форме задачи: сначала параметры, собранные в блоки (по порядку блоков, внутри блока — по позиции параметра), затем параметры вне блоков — в порядке привязки к категории.
- **Имя листа** — имя параметра в категории; если имя в категории не задано, берётся имя самого параметра. По этому имени строятся межлистовые формулы, поэтому имена параметров в пределах категории не повторяются — в том числе различающиеся только регистром.
- **Один лист — одна книга.** Лист нельзя привязать ко второй категории: привязка отклоняется. По той же причине нельзя включить режим Excel у табличного параметра, который уже привязан больше чем к одной категории: сохранение настроек таблицы возвращает ошибку «Табличный доп. параметр в режиме Excel уже привязан к другой категории и не может быть листом двух книг», и режим не включается. Параметр с единственной привязкой включается как обычно.
- **Скрытый лист.** Признак видимости хранится на привязке листа к категории. Скрытый лист остаётся в составе книги, но не отдаётся пользователю ни в настройках таблицы, ни в расчётном снимке: его формулы и значения другим листам недоступны, а расчёт остальных листов от этого не ломается. Права на лист проверяются по привязке к категории, а не по самому параметру.

При копировании категории лист-таблица копируется в отдельный параметр со своей структурой столбцов и настройками — исходный и новый лист дальше редактируются независимо.

## Типы столбцов (ExtParamTableSettings.Type)

Доступные типы столбцов таблицы и их особенности:

| Тип | Type (tinyint) | Особенности |
|----------|---------------|-------------|
| Текст | 1 | Маска, столбец шаблона значения |
| Большой текст без форматирования | 14 | Textarea, без маски |
| Выпадающий список | 2 | Опции в ExtParamTableOptions; или ссылка на ДП через ReferencedExtParamId |
| Текст с маской | 3 | Маска: Email, Phone, пользовательскые через спецсимволы (0 = цифра, a = буква, * = любой) |
| Деньги | 4 | Поддержка итогов (EnableTotal); диапазон ±922 337 203 685 476.99 |
| Дата и время | 5 | Формат DD-MM-YYYY hh:mm для стандартного значения |
| Дата | 11 | Формат DD-MM-YYYY для стандартного значения |
| Телефон | 6 | Форматированное отображение |
| Lookup | 7 | Настройки через ReferencedExtParamId (→ ExtParams) и LookupParamSettingID (→ LookupParamSettings); поддержка смарт-фильтров, каскадных зависимостей |
| Чекбокс | 8 | bool |
| Число | 9 | Поддержка итогов (EnableTotal); диапазон ±99 999 999 999 999; настройки через ReferencedExtParamNumberSettings |
| Файл | 10 | Мультифайл, сканирование, превью, логирование действий; провайдер наследуется от таблицы |
| Виртуальная | 12 | Только для чтения; ссылка на Lookup-столбец + поле категории; наследует настройки Lookup (включая «Отображать как текст»); режим «Невидимая» не поддерживается |
| Шаблонная | 13 | Mustache-подобный шаблон: `{{c123.stringValue}}`; регистрозависимо; без фильтрации |
| Блок кнопок | 15 | JS-выражение или смарт-пакет; видимость/активность по колонкам или смарт-фильтру; без фильтрации |
| Выбор пользователей | 16 | Настройки через ReferencedExtParamId (→ ExtParams типа Users); перенос строк влияет на множественный выбор |
| URL | 17 | Значение выводится кликабельной ссылкой; схема проверяется по общему списку разрешённых схем — см. «Дополнительные настройки столбцов по типам» ниже |

Проверка размера и отображение состояния загрузки файлов в ячейке описаны в Frontend: ДП типа File и MultiFile, раздел «Файлы в табличных ДП».

Число в колонке «Type» — код типа в серверном перечислении `ColumnType` (`Valhalla.Integration/Dto/Tasks/ExtParams/ColumnType.cs`), оно же лежит в `ExtParamTableSettings.Type`.

## Настройки столбца (ExtParamTableSettings)

Вкладка «Столбцы» в админке ДП — список всех столбцов таблицы с типом, порядком, сортировкой, маской, режимом и значением по умолчанию; кнопка «Создать» добавляет новый столбец.

![Вкладка «Столбцы»: список столбцов таблицы с типом, порядком, сортировкой и режимом, кнопка «Создать»](https://help.1forma.ru/help-images/ext-params/dp_edit_more_table-columns-settings-0.png)

Клик по столбцу — как и клик по иконке шестерёнки в колонке «Настройки» — открывает карточку с его полными настройками.

Карточка столбца — одна форма без вкладок: сначала общие поля «Имя», «Порядок», «Тип», затем блоки, зависящие от типа столбца (ДП-ссылка, «Шаблон» для шаблонной колонки, LookUpField и «Параметр» для виртуальной, набор кнопок, файловые настройки), затем остальные общие настройки — название секции, сортировка по умолчанию, маска, режим, ширина, макс высота, выравнивание, прикрепление, экспорт/импорт, перенос строк, видимость в секциях, участие в поиске и группировке, «Итого», столбец шаблона значения.

Блоки, зависящие от типа, показываются по типу, выбранному в форме: как только в поле «Тип» выбран тип столбца, соответствующие поля появляются сразу — до сохранения столбца. Поэтому ссылки виртуальной колонки, шаблон шаблонной колонки и поле «ДП-ссылка» можно задать уже при создании столбца, не сохраняя его промежуточно и не открывая карточку заново.

Тип, выбранный в форме, имеет приоритет над сохранённым: если в карточке открытого столбца сменить «Тип», состав блоков меняется сразу, а введённые значения полей остаются в форме до сохранения столбца. Исключения остаются прежними: «Логировать действия с файлами» и «Столбец шаблона значения» появляются, как только в форме выбран тип «Файл» или «Текст».

![Карточка настройки столбца: имя, порядок, тип, секция, режим, ширина, прикрепление, экспорт](https://help.1forma.ru/help-images/ext-params/table_column_edit.png)

| Настройка | Поле БД | Тип | Что делает |
|----------------|---------|-----|-----------|
| ID | `ID` | int PK | Идентификатор столбца |
| Имя | `Name` | varchar | Название столбца в UI |
| Порядок | `OrderID` | int | Порядок расположения; 0 = по порядку создания |
| Тип | `Type` | tinyint | Тип данных (см. таблицу выше) |
| Режим | `Mode` (в API) / `Locked` + `IsHidden` (в БД) | — | Необязательно / Обязательно / Только для чтения / Скрытая / Невидимая |
| Значение по умолчанию | `DefaultValue` | varchar | Пустое / Фиксированное / смарт-выражение (DefaultValueSmartExpressionId) |
| Смарт-выражение | `SmartExpressionId` | int FK | Вычисление значения; вычисляется после сохранения «не-смарт» столбцов; порядок — по OrderID. При наличии смарт-выражения режим «Обязательно» для столбца недоступен |
| Маска | `Mask` | varchar | Для текстовых столбцов; новая таблица: 0=цифра, a=буква, *=любой |
| Столбец шаблона значения | `TemplateColumnId` (в ExtParamTableTextColumnSettings) | int FK | Ссылка на Lookup/Текст столбец с шаблоном RegEx; только для типа Текст |
| Ширина | `ColumnWidth` | int | 0 = авто, 1/2/4/6 = диапазон растягивания, другие = px |
| Макс высота | — | — | Устаревшее, не используется |
| Выравнивание | `Align` | tinyint | 0=лево, 1=центр, 2=право, 3=ширина (не поддерж. в новой таблице) |
| Прикрепить слева | `Locked` | int | Фиксация столбца при горизонтальной прокрутке |
| Итого | `EnableTotal` | bit | Строка итогов под таблицей; только Число и Деньги |
| Показывать отклонения | `ComparisonType` | tinyint | 0 = Выключено, 1 = Прямая метрика, 2 = Обратная метрика, 3 = Только факт изменения. Задаёт, как подсвечивать отличие значения ячейки от эталона. Поле появляется в карточке столбца, только когда у таблицы выбран режим сравнения версий |
| Сортировка по умолчанию | `DefaultSort` | int (enum `SortTypeEnum`) | 0 = нет (None), 1 = по возрастанию (Ascending), −1 = по убыванию (Descending); только один столбец; пересортировка срабатывает автоматически после любого изменения значения в строке (ручное редактирование или смарт-кнопка) |
| Участвует в группировке, порядок | `DefaultGroupingOrder` | int NULL | Номер позиции в группировке таблицы по умолчанию; пусто — столбец не участвует в группировке. Чем больше число, тем глубже уровень вложенности. Не применяется при включённом режиме секций — приоритет за секциями. Группировка действует только при просмотре и редактировании сохранённой задачи; на форме создания задачи (НТФ) столбцы не группируются, чтобы можно было добавлять и редактировать строки до сохранения. Столбцы группировки по умолчанию скрываются из сетки, как при группировке вручную; при снятии группировки столбец возвращается с прежней видимостью |
| Разрешить экспорт | `ExportEnabled` | bit | Столбец участвует в экспорте; скрытые не экспортируются |
| Разрешить импорт | `ImportEnabled` | bit | Столбец участвует в импорте; скрытые и только для чтения не импортируются |
| Перенос строк | `UseLineBreak` (в API) | bit | Текст переносится по ширине вместо обрезки. В столбце «Блок кнопок» переносит кнопки на следующие строки внутри ячейки (без настройки кнопки идут в один ряд и обрезаются границей колонки). Для Users — ограничение одним пользователем |
| Название секции | `SectionId` | int FK → ExtParamTableSections | Принадлежность к секции |
| Видимость в закрытой секции | `IsVisibleInClosedSection` (в API) | bit | Столбец виден когда секция свёрнута |
| Видимость в открытой секции | `IsVisibleInOpenSection` (в API) | bit | Столбец виден когда секция развёрнута |
| Участвует в поиске | `IsUsedInSearch` (в БД) | bit | Управляет двумя механизмами: (1) **Поиск «в полях»** — столбец включается в полнотекстовый поиск по задачам категории в режиме «в полях»; (2) **Фильтр «Содержит»** на колонке ДП Таблица в списке задач категории — поиск ведётся только по строкам столбцов, у которых флаг включён. Если флаг отключён у всех столбцов, фильтр «Содержит» вернёт 0 задач. Фильтры «Нет значения» и «Есть значение» от этого флага не зависят. **Диагностика:** если фильтрация по содержимому ДП Таблица не работает / поиск «в полях» не находит значения из таблицы — первым делом проверить этот флаг. Также требуется настроенный шаблон (`ItemTemplate`) и `StoreHtmlPresentation` = true. См. [Списки задач → Решение проблем](https://help.1forma.ru/domains/grids/support-guide.md) (§ 1.3). |
| Логировать действия с файлами | `IsLogFileReadsAction` (в API) | bit | Запись в журнал Диск; только для типа Файл |
| Локализованное название | `LocalizedNameId` | int FK → LocalizedBusinessObjects | Перевод названия столбца |
| Ссылка на ДП | `ReferencedExtParamId` | int FK → ExtParams | Для Lookup, Select, Users, Number — ДП-источник настроек |
| Виртуальная: Lookup-столбец | `VirtualColumnReferencedLookupColumnId` | int FK | Lookup-столбец, из которого берётся ссылка на задачу |
| Виртуальная: ДП категории | `VirtualColumnReferencedExtParamId` | int FK → ExtParams | Поле категории для отображения |
| Настройки Lookup | `LookupParamSettingID` | int FK → LookupParamSettings | Полные настройки Lookup (фильтры, каскады, вид) |
| Источник данных | `DataSource`, `DataValueField`, `DataTextField` | varchar | Для Выпадающего списка — SQL или набор опций |
| Set of elements as DataSource | `SetOfElementsAsDataSource` (в API) | bit | Опции берутся из ExtParamTableOptions |

**Режимы столбца подробнее.** «Обязательно» — в пользовательском режиме поле выделяется курсивом; проверка действует только в рамках ДП «Таблица» и только для новых и изменённых в текущем сеансе строк, поэтому не блокирует создание задачи; пустые обязательные ячейки в ранее существовавших строках подсвечиваются красным, но сохранению не мешают. «Скрытая» — столбец не отображается и недоступен для вычислений, к нему не обращается автоматизация. «Невидимая» — столбец скрыт от пользователя, но доступен автоматизации; не поддерживается для типов «Виртуальная» и «Шаблонная».

Режим «Невидимая» действует при обоих способах отображения таблицы: невидимый столбец не показывается ни при просмотре строк, ни при добавлении новой и в проверке обязательности не участвует — незаполненным он сохранению не мешает.

**Ширина колонки и минимальная ширина по типу.** Ширина колонки в карточке задачи динамическая: пользователь меняет её перетаскиванием границы столбца, а кнопка в панели инструментов переключает режимы «По заголовкам / По размеру экрана / По содержимому». Какой бы узкой пользователь ни сделал колонку, она не сожмётся ниже минимальной ширины, рассчитанной по типу столбца: минимум зависит от формата значения — у колонок «Деньги», «Число», «Нумератор» и «Телефон» он вмещает типовое значение вместе с разделителями разрядов и дробной частью, у колонок с коротким содержимым он меньше.

Если значение всё же длиннее доступной ширины ячейки (например, в денежной колонке длинное число, а соседние колонки растянуты), оно обрезается внутри своей ячейки и не выходит за её границы — текст соседних колонок не перекрывается. У текстовых колонок с включённой настройкой «Перенос строк» поведение прежнее: текст переносится по строкам внутри ячейки.

## Дополнительные настройки столбцов по типам

### Lookup

Настраивается через создание/выбор ДП типа Lookup (`ReferencedExtParamId`). Наследует все настройки ДП Lookup: категория, смарт-фильтр, каскадные зависимости, вид. Если ссылочный Lookup иерархический, колонка наследует и настройку «Загружать все дерево»: при выключенном флаге дерево в ячейке подгружается по уровням, поиск выполняется на стороне сервера, а выбранный в ячейке элемент показывается с полным путём в иерархии — ветка предков до него раскрывается автоматически.

### Выбор пользователей

Настраивается через создание/выбор ДП типа Users (`ReferencedExtParamId`). Настройки: группы, фильтры пользователей.

### Выпадающий список

Варианты: через `ExtParamTableOptions` (локальные опции) или через `ReferencedExtParamId` → ДП типа List.

### Файл

Настройки файлового столбца:

| Настройка | Описание |
|-----------|----------|
| Разрешить сканирование | Иконка сканирования при добавлении строки |
| Создавать системные копии при акцепте подписи | Системная копия файла при подписании |
| Отображать превью для картинок | Превью с размерами; не работает для мультифайл |
| Мультифайл | Несколько файлов в ячейке |
| Работа с Word | Наследует настройки ДП «Файл» (блок «Работа с файлами Word») |

### Число

Настраивается через ДП типа Число (`ReferencedExtParamId`). Диапазон: ±99 999 999 999 999.

### Деньги

Настраивается через ДП типа Деньги (`ReferencedExtParamId`). Диапазон: ±922 337 203 685 476.99.

### Виртуальная

Столбец только для чтения, отображающий поле из задачи, на которую ссылается Lookup-столбец:

| Настройка | Описание |
|-----------|----------|
| Lookup-столбец | Уже настроенный Lookup-столбец в этой таблице |
| ДП категории | Параметр из категории, на которую смотрит Lookup |
| Превью (для файлового ДП) | Высота/ширина превью, флаг отображения |

Режим: только для чтения. Режим «Невидимая» не поддерживается.

Если виртуальная колонка отображает значение ДП из связанной задачи, то при изменении этого ДП значение в таблице обновляется в реальном времени у всех пользователей, у которых задача открыта сейчас или была открыта в течение последнего часа. Автообновление не работает для проектных ДП-Таблиц (настроенных через `ProjectTableJSONExtParamID`).

### Шаблонная

Mustache-подобный шаблон для объединения в одном столбце данных из нескольких других столбцов таблицы. Синтаксис: `текст1 {{c123.stringValue}} текст2 {{c456.stringValue}}`, где 123 и 456 — ID столбцов. Запись регистрозависима (`stringValue` — верно, `StringValue` — нет). Принципы шаблонов — по [документации Mustache](https://mustache.github.io/mustache.5.html). В пользовательском режиме фильтрация по шаблонному столбцу невозможна.

### Блок кнопок

Столбец с кнопками действий (JS-выражение или смарт-пакет):

| Настройка | Описание |
|-----------|----------|
| Имя | Текст на кнопке (если нет иконки) или подсказка (если есть) |
| Описание | Подсказка при отсутствии иконки |
| Иконка | Из набора `/spa/content-icons` |
| JavaScript выражение | JS-код; доступны `event.originalEvent`, `event.data`, `event.block.reload/freeze/unfreeze`. Через `event.data` доступны поля строки по названию столбца таблицы (например, `event.data.isActive`) |
| Колонка идентификатора (int) | Столбец, возвращающий ID объекта; в смарт-пакете доступен как параметр «Идентификатор объекта». Имя столбца должно точно совпадать с именем поля в возвращаемом наборе данных (например, `TaskID`), регистрозависимо |
| Пакеты действий | Смарт-пакет по нажатию; в его смарт-выражениях доступны параметры события: идентификатор объекта (из столбца идентификатора или ID строки), строка с JSON-объектом, ID кнопки, параметры текущего пользователя |
| URL | Смарт-выражение → URL для модального окна после смарт-пакета. Адрес относительный (`/spa/tasks/12345`) или абсолютный (`https://…/spa/tasks/12345`); абсолютный — только по `https` |
| Колонка видимости (bool) | Столбец, определяющий видимость кнопки |
| Колонка активности (bool) | Столбец, определяющий активность кнопки |
| Сообщение при успехе | Текст всплывающего уведомления после успешного выполнения действия |
| Сообщение при ошибке | Текст всплывающего уведомления при ошибке выполнения действия |
| Информационное сообщение при нажатии | Текст модального диалога подтверждения перед выполнением действия |
| Режим видимости | Смарт-фильтр: Блокировать (disabled) или Скрыть (hidden) |

JS или смарт-пакет — взаимоисключающие. Фильтрация по столбцу невозможна. При нажатии все кнопки автоблокируются; разблокировка через `event.block.unfreeze()`. Вызов методов веб-сервисов из JS-выражений описан в отдельном разделе руководства администратора.

### URL

Столбец хранит адрес и показывает его кликабельной ссылкой — и в колонке, и в ячейке. Схема адреса проверяется по общему для платформы списку разрешённых схем — тому же, что у ДП «URL» (см. [types-reference.md](https://help.1forma.ru/domains/ext-params/types-reference.md), раздел «ДП «URL (ссылка)»»): адреса с веб-схемой (`http:`, `https:`) открываются в новой вкладке, адреса со схемами `mailto:`, `tel:`, `e1c:` браузер передаёт системному обработчику, адрес с любой другой схемой клик не открывает. Собственных настроек у столбца нет: значение вводится как текст.

## Секции столбцов (ExtParamTableSections)

Группировка столбцов в сворачиваемые секции:

![Вкладка «Настройка секций колонок»: список секций с порядком и признаком «по умолчанию развёрнуто»](https://help.1forma.ru/help-images/ext-params/table_sections.png)

| Настройка | Поле БД | Описание |
|-----------|---------|----------|
| Имя | `SectionName` | Название секции. Рядом с полем — значок локализации (глобус): по клику вводится перевод названия секции на каждый активный язык системы; в карточке задачи заголовок секции показывается на языке профиля пользователя. |
| Порядок | `SectionOrder` | Порядок расположения |
| По умолчанию развёрнуто | `IsDefaultExpanded` | Секция развёрнута или свёрнута |

Требования: включён флаг `IsSectionsEnabled` в настройках таблицы. Автосохранение не обязательно: секции работают и в режиме накопительного сохранения, когда правки применяются одним запросом по кнопке «Сохранить». Сворачивание и разворачивание секции при этом не сбрасывает несохранённые изменения в остальных колонках.

На этой же вкладке, над списком секций, находится переключатель «Сохранять строку после редактирования» — он перенесён сюда с вкладки «Дополнительные настройки», на прежней вкладке его больше нет. Пока переключатель выключен, над ним показывается предупреждение: строки таблицы нужно сохранять кнопкой «Сохранить», автоматического сохранения нет. Как только переключатель включён, предупреждение исчезает.

Способ сохранения влияет только на то, когда правки уходят на сервер: на состав и поведение секций он не влияет — группировка столбцов работает и при автосохранении, и при сохранении по кнопке.

Для каждого столбца: `SectionId` + `IsVisibleInClosedSection` + `IsVisibleInOpenSection`.

В карточке задачи столбцы выводятся сгруппированными под общими заголовками секций.

![Таблица с секциями столбцов: колонки сгруппированы под общими заголовками секций](https://help.1forma.ru/help-images/ext-params/dp_table-sec-01.png)

## Множественный выбор (Multiselect)

Отметки в окне накапливаются: поиск, фильтрация, сортировка, группировка, переход между страницами и уровнями иерархии и кнопка обновления уже отмеченные строки не снимают, а по кнопке применения в таблицу уходят все отмеченные объекты независимо от того, в каком месте списка они были отмечены. В иерархическом окне при запрете выбора папок в подсчёт и в таблицу попадают только выбранные конечные элементы. Если ранее отмеченные строки пропадают при поиске, это дефект, а не следствие фильтра: накопительный выбор есть в сборке 2.268 «Скульптор» и для плоского окна, и для иерархического.

Настройка: `MultiselectColumnId` → Lookup-столбец в таблице.

**Ключевой столбец.** Ключевой столбец для множественного выбора задаётся на этой же вкладке — в поле «Ключевой столбец» над списком столбцов. Пока столбец не выбран, над полем показано предупреждение «Не выбран ключевой столбец»; после выбора столбца предупреждение пропадает. В списке поля — Lookup-столбцы таблицы; значение сохраняется настройкой `MultiselectColumnId`.

![Вкладка «Настройки множественного выбора»: поле «Ключевой столбец» с предупреждением, когда столбец не выбран, и список столбцов — какие показывать при множественном выборе, их ширина и порядок](https://help.1forma.ru/help-images/ext-params/table_multiselect.png)

Во вкладке «Настройки множественного выбора»: для каждого столбца — флаг «Использовать в множественном выборе», ширина, порядок, прикрепление.

Параметры отдельного столбца в этом списке правятся в окне «Редактирование множественного выбора».

![Окно «Редактирование множественного выбора»: имя столбца, флаг «Использовать в множественном выборе», ширина, порядок, прикрепление](https://help.1forma.ru/help-images/ext-params/dp_edit_more_table06.png)

Отдельная вкладка «Вид множественного выбора» настраивает внешний вид окна выбора: стиль и выравнивание столбцов, тип фильтра, доступность и видимость по умолчанию, порядок и закрепление колонок, группировку.

![Вкладка «Вид множественного выбора»: стиль, выравнивание, тип фильтра, доступность, видимость, порядок и закрепление столбцов](https://help.1forma.ru/help-images/ext-params/table_view-0.png)

В карточке задачи множественный выбор вызывается кнопкой на панели инструментов таблицы.

![Кнопка «Множественный выбор» на панели инструментов таблицы](https://help.1forma.ru/help-images/ext-params/dp_table_mult_icon-02.png)

Откроется окно со списком значений ключевого столбца; отмеченные строки добавляются в таблицу по кнопке «Применить». Как ведёт себя окно при отборе: накопление отметок поверх поиска и фильтрации, счётчик «Выбрано», поведение по «Обновить» и при закрытии без применения — в [business.md](https://help.1forma.ru/domains/ext-params/business.md), раздел «Множественный выбор (для ключевого столбца)».

**Обязательные колонки при множественном выборе.** Если у обязательной колонки задано значение по умолчанию, оно подставляется в добавляемые строки автоматически. Если значения по умолчанию нет, а колонка выведена в окно множественного выбора, её нужно заполнить в окне: до этого применение не выполняется, незаполненные ячейки подсвечиваются, а в сообщении перечислены колонки — «Заполните: …». Если обязательная колонка в окно не выведена, заполнить её там нельзя, и выводится сообщение «Обязательные колонки не выведены в окно множественного выбора. Настройку изменяет администратор: …» — в этом случае администратору нужно либо задать колонке значение по умолчанию, либо включить её отображение в окне выбора.

![Окно множественного выбора: список значений с галочками и кнопка «Применить»](https://help.1forma.ru/help-images/ext-params/many_select_table.png)

Кнопка множественного выбора **не отображается** в следующих случаях:

- В задаче активны настройки «Ограничить добавление новых строк» или «Ограничить удаление строк» (из настроек ДП в подкатегории).
- Таблица открыта в **НТФ (форме постановки задачи)** — кнопка не отображается до момента создания задачи. Это ожидаемое ограничение, не баг.
- Таблица доступна пользователю **только для чтения**.

**Большой объём значений.** Если ключевой Lookup-столбец смотрит на большой справочник или категорию с множеством задач, окно множественного выбора станет неудобным. Ограничить набор отображаемых значений можно смарт-фильтром в настройках Lookup-столбца.

## Права доступа к столбцам

### По группам пользователей (ExtParamTableSettingsInSubcatGroupPermissions)

Настраивается для каждого столбца и подкатегории. Режим контроля: `GroupAccessControlMode`.

### По статусам задачи (ExtParamTableSettingsInSubcatStatePermissions)

Настраивается для каждого столбца и подкатегории. Включается флагом `StateAccessControlEnabled`.

Тип доступа: чтение или запись.

### По SMART-выражению

Видимость столбца можно поставить в зависимость от SMART-выражения: в диалоге настройки доступа столбца включается переключатель «Доступ зависит от SMART» и выбирается выражение (флаги `SmartAccessControlEnabled` и `VisibilitySmartExpressionId`). Выражение вычисляется для конкретной задачи; если оно возвращает ложь — столбец скрывается в карточке. Режим действует поверх доступа по группам и статусам: SMART может только скрыть уже видимый столбец, вернуть скрытый — нет. При ошибке вычисления выражения столбец остаётся видимым (fail-open, ошибка пишется в лог). В карточке столбец появляется и исчезает без перезагрузки страницы.

### Сочетание с доступом ДП

Явное право «Редактировать», выданное группе на столбце, снимает запрет «только для чтения», пришедший от групповых прав на сам ДП, — и только его. Типичный случай: у группы на ДП есть только чтение, а на одном столбце выдано «Редактировать»; пользователь этой группы видит всю таблицу и редактирует ячейки только этого столбца, остальные остаются только для чтения. Правило работает, когда у столбца включён контроль по группам (`BYGROUP`, `BYTASKANDGROUP` или `BYTASKORGROUP`).

Остальные запреты столбцовое «Редактировать» не снимает — если работает любой из них, столбец остаётся только для чтения:

- нет права на редактирование задачи, задача закрыта или ДП заблокирован активной подписью;
- смарт-доступ не даёт записи;
- у ДП включено «только для чтения» после заполнения;
- по статусу столбцу выдано только «Чтение» — групповое «Редактировать» статусное ограничение не повышает;
- столбец уже имеет режим «Только для чтения», «Скрытая» или «Невидимая»;
- столбец «Виртуальная» и столбец множественного выбора остаются нередактируемыми.

Явное «Чтение» на столбце оставляет его только для чтения, даже если группе на ДП выдано редактирование. Добавление и удаление строк считаются от доступа к самому ДП и правом на столбце не открываются. Серверная проверка на сохранении опирается на тот же признак, что и интерфейс, поэтому правка ячейки и импорт из Excel ведут себя одинаково. От того же расчёта зависит и кнопка импорта из Excel: она показывается, только если пользователю доступен на редактирование хотя бы один импортируемый столбец. Поэтому на таблице только для чтения кнопки импорта нет; если право на редактирование даёт ровно один столбец с включённым импортом — кнопка остаётся, и импорт разрешён по этому столбцу. Кнопка экспорта от доступности редактирования не зависит.

## Динамическая обязательность

Вкладка «Динамическая обязательность» задаёт правила, по которым отдельные ячейки строк ДП «Таблица» становятся обязательными к заполнению по условию: если в строке выполнены проверки по значениям других столбцов, то значение в целевой колонке этой строки обязательно.

Признак обязательности вычисляется на уровне строки — одно и то же поле в разных строках может быть обязательным или нет в зависимости от значений соседних ячеек той же строки. Незаполненная обязательная ячейка блокирует сохранение строки, в том числе при добавлении строки через модальное окно.

Правила действуют в обоих режимах отображения таблицы. В режиме «Динамический набор полей» обязательное поле помечается звёздочкой у подписи, а незаполненное — подсвечивается цветом ошибки и не даёт сохранить строку.

![Вкладка «Динамическая обязательность»: карточка правила (Активный, Целевая колонка, Логика условий), условия ещё не заданы](https://help.1forma.ru/help-images/ext-params/table_dynamic_obligation_2.png)

Кнопка «Добавить правило» создаёт новое правило; для одной таблицы можно создать несколько правил — они хранятся и применяются независимо. Поля правила:

| Поле | Описание |
|------|----------|
| Активный | Правило участвует в проверке. Со снятым флажком правило сохраняется, но не применяется |
| Целевая колонка | Столбец, который становится обязательным при выполнении условий правила |
| Логика условий | «И (все условия)» — правило срабатывает только при выполнении всех условий; «ИЛИ (любое условие)» — при выполнении хотя бы одного |
| Условия | Список проверок (кнопка «Добавить условие»); пока их нет — «Нет условий» |

Каждое условие состоит из трёх частей: столбец условия (любой столбец таблицы, кроме целевого), оператор сравнения и значение для сравнения. Для столбцов типа «Выпадающий список» варианты значения подгружаются из настроек столбца.

![Условие правила: столбец, оператор «= (равно)» и значение, кнопка × для удаления условия](https://help.1forma.ru/help-images/ext-params/table_dynamic_obligation_3.png)

Операторы сравнения: `=` (равно), `≠` (не равно), `>` (больше), `<` (меньше), `≥` (больше или равно), `≤` (меньше или равно), пусто, не пусто, содержит, не содержит.

Правило удаляется кнопкой «Удалить» в его карточке, отдельное условие — кнопкой × рядом с ним.

Хранение: правила — в `ExtParamTableRequiredRules` (`TargetColumnId`, `LogicOperator`, `IsActive`), условия — в `ExtParamTableRequiredConditions` (`RuleId`, `ConditionColumnId`, `CompareOperator`, `CompareValue`).

**Методы API.** Правила обязательности таблицы ведутся теми же маршрутами, что и правила форматирования, — на идентификатор самого табличного параметра, а не колонки:

| Метод | Маршрут | Назначение |
|---|---|---|
| GET | `/api/admin/extparams/table/{tableId}/required-rules` | Все правила таблицы |
| POST | `/api/admin/extparams/table/{tableId}/required-rules` | Создать правило |
| PUT | `/api/admin/extparams/table/{tableId}/required-rules/{ruleId}` | Обновить правило |
| DELETE | `/api/admin/extparams/table/{tableId}/required-rules/{ruleId}` | Удалить правило |

**Форма ответа.** На создание и обновление сервер отвечает конвертом с полем `data`, внутри которого лежит правило: идентификатор созданного правила приходит внутри `data`. Клиент разворачивает конверт перед использованием ответа — без этого у только что созданного правила не появляется идентификатор, форма настроек расходится с состоянием, принятым сервером, и следующее сохранение пытается удалить правило по адресу с пустым идентификатором. После успешного сохранения нового правила страница настроек уходит на список ДП.

## Условное форматирование колонок (ExtParamTableColumnFormattingRules)

Позволяет раскрашивать ячейки таблицы по условиям (по аналогии с Excel): «больше N — красным», «совпадает с X — зелёным», «в диапазоне A..B — жёлтым» и т.п. Правила задаются для каждой колонки ДП Таблица.

**Где настраивается:** в админке — на странице настроек ДП Таблица (см. ниже «Интерфейс настройки в админке»); программно — через Admin API (маршрут `/api/admin/extparams/table/{tableId}/formatting-rules`).
**Таблица БД:** `dbo.ExtParamTableColumnFormattingRules` (FK → `ExtParamTableSettings.Id`).

### Интерфейс настройки в админке

Редактор правил встроен в страницу настроек ДП: когда открыты настройки ДП с типом Таблица, появляется секция управления правилами форматирования. Правила сохраняются вместе с остальными настройками ДП.

**Что видит администратор:**

- Кнопка «**+ Добавить правило**» в шапке секции.
- Список карточек-правил (если правил нет — пустое состояние «Правил нет»). Карточки автоматически пересортированы по приоритету.
- В каждой карточке: заголовок «Правило N», чекбокс «**Активно**» и кнопка «**Удалить**» (с подтверждением; удаляется сразу).

**Поля карточки:**

| Поле | Контрол | Поведение |
|------|---------|-----------|
| Колонка | выпадающий список с поиском | Список **только форматируемых колонок**: Число, Деньги (числовые) и Текст (текстовая). Остальные типы колонок в список **не попадают** |
| Тип правила | выпадающий список с поиском | Состав зависит от типа выбранной колонки: для числовой — 11 вариантов (больше/меньше/между/вне диапазона + минимум/максимум + дубликаты), для текстовой — 7 вариантов (содержит/начинается/… + дубликаты). При смене колонки несовместимый тип сбрасывается на первый доступный |
| Значение X | число (для числовых) / текст (для текстовых) | Скрыто для «Минимум»/«Максимум»/«Дубликаты». Обязательное для остальных |
| Значение Y | число / текст | Появляется **только** для «Между»/«Вне диапазона». Обязательное. Должно быть больше X (иначе ошибка «X должен быть меньше Y») |
| Цвет | выпадающий список | 12 вариантов (Default, Primary, Red, …, Grey) |
| Тон | выпадающий список | 5 вариантов (None, White, Light, Normal, Dark) |
| Приоритет | число, ≥0 | Обязательное. При выходе из поля карточки пересортировываются по новому значению |

**Сохранение.** Изменения правил применяются при сохранении формы ДП: новые правила создаются, удалённые — удаляются, изменённые — обновляются. При ошибке любой операции показывается сообщение.

### Поля правила

Состав одного правила условного форматирования (хранится в `ExtParamTableColumnFormattingRules`):

| Поле БД | Тип | Описание |
|---------|-----|----------|
| `Id` | int identity PK | |
| `ColumnId` | int NOT NULL, FK → ExtParamTableSettings.Id | На какую колонку правило |
| `RuleType` | tinyint, enum `EpTableFormattingRuleType` | Тип правила — см. ниже |
| `ValueX` | nvarchar(500) NULL | Первое значение условия (число/текст); для Min/Max/Duplicates — не используется |
| `ValueY` | nvarchar(500) NULL | Второе значение условия (для Between/Outside — верхняя граница); иначе не используется |
| `Color` | nvarchar(50) NOT NULL | Цвет — см. ниже |
| `ColorTone` | nvarchar(50) NOT NULL | Тон цвета — см. ниже |
| `Priority` | int NOT NULL | Приоритет: при пересечении условий первым применяется правило с меньшим значением |
| `IsActive` | bit DEFAULT 1 | Активность правила |

### Типы правил (RuleType)

**Числовые** — применимы только к колонкам типа Число и Деньги:

| Значение | Описание | Что требуется |
|----------|----------|---------------|
| GreaterThan (0) | Значение > X | ValueX |
| LessThan (1) | Значение < X | ValueX |
| GreaterOrEqual (2) | Значение ≥ X | ValueX |
| LessOrEqual (3) | Значение ≤ X | ValueX |
| Equal (4) | Значение = X | ValueX |
| NotEqual (5) | Значение ≠ X | ValueX |
| Between (6) | X ≤ Значение ≤ Y | ValueX + ValueY |
| Outside (7) | Значение < X или > Y | ValueX + ValueY |
| Min (20) | Минимум в колонке | — |
| Max (21) | Максимум в колонке | — |

**Текстовые** — применимы только к колонкам типа Текст, Большой текст без форматирования, Текст с маской:

| Значение | Описание | Что требуется |
|----------|----------|---------------|
| Contains (10) | Содержит подстроку | ValueX |
| NotContains (11) | Не содержит | ValueX |
| StartsWith (12) | Начинается с | ValueX |
| EndsWith (13) | Заканчивается на | ValueX |
| TextEqual (14) | Точное равенство (строка) | ValueX |
| TextNotEqual (15) | Точное неравенство (строка) | ValueX |

**Универсальные** — любой тип колонки:

| Значение | Описание | Что требуется |
|----------|----------|---------------|
| Duplicates (22) | Подсветить дубликаты в колонке | — |

### Цвет (Color) и тон (ColorTone)

**Color:** `Default`, `Primary`, `Red`, `Pink`, `Purple`, `Green`, `Yellow`, `Orange`, `Blue`, `Cyan`, `Brown`, `Grey` — 12 значений.

**ColorTone:** `None`, `White`, `Light`, `Normal`, `Dark` — модификатор насыщенности.

Это те же палитры, что используются в портальных виджетах. В БД оба поля хранятся как **строковые имена** значений (`Color`, `ColorTone`).

### Методы API

Управление правилами форматирования через Admin API:

| Метод | Маршрут | Назначение |
|-------|---------|------------|
| GET | `/api/admin/extparams/table/{tableId}/formatting-rules` | Все правила для ДП Таблица (включая неактивные) |
| POST | `/api/admin/extparams/table/{tableId}/formatting-rules` | Создать правило |
| PUT | `/api/admin/extparams/table/{tableId}/formatting-rules/{ruleId}` | Обновить |
| DELETE | `/api/admin/extparams/table/{tableId}/formatting-rules/{ruleId}` | Удалить |

`tableId` — ID самого ДП Таблица (`ExtParams.Id`), а не ID колонки. ID колонки передаётся в теле запроса.

### Валидация при сохранении

При сохранении правила проверяется:

| Проверка | Когда срабатывает |
|----------|-------------------|
| ДП с указанным `tableId` имеет тип «Таблица» | Передан ID не-таблицы |
| Колонка принадлежит этой таблице | Попытка создать правило для чужой колонки |
| Тип правила совместим с типом колонки | Например, «Содержит» для колонки Число |
| Тип правила — допустимое значение | Передан неизвестный код правила |
| Цвет и тон — допустимые значения | Передан неизвестный цвет/тон |
| `ValueX` указан для правил, требующих X | Пустой `ValueX` для «Больше» и пр. |
| `ValueY` указан для «Между»/«Вне диапазона» | Пустой `ValueY` |
| `ValueX` **пустой** для «Минимум»/«Максимум»/«Дубликаты» | Лишний `ValueX` |
| `ValueY` **пустой** для всех правил, кроме «Между»/«Вне диапазона» | Лишний `ValueY` |
| Не более **50 правил на одну колонку** | Попытка создать 51-е правило |
| При изменении/удалении: правило принадлежит таблице из запроса | `tableId` не совпадает с фактической таблицей правила |

При нарушении правило не сохраняется, API возвращает ошибку с локализованным сообщением (ru/en).

### Применение правил в таблице

**Алгоритм для каждой ячейки:**

1. Берётся список правил форматирования колонки.
2. Отбрасываются неактивные.
3. Активные сортируются по приоритету (меньше — раньше).
4. Для каждого правила по порядку проверяется условие; **применяется первое подходящее** — его цвет и тон задают подсветку ячейки. Если ни одно не подошло — ячейка без подсветки. Правила **не комбинируются**.

**Агрегаты «Минимум»/«Максимум»/«Дубликаты»** считаются по **видимым** строкам таблицы; группы и строки итогов исключаются. Поэтому при фильтрации или группировке набор видимых строк меняется и подсветка минимума/максимума пересчитывается.

**Особенности правил:**

- «Между»/«Вне диапазона»: порядок ValueX и ValueY на результат не влияет.
- «Содержит»/«Не содержит»/«Начинается с»/«Заканчивается на» при пустом значении не срабатывают (и через интерфейс сохранить такое правило нельзя).
- «Точное равенство»/«Точное неравенство» работают и с пустой строкой как с допустимым значением.

### Журнал изменений

Любое изменение правила (создание, изменение, удаление) записывается в журнал администрирования. Журнал доступен через интерфейс «Журнал администрирования» или таблицу `AdminActionLog`.

### Ограничения

Что нужно учитывать при настройке условного форматирования:

- **Форматирование поддерживается только для колонок Число, Деньги и Текст.** Для остальных типов колонок (Большой текст без форматирования, Текст с маской, Lookup, MultiLookup, Дата и т.д.) правила в интерфейсе создать нельзя. У столбцов Lookup и MultiLookup цвет берётся из связанной задачи или справочника по прежней логике, а не из этой вкладки.
- **«Минимум»/«Максимум»/«Дубликаты» считаются по видимым строкам**, а не по всем данным таблицы. При фильтрации или группировке набор видимых строк меняется — подсветка пересчитывается.
- **Лимит 50 правил на одну колонку.** При попытке создать 51-е правило — ошибка.
- **Дубликаты правил не запрещены:** можно создать два правила с одинаковым условием, различающихся только приоритетом и цветом; сработает то, что выше по приоритету. При одинаковом приоритете применяется первое совпавшее правило (в порядке создания).
- Для правил «Между»/«Вне диапазона» значение Y должно быть строго больше X.

## Сравнение с эталоном (подсветка отклонений)

Сравнение с эталоном показывает, что значение ячейки отличается от сохранённого прежнего значения. Это не условное форматирование: правило форматирования красит ячейку по сравнению с константой из настройки, а сравнение с эталоном — по сравнению с тем, что было в этой же ячейке раньше. Если сработали оба механизма, цвет отклонения перекрывает цвет условного форматирования.

Функция включается двумя настройками: «Режим сравнения версий» у таблицы и «Показывать отклонения» у каждого столбца, который нужно сравнивать. Столбцы с выключенным типом сравнения не сравниваются и не подсвечиваются.

### Режим «Последнее редактирование»

Эталон накапливается сам: при каждой правке ячейки её прежнее значение записывается в эталон и при следующей правке перезаписывается. Поэтому сравнение идёт с предыдущим сохранённым значением, а не с первым за всю историю: последовательность 10 → 15 → 18 → 20 даст подсказку «Было: 18 (+2)».

Подсказка появляется сразу после сохранения правки, без перезагрузки страницы: прежнее значение и разница показываются в том же виде, что и значение в ячейке, — с тем же числом знаков после запятой и с учётом формата столбца. Поэтому у столбца с двумя знаками «200 → 50» даст «Было: 200,00 (-150,00)», а не сырое число с длинным хвостом.

**Первое значение ячейки не отслеживается.** Первым считается то значение, с которым строка создана: пустое — в таблице с автосохранением при добавлении строки сразу сохраняется пустая строка — или любое непустое, если автосохранения нет. Записи эталона по такой ячейке не создаётся, подсветки нет. Если первое значение пустое, не отслеживается и первое заполнение этой ячейки: для пользователя оно и есть первое значение. Отслеживается всё, что после него: смена непустого значения, очистка и заполнение после очистки. «Первое значение» и «заполнение после очистки» различаются по наличию записи эталона — очистка записывает предыдущее значение, поэтому «пусто, затем 3» после очистки показывается как изменение с подсказкой, а первое заполнение пустой ячейки новой строки — нет.

Очистка ячейки — такое же изменение, как правка: «20 → пусто» подсвечивается, а в эталон попадает пустое значение. Следующее заполнение этой ячейки — отдельное изменение с подсказкой «Было: (пусто)». Цепочка «2 → пусто → 3» даёт ровно два подсвеченных изменения: сначала «2 → пусто», затем «пусто → 3».

Подсветка показывает разницу между текущим и предыдущим сохранённым значением, поэтому она снимается, когда значение возвращают к предыдущему: текущее совпало с эталоном — изменения нет. Возврат к более раннему значению, не совпадающему с эталоном, — обычная правка, и подсветка покажет обратное направление.

### Режим «Конкретная версия»

Эталон — снимок текущих значений сравниваемых столбцов. Пока версия не зафиксирована, отклонений нет; после фиксации подсвечивается всё, что отличается от снимка.

Снимок ставят и снимают два стандартных смарт-действия над задачей: «Fix table comparison version» — зафиксировать версию, «Clear table comparison version» — снять. Параметры действия: задача, пользователь и ДП «Таблица». Русских названий у этих действий нет, в списке действий они показаны по-английски. Оба работают только при режиме «Конкретная версия» — в других режимах вызов ничего не меняет. Повторная фиксация полностью заменяет предыдущий снимок, снятие удаляет эталон целиком; одновременно существует один снимок либо ни одного.

Типовой сценарий — согласование: смарт-действие на переходе статуса фиксирует версию, проверяющий видит отклонения сразу после сохранения таблицы, после утверждения версия снимается и подсветка исчезает.

### Цвета и подсказка

| Цвет ячейки | Когда |
|---|---|
| Зелёный | Число стало больше эталона; у столбца с обратной метрикой — меньше |
| Красный | Число стало меньше эталона; у столбца с обратной метрикой — больше |
| Голубой | Значение изменилось, но направление не показывается: столбец нечисловой или выбран тип «Только факт изменения» |

Направление считается только для столбцов «Число» и «Деньги»; «Телефон» числовым не считается.

В подсказке к изменённой ячейке выводится прежнее значение — «Было: 10». Для столбцов «Число» и «Деньги» в скобках добавляется разница со знаком — «Было: 10 (+10)»; разница округляется и форматируется так же, как само значение столбца. Строка итогов не подсвечивается.

Строка, добавленная после фиксации версии (в режиме «Последнее редактирование» — любая добавленная строка), выделяется голубым в тех столбцах, где включено сравнение. Удалённые строки отдельно не показываются.

Подсветка появляется после сохранения строки, без перезагрузки страницы; пока открыт редактор ячейки, обновление откладывается до конца ввода.

### Когда эталон очищается

- смена режима сравнения таблицы или типа сравнения любого столбца — эталон удаляется по всему ДП, во всех задачах;
- полная перезапись таблицы и её очистка;
- удаление строки — вместе со строкой удаляется её эталон;
- смарт-действие снятия версии.

При смене порядка строк эталон переносится вместе со строкой.

### Ограничения

- Сравнение и подсветка работают только в новой таблице ДП — она включается настройкой [`newEpTable`](https://help.1forma.ru/domains/system/settings-custom.md) для перечисленных в ней категорий и пользователей.
- Сразу после включения режима «Последнее редактирование» подсветки нет: эталон пуст и накапливается с первой правки.
- Настройка столбца «Показывать отклонения» доступна, только когда у таблицы выбран режим сравнения версий.

## Формула, формат и защита ячейки (Excel-режим)

В Excel-режиме (настройка «Режим Excel», `IsExcelMode`) ячейка хранит не только значение, но и формулу, формат ячейки и признак защиты. Они лежат в `ExtParamTableValues` — в колонках `Formula`, `CellFormat` и `IsBlocked` — и выходят в денормализованное представление как `Column{ID}Formula`, `Column{ID}CellFormat` и `Column{ID}IsBlocked`. Формулу считает браузер, сервер сохраняет присланное значение и саму формулу не пересчитывает.

**Сохранение ячейки.** Ячейки передаются в `cols[]` строк запроса `POST task/{taskId}/ep/table/{tableId}/update`:

```json
{
  "rows": [
    {
      "id": 12,
      "modifyType": "update",
      "cols": [
        {
          "id": 123,
          "value": "12.5",
          "excel": { "formula": "=A2+B2", "cellFormat": "0.00", "isBlocked": false, "calculationError": null }
        }
      ]
    }
  ]
}
```

У ячейки, кроме `id` и `value`, есть необязательный объект `excel` с полями `formula`, `cellFormat`, `isBlocked` и `calculationError`. Отсутствие ключа и явная очистка различаются разбором тела запроса:

- **ключа `excel` нет** — формула, формат, защита и код ошибки расчёта не трогаются: обычная правка значения их не стирает;
- **объект `excel` есть** — применяются только перечисленные в нём поля; `null` в поле означает очистку (снять формулу, формат или код ошибки расчёта);
- **пришли обе формы** — плоские поля `Formula`, `CellFormat`, `IsBlocked` и `CalculationError` уступают объекту `excel`; плоской формой пользуется импорт из Excel (адреса вида `A2` при импорте переводятся во внутренние ссылки `cXrY`, при экспорте — обратно);
- **пришла только плоская форма** — применяется она.

Excel-поля записываются только у запросов, которые их несут по смыслу: такие запросы помечает флаг `WriteCellExtras`. Его ставят сохранение из грида карточки и импорт из Excel. Потребители, передающие только значения ячейки (загрузка файла в ячейку, смарт-действие обновления строк, синхронизация), флаг не ставят — их сохранение формулу, формат и защиту не затирает.

**Ответы сервера.**

| Ситуация | Ответ |
|----------|-------|
| Сохранение корректно | 200 |
| Формула или код ошибки расчёта длиннее 1000 символов | 400; в БД значение не усекается |
| Смена защиты ячейки без права «Администратор категории» | 403 |

Формула и код ошибки расчёта хранятся в колонках по 1000 символов, поэтому при превышении длины отклоняется всё сохранение, а не обрезается ячейка. Сменой защиты считается только фактическое изменение признака: переданное значение, совпадающее с хранимым, а также `false` для новой строки, права не требуют.

**Ошибка расчёта.** Колонки «Число» и «Деньги» не принимают нечисловое значение, поэтому код ошибки расчёта хранится в отдельном поле ячейки (`calculationError` в API, колонка `CalculationError`), а значение при ошибке остаётся пустым. Поле отдаётся вместе с данными ячейки в DTO чтения.

**Включение и выключение режима Excel.** Переключение флага данные не пересчитывает: уже записанные формулы и форматы остаются в ячейках как есть. Выключение режима не удаляет формулу, формат и защиту ячейки — они сохраняются в данных и снова действуют, когда режим включат обратно. Включение режима у табличного ДП, привязанного больше чем к одной категории, отклоняется, и флаг при этом не меняется.

**Версия представления ссылок.** Ссылка внутри формулы хранится во внутреннем виде `c{ColumnId}r{RowId}`. У этого представления есть версия: формула без префикса — историческая форма, которая читается как есть; префикс `v{N}:` в начале формулы задаёт версию явно. Неизвестная версия — явная ошибка, а не разбор чужого представления своим: иначе ячейка получила бы правдоподобное, но неверное значение. Ячейки в старом и новом представлении могут соседствовать в одной таблице — каждая читается по своей версии.

**Формула для пользователя и формула в хранении.** Пользователь видит и вводит формулу в формате Excel на языке интерфейса: при русском интерфейсе `=СУММ(D3:E3)`, при остальных — английский вид. В хранении формула лежит в каноническом виде `v2:` с английскими именами функций, английскими кодами ошибок и разделителями `,`; ссылки — во внутреннем виде `c{ColumnId}r{RowId}`. Между этими формами формулу переводит сервер: у клиента нет собственного разбора, поэтому показ, ввод, импорт и выгрузка дают один и тот же текст для одной и той же формулы.

- **Чтение.** При открытии карточки таблица отдаёт для ячейки с формулой поле `formulaText` — Excel-текст на языке пользователя; поле есть только у таблицы в режиме Excel, у остальных оно `null`. Расчётный снимок книги отдаёт для формулы дерево выражения `expr` — по нему фронт считает значения, не разбирая текст.
- **Ввод.** Ячейка в `update` может нести `excel.formulaText` — Excel-текст на языке пользователя или английский. Сервер разбирает его, переводит в каноническое хранение и записывает вместе со значением. Прислать в одной ячейке и `formula` (хранение), и `formulaText` нельзя — такой запрос отклоняется с ошибкой.
- **Разбор без сохранения.** `POST task/{taskId}/ep/table/{tableId}/formula/parse` принимает текст формулы и возвращает дерево выражения `expr` и нормализованный `formulaText`, а при ошибке — список `errors` с кодом, позицией в тексте пользователя (с 1; 0 — позиция неизвестна) и фрагментом, который не разобрался. Тот же разбор выполняется при сохранении, поэтому позиция ошибки в ответе `update` совпадает с той, что показывает редактор.
- **Что не поддерживается.** Формула вне модели расчёта отклоняется явной ошибкой с адресом ячейки, а не сохраняется как есть: ссылка на целую колонку (`A:A`) или строку (`1:1`), трёхмерная ссылка, ссылка на другую книгу, именованный диапазон, функция вне словаря первой волны, массив-константа (`{1,2}`) и объединение ссылок.
- **Словарь показа.** Настройки таблицы в режиме Excel отдают словарь `ExcelFormulaLexicon`: как показывать коды ошибок и логические значения и какие разделители использовать в подсказках редактора. У таблицы без режима Excel словаря нет.

**Ошибка расчёта при импорте.** Ячейка, прочитанная из файла, несёт не только значение, формулу и формат, но и код ошибки расчёта: цепочка чтения листа (`DevExpressSheetReadEngine` → `ExcelModelMapper` → `EpTableExcelReaderService`) переносит признак ошибки ячейки в поле `CalculationError` сохраняемой ячейки. Поэтому ячейка с ошибкой расчёта (`#REF!`, `#VALUE!` и подобными) попадает в таблицу сразу с кодом ошибки, а не остаётся с пустым полем до первой правки через Excel-объект.

## Шаблон в табличных представлениях (ExtParamTableTemplate)

Для отображения ДП Таблица в списке задач категории. Настраивается на вкладке «Шаблон в табличных представлениях»: флаги «Использовать шаблон», «Отображать кол-во строк», «Хранить html представление», число отображаемых строк и заголовок.

![Вкладка «Шаблон в табличных представлениях»: флаги использования шаблона и хранения HTML, число строк, заголовок](https://help.1forma.ru/help-images/ext-params/ExtParamTableTemplate--0005.png)

| Настройка | Поле БД | Описание |
|-----------|---------|----------|
| Использовать шаблон | `Enabled` | Активация шаблона |
| Отображать количество строк | `RenderTotalRows` | Показ общего числа строк |
| Количество отображаемых строк | `RowsToRender` | Сколько первых строк выводить; 0 = пустой объект, без HTML. При 0 изменения значений ДП также не порождают UPDATE-запросов к `ExtParamValues` (экономия БД при больших таблицах без шаблона) |
| Заголовок | `HeaderTemplate` | HTML в начале |
| Шаблон строки | `ItemTemplate` | HTML с тегами `<cell columnid="...">` для каждой строки |
| Разделитель | `SeparatorTemplate` | HTML между строками |
| Футер | `FooterTemplate` | HTML в конце |
| Хранить html представление | → `StoreHtmlPresentation` в CommonSettings | GZip-хранение в ExtParamValues.ExtParamValueGZip |
| Синхронизировать существующие задачи | — | Пересчёт HTML для существующих задач при изменении шаблона |

Шаблон строки собирается из тегов `<cell columnid="...">` подстановкой названий столбцов; ниже задаются разделитель между строками и футер.

![Шаблон строки таблицы из тегов <cell columnid> с подстановкой столбцов, разделитель и футер](https://help.1forma.ru/help-images/ext-params/ExtParamTableTemplate--04.png)

Тег ячейки в шаблоне строки выводится пустой строкой, если в настройках таблицы нет столбца с указанным `columnid` (например, столбец удалён, а тег в шаблоне остался) или у строки нет значения этого столбца.

HTML-представление хранится в `ExtParamValues.ExtParamValueGZip`. При денормализации → `ExtParamNativeValue`. Фоновое задание `TableExtParamValuesGZipCompressJob` каждые 3 минуты сжимает по 10000 строк.

### Массовый пересчёт при «Синхронизировать существующие задачи»

Настройка «Синхронизировать существующие задачи» пересчитывает сохранённое HTML-представление по задачам тех категорий, в которых используется этот ДП, — не только по той категории, где меняли шаблон. Сам шаблон сохраняется сразу: пересчёт вынесен из транзакции и не держит HTTP-запрос. До исправления пересчёт выполнялся синхронно, и на большой категории сохранение с галочкой падало по таймауту SQL («Время ожидания выполнения истекло»), а применённые настройки не сохранялись.

Пересчёт идёт в фоне, курсором по `TaskID`, порциями примерно по 500 задач. Повторное сохранение с галочкой во время идущего обхода второй обход параллельно не запускает: текущий доводится до конца, затем выполняется контрольный повтор.

Ограничения, о которых стоит помнить:

- **Прогресса и уведомления о завершении в интерфейсе нет.** Остановился пересчёт или продолжается — по экрану настроек не отличить: сбой порции виден только в логе приложения, а пустая ячейка сразу после сохранения с галочкой одинаково выглядит и при идущем пересчёте, и при его сбое. Если через разумное для объёма категории время значения не появились, это повод обратиться в поддержку, а не ждать дальше.
- **При перезапуске приложения незавершённый обход не продолжается сам** — сохранение с галочкой нужно выполнить заново.
- **Координация запусков ведётся в памяти процесса**, поэтому одновременная работа нескольких узлов не синхронизируется.
- **Изменение шаблона без галочки** старые снимки не трогает: часть задач останется в старом виде.

Синхронный пересчёт того же вида остался в других местах (в частности, при работе с табличными ДП из админ-раздела) — на фоновую логику они пока не переведены.

Значение ДП Таблица **не хранится** в `ExtParamValues.ExtParamValue` и `TasksInSubcatXXXDenormalized.ExtParamXXXValue`. Наличие в `ExtParamXXXNativeValue` зависит от флага «Хранить html представление».

**История изменений ДП.** Экран «История изменений ДП» (`params-history`) для табличного ДП показывает этот же html-снимок, а не данные строк: в `ExtParamHistory` для таблицы пишутся `ExtParamValueGZip` и `ExtParamOldValueGZip` (сжатое html-представление), а колонки `ExtParamValue`/`ExtParamOldValue` не заполняются. Поэтому история наследует поведение настроек представления: при выключенном «Хранить html представление» история табличного ДП пустая; при включённом шаблоне отображения она показывает вывод шаблона (заголовок, футер, «Кол-во строк»), а не значения ячеек; ограничение в 6900 байт с тихим отбрасыванием непоместившихся строк действует и здесь. Сами данные строк хранятся в `ExtParamTableValues` и в истории изменений не участвуют.

Колонка табличного параметра в списке задач показывает сохранённое HTML-представление, а не таблицу из карточки. Чтобы представление было, включите «Хранить html представление» и задайте шаблон. Список не должен отвечать ошибкой из-за одной такой колонки: и новое значение, и значения, записанные после перевода денормализации на Unicode, читаются в списке так же, как в карточке. Если список падает только при включённой колонке табличного параметра, это сбой распаковки денормализованного представления, а не прав на столбец.

## Импорт/экспорт Excel

**Экспорт**: выгрузка в XLS. Первая строка — названия столбцов. Lookup — текст задачи. Файл — ссылка на файл.

**Импорт**: XLS/XLSX, одна страница.

| Режим | Описание |
|-------|----------|
| С заголовками (опция включена) | Сопоставление по названиям столбцов |
| Без заголовков (опция выключена) | Сопоставление по порядку столбцов |

Важно:

- Без ключевого столбца: полная перезапись (все строки удаляются, загружаются новые)
- С ключевым столбцом: строки матчатся по ключу (обновление + добавление новых)
- Файловые столбцы при импорте игнорируются
- Lookup при импорте: можно использовать текст задачи или ID задачи
- «Выбор пользователей» при импорте: ячейка содержит идентификаторы пользователей, групп или подразделений — через запятую или `#`, допустимы префиксы `+` и `-`, — либо JSON. Пустая ячейка и ячейка из одних разделителей допустимы. Произвольный текст, в том числе ФИО, отклоняется: значение проверяется на границе импорта, ошибка с указанием значения, строки и колонки возвращается в результате импорта, и весь файл не применяется — данные таблицы остаются прежними
- Скрытые и только для чтения столбцы не импортируются
- Кнопка импорта показывается, только если есть хотя бы один столбец с включённой настройкой «Разрешить импорт», доступный пользователю на редактирование. На таблице, доступной только для чтения, и на таблице, где ни один импортируемый столбец не редактируется, кнопки нет — импорт всё равно не прошёл бы проверку права записи. Кнопка экспорта считается отдельно и на таблице только для чтения остаётся доступной
- Имена столбцов не должны содержать лишних пробелов

**Импорт в новый табличный параметр.** Если параметра ещё нет и при импорте выбран один лист файла, система создаёт один табличный дополнительный параметр из этого листа и даёт ему имя выбранного листа. Если имя листа пустое, параметр получает имя файла. Созданный параметр сразу включается в режим Excel, то есть становится листом книги категории, — по его имени далее строятся межлистовые формулы.

Импорт сразу нескольких листов — отдельная операция: она создаёт отдельный табличный параметр на каждый выбранный лист, в порядке выбора. Если хотя бы один лист не удалось импортировать, все созданные этой операцией параметры удаляются — повтор файла безопасен. Имена листов, различающиеся только регистром, отклоняются до создания параметров.

### Выгрузка в Excel-режиме (формулы и формат ячеек)

Если у таблицы включён режим Excel, выгрузка несёт не только значения, но и формулы и формат ячеек: там, где в ячейке есть формула, в файл записана формула, а значение Excel считает сам при открытии.

- Ссылки внутри формулы выгружаются привычными адресами: на ячейку этой же таблицы — `A1`. Если строки или столбца, на которые ссылается формула, в выгрузке нет (строка удалена, столбец не помечен экспортируемым), на месте ссылки в файле стоит `#REF!`.
- Выгружается вся таблица целиком, а не видимый срез: фильтр, сортировка и страница, выставленные на экране, на состав файла не влияют. Строки идут в порядке идентификатора строки, поэтому адреса в формулах соответствуют строкам файла.
- Если первой колонкой выведен идентификатор строки (настройка «Использовать RowID как ключ»), он выгружается первой колонкой, а колонки данных сдвигаются — адреса в формулах смещаются вместе с ними.
- Формат ячейки переносится в поддерживаемом объёме: шрифт, заливка, границы, числовой формат, выравнивание. Незнакомое или повреждённое описание формата выгрузку не роняет — ячейка выгружается без формата.
- Число колонки «Число» выгружается без потерь сверх точности формата Excel — подробнее в «Точность числовых значений (колонка «Число»)» ниже.

Таблица без режима Excel выгружается как раньше: типизированными значениями, без формул и форматов.

### Колонка со смешанными значениями: числа и текст в одной колонке

Тип колонки в файле определяется самим файлом: если в колонке есть хоть одно число, она читается как числовая, и нечисловой текст в ней — например, `84955433676 (доб 175)` рядом с `89080181818` — значением для неё не является. Формат ячейки «Общий» ничего не предписывает: одно значение Excel хранит числом, другое текстом, потому что `(доб 175)` числом не является.

Разбирается значение по типу колонки ДП, а не по тому, как заведена колонка в файле. В колонку «Текст», «Большой текст», «Маска», «Телефон» и «URL» значение попадает как текст, даже если в файле колонка числовая; «Число» и «Деньги» разбираются числом, «Галочка» — по штатным правилам галочки.

Важно:

- если значение всё же не удалось привести к типу колонки, ячейка остаётся пустой, но импорт считается успешным и остальные строки применяются как обычно. В результате импорта появляется предупреждение с адресом ячейки и названием колонки: «Ячейка B3: значение не удалось преобразовать для колонки «Телефон», оно не импортировано»;
- колонка, целиком состоящая из текста, читается как текст и импортируется без потерь — расхождение возникает только там, где числа и текст смешаны в одной колонке;
- чтобы исключить такие потери заранее, держите телефоны и другие значения с добавочным текстом в отдельной колонке или храните их полностью текстом.

### Поведение при сбое импорта

Если при импорте Excel возникает исключение на уровне БД (например, на PostgreSQL — `Npgsql.PostgresException`), запрос завершается с HTTP 200, в `ImportResultDto.Errors` возвращается сообщение «Ошибка импорта.», и существующий диалог результатов импорта показывает его поверх МТФ. Технические детали (код, inner exception, стек) попадают только в журнал приложения. Данные таблицы при этом не меняются — транзакция не коммитится. Ранее (до 2.268.x) такие исключения уходили как HTTP 500 и порождали вторичный `ObjectDisposedException` из-за разрушения DI-scope.

По тому же пути возвращаются ошибки проверки идентификаторов строк при полной перезаписи — импорте без ключевого столбца. Идентификатор должен быть положительным и уникальным в пределах загружаемого набора: при нулевом или отрицательном значении импорт прерывается сообщением «Недопустимый RowID N в строке M: идентификатор строки должен быть положительным числом», при повторном — «Дублирующийся RowID N в строке M: такой идентификатор уже используется другой строкой этого обновления». M — порядковый номер строки в наборе импорта. Сообщение показывается в диалоге результатов импорта, транзакция откатывается, данные таблицы не меняются.

### Точность числовых значений (колонка «Число»)

Значение колонки «Число» хранится в БД как десятичное число высокой точности (`ExtParamTableValues.DecimalValue` — `decimal(29,15)`, то есть до 15 знаков после запятой). Предел сквозного прохода числа задаёт не ширина столбца, а формат файла Excel: числовая ячейка xlsx хранит число с плавающей точкой двойной точности, поэтому при обмене с Excel гарантируются 15 **значащих** цифр, и целая часть входит в их счёт. Значение `12345.123456789012345` выгружается как `12345.123456789` — эта граница зафиксирована тестом.

| Участок | Что гарантируется |
|---|---|
| Импорт из Excel → БД | потерь сверх содержимого файла нет: в БД попадает то же число, что лежит в ячейке xlsx. Цифры, которых в файле не было, десятичное хранение не восстановит |
| БД → интерфейс и API → БД | значение передаётся строкой в инвариантном формате (разделитель — точка, запятая тоже принимается), поэтому знаки не зависят от культуры пользователя и не теряются |
| БД → расчёт по формулам → БД | формулы Excel-режима считает браузер (JS-число), сервер разбирает полученный результат в decimal — точность самого расчёта при этом не восстанавливается |
| БД → экспорт в Excel | число берётся из `DecimalValue` и остаётся decimal до записи числовой ячейки: выгружаются те же 15 значащих цифр, всё, что длиннее, ожидаемо округляется |

Колонки «Деньги» этим изменениям не подвергались: их значение хранится в отдельной колонке (`MoneyValue`) и выгружается прежним маршрутом.

### Формулы в ячейках

Ячейка таблицы может содержать формулу; результат хранится в колонке значения, а текст формулы — в поле `Formula` строки. Ссылка на другую ячейку внутри таблицы хранится во внутреннем виде `c{ColumnId}r{RowId}` — по идентификаторам колонки и строки, не по адресу вида `A1`; нераспознанная ссылка записывается как `#REF!`.

Значения внешних ссылок — ячейка этой же таблицы, ДП текущей задачи, ДП связанной категории через лукап — сервер отдаёт отдельным запросом `POST task/{taskId}/ep/formula-context`, типизированно и по каждому адресу-токену, с проверкой прав полной матрицей доступа ДП. Числовое значение приходит строкой в инвариантном формате и сохраняет до 15 знаков после запятой.

## Значение по умолчанию — два уровня

Для ДП «Таблица» есть два независимых механизма задания дефолтных значений.

### 1. Предзаполненные строки при создании задачи (уровень ДП в категории)

Настраивается в AdminSPA на странице настроек ДП категории → поле **«Значение по умолчанию»**. При создании задачи (НТФ) таблица будет открыта с уже заполненными строками.

**Формат:** JSON-строка вида `{"rows":[{"c{ID}":"значение",...},...]}`, где `ID` — числовой идентификатор столбца (`ExtParamTableSettings.ID`).

Узнать ID столбца: в AdminSPA → настройки ДП → вкладка «Столбцы» → навести на название столбца или открыть инструменты разработчика браузера (Network → запрос настроек ДП, поле `id` в объекте столбца).

**Примеры:**

```json
// Одна предзаполненная строка, столбцы 123 и 456
{"rows":[{"c123":"Текст по умолчанию","c456":"42"}]}

// Две строки
{"rows":[{"c123":"Строка 1"},{"c123":"Строка 2"}]}
```

Форматы для конкретных типов столбцов:

- Текст, Большой текст — строка: `"Привет"`
- Число, Деньги — строка с числом: `"42"` или `"3.14"`
- Дата — `"DD-MM-YYYY"`, например `"01-01-2026"`
- Дата и время — `"DD-MM-YYYY hh:mm"`, например `"01-01-2026 09:00"`
- Чекбокс — `"true"` / `"false"`
- Lookup — ID задачи: `"12345"`
- Выпадающий список — значение опции: `"Опция 1"`

> Этот JSON перекрывает глобальный `DefaultValue` самого ДП. Если таблица находится в категории с настроенным JSON — используется он; глобальный дефолт ДП игнорируется.

### 2. Значение по умолчанию при добавлении строки пользователем (уровень столбца)

Настраивается на вкладке «Столбцы» → поле **«Значение по умолчанию»** конкретного столбца (`ExtParamTableSettings.DefaultValue` или `DefaultValueSmartExpressionId`). Применяется каждый раз, когда пользователь добавляет новую строку в таблицу — уже существующие строки не затрагиваются.

Поддерживает смарт-выражение (FK `DefaultValueSmartExpressionId`) для динамического вычисления.

Варианты значения: «Оставить пустым» (только для новой таблицы, формат 2.256+), фиксированное значение или смарт-выражение. Фиксированное значение задаётся в особом формате, отличном от смарт-выражений:

- Дата — `DD-MM-YYYY`;
- Дата и время — `DD-MM-YYYY hh:mm`;
- Lookup — `{"ID задачи":"Текст"}` (например `{"123":"Продажа"}`);
- Выпадающий список — `{"Значение":"Текст"}` (например `{"2":"Встреча"}`).
