Расчет средних ЗРВ

This commit is contained in:
emelianov
2026-05-28 13:49:35 +03:00
parent 6e62a0bd19
commit 2c65f412cf
3 changed files with 87 additions and 9 deletions
@@ -57,4 +57,37 @@ class RvaRestController(
@PathVariable duration: Long,
@RequestBody stations: List<StationDTO>
) = slotService.rvaMergeOnRev(satelliteId, duration, stations)
@PostMapping("/average/{satelliteId}/{duration}")
@ResponseBody
fun rvaAverage(
@PathVariable satelliteId: Long,
@PathVariable duration: Long,
@RequestBody stations: List<StationDTO>
): List<RvaAverageDTO> {
val days = duration.coerceAtLeast(1).toDouble()
val zonesByStation = slotService.rvaCommon(satelliteId, duration, stations)
.groupBy { it.stationId }
return stations
.sortedBy { it.number }
.map { station ->
val zones = zonesByStation[station.number.toLong()].orEmpty()
val zoneCount = zones.size
val totalDurationSec = zones.sumOf { it.duration }
RvaAverageDTO(
ppiNumber = station.number.toLong(),
ppiLatitude = station.position.lat,
averageCount = zoneCount / days,
averageDurationSec = if (zoneCount == 0) 0.0 else totalDurationSec / zoneCount
)
}
}
}
data class RvaAverageDTO(
val ppiNumber: Long,
val ppiLatitude: Double,
val averageCount: Double,
val averageDurationSec: Double
)
@@ -30,6 +30,17 @@
return date.toLocaleString('ru-RU');
}
function formatNumber(value, digits = 3) {
const number = Number(value);
if (!Number.isFinite(number)) {
return '';
}
return number.toLocaleString('ru-RU', {
minimumFractionDigits: 0,
maximumFractionDigits: digits
});
}
function selectedMode() {
return document.querySelector('input[name="rva-mode"]:checked')?.value || 'common';
}
@@ -113,7 +124,7 @@
<td>${row.durationSec}</td>
</tr>
`).join('');
} else {
} else if (resultState.mode === 'merge-on-rev') {
head.innerHTML = `
<tr>
<th>Виток</th>
@@ -123,7 +134,24 @@
body.innerHTML = resultState.rows.map(row => `
<tr>
<td>${row.revolution}</td>
<td>${row.durationSec}</td>
<td>${formatNumber(row.durationSec, 1)}</td>
</tr>
`).join('');
} else if (resultState.mode === 'average') {
head.innerHTML = `
<tr>
<th>№ППИ</th>
<th>Широта ППИ</th>
<th>Сред.кол-во</th>
<th>Сред.длит., с</th>
</tr>
`;
body.innerHTML = resultState.rows.map(row => `
<tr>
<td>${row.ppiNumber}</td>
<td>${formatNumber(row.ppiLatitude, 6)}</td>
<td>${formatNumber(row.averageCount, 3)}</td>
<td>${formatNumber(row.averageDurationSec, 1)}</td>
</tr>
`).join('');
}
@@ -145,8 +173,9 @@
return;
}
const lines = resultState.mode === 'common'
? [
let lines;
if (resultState.mode === 'common') {
lines = [
['stationId', 'revolution', 'onStart', 'onMaximum', 'onStop', 'duration'],
...resultState.rows.map(row => [
row.stationId,
@@ -156,23 +185,35 @@
row.onStop.time,
row.duration
])
]
: resultState.mode === 'merge'
? [
];
} else if (resultState.mode === 'merge') {
lines = [
['begin', 'end', 'durationSec'],
...resultState.rows.map(row => [
row.begin,
row.end,
row.durationSec
])
]
: [
];
} else if (resultState.mode === 'merge-on-rev') {
lines = [
['revolution', 'durationSec'],
...resultState.rows.map(row => [
row.revolution,
row.durationSec
])
];
} else {
lines = [
['ppiNumber', 'ppiLatitude', 'averageCount', 'averageDurationSec'],
...resultState.rows.map(row => [
row.ppiNumber,
row.ppiLatitude,
row.averageCount,
row.averageDurationSec
])
];
}
const csv = lines.map(line => line.map(csvEscape).join(';')).join('\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
@@ -56,6 +56,10 @@
<input class="form-check-input" type="radio" name="rva-mode" id="rva-mode-merge-on-rev" value="merge-on-rev">
<label class="form-check-label" for="rva-mode-merge-on-rev">Суммарная длительность на витке</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="rva-mode" id="rva-mode-average" value="average">
<label class="form-check-label" for="rva-mode-average">Средняя длительность</label>
</div>
</div>
</div>