97 行
3.4 KiB
TypeScript
97 行
3.4 KiB
TypeScript
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<ReimbursementDetail, "formNumber" | "owner" | "reimbursementDate" | "totalAmount" | "description" | "id">,
|
|
): 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;
|
|
}
|