refactor(*): 代码质量治理 - 收敛接口客户端、模型职责与异步计费巡检

This commit is contained in:
ddCat
2026-08-06 16:36:51 +08:00
parent 9ca9dd9df6
commit b3199c5e7e
42 changed files with 3051 additions and 2271 deletions

View File

@@ -1,6 +1,4 @@
import axios from "axios";
import type { BackendEnvelope } from "@/services/api/task-center";
import { apiClient, request } from "@/services/api/request";
export type AnnouncementLevel = "info" | "success" | "warning" | "critical";
export type AnnouncementStatus = "active" | "closed";
@@ -30,13 +28,7 @@ export type AdminAnnouncementListParams = {
limit?: number;
};
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
}
const api = apiClient;
export function getAnnouncementFeed() {
return request<AnnouncementFeed>(api.get("/announcements"));

View File

@@ -1,12 +1,11 @@
import axios from "axios";
import type { ModelChannel } from "@/stores/use-config-store";
import type { CreditLedgerEntry } from "@/services/api/wallet";
import type { GenerationTask, TaskStatus } from "@/services/api/task-center";
import type { CanvasDrawingEngineSetting } from "@/lib/canvas/canvas-drawing-engine";
import type { FeatureAvailability } from "@/stores/use-user-store";
import { apiClient, request } from "@/services/api/request";
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
const api = apiClient;
export type LocalUser = {
id: string;
@@ -325,18 +324,6 @@ export type RuntimePolicySetting = {
updatedAt?: string;
};
type BackendEnvelope<T> = { code: number; data: T; msg: string };
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) throw new Error(error.response?.data?.msg || error.message || "请求失败");
throw error;
}
}
export function getAuthSettings() {
return request<{ firstUser: boolean; registrationEnabled: boolean; linuxdoEnabled: boolean; emailEnabled: boolean; emailCodeRequired: boolean }>(api.get("/auth/settings"));

View File

@@ -1,9 +1,7 @@
import axios from "axios";
import type { BackendEnvelope } from "@/services/api/task-center";
import type { CanvasProject } from "@/stores/canvas/use-canvas-store";
import { apiClient, request } from "@/services/api/request";
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
const api = apiClient;
export type CanvasShareStatus = {
enabled: boolean;
@@ -17,12 +15,6 @@ export type PublicCanvasShare = {
expiresAt?: string;
};
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
}
export function getCanvasShare(projectId: string) {
return request<{ share: CanvasShareStatus }>(api.get(`/canvas-projects/${encodeURIComponent(projectId)}/share`));
}

View File

@@ -1,8 +1,6 @@
import axios from "axios";
import { apiClient, request } from "@/services/api/request";
import type { BackendEnvelope } from "@/services/api/task-center";
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
const api = apiClient;
export type Project = {
id: string;
@@ -167,16 +165,6 @@ export type ProjectDetail = {
assetCandidates: ProjectAssetCandidate[];
};
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) throw new Error(error.response?.data?.msg || error.message || "请求失败");
throw error;
}
}
export function listProjects() {
return request<{ projects: ProjectSummary[] }>(api.get("/projects"));

View File

@@ -1,5 +1,30 @@
import axios from "axios";
export type ApiParams = Record<string, string | string[] | number | number[] | undefined>;
export type BackendEnvelope<T> = {
code: number;
data: T;
msg: string;
};
// 所有后端 JSON 请求共用同一实例,避免认证、Base URL 和错误语义在模块间漂移。
export const apiBaseURL = import.meta.env.VITE_CANVAS_BACKEND_URL || "/api";
export const apiClient = axios.create({ baseURL: apiBaseURL, withCredentials: true });
export async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) {
throw new Error(error.response?.data?.msg || error.message || "请求失败");
}
throw error;
}
}
export function compactApiParams(params: ApiParams) {
return Object.fromEntries(Object.entries(params).filter(([, value]) => value !== "" && value !== undefined && (!Array.isArray(value) || value.length > 0))) as ApiParams;
}

View File

@@ -1,7 +1,6 @@
import axios from "axios";
import { getActiveUserScope } from "@/lib/user-scope";
import type { BackendEnvelope } from "@/services/api/task-center";
import axios from "axios";
import { apiBaseURL, apiClient, request, type BackendEnvelope } from "@/services/api/request";
export type RemoteResource = {
id: string;
@@ -41,18 +40,11 @@ export type UserOSSSettingInput = Pick<UserOSSSetting, "enabled" | "provider" |
accessKeySecret?: string;
};
const apiBaseURL = import.meta.env.VITE_CANVAS_BACKEND_URL || "/api";
const api = axios.create({ baseURL: apiBaseURL, withCredentials: true });
const api = apiClient;
const resourceCache = new Map<string, RemoteResource>();
const resourceRequests = new Map<string, Promise<RemoteResource>>();
const missingResourceIds = new Set<string>();
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
}
export function resourceStorageKey(id: string) {
return `resource:${id}`;
}

View File

@@ -1,9 +1,7 @@
import axios from "axios";
import { compactApiParams, serializeApiParams, type ApiParams } from "@/services/api/request";
import type { BackendEnvelope } from "@/services/api/task-center";
import { apiClient, request } from "@/services/api/request";
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
const api = apiClient;
export type SkillSort = "popular" | "new" | "updated";
export type SkillScope = "public" | "mine" | "created" | "favorites";
@@ -73,16 +71,6 @@ export type SkillMutationInput = {
extra_info: string;
};
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) throw new Error(error.response?.data?.msg || error.message || "请求失败");
throw error;
}
}
export function listSkills(input: ListSkillsInput = {}) {
const params = serializeApiParams(compactApiParams(input as ApiParams));

View File

@@ -1,18 +1,13 @@
import axios from "axios";
import { generationErrorMessage } from "@/lib/generation-error";
import { apiClient, request, type BackendEnvelope } from "@/services/api/request";
export type { BackendEnvelope } from "@/services/api/request";
export type TaskStatus = "queued" | "running" | "succeeded" | "failed" | "cancelled";
export type TaskBillingStatus = "reserved" | "running" | "settled" | "refunded" | "uncertain";
export type ProviderCancelStatus = "requested" | "confirmed" | "uncertain";
export type AgentSessionStatus = "active" | "completed" | "failed";
export type BackendEnvelope<T> = {
code: number;
data: T;
msg: string;
};
export type GenerationTask = {
id: string;
sessionId?: string;
@@ -116,7 +111,7 @@ export type SessionFile = {
sessionId: string;
fileName: string;
mimeType: string;
size: number;
size: number;
createdAt: string;
};
@@ -157,30 +152,17 @@ export type CreateTaskInput = {
input?: Record<string, unknown>;
};
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) {
throw new Error(error.response?.data?.msg || error.message || "请求失败");
}
throw error;
}
}
const api = apiClient;
export function createAgentSession(input: CreateSessionInput) {
return request<AgentSessionDetail>(api.post("/create_session", input)).then((detail) => {
return request<AgentSessionDetail>(api.post("/sessions", input)).then((detail) => {
detail.tasks.forEach((task) => notifyCanvasTaskCreated(task));
return detail;
});
}
export function queryAgentSession(id: string) {
return request<AgentSessionDetail>(api.get(`/query_session/${encodeURIComponent(id)}`));
return request<AgentSessionDetail>(api.get(`/sessions/${encodeURIComponent(id)}`));
}
export function agentSessionFailureMessage(detail: AgentSessionDetail, fallback = "后端影视 Agent 会话失败") {
@@ -196,14 +178,14 @@ export function agentSessionFailureMessage(detail: AgentSessionDetail, fallback
}
export function downloadSessionResults(id: string) {
return request<TaskResult[]>(api.get(`/download_results/${encodeURIComponent(id)}`));
return request<TaskResult[]>(api.get(`/sessions/${encodeURIComponent(id)}/results`));
}
export function uploadAgentFile(sessionId: string, file: File) {
const formData = new FormData();
formData.append("sessionId", sessionId);
formData.append("file", file);
return request<SessionFile>(api.post("/upload_file", formData));
return request<SessionFile>(api.post("/files", formData));
}
export function createGenerationTask(input: CreateTaskInput) {

View File

@@ -1,10 +1,8 @@
import axios from "axios";
import type { BackendEnvelope } from "@/services/api/task-center";
import type { Asset } from "@/stores/use-asset-store";
import type { CanvasProject } from "@/stores/canvas/use-canvas-store";
import { apiClient, request } from "@/services/api/request";
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
const api = apiClient;
export type RemoteUserDataSummary = {
id: string;
@@ -14,16 +12,6 @@ export type RemoteUserDataSummary = {
updatedAt: string;
};
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) throw new Error(error.response?.data?.msg || error.message || "请求失败");
throw error;
}
}
export function listRemoteAssets() {
return request<{ assets: RemoteUserDataSummary[] }>(api.get("/assets"));

View File

@@ -1,19 +1,6 @@
import axios from "axios";
import { apiClient, request } from "@/services/api/request";
const api = axios.create({ baseURL: import.meta.env.VITE_CANVAS_BACKEND_URL || "/api", withCredentials: true });
type BackendEnvelope<T> = { code: number; data: T; msg: string };
async function request<T>(promise: Promise<{ data: BackendEnvelope<T> }>) {
try {
const response = await promise;
if (response.data.code !== 0) throw new Error(response.data.msg || "请求失败");
return response.data.data;
} catch (error) {
if (axios.isAxiosError<BackendEnvelope<unknown>>(error)) throw new Error(error.response?.data?.msg || error.message || "请求失败");
throw error;
}
}
const api = apiClient;
export type CreditAccount = {
userId: string;