fix(admin-ui): корректные бейджи в истории — future/active/expired по реальному времени
Раньше любую запись с validTo<9999 помечал 'закрыта'. Но запись с validTo в будущем — не закрытая, а либо ЗАПЛАНИРОВАННАЯ (validFrom > now), либо АКТИВНАЯ (validFrom <= now < validTo). User видел 'закрыта' на v3 которая ещё не настала. Теперь: - future: validFrom > now → бейдж 'запланирована' (info), точка orbit/horizon - active: validFrom <= now < validTo → бейдж 'активна' (success) если не latest - expired: validTo <= now → 'закрыта' (neutral), точка пустая - latest active: 'текущая' (primary), точка ultramarain Бессрочная запись (validTo year>=9999) больше не показывает 'действует до:' — у бессрочной нет конечной даты, отображение его смущало. i18n: новые ключи history.active / history.scheduled (RU/EN).
This commit is contained in:
@@ -35,33 +35,50 @@ export const RecordHistoryDrawer = ({ open, onClose, dictionaryName, businessKey
|
|||||||
<ol className="relative border-l-2 border-regolith pl-5 space-y-4">
|
<ol className="relative border-l-2 border-regolith pl-5 space-y-4">
|
||||||
{data.map((rec, idx) => {
|
{data.map((rec, idx) => {
|
||||||
const isLatest = idx === 0
|
const isLatest = idx === 0
|
||||||
const closed = new Date(rec.validTo).getFullYear() < 9999
|
|
||||||
// Нумерация по позиции в timeline: total..1, новая запись = total.
|
|
||||||
// rec.version (JPA optimistic lock) растёт на UPDATE и у нескольких
|
|
||||||
// закрытых может совпасть → дубли в UI. Index — стабильный 1-based счётчик.
|
|
||||||
const displayVersion = data.length - idx
|
const displayVersion = data.length - idx
|
||||||
|
const now = new Date()
|
||||||
|
const from = new Date(rec.validFrom)
|
||||||
|
const to = new Date(rec.validTo)
|
||||||
|
const farFuture = to.getFullYear() >= 9999
|
||||||
|
// Статус по реальному времени:
|
||||||
|
// future — validFrom ещё впереди (запланирована)
|
||||||
|
// active — сейчас в её диапазоне
|
||||||
|
// expired — validTo уже прошла (закрыта)
|
||||||
|
const status = from > now
|
||||||
|
? 'future'
|
||||||
|
: !farFuture && to <= now
|
||||||
|
? 'expired'
|
||||||
|
: 'active'
|
||||||
return (
|
return (
|
||||||
<li key={rec.id} className="relative">
|
<li key={rec.id} className="relative">
|
||||||
<span
|
<span
|
||||||
className={`absolute -left-[27px] top-1 h-3 w-3 rounded-full border-2 ${
|
className={`absolute -left-[27px] top-1 h-3 w-3 rounded-full border-2 ${
|
||||||
isLatest
|
isLatest && status === 'active'
|
||||||
? 'bg-ultramarain border-ultramarain'
|
? 'bg-ultramarain border-ultramarain'
|
||||||
: closed
|
: status === 'future'
|
||||||
? 'bg-white border-carbon/40'
|
? 'bg-orbit border-horizon'
|
||||||
: 'bg-aurora border-aurora'
|
: status === 'expired'
|
||||||
|
? 'bg-white border-carbon/40'
|
||||||
|
: 'bg-aurora border-aurora'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<span className="text-sm font-primary text-ultramarain">v{displayVersion}</span>
|
<span className="text-sm font-primary text-ultramarain">v{displayVersion}</span>
|
||||||
{isLatest && <Badge variant="primary">{t('history.current')}</Badge>}
|
{isLatest && status === 'active' && (
|
||||||
{!isLatest && closed && <Badge variant="neutral">{t('history.closed')}</Badge>}
|
<Badge variant="primary">{t('history.current')}</Badge>
|
||||||
|
)}
|
||||||
|
{status === 'future' && <Badge variant="info">{t('history.scheduled')}</Badge>}
|
||||||
|
{status === 'expired' && <Badge variant="neutral">{t('history.closed')}</Badge>}
|
||||||
|
{status === 'active' && !isLatest && (
|
||||||
|
<Badge variant="success">{t('history.active')}</Badge>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-2xs text-carbon/70 space-y-0.5">
|
<div className="text-2xs text-carbon/70 space-y-0.5">
|
||||||
<div>
|
<div>
|
||||||
<span className="font-mono">{t('history.validFrom')}:</span>{' '}
|
<span className="font-mono">{t('history.validFrom')}:</span>{' '}
|
||||||
{new Date(rec.validFrom).toLocaleString()}
|
{new Date(rec.validFrom).toLocaleString()}
|
||||||
</div>
|
</div>
|
||||||
{closed && (
|
{!farFuture && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-mono">{t('history.validTo')}:</span>{' '}
|
<span className="font-mono">{t('history.validTo')}:</span>{' '}
|
||||||
{new Date(rec.validTo).toLocaleString()}
|
{new Date(rec.validTo).toLocaleString()}
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ i18n
|
|||||||
'history.title': 'История версий',
|
'history.title': 'История версий',
|
||||||
'history.empty': 'История пуста',
|
'history.empty': 'История пуста',
|
||||||
'history.current': 'текущая',
|
'history.current': 'текущая',
|
||||||
|
'history.active': 'активна',
|
||||||
|
'history.scheduled': 'запланирована',
|
||||||
'history.closed': 'закрыта',
|
'history.closed': 'закрыта',
|
||||||
'history.validFrom': 'действует с',
|
'history.validFrom': 'действует с',
|
||||||
'history.validTo': 'действует до',
|
'history.validTo': 'действует до',
|
||||||
@@ -202,6 +204,8 @@ i18n
|
|||||||
'history.title': 'Version history',
|
'history.title': 'Version history',
|
||||||
'history.empty': 'No history',
|
'history.empty': 'No history',
|
||||||
'history.current': 'current',
|
'history.current': 'current',
|
||||||
|
'history.active': 'active',
|
||||||
|
'history.scheduled': 'scheduled',
|
||||||
'history.closed': 'closed',
|
'history.closed': 'closed',
|
||||||
'history.validFrom': 'valid from',
|
'history.validFrom': 'valid from',
|
||||||
'history.validTo': 'valid to',
|
'history.validTo': 'valid to',
|
||||||
|
|||||||
Reference in New Issue
Block a user