feat: 完成错误原因合同与付款就绪提示(09-05-error-explainability-payment-readiness)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-09-05 19:00:35 +08:00
父节点 ab82fe30c0
当前提交 a837912638
共修改 42 个文件,包含 2867 行新增和 876 行删除
+16 -1
查看文件
@@ -1,4 +1,19 @@
import type { PaymentBatchStatus } from "../api/paymentBatches";
import type { PaymentBatchItem, PaymentBatchStatus } from "../api/paymentBatches";
import type { RiskFlag } from "../api/feeControl";
import { resolveErrorReasonMessage, UNKNOWN_VALIDATION_MESSAGE } from "../api/errorReasons";
export function paymentItemFailureMessage(item: Pick<PaymentBatchItem, "id" | "status" | "failureCode" | "failureMessage" | "openRiskFlags">, batchId: string) {
if (item.status !== "failed" && !item.failureCode && !item.failureMessage) return null;
const flag = item.openRiskFlags.find((risk) => risk.riskCode === "payment_batch_execute_failed"
&& risk.payloadJson?.batchId === batchId && risk.payloadJson?.itemId === item.id);
return resolveErrorReasonMessage(flag?.payloadJson?.reasonCode) ?? UNKNOWN_VALIDATION_MESSAGE;
}
export function paymentRiskFlagsForDisplay(flags: RiskFlag[]) {
return flags.map((flag) => flag.riskCode === "payment_batch_execute_failed" ? {
...flag, detail: resolveErrorReasonMessage(flag.payloadJson?.reasonCode) ?? UNKNOWN_VALIDATION_MESSAGE,
} : flag);
}
const PAYMENT_BATCH_STATUS_LABELS: Record<PaymentBatchStatus, string> = {
draft: "待付款复核",
+9 -1
查看文件
@@ -1,5 +1,6 @@
import { isApiError } from "../api/types";
import { mapApiErrorMessage } from "../api/errorMessages";
import { UNKNOWN_VALIDATION_MESSAGE } from "../api/errorReasons";
function toUserSafeMessage(message: string | undefined, fallback: string) {
const normalized = (message ?? "")
@@ -8,9 +9,11 @@ function toUserSafeMessage(message: string | undefined, fallback: string) {
if (!normalized) {
return fallback;
}
if (normalized === "参数校验失败") return UNKNOWN_VALIDATION_MESSAGE;
const exposesTechnicalDetail =
!/[\u3400-\u9fff]/.test(normalized) ||
/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i.test(normalized) ||
/https?:\/\/|\/api\/|(?:^|\s)\/[A-Za-z0-9._-]+(?:\/[^\s]*)?|[A-Za-z]:\\|(?:^|\n)\s*at\s|\b(?:GET|POST|PUT|PATCH|DELETE)\s+\/|^(?:\{|\[)/.test(normalized);
return exposesTechnicalDetail ? fallback : normalized;
@@ -21,8 +24,13 @@ export function resolveErrorMessage(
fallback = "操作失败,请稍后重试",
): string {
if (isApiError(error)) {
const message = mapApiErrorMessage(error.code, error.details, error.message);
if (message === UNKNOWN_VALIDATION_MESSAGE) {
const requestId = /^[A-Za-z0-9_-]{1,80}$/.test(error.requestId) ? error.requestId : "";
return requestId ? `${message} 排障编号:${requestId}` : message;
}
return toUserSafeMessage(
mapApiErrorMessage(error.code, error.details, error.message),
message,
fallback,
);
}