Files
omniai-ds-code-package/src/api/assetClient.ts
T

130 lines
4.1 KiB
TypeScript
Raw Normal View History

2026-06-10 14:06:16 +08:00
import type { WebAssetItem } from "../types";
import { isRecord, serverRequest } from "./serverConnection";
export interface ServerAssetItem extends WebAssetItem {
id: string;
url?: string | null;
ossKey?: string | null;
tags: string[];
sourceTaskId?: string | null;
sourceProjectId?: string | null;
metadata?: Record<string, unknown>;
createdAt?: string;
}
export interface CreateAssetInput {
type: WebAssetItem["type"] | "image" | "asset" | "other";
name: string;
description?: string;
url?: string;
imageUrl?: string;
ossKey?: string;
tags?: string[];
status?: WebAssetItem["status"] | "pending" | "failed";
sourceTaskId?: string;
sourceProjectId?: string;
metadata?: Record<string, unknown>;
}
export interface DeleteAssetOptions {
cleanupUserData?: boolean;
}
function toStringValue(value: unknown, fallback = ""): string {
if (typeof value === "string") return value.trim() || fallback;
if (typeof value === "number" && Number.isFinite(value)) return String(value);
return fallback;
}
function normalizeAssetType(value: unknown): WebAssetItem["type"] {
const type = toStringValue(value);
if (
type === "character" ||
type === "scene" ||
type === "prop" ||
type === "video" ||
type === "image" ||
type === "asset" ||
type === "other"
) {
return type;
}
return "other";
}
function normalizeAssetStatus(value: unknown): WebAssetItem["status"] {
const status = toStringValue(value);
if (
status === "ready" ||
status === "draft" ||
status === "reviewing" ||
status === "pending" ||
status === "failed"
) {
return status;
}
return "ready";
}
function normalizeTags(value: unknown): string[] {
if (!Array.isArray(value)) return [];
const tags: string[] = [];
for (const item of value) {
const tag = toStringValue(item);
if (tag) tags.push(tag);
}
return tags;
}
function normalizeAsset(raw: unknown): ServerAssetItem {
const item = isRecord(raw) ? raw : {};
const url = toStringValue(item.url ?? item.imageUrl) || null;
return {
id: toStringValue(item.id, `asset-${Date.now()}`),
type: normalizeAssetType(item.type),
name: toStringValue(item.name, "未命名素材"),
description: toStringValue(item.description, "从服务器资产库同步的素材。"),
imageUrl: url || "",
url,
ossKey: toStringValue(item.ossKey ?? item.oss_key) || null,
tags: normalizeTags(item.tags),
status: normalizeAssetStatus(item.status),
sourceTaskId: toStringValue(item.sourceTaskId ?? item.source_task_id) || null,
sourceProjectId: toStringValue(item.sourceProjectId ?? item.source_project_id) || null,
metadata: isRecord(item.metadata) ? item.metadata : {},
createdAt: toStringValue(item.createdAt ?? item.created_at),
updatedAt: toStringValue(item.updatedAt ?? item.updated_at, "刚刚"),
};
}
function extractAssets(payload: unknown): ServerAssetItem[] {
if (Array.isArray(payload)) return payload.map(normalizeAsset);
if (!isRecord(payload)) return [];
const rows = payload.assets ?? payload.items;
return Array.isArray(rows) ? rows.map(normalizeAsset) : [];
}
export const assetClient = {
async list(params?: { type?: string; q?: string; status?: string }): Promise<ServerAssetItem[]> {
const search = new URLSearchParams();
if (params?.type && params.type !== "all") search.set("type", params.type);
if (params?.q) search.set("q", params.q);
if (params?.status) search.set("status", params.status);
const query = search.toString();
return extractAssets(await serverRequest<unknown>(`assets${query ? `?${query}` : ""}`));
},
async create(input: CreateAssetInput): Promise<ServerAssetItem> {
const payload = await serverRequest<{ asset: unknown }>("assets", {
method: "POST",
body: input,
});
return normalizeAsset(payload.asset ?? payload);
},
async delete(id: string, options?: DeleteAssetOptions): Promise<void> {
const path = options?.cleanupUserData ? `assets/${encodeURIComponent(id)}?cleanupUserData=1` : `assets/${encodeURIComponent(id)}`;
await serverRequest(path, { method: "DELETE" });
},
};