统一业务台账首屏布局(05-30-fix-payment-ledger-layout-consistency)
这个提交包含在:
+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>
|
||||
|
||||
在新工单中引用
屏蔽一个用户