import { useMemo } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { QRCodeSVG } from "qrcode.react"; import { fetchReimbursementDetail } from "../api/reimbursements"; import { isApiError } from "../api/types"; import { mapApiErrorMessage } from "../api/errorMessages"; import { useAuth } from "../auth/AuthContext"; import { CardSkeleton } from "../components/common/CardSkeleton"; import { Button } from "../components/ui/button"; import { resolveReimbursementDisplayCode } from "../lib/reimbursementDisplay"; function formatDate(value: string | null) { return value || "-"; } function formatDateTime(value: string | null) { if (!value) { return "-"; } return value.slice(0, 19).replace("T", " "); } function formatActionLabel(action: string) { const labels: Record = { start: "提交", approve: "通过", reject: "驳回", return: "退回", transfer: "转审", withdraw: "撤回", }; return labels[action] ?? action; } function formatCurrentPrintTime() { return new Date().toLocaleString("zh-CN", { hour12: false }); } export function ReimbursementPrintPage() { const { reimbursementId = "" } = useParams(); const navigate = useNavigate(); const { me } = useAuth(); const detailQuery = useQuery({ enabled: Boolean(reimbursementId), queryKey: ["reimbursements", reimbursementId, "print"], queryFn: () => fetchReimbursementDetail(reimbursementId), }); const printTime = useMemo(() => formatCurrentPrintTime(), []); 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 totalAmount = detail.totalAmount ?? "0.00"; const qrValue = `https://oa.hyinda.com/reimbursements/${detail.id}`; const displayCode = resolveReimbursementDisplayCode(detail); return (
费用报销单打印视图
浏览器可直接打印或另存为 PDF。
LOGO

费用报销单

标准打印稿,仅用于归档与线下签批留存。

表单号
{displayCode}
报销人 {detail.owner?.name ?? "-"}
部门 {detail.department?.name ?? "-"}
报销日期 {formatDate(detail.reimbursementDate)}
提交日期 {formatDateTime(detail.submittedAt)}
当前状态 {detail.status}
提交人 {detail.submitter?.name ?? "-"}
表单编号 {displayCode}
总金额 ¥{totalAmount}
报销明细
{detail.items.map((item, index) => ( ))}
序号 费用日期 费用类型 说明 金额
{index + 1} {formatDate(item.expenseDate)} {item.expenseType?.name ?? item.expenseTypeId} {item.description ?? "-"} ¥{item.amount}
合计 ¥{totalAmount}
发票清单
{detail.invoices.length ? ( detail.invoices.map((invoice) => ( )) ) : ( )}
发票号 发票日期 卖方 金额
{invoice.invoiceCode || "-"}-{invoice.invoiceNumber || "-"} {formatDate(invoice.invoiceDate)} {invoice.sellerName || "-"} ¥{invoice.totalAmount ?? "-"}
暂无关联发票
审批记录
{detail.approvalHistory.length ? ( detail.approvalHistory.map((record) => ( )) ) : ( )}
步骤 审批人 审批时间 状态 意见
{record.stepName ?? "-"} {record.actorName || "-"} {formatDateTime(record.createdAt)} {formatActionLabel(record.action)} {record.comment || "-"}
暂无审批记录
{(detail.linkedTravelRequest || detail.project) ? (
关联信息
关联差旅申请
{detail.linkedTravelRequest ? `${detail.linkedTravelRequest.requestNo ?? detail.linkedTravelRequest.id} · ${detail.linkedTravelRequest.purpose ?? "未填写目的"}` : "未关联"}
关联项目
{detail.project ? `${detail.project.projectNo} · ${detail.project.name}` : "未关联"}
) : null}
扫码查看线上原件
{qrValue}
打印时间:{printTime}
打印人:{me?.name ?? "-"}
); } export default ReimbursementPrintPage;