fix: stabilize agent project startup
This commit is contained in:
parent
57a1e25921
commit
33f25f4b21
@ -25,6 +25,30 @@ export const revalidate = 0;
|
|||||||
const FAL_IMAGE_TASK_POLL_INTERVAL_MS = 2_000;
|
const FAL_IMAGE_TASK_POLL_INTERVAL_MS = 2_000;
|
||||||
const falTaskLastPolledAt = new Map<string, number>();
|
const falTaskLastPolledAt = new Map<string, number>();
|
||||||
const falTaskSyncInFlight = new Set<string>();
|
const falTaskSyncInFlight = new Set<string>();
|
||||||
|
const AGENT_MODE_SCOPED_CHAT_SUFFIX = "a93e17a60001";
|
||||||
|
|
||||||
|
function isAgentModeScopedChatId(chatId: string) {
|
||||||
|
const normalized = String(chatId || "")
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/-/g, "");
|
||||||
|
|
||||||
|
return (
|
||||||
|
/^[0-9a-f]{32}$/.test(normalized) &&
|
||||||
|
normalized.endsWith(AGENT_MODE_SCOPED_CHAT_SUFFIX)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEmptyMessagesResponse() {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ messages: [] },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Cache-Control": "no-store, max-age=0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function markFalTaskFailed(params: {
|
async function markFalTaskFailed(params: {
|
||||||
message: DBMessage;
|
message: DBMessage;
|
||||||
@ -212,7 +236,15 @@ export async function GET(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectedChat = await getChatById({ id: chatId });
|
const selectedChat = await getChatById({ id: chatId });
|
||||||
if (!selectedChat || selectedChat.userId !== session.user.id) {
|
if (!selectedChat) {
|
||||||
|
if (isAgentModeScopedChatId(chatId)) {
|
||||||
|
return createEmptyMessagesResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedChat.userId !== session.user.id) {
|
||||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -967,38 +967,6 @@ function normalizeImportedCanvasState(payload: unknown): {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasMeaningfulWorkflowState(
|
|
||||||
workflowState: AgentWorkflowPersistedState | null | undefined
|
|
||||||
) {
|
|
||||||
if (!workflowState) return false;
|
|
||||||
|
|
||||||
const inputs = workflowState.inputs;
|
|
||||||
const hasInputs = Boolean(
|
|
||||||
String(inputs?.primarySku || "").trim() ||
|
|
||||||
String(inputs?.secondarySku || "").trim() ||
|
|
||||||
String(inputs?.brand || "").trim() ||
|
|
||||||
String(inputs?.store || "").trim() ||
|
|
||||||
String(inputs?.officialSecondCategory || "").trim() ||
|
|
||||||
String(inputs?.officialThirdCategory || "").trim() ||
|
|
||||||
String(inputs?.thirdCategory || "").trim() ||
|
|
||||||
String(inputs?.fourthCategory || "").trim() ||
|
|
||||||
String(inputs?.fifthCategory || "").trim() ||
|
|
||||||
String(inputs?.priceBand || "").trim()
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasSelections = Object.values(workflowState.selections || {}).some(
|
|
||||||
(value) => Boolean(String(value || "").trim())
|
|
||||||
);
|
|
||||||
const hasBrandModel = Boolean(
|
|
||||||
String(workflowState.selectedBrandModel?.imageUrl || "").trim()
|
|
||||||
);
|
|
||||||
const hasPreset = Boolean(
|
|
||||||
String(workflowState.selectedAgentPresetId || "").trim()
|
|
||||||
);
|
|
||||||
|
|
||||||
return hasInputs || hasSelections || hasBrandModel || hasPreset;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FLOATING_PANEL_WIDTH = 460;
|
const FLOATING_PANEL_WIDTH = 460;
|
||||||
const FLOATING_PANEL_INSET = 16;
|
const FLOATING_PANEL_INSET = 16;
|
||||||
const DOCKED_PANEL_INSET = 0;
|
const DOCKED_PANEL_INSET = 0;
|
||||||
@ -1712,12 +1680,14 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
const hasClientPoint =
|
const hasClientPoint =
|
||||||
typeof anchorPoint?.clientX === "number" &&
|
typeof anchorPoint?.clientX === "number" &&
|
||||||
typeof anchorPoint?.clientY === "number";
|
typeof anchorPoint?.clientY === "number";
|
||||||
|
const clientX = hasClientPoint ? anchorPoint.clientX : null;
|
||||||
|
const clientY = hasClientPoint ? anchorPoint.clientY : null;
|
||||||
|
|
||||||
anchorX = hasClientPoint
|
anchorX = hasClientPoint
|
||||||
? Math.min(Math.max(anchorPoint.clientX - rect.left, 0), rect.width)
|
? Math.min(Math.max((clientX ?? 0) - rect.left, 0), rect.width)
|
||||||
: rect.width / 2;
|
: rect.width / 2;
|
||||||
anchorY = hasClientPoint
|
anchorY = hasClientPoint
|
||||||
? Math.min(Math.max(anchorPoint.clientY - rect.top, 0), rect.height)
|
? Math.min(Math.max((clientY ?? 0) - rect.top, 0), rect.height)
|
||||||
: rect.height / 2;
|
: rect.height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2895,14 +2865,6 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
workflowMaterials,
|
workflowMaterials,
|
||||||
sanitizedWorkflowSelections,
|
sanitizedWorkflowSelections,
|
||||||
]);
|
]);
|
||||||
const currentWorkflowPersistedStateRef = useRef<AgentWorkflowPersistedState>(
|
|
||||||
buildCurrentWorkflowPersistedState()
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
currentWorkflowPersistedStateRef.current =
|
|
||||||
buildCurrentWorkflowPersistedState();
|
|
||||||
}, [buildCurrentWorkflowPersistedState]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void checkCanvasAuthSession();
|
void checkCanvasAuthSession();
|
||||||
@ -2936,15 +2898,11 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
console.log("[Canvas] Loading project:", id);
|
console.log("[Canvas] Loading project:", id);
|
||||||
|
|
||||||
const loadProject = async () => {
|
const loadProject = async () => {
|
||||||
const preservedWorkflowState = currentWorkflowPersistedStateRef.current;
|
|
||||||
const shouldPreserveCurrentWorkflowState =
|
|
||||||
requestedAgentMode &&
|
|
||||||
lastLoadedCanvasIdRef.current === id &&
|
|
||||||
hasMeaningfulWorkflowState(preservedWorkflowState);
|
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setWorkflowHydrationSource("pending");
|
if (!requestedAgentMode) {
|
||||||
if (!shouldPreserveCurrentWorkflowState) {
|
setWorkflowHydrationSource("pending");
|
||||||
|
}
|
||||||
|
if (!requestedAgentMode) {
|
||||||
setWorkflowInputs({
|
setWorkflowInputs({
|
||||||
primarySku: "",
|
primarySku: "",
|
||||||
secondarySku: "",
|
secondarySku: "",
|
||||||
@ -2962,13 +2920,15 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
setSelectedBrandModel(null);
|
setSelectedBrandModel(null);
|
||||||
setSelectedAgentPresetId(null);
|
setSelectedAgentPresetId(null);
|
||||||
}
|
}
|
||||||
setAgentModeState(createEmptyAgentModeWorkspaceState());
|
if (!requestedAgentMode) {
|
||||||
setAgentWorkspaceState(createEmptyAgentGenerationProjectWorkspaceState());
|
setAgentModeState(createEmptyAgentModeWorkspaceState());
|
||||||
setAgentProjectTitle("未命名生图项目");
|
setAgentWorkspaceState(createEmptyAgentGenerationProjectWorkspaceState());
|
||||||
setAgentProjectThumbnail(null);
|
setAgentProjectTitle("未命名生图项目");
|
||||||
setAgentProjectResultCollections({});
|
setAgentProjectThumbnail(null);
|
||||||
setAgentProjectDeletedResultCollections({});
|
setAgentProjectResultCollections({});
|
||||||
setLoadedAgentProjectId(null);
|
setAgentProjectDeletedResultCollections({});
|
||||||
|
setLoadedAgentProjectId(null);
|
||||||
|
}
|
||||||
|
|
||||||
// 🆕 先清空当前画布状态,确保切换时不会显示旧数据
|
// 🆕 先清空当前画布状态,确保切换时不会显示旧数据
|
||||||
useCanvasStore.getState().clearCanvas();
|
useCanvasStore.getState().clearCanvas();
|
||||||
@ -3077,8 +3037,6 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
normalizeAgentModeWorkspaceState(persistedWorkflow.agentModeState)
|
normalizeAgentModeWorkspaceState(persistedWorkflow.agentModeState)
|
||||||
);
|
);
|
||||||
setWorkflowHydrationSource("project");
|
setWorkflowHydrationSource("project");
|
||||||
} else if (requestedAgentMode && shouldPreserveCurrentWorkflowState) {
|
|
||||||
setWorkflowHydrationSource("project");
|
|
||||||
} else {
|
} else {
|
||||||
setWorkflowHydrationSource("empty");
|
setWorkflowHydrationSource("empty");
|
||||||
}
|
}
|
||||||
@ -3995,32 +3953,42 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
}, [agentProjectId, agentProjectTitle, handleRenameAgentProject]);
|
}, [agentProjectId, agentProjectTitle, handleRenameAgentProject]);
|
||||||
|
|
||||||
const handleCreateAgentProject = useCallback(async () => {
|
const handleCreateAgentProject = useCallback(async () => {
|
||||||
if (agentProjectId) {
|
if (isAgentProjectSaving) {
|
||||||
await persistAgentProject("switch");
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await agentProjectService.createProject({
|
|
||||||
title: buildDefaultAgentProjectTitle(),
|
|
||||||
projectState: createEmptyAgentGenerationProjectPersistedState(),
|
|
||||||
});
|
|
||||||
if (!result.success || !result.data) {
|
|
||||||
if (isUnauthorizedApiError(result.error)) {
|
|
||||||
setIsAuthenticated(false);
|
|
||||||
openLoginDialog(
|
|
||||||
result.error || "当前登录状态已失效,请重新登录后继续操作。"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
toast.error(result.error || "创建生图项目失败");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success("已新建空白项目");
|
setIsAgentProjectSaving(true);
|
||||||
updateCanvasSearchParams({
|
try {
|
||||||
mode: "agent",
|
if (agentProjectId) {
|
||||||
agentProjectId: result.data.id,
|
await persistAgentProject("switch");
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const result = await agentProjectService.createProject({
|
||||||
|
title: buildDefaultAgentProjectTitle(),
|
||||||
|
projectState: createEmptyAgentGenerationProjectPersistedState(),
|
||||||
|
});
|
||||||
|
if (!result.success || !result.data) {
|
||||||
|
if (isUnauthorizedApiError(result.error)) {
|
||||||
|
setIsAuthenticated(false);
|
||||||
|
openLoginDialog(
|
||||||
|
result.error || "当前登录状态已失效,请重新登录后继续操作。"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
toast.error(result.error || "创建生图项目失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success("已新建空白项目");
|
||||||
|
updateCanvasSearchParams({
|
||||||
|
mode: "agent",
|
||||||
|
agentProjectId: result.data.id,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsAgentProjectSaving(false);
|
||||||
|
}
|
||||||
}, [
|
}, [
|
||||||
agentProjectId,
|
agentProjectId,
|
||||||
|
isAgentProjectSaving,
|
||||||
openLoginDialog,
|
openLoginDialog,
|
||||||
persistAgentProject,
|
persistAgentProject,
|
||||||
updateCanvasSearchParams,
|
updateCanvasSearchParams,
|
||||||
@ -9034,14 +9002,21 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
className="rounded-[28px] border border-emerald-400/20 bg-emerald-500/[0.10] p-5 text-left transition-colors hover:border-emerald-300/35 hover:bg-emerald-500/[0.16]"
|
className="rounded-[28px] border border-emerald-400/20 bg-emerald-500/[0.10] p-5 text-left transition-colors hover:border-emerald-300/35 hover:bg-emerald-500/[0.16]"
|
||||||
|
disabled={isAgentProjectSaving}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
void handleCreateAgentProject();
|
void handleCreateAgentProject();
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 text-emerald-100">
|
<div className="flex items-center gap-3 text-emerald-100">
|
||||||
<Plus className="h-5 w-5" />
|
{isAgentProjectSaving ? (
|
||||||
<span className="font-medium text-sm">新建空白项目</span>
|
<Loader2 className="h-5 w-5 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Plus className="h-5 w-5" />
|
||||||
|
)}
|
||||||
|
<span className="font-medium text-sm">
|
||||||
|
{isAgentProjectSaving ? "正在新建项目" : "新建空白项目"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 text-emerald-50/70 text-sm leading-6">
|
<div className="mt-3 text-emerald-50/70 text-sm leading-6">
|
||||||
仅在你要开始一条全新的场景生图流程时再创建,避免项目列表里自动冒出一堆无效项目。
|
仅在你要开始一条全新的场景生图流程时再创建,避免项目列表里自动冒出一堆无效项目。
|
||||||
|
|||||||
@ -1929,6 +1929,13 @@ export function sanitizeAgentWorkflowSelections(params: {
|
|||||||
config?: AgentWorkflowUiConfig | null;
|
config?: AgentWorkflowUiConfig | null;
|
||||||
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
||||||
}) {
|
}) {
|
||||||
|
const hasSelection = Object.values(params.selections || {}).some((value) =>
|
||||||
|
Boolean(String(value || "").trim())
|
||||||
|
);
|
||||||
|
if (!hasSelection) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const config = params.config || defaultAgentWorkflowUiConfig;
|
const config = params.config || defaultAgentWorkflowUiConfig;
|
||||||
const enabledSteps = flattenAgentWorkflowSteps(
|
const enabledSteps = flattenAgentWorkflowSteps(
|
||||||
getEnabledAgentWorkflowStepTree(Array.isArray(config.steps) ? config.steps : [])
|
getEnabledAgentWorkflowStepTree(Array.isArray(config.steps) ? config.steps : [])
|
||||||
@ -2089,6 +2096,13 @@ export function getAgentWorkflowBlockedOptionKeysForSelections(params: {
|
|||||||
config?: AgentWorkflowUiConfig | null;
|
config?: AgentWorkflowUiConfig | null;
|
||||||
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
||||||
}) {
|
}) {
|
||||||
|
const hasSelection = Object.values(params.selections || {}).some((value) =>
|
||||||
|
Boolean(String(value || "").trim())
|
||||||
|
);
|
||||||
|
if (!hasSelection) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const config = params.config || defaultAgentWorkflowUiConfig;
|
const config = params.config || defaultAgentWorkflowUiConfig;
|
||||||
const constraintSettings = getAgentWorkflowConstraintSettings(config);
|
const constraintSettings = getAgentWorkflowConstraintSettings(config);
|
||||||
const visibleSteps = flattenVisibleAgentWorkflowSteps(
|
const visibleSteps = flattenVisibleAgentWorkflowSteps(
|
||||||
|
|||||||
@ -9,22 +9,65 @@ interface ApiResponse<T = unknown> {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AGENT_PROJECT_REQUEST_TIMEOUT_MS = 15_000;
|
||||||
|
|
||||||
|
async function fetchAgentProjectApi<T>(
|
||||||
|
input: RequestInfo | URL,
|
||||||
|
init?: RequestInit
|
||||||
|
): Promise<ApiResponse<T>> {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = globalThis.setTimeout(
|
||||||
|
() => controller.abort(),
|
||||||
|
AGENT_PROJECT_REQUEST_TIMEOUT_MS
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(input, {
|
||||||
|
...init,
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
return await response.json();
|
||||||
|
} finally {
|
||||||
|
globalThis.clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAgentProjectRequestErrorMessage(error: unknown, fallback: string) {
|
||||||
|
if (error instanceof DOMException && error.name === "AbortError") {
|
||||||
|
return `${fallback}:请求超时`;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
export const agentProjectService = {
|
export const agentProjectService = {
|
||||||
async getProjects(): Promise<ApiResponse<AgentGenerationProject[]>> {
|
async getProjects(): Promise<ApiResponse<AgentGenerationProject[]>> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/agent-projects", { cache: "no-store" });
|
return await fetchAgentProjectApi<AgentGenerationProject[]>(
|
||||||
return await response.json();
|
"/api/agent-projects",
|
||||||
} catch {
|
{ cache: "no-store" }
|
||||||
return { success: false, error: "获取生图项目列表失败" };
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: getAgentProjectRequestErrorMessage(
|
||||||
|
error,
|
||||||
|
"获取生图项目列表失败"
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async getProject(id: string): Promise<ApiResponse<AgentGenerationProject>> {
|
async getProject(id: string): Promise<ApiResponse<AgentGenerationProject>> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/agent-projects/${id}`, { cache: "no-store" });
|
return await fetchAgentProjectApi<AgentGenerationProject>(
|
||||||
return await response.json();
|
`/api/agent-projects/${id}`,
|
||||||
} catch {
|
{ cache: "no-store" }
|
||||||
return { success: false, error: "获取生图项目失败" };
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: getAgentProjectRequestErrorMessage(error, "获取生图项目失败"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -35,14 +78,19 @@ export const agentProjectService = {
|
|||||||
projectState?: AgentGenerationProjectPersistedState;
|
projectState?: AgentGenerationProjectPersistedState;
|
||||||
}): Promise<ApiResponse<AgentGenerationProject>> {
|
}): Promise<ApiResponse<AgentGenerationProject>> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/agent-projects", {
|
return await fetchAgentProjectApi<AgentGenerationProject>(
|
||||||
method: "POST",
|
"/api/agent-projects",
|
||||||
headers: { "Content-Type": "application/json" },
|
{
|
||||||
body: JSON.stringify(payload),
|
method: "POST",
|
||||||
});
|
headers: { "Content-Type": "application/json" },
|
||||||
return await response.json();
|
body: JSON.stringify(payload),
|
||||||
} catch {
|
}
|
||||||
return { success: false, error: "创建生图项目失败" };
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: getAgentProjectRequestErrorMessage(error, "创建生图项目失败"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -56,25 +104,32 @@ export const agentProjectService = {
|
|||||||
}
|
}
|
||||||
): Promise<ApiResponse<AgentGenerationProject>> {
|
): Promise<ApiResponse<AgentGenerationProject>> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/agent-projects/${id}`, {
|
return await fetchAgentProjectApi<AgentGenerationProject>(
|
||||||
method: "PUT",
|
`/api/agent-projects/${id}`,
|
||||||
headers: { "Content-Type": "application/json" },
|
{
|
||||||
body: JSON.stringify(payload),
|
method: "PUT",
|
||||||
});
|
headers: { "Content-Type": "application/json" },
|
||||||
return await response.json();
|
body: JSON.stringify(payload),
|
||||||
} catch {
|
}
|
||||||
return { success: false, error: "保存生图项目失败" };
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: getAgentProjectRequestErrorMessage(error, "保存生图项目失败"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteProject(id: string): Promise<ApiResponse> {
|
async deleteProject(id: string): Promise<ApiResponse> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/agent-projects/${id}`, {
|
return await fetchAgentProjectApi(`/api/agent-projects/${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
return await response.json();
|
} catch (error) {
|
||||||
} catch {
|
return {
|
||||||
return { success: false, error: "删除生图项目失败" };
|
success: false,
|
||||||
|
error: getAgentProjectRequestErrorMessage(error, "删除生图项目失败"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user