Задание НУ из ui
This commit is contained in:
+8
@@ -42,6 +42,14 @@ class SatelliteController {
|
|||||||
return ResponseEntity.accepted().build()
|
return ResponseEntity.accepted().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{satellite_id}/initial-conditions/current")
|
||||||
|
fun currentInitialConditions(
|
||||||
|
@PathVariable("satellite_id") satelliteId: Long
|
||||||
|
): ResponseEntity<SatelliteICDTO> =
|
||||||
|
satelliteService.currentInitialConditions(satelliteId)
|
||||||
|
?.let { ResponseEntity.ok(it) }
|
||||||
|
?: ResponseEntity.noContent().build()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
package space.nstart.pcp.pcp_request_service.entity
|
||||||
|
|
||||||
|
import jakarta.persistence.Column
|
||||||
|
import jakarta.persistence.Entity
|
||||||
|
import jakarta.persistence.EnumType
|
||||||
|
import jakarta.persistence.Enumerated
|
||||||
|
import jakarta.persistence.GeneratedValue
|
||||||
|
import jakarta.persistence.GenerationType
|
||||||
|
import jakarta.persistence.Id
|
||||||
|
import jakarta.persistence.Table
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.InitialConditionsDTO
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.MovementModel
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "satellite_initial_conditions")
|
||||||
|
class SatelliteInitialConditionEntity(
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "satellite_initial_condition_id")
|
||||||
|
val id: Long? = null,
|
||||||
|
@Column(name = "satellite_id", nullable = false)
|
||||||
|
val satelliteId: Long = 0,
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(name = "movement_model", nullable = false)
|
||||||
|
val movementModel: MovementModel = MovementModel.FOTO,
|
||||||
|
@Column(name = "orb_time", nullable = false)
|
||||||
|
val orbTime: LocalDateTime = LocalDateTime.now(),
|
||||||
|
@Column(name = "orb_revolution", nullable = false)
|
||||||
|
val orbRevolution: Long = 0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val x: Double = 0.0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val y: Double = 0.0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val z: Double = 0.0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val vx: Double = 0.0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val vy: Double = 0.0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val vz: Double = 0.0,
|
||||||
|
@Column(name = "s_ball", nullable = false)
|
||||||
|
val sBall: Double = 0.0,
|
||||||
|
@Column(nullable = false)
|
||||||
|
val f81: Double = 147.8,
|
||||||
|
@Column(name = "received_at", nullable = false)
|
||||||
|
val receivedAt: LocalDateTime = LocalDateTime.now(),
|
||||||
|
@Column(name = "calculated_at")
|
||||||
|
var calculatedAt: LocalDateTime? = null,
|
||||||
|
@Column(name = "last_calculated", nullable = false)
|
||||||
|
var lastCalculated: Boolean = false
|
||||||
|
) {
|
||||||
|
constructor(request: SatelliteICDTO) : this(
|
||||||
|
satelliteId = request.satelliteId,
|
||||||
|
movementModel = request.movementModel,
|
||||||
|
orbTime = request.ic.orbPoint.time,
|
||||||
|
orbRevolution = request.ic.orbPoint.revolution,
|
||||||
|
x = request.ic.orbPoint.x,
|
||||||
|
y = request.ic.orbPoint.y,
|
||||||
|
z = request.ic.orbPoint.z,
|
||||||
|
vx = request.ic.orbPoint.vx,
|
||||||
|
vy = request.ic.orbPoint.vy,
|
||||||
|
vz = request.ic.orbPoint.vz,
|
||||||
|
sBall = request.ic.sBall,
|
||||||
|
f81 = request.ic.f81
|
||||||
|
)
|
||||||
|
|
||||||
|
fun markLastCalculated(calculatedAt: LocalDateTime = LocalDateTime.now()) {
|
||||||
|
this.calculatedAt = calculatedAt
|
||||||
|
this.lastCalculated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toDto() = SatelliteICDTO(
|
||||||
|
satelliteId = satelliteId,
|
||||||
|
movementModel = movementModel,
|
||||||
|
ic = InitialConditionsDTO(
|
||||||
|
orbPoint = OrbPointDTO(
|
||||||
|
time = orbTime,
|
||||||
|
revolution = orbRevolution,
|
||||||
|
vx = vx,
|
||||||
|
vy = vy,
|
||||||
|
vz = vz,
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
z = z
|
||||||
|
),
|
||||||
|
sBall = sBall,
|
||||||
|
f81 = f81
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package space.nstart.pcp.pcp_request_service.repository
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
import org.springframework.data.jpa.repository.Modifying
|
||||||
|
import org.springframework.data.jpa.repository.Query
|
||||||
|
import org.springframework.data.repository.query.Param
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import space.nstart.pcp.pcp_request_service.entity.SatelliteInitialConditionEntity
|
||||||
|
|
||||||
|
interface SatelliteInitialConditionRepository : JpaRepository<SatelliteInitialConditionEntity, Long> {
|
||||||
|
fun findFirstBySatelliteIdAndLastCalculatedTrueOrderByCalculatedAtDescIdDesc(
|
||||||
|
satelliteId: Long
|
||||||
|
): SatelliteInitialConditionEntity?
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Transactional
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
update SatelliteInitialConditionEntity entity
|
||||||
|
set entity.lastCalculated = false
|
||||||
|
where entity.satelliteId = :satelliteId
|
||||||
|
and entity.lastCalculated = true
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun clearLastCalculated(@Param("satelliteId") satelliteId: Long): Int
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package space.nstart.pcp.pcp_request_service.service
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import space.nstart.pcp.pcp_request_service.entity.SatelliteInitialConditionEntity
|
||||||
|
import space.nstart.pcp.pcp_request_service.repository.SatelliteInitialConditionRepository
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class SatelliteInitialConditionService(
|
||||||
|
private val satelliteInitialConditionRepository: SatelliteInitialConditionRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun saveReceived(request: SatelliteICDTO): SatelliteInitialConditionEntity =
|
||||||
|
satelliteInitialConditionRepository.save(SatelliteInitialConditionEntity(request))
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun markLastCalculated(initialCondition: SatelliteInitialConditionEntity) {
|
||||||
|
satelliteInitialConditionRepository.clearLastCalculated(initialCondition.satelliteId)
|
||||||
|
initialCondition.markLastCalculated()
|
||||||
|
satelliteInitialConditionRepository.save(initialCondition)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun current(satelliteId: Long): SatelliteICDTO? =
|
||||||
|
satelliteInitialConditionRepository
|
||||||
|
.findFirstBySatelliteIdAndLastCalculatedTrueOrderByCalculatedAtDescIdDesc(satelliteId)
|
||||||
|
?.toDto()
|
||||||
|
}
|
||||||
+23
@@ -89,6 +89,10 @@ class SatelliteService {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var pdcmRepository: PDCMRepository
|
private lateinit var pdcmRepository: PDCMRepository
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var satelliteInitialConditionService: SatelliteInitialConditionService
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var ascNodeRepository: AscNodeRepository
|
private lateinit var ascNodeRepository: AscNodeRepository
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -185,6 +189,7 @@ class SatelliteService {
|
|||||||
)
|
)
|
||||||
|
|
||||||
suspend fun resieveRV(rv: SatelliteICDTO) {
|
suspend fun resieveRV(rv: SatelliteICDTO) {
|
||||||
|
val savedInitialCondition = satelliteInitialConditionService.saveReceived(rv)
|
||||||
val bal = Ballistics()
|
val bal = Ballistics()
|
||||||
bal.modDVType = rv.movementModel.toModDVType()
|
bal.modDVType = rv.movementModel.toModDVType()
|
||||||
|
|
||||||
@@ -230,10 +235,15 @@ class SatelliteService {
|
|||||||
|
|
||||||
prepareEarthCovering(bal, rv.satelliteId)
|
prepareEarthCovering(bal, rv.satelliteId)
|
||||||
|
|
||||||
|
satelliteInitialConditionService.markLastCalculated(savedInitialCondition)
|
||||||
|
|
||||||
bal.clear()
|
bal.clear()
|
||||||
logger.info("Расчет для КА ${rv.satelliteId} завершился успешно")
|
logger.info("Расчет для КА ${rv.satelliteId} завершился успешно")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun currentInitialConditions(satelliteId: Long): SatelliteICDTO? =
|
||||||
|
satelliteInitialConditionService.current(satelliteId)
|
||||||
|
|
||||||
private fun MovementModel.toModDVType(): ModDVType =
|
private fun MovementModel.toModDVType(): ModDVType =
|
||||||
when (this) {
|
when (this) {
|
||||||
MovementModel.FOTO -> ModDVType.FOTO
|
MovementModel.FOTO -> ModDVType.FOTO
|
||||||
@@ -893,3 +903,16 @@ data class SatelliteBallisticsDeletionSummary(
|
|||||||
val earthCoverageDeleted: Int,
|
val earthCoverageDeleted: Int,
|
||||||
val earthCellViewsDeleted: Int
|
val earthCellViewsDeleted: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//DT: 11.12.2028 01:24:24.257000000 MDT
|
||||||
|
//x= 2610612.004898679
|
||||||
|
//y= -3507514.947081291
|
||||||
|
//z= -5291534.374006776
|
||||||
|
//Vx= -4935.515395115775
|
||||||
|
//Vy= 3497.047795669036
|
||||||
|
//Vz= -4742.501356855924
|
||||||
|
//CS: GSK
|
||||||
|
//Sb= 0.06
|
||||||
|
//kappa= 0
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS satellite_initial_conditions (
|
||||||
|
satellite_initial_condition_id BIGSERIAL PRIMARY KEY,
|
||||||
|
satellite_id BIGINT NOT NULL,
|
||||||
|
movement_model VARCHAR(32) NOT NULL DEFAULT 'FOTO',
|
||||||
|
orb_time TIMESTAMP NOT NULL,
|
||||||
|
orb_revolution BIGINT NOT NULL,
|
||||||
|
x DOUBLE PRECISION NOT NULL,
|
||||||
|
y DOUBLE PRECISION NOT NULL,
|
||||||
|
z DOUBLE PRECISION NOT NULL,
|
||||||
|
vx DOUBLE PRECISION NOT NULL,
|
||||||
|
vy DOUBLE PRECISION NOT NULL,
|
||||||
|
vz DOUBLE PRECISION NOT NULL,
|
||||||
|
s_ball DOUBLE PRECISION NOT NULL,
|
||||||
|
f81 DOUBLE PRECISION NOT NULL,
|
||||||
|
received_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
calculated_at TIMESTAMP,
|
||||||
|
last_calculated BOOLEAN NOT NULL DEFAULT FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_satellite_initial_conditions_satellite_id ON satellite_initial_conditions(satellite_id);
|
||||||
|
CREATE INDEX idx_satellite_initial_conditions_last_calculated ON satellite_initial_conditions(satellite_id, last_calculated);
|
||||||
+58
@@ -14,6 +14,11 @@ import org.springframework.kafka.core.DefaultKafkaConsumerFactory
|
|||||||
import org.springframework.kafka.listener.adapter.RecordFilterStrategy
|
import org.springframework.kafka.listener.adapter.RecordFilterStrategy
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
import space.nstart.pcp.pcp_request_service.entity.PDCMEntity
|
import space.nstart.pcp.pcp_request_service.entity.PDCMEntity
|
||||||
|
import space.nstart.pcp.pcp_request_service.entity.SatelliteInitialConditionEntity
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.InitialConditionsDTO
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.MovementModel
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
|
||||||
|
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@@ -41,6 +46,9 @@ class PDCMRepositoryTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var repository: PDCMRepository
|
private lateinit var repository: PDCMRepository
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var satelliteInitialConditionRepository: SatelliteInitialConditionRepository
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `find satellite orbit availability returns all satellites with points when time is null`() {
|
fun `find satellite orbit availability returns all satellites with points when time is null`() {
|
||||||
persistPoint(11L, LocalDateTime.of(2026, 4, 14, 10, 0))
|
persistPoint(11L, LocalDateTime.of(2026, 4, 14, 10, 0))
|
||||||
@@ -74,6 +82,34 @@ class PDCMRepositoryTest {
|
|||||||
assertEquals(LocalDateTime.of(2026, 4, 14, 12, 0), actual.single().timeStop)
|
assertEquals(LocalDateTime.of(2026, 4, 14, 12, 0), actual.single().timeStop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `satellite initial conditions repository returns last calculated condition`() {
|
||||||
|
val oldCondition = satelliteInitialConditionRepository.save(sampleInitialCondition(11L, 1L))
|
||||||
|
oldCondition.markLastCalculated(LocalDateTime.of(2026, 4, 14, 10, 0))
|
||||||
|
satelliteInitialConditionRepository.save(oldCondition)
|
||||||
|
|
||||||
|
val newCondition = satelliteInitialConditionRepository.save(sampleInitialCondition(11L, 2L))
|
||||||
|
satelliteInitialConditionRepository.clearLastCalculated(11L)
|
||||||
|
newCondition.markLastCalculated(LocalDateTime.of(2026, 4, 14, 12, 0))
|
||||||
|
satelliteInitialConditionRepository.save(newCondition)
|
||||||
|
satelliteInitialConditionRepository.save(sampleInitialCondition(11L, 3L))
|
||||||
|
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val actual = satelliteInitialConditionRepository
|
||||||
|
.findFirstBySatelliteIdAndLastCalculatedTrueOrderByCalculatedAtDescIdDesc(11L)
|
||||||
|
|
||||||
|
assertEquals(2L, actual?.toDto()?.ic?.orbPoint?.revolution)
|
||||||
|
assertEquals(MovementModel.KONDOR, actual?.movementModel)
|
||||||
|
assertEquals(
|
||||||
|
1,
|
||||||
|
satelliteInitialConditionRepository.findAll().count { entity ->
|
||||||
|
entity.satelliteId == 11L && entity.lastCalculated
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun persistPoint(satelliteId: Long, time: LocalDateTime) {
|
private fun persistPoint(satelliteId: Long, time: LocalDateTime) {
|
||||||
entityManager.persist(
|
entityManager.persist(
|
||||||
PDCMEntity(
|
PDCMEntity(
|
||||||
@@ -91,6 +127,28 @@ class PDCMRepositoryTest {
|
|||||||
entityManager.flush()
|
entityManager.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun sampleInitialCondition(satelliteId: Long, revolution: Long) =
|
||||||
|
SatelliteInitialConditionEntity(
|
||||||
|
SatelliteICDTO(
|
||||||
|
satelliteId = satelliteId,
|
||||||
|
movementModel = MovementModel.KONDOR,
|
||||||
|
ic = InitialConditionsDTO(
|
||||||
|
orbPoint = OrbPointDTO(
|
||||||
|
time = LocalDateTime.of(2026, 4, 14, 10, 0).plusHours(revolution),
|
||||||
|
revolution = revolution,
|
||||||
|
vx = 1.0,
|
||||||
|
vy = 2.0,
|
||||||
|
vz = 3.0,
|
||||||
|
x = 4.0,
|
||||||
|
y = 5.0,
|
||||||
|
z = 6.0
|
||||||
|
),
|
||||||
|
sBall = 0.2,
|
||||||
|
f81 = 141.0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@TestConfiguration
|
@TestConfiguration
|
||||||
class KafkaFilterStubConfiguration {
|
class KafkaFilterStubConfiguration {
|
||||||
@Bean("kafkaListenerContainerFactory")
|
@Bean("kafkaListenerContainerFactory")
|
||||||
|
|||||||
+10
@@ -91,6 +91,16 @@ class CatalogRestController(
|
|||||||
return ResponseEntity.accepted().build()
|
return ResponseEntity.accepted().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/satellites/pdcm/{satelliteId}/initial-conditions")
|
||||||
|
fun currentPdcmInitialConditions(@PathVariable satelliteId: Long): ResponseEntity<Any> {
|
||||||
|
val response = ballisticsService.currentInitialConditions(satelliteId)
|
||||||
|
return if (response == null) {
|
||||||
|
ResponseEntity.noContent().build()
|
||||||
|
} else {
|
||||||
|
ResponseEntity.ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseSendInitialConditionsTime(time: String?): LocalDateTime {
|
private fun parseSendInitialConditionsTime(time: String?): LocalDateTime {
|
||||||
val normalizedTime = time?.trim()?.takeIf { it.isNotEmpty() }
|
val normalizedTime = time?.trim()?.takeIf { it.isNotEmpty() }
|
||||||
?: return LocalDateTime.now()
|
?: return LocalDateTime.now()
|
||||||
|
|||||||
+13
@@ -82,6 +82,19 @@ class BallisticsService (webClientBuilderProvider: ObjectProvider<WebClient.Buil
|
|||||||
.block()
|
.block()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun currentInitialConditions(satelliteId: Long): SatelliteICDTO? =
|
||||||
|
webClientBuilder.build()
|
||||||
|
.get()
|
||||||
|
.uri("$url/api/satellites/$satelliteId/initial-conditions/current")
|
||||||
|
.exchangeToMono { response ->
|
||||||
|
when {
|
||||||
|
response.statusCode().is2xxSuccessful -> response.bodyToMono(SatelliteICDTO::class.java)
|
||||||
|
response.statusCode().value() == 404 || response.statusCode().value() == 204 -> reactor.core.publisher.Mono.empty()
|
||||||
|
else -> response.createException().flatMap { reactor.core.publisher.Mono.error(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.block()
|
||||||
|
|
||||||
fun parseTle(tle: TLEDTO): TleParsedDTO =
|
fun parseTle(tle: TLEDTO): TleParsedDTO =
|
||||||
webClientBuilder.build()
|
webClientBuilder.build()
|
||||||
.post()
|
.post()
|
||||||
|
|||||||
@@ -68,6 +68,21 @@
|
|||||||
return `${pad(now.getDate())}.${pad(now.getMonth() + 1)}.${now.getFullYear()} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
|
return `${pad(now.getDate())}.${pad(now.getMonth() + 1)}.${now.getFullYear()} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDateTimeInput(value) {
|
||||||
|
if (!value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const match = String(value).match(
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})[T\s](\d{2}):(\d{2})(?::(\d{2})(?:[.,](\d{1,9}))?)?/
|
||||||
|
);
|
||||||
|
if (!match) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, year, month, day, hour, minute, second = '00', millis = '000'] = match;
|
||||||
|
return `${day}.${month}.${year} ${hour}:${minute}:${second}.${millis.slice(0, 3).padEnd(3, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
function parseSendInitialConditionsTime() {
|
function parseSendInitialConditionsTime() {
|
||||||
const input = document.getElementById('satellite-pdcm-send-ic-time');
|
const input = document.getElementById('satellite-pdcm-send-ic-time');
|
||||||
const value = input?.value.trim() || '';
|
const value = input?.value.trim() || '';
|
||||||
@@ -194,9 +209,10 @@
|
|||||||
function renderSetInitialConditionsState(details, loading = false) {
|
function renderSetInitialConditionsState(details, loading = false) {
|
||||||
const openButton = document.getElementById('satellite-pdcm-open-set-ic');
|
const openButton = document.getElementById('satellite-pdcm-open-set-ic');
|
||||||
const submitButton = document.getElementById('satellite-pdcm-set-ic-submit');
|
const submitButton = document.getElementById('satellite-pdcm-set-ic-submit');
|
||||||
|
const satelliteSelected = !!state.selectedSatelliteId;
|
||||||
if (openButton) {
|
if (openButton) {
|
||||||
openButton.disabled = !details || loading;
|
openButton.disabled = !satelliteSelected || loading;
|
||||||
openButton.title = details ? '' : 'Выберите спутник';
|
openButton.title = satelliteSelected ? '' : 'Выберите спутник';
|
||||||
}
|
}
|
||||||
if (submitButton) {
|
if (submitButton) {
|
||||||
submitButton.disabled = loading;
|
submitButton.disabled = loading;
|
||||||
@@ -429,14 +445,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSetInitialConditionsModal() {
|
function resetInitialConditionsForm() {
|
||||||
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-time').value = currentDateTimeInputValue();
|
||||||
document.getElementById('satellite-pdcm-ic-revolution').value = '';
|
document.getElementById('satellite-pdcm-ic-revolution').value = '';
|
||||||
document.getElementById('satellite-pdcm-ic-movement-model').value = 'FOTO';
|
document.getElementById('satellite-pdcm-ic-movement-model').value = 'FOTO';
|
||||||
@@ -445,10 +454,54 @@
|
|||||||
['x', 'y', 'z', 'vx', 'vy', 'vz'].forEach(field => {
|
['x', 'y', 'z', 'vx', 'vy', 'vz'].forEach(field => {
|
||||||
document.getElementById(`satellite-pdcm-ic-${field}`).value = '';
|
document.getElementById(`satellite-pdcm-ic-${field}`).value = '';
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillInitialConditionsForm(initialConditions) {
|
||||||
|
document.getElementById('satellite-pdcm-ic-time').value =
|
||||||
|
formatDateTimeInput(initialConditions?.ic?.orbPoint?.time) || currentDateTimeInputValue();
|
||||||
|
document.getElementById('satellite-pdcm-ic-revolution').value =
|
||||||
|
initialConditions?.ic?.orbPoint?.revolution ?? '';
|
||||||
|
document.getElementById('satellite-pdcm-ic-movement-model').value =
|
||||||
|
initialConditions?.movementModel || 'FOTO';
|
||||||
|
document.getElementById('satellite-pdcm-ic-s-ball').value =
|
||||||
|
initialConditions?.ic?.sBall ?? '0';
|
||||||
|
document.getElementById('satellite-pdcm-ic-f81').value =
|
||||||
|
initialConditions?.ic?.f81 ?? '147.8';
|
||||||
|
document.getElementById('satellite-pdcm-ic-x').value = initialConditions?.ic?.orbPoint?.x ?? '';
|
||||||
|
document.getElementById('satellite-pdcm-ic-y').value = initialConditions?.ic?.orbPoint?.y ?? '';
|
||||||
|
document.getElementById('satellite-pdcm-ic-z').value = initialConditions?.ic?.orbPoint?.z ?? '';
|
||||||
|
document.getElementById('satellite-pdcm-ic-vx').value = initialConditions?.ic?.orbPoint?.vx ?? '';
|
||||||
|
document.getElementById('satellite-pdcm-ic-vy').value = initialConditions?.ic?.orbPoint?.vy ?? '';
|
||||||
|
document.getElementById('satellite-pdcm-ic-vz').value = initialConditions?.ic?.orbPoint?.vz ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openSetInitialConditionsModal() {
|
||||||
|
if (!state.selectedSatelliteId) {
|
||||||
|
showAlert('Выберите спутник для задания начальных условий');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedSatellite = state.details?.satelliteId === state.selectedSatelliteId
|
||||||
|
? state.details
|
||||||
|
: state.satellites.find(satellite => satellite.satelliteId === state.selectedSatelliteId);
|
||||||
|
document.getElementById('satellite-pdcm-set-ic-target').textContent =
|
||||||
|
selectedSatellite
|
||||||
|
? `${selectedSatellite.name} · ID ${selectedSatellite.satelliteId}`
|
||||||
|
: `ID ${state.selectedSatelliteId}`;
|
||||||
|
resetInitialConditionsForm();
|
||||||
|
|
||||||
if (window.bootstrap) {
|
if (window.bootstrap) {
|
||||||
window.bootstrap.Modal.getOrCreateInstance(document.getElementById('satellite-pdcm-set-ic-modal')).show();
|
window.bootstrap.Modal.getOrCreateInstance(document.getElementById('satellite-pdcm-set-ic-modal')).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const currentInitialConditions = await requestJson(`${apiBase}/${state.selectedSatelliteId}/initial-conditions`);
|
||||||
|
if (currentInitialConditions) {
|
||||||
|
fillInitialConditionsForm(currentInitialConditions);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showAlert(error.message || 'Не удалось загрузить актуальные начальные условия');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildInitialConditionsPayload() {
|
function buildInitialConditionsPayload() {
|
||||||
@@ -475,7 +528,7 @@
|
|||||||
|
|
||||||
async function submitInitialConditions(event) {
|
async function submitInitialConditions(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!state.selectedSatelliteId || !state.details) {
|
if (!state.selectedSatelliteId) {
|
||||||
showAlert('Выберите спутник для задания начальных условий');
|
showAlert('Выберите спутник для задания начальных условий');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -509,6 +562,7 @@
|
|||||||
|
|
||||||
async function selectSatellite(satelliteId) {
|
async function selectSatellite(satelliteId) {
|
||||||
state.selectedSatelliteId = satelliteId;
|
state.selectedSatelliteId = satelliteId;
|
||||||
|
state.details = null;
|
||||||
renderList();
|
renderList();
|
||||||
renderSendInitialConditionsState(null);
|
renderSendInitialConditionsState(null);
|
||||||
renderSetInitialConditionsState(null);
|
renderSetInitialConditionsState(null);
|
||||||
@@ -523,6 +577,7 @@
|
|||||||
state.details = null;
|
state.details = null;
|
||||||
renderSummary(null);
|
renderSummary(null);
|
||||||
renderTable(null);
|
renderTable(null);
|
||||||
|
renderSetInitialConditionsState(null);
|
||||||
showAlert(error.message || 'Не удалось загрузить ПДЦМ спутника');
|
showAlert(error.message || 'Не удалось загрузить ПДЦМ спутника');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,12 +593,14 @@
|
|||||||
if (nextSatelliteId) {
|
if (nextSatelliteId) {
|
||||||
await selectSatellite(nextSatelliteId);
|
await selectSatellite(nextSatelliteId);
|
||||||
} else {
|
} else {
|
||||||
|
state.selectedSatelliteId = null;
|
||||||
state.details = null;
|
state.details = null;
|
||||||
renderSummary(null);
|
renderSummary(null);
|
||||||
renderTable(null);
|
renderTable(null);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
state.satellites = [];
|
state.satellites = [];
|
||||||
|
state.selectedSatelliteId = null;
|
||||||
state.details = null;
|
state.details = null;
|
||||||
renderList();
|
renderList();
|
||||||
renderSummary(null);
|
renderSummary(null);
|
||||||
|
|||||||
+35
@@ -389,6 +389,41 @@ class CatalogControllerTest {
|
|||||||
assertEquals(42L, requestCaptor.value.ic.orbPoint.revolution)
|
assertEquals(42L, requestCaptor.value.ic.orbPoint.revolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `satellite pdcm current initial conditions endpoint proxies request to ballistics`() {
|
||||||
|
val response = SatelliteICDTO(
|
||||||
|
satelliteId = 501L,
|
||||||
|
movementModel = MovementModel.KONDOR,
|
||||||
|
ic = InitialConditionsDTO(
|
||||||
|
orbPoint = OrbPointDTO(
|
||||||
|
time = LocalDateTime.of(2026, 4, 24, 10, 15, 30, 123_000_000),
|
||||||
|
revolution = 42L,
|
||||||
|
vx = 1.0,
|
||||||
|
vy = 2.0,
|
||||||
|
vz = 3.0,
|
||||||
|
x = 4.0,
|
||||||
|
y = 5.0,
|
||||||
|
z = 6.0
|
||||||
|
),
|
||||||
|
sBall = 0.07,
|
||||||
|
f81 = 145.2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
doReturn(response).`when`(ballisticsService).currentInitialConditions(501L)
|
||||||
|
|
||||||
|
val actual = WebClient.create("http://localhost:$port")
|
||||||
|
.get()
|
||||||
|
.uri("/api/catalog/satellites/pdcm/501/initial-conditions")
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(SatelliteICDTO::class.java)
|
||||||
|
.block()!!
|
||||||
|
|
||||||
|
assertEquals(501L, actual.satelliteId)
|
||||||
|
assertEquals(MovementModel.KONDOR, actual.movementModel)
|
||||||
|
assertEquals(42L, actual.ic.orbPoint.revolution)
|
||||||
|
verify(ballisticsService).currentInitialConditions(501L)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `satellite create endpoint proxies request`() {
|
fun `satellite create endpoint proxies request`() {
|
||||||
val request = SatelliteCreateDTO(
|
val request = SatelliteCreateDTO(
|
||||||
|
|||||||
+32
-1
@@ -59,6 +59,7 @@ class BallisticsServiceTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
val currentInitialConditions = service.currentInitialConditions(101L)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(
|
listOf(
|
||||||
@@ -67,7 +68,8 @@ class BallisticsServiceTest {
|
|||||||
"/api/satellites/101/orbit",
|
"/api/satellites/101/orbit",
|
||||||
"/api/satellites/orbit/availability",
|
"/api/satellites/orbit/availability",
|
||||||
"/api/satellites/101/extract-time",
|
"/api/satellites/101/extract-time",
|
||||||
"/api/satellites/receive-rv"
|
"/api/satellites/receive-rv",
|
||||||
|
"/api/satellites/101/initial-conditions/current"
|
||||||
),
|
),
|
||||||
requests.map { it.path }
|
requests.map { it.path }
|
||||||
)
|
)
|
||||||
@@ -78,6 +80,7 @@ class BallisticsServiceTest {
|
|||||||
"time_start=2026-04-21T10:00&time_stop=2026-04-21T12:00",
|
"time_start=2026-04-21T10:00&time_stop=2026-04-21T12:00",
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
null
|
null
|
||||||
),
|
),
|
||||||
requests.map { it.query }
|
requests.map { it.query }
|
||||||
@@ -87,6 +90,8 @@ class BallisticsServiceTest {
|
|||||||
assertNotNull(exactPoint)
|
assertNotNull(exactPoint)
|
||||||
assertEquals(timeStart, exactPoint.time)
|
assertEquals(timeStart, exactPoint.time)
|
||||||
assertEquals(true, requestBodies.single().contains(""""movementModel":"KONDOR""""))
|
assertEquals(true, requestBodies.single().contains(""""movementModel":"KONDOR""""))
|
||||||
|
assertNotNull(currentInitialConditions)
|
||||||
|
assertEquals(101L, currentInitialConditions.satelliteId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createService(serverUrl: String): BallisticsService {
|
private fun createService(serverUrl: String): BallisticsService {
|
||||||
@@ -133,6 +138,32 @@ class BallisticsServiceTest {
|
|||||||
requestBodies.add(exchange.requestBody.bufferedReader().use { it.readText() })
|
requestBodies.add(exchange.requestBody.bufferedReader().use { it.readText() })
|
||||||
respond(exchange, "")
|
respond(exchange, "")
|
||||||
}
|
}
|
||||||
|
startedServer.createContext("/api/satellites/101/initial-conditions/current") { exchange ->
|
||||||
|
requests.add(exchange.requestURI)
|
||||||
|
respond(
|
||||||
|
exchange,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"satelliteId": 101,
|
||||||
|
"movementModel": "KONDOR",
|
||||||
|
"ic": {
|
||||||
|
"orbPoint": {
|
||||||
|
"time": "2026-04-21T10:00:00",
|
||||||
|
"revolution": 7,
|
||||||
|
"vx": 1.0,
|
||||||
|
"vy": 2.0,
|
||||||
|
"vz": 3.0,
|
||||||
|
"x": 4.0,
|
||||||
|
"y": 5.0,
|
||||||
|
"z": 6.0
|
||||||
|
},
|
||||||
|
"sBall": 0.0,
|
||||||
|
"f81": 147.8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
startedServer.start()
|
startedServer.start()
|
||||||
server = startedServer
|
server = startedServer
|
||||||
return "http://localhost:${startedServer.address.port}"
|
return "http://localhost:${startedServer.address.port}"
|
||||||
|
|||||||
Reference in New Issue
Block a user