ux: 花名册列表两行记录样式美化
- 姓名列:姓名加粗深色 + 证件号码淡灰小字,紧凑行间距 - 社保缴费列:个人/企业改为右对齐标签式,字号区分主次 - 操作列:两行按钮间增加分隔线,按钮间距收紧 - 全行 padding 从 py-3 调整为 py-2.5,行高更紧凑 - 行间分隔线变淡(gray-100 → gray-50),hover 效果加 group Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -674,23 +674,25 @@ export default function Roster() {
|
||||
{employees.map((e: any) => (
|
||||
<tr
|
||||
key={e.id}
|
||||
className="border-b border-gray-100 last:border-0 cursor-pointer transition-colors hover:bg-primary/[0.03]"
|
||||
className="border-b border-gray-50 last:border-0 cursor-pointer transition-colors hover:bg-primary/[0.03] group"
|
||||
onClick={() => setSelectedId(e.id)}
|
||||
>
|
||||
<td className="px-4 py-3" onClick={(ev) => ev.stopPropagation()}>
|
||||
<td className="px-4 py-2.5" onClick={(ev) => ev.stopPropagation()}>
|
||||
<input type="checkbox" checked={selectedIds.has(e.id)} onChange={() => toggleSelect(e.id)} />
|
||||
</td>
|
||||
<td className="px-4 py-3 font-medium">
|
||||
<div>{e.name}</div>
|
||||
<div className="text-gray-400 text-xs font-mono cursor-pointer hover:text-primary transition-colors" title="点击复制完整证件号码" onClick={(ev) => {
|
||||
ev.stopPropagation()
|
||||
if (e.idCardNumber) {
|
||||
copyToClipboard(e.idCardNumber, '已复制证件号码')
|
||||
}
|
||||
}}>{e.idCardMasked || '—'}</div>
|
||||
<td className="px-4 py-2.5">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="font-medium text-gray-900 text-sm leading-tight">{e.name}</span>
|
||||
<span className="text-gray-400 text-[11px] font-mono cursor-pointer hover:text-primary transition-colors leading-tight" title="点击复制完整证件号码" onClick={(ev) => {
|
||||
ev.stopPropagation()
|
||||
if (e.idCardNumber) {
|
||||
copyToClipboard(e.idCardNumber, '已复制证件号码')
|
||||
}
|
||||
}}>{e.idCardMasked || '—'}</span>
|
||||
</div>
|
||||
</td>
|
||||
{colVisible('department') && <td className="px-4 py-3 text-gray-500">{e.department}</td>}
|
||||
{colVisible('status') && <td className="px-4 py-3">
|
||||
{colVisible('department') && <td className="px-4 py-2.5 text-gray-500">{e.department}</td>}
|
||||
{colVisible('status') && <td className="px-4 py-2.5">
|
||||
<span className={`px-2 py-0.5 rounded text-xs ${
|
||||
e.status === 'ACTIVE' ? 'bg-green-50 text-safe'
|
||||
: e.status === 'PRE_HIRE' ? 'bg-blue-50 text-blue-600'
|
||||
@@ -708,8 +710,8 @@ export default function Roster() {
|
||||
</span>
|
||||
)}
|
||||
</td>}
|
||||
{colVisible('hireDate') && <td className="px-4 py-3 text-gray-500">{e.hireDate?.toString().slice(0, 10)}</td>}
|
||||
<td className="hidden px-4 py-3 text-gray-500">
|
||||
{colVisible('hireDate') && <td className="px-4 py-2.5 text-gray-500">{e.hireDate?.toString().slice(0, 10)}</td>}
|
||||
<td className="hidden px-4 py-2.5 text-gray-500">
|
||||
{e.hasTermination && e.latestTerminationDate && e.latestTerminationStatus !== 'CANCELLED' && e.latestTerminationStatus !== 'COMPLETED' ? (
|
||||
<span className={e.status === 'RESIGNED' ? 'text-gray-500' : 'text-amber-600'}>
|
||||
{e.latestTerminationDate.toString().slice(0, 10)}
|
||||
@@ -719,10 +721,10 @@ export default function Roster() {
|
||||
<span className="text-gray-300">—</span>
|
||||
)}
|
||||
</td>
|
||||
{colVisible('position') && <td className="px-4 py-3 text-gray-500">{e.position || '—'}</td>}
|
||||
{colVisible('phone') && <td className="px-4 py-3 text-gray-500">{e.phone || '—'}</td>}
|
||||
{colVisible('gender') && <td className="px-4 py-3 text-center text-gray-500">{e.gender || '—'}</td>}
|
||||
{colVisible('contractType') && <td className="px-4 py-3">
|
||||
{colVisible('position') && <td className="px-4 py-2.5 text-gray-500">{e.position || '—'}</td>}
|
||||
{colVisible('phone') && <td className="px-4 py-2.5 text-gray-500">{e.phone || '—'}</td>}
|
||||
{colVisible('gender') && <td className="px-4 py-2.5 text-center text-gray-500">{e.gender || '—'}</td>}
|
||||
{colVisible('contractType') && <td className="px-4 py-2.5">
|
||||
{(() => {
|
||||
const typeConfig: Record<string, { label: string; style: string }> = {
|
||||
FIXED: { label: '劳动合同-固定期', style: 'bg-blue-50 text-blue-700 border border-blue-200' },
|
||||
@@ -739,7 +741,7 @@ export default function Roster() {
|
||||
return <span className={`px-2 py-0.5 rounded text-xs ${cfg.style}`}>{cfg.label}</span>
|
||||
})()}
|
||||
</td>}
|
||||
{colVisible('contractStatus') && <td className="px-4 py-3">
|
||||
{colVisible('contractStatus') && <td className="px-4 py-2.5">
|
||||
{(() => {
|
||||
const tagStyles: Record<string, string> = {
|
||||
expired: 'bg-red-50 text-danger',
|
||||
@@ -764,7 +766,7 @@ export default function Roster() {
|
||||
return <span className={`px-2 py-0.5 rounded text-xs ${style}`}>{text}</span>
|
||||
})()}
|
||||
</td>}
|
||||
{colVisible('contractExpiry') && <td className="px-4 py-3 text-gray-500">
|
||||
{colVisible('contractExpiry') && <td className="px-4 py-2.5 text-gray-500">
|
||||
{(() => {
|
||||
const endDate = e.latestContract?.endDate
|
||||
if (!endDate) {
|
||||
@@ -784,7 +786,7 @@ export default function Roster() {
|
||||
return <span className="text-xs">{dateStr}</span>
|
||||
})()}
|
||||
</td>}
|
||||
{colVisible('socialStatus') && <td className="px-4 py-3">
|
||||
{colVisible('socialStatus') && <td className="px-4 py-2.5">
|
||||
{(() => {
|
||||
const status = e.socialInsuranceStatus
|
||||
if (!status) return <span className="text-gray-300 text-xs">—</span>
|
||||
@@ -798,12 +800,12 @@ export default function Roster() {
|
||||
return <span className={`px-2 py-0.5 rounded text-xs ${c.style}`}>{c.label}</span>
|
||||
})()}
|
||||
</td>}
|
||||
{colVisible('socialInsBase') && <td className="px-4 py-3 text-right text-xs">
|
||||
{colVisible('socialInsBase') && <td className="px-4 py-2.5 text-right text-xs">
|
||||
{e.socialInsBase ? e.socialInsBase.toLocaleString() : <span className="text-gray-300">—</span>}
|
||||
</td>}
|
||||
{colVisible('socialInsAmount') && <td className="px-4 py-3 text-right text-xs">
|
||||
{colVisible('socialInsAmount') && <td className="px-4 py-2.5 text-right">
|
||||
{(() => {
|
||||
if (!e.socialInsCalc && !e.housingFundCalc) return <span className="text-gray-300">—</span>
|
||||
if (!e.socialInsCalc && !e.housingFundCalc) return <span className="text-gray-300 text-xs">—</span>
|
||||
const socialEmp = e.socialInsCalc?.socialEmp || 0
|
||||
const socialOrg = e.socialInsCalc?.socialOrg || 0
|
||||
const housingEmp = e.housingFundCalc?.housingEmp || 0
|
||||
@@ -811,14 +813,14 @@ export default function Roster() {
|
||||
const totalEmp = socialEmp + housingEmp
|
||||
const totalOrg = socialOrg + housingOrg
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<span>个人: {totalEmp.toFixed(2)}</span>
|
||||
<span className="text-gray-400">企业: {totalOrg.toFixed(2)}</span>
|
||||
<div className="flex flex-col gap-0.5 items-end">
|
||||
<span className="text-xs text-gray-700 leading-tight">个人 {totalEmp.toFixed(2)}</span>
|
||||
<span className="text-[11px] text-gray-400 leading-tight">企业 {totalOrg.toFixed(2)}</span>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
</td>}
|
||||
{colVisible('records') && <td className="px-4 py-3 text-center">
|
||||
{colVisible('records') && <td className="px-4 py-2.5 text-center">
|
||||
<div className="flex items-center justify-center gap-1 flex-wrap">
|
||||
{(() => {
|
||||
const items = [
|
||||
@@ -839,10 +841,10 @@ export default function Roster() {
|
||||
})()}
|
||||
</div>
|
||||
</td>}
|
||||
<td className="px-4 py-3 text-center">
|
||||
<td className="px-3 py-2 text-center">
|
||||
{e.status === 'ACTIVE' && (!e.hasTermination || e.latestTerminationStatus === 'CANCELLED' || e.latestTerminationStatus === 'COMPLETED') && (
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<div className="flex flex-col items-center gap-1.5">
|
||||
<div className="flex items-center justify-center gap-0.5">
|
||||
<button
|
||||
type="button"
|
||||
title="调薪"
|
||||
@@ -886,7 +888,7 @@ export default function Roster() {
|
||||
<Building2 className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<div className="flex items-center justify-center gap-0.5 border-t border-gray-100 pt-1.5">
|
||||
<button
|
||||
type="button"
|
||||
title="开具证明"
|
||||
|
||||
Reference in New Issue
Block a user