文件
hyb-oa/client/src/pages/invoice-pool/InvoiceUploadCard.tsx
T

100 行
3.5 KiB
TypeScript

import type { FetchMyDelegationsResponse } from "../../api/delegations";
import { Button } from "../../components/ui/button";
import { PDF_FILE_ACCEPT, splitPdfFiles } from "../../lib/pdfFiles";
export type InvoiceUploadCardProps = {
selectedFiles: File[];
setSelectedFiles: (files: File[]) => void;
isUploading: boolean;
uploadProgressLabel: string;
onUpload: () => void;
showProxyOwnerSelector: boolean;
proxyDelegationsQuery: { data?: FetchMyDelegationsResponse };
uploadOwnerEmployeeId: string;
setUploadOwnerEmployeeId: (id: string) => void;
};
export function InvoiceUploadCard({
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">添加发票</h3>
{showProxyOwnerSelector ? (
<select
className="select-std"
data-testid="invoice-upload-owner"
onChange={(event) => setUploadOwnerEmployeeId(event.target.value)}
value={uploadOwnerEmployeeId}
>
<option value="">自己</option>
{(proxyDelegationsQuery.data?.received ?? [])
.filter((item) => item.status === "active")
.map((item) => (
<option key={item.id} value={item.principalEmployeeId}>
{item.principal?.name ?? item.principalEmployeeId}
</option>
))}
</select>
) : null}
<div className="flex items-center gap-3">
<label
htmlFor="file-upload"
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>
{selectedLabel}
</label>
<input
id="file-upload"
className="hidden"
accept={PDF_FILE_ACCEPT}
data-testid="invoice-upload-file"
multiple
onChange={(event) => {
setSelectedFiles(splitPdfFiles(event.target.files).accepted);
event.target.value = "";
}}
type="file"
/>
<Button
data-testid="invoice-upload-submit"
className={selectedFiles.length ? "" : "opacity-50"}
disabled={isUploading || selectedFiles.length === 0}
onClick={onUpload}
type="button"
>
{isUploading ? uploadProgressLabel || "上传中..." : "上传"}
</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>
);
}