Files
flvx/vite-frontend/src/api/error-message.ts
T
sagitchu 7d07fe08b7 Restore removed features from PR #322
- Add back BatchOperationFailure type and batch failure handling functions
- Add back dismissNodeExpiryReminder API endpoint
- Add back update channel selection UI in config page
- Keep simplified version display in version-footer.tsx
2026-03-15 21:07:08 +08:00

136 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { BatchOperationFailure } from "@/api/types";
import axios from "axios";
interface ErrorPayload {
msg?: string;
message?: string;
}
interface BatchFailurePayload {
id?: number;
name?: string;
reason?: string;
msg?: string;
message?: string;
}
interface BatchResultPayload {
failures?: unknown[];
}
const MAX_BATCH_FAILURES_IN_TOAST = 3;
export const isUnauthorizedError = (error: unknown): boolean => {
return axios.isAxiosError(error) && error.response?.status === 401;
};
export const extractApiErrorMessage = (
error: unknown,
fallback = "网络请求失败",
): string => {
if (axios.isAxiosError(error)) {
const payload = error.response?.data as ErrorPayload | undefined;
return payload?.msg || payload?.message || error.message || fallback;
}
if (error instanceof Error && error.message) {
return error.message;
}
return fallback;
};
const normalizeBatchFailure = (
failure: unknown,
): BatchOperationFailure | null => {
if (typeof failure === "string") {
const reason = failure.trim();
return reason ? { reason } : null;
}
const payload = (failure ?? {}) as BatchFailurePayload;
const id =
typeof payload.id === "number" && Number.isFinite(payload.id)
? payload.id
: undefined;
const name = typeof payload.name === "string" ? payload.name.trim() : "";
const reasonSource = [payload.reason, payload.msg, payload.message].find(
(item) => typeof item === "string" && item.trim() !== "",
);
const reason = typeof reasonSource === "string" ? reasonSource.trim() : "";
if (!name && !reason && id === undefined) {
return null;
}
return {
...(id !== undefined ? { id } : {}),
...(name ? { name } : {}),
...(reason ? { reason } : {}),
};
};
const normalizeBatchFailureReason = (
failure: BatchOperationFailure,
): string => {
const name = typeof failure.name === "string" ? failure.name.trim() : "";
const reason =
typeof failure.reason === "string" ? failure.reason.trim() : "";
if (name && reason) {
return `${name}: ${reason}`;
}
if (reason) {
if (typeof failure.id === "number" && Number.isFinite(failure.id)) {
return `ID ${failure.id}: ${reason}`;
}
return reason;
}
if (name) {
return name;
}
if (typeof failure.id === "number" && Number.isFinite(failure.id)) {
return `ID ${failure.id} 下发失败`;
}
return "";
};
export const extractBatchFailures = (
result: unknown,
): BatchOperationFailure[] => {
const payload = (result ?? {}) as BatchResultPayload;
return Array.isArray(payload.failures)
? payload.failures
.map((item) => normalizeBatchFailure(item))
.filter((item): item is BatchOperationFailure => item !== null)
: [];
};
export const buildBatchFailureMessage = (
result: unknown,
fallbackSummary: string,
): string => {
const failures = extractBatchFailures(result)
.map((item) => normalizeBatchFailureReason(item))
.filter((item) => item !== "");
if (failures.length === 0) {
return fallbackSummary;
}
const visibleFailures = failures.slice(0, MAX_BATCH_FAILURES_IN_TOAST);
const hiddenCount = failures.length - visibleFailures.length;
const hiddenSuffix = hiddenCount > 0 ? ` 等 ${failures.length} 项` : "";
return `${fallbackSummary}:${visibleFailures.join(";")}${hiddenSuffix}`;
};