1
This commit is contained in:
78
src/editor/shared/editorApiClient.ts
Normal file
78
src/editor/shared/editorApiClient.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { fetchJson, parseApiErrorMessage, saveJsonObject } from './jsonClient';
|
||||
|
||||
export const EDITOR_API_BASE_PATH = '/api/editor';
|
||||
export const ASSETS_API_BASE_PATH = '/api/assets';
|
||||
|
||||
export const EDITOR_JSON_RESOURCE_IDS = {
|
||||
itemOverrides: 'item-overrides',
|
||||
npcVisualOverrides: 'npc-visual-overrides',
|
||||
npcLayoutConfig: 'npc-layout-config',
|
||||
characterOverrides: 'character-overrides',
|
||||
monsterOverrides: 'monster-overrides',
|
||||
sceneOverrides: 'scene-overrides',
|
||||
sceneNpcOverrides: 'scene-npc-overrides',
|
||||
stateFunctionOverrides: 'state-function-overrides',
|
||||
} as const;
|
||||
|
||||
export type EditorJsonResourceId =
|
||||
(typeof EDITOR_JSON_RESOURCE_IDS)[keyof typeof EDITOR_JSON_RESOURCE_IDS];
|
||||
|
||||
export const ASSET_API_PATHS = {
|
||||
characterVisualGenerate: `${ASSETS_API_BASE_PATH}/character-visual/generate`,
|
||||
characterVisualPublish: `${ASSETS_API_BASE_PATH}/character-visual/publish`,
|
||||
characterVisualJobs: `${ASSETS_API_BASE_PATH}/character-visual/jobs`,
|
||||
characterAnimationGenerate: `${ASSETS_API_BASE_PATH}/character-animation/generate`,
|
||||
characterAnimationPublish: `${ASSETS_API_BASE_PATH}/character-animation/publish`,
|
||||
characterAnimationJobs: `${ASSETS_API_BASE_PATH}/character-animation/jobs`,
|
||||
characterAnimationImportVideo: `${ASSETS_API_BASE_PATH}/character-animation/import-video`,
|
||||
characterAnimationTemplates: `${ASSETS_API_BASE_PATH}/character-animation/templates`,
|
||||
qwenSpriteMaster: `${ASSETS_API_BASE_PATH}/qwen-sprite/master`,
|
||||
qwenSpriteSheet: `${ASSETS_API_BASE_PATH}/qwen-sprite/sheet`,
|
||||
qwenSpriteFrameRepair: `${ASSETS_API_BASE_PATH}/qwen-sprite/frame-repair`,
|
||||
qwenSpriteSave: `${ASSETS_API_BASE_PATH}/qwen-sprite/save`,
|
||||
} as const;
|
||||
|
||||
export const EDITOR_ITEM_CATALOG_API_PATH =
|
||||
`${EDITOR_API_BASE_PATH}/catalog/items`;
|
||||
|
||||
export function buildEditorJsonApiPath(resourceId: EditorJsonResourceId) {
|
||||
return `${EDITOR_API_BASE_PATH}/json/${resourceId}`;
|
||||
}
|
||||
|
||||
export function fetchEditorJsonResource<T>(
|
||||
resourceId: EditorJsonResourceId,
|
||||
fallbackMessage = '读取失败',
|
||||
) {
|
||||
return fetchJson<T>(buildEditorJsonApiPath(resourceId), fallbackMessage);
|
||||
}
|
||||
|
||||
export function saveEditorJsonResource(
|
||||
resourceId: EditorJsonResourceId,
|
||||
payload: Record<string, unknown>,
|
||||
fallbackMessage = '保存失败',
|
||||
) {
|
||||
return saveJsonObject(
|
||||
buildEditorJsonApiPath(resourceId),
|
||||
payload,
|
||||
fallbackMessage,
|
||||
);
|
||||
}
|
||||
|
||||
export async function postApiJson<T>(
|
||||
url: string,
|
||||
payload: Record<string, unknown>,
|
||||
fallbackMessage: string,
|
||||
) {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const responseText = await response.text();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
}
|
||||
|
||||
return responseText ? (JSON.parse(responseText) as T) : ({} as T);
|
||||
}
|
||||
@@ -1,43 +1,28 @@
|
||||
type ApiErrorPayload = {
|
||||
error?: {
|
||||
message?: string;
|
||||
};
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export function parseApiErrorMessage(responseText: string, fallbackMessage: string) {
|
||||
if (!responseText) {
|
||||
return fallbackMessage;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(responseText) as ApiErrorPayload;
|
||||
if (parsed.error?.message) {
|
||||
return parsed.error.message;
|
||||
}
|
||||
|
||||
if (typeof parsed.message === 'string' && parsed.message.trim()) {
|
||||
return parsed.message;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to the raw response text below.
|
||||
}
|
||||
|
||||
return responseText;
|
||||
}
|
||||
import {
|
||||
API_RESPONSE_ENVELOPE_HEADER,
|
||||
API_RESPONSE_ENVELOPE_VERSION,
|
||||
parseApiErrorMessage,
|
||||
unwrapApiResponse,
|
||||
} from '../../../packages/shared/src/http';
|
||||
|
||||
export async function fetchJson<T>(
|
||||
url: string,
|
||||
fallbackMessage = '请求失败',
|
||||
): Promise<T> {
|
||||
const response = await fetch(url);
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
[API_RESPONSE_ENVELOPE_HEADER]: API_RESPONSE_ENVELOPE_VERSION,
|
||||
},
|
||||
});
|
||||
const responseText = await response.text();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(parseApiErrorMessage(responseText, `${fallbackMessage}: ${response.status}`));
|
||||
}
|
||||
|
||||
return responseText ? (JSON.parse(responseText) as T) : ({} as T);
|
||||
return responseText
|
||||
? unwrapApiResponse<T>(JSON.parse(responseText) as T)
|
||||
: ({} as T);
|
||||
}
|
||||
|
||||
export async function saveJsonObject(
|
||||
@@ -47,7 +32,10 @@ export async function saveJsonObject(
|
||||
) {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
[API_RESPONSE_ENVELOPE_HEADER]: API_RESPONSE_ENVELOPE_VERSION,
|
||||
},
|
||||
body: JSON.stringify(payload, null, 2),
|
||||
});
|
||||
const responseText = await response.text();
|
||||
@@ -56,3 +44,5 @@ export async function saveJsonObject(
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
}
|
||||
}
|
||||
|
||||
export { parseApiErrorMessage };
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { saveJsonObject } from './jsonClient';
|
||||
import {
|
||||
saveEditorJsonResource,
|
||||
type EditorJsonResourceId,
|
||||
} from './editorApiClient';
|
||||
|
||||
type UseJsonSaveOptions = {
|
||||
endpoint: string;
|
||||
resourceId: EditorJsonResourceId;
|
||||
payload: Record<string, unknown>;
|
||||
validate?: () => string[];
|
||||
successMessage: string;
|
||||
@@ -11,7 +14,7 @@ type UseJsonSaveOptions = {
|
||||
};
|
||||
|
||||
export function useJsonSave({
|
||||
endpoint,
|
||||
resourceId,
|
||||
payload,
|
||||
validate,
|
||||
successMessage,
|
||||
@@ -32,7 +35,7 @@ export function useJsonSave({
|
||||
}
|
||||
|
||||
try {
|
||||
await saveJsonObject(endpoint, payload);
|
||||
await saveEditorJsonResource(resourceId, payload, errorMessage);
|
||||
setSaveMessage(successMessage);
|
||||
} catch (error) {
|
||||
setSaveMessage(error instanceof Error ? error.message : errorMessage);
|
||||
|
||||
Reference in New Issue
Block a user