Страница «Редакции конфигурации» — План реализации
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Реализовать красивую HTML-страницу с матрицей возможностей редакций СТАНДАРТ/ПРОФ/КОРП, которая открывается программно с подсветкой конкретной фичи, когда пользователь пытается использовать недоступную функциональность.
Architecture: Markdown-макет (единый источник правды) → парсер в модуле СЛС → HTML-генератор через РаботаСВебСервер (поток в памяти + ЗаписьТекста, без конкатена ции) → ПолеHTMLДокумента на общей форме. Клиентский фасад СЛСКлиент.ПроверитьДоступностьРедакции(КодФункции) — одна строка в месте вызова.
Tech Stack: 1С:EDT, BSL, MCP EDT (read_module_source, write_module_source, get_project_errors), прямое редактирование .mdo/.form/.txt файлов через Read/Edit/Write.
Spec: docs/superpowers/specs/2026-04-10-editions-page-design.md
Текущее состояние репозитория (до задач)
В ветке uit4 уже есть незакоммиченные изменения, создающие каркас:
- Создана директория
it/src/CommonForms/РедакцииКонфигурации/с пустымиForm.formиРедакцииКонфигурации.mdo it/src/CommonTemplates/РедакцииКонфигурации/РедакцииКонфигурации.mdoизменён (типTextDocument)it/src/CommonTemplates/РедакцииКонфигурации/Template.mxlxудалён (стары й табличный макет)it/src/CommonTemplates/РедакцииКонфигурации/Template.txtсоздан (пустой)it/src/Configuration/Configuration.mdoизменён — добавлена регистрацияCommonForm.РедакцииКонфигурациии перемещёнCommonTemplate.РедакцииКонфигурацииit/src/Roles/БазовыеПраваУФ/Rights.rightsуже содержитViewнаCommonForm.РедакцииКонфигурации
Эти изменения — каркас, на котором базируется план. Они не коммитятся отдельно — первый же Task добавляет к ним новый файл и всё коммитится единым атомарным изменением.
Порядок задач
Task 1: Создать CommonTemplate.css_editions (метаданные + CSS + регистрация)
Task 2: Заполнить Template.txt макета РедакцииКонфигурации Markdown-контентом
Task 3: СЛС.ФункциональностьДоступна — серверная проверка
Task 4: СЛС.ПрочитатьМакетРедакций — парсер
Task 5: СЛС.СформироватьHTMLРедакций + вспомогательные (+ HTMLОшибкиМакетаРедакций)
Task 6: СЛСКлиент.ПроверитьДоступностьРедакции — клиентский фасад
Task 7: Реквизиты формы РедакцииКонфигурации (ТекстHTML, КодФункции)
Task 8: Элемент ПолеHTMLДокумента на форме РедакцииКонфигурации
Task 9: Модуль формы РедакцииКонфигурации (обработчики)
Task 10: Ручное тестирование по чек-листу спецификации
Порядок важен: Tasks 3–6 создают API, который использует форма в Tasks 7–9. Ручное тестирование — только после всех BSL-изменений.
Task 1: Создать CommonTemplate.css_editions
Files:
-
Create:
it/src/CommonTemplates/css_editions/css_editions.mdo -
Create:
it/src/CommonTemplates/css_editions/Template.txt -
Modify:
it/src/Configuration/Configuration.mdo(добавить регистрацию в алфавитном порядке междуcss_docsinum_staticиcss_hack_font) -
Step 1: Создать
css_editions.mdo
Записать в it/src/CommonTemplates/css_editions/css_editions.mdo:
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:CommonTemplate xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="a02b55eb-9f48-4fff-b25c-bc892f55e388">
<name>css_editions</name>
<synonym>
<key>ru</key>
<value>css_editions</value>
</synonym>
<templateType>TextDocument</templateType>
</mdclass:CommonTemplate>
- Step 2: Создать
Template.txtс CSS
Записать в it/src/CommonTemplates/css_editions/Template.txt (~180 строк):
/* === Страница Редакции конфигурации === */
/* Правила окружения: старый webkit 2015+, без @media, без CSS-переменных. */
.editions-panel {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-flex-direction: column;
flex-direction: column;
max-width: 960px;
margin: 0 auto;
padding: 20px;
font-family: "Segoe UI", "Open Sans", Tahoma, Arial, sans-serif;
font-size: 14px;
color: #212529;
line-height: 1.5;
}
/* === Шапка === */
.editions-hero {
margin-bottom: 24px;
padding: 20px 24px;
background: -webkit-linear-gradient(left, #f8f9fa, #e9ecef);
background: linear-gradient(90deg, #f8f9fa, #e9ecef);
border-radius: 6px;
border-left: 4px solid #0066cc;
}
.editions-hero h1 {
margin: 0 0 12px 0;
font-size: 22px;
font-weight: 600;
color: #212529;
}
.current-edition-badge {
display: inline-block;
padding: 6px 14px;
border-radius: 20px;
font-weight: 600;
font-size: 13px;
color: #ffffff;
}
.current-edition-badge.edition-standart {
background-color: #6c757d;
}
.current-edition-badge.edition-prof {
background-color: #0066cc;
}
.current-edition-badge.edition-corp {
background-color: #d4a017;
}
.current-edition-badge.edition-unknown {
background-color: #adb5bd;
}
/* === Введение === */
.editions-intro {
margin-bottom: 24px;
padding: 0 4px;
}
/* Стили markdown для введения идут из css_markdown_content */
/* === Матрица возможностей === */
.editions-matrix {
width: 100%;
border-collapse: collapse;
border: 1px solid #dee2e6;
margin-bottom: 16px;
background-color: #ffffff;
}
.editions-matrix th,
.editions-matrix td {
padding: 8px 12px;
border: 1px solid #dee2e6;
vertical-align: top;
text-align: left;
}
.editions-matrix thead th {
background-color: #343a40;
color: #ffffff;
font-weight: 600;
text-align: center;
position: relative;
}
.editions-matrix thead th.col-feature {
text-align: left;
width: 60%;
}
.editions-matrix thead th.col-edition {
width: 13%;
}
.editions-matrix thead th.col-current {
background-color: #0066cc;
}
.editions-matrix tbody td.col-current {
background-color: #e7f1ff;
}
/* Строка раздела */
.row-section td {
background-color: #343a40;
color: #ffffff;
font-weight: 700;
font-size: 15px;
padding: 10px 12px;
border-top: 2px solid #212529;
}
/* Строка подраздела */
.row-subsection td {
background-color: #e9ecef;
color: #495057;
font-weight: 600;
font-style: italic;
padding: 6px 12px;
}
/* Строка фичи */
.row-feature td {
font-size: 13px;
}
.row-feature td.check {
text-align: center;
font-size: 16px;
color: #28a745;
font-weight: 700;
}
.row-feature td.dash {
text-align: center;
font-size: 16px;
color: #adb5bd;
}
/* Примечание под названием фичи */
.feature-note {
display: block;
margin-top: 4px;
font-size: 12px;
font-style: italic;
color: #6c757d;
}
/* === Подсветка целевой фичи === */
.row-highlighted td {
background-color: #fff3cd;
border-left: 3px solid #dc3545;
}
.row-highlighted td.col-current {
background-color: #ffe8b3;
}
.feature-unavailable-badge {
display: block;
margin-top: 6px;
padding: 6px 10px;
background-color: #dc3545;
color: #ffffff;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
}
/* === Блок ошибки макета === */
.editions-error {
margin: 24px;
padding: 16px 20px;
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c2c7;
border-radius: 4px;
font-family: "Consolas", "Courier New", monospace;
font-size: 12px;
white-space: pre-wrap;
word-wrap: break-word;
}
- Step 3: Зарегистрировать в
Configuration.mdo
Найти блок <commonTemplates> с CSS-макетами (строки ~2443–2455). Вставить новый элемент после css_docsinum_static и перед css_hack_font. Используй Edit для точной вставки:
Найти:
<commonTemplates>CommonTemplate.css_docsinum_static</commonTemplates>
<commonTemplates>CommonTemplate.css_hack_font</commonTemplates>
Заменить на:
<commonTemplates>CommonTemplate.css_docsinum_static</commonTemplates>
<commonTemplates>CommonTemplate.css_editions</commonTemplates>
<commonTemplates>CommonTemplate.css_hack_font</commonTemplates>
- Step 4: Проверить ошибки EDT
MCP: get_project_errors
Expected: no new errors.
- Step 5: Commit
git add it/src/CommonTemplates/css_editions/ it/src/Configuration/Configuration.mdo
git commit -m "feat: Новый макет CSS css_editions для страницы редакций"
Task 2: Заполнить Template.txt макета РедакцииКонфигурации Markdown-контентом
Files:
- Modify:
it/src/CommonTemplates/РедакцииКонфигурации/Template.txt(из пустого → полный макет)
Этот макет — единый источник правды о матрице возможностей. Заполняется однократно на основе Возможности УИТ 4.xlsx и СЛС.УстановитьФункционал() Module.bsl:5321. Для строк с code= маска должна совпадать с ФО-реальностью (параметры СтандАРТ, ПРОФ, КОРП в УстановитьДоступностьФункционала). Для строк без кода — маска берётся из xlsx.
- Step 1: Записать содержимое макета
Записать в it/src/CommonTemplates/РедакцииКонфигурации/Template.txt:
# Возможности "Управление IT-отделом 8"
В программе **"Управление IT-отделом 8"** существует три редакции:
**Стандарт**, **Проф** и **Корп**. Редакции отличаются набором
доступных возможностей. Ниже — полная матрица функционала.
Если вы видите эту страницу, значит функция, к которой вы обратились,
недоступна в вашей редакции. Обратитесь к поставщику для перехода
на редакцию с нужной функциональностью.
## 1. Service Desk (управление инцидентами)
### 1.1. Документ "Задание"
- Создание, редактирование, выполнение заданий | СПК
- Шаблоны заданий/комментариев | СПК
note: Планируется убрать из Стандарта.
- Оценка заданий и лояльность пользователей | СПК
### 1.2. Мастер регистрации
- Функционал Мастера регистрации | СПК
note: Планируется убрать из Стандарта.
### 1.3. SLA (Service Level Agreement)
- Функционал SLA | -ПК | code=SLAСервисыРаботы
note: Сам функционал виден везде, в Стандарте скрыты только услуги.
### 1.4. CRM-подсистема
- Потенциальные клиенты | --К | code=ИспользоватьCRM
### 1.5. Управление проблемами
- Регистрация и отслеживание проблем | --К | code=ИспользоватьПроблемы
### 1.6. Отчёты Service Desk
- Отчёты Service Desk | СПК
note: Планируется дифференцировать набор отчётов по редакциям.
## 2. База знаний
### 2.1. Статьи и каталоги
- Создание статей и каталогов | СПК
- Схемы Mermaid | СПК
note: Планируется убрать из Стандарта.
## 3. Управление проектами
### 3.1. Планирование проекта
- Создание и ведение проектов | СПК
- Канбан-доска | СПК
- Спринты | СПК
### 3.2. Подсистема Agile
- Покер планирования | --К | code=ИспользоватьПокерПланирование
- Ежедневный стендап | --К | code=ИспользоватьЕжедневныйСтендап
- Ретроспектива | --К | code=ИспользоватьРетроспективу
## 4. Сотрудники
### 4.1. Управление сотрудниками
- Справочник сотрудников | СПК
- Закрепление сотрудников за местами хранения | СПК
### 4.2. Анкетирование
- Создание анкет и опросов | --К | code=ИспользоватьАнкетирование
note: Планируется добавить в Проф.
### 4.3. Управле ние доступом к информационным ресурсам
- Просмотр доступных ресурсов | --К | code=ИспользоватьДоступКИнформационнымРесурсам
### 4.4. Заработная плата
- Назначения начислений и удержаний | -ПК
- Начисления заработной платы | -ПК
## 5. Учёт рабочего времени
### 5.1. Ежедневный отчёт
- Документ "Ежедневный отчёт" | --К
### 5.2. Работы
- Учёт трудозатрат сотрудников | СПК
- Наряды на работы | -ПК
- Листы учёта рабочего времени | -ПК
### 5.3. Причины отклонений от графика
- Отслеживание отклонений | СПК
## 6. Логины и пароли
### 6.1. Хранилище
- Хранение логинов и паролей | СПК
- Удалённое подключение к рабочим местам | --К | code=ИспользоватьУдаленноеУправление
note: Удалённое подключение можно настроить вне зависимости от редакции. Выделенный функционал только в КОРП.
## 7. Взаимодействия
### 7.1. Электронная почта
- Входящие/исходящие письма | СПК
- Шаблоны писем | СПК
note: Планируется убрать из Стандарта (требует обсуждения — всё-таки почта).
### 7.2. SMS-сообщения
- Отправка и получение SMS | -ПК | code=ИспользоватьОповещенияПоSMS
### 7.3. Телефония
- Звонки и работа с телефонией | --К
- Журнал звонков | --К
### 7.4. Встречи
- Планирование и проведение встреч | СПК
## 8. Автоматизация
### 8.1. Правила событий
- Правила событий | СПК
note: Планируется дифференцировать набор правил по редакциям.
- Действия правил событий | СПК
## 9. Управление IT-активами
### 9.1. Номенклатура
- Номенклатуры и карточки номенклатуры | СПК
- Комплекты и комплектующие | СПК
### 9.2. Складской учёт
- Места хранения | СПК
- Местоположение | СПК
- Закрепление сотрудников за местами хранения | СПК
- Складской учёт клиентов | --К | code=СкладскойУчетКлиентов
note: Константу можно включить в любой момент, функционал только в КОРП.
### 9.3. Складские документы
- Заказы клиентов и заказы поставщику | СПК
- Поступление, Перемещение, Списание, Инвентаризация | СПК
- Продажа | СПК
- Сборка и разбиение комплектации | СПК
### 9.4. Терминал сбора данных
- Выгрузка данных в и из ТСД | СПК
- Инвентаризация на основании мобильного ТСД | -ПК | code=ИспользоватьМобильныйТСД
### 9.5. Ремонты и обслуживание
- Документ "Начало обслуживания" | -ПК | code=ИспользоватьРемонтыИОбслуживание
- Документ "Окончание обслуживания" | -ПК
- Изменение показателей оборудования | -ПК
### 9.6. Импорт данных
- Загрузка номенклатуры из файла Excel | СПК
- Загрузка из AIDA64 и WMI | СПК
note: Планируется убрать из Стандарта и Проф.
### 9.7. Отчёты складского учёта
- Отчёты складского учёта | СПК
note: Планируется дифференцировать набор отчётов по редакциям.
## 10. Денежные средства
### 10.1. Учёт и взаиморасчёты
- Учёт денежных средств | СПК
- Взаиморасчёты с контрагентами | СПК
- Бюджетирование | --К | code=ИспользоватьБюджетирование
## 11. Первичные документы
### 11.1. Учёт первичных документов
- Учёт первичных документов | СПК
## 12. Интеграция со сторонними сервисами
### 12.1. Каналы взаимодействия
- Личный кабинет | СПК
- Telegram-bot | -ПК | code=ИспользоватьTelegram
- Мобильное приложение | --К
## 13. Администрирование
### 13.1. Обмен и миграция
- Обмен с конфигурациями 1С (справочной информацией) | СПК
note: Планируется убрать из Стандарта.
- Импорт данных из Active Directory | СПК
note: Планируется убрать из Стандарта и Проф.
- Свёртка информационной базы | СПК
note: Планируется убрать из Стандарта.
### 13.2. Настройка и API
- Изменение макетов печатных форм | СПК
note: Обсуждается вариант максимальной настраиваемости только в КОРП.
- Настройка рабочего стола | СПК
note: Планируется убрать из Стандарта.
- REST API | СПК
- Step 2: Проверить ошибки EDT
MCP: get_project_errors
Expected: no new errors (Template.txt — просто текстовый файл, EDT не должен ругаться).
- Step 3: Commit
git add it/src/CommonTemplates/РедакцииКонфигурации/
git commit -m "feat: Макет редакций конфигурации — матрица возможностей в формате Markdown"
Task 3: СЛС.ФункциональностьДоступна — серверная проверка
Files:
-
Modify:
it/src/CommonModules/СЛС/Module.bsl(добавить в областьПрограммныйИнтерфейсрядом с другими функциями о редакциях — около Module.bsl:534, послеЭтоРедакцияКОРП()) -
Step 1: Прочитать контекст вставки
MCP: read_method_source для метода ЭтоРедакцияКОРП в модуле СЛС — убедиться, что вставка будет после этой функции.
- Step 2: Добавить функцию
ФункциональностьДоступна
Вставить после функции ЭтоРедакцияКОРП:
// Возвращает Истина, если функция доступна в текущей редакции конфигурации.
// Проверка делается через значение константы функциональной опции, которую
// устанавливает СЛС.УстановитьФункционал() согласно редакции.
//
// Параметры:
// КодФункции - Строка - Имя константы функциональной опции
// (например, "ИспользоватьCRM").
// Если пустая строка - возврат Истина.
//
// Возвращаемое значение:
// Булево - Истина, если функция доступна.
//
Функция ФункциональностьДоступна(Знач КодФункции) Экспорт
Если НЕ ЗначениеЗаполнено(КодФункции) Тогда
Возврат Истина;
КонецЕсли;
МетаданныеКонстанты = Метаданные.Константы.Найти(КодФункции);
Если МетаданныеКонстанты = Неопределено Т огда
Возврат Истина;
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
Значение = Константы[КодФункции].Получить();
УстановитьПривилегированныйРежим(Ложь);
Возврат Значение = Истина;
КонецФункции
Используй MCP write_module_source для вставки — не трогай Read/Edit напрямую для .bsl файлов (правило CLAUDE.md → Инструменты по типам файлов 1С).
- Step 3: Проверить ошибки EDT
MCP: get_project_errors
Expected: no new errors.
- Step 4: Commit
git add it/src/CommonModules/СЛС/Module.bsl
git commit -m "feat: СЛС.ФункциональностьДоступна — проверка доступности функции по коду"
Task 4: СЛС.ПрочитатьМакетРедакций — парсер макета
Files:
-
Modify:
it/src/CommonModules/СЛС/Module.bsl(добавить публичную функцию вПрограммныйИнтерфейс, служебные — вСлужебныеПроцедурыИФункции) -
Step 1: Добавить публичную функцию
ПрочитатьМакетРедакций
Через MCP write_module_source вставить в область ПрограммныйИнтерфейс (после ФункциональностьДоступна):
// Читает макет "РедакцииКонфигурации" и разбирает его в структуру данных
// с разделами, подразделами и фичами.
//
// Возвращаемое значение:
// Структура - Разобранные данные макета:
// * Введение - Строка - Markdown-текст введения до первого "## ".
// * Разделы - Массив из Структура - Список разделов:
// ** Название - Строка - Название раздела.
// ** Подразделы - Массив из Структура - Список подразделов:
// *** Название - Строка - Название подраздела.
// *** Фичи - Массив из Структура - Список фич:
// **** Название - Строка - Название фичи.
// **** Маска - Строка - Маска доступности (например, "СПК", "-ПК", "--К").
// **** Код - Строка - Имя константы функциональной опции (или пустая строка).
// **** Примечание - Строка - Примечание к фиче (или пустая строка).
//
Функция ПрочитатьМакетРедакций() Экспорт
МакетОбъект = ПолучитьОбщийМакет("РедакцииКонфигурации");
Текст = МакетОбъект.ПолучитьТекст();
Строки = СтрРазделить(Текст, Символы.ПС, Истина);
Результат = Новый Структура("Введение, Разделы", "", Новый Массив);
ТекущийРаздел = Неопределено;
ТекущийПодраздел = Неопределено;
ПоследняяФича = Неопределено;
ВведениеНакапливаем = Истина;
БуферВведения = Новый Массив;
ЗаголовокПройден = Ложь;
Для НомерСтроки = 1 По Строки.Количество() Цикл
Строка = Строки[НомерСтроки - 1];
Если НЕ ЗаголовокПройден И СтрНачинаетсяС(Строка, "# ") Тогда
ЗаголовокПройден = Истина;
Продолжить;
КонецЕсли;
Если СтрНачинаетсяС(Строка, "## ") Тогда
ВведениеНакапливаем = Ложь;
ТекущийРаздел = НовыйЭлементРаздела(СокрЛП(Сред(Строка, 4)));
Результат.Разделы.Добавить(ТекущийРаздел);
ТекущийПодраздел = Неопределено;
ПоследняяФича = Неопределено;
Продолжить;
КонецЕсли;
Если СтрНачинаетсяС(Строка, "### ") Тогда
Если ТекущийРаздел = Неопределено Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Макет редакций: подраздел вне раздела, строка %1'"),
НомерСтроки);
КонецЕсли;
ТекущийПодраздел = НовыйЭлементПодраздела(СокрЛП(Сред(Строка, 5)));
ТекущийРаздел.Подразделы.Добавить(ТекущийПодраздел);
ПоследняяФича = Неопределено;
Продолжить;
КонецЕсли;
Если СтрНачинаетсяС(Строка, "- ") Тогда
Если ТекущийПодраздел = Неопределено Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Макет редакций: фича вне подраздела, строка %1'"),
НомерСтроки);
КонецЕсли;
Фича = РазобратьСтрокуФичиМакетаРедакций(Строка, НомерСтроки);
ТекущийПодраздел.Фичи.Добавить(Фича);
ПоследняяФича = Фича;
Продолжить;
КонецЕсли;
СтрокаБезОтступа = СокрЛ(Строка);
Если СтрНачинаетсяС(СтрокаБезОтступа, "note: ") Тогда
Если ПоследняяФича = Неопределено Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Макет редакций: note без фичи, строка %1'"),
НомерСтроки);
КонецЕсли;
ПоследняяФича.Примечание = СокрЛП(Сред(СтрокаБезОтступа, 7));
Продолжить;
КонецЕсли;
Если ВведениеНакапливаем Тогда
БуферВведения.Добавить(Строка);
КонецЕсли;
КонецЦикла;
Результат.Введение = СокрЛП(СтрСоединить(БуферВведения, Символы.ПС));
Возврат Результат;
КонецФункции
- Step 2: Добавить служебные функции парсера
Через MCP write_module_source вставить в область СлужебныеПроцедурыИФункции (в конце модуля перед закрывающим #КонецОбласти):
// Создает структуру нового раздела макета редакций.
Функция НовыйЭлементРаздела(Знач Название)
Раздел = Новый С труктура;
Раздел.Вставить("Название", Название);
Раздел.Вставить("Подразделы", Новый Массив);
Возврат Раздел;
КонецФункции
// Создает структуру нового подраздела макета редакций.
Функция НовыйЭлементПодраздела(Знач Название)
Подраздел = Новый Структура;
Подраздел.Вставить("Название", Название);
Подраздел.Вставить("Фичи", Новый Массив);
Возврат Подраздел;
КонецФункции
// Разбирает одну строку фичи макета редакций вида
// "- Название | Маска | атрибут1 | атрибут2"
Функция РазобратьСтрокуФичиМакетаРедакций(Знач Строка, Знач НомерСтроки)
ТелоСтроки = СокрЛ(Сред(Строка, 3));
Части = СтрРазделить(ТелоСтроки, "|", Ложь);
Если Части.Количество() < 2 Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Макет редакций: ожидается ""- Название | Маска"", строка %1'"),
НомерСтроки);
КонецЕсли;
Фича = Новый Структура("Название, Маска, Код, Примечание", "", "---", "", "");
Фича.Название = СокрЛП(Части[0]);
Фича.Маска = ВалидироватьМаскуРедакций(СокрЛП(Части[1]), НомерСтроки);
Для Индекс = 2 По Части.ВГраница() Цикл
Атрибут = СокрЛП(Части[Индекс]);
Если СтрНачинаетсяС(Атрибут, "code=") Тогда
Фича.Код = СокрЛП(Сред(Атрибут, 6));
КонецЕсли;
КонецЦикла;
Возврат Фича;
КонецФункции
// Проверяет маску редакций: ровно 3 символа из набора { "С", "П", "К", "-" }.
Функция ВалидироватьМаскуРедакций(Знач Маска, Знач НомерСтроки)
Если СтрДлина(Маска) <> 3 Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Макет редакций: маска должна быть ровно 3 символа, строка %1, получено: ""%2""'"),
НомерСтроки, Маска);
КонецЕсли;
РазрешенныеСимволы = "СПК-";
Для Позиция = 1 По 3 Цикл
Символ = Сред(Маска, Позиция, 1);
Если СтрНайти(РазрешенныеСимволы, Символ) = 0 Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Макет редакций: недопустимый символ ""%1"" в маске, строка %2'"),
Символ, НомерСтроки);
КонецЕсли;
КонецЦикла;
Возврат Маска;
КонецФункции
Используй MCP write_module_source для вставки.
- Step 3: Проверить ошибки EDT
MCP: get_project_errors
Expected: no new errors.
- Step 4: Commit
git add it/src/CommonModules/СЛС/Module.bsl
git commit -m "feat: СЛС.ПрочитатьМакетРедакций — парсер Markdown-макета матрицы возможностей"
Task 5: СЛС.СформироватьHTMLРедакций и СЛС.HTMLОшибкиМакетаРедакций
Files:
- Modify:
it/src/CommonModules/СЛС/Module.bsl
Этот Task содержит самый большой объём BSL-кода. Разделён на два шага: публичные функции в ПрограммныйИнтерфейс, служебные — в СлужебныеПроцедурыИФункции.
- Step 1: Добавить публичные функции
СформироватьHTMLРедакцийиHTMLОшибкиМакетаРедакций
Через MCP write_module_source вставить после функции ПрочитатьМакетРедакций в область ПрограммныйИнтерфейс:
// Формирует полный HTML-документ страницы "Редакции конфигурации".
//
// Параметры:
// ДанныеМакета - Структура - Результат СЛС.ПрочитатьМакетРедакций().
// ТекущаяРедакция - Число, Неопределено - Номер текущей редакции (1, 2, 3 или Неопределено).
// ВыделеннаяФича - Строка - Код функциональной опции для подсветки (может быть пустой).
//
// Возвращаемое значение:
// Строка - Полный HTML-документ.
//
Функция СформироватьHTMLРедакций(ДанныеМакета, Знач ТекущаяРедакция, Знач ВыделеннаяФича = "") Экспорт
Стили = Новый Массив;
Стили.Добавить(РаботаСВебСервер.ПолучитьТекстОбщегоМакета("css_markdown_content"));
Стили.Добавить(РаботаСВебСервер.ПолучитьТекстОбщегоМакета("css_editions"));
ПотокДанных = Новый ПотокВПамяти;
Запись = Новый ЗаписьТекста(ПотокДанных, КодировкаТекста.UTF8);
Заголовок = НСтр("ru = 'Редакции конфигурации'");
РаботаСВебСервер.ОткрытьДокумент(Запись, Заголовок, Стили);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "div", "editions-panel");
РаботаСВебСервер.ДобавитьСвойствоЗначениеТега(Запись,
"data-current-edition",
?(ТекущаяРедакция = Неопределено, "0", Формат(ТекущаяРедакция, "ЧН=0; ЧГ=0")));
Если ЗначениеЗаполнено(ВыделеннаяФича) Тогда
РаботаСВебСервер.ДобавитьСвойствоЗначениеТега(Запись,
"data-highlighted-feature", ВыделеннаяФича);
КонецЕсли;
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
СобратьШапкуРедакций(Запись, ТекущаяРедакция);
СобратьВведениеРедакций(Запись, ДанныеМакета.Введение);
СобратьТаблицуРедакций(Запись, ДанныеМакета, ТекущаяРедакция, ВыделеннаяФича);
РаботаСВебСервер.ЗакрытьDiv(Запись);
РаботаСВебСервер.ЗакрытьДокумент(Запись);
Запись.Закрыть();
ПотокДанных.Позиция = 0;
Чтение = Новый ЧтениеТекста(ПотокДанных, КодировкаТекста.UTF8);
РезультатHTML = Чтение.Прочитать();
Чтение.Закрыть();
Возврат РезультатHTML;
КонецФункции
// Формирует HTML-страницу для отображения ошибки загрузки/парсинга макета редакций.
//
// Параметры:
// ИнформацияОбОшибке - ИнформацияОбОшибке - Объект с описанием ошибки.
//
// Возвращаемое значение:
// Строка - HTML-документ с сообщением об ошибке.
//
Функция HTMLОшибкиМакетаРедакций(ИнформацияОбОшибке) Экспорт
ПотокДанных = Новый ПотокВПамяти;
Запись = Новый ЗаписьТекста(ПотокДанных, КодировкаТекста.UTF8);
Заголовок = НСтр("ru = 'Редакции конфигурации - ошибка макета'");
РаботаСВебСервер.ОткрытьДокумент(Запись, Заголовок, РаботаСВебСервер.ПолучитьТекстОбщегоМакета("css_editions"));
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "div", "editions-error");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
ТекстОшибки = НСт р("ru = 'Не удалось загрузить матрицу возможностей редакций.'")
+ Символы.ПС + Символы.ПС
+ ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
РаботаСВебСервер.ДобавитьHTML(Запись, РаботаСВебСервер.ЗаменитьСпецСимволыHTML(ТекстОшибки));
РаботаСВебСервер.ЗакрытьDiv(Запись);
РаботаСВебСервер.ЗакрытьДокумент(Запись);
Запись.Закрыть();
ПотокДанных.Позиция = 0;
Чтение = Новый ЧтениеТекста(ПотокДанных, КодировкаТекста.UTF8);
РезультатHTML = Чтение.Прочитать();
Чтение.Закрыть();
Возврат РезультатHTML;
КонецФункции
- Step 2: Добавить служебные процедуры HTML-сборки
Через MCP write_module_source вставить в конец области СлужебныеПроцедурыИФункции (после ВалидироватьМаскуРедакций из Task 4):
// Собирает hero-блок: заголовок + бейдж текущей редакции.
Процедура СобратьШапкуРедакций(Запись, Знач ТекущаяРедакция)
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "header", "editions-hero");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "h1");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(НСтр("ru = 'Возможности ""Управление IT-отделом 8""'"));
РаботаСВебСервер.ЗакрытьТег(Запись, "h1");
КлассБейджа = "current-edition-badge " + КлассБейджаТекущейРедакции(ТекущаяРедакция);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "div", КлассБейджа);
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
ТекстБейджа = СтрШаблон(НСтр("ru = 'Ваша редакция: %1'"),
НазваниеРедакцииДляБейджа(ТекущаяРедакция));
РаботаСВебСервер.ДобавитьHTML(Запись, РаботаСВебСервер.ЗаменитьСпецСимволыHTML(ТекстБейджа));
РаботаСВебСервер.ЗакрытьDiv(Запись);
РаботаСВебСервер.ЗакрытьТег(Запись, "header");
КонецПроцедуры
// Собирает секцию с введением (рендерит Markdown через ДоксинумПарсер).
Процедура СобратьВведениеРедакций(Запись, Знач ТекстВведения)
Если НЕ ЗначениеЗаполнено(ТекстВведения) Тогда
Возврат;
КонецЕсли;
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "section", "editions-intro markdown-content");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
ПараметрыMD = ДоксинумПарсер.ПараметрыMD(ДоксинумПарсер, ДоксинумШаблоны);
HTMLВведения = ДоксинумПарсер.ОбработатьТекстMD(ПараметрыMD, ТекстВведения);
РаботаСВебСервер.ДобавитьHTML(Запись, HTMLВведения);
РаботаСВебСервер.ЗакрытьТег(Запись, "section");
КонецПроцедуры
// Собирает основную таблицу матрицы возможностей.
Процедура СобратьТаблицуРедакций(Запись, ДанныеМакета, Знач ТекущаяРедакция, Знач ВыделеннаяФича)
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "table", "editions-matrix");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
СобратьЗаголовокТаблицыРедакций(Запись, ТекущаяРедакция);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "tbody");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Для Каждого Раздел Из ДанныеМакета.Разделы Цикл
СобратьСтрокуРазделаРедакций(Запись, Раздел.Название);
Для Каждого Подраздел Из Раздел.Подразделы Цикл
СобратьСтрокуПодразделаРедакций(Запись, Подраздел.Название);
Для Каждого Фича Из Подраздел.Фичи Цикл
СобратьСтрокуФичиРедакций(Запись, Фича, ТекущаяРедакция, ВыделеннаяФича);
КонецЦикла;
КонецЦикла;
КонецЦикла;
РаботаСВебСервер.ЗакрытьТег(Запись, "tbody");
РаботаСВебСервер.ЗакрытьТег(Запись, "table");
КонецПроцедуры
// Собирает thead с заголовками колонок: Возможность + 3 редакции.
Процедура СобратьЗаголовокТаблицыРедакций(Запись, Знач ТекущаяРедакция)
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "thead");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "tr");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "th", "col-feature");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(НСтр("ru = 'Возможность'"));
РаботаСВебСервер.ЗакрытьТег(Запись, "th");
ЗаголовкиРедакций = Новый Массив;
ЗаголовкиРедакций.Добавить(НСтр("ru = 'Стандарт'"));
ЗаголовкиРедакций.Добавить(НСтр("ru = 'Проф'"));
ЗаголовкиРедакций.Добавить(НСтр("ru = 'Корп'"));
Для НомерРедакции = 1 По 3 Цикл
КлассКолонки = "col-edition";
Если НомерРедакции = ТекущаяРедакция Тогда
КлассКолонки = КлассКолонки + " col-current";
КонецЕсли;
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "th", КлассКолонки);
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(ЗаголовкиРедакций[НомерРедакции - 1]);
РаботаСВебСервер.ЗакрытьТег(Запись, "th");
КонецЦикла;
РаботаСВебСервер.ЗакрытьТег(Запись, "tr");
РаботаСВебСервер.ЗакрытьТег(Запись, "thead");
КонецПроцедуры
// Собирает строку раздела (tr class="row-section" с colspan).
Процедура СобратьСтрокуРазделаРедакций(Запись, Знач Название)
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "tr", "row-section");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "td");
РаботаСВебСервер.ДобавитьСвойствоЗначениеТега(Запись, "colspan", "4");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(РаботаСВебСервер.ЗаменитьСпецСимволыHTML(Название));
РаботаСВебСервер.ЗакрытьТег(Запись, "td");
РаботаСВебСервер.ЗакрытьТег(Запись, "tr");
КонецПроцедуры
// Собирает строку подраздела.
Процедура СобратьСтрокуПодразделаРедакций(Запись, Знач Название)
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "tr", "row-subsection");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "td");
РаботаСВебСервер.ДобавитьСвойствоЗначениеТега(Запись, "colspan", "4");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(РаботаСВебСервер.ЗаменитьСпецСимволыHTML(Название));
РаботаСВебСервер.ЗакрытьТег(Запись, "td");
РаботаСВебСервер.ЗакрытьТег(Запись, "tr");
КонецПроцедуры
// Собирает строку фичи с 4 колонками и опциональной подсветкой.
Процедура СобратьСтрокуФичиРедакций(Запись, Фича, Знач ТекущаяРедакция, Знач ВыделеннаяФича)
ЭтоВыделеннаяСтрока = ЗначениеЗаполнено(Фича.Код) И Фича.Код = ВыделеннаяФича;
КлассСтроки = "row-feature";
Если ЭтоВыделеннаяСтрока Тогда
КлассСтроки = КлассСтроки + " row-highlighted";
КонецЕсли;
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "tr", КлассСтроки);
Если ЗначениеЗаполнено(Фича.Код) Тогда
РаботаСВебСервер.ДобавитьСвойствоЗначениеТега(Запись, "id", "feature-" + Фича.Код);
КонецЕсли;
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
// Колонка с названием + опциональными note и unavailable-badge.
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "td");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(РаботаСВебСервер.ЗаменитьСпецСимволыHTML(Фича.Название));
Если ЗначениеЗаполнено(Фича.Примечание) Тогда
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "span", "feature-note");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(РаботаСВебСервер.ЗаменитьСпецСимволыHTML(Фича.Примечание));
РаботаСВебСервер.ЗакрытьТег(Запись, "span");
КонецЕсли;
Если ЭтоВыделеннаяСтрока Тогда
ТребуемаяРедакция = МинимальнаяДоступнаяРедакцияИзМаски(Фича.Маска);
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "div", "feature-unavailable-badge");
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
ТекстБейджа = СтрШаблон(
НСтр("ru = 'Недоступно в вашей редакции, требуется %1'"), ТребуемаяРедакция);
РаботаСВебСервер.ДобавитьHTML(Запись,
РаботаСВебСервер.ЗаменитьСпецСимволыHTML(ТекстБейджа));
РаботаСВебСервер.ЗакрытьDiv(Запись);
КонецЕсли;
РаботаСВебСервер.ЗакрытьТег(Запись, "td");
// 3 колонки редакций - галочка или прочерк.
Для НомерРедакции = 1 По 3 Цикл
ЕстьГалочка = МаскаРедакцийСодержит(Фича.Маска, НомерРедакции);
КлассЯчейки = ?(ЕстьГалочка, "check", "dash");
Если НомерРедакции = ТекущаяРедакция Тогда
КлассЯчейки = КлассЯчейки + " col-current";
КонецЕсли;
РаботаСВебСервер.НачатьОткрытиеТега(Запись, "td", КлассЯчейки);
РаботаСВебСервер.ЗакрытьОткрытиеТега(Запись);
Запись.ЗаписатьСтроку(?(ЕстьГалочка, "✓", "—"));
РаботаСВебСервер.ЗакрытьТег(Запись, "td");
КонецЦикла;
РаботаСВебСервер.ЗакрытьТег(Запись, "tr");
КонецПроцедуры
// Возвращает CSS-класс бейджа по номеру редакции.
Функция КлассБейджаТекущейРедакции(Знач ТекущаяРедакция)
Если ТекущаяРедакция = 1 Тогда
Возврат "edition-standart";
ИначеЕсли ТекущаяРедакция = 2 Тогда
Возврат "edition-prof";
ИначеЕсли ТекущаяРедакция = 3 Тогда
Возврат "edition-corp";
КонецЕсли;
Возврат "edition-unknown";
КонецФункции
// Возвращает локализованное название редакции для бейджа.
Функция НазваниеРедакцииДляБейджа(Знач ТекущаяРедакция)
Если ТекущаяРедакция = 1 Тогда
Возврат НСтр("ru = 'СТАНДАРТ'");
ИначеЕсли ТекущаяРедакция = 2 Тогда
Возврат НСтр("ru = 'ПРОФ'");
ИначеЕсли ТекущаяРедакция = 3 Тогда
Возврат НСтр("ru = 'КОРП'");
КонецЕсли;
Возврат НСтр("ru = 'не определена'");
КонецФункции
// Проверяет, содержит ли маска указанную редакцию (позиция 1-3).
Функция МаскаРедакцийСодержит(Знач Маска, Знач НомерРедакции)
Символ = Сред(Маска, НомерРедакции, 1);
Возврат Символ <> "-";
КонецФункции
// Возвращает строковое представление минимальной редакции, в которой
// доступна фича согласно маске. Используется для бейджа "требуется ...".
Функция МинимальнаяДоступнаяРеда кцияИзМаски(Знач Маска)
Если МаскаРедакцийСодержит(Маска, 2) Тогда
Возврат НСтр("ru = 'ПРОФ'");
ИначеЕсли МаскаРедакцийСодержит(Маска, 3) Тогда
Возврат НСтр("ru = 'КОРП'");
КонецЕсли;
Возврат НСтр("ru = 'СТАНДАРТ'");
КонецФункции
- Step 3: Проверить ошибки EDT
MCP: get_project_errors
Expected: no new errors. Возможные предупреждения про ДоксинумПарсер / ДоксинумШаблоны — проверить, что имена общих модулей верны (ДоксинумШаблоны может называться иначе — уточнить через list_modules).
Если ДоксинумШаблоны не найден — заменить сигнатуру вызова ДоксинумПарсер.ПараметрыMD(ДоксинумПарсер, ДоксинумШаблоны) на корректный по факту контекст: посмотреть, как ДоксинумПарсер.ПараметрыMD вызывается в существующем коде (например, через search_in_code MCP EDT или через Grep по .bsl файлам).
- Step 4: Commit
git add it/src/CommonModules/СЛС/Module.bsl
git commit -m "feat: СЛС.СформироватьHTMLРедакций — генератор страницы матрицы возможностей"
Task 6: СЛСКлиент.ПроверитьДоступностьРедакции — клиентский фасад
Files:
-
Modify:
it/src/CommonModules/СЛСКлиент/Module.bsl(добавить в областьПрограммныйИнтерфейсв конец существующих экспортных функций) -
Step 1: Определить точку вставки
MCP: list_modules или read_module_source — найти последнюю экспортную функцию в СЛСКлиент и область ПрограммныйИнтерфейс. Существующие функции: Старт, СтартЗавершение,