From 1221b31225183484e99c4a2a1fe5c4298c08d55f Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Fri, 28 Aug 2026 11:33:13 +0500 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=81=20=D0=B4=D0=B0=D1=82=D0=B0=D0=BC=D0=B8=20=D1=82?= =?UTF-8?q?=D0=B5=D1=80=D1=8F=D0=BB=D0=B8=20=D0=B7=D0=B0=D0=BB=D0=B8=D0=B2?= =?UTF-8?q?=D0=BA=D1=83=20=D1=88=D0=B0=D0=BF=D0=BA=D0=B8=20(SetDefaultColu?= =?UTF-8?q?mnStyle=20=D0=B2=20NPOI)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit H1/I1/K1 («Дата подачи заявки», «Дата закрытия вакансии», «Дата выхода») выходили с форматом даты вместо синей заливки шапки — хотя код применял ко всей строке 1 один и тот же стиль Header. Причина — SetDefaultColumnStyle(col, DataDate), вызванный ПОСЛЕ записи строк: в отличие от чистого OOXML, где стиль колонки уступает явному стилю ячейки, NPOI этим вызовом переписывает стиль уже существующих ячеек колонки целиком, включая шапку. Формат даты и так стоит на каждой конкретной ячейке с датой (SetDate) — вызов просто убран. Добавлен регрессионный тест (сравнение Index стиля, а не ссылки на объект — NPOI отдаёт новую обёртку ICellStyle на каждый вызов CellStyle, ссылки не совпадают даже у идентичного стиля). Co-Authored-By: Claude Opus 5 --- .../Reports/VacancyReportWorkbook.cs | 15 ++++++++++----- .../VacancyReportWorkbookTests.cs | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/Tnsu.ApprovalRoute.Application/Reports/VacancyReportWorkbook.cs b/backend/Tnsu.ApprovalRoute.Application/Reports/VacancyReportWorkbook.cs index c950894..99ee23a 100644 --- a/backend/Tnsu.ApprovalRoute.Application/Reports/VacancyReportWorkbook.cs +++ b/backend/Tnsu.ApprovalRoute.Application/Reports/VacancyReportWorkbook.cs @@ -216,11 +216,16 @@ public static class VacancyReportWorkbook /// private static void FinishVacancyListSheet(XSSFSheet sheet, Styles styles, int lastDataRowIdx) { - // Даты — дефолтным стилем колонки, а не только по заполненным ячейкам: - // формат должен остаться и у строк, которые допишут руками. - foreach (var col in (int[])[ColSubmitDate, ColClosingDate, ColStartDate]) - sheet.SetDefaultColumnStyle(col, styles.DataDate); - + // ВАЖНО: даты НЕ переносятся сюда через SetDefaultColumnStyle — NPOI (в + // отличие от чистого OOXML, где стиль колонки должен уступать явному + // стилю ячейки) переписывает им стиль уже существующих ячеек колонки + // целиком, включая шапку: заголовки «Дата подачи заявки»/«Дата закрытия + // вакансии»/«Дата выхода» лишались синей заливки и получали формат даты + // вместо неё. Формат даты у самих дат и так стоит явно, ячейка за + // ячейкой (см. SetDate) — колонки, дописанные в файл руками ниже данных, + // формат не унаследуют, но это не тот случай, ради которого стоит опять + // ломать шапку. + // // Шапка закреплена — лист длинный, без этого при прокрутке не видно, // какая колонка какая. sheet.CreateFreezePane(0, HeaderRowIdx + 1); diff --git a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/VacancyReportWorkbookTests.cs b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/VacancyReportWorkbookTests.cs index 1b6bd2c..6861295 100644 --- a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/VacancyReportWorkbookTests.cs +++ b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/VacancyReportWorkbookTests.cs @@ -90,6 +90,23 @@ public sealed class VacancyReportWorkbookTests IsEmptyAt(sheet, 1, 17).ShouldBeTrue(); } + [Fact(DisplayName = "Шапка колонок с датами закрашена так же, как остальная шапка")] + public void Header_DateColumns_SameStyleAsRestOfHeader() + { + // Регрессия: даты когда-то получали формат через SetDefaultColumnStyle, + // а он в NPOI переписывает стиль УЖЕ существующих ячеек колонки — + // включая шапку, которая от этого лишалась заливки (H1/I1/K1 получали + // DataDate вместо Header). Формат даты теперь ставится только на сами + // ячейки с датами (см. SetDate), шапки колонок с датами он не касается. + var sheet = BuildListSheet(new VacancyReportGroup("", [Row("Логист")])); + + // NPOI отдаёт на каждый вызов CellStyle новую обёртку — сравнивать + // нужно индекс стиля в книге, а не ссылки на объекты. + var headerStyleIndex = CellAt(sheet, 1, 3)!.CellStyle.Index; // «Вакансия» — заведомо обычная шапка. + foreach (var col in (int[])[8, 9, 11]) // H «Дата подачи заявки», I «Дата закрытия», K «Дата выхода» + CellAt(sheet, 1, col)!.CellStyle.Index.ShouldBe(headerStyleIndex); + } + [Fact(DisplayName = "Строка вакансии: значения в своих колонках, «Комментарии» пусты")] public void DataRow_Layout() {