import type { ReactNode } from "react"; import type { ReimbursementDetail } from "../api/reimbursements"; import type { ReimbursementApprovalEvidenceProjection } from "./reimbursementApprovalProjection"; import { resolveReimbursementDisplayCode } from "./reimbursementDisplay"; export type ReimbursementWorkspaceHeaderModel = { displayCode: string; ownerName: string; reimbursementDate: string | null; totalAmount: string | null; description: string | null; }; export type ReimbursementWorkspaceIssueAnchor = { id: string; label: string; severity: "blocking" | "review" | "info"; }; export type ReimbursementWorkspaceModel = { header: ReimbursementWorkspaceHeaderModel; evidence: ReimbursementApprovalEvidenceProjection; issueAnchors: ReimbursementWorkspaceIssueAnchor[]; }; export type ReimbursementWorkspaceSlots = { status: ReactNode; backAction?: ReactNode; headerDetails?: ReactNode; beforeEvidence?: ReactNode; afterEvidence?: ReactNode; timeline?: ReactNode; actionPanel?: ReactNode; mobileActions?: ReactNode; transientFeedback?: ReactNode; }; export function buildReimbursementWorkspaceHeader( detail: Pick, ): ReimbursementWorkspaceHeaderModel { return { displayCode: resolveReimbursementDisplayCode(detail), ownerName: detail.owner?.name ?? "-", reimbursementDate: detail.reimbursementDate, totalAmount: detail.totalAmount, description: detail.description, }; } export function buildReimbursementWorkspaceIssueAnchors( evidence: ReimbursementApprovalEvidenceProjection, options: { snapshotMissing?: boolean; snapshotInvalid?: boolean } = {}, ): ReimbursementWorkspaceIssueAnchor[] { const anchors: ReimbursementWorkspaceIssueAnchor[] = []; if (options.snapshotInvalid) { anchors.push({ id: "reimbursement-workspace-snapshot", label: "提交记录无法读取", severity: "blocking" }); } else if (options.snapshotMissing) { anchors.push({ id: "reimbursement-workspace-snapshot", label: "未留存预算快照", severity: "info" }); } if (evidence.currentCheck.unlinkedInvoiceCount) { anchors.push({ id: "reimbursement-workspace-unlinked", label: `${evidence.currentCheck.unlinkedInvoiceCount} 张票据尚未选择明细`, severity: "blocking", }); } if (evidence.currentCheck.missingInvoiceItemCount) { anchors.push({ id: "reimbursement-workspace-evidence", label: `${evidence.currentCheck.missingInvoiceItemCount} 条明细缺少票据`, severity: "review", }); } if (evidence.currentCheck.amountUnavailableItemCount) { anchors.push({ id: "reimbursement-workspace-evidence", label: `${evidence.currentCheck.amountUnavailableItemCount} 条明细的票面金额未能读取`, severity: "blocking", }); } if (evidence.currentCheck.manualReviewItemCount) { anchors.push({ id: "reimbursement-workspace-evidence", label: `${evidence.currentCheck.manualReviewItemCount} 条明细需查看原件核对金额`, severity: "review", }); } if (evidence.currentCheck.amountExceededItemCount) { anchors.push({ id: "reimbursement-workspace-evidence", label: `${evidence.currentCheck.amountExceededItemCount} 条明细申报额高于票面金额`, severity: "blocking", }); } return anchors; }