Исправлена работа селектора временной зоны, добавлен метод сдвига даты на дробное время

This commit is contained in:
Александр Сироткин 2022-03-10 20:01:43 +05:00
parent ab0a100a05
commit c69bcf7089
2 changed files with 72 additions and 34 deletions

View File

@ -1,69 +1,72 @@
import { memo, ReactNode, useEffect, useState } from 'react' import { memo, ReactNode, useCallback, useEffect, useState } from 'react'
import { Select, SelectProps } from 'antd' import { Select, SelectProps } from 'antd'
import { OmitExtends } from '@utils'
import { findTimezoneId, rawTimezones, TimezoneId } from '@utils/datetime'
import { SimpleTimezoneDto } from '@api' import { SimpleTimezoneDto } from '@api'
import { columnPropsOther, makeColumn } from '.' import { columnPropsOther, makeColumn } from '.'
export const rawTimezones = { const makeTimezoneLabel = (id?: string | null, hours?: number) =>
'Калининград': 2, `UTC${hours && hours > 0 ? '+':''}${hours ? ('0' + hours).slice(-2) : '~??'} :: ${id ?? 'Неизвестно'}`
'Москва': 3,
'Самара': 4,
'Екатеринбург': 5,
'Омск': 6,
'Красноярск': 7,
'Новосибирск': 7,
'Иркутск': 8,
'Чита': 9,
'Владивосток': 10,
'Магадан': 11,
'Южно-Сахалинск': 11,
'Среднеколымск': 11,
'Анадырь': 12,
'Петропавловск-Камчатский': 12,
}
export const timezoneOptions = Object export const timezoneOptions = Object
.entries(rawTimezones) .entries(rawTimezones)
.sort((a, b) => a[1] - b[1]) .sort((a, b) => a[1] - b[1])
.map(([id, hours]) => ({ .map(([id, hours]) => ({
label: `UTC${hours > 0 ? '+':''}${('0' + hours).slice(-2)} :: ${id}`, label: makeTimezoneLabel(id, hours),
value: id, value: id,
})) }))
export const TimezoneSelect = memo<SelectProps>(({ onChange, ...other }) => {
const [id, setId] = useState<keyof typeof rawTimezones | null>(null)
useEffect(() => onChange?.({
timezoneId: id,
hours: id ? rawTimezones[id] : 0,
isOverride: false,
}, []), [id, onChange])
return (<Select {...other} onChange={setId} value={id} />)
})
export const makeTimezoneRenderer = () => (timezone?: SimpleTimezoneDto) => { export const makeTimezoneRenderer = () => (timezone?: SimpleTimezoneDto) => {
if (!timezone) return 'UTC~?? :: Неизвестно' if (!timezone) return 'UTC~?? :: Неизвестно'
const { hours, timezoneId } = timezone const { hours, timezoneId } = timezone
return `UTC${hours && hours > 0 ? '+':''}${hours ? ('0' + hours).slice(-2) : '~??'} :: ${timezoneId ?? 'Неизвестно'}` return makeTimezoneLabel(timezoneId, hours)
} }
export type TimezoneSelectProps = OmitExtends<{
onChange?: ((value?: SimpleTimezoneDto | null) => void) | null
value?: SimpleTimezoneDto | null
defaultValue?: SimpleTimezoneDto | null
}, SelectProps<TimezoneId>>
export const TimezoneSelect = memo<TimezoneSelectProps>(({ onChange, value, defaultValue, ...other }) => {
const [id, setId] = useState<TimezoneId | null>(null)
const [defaultTimezone, setDefaultTimezone] = useState<TimezoneId | null>(null)
useEffect(() => setDefaultTimezone(defaultValue ? findTimezoneId(defaultValue) : null), [defaultValue])
useEffect(() => setId(value ? findTimezoneId(value) : null), [value])
const onValueChanged = useCallback((id: TimezoneId | null) => {
console.log(id)
onChange?.({
timezoneId: id,
hours: id ? rawTimezones[id] : 0,
isOverride: false,
})
}, [onChange])
return (<Select {...other} onChange={onValueChanged} value={id} defaultValue={defaultTimezone} />)
})
export const makeTimezoneColumn = ( export const makeTimezoneColumn = (
title: ReactNode = 'Зона', title: ReactNode = 'Зона',
key: string = 'timezone', key: string = 'timezone',
defaultValue?: SimpleTimezoneDto, defaultValue?: SimpleTimezoneDto,
allowClear: boolean = true, allowClear: boolean = true,
other?: columnPropsOther other?: columnPropsOther,
selectOther?: TimezoneSelectProps
) => makeColumn(title, key, { ) => makeColumn(title, key, {
width: 100, width: 100,
editable: true, editable: true,
render: makeTimezoneRenderer(), render: makeTimezoneRenderer(),
input: ( input: (
<TimezoneSelect <TimezoneSelect
key={key}
allowClear={allowClear} allowClear={allowClear}
options={timezoneOptions} options={timezoneOptions}
defaultValue={defaultValue} defaultValue={defaultValue}
{...selectOther}
/> />
), ),
...other ...other

View File

@ -1,5 +1,7 @@
import moment from 'moment' import moment from 'moment'
import { SimpleTimezoneDto } from '@api'
export type RawDate = number | string | Date export type RawDate = number | string | Date
export const defaultFormat: string = 'YYYY.MM.DD HH:mm' export const defaultFormat: string = 'YYYY.MM.DD HH:mm'
@ -38,7 +40,40 @@ export const periodToString = (time?: number) => {
return `${days > 0 ? days : ''} ${toFixed(hours)}:${toFixed(minutes)}:${toFixed(seconds)}` return `${days > 0 ? days : ''} ${toFixed(hours)}:${toFixed(minutes)}:${toFixed(seconds)}`
} }
export const calcDuration = (start: RawDate, end: RawDate) => { export const calcDuration = (start: unknown, end: unknown) => {
if (!isRawDate(start) || !isRawDate(end)) return if (!isRawDate(start) || !isRawDate(end)) return
return (+new Date(end) - +new Date(start)) * timeInS.millisecond / timeInS.day return (+new Date(end) - +new Date(start)) * timeInS.millisecond / timeInS.day
} }
export const fractionalSum = (date: unknown, value: number, type: keyof typeof timeInS): RawDate => {
if (!isRawDate(date) || !timeInS[type] || isNaN(value ?? NaN)) return NaN
const d = new Date(date)
d.setMilliseconds(d.getMilliseconds() + value * timeInS[type] * 1000)
return d
}
export const rawTimezones = {
'Калининград': 2,
'Москва': 3,
'Самара': 4,
'Екатеринбург': 5,
'Омск': 6,
'Красноярск': 7,
'Новосибирск': 7,
'Иркутск': 8,
'Чита': 9,
'Владивосток': 10,
'Магадан': 11,
'Южно-Сахалинск': 11,
'Среднеколымск': 11,
'Анадырь': 12,
'Петропавловск-Камчатский': 12,
}
export type TimezoneId = keyof typeof rawTimezones
export const isTimezoneId = (value: unknown): value is TimezoneId => !!value && String(value) in rawTimezones
export const findTimezoneId = (value: SimpleTimezoneDto): TimezoneId =>
(isTimezoneId(value.timezoneId) && value.timezoneId) ||
(Object.keys(rawTimezones) as TimezoneId[]).find(id => rawTimezones[id] === value.hours) as TimezoneId