mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-29 02:38:45 +08:00
fix: Fix image loading issue (#9164)
This commit is contained in:
parent
8b22acce27
commit
47547ad4e1
5 changed files with 112 additions and 52 deletions
|
|
@ -2,19 +2,21 @@
|
|||
<div class="logo" style="cursor: pointer" @click="goHome">
|
||||
<template v-if="isCollapse">
|
||||
<img
|
||||
v-if="globalStore.themeConfig.logo"
|
||||
v-if="globalStore.themeConfig.logo && !logoLoadFailed"
|
||||
:src="`/api/v2/images/logo?t=${Date.now()}`"
|
||||
style="cursor: pointer"
|
||||
alt="logo"
|
||||
@error="logoLoadFailed = true"
|
||||
/>
|
||||
<MenuLogo v-else />
|
||||
</template>
|
||||
<template v-else>
|
||||
<img
|
||||
v-if="globalStore.themeConfig.logoWithText"
|
||||
v-if="globalStore.themeConfig.logoWithText && !logoWithTextLoadFailed"
|
||||
:src="`/api/v2/images/logoWithText?t=${Date.now()}`"
|
||||
style="cursor: pointer"
|
||||
alt="logo"
|
||||
@error="logoWithTextLoadFailed = true"
|
||||
/>
|
||||
<PrimaryLogo v-else />
|
||||
</template>
|
||||
|
|
@ -26,9 +28,12 @@ import router from '@/routers';
|
|||
import { GlobalStore } from '@/store';
|
||||
import PrimaryLogo from '@/assets/images/1panel-logo.svg?component';
|
||||
import MenuLogo from '@/assets/images/1panel-menu-logo.svg?component';
|
||||
import { ref } from 'vue';
|
||||
|
||||
defineProps<{ isCollapse: boolean }>();
|
||||
|
||||
const logoLoadFailed = ref(false);
|
||||
const logoWithTextLoadFailed = ref(false);
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
const goHome = () => {
|
||||
|
|
|
|||
|
|
@ -810,3 +810,12 @@ export const toLink = (link: string) => {
|
|||
window.open(link, '_blank');
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
export const preloadImage = (url: string): Promise<string> => {
|
||||
return new Promise((resolve) => {
|
||||
const img = new Image();
|
||||
img.onload = () => resolve(url);
|
||||
img.onerror = () => resolve(url);
|
||||
img.src = url;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,30 +13,44 @@ export function resetXSetting() {
|
|||
|
||||
export function initFavicon() {
|
||||
document.title = globalStore.themeConfig.panelName;
|
||||
let favicon = globalStore.themeConfig.favicon;
|
||||
const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement;
|
||||
link.type = 'image/x-icon';
|
||||
link.rel = 'shortcut icon';
|
||||
let goldLink = new URL(`../assets/images/favicon.svg`, import.meta.url).href;
|
||||
if (globalStore.isProductPro) {
|
||||
const themeColor = globalStore.themeConfig.primary;
|
||||
const svg = `
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="${themeColor}" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.1451 18.8875L5.66228 15.7224V8.40336L3.5376 7.1759V16.9488L9.02038 20.114L11.1451 18.8875Z" />
|
||||
<path d="M18.3397 15.7224L12.0005 19.3819L9.87683 20.6083L12.0005 21.8348L20.4644 16.9488L18.3397 15.7224Z" />
|
||||
<path d="M12.0015 4.74388L14.1252 3.5174L12.0005 2.28995L3.5376 7.17591L5.66228 8.40337L12.0005 4.74388H12.0015Z" />
|
||||
<path d="M14.9816 4.01077L12.8569 5.23723L18.3397 8.40336V15.7224L20.4634 16.9488V7.1759L14.9816 4.01077Z" />
|
||||
<path d="M11.9995 1.02569L21.5576 6.54428V17.5795L11.9995 23.0971L2.44343 17.5795V6.54428L11.9995 1.02569ZM11.9995 0.72728L2.18182 6.39707V17.7366L11.9995 23.4064L21.8182 17.7366V6.39707L11.9995 0.72728Z" />
|
||||
<path d="M12.3079 6.78001L12.9564 7.16695V17.105L12.3079 17.48V6.78001Z" />
|
||||
<path d="M12.3078 6.78001L9.10889 8.6222V9.86954H10.2359V16.2854L12.3059 17.481L12.3078 6.78001Z" />
|
||||
</svg>
|
||||
`;
|
||||
goldLink = `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
||||
link.href = favicon ? `/api/v2/images/favicon?t=${Date.now()}` : goldLink;
|
||||
const favicon = globalStore.themeConfig.favicon;
|
||||
const isPro = globalStore.isProductPro;
|
||||
const themeColor = globalStore.themeConfig.primary;
|
||||
|
||||
const customFaviconUrl = `/api/v2/images/favicon?t=${Date.now()}`;
|
||||
const fallbackSvg = isPro
|
||||
? `data:image/svg+xml,${encodeURIComponent(`
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="${themeColor}" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.1451 18.8875L5.66228 15.7224V8.40336L3.5376 7.1759V16.9488L9.02038 20.114L11.1451 18.8875Z" />
|
||||
<path d="M18.3397 15.7224L12.0005 19.3819L9.87683 20.6083L12.0005 21.8348L20.4644 16.9488L18.3397 15.7224Z" />
|
||||
<path d="M12.0015 4.74388L14.1252 3.5174L12.0005 2.28995L3.5376 7.17591L5.66228 8.40337L12.0005 4.74388H12.0015Z" />
|
||||
<path d="M14.9816 4.01077L12.8569 5.23723L18.3397 8.40336V15.7224L20.4634 16.9488V7.1759L14.9816 4.01077Z" />
|
||||
<path d="M11.9995 1.02569L21.5576 6.54428V17.5795L11.9995 23.0971L2.44343 17.5795V6.54428L11.9995 1.02569ZM11.9995 0.72728L2.18182 6.39707V17.7366L11.9995 23.4064L21.8182 17.7366V6.39707L11.9995 0.72728Z" />
|
||||
<path d="M12.3079 6.78001L12.9564 7.16695V17.105L12.3079 17.48V6.78001Z" />
|
||||
<path d="M12.3078 6.78001L9.10889 8.6222V9.86954H10.2359V16.2854L12.3059 17.481L12.3078 6.78001Z" />
|
||||
</svg>
|
||||
`)}`
|
||||
: '/public/favicon.png';
|
||||
|
||||
const setLink = (href: string) => {
|
||||
let link = document.querySelector("link[rel*='icon']") as HTMLLinkElement;
|
||||
if (!link) {
|
||||
link = document.createElement('link');
|
||||
link.rel = 'shortcut icon';
|
||||
link.type = 'image/x-icon';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
link.href = href;
|
||||
};
|
||||
|
||||
if (favicon) {
|
||||
const testImg = new Image();
|
||||
testImg.onload = () => setLink(customFaviconUrl);
|
||||
testImg.onerror = () => setLink(fallbackSvg);
|
||||
testImg.src = customFaviconUrl;
|
||||
} else {
|
||||
link.href = favicon ? `/api/v2/images/favicon?t=${Date.now()}` : '/public/favicon.png';
|
||||
setLink(fallbackSvg);
|
||||
}
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
export async function getXpackSetting() {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
<template>
|
||||
<div class="flex items-center justify-center min-h-screen relative bg-gray-100">
|
||||
<div
|
||||
class="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
||||
:style="
|
||||
globalStore.themeConfig.loginBgType === 'color'
|
||||
? { backgroundColor: globalStore.themeConfig.loginBackground }
|
||||
: { backgroundImage: `url(${loadImage('loginBackground')})` }
|
||||
"
|
||||
></div>
|
||||
<div class="absolute inset-0 bg-cover bg-center bg-no-repeat" :style="backgroundStyle"></div>
|
||||
<div
|
||||
:style="{ opacity: backgroundOpacity, width: containerWidth, height: containerHeight }"
|
||||
class="bg-white shadow-lg relative z-10 border border-gray-200 flex overflow-hidden"
|
||||
|
|
@ -15,9 +8,12 @@
|
|||
<div class="grid grid-cols-1 md:grid-cols-2 items-stretch w-full">
|
||||
<div v-if="showLogo" class="flex justify-center" :style="{ height: containerHeight }">
|
||||
<img
|
||||
v-show="imgLoaded"
|
||||
:src="loadImage('loginImage')"
|
||||
class="max-w-full max-h-full object-cover bg-cover bg-center"
|
||||
alt="1panel"
|
||||
@load="onImgLoad"
|
||||
@error="onImgError"
|
||||
/>
|
||||
</div>
|
||||
<div :class="loginFormClass">
|
||||
|
|
@ -32,10 +28,20 @@
|
|||
import LoginForm from './components/login-form.vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { preloadImage } from '@/utils/util';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
const backgroundOpacity = ref(1);
|
||||
const defaultLoginImage = new URL('@/assets/images/1panel-login.jpg', import.meta.url).href;
|
||||
const defaultLoginBgImage = new URL('@/assets/images/1panel-login-bg.jpg', import.meta.url).href;
|
||||
const loadedLoginImage = ref<string | null>(null);
|
||||
const loadedBackgroundImage = ref<string | null>(null);
|
||||
const backgroundStyle = ref<{ backgroundImage?: string; backgroundColor?: string }>({});
|
||||
const imgLoaded = ref(false);
|
||||
|
||||
function onImgLoad() {
|
||||
imgLoaded.value = true;
|
||||
}
|
||||
const mySafetyCode = defineProps({
|
||||
code: {
|
||||
type: String,
|
||||
|
|
@ -51,29 +57,52 @@ const getStatus = async () => {
|
|||
};
|
||||
|
||||
const loadImage = (name: string) => {
|
||||
switch (name) {
|
||||
case 'loginImage':
|
||||
if (globalStore.themeConfig.loginImage === 'loginImage') {
|
||||
return `/api/v2/images/loginImage?t=${Date.now()}`;
|
||||
}
|
||||
return new URL('@/assets/images/1panel-login.jpg', import.meta.url).href;
|
||||
case 'loginBackground':
|
||||
if (globalStore.themeConfig.loginBgType === 'image') {
|
||||
if (globalStore.themeConfig.loginBackground === 'loginBackground') {
|
||||
return `/api/v2/images/loginBackground?t=${Date.now()}`;
|
||||
}
|
||||
return new URL('@/assets/images/1panel-login-bg.jpg', import.meta.url).href;
|
||||
} else if (globalStore.themeConfig.loginBgType === 'color') {
|
||||
return globalStore.themeConfig.loginBackground;
|
||||
} else {
|
||||
return new URL('@/assets/images/1panel-login-bg.jpg', import.meta.url).href;
|
||||
}
|
||||
const { loginImage, loginBackground, loginBgType } = globalStore.themeConfig;
|
||||
if (name === 'loginImage') {
|
||||
return loginImage === 'loginImage' ? loadedLoginImage.value : defaultLoginImage;
|
||||
}
|
||||
if (name === 'loginBackground') {
|
||||
if (loginBgType === 'image') {
|
||||
return loginBackground === 'loginBackground' ? loadedBackgroundImage.value : defaultLoginBgImage;
|
||||
}
|
||||
if (loginBgType === 'color') {
|
||||
return loginBackground;
|
||||
}
|
||||
return defaultLoginBgImage;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getStatus();
|
||||
const onImgError = (event: any) => {
|
||||
event.target.src = defaultLoginImage;
|
||||
imgLoaded.value = true;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getStatus();
|
||||
const loginImageUrl = `/api/v2/images/loginImage?t=${Date.now()}`;
|
||||
const backgroundImageUrl = `/api/v2/images/loginBackground?t=${Date.now()}`;
|
||||
loadedLoginImage.value = await preloadImage(loginImageUrl);
|
||||
loadedBackgroundImage.value = await preloadImage(backgroundImageUrl);
|
||||
if (globalStore.themeConfig.loginBgType === 'color') {
|
||||
backgroundStyle.value = {
|
||||
backgroundColor: globalStore.themeConfig.loginBackground,
|
||||
};
|
||||
} else {
|
||||
const img = new Image();
|
||||
const url = loadImage('loginBackground');
|
||||
img.onload = () => {
|
||||
backgroundStyle.value = {
|
||||
backgroundImage: `url(${url})`,
|
||||
};
|
||||
};
|
||||
img.onerror = () => {
|
||||
backgroundStyle.value = {
|
||||
backgroundImage: `url(${defaultLoginBgImage})`, // 你定义的默认图
|
||||
};
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
});
|
||||
|
||||
const FIXED_WIDTH = 1000;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
<div style="text-align: center; margin-top: 20px">
|
||||
<div style="justify-self: center" class="logo">
|
||||
<img
|
||||
v-if="globalStore.themeConfig.logo"
|
||||
v-if="globalStore.themeConfig.logo && !logoLoadFailed"
|
||||
style="width: 80px"
|
||||
:src="`/api/v2/images/logo?t=${Date.now()}`"
|
||||
@error="logoLoadFailed = true"
|
||||
alt=""
|
||||
/>
|
||||
<PrimaryLogo v-else />
|
||||
</div>
|
||||
|
|
@ -49,6 +51,7 @@ import { storeToRefs } from 'pinia';
|
|||
const globalStore = GlobalStore();
|
||||
const { docsUrl } = storeToRefs(globalStore);
|
||||
const loading = ref();
|
||||
const logoLoadFailed = ref(false);
|
||||
|
||||
const toDoc = () => {
|
||||
window.open(docsUrl.value, '_blank', 'noopener,noreferrer');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue