refactor(data): consolidate data layer under services namespace
- Move src/data/{api,dto,schemas} directories to src/data/services/*
- Update all relative imports across the codebase to reference new paths
- Use CSS color tokens for splash button gradient in splash-button.module.css
- Add responsive sizes attribute to splash background image
- Add JSDoc documentation to splash-background component referencing original Dart implementation
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 日志拦截器
|
||||
*
|
||||
* 在开发模式下记录请求/响应/错误日志。
|
||||
* 原始 Dart: lib/core/net/interceptor/app_interceptor.dart 中的日志部分。
|
||||
*/
|
||||
import type { FetchHook } from "ofetch";
|
||||
|
||||
const TAG = "[API]";
|
||||
|
||||
function isDev(): boolean {
|
||||
return process.env.NODE_ENV !== "production";
|
||||
}
|
||||
|
||||
function getRequestUrl(request: Request | string): string {
|
||||
return typeof request === "string" ? request : request.url;
|
||||
}
|
||||
|
||||
function getRequestMethod(
|
||||
request: Request | string,
|
||||
options: { method?: string }
|
||||
): string {
|
||||
return request instanceof Request ? request.method : options.method ?? "GET";
|
||||
}
|
||||
|
||||
function formatBody(body: unknown): string {
|
||||
if (body === undefined || body === null) return "";
|
||||
try {
|
||||
if (body instanceof FormData) {
|
||||
const entries: string[] = [];
|
||||
body.forEach((value, key) => {
|
||||
if (value instanceof File) {
|
||||
entries.push(`${key}=File(${value.name})`);
|
||||
} else {
|
||||
entries.push(`${key}=${String(value)}`);
|
||||
}
|
||||
});
|
||||
return `FormData{${entries.join(", ")}}`;
|
||||
}
|
||||
return JSON.stringify(body);
|
||||
} catch {
|
||||
return String(body);
|
||||
}
|
||||
}
|
||||
|
||||
export const onRequestLogging: FetchHook = async (ctx) => {
|
||||
if (!isDev()) return;
|
||||
const method = getRequestMethod(ctx.request, ctx.options);
|
||||
const url = getRequestUrl(ctx.request);
|
||||
console.log(
|
||||
`${TAG} → ${method} ${url}`,
|
||||
ctx.options.body !== undefined ? formatBody(ctx.options.body) : ""
|
||||
);
|
||||
};
|
||||
|
||||
export const onResponseLogging: FetchHook = async (ctx) => {
|
||||
if (!isDev() || !ctx.response) return;
|
||||
const method = getRequestMethod(ctx.request, ctx.options);
|
||||
const url = getRequestUrl(ctx.request);
|
||||
console.log(
|
||||
`${TAG} ← ${ctx.response.status} ${method} ${url}`,
|
||||
formatBody(ctx.response._data)
|
||||
);
|
||||
};
|
||||
|
||||
export const onErrorLogging: FetchHook = async (ctx) => {
|
||||
if (!isDev()) return;
|
||||
const status = ctx.response?.status ?? "N/A";
|
||||
const method = getRequestMethod(ctx.request, ctx.options);
|
||||
const url = getRequestUrl(ctx.request);
|
||||
console.error(
|
||||
`${TAG} ✕ ${status} ${method} ${url}`,
|
||||
ctx.error?.message ?? "Unknown error"
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 兼容旧接口的 FetchHooks 形式(保留以备兼容)
|
||||
*/
|
||||
export const loggingInterceptor = {
|
||||
onRequest: onRequestLogging,
|
||||
onResponse: onResponseLogging,
|
||||
onResponseError: onErrorLogging,
|
||||
onRequestError: onErrorLogging,
|
||||
};
|
||||
Reference in New Issue
Block a user