import { useState } from "react"; import { Link, useParams } from "react-router-dom"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { isApiError } from "../api/types"; import { mapApiErrorMessage } from "../api/errorMessages"; import { fetchReimbursementDetail, payReimbursement, submitReimbursement, withdrawReimbursement, } from "../api/reimbursements"; import { useAuth } from "../auth/AuthContext"; import { hasPermission } from "../auth/permissions"; import { PageHeader } from "../components/common/PageHeader"; export function ReimbursementDetailPage() { const { reimbursementId = "" } = useParams(); const { permissions } = useAuth(); const queryClient = useQueryClient(); const [withdrawComment, setWithdrawComment] = useState("申请撤回并补充说明后重提"); const [paymentVoucherNo, setPaymentVoucherNo] = useState(""); const [paymentDate, setPaymentDate] = useState("2026-02-08"); const [paymentChannel, setPaymentChannel] = useState<"bank" | "alipay" | "wechat" | "cash" | "other">( "bank", ); const [actionError, setActionError] = useState(""); const detailQuery = useQuery({ enabled: Boolean(reimbursementId), queryKey: ["reimbursements", reimbursementId], queryFn: () => fetchReimbursementDetail(reimbursementId), }); const mutation = useMutation({ mutationFn: async (action: "submit" | "withdraw" | "pay") => { if (!reimbursementId) { throw new Error("missing reimbursementId"); } if (action === "submit") { return submitReimbursement(reimbursementId); } if (action === "withdraw") { return withdrawReimbursement(reimbursementId, withdrawComment.trim()); } return payReimbursement(reimbursementId, { paymentVoucherNo: paymentVoucherNo.trim() || undefined, paymentDate: paymentDate || undefined, paymentChannel, }); }, onSuccess: async () => { await Promise.all([ queryClient.invalidateQueries({ queryKey: ["reimbursements"] }), queryClient.invalidateQueries({ queryKey: ["reimbursements", reimbursementId] }), ]); setActionError(""); }, onError: (error) => { if (isApiError(error)) { setActionError( `${error.code}: ${mapApiErrorMessage(error.code, error.details, error.message)}`, ); return; } if (error instanceof Error) { setActionError(error.message); return; } setActionError("操作失败,请稍后重试"); }, }); if (!reimbursementId) { return (

缺少 reimbursementId 参数。

); } if (detailQuery.isLoading) { return (

加载报销详情中...

); } if (detailQuery.isError || !detailQuery.data) { const message = isApiError(detailQuery.error) ? `${detailQuery.error.code}: ${mapApiErrorMessage( detailQuery.error.code, detailQuery.error.details, detailQuery.error.message, )}` : "加载报销详情失败"; return (

{message}

返回报销列表
); } const detail = detailQuery.data; const canPay = hasPermission(permissions, "expense.finance.pay"); return (
返回列表 } />
报销ID:{detail.id}
报销日期:{detail.reimbursementDate ?? "-"}
金额:{detail.totalAmount ?? "-"}
提交人:{detail.submitter?.name ?? "-"}
报销人:{detail.owner?.name ?? "-"}
说明:{detail.description || "-"}

可执行动作

{actionError ? (

{actionError}

) : null}

撤回报销