R92 A3-A4 优化发票上传状态与批量上传
这个提交包含在:
@@ -1,26 +1,36 @@
|
||||
import type { UseMutationResult, UseQueryResult } from "@tanstack/react-query";
|
||||
import type { FetchMyDelegationsResponse } from "../../api/delegations";
|
||||
import { Button } from "../../components/ui/button";
|
||||
|
||||
export type InvoiceUploadCardProps = {
|
||||
uploadMutation: UseMutationResult<{ invoicePoolId: string; status: string; fileSha256: string }, Error, void>;
|
||||
selectedFile: File | null;
|
||||
setSelectedFile: (file: File | null) => void;
|
||||
selectedFiles: File[];
|
||||
setSelectedFiles: (files: File[]) => void;
|
||||
isUploading: boolean;
|
||||
uploadProgressLabel: string;
|
||||
onUpload: () => void;
|
||||
showProxyOwnerSelector: boolean;
|
||||
proxyDelegationsQuery: UseQueryResult<FetchMyDelegationsResponse, Error>;
|
||||
proxyDelegationsQuery: { data?: FetchMyDelegationsResponse };
|
||||
uploadOwnerEmployeeId: string;
|
||||
setUploadOwnerEmployeeId: (id: string) => void;
|
||||
};
|
||||
|
||||
export function InvoiceUploadCard({
|
||||
uploadMutation,
|
||||
selectedFile,
|
||||
setSelectedFile,
|
||||
selectedFiles,
|
||||
setSelectedFiles,
|
||||
isUploading,
|
||||
uploadProgressLabel,
|
||||
onUpload,
|
||||
showProxyOwnerSelector,
|
||||
proxyDelegationsQuery,
|
||||
uploadOwnerEmployeeId,
|
||||
setUploadOwnerEmployeeId,
|
||||
}: InvoiceUploadCardProps) {
|
||||
const selectedLabel =
|
||||
selectedFiles.length === 0
|
||||
? "选择文件"
|
||||
: selectedFiles.length === 1
|
||||
? selectedFiles[0].name
|
||||
: `已选择 ${selectedFiles.length} 个文件`;
|
||||
|
||||
return (
|
||||
<div className="card-std p-6 space-y-4">
|
||||
<h3 className="card-title">上传票据(VAT OCR)</h3>
|
||||
@@ -47,27 +57,39 @@ export function InvoiceUploadCard({
|
||||
className="cursor-pointer inline-flex h-9 items-center justify-center rounded-md border border-dashed border-zinc-300 bg-zinc-50 px-4 py-2 text-sm font-medium text-zinc-600 shadow-sm transition-colors hover:bg-zinc-100 hover:text-zinc-900 focus-within:ring-1 focus-within:ring-zinc-400"
|
||||
>
|
||||
<span className="material-symbols-outlined mr-2 text-[18px]">cloud_upload</span>
|
||||
{selectedFile ? selectedFile.name : "选择文件"}
|
||||
{selectedLabel}
|
||||
</label>
|
||||
<input
|
||||
id="file-upload"
|
||||
className="hidden"
|
||||
accept="application/pdf,image/jpeg,image/png,image/webp"
|
||||
data-testid="invoice-upload-file"
|
||||
onChange={(event) => setSelectedFile(event.target.files?.[0] ?? null)}
|
||||
multiple
|
||||
onChange={(event) => setSelectedFiles(Array.from(event.target.files ?? []))}
|
||||
type="file"
|
||||
/>
|
||||
|
||||
<Button
|
||||
data-testid="invoice-upload-submit"
|
||||
className={selectedFile ? "" : "opacity-50"}
|
||||
disabled={uploadMutation.isPending || !selectedFile}
|
||||
onClick={() => uploadMutation.mutate()}
|
||||
className={selectedFiles.length ? "" : "opacity-50"}
|
||||
disabled={isUploading || selectedFiles.length === 0}
|
||||
onClick={onUpload}
|
||||
type="button"
|
||||
>
|
||||
{uploadMutation.isPending ? "上传中..." : "上传并触发 OCR"}
|
||||
{isUploading ? uploadProgressLabel || "上传中..." : "上传并触发 OCR"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{selectedFiles.length ? (
|
||||
<div className="rounded-xl border border-zinc-200 bg-zinc-50 px-3 py-2 text-xs text-zinc-600">
|
||||
{selectedFiles.slice(0, 4).map((file) => (
|
||||
<div key={`${file.name}-${file.size}`} className="truncate">
|
||||
{file.name} · {Math.ceil(file.size / 1024)} KB
|
||||
</div>
|
||||
))}
|
||||
{selectedFiles.length > 4 ? <div>另有 {selectedFiles.length - 4} 个文件</div> : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户