R56 A1-A6:费用标准管控

这个提交包含在:
2026-04-08 12:47:40 +08:00
父节点 40c3b7632a
当前提交 845558ab17
共修改 25 个文件,包含 2993 行新增和 10 行删除
+90
查看文件
@@ -0,0 +1,90 @@
import { apiRequestData } from "./http";
export type ExpenseStandardPerUnit = "item" | "day" | "trip";
export type ExpenseStandardControlMode = "warn" | "block";
export type ExpenseStandardScopeType = "global" | "department";
export type ExpenseStandard = {
id: string;
expenseTypeId: string;
expenseTypeName: string | null;
name: string;
maxAmount: string;
perUnit: ExpenseStandardPerUnit;
controlMode: ExpenseStandardControlMode;
scopeType: ExpenseStandardScopeType;
scopeKey: string | null;
scopeLabel: string;
enabled: boolean;
note: string | null;
createdAt: string | null;
updatedAt: string | null;
};
export type ExpenseStandardListResponse = {
expenseTypeId: string | null;
scopeType: ExpenseStandardScopeType | null;
enabled: boolean | null;
items: ExpenseStandard[];
};
export type ExpenseStandardListQuery = {
expenseTypeId?: string;
scopeType?: ExpenseStandardScopeType;
enabled?: boolean;
};
export type CreateExpenseStandardPayload = {
expenseTypeId: string;
name: string;
maxAmount: string;
perUnit?: ExpenseStandardPerUnit;
controlMode?: ExpenseStandardControlMode;
scopeType?: ExpenseStandardScopeType;
scopeKey?: string | null;
enabled?: boolean;
note?: string | null;
};
export type UpdateExpenseStandardPayload = Partial<CreateExpenseStandardPayload>;
function toQueryString(query: Record<string, string | number | boolean | undefined>) {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(query)) {
if (value == null || value === "") {
continue;
}
params.set(key, String(value));
}
const encoded = params.toString();
return encoded ? `?${encoded}` : "";
}
export async function fetchExpenseStandards(query: ExpenseStandardListQuery = {}) {
return apiRequestData<ExpenseStandardListResponse>(
`/api/expense-standards${toQueryString(query as Record<string, string | number | boolean | undefined>)}`,
);
}
export async function createExpenseStandard(payload: CreateExpenseStandardPayload) {
return apiRequestData<ExpenseStandard>("/api/expense-standards", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function updateExpenseStandard(standardId: string, payload: UpdateExpenseStandardPayload) {
return apiRequestData<ExpenseStandard>(`/api/expense-standards/${standardId}`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function deleteExpenseStandard(standardId: string) {
return apiRequestData<ExpenseStandard>(`/api/expense-standards/${standardId}`, {
method: "DELETE",
body: JSON.stringify({}),
});
}
+17
查看文件
@@ -19,6 +19,22 @@ export type RiskFlag = {
export type PrecheckDecision = "pass" | "warn" | "manual_review" | "block";
export type ExpenseStandardCheck = {
itemId: string;
expenseTypeId: string;
expenseTypeName: string;
amount: string;
standardId: string;
standardName: string;
maxAmount: string;
perUnit: "item" | "day" | "trip";
controlMode: "warn" | "block";
scopeType: "global" | "department";
scopeKey: string | null;
exceeded: boolean;
exceededAmount: string;
};
export type PrecheckResponse = {
entityType: "reimbursement" | "purchase_request" | "travel_request";
entityId: string;
@@ -29,6 +45,7 @@ export type PrecheckResponse = {
controlMode: "warn" | "block" | "manual_review";
} | null;
budgetHint: Record<string, unknown> | null;
standardChecks: ExpenseStandardCheck[];
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 }>;
+2 -1
查看文件
@@ -1,5 +1,5 @@
import { apiRequestData } from "./http";
import type { PrecheckResponse, RiskFlag } from "./feeControl";
import type { ExpenseStandardCheck, PrecheckResponse, RiskFlag } from "./feeControl";
export type ReimbursementStatus =
| "draft"
@@ -245,6 +245,7 @@ export type ReimbursementSubmitResponse = {
exceededBudget: boolean;
} | null;
precheckDecision: "pass" | "warn" | "manual_review";
standardWarnings: ExpenseStandardCheck[];
openedRiskFlagCount: number;
};
+4
查看文件
@@ -1,4 +1,5 @@
import { apiRequestData } from "./http";
import type { ExpenseStandardCheck } from "./feeControl";
export type WorkflowTaskSummary = {
id: string;
@@ -57,6 +58,9 @@ export type WorkflowTaskDetail = {
entityType: string;
currentStatus: string;
currentStepId: string;
contextData: {
standardViolations: ExpenseStandardCheck[];
};
startedAt: string | null;
completedAt: string | null;
} | null;