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

148 行
5.2 KiB
TypeScript

import type { UseMutationResult, UseQueryResult } from "@tanstack/react-query";
import type { InvoicePoolListResponse } from "../../api/invoicePool";
import type { ReimbursementListResponse } from "../../api/reimbursements";
import type { TravelRequestDetail, TravelRequestListResponse } from "../../api/travelRequests";
import { Button } from "../../components/ui/button";
export type InvoiceBindMode = "reimbursement" | "travelOrder";
export type InvoiceBindCardProps = {
listQuery: UseQueryResult<InvoicePoolListResponse, Error>;
reimbursementQuery: UseQueryResult<ReimbursementListResponse, Error>;
travelRequestQuery: UseQueryResult<TravelRequestListResponse, Error>;
travelRequestDetailQuery: UseQueryResult<TravelRequestDetail, Error>;
bindMutation: UseMutationResult<Record<string, unknown>, Error, void>;
bindMode: InvoiceBindMode;
setBindMode: (mode: InvoiceBindMode) => void;
canManageTravelPayments: boolean;
selectedInvoiceId: string;
setSelectedInvoiceId: (id: string) => void;
selectedReimbursementId: string;
setSelectedReimbursementId: (id: string) => void;
selectedTravelRequestId: string;
setSelectedTravelRequestId: (id: string) => void;
selectedTravelOrderId: string;
setSelectedTravelOrderId: (id: string) => void;
};
export function InvoiceBindCard({
listQuery,
reimbursementQuery,
travelRequestQuery,
travelRequestDetailQuery,
bindMutation,
bindMode,
setBindMode,
canManageTravelPayments,
selectedInvoiceId,
setSelectedInvoiceId,
selectedReimbursementId,
setSelectedReimbursementId,
selectedTravelRequestId,
setSelectedTravelRequestId,
selectedTravelOrderId,
setSelectedTravelOrderId,
}: InvoiceBindCardProps) {
const bindableTravelOrders = (travelRequestDetailQuery.data?.travelOrders ?? []).filter((item) =>
["confirmed", "paid"].includes(item.status),
);
return (
<div className="card-std p-6 space-y-4">
<div className="flex items-center justify-between gap-3">
<h3 className="card-title">绑定业务单据</h3>
{canManageTravelPayments ? (
<select
className="select-std max-w-[180px]"
value={bindMode}
onChange={(event) => setBindMode(event.target.value as InvoiceBindMode)}
>
<option value="reimbursement">绑定报销</option>
<option value="travelOrder">绑定差旅订单</option>
</select>
) : null}
</div>
<select
className="select-std"
data-testid="invoice-bind-invoice"
onChange={(event) => setSelectedInvoiceId(event.target.value)}
value={selectedInvoiceId}
>
<option value="">选择票据</option>
{(listQuery.data?.items ?? []).map((item) => (
<option key={item.id} value={item.id}>
{item.invoiceCode ? `${item.invoiceCode}-${item.invoiceNumber}` : item.id.substring(0, 8)} ({item.status})
</option>
))}
</select>
{bindMode === "reimbursement" ? (
<select
className="select-std"
data-testid="invoice-bind-reimbursement"
onChange={(event) => setSelectedReimbursementId(event.target.value)}
value={selectedReimbursementId}
>
<option value="">选择报销单</option>
{(reimbursementQuery.data?.items ?? []).map((item) => (
<option key={item.id} value={item.id}>
{item.formNumber ?? item.id} ({item.status})
</option>
))}
</select>
) : (
<>
<select
className="select-std"
data-testid="invoice-bind-travel-request"
onChange={(event) => {
setSelectedTravelRequestId(event.target.value);
setSelectedTravelOrderId("");
}}
value={selectedTravelRequestId}
>
<option value="">选择差旅申请</option>
{(travelRequestQuery.data?.items ?? []).map((item) => (
<option key={item.id} value={item.id}>
{item.requestNo ?? item.purpose} ({item.status})
</option>
))}
</select>
<select
className="select-std"
data-testid="invoice-bind-travel-order"
onChange={(event) => setSelectedTravelOrderId(event.target.value)}
value={selectedTravelOrderId}
disabled={!selectedTravelRequestId}
>
<option value="">选择差旅订单</option>
{bindableTravelOrders.map((item) => (
<option key={item.id} value={item.id}>
{item.externalOrderNo} ({item.status})
</option>
))}
</select>
</>
)}
<div className="pt-2">
<Button
data-testid="invoice-bind-submit"
className="btn-primary"
disabled={
bindMutation.isPending ||
!selectedInvoiceId ||
(bindMode === "reimbursement" ? !selectedReimbursementId : !selectedTravelOrderId)
}
onClick={() => bindMutation.mutate()}
type="button"
>
{bindMutation.isPending ? "绑定中..." : "绑定票据"}
</Button>
</div>
</div>
);
}