feat(reimbursement-small-team-form-validation): 完善小团队报销填报校验

这个提交包含在:
2026-08-04 23:28:56 +08:00
父节点 f33c67eb20
当前提交 50c14c1b85
共修改 28 个文件,包含 1095 行新增和 30 行删除
+12
查看文件
@@ -119,6 +119,18 @@ export function mapApiErrorMessage(
}
if (code === "VALID_001") {
if (details?.amount === "must_be_positive") {
return "明细金额必须大于 0。";
}
if (details?.items === "at_least_one_required") {
return "请先添加至少 1 条报销明细。";
}
if (details?.items === "positive_amount_required") {
return "所有报销明细金额都必须大于 0,请修改后再提交。";
}
const passwordErrors = readStringList(details?.password);
if (passwordErrors.length) {
return `新密码不符合要求:${passwordErrors.join(";")}。`;
+18
查看文件
@@ -46,6 +46,24 @@ export type PrecheckResponse = {
} | null;
budgetHint: Record<string, unknown> | null;
standardChecks: ExpenseStandardCheck[];
evidenceSummary?: {
invoiceCount: number;
attachmentCount: number;
items: Array<{
itemId: string;
linkedInvoiceCount: number;
invoiceState: "linked" | "unlinked";
}>;
};
timelinessChecks?: Array<{
itemId: string;
expenseDate: string;
ageDays: number;
maxAgeDays: 180 | 365;
overdue: boolean;
crossCalendarYear: boolean;
}>;
assetHint?: { required: boolean; itemCount: number };
warnings: Array<{ code: string; title: string; detail: string }>;
blockingReasons: Array<{ code: string; title: string; detail: string }>;
riskFlags: Array<{ code: string; level: "low" | "medium" | "high"; title: string; detail: string; willOpenOnSubmit: boolean }>;
+23 -4
查看文件
@@ -301,6 +301,11 @@ export type ReimbursementTravelSummaryPayload = {
travelEndDate: string | null;
};
export type ReimbursementUpdatePayload = Partial<ReimbursementTravelSummaryPayload> & {
reimbursementDate?: string;
description?: string | null;
};
export type ReimbursementCreateResponse = {
id: string;
formNumber: string | null;
@@ -486,10 +491,24 @@ export async function updateReimbursementTravelSummary(
reimbursementId: string,
payload: ReimbursementTravelSummaryPayload,
) {
return apiRequestData<{ travelSummary: Omit<ReimbursementDetail["travelSummary"], "isTravel"> }>(
`/api/reimbursements/${reimbursementId}`,
{ method: "PATCH", body: JSON.stringify(payload) },
);
return updateReimbursement(reimbursementId, payload);
}
export async function updateReimbursement(
reimbursementId: string,
payload: ReimbursementUpdatePayload,
) {
return apiRequestData<{
id: string;
status: ReimbursementStatus;
reimbursementDate: string;
description: string | null;
totalAmount: string;
travelSummary: Omit<ReimbursementDetail["travelSummary"], "isTravel">;
}>(`/api/reimbursements/${reimbursementId}`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function createReimbursementItem(