R92 A3-A4 优化发票上传状态与批量上传
这个提交包含在:
@@ -4,6 +4,7 @@ import { StatusBadge } from "../../components/common/StatusBadge";
|
||||
import { TableSkeleton } from "../../components/common/TableSkeleton";
|
||||
import { Pagination } from "../../components/common/Pagination";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../../components/ui/dropdown-menu";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { formatInvoiceOcrErrorMessage } from "../../lib/invoiceOcr";
|
||||
|
||||
export type InvoiceListCardProps = {
|
||||
@@ -34,9 +35,9 @@ export function InvoiceListCard({
|
||||
}: InvoiceListCardProps) {
|
||||
return (
|
||||
<div className="card-std p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<h3 className="card-title">筛选与列表</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
||||
<select
|
||||
className="select-sm"
|
||||
data-testid="invoice-filter-status"
|
||||
@@ -72,7 +73,72 @@ export function InvoiceListCard({
|
||||
{listQuery.isLoading ? <TableSkeleton columns={5} rows={5} /> : null}
|
||||
{!listQuery.isLoading ? (
|
||||
<>
|
||||
<div className="table-container">
|
||||
<div className="space-y-3 md:hidden" data-testid="invoice-pool-mobile-list">
|
||||
{(listQuery.data?.items ?? []).length ? (
|
||||
listQuery.data?.items.map((item) => (
|
||||
<article className="rounded-xl border border-zinc-200 bg-white p-4 shadow-sm" data-testid="invoice-mobile-row" 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.originalName || item.id}</div>
|
||||
<div className="mt-1 font-mono text-xs text-zinc-500">{item.id.slice(0, 8)}</div>
|
||||
</div>
|
||||
<StatusBadge className="shrink-0" status={item.status} />
|
||||
</div>
|
||||
|
||||
<div className="mt-3 grid grid-cols-2 gap-3 text-sm">
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">发票号码</div>
|
||||
<div className="truncate font-medium text-zinc-900">
|
||||
{item.invoiceCode || "-"}-{item.invoiceNumber || "-"}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">金额</div>
|
||||
<div className="font-medium text-zinc-900">{item.totalAmount ?? "-"}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 rounded-lg bg-zinc-50 px-3 py-2 text-xs text-zinc-600">
|
||||
{item.status === "pending_ocr"
|
||||
? `OCR 识别中,重试 ${item.ocrAttempts} 次`
|
||||
: item.status === "ocr_failed"
|
||||
? `OCR 失败:${formatInvoiceOcrErrorMessage(item.ocrLastError)}`
|
||||
: "OCR 已完成或无需处理"}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 grid grid-cols-2 gap-2">
|
||||
<Button
|
||||
className="min-h-10"
|
||||
data-testid="invoice-mobile-detail-button"
|
||||
onClick={() => setDetailInvoiceId(item.id)}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
查看详情
|
||||
</Button>
|
||||
<Button
|
||||
className="min-h-10"
|
||||
data-testid="invoice-mobile-preview-button"
|
||||
disabled={signedUrlMutation.isPending}
|
||||
onClick={() => signedUrlMutation.mutate(item.id)}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
预览
|
||||
</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>
|
||||
|
||||
<div className="table-container hidden md:block">
|
||||
<table className="w-full text-left text-sm text-zinc-600" data-testid="invoice-pool-table">
|
||||
<thead className="bg-zinc-50/50">
|
||||
<tr>
|
||||
|
||||
在新工单中引用
屏蔽一个用户