R92 A5-A6 修复手机报销列表并补自动化回归
这个提交包含在:
@@ -587,7 +587,92 @@ export function ReimbursementsPage() {
|
||||
|
||||
{!listQuery.isLoading && !listQuery.isError ? (
|
||||
<>
|
||||
<PrimaryTable>
|
||||
<div className="space-y-3 md:hidden" data-testid="reimbursements-mobile-list">
|
||||
{items.length ? (
|
||||
items.map((item) => {
|
||||
const canSelectRow = Boolean(
|
||||
item.pendingWorkflow?.task?.id && item.pendingWorkflow.allowedActions.includes("approve"),
|
||||
);
|
||||
const actionLabel = ["draft", "rejected"].includes(item.status) ? "继续编辑" : "查看详情";
|
||||
|
||||
return (
|
||||
<article
|
||||
className="card-std space-y-3 p-4"
|
||||
data-testid="reimbursement-mobile-card"
|
||||
key={item.id}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="truncate text-sm font-semibold text-zinc-900">
|
||||
{item.formNumber || item.id}
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-zinc-500">{item.reimbursementDate ?? "未填写日期"}</div>
|
||||
</div>
|
||||
<StatusBadge className="shrink-0" status={item.status} />
|
||||
</div>
|
||||
|
||||
{item.project ? (
|
||||
<div className="rounded-lg bg-zinc-50 px-3 py-2 text-xs text-zinc-600">
|
||||
项目:{item.project.projectNo} · {item.project.name}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">金额</div>
|
||||
<div className="font-semibold text-zinc-900">
|
||||
{item.totalAmount != null
|
||||
? new Intl.NumberFormat("zh-CN", { style: "currency", currency: "CNY" }).format(
|
||||
Number(item.totalAmount),
|
||||
)
|
||||
: "-"}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">报销人</div>
|
||||
<div className="truncate font-medium text-zinc-900">{item.owner?.name ?? "-"}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{item.pendingWorkflow?.task?.id ? (
|
||||
<div className="rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-700">
|
||||
当前待办:{item.pendingWorkflow.task.stepName}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex items-center gap-2 pt-1">
|
||||
{batchMode ? (
|
||||
<label className="flex min-h-10 items-center gap-2 rounded-lg border border-zinc-200 px-3 text-sm text-zinc-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedReimbursementIds.includes(item.id)}
|
||||
disabled={!canSelectRow}
|
||||
onChange={() => toggleBatchSelection(item.id)}
|
||||
aria-label={`选择报销单 ${item.formNumber ?? item.id}`}
|
||||
/>
|
||||
选择
|
||||
</label>
|
||||
) : null}
|
||||
<Button asChild className="min-h-10 flex-1" size="sm" variant="secondary">
|
||||
<Link
|
||||
to={`/reimbursements/${item.id}`}
|
||||
data-testid="reimbursement-mobile-detail-link"
|
||||
>
|
||||
{actionLabel}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="rounded-xl border border-dashed border-zinc-300 px-4 py-8 text-center text-sm text-zinc-500">
|
||||
暂无数据
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<PrimaryTable className="hidden md:block">
|
||||
<table className="w-full border-collapse text-left" data-testid="reimbursements-table">
|
||||
<thead className="table-header">
|
||||
<tr>
|
||||
|
||||
在新工单中引用
屏蔽一个用户