[CLAUDE] CICD+FE-Admin+FE-User: deploy pool-state guard + SlaTimer component
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
CICD: check app pool state before Stop-WebAppPool (idempotent). FE: new SlaTimer component with color-coded countdown (emerald/amber/red) and progress bar. Two variants: - inline: used in list tables (Inbox, Contracts list x2, MyContracts) - full: used in ContractDetail card with progress bar + deadline timestamp Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -5,6 +5,7 @@ import { ArrowRight, CheckCircle2, MessageSquare, Clock, ArrowLeft, XCircle } fr
|
||||
import { toast } from 'sonner'
|
||||
import { PageHeader } from '@/components/PageHeader'
|
||||
import { PhaseBadge } from '@/components/PhaseBadge'
|
||||
import { SlaTimer } from '@/components/SlaTimer'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Select } from '@/components/ui/Select'
|
||||
import { Textarea } from '@/components/ui/Textarea'
|
||||
@ -140,7 +141,7 @@ export function ContractDetailPage() {
|
||||
<div><dt className="text-slate-500">Dự án</dt><dd>{c.projectName}</dd></div>
|
||||
<div><dt className="text-slate-500">Phòng ban</dt><dd>{c.departmentName ?? '—'}</dd></div>
|
||||
<div><dt className="text-slate-500">Người soạn</dt><dd>{c.drafterName ?? '—'}</dd></div>
|
||||
<div><dt className="text-slate-500">SLA</dt><dd>{c.slaDeadline ? fmt(c.slaDeadline) : '—'}</dd></div>
|
||||
<div className="col-span-2"><dt className="text-slate-500 mb-1">SLA</dt><dd><SlaTimer deadline={c.slaDeadline} createdAt={c.createdAt} variant="full" /></dd></div>
|
||||
<div><dt className="text-slate-500">Bypass CCM</dt><dd>{c.bypassProcurementAndCCM ? 'Có (HĐ Chủ đầu tư)' : 'Không'}</dd></div>
|
||||
</dl>
|
||||
{c.noiDung && (
|
||||
|
||||
@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { PageHeader } from '@/components/PageHeader'
|
||||
import { DataTable, Pagination, type Column } from '@/components/DataTable'
|
||||
import { PhaseBadge } from '@/components/PhaseBadge'
|
||||
import { SlaTimer } from '@/components/SlaTimer'
|
||||
import { Input } from '@/components/ui/Input'
|
||||
import { Select } from '@/components/ui/Select'
|
||||
import { api } from '@/lib/api'
|
||||
@ -12,15 +13,6 @@ import { ContractPhase, ContractPhaseLabel, type ContractListItem } from '@/type
|
||||
import { ContractTypeLabel } from '@/types/forms'
|
||||
|
||||
const fmtMoney = (v: number) => v.toLocaleString('vi-VN')
|
||||
const fmtSla = (s: string | null) => {
|
||||
if (!s) return '—'
|
||||
const ms = new Date(s).getTime() - Date.now()
|
||||
const days = Math.floor(ms / (1000 * 60 * 60 * 24))
|
||||
const hours = Math.floor((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
|
||||
if (ms < 0) return <span className="text-red-600">Quá hạn</span>
|
||||
if (days > 0) return `còn ${days}d ${hours}h`
|
||||
return <span className="text-amber-600">còn {hours}h</span>
|
||||
}
|
||||
|
||||
export function ContractsListPage() {
|
||||
const navigate = useNavigate()
|
||||
@ -46,7 +38,7 @@ export function ContractsListPage() {
|
||||
{ key: 'supplierName', header: 'NCC', render: c => c.supplierName },
|
||||
{ key: 'projectName', header: 'Dự án', render: c => c.projectName },
|
||||
{ key: 'giaTri', header: 'Giá trị', align: 'right', width: 'w-32', render: c => fmtMoney(c.giaTri) },
|
||||
{ key: 'slaDeadline', header: 'SLA', width: 'w-32', render: c => fmtSla(c.slaDeadline) },
|
||||
{ key: 'slaDeadline', header: 'SLA', width: 'w-40', render: c => <SlaTimer deadline={c.slaDeadline} createdAt={c.createdAt} /> },
|
||||
]
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user