refactor(canvas): 替换自定义ID生成函数为nanoid并优化配置逻辑

- 移除自定义createId函数,统一使用nanoid库生成唯一标识符
- 将useEffectiveAiConfig Hook替换为resolveEffectiveConfig工具函数
- 直接从config store获取publicSettings避免额外的Hook依赖
- 更新所有组件中的ID生成调用以使用nanoid
- 简化buildApiUrl函数中的基础URL规范化逻辑
This commit is contained in:
HouYunFei
2026-05-21 14:43:09 +08:00
parent 22d34a0c99
commit ef9e87fb29
12 changed files with 78 additions and 67 deletions
+26 -17
View File
@@ -1,5 +1,6 @@
"use client";
import { useMemo } from "react";
import { create } from "zustand";
import { persist } from "zustand/middleware";
@@ -44,11 +45,31 @@ type ConfigStore = {
shouldPromptContinue: boolean;
updateConfig: <K extends keyof AiConfig>(key: K, value: AiConfig[K]) => void;
loadPublicSettings: () => Promise<void>;
isAiConfigReady: (config: AiConfig, model: string) => boolean;
openConfigDialog: (shouldPromptContinue?: boolean) => void;
setConfigDialogOpen: (isOpen: boolean) => void;
clearPromptContinue: () => void;
};
function resolveEffectiveConfig(config: AiConfig, modelChannel: AdminPublicSettings["modelChannel"] | null) {
const channelMode = modelChannel?.allowCustomChannel ? config.channelMode : "remote";
if (channelMode === "local" || !modelChannel) return { ...config, channelMode };
const models = modelChannel.availableModels;
return {
...config,
channelMode,
models,
model: models.includes(config.model) ? config.model : modelChannel.defaultModel,
imageModel: models.includes(config.imageModel) ? config.imageModel : modelChannel.defaultImageModel || modelChannel.defaultModel,
textModel: models.includes(config.textModel) ? config.textModel : modelChannel.defaultTextModel || modelChannel.defaultModel,
systemPrompt: modelChannel.systemPrompt,
};
}
function isAiConfigReady(config: AiConfig, model: string) {
return Boolean(model.trim()) && (config.channelMode === "remote" || Boolean(config.baseUrl.trim() && config.apiKey.trim()));
}
export const useConfigStore = create<ConfigStore>()(
persist(
(set, get) => ({
@@ -73,6 +94,7 @@ export const useConfigStore = create<ConfigStore>()(
set({ isPublicSettingsLoading: false });
}
},
isAiConfigReady: (config, model) => isAiConfigReady(config, model),
openConfigDialog: (shouldPromptContinue = false) => set({ isConfigOpen: true, shouldPromptContinue }),
setConfigDialogOpen: (isConfigOpen) => set({ isConfigOpen }),
clearPromptContinue: () => set({ shouldPromptContinue: false }),
@@ -88,19 +110,10 @@ export const useConfigStore = create<ConfigStore>()(
),
);
export function resolveEffectiveConfig(config: AiConfig, modelChannel: AdminPublicSettings["modelChannel"] | null) {
const channelMode = modelChannel?.allowCustomChannel ? config.channelMode : "remote";
if (channelMode === "local" || !modelChannel) return { ...config, channelMode };
const models = modelChannel.availableModels;
return {
...config,
channelMode,
models,
model: models.includes(config.model) ? config.model : modelChannel.defaultModel,
imageModel: models.includes(config.imageModel) ? config.imageModel : modelChannel.defaultImageModel || modelChannel.defaultModel,
textModel: models.includes(config.textModel) ? config.textModel : modelChannel.defaultTextModel || modelChannel.defaultModel,
systemPrompt: modelChannel.systemPrompt,
};
export function useEffectiveConfig() {
const config = useConfigStore((state) => state.config);
const modelChannel = useConfigStore((state) => state.publicSettings?.modelChannel || null);
return useMemo(() => resolveEffectiveConfig(config, modelChannel), [config, modelChannel]);
}
export function buildApiUrl(baseUrl: string, path: string) {
@@ -108,7 +121,3 @@ export function buildApiUrl(baseUrl: string, path: string) {
const apiBaseUrl = normalizedBaseUrl.endsWith("/v1") ? normalizedBaseUrl : `${normalizedBaseUrl}/v1`;
return `${apiBaseUrl}${path}`;
}
export function isAiConfigReady(config: AiConfig, model: string) {
return Boolean(model.trim()) && (config.channelMode === "remote" || Boolean(config.baseUrl.trim() && config.apiKey.trim()));
}