diff --git a/IDE官网/assets/js/ai-advisor.js b/IDE官网/assets/js/ai-advisor.js index 19e5c58..4363832 100644 --- a/IDE官网/assets/js/ai-advisor.js +++ b/IDE官网/assets/js/ai-advisor.js @@ -752,6 +752,30 @@ return omsUrl(preferOmsH5() ? '/h5/login' : '/login'); } + let omsLoginWarmed = false; + function warmupOmsLogin() { + if (omsLoginWarmed) return; + omsLoginWarmed = true; + try { + const url = loginPortalUrl(); + const origin = resolveOmsOrigin(); + const preconnect = document.createElement('link'); + preconnect.rel = 'preconnect'; + preconnect.href = origin; + document.head.appendChild(preconnect); + const prefetch = document.createElement('link'); + prefetch.rel = 'prefetch'; + prefetch.href = url; + document.head.appendChild(prefetch); + if (/localhost|127\.0\.0\.1/i.test(new URL(origin).hostname)) { + fetch(new URL('/src/views/login/index.vue', origin), { + credentials: 'omit', + mode: 'cors', + }).catch(function () {}); + } + } catch (e) {} + } + function registerUrl(dest) { // 官网「注册询价」走客户登录页微信扫码(注册/登录同一入口) const url = new URL(loginPortalUrl()); @@ -2654,7 +2678,13 @@ if (heroCta) { heroCta.textContent = t('heroCta'); heroCta.href = loginPortalUrl(); + if (!heroCta.dataset.omsWarm) { + heroCta.dataset.omsWarm = '1'; + heroCta.addEventListener('pointerenter', warmupOmsLogin, { once: true }); + heroCta.addEventListener('focus', warmupOmsLogin, { once: true }); + } } + warmupOmsLogin(); const welcomeHuman = shell.querySelector('.ai-welcome-human'); if (welcomeHuman) welcomeHuman.textContent = t('human') + ' →'; renderWelcomeStats(); diff --git a/index.html b/index.html index 4801455..98afdad 100644 --- a/index.html +++ b/index.html @@ -66,6 +66,14 @@ : 'IDE客户中心' : 'IDE I Faster & Simpler'; } catch (e2) {} + if (path === '/login') { + var plane = document.createElement('link'); + plane.rel = 'preload'; + plane.as = 'image'; + plane.href = '/login-assets/hero-plane.webp'; + plane.type = 'image/webp'; + document.head.appendChild(plane); + } })(); diff --git a/public/login-assets/hero-truck.png b/public/login-assets/hero-truck.png new file mode 100644 index 0000000..e1d9737 Binary files /dev/null and b/public/login-assets/hero-truck.png differ diff --git a/src/main.ts b/src/main.ts index 2b57ba9..af0cf6b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -135,8 +135,8 @@ async function bootstrap() { installWeChatH5HistoryGuard(router); initAuthKeepAlive(); - // PC 登录/首页可后台预热;H5 全程跳过,避免全局 CSS 打乱首屏 - if ((light || isHomePath(entryPath)) && !isH5LikePath(entryPath)) { + // 登录页勿预热 VXE/Element:体积大且会注入全局 CSS,和首屏抢带宽 + if (isHomePath(entryPath) && !isH5LikePath(entryPath) && !light) { void ensureHeavyPlugins(); } diff --git a/src/views/login/components/LoginHero.vue b/src/views/login/components/LoginHero.vue index 938c045..3b03c48 100644 --- a/src/views/login/components/LoginHero.vue +++ b/src/views/login/components/LoginHero.vue @@ -26,8 +26,6 @@ - {{ t('login.hero.admin.brief') }} - - + AI {{ t('login.hero.admin.ai') }} - - - {{ t('login.hero.admin.flow.pickup') }} - - {{ t('login.hero.admin.flow.transit') }} - - {{ t('login.hero.admin.flow.delivery') }} - - + + @@ -116,8 +117,37 @@ interface AdminPillar { icon: Component; titleKey: string; descKey: string; + side: 'left' | 'right'; + t: number; } +const adminPillars: AdminPillar[] = [ + { + key: 'care', + icon: IconCheckCircle, + titleKey: 'login.hero.admin.pillar.care.title', + descKey: 'login.hero.admin.pillar.care.desc', + side: 'left', + t: 0.24, + }, + { + key: 'speed', + icon: IconThunderbolt, + titleKey: 'login.hero.admin.pillar.speed.title', + descKey: 'login.hero.admin.pillar.speed.desc', + side: 'left', + t: 0.40, + }, + { + key: 'reach', + icon: IconMindMapping, + titleKey: 'login.hero.admin.pillar.reach.title', + descKey: 'login.hero.admin.pillar.reach.desc', + side: 'left', + t: 0.56, + }, +]; + const props = withDefaults( defineProps<{ light?: boolean; @@ -138,27 +168,6 @@ let cycleTimer: ReturnType | null = null; const isCustomer = computed(() => props.portal === 'customer'); -const adminPillars: AdminPillar[] = [ - { - key: 'care', - icon: IconCheckCircle, - titleKey: 'login.hero.admin.pillar.care.title', - descKey: 'login.hero.admin.pillar.care.desc', - }, - { - key: 'speed', - icon: IconThunderbolt, - titleKey: 'login.hero.admin.pillar.speed.title', - descKey: 'login.hero.admin.pillar.speed.desc', - }, - { - key: 'reach', - icon: IconMindMapping, - titleKey: 'login.hero.admin.pillar.reach.title', - descKey: 'login.hero.admin.pillar.reach.desc', - }, -]; - function startCycle() { stopCycle(); if (isCustomer.value) return; @@ -258,25 +267,75 @@ onBeforeUnmount(() => { max-width: 520px; } -.login-hero--admin .login-hero__inner { - justify-content: flex-start; - align-items: center; +.login-hero--admin { + width: 100%; + height: 100%; } -.login-hero--admin .login-hero__content { - flex: 1 1 auto; - width: 100%; - max-width: 520px; +.login-hero--admin .login-hero__inner { display: block; + position: relative; + width: 100%; + height: 100%; +} + +.login-hero--admin .login-hero__content, +.login-hero--admin .login-hero__admin-stack, +.login-hero--admin .login-hero__principles { + display: contents; +} + +.login-hero--admin .login-hero__spine-item { + --split-x: calc( + var(--login-split-top) + (var(--login-split-bottom) - var(--login-split-top)) * var(--t, 0.5) + ); + position: absolute; + top: calc(var(--t, 0.5) * 100%); + left: auto; + right: calc(100% - var(--split-x) + 20px); + width: min(360px, 30vw); + margin: 0; + padding-right: 0; + pointer-events: auto; +} + +.login-hero--admin .login-hero__spine-item--left { + transform: translateY(-50%); +} + +.login-hero--admin .login-hero__principle { + animation-name: login-hero-principle-in-admin; + transition: + background 0.25s ease, + opacity 0.25s ease; + + &::before { + display: none; + } + + &.is-active { + transform: translateY(-50%); + } +} + +@keyframes login-hero-principle-in-admin { + from { + opacity: 0; + transform: translateY(-50%); + } + to { + opacity: 1; + transform: translateY(-50%); + } } .login-hero__admin-stack { width: 100%; - max-width: 460px; + max-width: 440px; } .login-hero__brief { - margin: 0 0 22px; + margin: 0 0 18px; font-size: 14px; font-weight: 500; letter-spacing: 0.08em; @@ -299,8 +358,8 @@ onBeforeUnmount(() => { display: grid; grid-template-columns: 44px minmax(0, 1fr) 36px; align-items: center; - gap: 14px; - padding: 16px 12px 16px 4px; + gap: 12px; + padding: 12px 8px 12px 2px; border-radius: 10px; cursor: default; outline: none; @@ -371,8 +430,8 @@ onBeforeUnmount(() => { } .login-hero__principle-title { - margin: 0 0 6px; - font-size: 22px; + margin: 0 0 4px; + font-size: 20px; font-weight: 700; line-height: 1.2; letter-spacing: 0.04em; @@ -409,7 +468,7 @@ onBeforeUnmount(() => { display: flex; align-items: flex-start; gap: 12px; - margin: 22px 0 0; + margin: 16px 0 0; padding: 12px 14px; border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.14); @@ -443,29 +502,20 @@ onBeforeUnmount(() => { color: rgba(255, 255, 255, 0.72); } -.login-hero__flow { +.login-hero--admin .login-hero__visual { + position: absolute; + left: calc((var(--login-split-top) + var(--login-split-bottom)) / 4 - 150px); + top: 50%; + bottom: auto; + z-index: 1; + width: min(380px, 32vw); + margin: 0; display: flex; + flex-direction: column; align-items: center; - gap: 10px; - margin: 20px 0 0; - padding-top: 16px; - border-top: 1px solid rgba(255, 255, 255, 0.12); - font-size: 12px; - font-weight: 600; - letter-spacing: 0.12em; - color: rgba(255, 255, 255, 0.45); - - i { - flex: 1; - height: 1px; - min-width: 16px; - background: linear-gradient( - 90deg, - rgba(255, 255, 255, 0.08), - rgba(255, 255, 255, 0.35), - rgba(255, 255, 255, 0.08) - ); - } + transform: translate(-50%, -50%) scale(1.3); + justify-content: center; + align-self: auto; } @keyframes login-hero-principle-in { @@ -542,6 +592,17 @@ onBeforeUnmount(() => { user-select: none; } +.login-hero--admin .login-hero__truck { + width: 100%; + max-width: none; + height: auto; + display: block; + margin: 0; + transform: none; + pointer-events: none; + user-select: none; +} + .login-hero--light { color: rgba(26, 45, 74, 0.88); } @@ -607,30 +668,26 @@ onBeforeUnmount(() => { color: rgba(26, 45, 74, 0.68); } -.login-hero--light .login-hero__flow { - border-top-color: rgba(26, 45, 74, 0.1); - color: rgba(26, 45, 74, 0.42); - - i { - background: linear-gradient( - 90deg, - rgba(26, 45, 74, 0.04), - rgba(26, 45, 74, 0.22), - rgba(26, 45, 74, 0.04) - ); - } -} - @media screen and (max-width: 1250px) { .login-hero__visual { display: none; } + .login-hero--admin .login-hero__visual { + display: flex; + } + .login-hero__content { flex: 1 1 100%; } } +@media screen and (max-width: 900px) { + .login-hero--admin .login-hero__visual { + display: none; + } +} + @media screen and (max-width: 768px) { .login-hero__title { font-size: 2rem; @@ -653,10 +710,6 @@ onBeforeUnmount(() => { .login-hero__principle-title { font-size: 18px; } - - .login-hero__flow { - letter-spacing: 0.06em; - } } @media (prefers-reduced-motion: reduce) { diff --git a/src/views/login/index.vue b/src/views/login/index.vue index af7264f..34f21b6 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -24,19 +24,36 @@ :class="{ 'login-brand-corner--light': isLightMode }" > {{ t('brand.name') }} - I {{ t('brand.fullName') }} + · {{ t('brand.fullName') }} - @@ -96,7 +109,6 @@ import { getLoginTypeFromRouteName } from '@/utils/login-portal'; import { IconSunFill, IconMoonFill } from '@arco-design/web-vue/es/icon'; import LoginForm from './components/pwd-login/index.vue'; import LoginHero from './components/LoginHero.vue'; -import LoginCareBanner from './components/LoginCareBanner.vue'; import LoginLangToggle from './components/LoginLangToggle.vue'; import { LOGIN_CHARACTERS_KEY, @@ -112,6 +124,9 @@ const WechatLogin = defineAsyncComponent( const LoginCharacters = defineAsyncComponent( () => import('./components/LoginCharacters.vue'), ); +const LoginCareBanner = defineAsyncComponent( + () => import('./components/LoginCareBanner.vue'), +); const LOGIN_APPEARANCE_KEY = 'login-appearance'; const LOGIN_PAGE_SCROLL_LOCK_CLASS = 'login-page-no-scroll'; @@ -271,14 +286,18 @@ function prefetchWechatQr() { onMounted(() => { document.documentElement.classList.add(LOGIN_PAGE_SCROLL_LOCK_CLASS); shellReady.value = true; - // 首屏先出表单,下一帧再挂角色动画分包 - requestAnimationFrame(() => { + const idle = window.requestIdleCallback + ? (cb: () => void, timeout = 1200) => window.requestIdleCallback(cb, { timeout }) + : (cb: () => void, timeout = 1200) => window.setTimeout(cb, Math.min(timeout, 400)); + // 表单先出,空闲后再挂角色,避免和首屏 JS/图抢带宽 + idle(() => { showCharacters.value = true; - }); - // 后台预拉完整语言包,进系统时几乎不等 - void import('@/locale').then(({ ensureFullLocaleMessages }) => { - void ensureFullLocaleMessages(); - }); + }, 1600); + idle(() => { + void import('@/locale').then(({ ensureFullLocaleMessages }) => { + void ensureFullLocaleMessages(); + }); + }, 2500); }); onBeforeUnmount(() => { @@ -318,24 +337,6 @@ onBeforeUnmount(() => { pointer-events: none; } -.login-footer { - position: fixed; - left: 0; - right: 0; - bottom: 16px; - z-index: 12; - text-align: center; - padding: 0 16px; - font-size: 12px; - line-height: 1.6; - color: rgba(148, 163, 184, 0.92); - pointer-events: none; -} - -.login-container--light .login-footer { - color: rgba(100, 116, 139, 0.88); -} - .login-split { position: absolute; inset: 0; @@ -435,10 +436,22 @@ onBeforeUnmount(() => { } .login-hero-panel--admin { - display: flex; - align-items: center; - justify-content: center; - width: min(800px, calc((var(--login-split-top) + var(--login-split-bottom)) / 2 - 16px)); + inset: 0; + top: 0; + left: 0; + bottom: 0; + right: 0; + transform: none; + z-index: 3; + display: block; + width: auto; + max-width: none; + pointer-events: none; +} + +.login-hero-panel--admin .login-hero { + width: 100%; + height: 100%; } .login-characters-panel { @@ -451,6 +464,22 @@ onBeforeUnmount(() => { padding: 0 0 16px 8px; } +.login-characters-panel--admin { + left: auto; + right: 0; + bottom: 0; + z-index: 6; + padding: 0; + transform: scale(0.82); + transform-origin: bottom right; + opacity: 1; +} + +.login-characters-panel--admin :deep(.login-characters__stage) { + width: 450px; + transform-origin: bottom right; +} + .login-form-toolbar { position: absolute; top: 14px; diff --git a/src/views/login/locale/en-US.ts b/src/views/login/locale/en-US.ts index c28e17b..3b7d97e 100644 --- a/src/views/login/locale/en-US.ts +++ b/src/views/login/locale/en-US.ts @@ -46,9 +46,6 @@ 'login.hero.admin.pillar.reach.desc': 'Pickup to delivery · Clear flow · Fewer detours', 'login.hero.admin.ai': 'Embrace AI: spot issues, protect SLAs, simplify flows — people decide, AI accelerates.', - 'login.hero.admin.flow.pickup': 'Pickup', - 'login.hero.admin.flow.transit': 'In transit', - 'login.hero.admin.flow.delivery': 'Delivered', 'login.care.period.morning': 'Good morning — a fresh start', 'login.care.period.afternoon': 'Good afternoon — steady wins', 'login.care.period.evening': 'Good evening — thanks for today', diff --git a/src/views/login/locale/zh-CN.ts b/src/views/login/locale/zh-CN.ts index 4f67192..6152adb 100644 --- a/src/views/login/locale/zh-CN.ts +++ b/src/views/login/locale/zh-CN.ts @@ -45,9 +45,6 @@ 'login.hero.admin.pillar.reach.title': '更简单', 'login.hero.admin.pillar.reach.desc': '揽收到签收 · 链路清晰 · 少绕少错', 'login.hero.admin.ai': '积极拥抱 AI:帮你盯异常、催时效、简流程——人做决策,AI 做加速。', - 'login.hero.admin.flow.pickup': '揽收', - 'login.hero.admin.flow.transit': '在途', - 'login.hero.admin.flow.delivery': '签收', 'login.care.period.morning': '早上好,新的一天开始了', 'login.care.period.afternoon': '下午好,稳稳推进就好', 'login.care.period.evening': '傍晚好,今天也辛苦了',
{{ t('login.hero.admin.brief') }}
{{ t('login.hero.admin.ai') }}
- {{ t('login.hero.admin.flow.pickup') }} - - {{ t('login.hero.admin.flow.transit') }} - - {{ t('login.hero.admin.flow.delivery') }} -