[CLAUDE] FE-User+FE-Admin: Plan AG6 — Compact PE card 3 row gọn đẹp
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m21s

Anh feedback 2026-05-21: "Cho thông tin bên trong này nó gọn đẹp lại nhé".
PE card hiện 4-5 row hơi dài. Compact xuống 3 row tightly packed:

Row 1: [Tên gói thầu]                        [Status badge]
Row 2: PE/2026/A/035 · 10:40 19/05/2026
Row 3: 👤 Drafter · Phòng ban                [✓ HĐ if any]

Changes:
- py-2.5 → py-2 (compact vertical padding)
- Drop Type label "Duyệt NCC" badge redundant (page header đã hiện)
- Combine maPhieu + createdAt vào 1 row với separator ·
- Combine drafter + department + contract badge vào 1 row (conditional render)
- "✓ Đã tạo HĐ" → "✓ HĐ" short label inline cuối row 3
- Separator color slate-300 nhẹ hơn slate-500

Verify:
- npm build fe-user PASS 0 TS err 1292.66 KB (gzip 337.19 KB)
- npm build fe-admin PASS 0 TS err 1404.01 KB (gzip 357.70 KB)
- 2 file SHA256 IDENTICAL 3645307C... (mirror §3.9)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-21 22:50:14 +07:00
parent 083b601ea4
commit d99069a305
2 changed files with 34 additions and 44 deletions

View File

@ -343,23 +343,13 @@ export function PurchaseEvaluationsListPage() {
<button
onClick={() => selectRow(p.id)}
className={cn(
'block w-full px-3 py-2.5 text-left transition hover:bg-slate-50',
'block w-full px-3 py-2 text-left transition hover:bg-slate-50',
selectedId === p.id && 'bg-brand-50 ring-1 ring-inset ring-brand-200',
)}
>
{/* Plan AG6 — compact card 3 row: title+badge / mã+time / drafter+dept+contract */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0 flex-1">
<div className="truncate text-[13px] font-medium text-slate-900">{p.tenGoiThau}</div>
<div className="mt-0.5 flex items-center gap-1.5 text-[11px] text-slate-500">
<span className="font-mono">{p.maPhieu ?? '—'}</span>
</div>
{(p.drafterName || p.departmentName) && (
<div className="mt-0.5 truncate text-[11px] text-slate-500">
<span>👤 {p.drafterName ?? '—'}</span>
{p.departmentName && <span className="text-slate-400"> · {p.departmentName}</span>}
</div>
)}
</div>
<div className="min-w-0 flex-1 truncate text-[13px] font-medium text-slate-900">{p.tenGoiThau}</div>
<span
className={cn(
'shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium',
@ -369,21 +359,26 @@ export function PurchaseEvaluationsListPage() {
{PeDisplayStatusLabel[getPeDisplayStatus(p.phase)]}
</span>
</div>
<div className="mt-1 flex items-center justify-between text-[11px] text-slate-500">
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-slate-600">
{PurchaseEvaluationTypeLabel[p.type]}
</span>
{/* S23 t2 UAT: BE list sort theo UpdatedAt DESC (fallback CreatedAt) —
phiếu vừa update (Tạo / Gửi duyệt / Trả lại) đưa lên đầu list. */}
<span className="font-medium text-slate-600" title={`Tạo lúc ${new Date(p.createdAt).toLocaleString('vi-VN')}`}>
<div className="mt-0.5 flex items-center gap-1.5 text-[11px] text-slate-500">
<span className="font-mono">{p.maPhieu ?? '—'}</span>
<span className="text-slate-300">·</span>
{/* S23 t2 UAT: BE list sort theo UpdatedAt DESC (fallback CreatedAt). */}
<span title={`Tạo lúc ${new Date(p.createdAt).toLocaleString('vi-VN')}`}>
{new Date(p.createdAt).toLocaleString('vi-VN', {
day: '2-digit', month: '2-digit', year: 'numeric',
hour: '2-digit', minute: '2-digit',
})}
</span>
</div>
{p.contractId && (
<div className="mt-1 text-[10px] text-brand-600"> Đã tạo </div>
{(p.drafterName || p.departmentName || p.contractId) && (
<div className="mt-0.5 flex items-center justify-between gap-2 text-[11px]">
<span className="min-w-0 flex-1 truncate text-slate-500">
{p.drafterName && <>👤 {p.drafterName}</>}
{p.drafterName && p.departmentName && <span className="text-slate-300"> · </span>}
{p.departmentName && <span className="text-slate-400">{p.departmentName}</span>}
</span>
{p.contractId && <span className="shrink-0 text-[10px] font-medium text-brand-600"> </span>}
</div>
)}
</button>
</li>

View File

@ -343,23 +343,13 @@ export function PurchaseEvaluationsListPage() {
<button
onClick={() => selectRow(p.id)}
className={cn(
'block w-full px-3 py-2.5 text-left transition hover:bg-slate-50',
'block w-full px-3 py-2 text-left transition hover:bg-slate-50',
selectedId === p.id && 'bg-brand-50 ring-1 ring-inset ring-brand-200',
)}
>
{/* Plan AG6 — compact card 3 row: title+badge / mã+time / drafter+dept+contract */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0 flex-1">
<div className="truncate text-[13px] font-medium text-slate-900">{p.tenGoiThau}</div>
<div className="mt-0.5 flex items-center gap-1.5 text-[11px] text-slate-500">
<span className="font-mono">{p.maPhieu ?? '—'}</span>
</div>
{(p.drafterName || p.departmentName) && (
<div className="mt-0.5 truncate text-[11px] text-slate-500">
<span>👤 {p.drafterName ?? '—'}</span>
{p.departmentName && <span className="text-slate-400"> · {p.departmentName}</span>}
</div>
)}
</div>
<div className="min-w-0 flex-1 truncate text-[13px] font-medium text-slate-900">{p.tenGoiThau}</div>
<span
className={cn(
'shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium',
@ -369,21 +359,26 @@ export function PurchaseEvaluationsListPage() {
{PeDisplayStatusLabel[getPeDisplayStatus(p.phase)]}
</span>
</div>
<div className="mt-1 flex items-center justify-between text-[11px] text-slate-500">
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-slate-600">
{PurchaseEvaluationTypeLabel[p.type]}
</span>
{/* S23 t2 UAT: BE list sort theo UpdatedAt DESC (fallback CreatedAt) —
phiếu vừa update (Tạo / Gửi duyệt / Trả lại) đưa lên đầu list. */}
<span className="font-medium text-slate-600" title={`Tạo lúc ${new Date(p.createdAt).toLocaleString('vi-VN')}`}>
<div className="mt-0.5 flex items-center gap-1.5 text-[11px] text-slate-500">
<span className="font-mono">{p.maPhieu ?? '—'}</span>
<span className="text-slate-300">·</span>
{/* S23 t2 UAT: BE list sort theo UpdatedAt DESC (fallback CreatedAt). */}
<span title={`Tạo lúc ${new Date(p.createdAt).toLocaleString('vi-VN')}`}>
{new Date(p.createdAt).toLocaleString('vi-VN', {
day: '2-digit', month: '2-digit', year: 'numeric',
hour: '2-digit', minute: '2-digit',
})}
</span>
</div>
{p.contractId && (
<div className="mt-1 text-[10px] text-brand-600"> Đã tạo </div>
{(p.drafterName || p.departmentName || p.contractId) && (
<div className="mt-0.5 flex items-center justify-between gap-2 text-[11px]">
<span className="min-w-0 flex-1 truncate text-slate-500">
{p.drafterName && <>👤 {p.drafterName}</>}
{p.drafterName && p.departmentName && <span className="text-slate-300"> · </span>}
{p.departmentName && <span className="text-slate-400">{p.departmentName}</span>}
</span>
{p.contractId && <span className="shrink-0 text-[10px] font-medium text-brand-600"> </span>}
</div>
)}
</button>
</li>