pcp-tgu-ops-ui: надёжный 24ч ввод времени (своё текстовое поле вместо нативного)
Нативные input type=time/datetime-local рендерят время по локали браузера/ОС (AM/PM) и игнорируют атрибут lang в Chrome — поэтому lang=ru-RU не помогал. Заменено на собственные контролы (components/timeFields.tsx): - Time24Field — текстовый ввод ЧЧ:ММ[:СС] с валидацией, детерминированный 24ч; - DateTime24Field — нативный календарь для даты + Time24Field для времени. Подключено в окне маршрута редактора и во всех datetime-local фильтрах (Планы, заявки на карте, создание/фильтр заявок).
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { formatDate, formatDateTime, formatDuration, formatTime, kindColor, kindLabel } from "./editorPresentation";
|
||||
import { statusStyle } from "../tgu-planning/tguStatus";
|
||||
import { formatUtcDateTime, parseUtc } from "../../utils/utcTime";
|
||||
import { Time24Field } from "../../components/timeFields";
|
||||
import type { RvaZone } from "../../api/ballisticsApi";
|
||||
import type { ChangeEvent } from "react";
|
||||
import type { SurveyRoute } from "../../api/missionPlanningApi";
|
||||
import type { Tgu2DMapSelection } from "../tgu-map-2d/model/mapSelectionTypes";
|
||||
import type { RequestMapItem } from "../../model/requestTypes";
|
||||
@@ -710,10 +710,8 @@ function RouteTimeStepper({
|
||||
}) {
|
||||
const clamp = (next: number) => Math.max(min ?? Number.NEGATIVE_INFINITY, Math.min(max ?? Number.POSITIVE_INFINITY, next));
|
||||
const change = (deltaMs: number) => onChange(clamp(value + deltaMs));
|
||||
const onInput = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const raw = event.target.value;
|
||||
if (!raw) return;
|
||||
// Ввод — только время суток; день оставляем прежним (UTC).
|
||||
const onTimeChange = (raw: string) => {
|
||||
// Ввод — только время суток (ЧЧ:ММ:СС, UTC); день оставляем прежним.
|
||||
const datePart = new Date(value).toISOString().slice(0, 10);
|
||||
const ms = parseUtc(`${datePart}T${raw}`);
|
||||
if (Number.isFinite(ms)) onChange(clamp(ms));
|
||||
@@ -722,8 +720,7 @@ function RouteTimeStepper({
|
||||
return (
|
||||
<label className="tgu-editor-time-stepper tgu-editor-time-stepper--seconds">
|
||||
<span>{label}</span>
|
||||
{/* lang=ru-RU — чтобы поле показывало время в 24-часовом формате, а не AM/PM. */}
|
||||
<input lang="ru-RU" type="time" step={1} value={new Date(value).toISOString().slice(11, 19)} onChange={onInput} />
|
||||
<Time24Field withSeconds value={new Date(value).toISOString().slice(11, 19)} onChange={onTimeChange} />
|
||||
<div className="tgu-editor-time-stepper__steps">
|
||||
<button type="button" onClick={() => change(-30_000)}>−30с</button>
|
||||
<button type="button" onClick={() => change(-5_000)}>−5с</button>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TGU_2D_MAP_LAYERS, type Tgu2DMapLayerKey, type Tgu2DMapLayersState } fr
|
||||
import type { Tgu2DMapLayerAvailability } from "./Tgu2DMapLayers";
|
||||
import type { RequestsState } from "./Tgu2DMapTab";
|
||||
import { parseUtc } from "../../utils/utcTime";
|
||||
import { DateTime24Field } from "../../components/timeFields";
|
||||
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
@@ -105,21 +106,11 @@ export function Tgu2DMapSidebar({
|
||||
<div className="tgu-map-requests-filter">
|
||||
<label className="tgu-field">
|
||||
<span>С</span>
|
||||
<input
|
||||
lang="ru-RU"
|
||||
type="datetime-local"
|
||||
value={requestsState.fromValue}
|
||||
onChange={(e) => onRequestsFromChange(e.target.value)}
|
||||
/>
|
||||
<DateTime24Field value={requestsState.fromValue} onChange={onRequestsFromChange} />
|
||||
</label>
|
||||
<label className="tgu-field">
|
||||
<span>По</span>
|
||||
<input
|
||||
lang="ru-RU"
|
||||
type="datetime-local"
|
||||
value={requestsState.toValue}
|
||||
onChange={(e) => onRequestsToChange(e.target.value)}
|
||||
/>
|
||||
<DateTime24Field value={requestsState.toValue} onChange={onRequestsToChange} />
|
||||
</label>
|
||||
<div className="tgu-map-requests-filter__actions">
|
||||
<button
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TguActiveTab } from "../../model/timelineTypes";
|
||||
import { DateTime24Field } from "../../components/timeFields";
|
||||
|
||||
type TguToolbarProps = {
|
||||
fromValue: string;
|
||||
@@ -77,11 +78,11 @@ export function TguToolbar({
|
||||
|
||||
<label className="tgu-field">
|
||||
<span>С</span>
|
||||
<input lang="ru-RU" type="datetime-local" value={fromValue} onChange={(event) => onFromChange(event.target.value)} />
|
||||
<DateTime24Field value={fromValue} onChange={onFromChange} />
|
||||
</label>
|
||||
<label className="tgu-field">
|
||||
<span>По</span>
|
||||
<input lang="ru-RU" type="datetime-local" value={toValue} onChange={(event) => onToChange(event.target.value)} />
|
||||
<DateTime24Field value={toValue} onChange={onToChange} />
|
||||
</label>
|
||||
|
||||
<button className="tgu-button tgu-button--primary" type="button" onClick={onApply} disabled={loading}>
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
RsaResultType
|
||||
} from "../../model/requestTypes";
|
||||
import { parseUtc } from "../../utils/utcTime";
|
||||
import { DateTime24Field } from "../../components/timeFields";
|
||||
|
||||
export type RequestFormSubmit = {
|
||||
name: string;
|
||||
@@ -200,11 +201,11 @@ export function RequestCreatePanel({
|
||||
</label>
|
||||
<label className="tgu-requests-field">
|
||||
<span>Начало</span>
|
||||
<input lang="ru-RU" type="datetime-local" value={begin} onChange={(e) => setBegin(e.target.value)} />
|
||||
<DateTime24Field value={begin} onChange={setBegin} />
|
||||
</label>
|
||||
<label className="tgu-requests-field">
|
||||
<span>Конец</span>
|
||||
<input lang="ru-RU" type="datetime-local" value={end} onChange={(e) => setEnd(e.target.value)} />
|
||||
<DateTime24Field value={end} onChange={setEnd} />
|
||||
</label>
|
||||
<label className="tgu-requests-field">
|
||||
<span>КПП</span>
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { Tgu2DMapSelection } from "../tgu-map-2d/model/mapSelectionTypes";
|
||||
import type { GeoPoint, MapPolygon } from "../tgu-map-2d/model/mapTypes";
|
||||
import { generateUuid } from "../../utils/uuid";
|
||||
import { parseUtc, toUtcInputValue, toUtcIso } from "../../utils/utcTime";
|
||||
import { DateTime24Field } from "../../components/timeFields";
|
||||
import { RequestCreatePanel, type RequestFormSubmit } from "./RequestCreatePanel";
|
||||
import { RequestDetailsPanel } from "./RequestDetailsPanel";
|
||||
import { polygonToWkt } from "./requestGeometry";
|
||||
@@ -288,20 +289,16 @@ export function TguRequestsTab({ range, invalidRange, platforms }: TguRequestsTa
|
||||
<div className="tgu-map-requests-filter">
|
||||
<label className="tgu-field">
|
||||
<span>С</span>
|
||||
<input
|
||||
lang="ru-RU"
|
||||
type="datetime-local"
|
||||
<DateTime24Field
|
||||
value={requestsState.fromValue}
|
||||
onChange={(e) => setRequestsState((cur) => ({ ...cur, fromValue: e.target.value }))}
|
||||
onChange={(value) => setRequestsState((cur) => ({ ...cur, fromValue: value }))}
|
||||
/>
|
||||
</label>
|
||||
<label className="tgu-field">
|
||||
<span>По</span>
|
||||
<input
|
||||
lang="ru-RU"
|
||||
type="datetime-local"
|
||||
<DateTime24Field
|
||||
value={requestsState.toValue}
|
||||
onChange={(e) => setRequestsState((cur) => ({ ...cur, toValue: e.target.value }))}
|
||||
onChange={(value) => setRequestsState((cur) => ({ ...cur, toValue: value }))}
|
||||
/>
|
||||
</label>
|
||||
<div className="tgu-map-requests-filter__actions">
|
||||
|
||||
Reference in New Issue
Block a user