[CLAUDE] FE: Hồ sơ NS — list pane flex-row gọn (hết tràn ngang rail) + đồng nhất cỡ chữ (x2 app SHA256)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m33s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m33s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -241,7 +241,7 @@ export function EmployeesListPage() {
|
|||||||
<section className="flex min-h-0 flex-1 flex-col gap-3">
|
<section className="flex min-h-0 flex-1 flex-col gap-3">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h2 className="truncate text-base font-semibold tracking-tight text-brand-800">Hồ sơ Nhân sự</h2>
|
<h2 className="truncate text-sm font-semibold tracking-tight text-brand-800">Hồ sơ Nhân sự</h2>
|
||||||
<p className="truncate text-xs text-slate-500">
|
<p className="truncate text-xs text-slate-500">
|
||||||
{selectedDeptName ? `Phòng: ${selectedDeptName}` : 'Tất cả phòng ban'}
|
{selectedDeptName ? `Phòng: ${selectedDeptName}` : 'Tất cả phòng ban'}
|
||||||
{' · '}
|
{' · '}
|
||||||
@ -297,8 +297,8 @@ export function EmployeesListPage() {
|
|||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* list table */}
|
{/* list — compact flex rows (KHÔNG bảng 3 cột → không tràn ngang rail hẹp) */}
|
||||||
<div className="min-h-0 flex-1 overflow-auto rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="min-h-0 flex-1 overflow-y-auto overflow-x-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||||
{list.isLoading ? (
|
{list.isLoading ? (
|
||||||
<div className="p-10 text-center text-sm text-slate-500">Đang tải…</div>
|
<div className="p-10 text-center text-sm text-slate-500">Đang tải…</div>
|
||||||
) : !list.data || list.data.items.length === 0 ? (
|
) : !list.data || list.data.items.length === 0 ? (
|
||||||
@ -308,44 +308,34 @@ export function EmployeesListPage() {
|
|||||||
description="Đổi bộ lọc, hoặc bấm 'Tạo mới' để thêm hồ sơ nhân viên."
|
description="Đổi bộ lọc, hoặc bấm 'Tạo mới' để thêm hồ sơ nhân viên."
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<table className="w-full border-collapse text-sm">
|
<div className="divide-y divide-slate-100">
|
||||||
<thead className="sticky top-0 z-10 bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500 shadow-[0_1px_0_theme(colors.slate.200)]">
|
{list.data.items.map(e => {
|
||||||
<tr>
|
const active = selectedId === e.id
|
||||||
<th className="px-3 py-2 text-left font-semibold">Nhân viên</th>
|
return (
|
||||||
<th className="px-3 py-2 text-left font-semibold">Phòng ban</th>
|
<button
|
||||||
<th className="px-3 py-2 text-left font-semibold">Trạng thái</th>
|
key={e.id}
|
||||||
</tr>
|
type="button"
|
||||||
</thead>
|
onClick={() => setParam('id', e.id)}
|
||||||
<tbody>
|
className={cn(
|
||||||
{list.data.items.map(e => {
|
'flex w-full items-center gap-2.5 px-3 py-2 text-left transition hover:bg-slate-50',
|
||||||
const active = selectedId === e.id
|
active && 'bg-brand-50 hover:bg-brand-50',
|
||||||
return (
|
)}
|
||||||
<tr
|
>
|
||||||
key={e.id}
|
<Avatar name={e.fullName} size={30} dim={e.status === 3} />
|
||||||
onClick={() => setParam('id', e.id)}
|
<div className="min-w-0 flex-1">
|
||||||
className={cn(
|
<div className="flex items-center justify-between gap-2">
|
||||||
'cursor-pointer border-b border-slate-100 transition last:border-0 hover:bg-slate-50',
|
<span className="truncate text-[13px] font-medium text-brand-800">{e.fullName ?? '—'}</span>
|
||||||
active && 'bg-brand-50 hover:bg-brand-50',
|
<span className="shrink-0"><StatusBadge status={e.status} /></span>
|
||||||
)}
|
</div>
|
||||||
>
|
<div className="mt-0.5 flex items-center gap-1.5 truncate text-[11px] text-slate-500">
|
||||||
<td className="px-3 py-2">
|
<span className="font-mono text-slate-400">{e.employeeCode}</span>
|
||||||
<div className="flex items-center gap-2.5">
|
{e.departmentName && <><span className="text-slate-300">·</span><span className="truncate">{e.departmentName}</span></>}
|
||||||
<Avatar name={e.fullName} size={32} dim={e.status === 3} />
|
</div>
|
||||||
<div className="min-w-0">
|
</div>
|
||||||
<div className="truncate font-medium text-brand-800">{e.fullName ?? '—'}</div>
|
</button>
|
||||||
<div className="font-mono text-[11px] text-slate-400">{e.employeeCode}</div>
|
)
|
||||||
</div>
|
})}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
|
||||||
<td className="px-3 py-2 text-slate-600">{e.departmentName ?? '—'}</td>
|
|
||||||
<td className="px-3 py-2">
|
|
||||||
<StatusBadge status={e.status} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -654,13 +644,13 @@ function EmployeeDetailTabs({ detail, onDelete }: { detail: EmployeeDetail; onDe
|
|||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div className="flex min-w-0 items-center gap-3.5">
|
<div className="flex min-w-0 items-center gap-3.5">
|
||||||
<span
|
<span
|
||||||
className="grid h-16 w-16 shrink-0 place-items-center rounded-2xl bg-white/15 text-2xl font-bold ring-1 ring-white/25 backdrop-blur-sm"
|
className="grid h-14 w-14 shrink-0 place-items-center rounded-2xl bg-white/15 text-xl font-bold ring-1 ring-white/25 backdrop-blur-sm"
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
{initials(detail.fullName)}
|
{initials(detail.fullName)}
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h2 className="truncate text-xl font-bold leading-tight text-white">{detail.fullName ?? '—'}</h2>
|
<h2 className="truncate text-lg font-bold leading-tight text-white">{detail.fullName ?? '—'}</h2>
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-white/85">
|
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-white/85">
|
||||||
<span className="font-mono">{detail.employeeCode}</span>
|
<span className="font-mono">{detail.employeeCode}</span>
|
||||||
{detail.departmentName && (<><span className="opacity-50">•</span><span className="truncate">{detail.departmentName}</span></>)}
|
{detail.departmentName && (<><span className="opacity-50">•</span><span className="truncate">{detail.departmentName}</span></>)}
|
||||||
|
|||||||
@ -241,7 +241,7 @@ export function EmployeesListPage() {
|
|||||||
<section className="flex min-h-0 flex-1 flex-col gap-3">
|
<section className="flex min-h-0 flex-1 flex-col gap-3">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h2 className="truncate text-base font-semibold tracking-tight text-brand-800">Hồ sơ Nhân sự</h2>
|
<h2 className="truncate text-sm font-semibold tracking-tight text-brand-800">Hồ sơ Nhân sự</h2>
|
||||||
<p className="truncate text-xs text-slate-500">
|
<p className="truncate text-xs text-slate-500">
|
||||||
{selectedDeptName ? `Phòng: ${selectedDeptName}` : 'Tất cả phòng ban'}
|
{selectedDeptName ? `Phòng: ${selectedDeptName}` : 'Tất cả phòng ban'}
|
||||||
{' · '}
|
{' · '}
|
||||||
@ -297,8 +297,8 @@ export function EmployeesListPage() {
|
|||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* list table */}
|
{/* list — compact flex rows (KHÔNG bảng 3 cột → không tràn ngang rail hẹp) */}
|
||||||
<div className="min-h-0 flex-1 overflow-auto rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="min-h-0 flex-1 overflow-y-auto overflow-x-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||||
{list.isLoading ? (
|
{list.isLoading ? (
|
||||||
<div className="p-10 text-center text-sm text-slate-500">Đang tải…</div>
|
<div className="p-10 text-center text-sm text-slate-500">Đang tải…</div>
|
||||||
) : !list.data || list.data.items.length === 0 ? (
|
) : !list.data || list.data.items.length === 0 ? (
|
||||||
@ -308,44 +308,34 @@ export function EmployeesListPage() {
|
|||||||
description="Đổi bộ lọc, hoặc bấm 'Tạo mới' để thêm hồ sơ nhân viên."
|
description="Đổi bộ lọc, hoặc bấm 'Tạo mới' để thêm hồ sơ nhân viên."
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<table className="w-full border-collapse text-sm">
|
<div className="divide-y divide-slate-100">
|
||||||
<thead className="sticky top-0 z-10 bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500 shadow-[0_1px_0_theme(colors.slate.200)]">
|
{list.data.items.map(e => {
|
||||||
<tr>
|
const active = selectedId === e.id
|
||||||
<th className="px-3 py-2 text-left font-semibold">Nhân viên</th>
|
return (
|
||||||
<th className="px-3 py-2 text-left font-semibold">Phòng ban</th>
|
<button
|
||||||
<th className="px-3 py-2 text-left font-semibold">Trạng thái</th>
|
key={e.id}
|
||||||
</tr>
|
type="button"
|
||||||
</thead>
|
onClick={() => setParam('id', e.id)}
|
||||||
<tbody>
|
className={cn(
|
||||||
{list.data.items.map(e => {
|
'flex w-full items-center gap-2.5 px-3 py-2 text-left transition hover:bg-slate-50',
|
||||||
const active = selectedId === e.id
|
active && 'bg-brand-50 hover:bg-brand-50',
|
||||||
return (
|
)}
|
||||||
<tr
|
>
|
||||||
key={e.id}
|
<Avatar name={e.fullName} size={30} dim={e.status === 3} />
|
||||||
onClick={() => setParam('id', e.id)}
|
<div className="min-w-0 flex-1">
|
||||||
className={cn(
|
<div className="flex items-center justify-between gap-2">
|
||||||
'cursor-pointer border-b border-slate-100 transition last:border-0 hover:bg-slate-50',
|
<span className="truncate text-[13px] font-medium text-brand-800">{e.fullName ?? '—'}</span>
|
||||||
active && 'bg-brand-50 hover:bg-brand-50',
|
<span className="shrink-0"><StatusBadge status={e.status} /></span>
|
||||||
)}
|
</div>
|
||||||
>
|
<div className="mt-0.5 flex items-center gap-1.5 truncate text-[11px] text-slate-500">
|
||||||
<td className="px-3 py-2">
|
<span className="font-mono text-slate-400">{e.employeeCode}</span>
|
||||||
<div className="flex items-center gap-2.5">
|
{e.departmentName && <><span className="text-slate-300">·</span><span className="truncate">{e.departmentName}</span></>}
|
||||||
<Avatar name={e.fullName} size={32} dim={e.status === 3} />
|
</div>
|
||||||
<div className="min-w-0">
|
</div>
|
||||||
<div className="truncate font-medium text-brand-800">{e.fullName ?? '—'}</div>
|
</button>
|
||||||
<div className="font-mono text-[11px] text-slate-400">{e.employeeCode}</div>
|
)
|
||||||
</div>
|
})}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
|
||||||
<td className="px-3 py-2 text-slate-600">{e.departmentName ?? '—'}</td>
|
|
||||||
<td className="px-3 py-2">
|
|
||||||
<StatusBadge status={e.status} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -654,13 +644,13 @@ function EmployeeDetailTabs({ detail, onDelete }: { detail: EmployeeDetail; onDe
|
|||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div className="flex min-w-0 items-center gap-3.5">
|
<div className="flex min-w-0 items-center gap-3.5">
|
||||||
<span
|
<span
|
||||||
className="grid h-16 w-16 shrink-0 place-items-center rounded-2xl bg-white/15 text-2xl font-bold ring-1 ring-white/25 backdrop-blur-sm"
|
className="grid h-14 w-14 shrink-0 place-items-center rounded-2xl bg-white/15 text-xl font-bold ring-1 ring-white/25 backdrop-blur-sm"
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
{initials(detail.fullName)}
|
{initials(detail.fullName)}
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h2 className="truncate text-xl font-bold leading-tight text-white">{detail.fullName ?? '—'}</h2>
|
<h2 className="truncate text-lg font-bold leading-tight text-white">{detail.fullName ?? '—'}</h2>
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-white/85">
|
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-white/85">
|
||||||
<span className="font-mono">{detail.employeeCode}</span>
|
<span className="font-mono">{detail.employeeCode}</span>
|
||||||
{detail.departmentName && (<><span className="opacity-50">•</span><span className="truncate">{detail.departmentName}</span></>)}
|
{detail.departmentName && (<><span className="opacity-50">•</span><span className="truncate">{detail.departmentName}</span></>)}
|
||||||
|
|||||||
Reference in New Issue
Block a user