fix(tgu-ui): таблица слотов — слить виток/цикл, секунды в начале, длительность

По замечаниям: Крен и Статус не помещались (8 колонок на узкую панель).
- «Виток» теперь = виток / ветвь / цикл (281 / восх / 1); отдельная «Слот/цикл» убрана
- «Начало» с секундами (formatLocalDateTimeSeconds) — слоты короткие, без секунд начало=конец
- «Конец» заменён на «Длит., с» (slotDurationSec); colSpan распорок 8→7
- Крен и Статус снова видны

Тесты 70/70, build чисто.
This commit is contained in:
Дмитрий Соловьев
2026-06-15 11:10:49 +03:00
parent 3b1a13e532
commit a5f3f0e375
2 changed files with 25 additions and 11 deletions
@@ -23,7 +23,7 @@ import type { Tgu2DMapLayersState } from "../tgu-map-2d/model/mapLayerTypes";
import type { Tgu2DMapSelection } from "../tgu-map-2d/model/mapSelectionTypes"; import type { Tgu2DMapSelection } from "../tgu-map-2d/model/mapSelectionTypes";
import { MapObjectInspector } from "../tgu-map-2d/MapObjectInspector"; import { MapObjectInspector } from "../tgu-map-2d/MapObjectInspector";
import { Tgu2DMapView } from "../tgu-map-2d/Tgu2DMapView"; import { Tgu2DMapView } from "../tgu-map-2d/Tgu2DMapView";
import { formatLocalDateTime, parseLocal, toLocalInputValue, toLocalIso } from "../../utils/localTime"; import { formatLocalDateTimeSeconds, parseLocal, toLocalInputValue, toLocalIso } from "../../utils/localTime";
import { SlotDaySelector, type SlotDay } from "./SlotDaySelector"; import { SlotDaySelector, type SlotDay } from "./SlotDaySelector";
import { SlotPickMenu, type SlotPick } from "./SlotPickMenu"; import { SlotPickMenu, type SlotPick } from "./SlotPickMenu";
import { chunk, selectionAfterCheck } from "./slotSelection"; import { chunk, selectionAfterCheck } from "./slotSelection";
@@ -830,9 +830,8 @@ export function TguSlotsTab({ range }: TguSlotsTabProps) {
</th> </th>
<th>КА</th> <th>КА</th>
<th>Виток</th> <th>Виток</th>
<th>Слот / цикл</th>
<th>Начало</th> <th>Начало</th>
<th>Конец</th> <th>Длит.</th>
<th>Крен</th> <th>Крен</th>
<th>Статус</th> <th>Статус</th>
</tr> </tr>
@@ -840,7 +839,7 @@ export function TguSlotsTab({ range }: TguSlotsTabProps) {
<tbody> <tbody>
{padTop > 0 && ( {padTop > 0 && (
<tr aria-hidden="true" style={{ height: padTop }}> <tr aria-hidden="true" style={{ height: padTop }}>
<td colSpan={8} /> <td colSpan={7} />
</tr> </tr>
)} )}
{virtualRows.map((vrow) => { {virtualRows.map((vrow) => {
@@ -868,13 +867,11 @@ export function TguSlotsTab({ range }: TguSlotsTabProps) {
</td> </td>
<td>{slot.satelliteId}</td> <td>{slot.satelliteId}</td>
<td> <td>
{slot.revolution} / {slot.revolutionSign === "DESC" ? "нисх" : "восх"} {slot.revolution} / {slot.revolutionSign === "DESC" ? "нисх" : "восх"} /{" "}
{slot.cycle}
</td> </td>
<td> <td>{formatLocalDateTimeSeconds(parseLocal(slot.tn))}</td>
{slot.slotNumber} / {slot.cycle} <td>{slotDurationSec(slot)} с</td>
</td>
<td>{formatLocalDateTime(parseLocal(slot.tn))}</td>
<td>{formatLocalDateTime(parseLocal(slot.tk))}</td>
<td>{slot.roll.toFixed(1)}°</td> <td>{slot.roll.toFixed(1)}°</td>
<td> <td>
{booked ? ( {booked ? (
@@ -888,7 +885,7 @@ export function TguSlotsTab({ range }: TguSlotsTabProps) {
})} })}
{padBottom > 0 && ( {padBottom > 0 && (
<tr aria-hidden="true" style={{ height: padBottom }}> <tr aria-hidden="true" style={{ height: padBottom }}>
<td colSpan={8} /> <td colSpan={7} />
</tr> </tr>
)} )}
</tbody> </tbody>
@@ -1040,6 +1037,11 @@ function strategyLabel(strategy: SlotCoverageStrategy): string {
return strategy === "CONTINUOUS" ? "непрерывный" : "жадный"; return strategy === "CONTINUOUS" ? "непрерывный" : "жадный";
} }
/** Длительность слота в секундах (tk − tn). Слоты короткие, поэтому показываем секунды. */
function slotDurationSec(slot: SlotDTO): number {
return Math.max(0, Math.round((parseLocal(slot.tk) - parseLocal(slot.tn)) / 1000));
}
function slotStateLabel(state: string): string { function slotStateLabel(state: string): string {
switch (state) { switch (state) {
case "AVAILABLE": case "AVAILABLE":
@@ -31,6 +31,18 @@ export function formatLocalDateTime(ms: number): string {
}); });
} }
/** Дата-время с секундами (дд.мм.гггг, чч:мм:сс) — для коротких слотов, где важны секунды. */
export function formatLocalDateTimeSeconds(ms: number): string {
return new Date(ms).toLocaleString("ru-RU", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
}
/** Дата (дд.мм) в локальной зоне. */ /** Дата (дд.мм) в локальной зоне. */
export function formatLocalDate(ms: number): string { export function formatLocalDate(ms: number): string {
return new Date(ms).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit" }); return new Date(ms).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit" });