refactor(ui): 提取表单原生组件公共样式并修复面板边距bug

这个提交包含在:
2026-03-05 18:38:56 +08:00
父节点 1412fead5d
当前提交 dc0feb60b2
共修改 4 个文件,包含 661 行新增和 0 行删除
@@ -0,0 +1,73 @@
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;
showProxyOwnerSelector: boolean;
proxyDelegationsQuery: UseQueryResult<FetchMyDelegationsResponse, Error>;
uploadOwnerEmployeeId: string;
setUploadOwnerEmployeeId: (id: string) => void;
};
export function InvoiceUploadCard({
uploadMutation,
selectedFile,
setSelectedFile,
showProxyOwnerSelector,
proxyDelegationsQuery,
uploadOwnerEmployeeId,
setUploadOwnerEmployeeId,
}: InvoiceUploadCardProps) {
return (
<div className="card-std space-y-4">
<h3 className="card-title">上传票据(VAT OCR)</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>
{selectedFile ? selectedFile.name : "选择文件"}
</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)}
type="file"
/>
<Button
data-testid="invoice-upload-submit"
className={selectedFile ? "" : "opacity-50"}
disabled={uploadMutation.isPending || !selectedFile}
onClick={() => uploadMutation.mutate()}
type="button"
>
{uploadMutation.isPending ? "上传中..." : "上传并触发 OCR"}
</Button>
</div>
</div>
);
}