统一业务台账首屏布局(05-30-fix-payment-ledger-layout-consistency)

这个提交包含在:
2026-05-30 21:44:16 +08:00
父节点 eea2af7718
当前提交 16fd9bdf52
共修改 25 个文件,包含 834 行新增和 543 行删除
+117 -100
查看文件
@@ -259,6 +259,7 @@ export function ApOperationsPage() {
const [ledgerSearch, setLedgerSearch] = useState("");
const [ledgerPage, setLedgerPage] = useState(1);
const [showLedgerTools, setShowLedgerTools] = useState(false);
const [showLedgerAdvancedFilters, setShowLedgerAdvancedFilters] = useState(false);
const [reviewTarget, setReviewTarget] = useState<PaymentBatch | null>(null);
const [reviewComment, setReviewComment] = useState("");
@@ -384,6 +385,7 @@ export function ApOperationsPage() {
}),
[openRiskFlags, riskBucket],
);
const hasLedgerAdvancedFilters = Boolean(ledgerInvoiceStatus !== "all" || ledgerDateFrom || ledgerDateTo);
const failedDetailItem = useMemo(() => {
if (!failedDetailTarget) {
@@ -666,108 +668,123 @@ export function ApOperationsPage() {
</TabsList>
<TabsContent value="ledger" className="mt-6 space-y-4">
<div className="finance-command-panel grid gap-3 !p-3 md:grid-cols-6">
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">审批状态</div>
<select
className="select-std"
value={ledgerStatus}
onChange={(event) => {
setLedgerStatus(event.target.value as FinanceLedgerStatusFilter);
setLedgerPage(1);
}}
>
<option value="all">全部</option>
<option value="approved">已通过</option>
<option value="paid">已支付</option>
<option value="reviewing">审批中</option>
<option value="rejected">已驳回</option>
<option value="cancelled">已取消</option>
</select>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">付款状态</div>
<select
className="select-std"
value={ledgerPaymentStatus}
onChange={(event) => {
setLedgerPaymentStatus(event.target.value as FinanceLedgerPaymentFilter);
setLedgerPage(1);
}}
>
<option value="all">全部</option>
<option value="unpaid">未付款</option>
<option value="paid">已付款</option>
</select>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">发票状态</div>
<select
className="select-std"
value={ledgerInvoiceStatus}
onChange={(event) => {
setLedgerInvoiceStatus(event.target.value as FinanceLedgerInvoiceFilter);
setLedgerPage(1);
}}
>
<option value="all">全部</option>
<option value="none">无发票</option>
<option value="pending_ocr">识别中</option>
<option value="ocr_failed">识别失败</option>
<option value="available">可添加</option>
<option value="bound">已绑定</option>
<option value="archived">已归档</option>
</select>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">报销日期从</div>
<DateTextInput
value={ledgerDateFrom}
onChange={(event) => {
setLedgerDateFrom(event.target.value);
setLedgerPage(1);
}}
/>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">报销日期至</div>
<DateTextInput
value={ledgerDateTo}
onChange={(event) => {
setLedgerDateTo(event.target.value);
setLedgerPage(1);
}}
/>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">搜索</div>
<Input
placeholder="单号、姓名、部门、项目"
value={ledgerSearch}
onChange={(event) => {
setLedgerSearch(event.target.value);
setLedgerPage(1);
}}
/>
<div className="finance-command-panel space-y-3 !p-3">
<div className="grid gap-3 xl:grid-cols-[minmax(240px,1fr)_160px_160px_auto_auto]">
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">搜索</div>
<Input
placeholder="单号、姓名、部门、项目"
value={ledgerSearch}
onChange={(event) => {
setLedgerSearch(event.target.value);
setLedgerPage(1);
}}
/>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">审批状态</div>
<select
className="select-std"
value={ledgerStatus}
onChange={(event) => {
setLedgerStatus(event.target.value as FinanceLedgerStatusFilter);
setLedgerPage(1);
}}
>
<option value="all">全部</option>
<option value="approved">已通过</option>
<option value="paid">已支付</option>
<option value="reviewing">审批中</option>
<option value="rejected">已驳回</option>
<option value="cancelled">已取消</option>
</select>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">付款状态</div>
<select
className="select-std"
value={ledgerPaymentStatus}
onChange={(event) => {
setLedgerPaymentStatus(event.target.value as FinanceLedgerPaymentFilter);
setLedgerPage(1);
}}
>
<option value="all">全部</option>
<option value="unpaid">未付款</option>
<option value="paid">已付款</option>
</select>
</div>
<div className="flex items-end">
<Button
type="button"
variant={showLedgerAdvancedFilters || hasLedgerAdvancedFilters ? "default" : "secondary"}
onClick={() => setShowLedgerAdvancedFilters((current) => !current)}
>
更多筛选
</Button>
</div>
<div className="flex items-end">
<Button
type="button"
variant="ghost"
onClick={() => {
setLedgerStatus("all");
setLedgerPaymentStatus("all");
setLedgerInvoiceStatus("all");
setLedgerDateFrom("");
setLedgerDateTo("");
setLedgerSearch("");
setLedgerPage(1);
}}
>
清空
</Button>
</div>
</div>
</div>
<div className="flex justify-end">
<Button
type="button"
variant="ghost"
onClick={() => {
setLedgerStatus("all");
setLedgerPaymentStatus("all");
setLedgerInvoiceStatus("all");
setLedgerDateFrom("");
setLedgerDateTo("");
setLedgerSearch("");
setLedgerPage(1);
}}
>
清空台账筛选
</Button>
</div>
{showLedgerAdvancedFilters || hasLedgerAdvancedFilters ? (
<div className="finance-command-panel grid gap-3 !p-3 md:grid-cols-3">
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">发票状态</div>
<select
className="select-std"
value={ledgerInvoiceStatus}
onChange={(event) => {
setLedgerInvoiceStatus(event.target.value as FinanceLedgerInvoiceFilter);
setLedgerPage(1);
}}
>
<option value="all">全部</option>
<option value="none">无发票</option>
<option value="pending_ocr">识别中</option>
<option value="ocr_failed">识别失败</option>
<option value="available">可添加</option>
<option value="bound">已绑定</option>
<option value="archived">已归档</option>
</select>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">报销日期从</div>
<DateTextInput
value={ledgerDateFrom}
onChange={(event) => {
setLedgerDateFrom(event.target.value);
setLedgerPage(1);
}}
/>
</div>
<div className="space-y-2">
<div className="text-sm font-medium text-zinc-700">报销日期至</div>
<DateTextInput
value={ledgerDateTo}
onChange={(event) => {
setLedgerDateTo(event.target.value);
setLedgerPage(1);
}}
/>
</div>
</div>
) : null}
<div className="ops-table-focus overflow-x-auto" data-testid="finance-ledger-table">
<Table>