using Rugrid.Sdaid.Notation.Documents;
namespace Rugrid.Sdaid.Epas.Nts.ChangeRequests
{
/// <summary>
/// Новое требование: сводная статистика по реестру ТС, выводится плашками в двух местах —
/// на вкладке «Сведения» организационного объекта (с фильтром по объекту) и на главной
/// странице модуля (без фильтра, по всему реестру).
/// </summary>
public class DOC_CR_2026_10_30_VehicleSummaryStatistics : IChangeRequestDocument, IHasStructuralLinks, IFolder<NtsChangeRequestsFolder>
{
public SdaidLink[] Links => new[]
{
Rel.Uses<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleSummaryStatistics>(),
Rel.Uses<Rugrid.Sdaid.Epas.Nts.Ui.DOC_VehicleSummaryWidget>(),
Rel.Uses<Rugrid.Sdaid.Epas.Nts.Ui.DOC_NtsMainPage>(),
Rel.Uses<Rugrid.Sdaid.Epas.Nts.Ui.DOC_VehicleRegistry>(),
};
public static string _refName = "CR 2026-10-30: сводная статистика ТС (плашки)";
public string Name => "Сводная статистика ТС (плашки)";
public string Description =>
@"Сводная статистика по реестру ТС — состояние обработки и потребление топлива в разрезе вида топлива, выводится плашками на главной странице модуля и на вкладке «Сведения» организационного объекта.";
public string Version => "0.4";
public string Status => "done";
public string[] Comments => new string[0];
public static string Source = """"
## Источник (как есть)
В модуле ЭНТС нет сводного представления состояния реестра ТС. Чтобы увидеть, сколько
ТС находится в каждом статусе обработки или каков суммарный нормативный расход топлива,
нужно открывать реестр ТС и просматривать строки вручную — нет агрегированной сводки.
Согласованы метрики двух групп:
1. **Состояние обработки.** Всего ТС и разбивка по каждому из семи значений справочника
«Статус обработки ТС»: Не выполнена, Мало данных загружено, Нет модификаций,
Отсутствуют данные для расчёта, Автовыбор не подтверждён, Модификация не определена,
Завершена.
2. **Потребление топлива ТС, в разрезе вида топлива.** Для каждого вида топлива
(бензин/дизельное топливо — не складываются, два отдельных разреза): нормативный
расход (сумма, максимум, минимум, среднее) из уже сохранённого поля
`VehicleCalc.NormConsumption` по ТС этого вида топлива с успешным расчётом;
фактический расход — зарезервированное поле на будущее, источник не определён.
Место вывода: плашки на вкладке «Сведения» организационного объекта (фильтр — ТС этого
объекта) и плашки на главной странице модуля (без фильтра, по всему реестру ТС).
"""";
public static string Analysis = $$""""
## Разбор
**Технология.** Не отчётный движок (ClosedXML и т. п. — для скачиваемых xlsx, не для
веб-плашек): обычный агрегирующий backend-эндпоинт/read-model + UI-виджет. Отдельная
задача на будущее — если понадобится скачиваемый xlsx-отчёт по этим же метрикам,
переиспользовать паттерн `Ntr.Reports`/`NtrReportApiController` (сейчас не проектируется).
**Форма read-model.** Статистика не хранимая сущность — вычисляется по запросу из уже
сохранённых {{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_Vehicle>()}} и
{{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleCalc>()}}. По аналогии с
`OutputModel` (форма результата калькулятора, не хранимая сущность,
{{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Backend.Calc.DOC_OutputModel>()}}) заведена
новая сущность {{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleSummaryStatistics>()}}
с двумя построчными формами разрезов — по статусу обработки и по виду топлива — каждая
из которых документирована отдельным `[DomainEntity]`-классом и встроена в тело основного
документа через `SdaidTable.OfClass<T>()` (приём, уже применённый в
`Nts/70_Infrastructure/AisOiaPeo/AisImportMaps.cs` для карт приёма данных АИС).
**Фильтр по организационному объекту.** Переиспользован принцип
{{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_VehicleRegistry>()}}: объект задаёт
организационный фильтр, при включённом «С потомками» — включаются подчинённые объекты
(ТС числятся за МЭС и ПМЭС). На вкладке «Сведения» отдельного переключателя «С
потомками» нет — сводка по объекту всегда считается с подчинёнными; на главной странице
модуля фильтр не задаётся вовсе.
**Почему не use-case.** Виджет — агрегирующее чтение в рамках одного модуля без
фонового процесса и без состояния, сохраняемого между шагами; значит, по методологии —
поведение страницы/компонента, не use-case.
**Почему «Фактический» не проектируется как рабочее поле.** В домене ЭНТС сейчас нет
источника фактических данных по топливу ТС. «Фактическое потребление» ЭНЗС (Ntr) — про
тепло/электричество зданий, другая модель данных и другой модуль; переиспользовать её
как источник для ЭНТС нельзя. Поле `ActualConsumption` зафиксировано в структуре как
зарезервированное (nullable, без `Calculated`), но не вычисляется и не выводится в
виджете, пока источник не определён — чтобы в будущем расширить read-model без изменения
состава уже существующих полей.
"""";
public static string BlastRadius = $""""
## Blast radius
### Спецификация
| Документ | Правка |
|---|---|
| `Nts/50_Domain/VehicleSummaryStatistics.cs` (новый) | {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleSummaryStatistics>()} — read-model, две построчные формы разрезов |
| `Nts/65_Ui/VehicleSummaryWidget.cs` (новый) | {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_VehicleSummaryWidget>()} — UI-компонент плашек, встраиваемый в двух местах |
| {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_NtsMainPage>()} | добавлена ссылка на виджет; раздел «Структура экрана» — плашки без фильтра до выбора объекта, плашки с фильтром на вкладке «Сведения» |
### Прототип
| Файл | Правка |
|---|---|
| `Nts/65_Ui/html/main-page.html` | блок плашек без фильтра (по всему реестру ТС), встроенный в разметку главной страницы |
| орг.объектная страница/вкладка «Сведения» (найти по разметке `VehicleRegistry`/оргструктуры в `Nts/65_Ui/html/`) | блок плашек с фильтром по текущему орг. объекту |
| `Ntr/65_Ui/html/shell.js` | функция агрегации по данным `NTS_VEHICLE`/`ensureNtsState` (количество по статусу обработки; сумма/макс/мин/среднее `NormConsumption` по виду топлива для ТС с успешным расчётом) + функция рендера плашек; вызовы в обоих местах вывода |
| `Ntr/65_Ui/html/shell.css` | стили плашек (переиспользовать существующие паттерны карточек/бейджей, не изобретать новый визуальный язык) |
Прототип — часть того же CR, не отдельный шаг «потом»: спека без рабочего прототипа,
который `testovich` может сверить выполнением, не считается законченной итерацией.
"""";
public static string Plan = """"
## План
1. Завести доменную сущность «Сводная статистика ТС» с двумя построчными формами
разрезов («Количество ТС по статусу обработки», «Потребление топлива по виду
топлива»), структурные связи на `Vehicle`, `VehicleCalc`, справочники.
2. Завести UI-компонент «Плашки сводной статистики ТС» с описанием структуры (два ряда
плашек) и поведения (фильтр внешний, компонент только отображает).
3. Обновить `NtsMainPage.cs`: ссылка на компонент, упоминание плашек в обоих местах
рабочей области (до выбора объекта — без фильтра; вкладка «Сведения» — с фильтром).
4. Собрать (`dotnet build`, `build-html.cmd`), проверить отсутствие документов-сирот.
5. Прототип: функция агрегации по демо-данным (`shell.js`) + разметка плашек в обоих
местах вывода (`main-page.html`, вкладка «Сведения» орг. объекта) + стили.
6. `testovich` — реальным выполнением на нескольких орг. объектах/без фильтра сверить
подсчёт плашек с фактическим составом демо-ТС.
7. Зафиксировать «Итог» по факту проверки.
"""";
public static string Acceptance = """"
## Acceptance criteria
- **AC-1.** В спеке описан read-model «Сводная статистика ТС» с полями: общее
количество ТС, количество по каждому из семи статусов обработки (строка выводится
даже при нулевом количестве), и по каждому виду топлива — количество ТС с успешным
расчётом, сумма/максимум/минимум/среднее нормативного расхода.
- **AC-2.** Поле фактического расхода зафиксировано как зарезервированное, без
источника данных и без вычисления в этой итерации.
- **AC-3.** Описан фильтр по организационному объекту, переиспользующий принцип фильтра
реестра ТС (объект + подчинённые объекты).
- **AC-4.** Описаны оба места вывода: главная страница модуля (без фильтра) и вкладка
«Сведения» организационного объекта (с фильтром), один и тот же UI-компонент.
- **AC-5.** Сборка спеки (`dotnet build`) и генерация сайта (`build-html.cmd`) проходят
без ошибок, новые документы не являются сиротами.
- **AC-6.** Прототип реализован в обоих местах вывода и подтверждён `testovich` реальным
выполнением: подсчёт плашек (по статусам обработки и по виду топлива) совпадает с
фактическим составом демо-ТС — без фильтра и с фильтром по орг. объекту.
- **AC-7.** На вкладке «Сведения» виджет размещён отдельным блоком после полей сведений
об организационном объекте, не между ними. Когда сумма ТС по видам топлива (плашка 2)
меньше «Всего ТС» (плашка 1) — остаток явно показан строкой «Без успешного расчёта: N
ТС», а не оставлен несходящимся молча.
- **AC-8.** Виджет — ровно **две плашки** (не десять): плашка 1 «Состояние обработки»
содержит строку «Всего ТС» и все 7 статусов как строки внутри неё; плашка 2
«Потребление автотоплива ТС» содержит по строке на каждый вид топлива. Разбивка —
строки внутри плашки своей группы, не отдельная плашка на каждое значение.
"""";
public static string Result = """"
## Итог
Реализовано и проверено `testovich` реальным выполнением. Read-model
{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleSummaryStatistics>()} и
виджет {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_VehicleSummaryWidget>()}
зафиксированы в спеке, прототип — в обоих местах вывода (главная страница без фильтра,
вкладка «Сведения» с фильтром по орг. объекту). По итогам ревью пользователя доведены
до соответствия: группировка по виду топлива — только бензин/дизель (как и методика
расчёта), ряд 2 скрывается лишь при пустой выборке, добавлена строка сверки «Без
успешного расчёта: N ТС», виджет размещён после полей сведений об объекте, не между
ними. AC-1 — AC-7 подтверждены. По итогам ещё одного ревью пользователя обнаружено:
«ряд»/«группа» были реализованы как множество отдельных плашек (10 штук — по одной на
статус/вид топлива), хотя имелось в виду ровно 2 плашки с разбивкой строками внутри
каждой (AC-8). Переделано: `summaryTilesHtml()` строит 2 `.summary-group`, разбивка —
`.summary-row` внутри; спека и CSS согласованы. AC-8 подтверждён `testovich` реальным
выполнением (несколько орг. объектов, ручной пересчёт сумм/мин/макс/среднего, случай
пустой выборки — вторая плашка действительно отсутствует в DOM). AC-1 — AC-8 подтверждены.
"""";
}
}