diff --git a/easyflow-ui-admin/app/src/components/cardPage/CardPage.vue b/easyflow-ui-admin/app/src/components/cardPage/CardPage.vue
index ea276e9..b16053d 100644
--- a/easyflow-ui-admin/app/src/components/cardPage/CardPage.vue
+++ b/easyflow-ui-admin/app/src/components/cardPage/CardPage.vue
@@ -16,6 +16,7 @@ import {
} from 'element-plus';
import { hasPermission } from '#/api/common/hasPermission.ts';
+import { getEmptyStateImageUrl } from '#/utils/assets';
const props = defineProps({
titleKey: {
@@ -137,9 +138,7 @@ const filteredActions = computed(() => {
-
+
diff --git a/easyflow-ui-admin/app/src/components/categoryPanel/CategoryCrudPanel.vue b/easyflow-ui-admin/app/src/components/categoryPanel/CategoryCrudPanel.vue
index c9c6ded..39465c9 100644
--- a/easyflow-ui-admin/app/src/components/categoryPanel/CategoryCrudPanel.vue
+++ b/easyflow-ui-admin/app/src/components/categoryPanel/CategoryCrudPanel.vue
@@ -20,6 +20,8 @@ import {
ElMessageBox,
} from 'element-plus';
+import { getEmptyStateImageUrl } from '#/utils/assets';
+
const props = defineProps({
title: {
type: String,
@@ -245,7 +247,7 @@ const handleDeleteClick = (event: any, item: any) => {
diff --git a/easyflow-ui-admin/app/src/components/json/ShowJson.vue b/easyflow-ui-admin/app/src/components/json/ShowJson.vue
index 43d7b71..3176932 100644
--- a/easyflow-ui-admin/app/src/components/json/ShowJson.vue
+++ b/easyflow-ui-admin/app/src/components/json/ShowJson.vue
@@ -7,6 +7,7 @@ import { ElEmpty } from 'element-plus';
import { JsonViewer } from 'vue3-json-viewer';
import 'vue3-json-viewer/dist/vue3-json-viewer.css';
+import { getEmptyStateImageUrl } from '#/utils/assets';
defineProps({
value: {
@@ -26,10 +27,7 @@ watch(
-
+
diff --git a/easyflow-ui-admin/app/src/components/page/PageData.vue b/easyflow-ui-admin/app/src/components/page/PageData.vue
index 24562b3..e52ba43 100644
--- a/easyflow-ui-admin/app/src/components/page/PageData.vue
+++ b/easyflow-ui-admin/app/src/components/page/PageData.vue
@@ -6,6 +6,7 @@ import { preferences } from '@easyflow/preferences';
import { ElEmpty, ElPagination } from 'element-plus';
import { api } from '#/api/request';
+import { getEmptyStateImageUrl } from '#/utils/assets';
interface PageDataProps {
pageUrl: string;
@@ -126,9 +127,7 @@ onMounted(() => {
-
+
diff --git a/easyflow-ui-admin/app/src/components/page/PageSide.vue b/easyflow-ui-admin/app/src/components/page/PageSide.vue
index b7d97c0..bcd9da1 100644
--- a/easyflow-ui-admin/app/src/components/page/PageSide.vue
+++ b/easyflow-ui-admin/app/src/components/page/PageSide.vue
@@ -16,6 +16,8 @@ import {
ElIcon,
} from 'element-plus';
+import { getEmptyStateImageUrl } from '#/utils/assets';
+
interface Props {
title?: string;
menus: T[];
@@ -182,7 +184,7 @@ const isSvgString = (icon: any) => {
diff --git a/easyflow-ui-admin/app/src/main.ts b/easyflow-ui-admin/app/src/main.ts
index 8256c7e..7fe15ab 100644
--- a/easyflow-ui-admin/app/src/main.ts
+++ b/easyflow-ui-admin/app/src/main.ts
@@ -1,7 +1,10 @@
-import { initPreferences } from '@easyflow/preferences';
+import { initPreferences, preferences, updatePreferences } from '@easyflow/preferences';
import { unmountGlobalLoading } from '@easyflow/utils';
-import { overridesPreferences } from './preferences';
+import {
+ normalizeBrandAssetPreferences,
+ overridesPreferences,
+} from './preferences';
/**
* 应用初始化完成之后再进行页面加载渲染
@@ -19,6 +22,11 @@ async function initApplication() {
overrides: overridesPreferences,
});
+ const { changed, normalized } = normalizeBrandAssetPreferences(preferences);
+ if (changed) {
+ updatePreferences(normalized);
+ }
+
// 启动应用并挂载
// vue应用主要逻辑及视图
const { bootstrap } = await import('./bootstrap');
diff --git a/easyflow-ui-admin/app/src/preferences.ts b/easyflow-ui-admin/app/src/preferences.ts
index dc1f1f6..838b307 100644
--- a/easyflow-ui-admin/app/src/preferences.ts
+++ b/easyflow-ui-admin/app/src/preferences.ts
@@ -1,5 +1,7 @@
import { defineOverridesPreferences } from '@easyflow/preferences';
+const assetBase = import.meta.env.BASE_URL || '/';
+
/**
* @description 项目配置文件
* 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置
@@ -11,9 +13,75 @@ export const overridesPreferences = defineOverridesPreferences({
name: import.meta.env.VITE_APP_TITLE,
accessMode: 'mixed',
},
+ auth: {
+ sloganImage: `${assetBase}slogan.svg`,
+ },
+ logo: {
+ source: `${assetBase}logo.svg`,
+ sourceDark: `${assetBase}logoDark.svg`,
+ sourceMini: `${assetBase}logoMini.svg`,
+ sourceMiniDark: `${assetBase}logoMiniDark.svg`,
+ },
transition: {
enable: false,
loading: false,
progress: false,
},
});
+
+const BUILTIN_BRAND_ASSETS = new Map([
+ ['/logo.svg', 'logo.svg'],
+ ['/logoDark.svg', 'logoDark.svg'],
+ ['/logoMini.svg', 'logoMini.svg'],
+ ['/logoMiniDark.svg', 'logoMiniDark.svg'],
+ ['/slogan.svg', 'slogan.svg'],
+]);
+
+function normalizeBuiltinBrandAsset(path?: string) {
+ if (!path) {
+ return path;
+ }
+
+ const fileName = BUILTIN_BRAND_ASSETS.get(path);
+ if (!fileName) {
+ return path;
+ }
+
+ return `${assetBase}${fileName}`;
+}
+
+export function normalizeBrandAssetPreferences(preferences: {
+ auth?: { sloganImage?: string };
+ logo?: {
+ source?: string;
+ sourceDark?: string;
+ sourceMini?: string;
+ sourceMiniDark?: string;
+ };
+}) {
+ const normalized = {
+ auth: {
+ sloganImage: normalizeBuiltinBrandAsset(preferences.auth?.sloganImage),
+ },
+ logo: {
+ source: normalizeBuiltinBrandAsset(preferences.logo?.source),
+ sourceDark: normalizeBuiltinBrandAsset(preferences.logo?.sourceDark),
+ sourceMini: normalizeBuiltinBrandAsset(preferences.logo?.sourceMini),
+ sourceMiniDark: normalizeBuiltinBrandAsset(
+ preferences.logo?.sourceMiniDark,
+ ),
+ },
+ };
+
+ const changed =
+ normalized.auth.sloganImage !== preferences.auth?.sloganImage ||
+ normalized.logo.source !== preferences.logo?.source ||
+ normalized.logo.sourceDark !== preferences.logo?.sourceDark ||
+ normalized.logo.sourceMini !== preferences.logo?.sourceMini ||
+ normalized.logo.sourceMiniDark !== preferences.logo?.sourceMiniDark;
+
+ return {
+ changed,
+ normalized,
+ };
+}
diff --git a/easyflow-ui-admin/app/src/utils/assets.ts b/easyflow-ui-admin/app/src/utils/assets.ts
new file mode 100644
index 0000000..086cd30
--- /dev/null
+++ b/easyflow-ui-admin/app/src/utils/assets.ts
@@ -0,0 +1,13 @@
+const assetBase = import.meta.env.BASE_URL || '/';
+
+export function getPublicAssetUrl(path: string) {
+ if (!path) {
+ return assetBase;
+ }
+ const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
+ return `${assetBase}${normalizedPath}`;
+}
+
+export function getEmptyStateImageUrl(themeMode?: string) {
+ return getPublicAssetUrl(`empty${themeMode === 'dark' ? '-dark' : ''}.png`);
+}
diff --git a/easyflow-ui-admin/app/src/views/ai/bots/pages/Run.vue b/easyflow-ui-admin/app/src/views/ai/bots/pages/Run.vue
index 7df0e3a..e3dfd58 100644
--- a/easyflow-ui-admin/app/src/views/ai/bots/pages/Run.vue
+++ b/easyflow-ui-admin/app/src/views/ai/bots/pages/Run.vue
@@ -23,6 +23,7 @@ import { getBotDetails, getSessionList } from '#/api';
import BotAvatar from '#/components/botAvatar/botAvatar.vue';
import Chat from '#/components/chat/chat.vue';
import { $t } from '#/locales';
+import { getEmptyStateImageUrl } from '#/utils/assets';
const route = useRoute();
const router = useRouter();
@@ -132,7 +133,7 @@ const updateActive = (_sessionId?: number | string) => {
@update:active="updateActive"
/>
diff --git a/easyflow-ui-admin/app/src/views/ai/workflow/components/ExecResult.vue b/easyflow-ui-admin/app/src/views/ai/workflow/components/ExecResult.vue
index d358777..20f0580 100644
--- a/easyflow-ui-admin/app/src/views/ai/workflow/components/ExecResult.vue
+++ b/easyflow-ui-admin/app/src/views/ai/workflow/components/ExecResult.vue
@@ -7,6 +7,7 @@ import { ElEmpty, ElMessage, ElRow } from 'element-plus';
import ShowJson from '#/components/json/ShowJson.vue';
import { $t } from '#/locales';
+import { getEmptyStateImageUrl } from '#/utils/assets';
import ExecResultItem from '#/views/ai/workflow/components/ExecResultItem.vue';
export interface ExecResultProps {
@@ -87,7 +88,7 @@ function getResult(res: any) {