🐛 fix: 修复登录/注册页面自定义 Logo 不显示及闪烁问题

- sanitizeUrl 新增 allowDataUrl 选项,支持 data:image/ 格式的 base64 图片 URL
- AuthLayout 改用 appStore 缓存数据,避免重复 API 请求和默认 Logo 闪烁

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
wucm667
2026-02-11 17:04:57 +08:00
parent 723102766b
commit ef2c35dbb1
2 changed files with 29 additions and 25 deletions

View File

@@ -29,17 +29,19 @@
<!-- Logo/Brand --> <!-- Logo/Brand -->
<div class="mb-8 text-center"> <div class="mb-8 text-center">
<!-- Custom Logo or Default Logo --> <!-- Custom Logo or Default Logo -->
<div <template v-if="settingsLoaded">
class="mb-4 inline-flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl shadow-lg shadow-primary-500/30" <div
> class="mb-4 inline-flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl shadow-lg shadow-primary-500/30"
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" /> >
</div> <img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<h1 class="text-gradient mb-2 text-3xl font-bold"> </div>
{{ siteName }} <h1 class="text-gradient mb-2 text-3xl font-bold">
</h1> {{ siteName }}
<p class="text-sm text-gray-500 dark:text-dark-400"> </h1>
{{ siteSubtitle }} <p class="text-sm text-gray-500 dark:text-dark-400">
</p> {{ siteSubtitle }}
</p>
</template>
</div> </div>
<!-- Card Container --> <!-- Card Container -->
@@ -61,25 +63,21 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { computed, onMounted } from 'vue'
import { getPublicSettings } from '@/api/auth' import { useAppStore } from '@/stores'
import { sanitizeUrl } from '@/utils/url' import { sanitizeUrl } from '@/utils/url'
const siteName = ref('Sub2API') const appStore = useAppStore()
const siteLogo = ref('')
const siteSubtitle = ref('Subscription to API Conversion Platform') const siteName = computed(() => appStore.siteName || 'Sub2API')
const siteLogo = computed(() => sanitizeUrl(appStore.siteLogo || '', { allowRelative: true, allowDataUrl: true }))
const siteSubtitle = computed(() => appStore.cachedPublicSettings?.site_subtitle || 'Subscription to API Conversion Platform')
const settingsLoaded = computed(() => appStore.publicSettingsLoaded)
const currentYear = computed(() => new Date().getFullYear()) const currentYear = computed(() => new Date().getFullYear())
onMounted(async () => { onMounted(() => {
try { appStore.fetchPublicSettings()
const settings = await getPublicSettings()
siteName.value = settings.site_name || 'Sub2API'
siteLogo.value = sanitizeUrl(settings.site_logo || '', { allowRelative: true })
siteSubtitle.value = settings.site_subtitle || 'Subscription to API Conversion Platform'
} catch (error) {
console.error('Failed to load public settings:', error)
}
}) })
</script> </script>

View File

@@ -6,6 +6,7 @@
*/ */
type SanitizeOptions = { type SanitizeOptions = {
allowRelative?: boolean allowRelative?: boolean
allowDataUrl?: boolean
} }
export function sanitizeUrl(value: string, options: SanitizeOptions = {}): string { export function sanitizeUrl(value: string, options: SanitizeOptions = {}): string {
@@ -18,6 +19,11 @@ export function sanitizeUrl(value: string, options: SanitizeOptions = {}): strin
return trimmed return trimmed
} }
// 允许 data:image/ 开头的 data URL仅限图片类型
if (options.allowDataUrl && trimmed.startsWith('data:image/')) {
return trimmed
}
// 只接受绝对 URL不使用 base URL 来避免相对路径被解析为当前域名 // 只接受绝对 URL不使用 base URL 来避免相对路径被解析为当前域名
// 检查是否以 http:// 或 https:// 开头 // 检查是否以 http:// 或 https:// 开头
if (!trimmed.match(/^https?:\/\//i)) { if (!trimmed.match(/^https?:\/\//i)) {