From 052ed5f04b16642005df84d759eda89541e32ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=A1=D0=BE?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2=D1=8C=D0=B5=D0=B2?= Date: Mon, 15 Jun 2026 16:45:14 +0300 Subject: [PATCH] =?UTF-8?q?feat(slots-service):=20=D0=BF=D0=B0=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=20all=20=D1=83=20request-cover=20?= =?UTF-8?q?=E2=80=94=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=82=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BD=D1=8F=D1=82=D1=8B=D1=85=20=D0=B1=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D1=8C=D1=8E=20(BUSY)=20=D1=81=D0=BB=D0=BE=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit «Показать все слоты» должно показывать полный набор. При all=true reqCover запрашивает статусы [AVAILABLE, BOOKED, BUSY], а selectCoverageSlots собирает BUSY отдельно и добавляет в ответ только в ветке без покрытия — в solver («Подобрать покрытие») занятые слоты по-прежнему не попадают. --- .../controller/SlotController.kt | 4 +- .../pcp/slots_service/service/SlotService.kt | 37 ++++++++++++++----- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/SlotController.kt b/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/SlotController.kt index 30627a7..392da65 100644 --- a/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/SlotController.kt +++ b/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/SlotController.kt @@ -103,8 +103,10 @@ class SlotController { @RequestParam("sun") sun : Double?, @Parameter(description = "Вариант расчета покрытия") @RequestParam("coverageStrategy", required = false) coverageStrategy: SlotCoverageStrategy?, + @Parameter(description = "Вернуть и занятые бронью слоты (BUSY) — для обзора; по умолчанию только доступные/забронированные") + @RequestParam("all", required = false) all: Boolean?, ) : List - = slotService.reqCover(requestId, timeStart, timeStop, sign, cov, satellites, sun, coverageStrategy).toList() + = slotService.reqCover(requestId, timeStart, timeStop, sign, cov, satellites, sun, coverageStrategy, all == true).toList() @GetMapping("interval") @Operation(summary = "Получение всех слотов на заданном интервале времени") diff --git a/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/service/SlotService.kt b/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/service/SlotService.kt index 63aaf4b..8e87501 100644 --- a/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/service/SlotService.kt +++ b/services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/service/SlotService.kt @@ -1216,7 +1216,8 @@ class SlotService { states: List? = null, sats : List? = null, sun : Double? = null, - coverageStrategy: SlotCoverageStrategy? = SlotCoverageStrategy.GREEDY + coverageStrategy: SlotCoverageStrategy? = SlotCoverageStrategy.GREEDY, + includeBusy: Boolean = false ): Iterable { val target = buildCoverageTargets( items = listOf(SlotCoverageTargetDTO(targetId = 1, wkt = wkt)) @@ -1235,7 +1236,8 @@ class SlotService { batchContext = batchContext, cov = cov, sun = sun, - coverageStrategy = coverageStrategy + coverageStrategy = coverageStrategy, + includeBusy = includeBusy ) logger.info( "polySlots finish: targetId={}, candidateSlots={}, sunFilteredSlots={}, returnedSlots={}, sun={}", @@ -1668,10 +1670,14 @@ class SlotService { batchContext: CoverageBatchContext, cov: Boolean?, sun: Double?, - coverageStrategy: SlotCoverageStrategy? + coverageStrategy: SlotCoverageStrategy?, + // true — добавить в результат и занятые бронью слоты (BUSY) для обзора. В расчёт покрытия + // (solver) они не попадают: selectedSlots остаётся только из AVAILABLE/BOOKED. + includeBusy: Boolean = false ): CoverageSelectionResult { val totalStartedAtMs = System.currentTimeMillis() val selectedSlots = mutableListOf() + val busySlots = mutableListOf() val targetSlotIdsBySatelliteId = batchContext.rawSlotIdsByTargetIdAndSatelliteId[target.targetId].orEmpty() val sourceSlotIds = targetSlotIdsBySatelliteId.values.sumOf { it.size } var preparedSlotsBeforeOccupiedFilter = 0 @@ -1710,6 +1716,12 @@ class SlotService { val sunFilterResult = filterBySunAngle(filteredSlots, sun) sunFilteredSlots += sunFilterResult.filteredCount selectedSlots.addAll(sunFilterResult.slots) + // «Показать все слоты»: добавляем и занятые бронью (BUSY) для обзора — тот же + // sun-фильтр, чтобы не показывать заведомо непригодные по Солнцу. + if (includeBusy) { + val busyPrepared = preparedSlotsIncludingBlocked.filter { it.state == SlotStatus.BUSY } + busySlots.addAll(filterBySunAngle(busyPrepared, sun).slots) + } } } logger.debug( @@ -1815,15 +1827,17 @@ class SlotService { candidateSelectionMs, totalMs ) + // Без покрытия («Показать все слоты»): при includeBusy возвращаем и занятые бронью слоты. + val resultSlots = if (includeBusy) selectedSlots + busySlots else selectedSlots return CoverageSelectionResult( - slots = selectedSlots, + slots = resultSlots, sourceSlotIds = sourceSlotIds, preparedSlotsBeforeOccupiedFilter = preparedSlotsBeforeOccupiedFilter, occupiedFilteredSlots = occupiedFilteredSlots, candidateSlotsBeforeSunFilter = candidateSlotsBeforeSunFilter, sunFilteredSlots = sunFilteredSlots, solverInputSlots = selectedSlots.size, - solverOutputSlots = selectedSlots.size, + solverOutputSlots = resultSlots.size, candidateSelectionDurationMs = candidateSelectionMs, solverDurationMs = 0L, totalDurationMs = totalMs @@ -1870,9 +1884,12 @@ class SlotService { cov: Boolean?, sats : List? = null, sun : Double? = null, - coverageStrategy: SlotCoverageStrategy? = SlotCoverageStrategy.GREEDY + coverageStrategy: SlotCoverageStrategy? = SlotCoverageStrategy.GREEDY, + // true — вернуть и занятые бронью слоты (BUSY) для обзора («Показать все слоты»). + // Бронировать их нельзя, в расчёт покрытия они не идут. + includeBusy: Boolean = false ): Iterable { - logger.info("Запрос покрытия заявки $id") + logger.info("Запрос покрытия заявки $id (includeBusy=$includeBusy)") val req = earthService.reqcells(id)?.request?.contour ?: throw CustomErrorException("Нет такой заявки!!!!") logger.info("Получена заявка : $req") return polySlots( @@ -1881,10 +1898,12 @@ class SlotService { timeStop, sign, cov, - listOf(SlotStatus.AVAILABLE, SlotStatus.BOOKED), + if (includeBusy) listOf(SlotStatus.AVAILABLE, SlotStatus.BOOKED, SlotStatus.BUSY) + else listOf(SlotStatus.AVAILABLE, SlotStatus.BOOKED), sats, sun, - coverageStrategy + coverageStrategy, + includeBusy ) }