fix: 修复子路径部署静态资源引用

- 修复 admin 与 usercenter 登录验证码资源在 /flow 子路径下的加载路径

- 统一 logo、空状态图、兜底头像与模型服务商图标的 BASE_URL 处理

- 补齐 usercenter 公共布局与 loading 注入的子路径兼容
This commit is contained in:
2026-03-20 13:02:39 +08:00
parent 39a6daf8fe
commit 07d8193e80
15 changed files with 102 additions and 19 deletions

View File

@@ -19,6 +19,7 @@ const props = defineProps({
},
});
const emits = defineEmits(['delete']);
const fallbackAvatarUrl = `${import.meta.env.BASE_URL || '/'}favicon.svg`;
const handleDelete = (item: any) => {
ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), {
confirmButtonText: $t('button.confirm'),
@@ -40,7 +41,7 @@ const handleDelete = (item: any) => {
<div class="el-list-item-container">
<div class="flex-center">
<ElAvatar :src="item.icon" v-if="item.icon" />
<ElAvatar v-else src="/favicon.svg" shape="circle" />
<ElAvatar v-else :src="fallbackAvatarUrl" shape="circle" />
</div>
<div class="el-list-item-content">
<div class="title">{{ item[titleKey] }}</div>

View File

@@ -57,6 +57,7 @@ const emit = defineEmits(['getData', 'buttonClick']);
const dialogVisible = ref(false);
const pageDataRef = ref();
const loading = ref(false);
const fallbackAvatarUrl = `${import.meta.env.BASE_URL || '/'}favicon.svg`;
const selectedIds = ref<(number | string)[]>([]);
// 存储上一级id与选中tool.name的关联关系
const selectedToolMap = ref<Record<number | string, SelectedMcpTool[]>>({});
@@ -231,7 +232,11 @@ const handleSearch = (query: string) => {
>
<div>
<ElAvatar :src="item.icon" v-if="item.icon" />
<ElAvatar v-else src="/favicon.svg" shape="circle" />
<ElAvatar
v-else
:src="fallbackAvatarUrl"
shape="circle"
/>
</div>
<div class="title-right-container">
<ElText truncated class="title">
@@ -326,7 +331,11 @@ const handleSearch = (query: string) => {
<div class="content-sec-left-container">
<div>
<ElAvatar :src="item.icon" v-if="item.icon" />
<ElAvatar v-else src="/favicon.svg" shape="circle" />
<ElAvatar
v-else
:src="fallbackAvatarUrl"
shape="circle"
/>
</div>
<div class="title-sec-right-container">
<ElText truncated class="title">

View File

@@ -13,6 +13,9 @@ onMounted(() => {});
const authStore = useAuthStore();
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
const assetBase = import.meta.env.BASE_URL || '/';
const captchaAssetBase = `${assetBase}tac`;
const captchaButtonUrl = `${assetBase}tac-btn.png`;
const formSchema = computed((): EasyFlowFormSchema[] => {
return [
@@ -71,11 +74,11 @@ function onSubmit(values: any) {
const style = {
logoUrl: null, // 去除logo
// logoUrl: "/xx/xx/xxx.png" // 替换成自定义的logo
btnUrl: '/tac-btn.png',
btnUrl: captchaButtonUrl,
};
window
// @ts-ignore
.initTAC('/tac', config, style)
.initTAC(captchaAssetBase, config, style)
.then((tac: any) => {
tac.init(); // 调用init则显示验证码
})

View File

@@ -1,5 +1,7 @@
import providerList from './providerList.json';
const assetBase = import.meta.env.BASE_URL || '/';
export interface ProviderModelPreset {
description: string;
label: string;
@@ -28,8 +30,25 @@ export interface ProviderPreset {
const providerOptions = providerList as ProviderPreset[];
export const getProviderPresetByValue = (targetValue?: string) =>
providerOptions.find((item) => item.value === targetValue);
const normalizeAssetUrl = (url?: string) => {
if (!url || !url.startsWith('/')) {
return url || '';
}
return `${assetBase}${url.slice(1)}`;
};
export const getProviderPresetByValue = (targetValue?: string) => {
const preset = providerOptions.find((item) => item.value === targetValue);
if (!preset) {
return undefined;
}
return {
...preset,
icon: normalizeAssetUrl(preset.icon),
};
};
/**
* 根据传入的value返回对应的icon属性
@@ -63,4 +82,7 @@ export const getProviderBadgeText = (
return source.replaceAll(/\s+/g, '').slice(0, 2).toUpperCase();
};
export const providerPresets = providerOptions;
export const providerPresets = providerOptions.map((item) => ({
...item,
icon: normalizeAssetUrl(item.icon),
}));

View File

@@ -142,7 +142,7 @@ const defaultPreferences: Preferences = {
timezone: false,
},
auth: {
sloganImage: '/slogan.svg',
sloganImage: `${assetBase}slogan.svg`,
pageTitle: '',
pageDescription: '',
welcomeBack: '',