Задание НУ из ui
This commit is contained in:
+19
-1
@@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.server.ResponseStatusException
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.InitialConditionsDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotCalculationSummaryDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteCreateDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteGroupCreateDTO
|
||||
@@ -22,6 +23,7 @@ import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteObservationProfileD
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteSlotProfileDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteUpdateDTO
|
||||
import space.nstart.pcp.slots_service.service.GroupStateService
|
||||
import space.nstart.pcp.slots_service.service.BallisticsService
|
||||
import space.nstart.pcp.slots_service.service.SatelliteCatalogService
|
||||
import space.nstart.pcp.slots_service.service.SatellitePdcmService
|
||||
import space.nstart.pcp.slots_service.service.SlotService
|
||||
@@ -36,7 +38,8 @@ class CatalogRestController(
|
||||
private val satelliteCatalogService: SatelliteCatalogService,
|
||||
private val slotService: SlotService,
|
||||
private val groupStateService: GroupStateService,
|
||||
private val satellitePdcmService: SatellitePdcmService
|
||||
private val satellitePdcmService: SatellitePdcmService,
|
||||
private val ballisticsService: BallisticsService
|
||||
) {
|
||||
private val sendInitialConditionsTimeFormatter =
|
||||
DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss.SSS").withResolverStyle(ResolverStyle.STRICT)
|
||||
@@ -73,6 +76,21 @@ class CatalogRestController(
|
||||
return ResponseEntity.accepted().build()
|
||||
}
|
||||
|
||||
@PostMapping("/satellites/pdcm/{satelliteId}/initial-conditions")
|
||||
fun setSatelliteInitialConditions(
|
||||
@PathVariable satelliteId: Long,
|
||||
@RequestBody request: SatelliteICDTO
|
||||
): ResponseEntity<Void> {
|
||||
ballisticsService.receiveRv(
|
||||
SatelliteICDTO(
|
||||
satelliteId = satelliteId,
|
||||
ic = request.ic,
|
||||
movementModel = request.movementModel
|
||||
)
|
||||
)
|
||||
return ResponseEntity.accepted().build()
|
||||
}
|
||||
|
||||
private fun parseSendInitialConditionsTime(time: String?): LocalDateTime {
|
||||
val normalizedTime = time?.trim()?.takeIf { it.isNotEmpty() }
|
||||
?: return LocalDateTime.now()
|
||||
|
||||
+11
@@ -9,6 +9,7 @@ import space.nstart.pcp.pcp_types_lib.dto.ballistics.ExactTimePositionRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.AscNodeDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.FlightLineDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteOrbitAvailabilityDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO
|
||||
@@ -71,6 +72,16 @@ class BallisticsService (webClientBuilderProvider: ObjectProvider<WebClient.Buil
|
||||
?.firstOrNull()
|
||||
?: throw CustomErrorException("Не удалось получить положение спутника $id на время $time")
|
||||
|
||||
fun receiveRv(request: SatelliteICDTO) {
|
||||
webClientBuilder.build()
|
||||
.post()
|
||||
.uri("$url/api/satellites/receive-rv")
|
||||
.bodyValue(request)
|
||||
.retrieve()
|
||||
.toBodilessEntity()
|
||||
.block()
|
||||
}
|
||||
|
||||
fun parseTle(tle: TLEDTO): TleParsedDTO =
|
||||
webClientBuilder.build()
|
||||
.post()
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.satellite-pdcm-ic-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.satellite-pdcm-status {
|
||||
display: inline-flex;
|
||||
width: 0.75rem;
|
||||
|
||||
@@ -110,6 +110,55 @@
|
||||
};
|
||||
}
|
||||
|
||||
function parseDateTimeForPayload(value, fieldName) {
|
||||
const text = value?.trim() || '';
|
||||
const match = text.match(sendInitialConditionsDateTimePattern);
|
||||
if (!match) {
|
||||
throw new Error(`${fieldName}: укажите время в формате dd.mm.yyyy hh:MM:ss.zzz`);
|
||||
}
|
||||
|
||||
const [, day, month, year, hour, minute, second, millisecond] = match;
|
||||
const parsed = new Date(
|
||||
Number(year),
|
||||
Number(month) - 1,
|
||||
Number(day),
|
||||
Number(hour),
|
||||
Number(minute),
|
||||
Number(second),
|
||||
Number(millisecond)
|
||||
);
|
||||
const validDate = parsed.getFullYear() === Number(year)
|
||||
&& parsed.getMonth() === Number(month) - 1
|
||||
&& parsed.getDate() === Number(day)
|
||||
&& parsed.getHours() === Number(hour)
|
||||
&& parsed.getMinutes() === Number(minute)
|
||||
&& parsed.getSeconds() === Number(second)
|
||||
&& parsed.getMilliseconds() === Number(millisecond);
|
||||
|
||||
if (!validDate) {
|
||||
throw new Error(`${fieldName}: некорректная дата или время`);
|
||||
}
|
||||
|
||||
return `${year}-${month}-${day}T${hour}:${minute}:${second}.${millisecond}`;
|
||||
}
|
||||
|
||||
function parseRequiredNumber(inputId, fieldName) {
|
||||
const value = document.getElementById(inputId)?.value;
|
||||
const number = Number(value);
|
||||
if (value === '' || !Number.isFinite(number)) {
|
||||
throw new Error(`${fieldName}: укажите число`);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
function parseRequiredInteger(inputId, fieldName) {
|
||||
const number = parseRequiredNumber(inputId, fieldName);
|
||||
if (!Number.isInteger(number)) {
|
||||
throw new Error(`${fieldName}: укажите целое число`);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
function formatNumber(value) {
|
||||
return Number(value ?? 0).toFixed(3);
|
||||
}
|
||||
@@ -142,6 +191,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
function renderSetInitialConditionsState(details, loading = false) {
|
||||
const openButton = document.getElementById('satellite-pdcm-open-set-ic');
|
||||
const submitButton = document.getElementById('satellite-pdcm-set-ic-submit');
|
||||
if (openButton) {
|
||||
openButton.disabled = !details || loading;
|
||||
openButton.title = details ? '' : 'Выберите спутник';
|
||||
}
|
||||
if (submitButton) {
|
||||
submitButton.disabled = loading;
|
||||
submitButton.textContent = loading ? 'Запуск...' : 'Запустить расчет';
|
||||
}
|
||||
}
|
||||
|
||||
function renderList() {
|
||||
const tableBody = document.getElementById('satellite-pdcm-list');
|
||||
tableBody.innerHTML = '';
|
||||
@@ -182,6 +244,7 @@
|
||||
summary.innerHTML = '<div class="catalog-helper">Выберите спутник слева.</div>';
|
||||
renderExportState(null);
|
||||
renderSendInitialConditionsState(null);
|
||||
renderSetInitialConditionsState(null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,6 +276,7 @@
|
||||
`;
|
||||
renderExportState(details);
|
||||
renderSendInitialConditionsState(details);
|
||||
renderSetInitialConditionsState(details);
|
||||
}
|
||||
|
||||
function renderTable(details) {
|
||||
@@ -365,10 +429,89 @@
|
||||
}
|
||||
}
|
||||
|
||||
function openSetInitialConditionsModal() {
|
||||
if (!state.selectedSatelliteId || !state.details) {
|
||||
showAlert('Выберите спутник для задания начальных условий');
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('satellite-pdcm-set-ic-target').textContent =
|
||||
`${state.details.name} · ID ${state.details.satelliteId}`;
|
||||
document.getElementById('satellite-pdcm-ic-time').value = currentDateTimeInputValue();
|
||||
document.getElementById('satellite-pdcm-ic-revolution').value = '';
|
||||
document.getElementById('satellite-pdcm-ic-movement-model').value = 'FOTO';
|
||||
document.getElementById('satellite-pdcm-ic-s-ball').value = '0';
|
||||
document.getElementById('satellite-pdcm-ic-f81').value = '147.8';
|
||||
['x', 'y', 'z', 'vx', 'vy', 'vz'].forEach(field => {
|
||||
document.getElementById(`satellite-pdcm-ic-${field}`).value = '';
|
||||
});
|
||||
|
||||
if (window.bootstrap) {
|
||||
window.bootstrap.Modal.getOrCreateInstance(document.getElementById('satellite-pdcm-set-ic-modal')).show();
|
||||
}
|
||||
}
|
||||
|
||||
function buildInitialConditionsPayload() {
|
||||
const movementModel = document.getElementById('satellite-pdcm-ic-movement-model').value || 'FOTO';
|
||||
return {
|
||||
satelliteId: state.selectedSatelliteId,
|
||||
movementModel,
|
||||
ic: {
|
||||
orbPoint: {
|
||||
time: parseDateTimeForPayload(document.getElementById('satellite-pdcm-ic-time').value, 'Time'),
|
||||
revolution: parseRequiredInteger('satellite-pdcm-ic-revolution', 'Revolution'),
|
||||
vx: parseRequiredNumber('satellite-pdcm-ic-vx', 'Vx'),
|
||||
vy: parseRequiredNumber('satellite-pdcm-ic-vy', 'Vy'),
|
||||
vz: parseRequiredNumber('satellite-pdcm-ic-vz', 'Vz'),
|
||||
x: parseRequiredNumber('satellite-pdcm-ic-x', 'X'),
|
||||
y: parseRequiredNumber('satellite-pdcm-ic-y', 'Y'),
|
||||
z: parseRequiredNumber('satellite-pdcm-ic-z', 'Z')
|
||||
},
|
||||
sBall: parseRequiredNumber('satellite-pdcm-ic-s-ball', 'S-ball'),
|
||||
f81: parseRequiredNumber('satellite-pdcm-ic-f81', 'F81')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function submitInitialConditions(event) {
|
||||
event.preventDefault();
|
||||
if (!state.selectedSatelliteId || !state.details) {
|
||||
showAlert('Выберите спутник для задания начальных условий');
|
||||
return;
|
||||
}
|
||||
|
||||
let payload;
|
||||
try {
|
||||
payload = buildInitialConditionsPayload();
|
||||
} catch (error) {
|
||||
showAlert(error.message || 'Проверьте параметры начальных условий');
|
||||
return;
|
||||
}
|
||||
|
||||
renderSetInitialConditionsState(state.details, true);
|
||||
showAlert('');
|
||||
try {
|
||||
await requestJson(`${apiBase}/${state.selectedSatelliteId}/initial-conditions`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const modalElement = document.getElementById('satellite-pdcm-set-ic-modal');
|
||||
if (window.bootstrap && modalElement) {
|
||||
window.bootstrap.Modal.getOrCreateInstance(modalElement).hide();
|
||||
}
|
||||
showAlert('Расчет ПДЦМ по начальным условиям запущен', 'success');
|
||||
} catch (error) {
|
||||
showAlert(error.message || 'Не удалось запустить расчет ПДЦМ по начальным условиям');
|
||||
} finally {
|
||||
renderSetInitialConditionsState(state.details);
|
||||
}
|
||||
}
|
||||
|
||||
async function selectSatellite(satelliteId) {
|
||||
state.selectedSatelliteId = satelliteId;
|
||||
renderList();
|
||||
renderSendInitialConditionsState(null);
|
||||
renderSetInitialConditionsState(null);
|
||||
showAlert('');
|
||||
|
||||
try {
|
||||
@@ -414,6 +557,8 @@
|
||||
});
|
||||
document.getElementById('satellite-pdcm-export').addEventListener('click', exportCurrentCsv);
|
||||
document.getElementById('satellite-pdcm-send-ic').addEventListener('click', sendInitialConditions);
|
||||
document.getElementById('satellite-pdcm-open-set-ic').addEventListener('click', openSetInitialConditionsModal);
|
||||
document.getElementById('satellite-pdcm-set-ic-form').addEventListener('submit', submitInitialConditions);
|
||||
const sendInitialConditionsTimeInput = document.getElementById('satellite-pdcm-send-ic-time');
|
||||
sendInitialConditionsTimeInput.value = currentDateTimeInputValue();
|
||||
sendInitialConditionsTimeInput.addEventListener('input', () => renderSendInitialConditionsState(state.details));
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
/>
|
||||
</div>
|
||||
<button id="satellite-pdcm-send-ic" type="button" class="btn btn-outline-primary" disabled>Передать НУ в slot-service</button>
|
||||
<button id="satellite-pdcm-open-set-ic" type="button" class="btn btn-primary" disabled>Задать НУ</button>
|
||||
<button id="satellite-pdcm-refresh" type="button" class="btn btn-outline-secondary">Обновить</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,6 +81,84 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="satellite-pdcm-set-ic-modal" tabindex="-1" aria-labelledby="satellite-pdcm-set-ic-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<form id="satellite-pdcm-set-ic-form" class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="satellite-pdcm-set-ic-title">Задать начальные условия</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="satellite-pdcm-set-ic-target" class="catalog-helper mb-3">Выберите спутник слева.</div>
|
||||
|
||||
<div class="satellite-pdcm-ic-grid">
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-time" class="form-label">Time</label>
|
||||
<input id="satellite-pdcm-ic-time" type="text" class="form-control" placeholder="dd.mm.yyyy hh:mm:ss.zzz" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-revolution" class="form-label">Revolution</label>
|
||||
<input id="satellite-pdcm-ic-revolution" type="number" class="form-control" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-movement-model" class="form-label">Модель движения</label>
|
||||
<select id="satellite-pdcm-ic-movement-model" class="form-select" required>
|
||||
<option value="FOTO" selected>FOTO</option>
|
||||
<option value="KONDOR">KONDOR</option>
|
||||
<option value="METEORM1">METEORM1</option>
|
||||
<option value="METEORM2">METEORM2</option>
|
||||
<option value="BARS">BARS</option>
|
||||
<option value="KONDOR_PROGNOZ">KONDOR_PROGNOZ</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-s-ball" class="form-label">S-ball</label>
|
||||
<input id="satellite-pdcm-ic-s-ball" type="number" step="any" class="form-control" value="0" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-f81" class="form-label">F81</label>
|
||||
<input id="satellite-pdcm-ic-f81" type="number" step="any" class="form-control" value="147.8" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="satellite-pdcm-ic-grid mt-3">
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-x" class="form-label">X</label>
|
||||
<input id="satellite-pdcm-ic-x" type="number" step="any" class="form-control" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-y" class="form-label">Y</label>
|
||||
<input id="satellite-pdcm-ic-y" type="number" step="any" class="form-control" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-z" class="form-label">Z</label>
|
||||
<input id="satellite-pdcm-ic-z" type="number" step="any" class="form-control" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="satellite-pdcm-ic-grid mt-3">
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-vx" class="form-label">Vx</label>
|
||||
<input id="satellite-pdcm-ic-vx" type="number" step="any" class="form-control" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-vy" class="form-label">Vy</label>
|
||||
<input id="satellite-pdcm-ic-vy" type="number" step="any" class="form-control" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="satellite-pdcm-ic-vz" class="form-label">Vz</label>
|
||||
<input id="satellite-pdcm-ic-vz" type="number" step="any" class="form-control" required/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
<button id="satellite-pdcm-set-ic-submit" type="submit" class="btn btn-primary">Запустить расчет</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/satellite_pdcm_scripts.js"></script>
|
||||
</th:block>
|
||||
|
||||
Reference in New Issue
Block a user