feat: 管理端登录视觉调整,并减轻客户登录首屏等待
登录页不再预热 VXE/Element,顾问 CTA 预热 /login,角色与全量语言包延后加载。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5178b6379f
commit
0d5ebdb591
@ -752,6 +752,30 @@
|
|||||||
return omsUrl(preferOmsH5() ? '/h5/login' : '/login');
|
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) {
|
function registerUrl(dest) {
|
||||||
// 官网「注册询价」走客户登录页微信扫码(注册/登录同一入口)
|
// 官网「注册询价」走客户登录页微信扫码(注册/登录同一入口)
|
||||||
const url = new URL(loginPortalUrl());
|
const url = new URL(loginPortalUrl());
|
||||||
@ -2654,7 +2678,13 @@
|
|||||||
if (heroCta) {
|
if (heroCta) {
|
||||||
heroCta.textContent = t('heroCta');
|
heroCta.textContent = t('heroCta');
|
||||||
heroCta.href = loginPortalUrl();
|
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');
|
const welcomeHuman = shell.querySelector('.ai-welcome-human');
|
||||||
if (welcomeHuman) welcomeHuman.textContent = t('human') + ' →';
|
if (welcomeHuman) welcomeHuman.textContent = t('human') + ' →';
|
||||||
renderWelcomeStats();
|
renderWelcomeStats();
|
||||||
|
|||||||
@ -66,6 +66,14 @@
|
|||||||
: 'IDE客户中心'
|
: 'IDE客户中心'
|
||||||
: 'IDE I Faster & Simpler';
|
: 'IDE I Faster & Simpler';
|
||||||
} catch (e2) {}
|
} 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);
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||||
|
|||||||
BIN
public/login-assets/hero-truck.png
Normal file
BIN
public/login-assets/hero-truck.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
@ -135,8 +135,8 @@ async function bootstrap() {
|
|||||||
installWeChatH5HistoryGuard(router);
|
installWeChatH5HistoryGuard(router);
|
||||||
initAuthKeepAlive();
|
initAuthKeepAlive();
|
||||||
|
|
||||||
// PC 登录/首页可后台预热;H5 全程跳过,避免全局 CSS 打乱首屏
|
// 登录页勿预热 VXE/Element:体积大且会注入全局 CSS,和首屏抢带宽
|
||||||
if ((light || isHomePath(entryPath)) && !isH5LikePath(entryPath)) {
|
if (isHomePath(entryPath) && !isH5LikePath(entryPath) && !light) {
|
||||||
void ensureHeavyPlugins();
|
void ensureHeavyPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="login-hero__admin-stack">
|
<div class="login-hero__admin-stack">
|
||||||
<p class="login-hero__brief">{{ t('login.hero.admin.brief') }}</p>
|
|
||||||
|
|
||||||
<ol
|
<ol
|
||||||
class="login-hero__principles"
|
class="login-hero__principles"
|
||||||
@mouseenter="hovered = true"
|
@mouseenter="hovered = true"
|
||||||
@ -38,12 +36,12 @@
|
|||||||
<li
|
<li
|
||||||
v-for="(pillar, index) in adminPillars"
|
v-for="(pillar, index) in adminPillars"
|
||||||
:key="pillar.key"
|
:key="pillar.key"
|
||||||
class="login-hero__principle"
|
class="login-hero__principle login-hero__spine-item login-hero__spine-item--left"
|
||||||
:class="{
|
:class="{
|
||||||
'is-active': activePrinciple === index,
|
'is-active': activePrinciple === index,
|
||||||
'is-dim': activePrinciple >= 0 && activePrinciple !== index,
|
'is-dim': activePrinciple >= 0 && activePrinciple !== index,
|
||||||
}"
|
}"
|
||||||
:style="{ '--i': index }"
|
:style="{ '--i': index, '--t': pillar.t }"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@mouseenter="activePrinciple = index"
|
@mouseenter="activePrinciple = index"
|
||||||
@focus="activePrinciple = index"
|
@focus="activePrinciple = index"
|
||||||
@ -61,27 +59,23 @@
|
|||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<div class="login-hero__ai" role="note">
|
<div
|
||||||
|
class="login-hero__ai login-hero__spine-item login-hero__spine-item--left"
|
||||||
|
role="note"
|
||||||
|
style="--t: 0.72"
|
||||||
|
>
|
||||||
<span class="login-hero__ai-badge">
|
<span class="login-hero__ai-badge">
|
||||||
<icon-robot :size="14" />
|
<icon-robot :size="14" />
|
||||||
AI
|
AI
|
||||||
</span>
|
</span>
|
||||||
<p class="login-hero__ai-text">{{ t('login.hero.admin.ai') }}</p>
|
<p class="login-hero__ai-text">{{ t('login.hero.admin.ai') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="login-hero__flow" aria-hidden="true">
|
|
||||||
<span>{{ t('login.hero.admin.flow.pickup') }}</span>
|
|
||||||
<i />
|
|
||||||
<span>{{ t('login.hero.admin.flow.transit') }}</span>
|
|
||||||
<i />
|
|
||||||
<span>{{ t('login.hero.admin.flow.delivery') }}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="login-hero__visual">
|
<div class="login-hero__visual">
|
||||||
<picture>
|
<picture v-if="isCustomer">
|
||||||
<source srcset="/login-assets/hero-plane.webp" type="image/webp" />
|
<source srcset="/login-assets/hero-plane.webp" type="image/webp" />
|
||||||
<img
|
<img
|
||||||
class="login-hero__plane"
|
class="login-hero__plane"
|
||||||
@ -90,6 +84,13 @@
|
|||||||
draggable="false"
|
draggable="false"
|
||||||
/>
|
/>
|
||||||
</picture>
|
</picture>
|
||||||
|
<img
|
||||||
|
v-else
|
||||||
|
class="login-hero__truck"
|
||||||
|
src="/login-assets/hero-truck.png"
|
||||||
|
alt=""
|
||||||
|
draggable="false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -116,8 +117,37 @@ interface AdminPillar {
|
|||||||
icon: Component;
|
icon: Component;
|
||||||
titleKey: string;
|
titleKey: string;
|
||||||
descKey: 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(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
light?: boolean;
|
light?: boolean;
|
||||||
@ -138,27 +168,6 @@ let cycleTimer: ReturnType<typeof window.setInterval> | null = null;
|
|||||||
|
|
||||||
const isCustomer = computed(() => props.portal === 'customer');
|
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() {
|
function startCycle() {
|
||||||
stopCycle();
|
stopCycle();
|
||||||
if (isCustomer.value) return;
|
if (isCustomer.value) return;
|
||||||
@ -258,25 +267,75 @@ onBeforeUnmount(() => {
|
|||||||
max-width: 520px;
|
max-width: 520px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-hero--admin .login-hero__inner {
|
.login-hero--admin {
|
||||||
justify-content: flex-start;
|
width: 100%;
|
||||||
align-items: center;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-hero--admin .login-hero__content {
|
.login-hero--admin .login-hero__inner {
|
||||||
flex: 1 1 auto;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 520px;
|
|
||||||
display: block;
|
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 {
|
.login-hero__admin-stack {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 460px;
|
max-width: 440px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-hero__brief {
|
.login-hero__brief {
|
||||||
margin: 0 0 22px;
|
margin: 0 0 18px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
@ -299,8 +358,8 @@ onBeforeUnmount(() => {
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 44px minmax(0, 1fr) 36px;
|
grid-template-columns: 44px minmax(0, 1fr) 36px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
gap: 12px;
|
||||||
padding: 16px 12px 16px 4px;
|
padding: 12px 8px 12px 2px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -371,8 +430,8 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-hero__principle-title {
|
.login-hero__principle-title {
|
||||||
margin: 0 0 6px;
|
margin: 0 0 4px;
|
||||||
font-size: 22px;
|
font-size: 20px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
@ -409,7 +468,7 @@ onBeforeUnmount(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
margin: 22px 0 0;
|
margin: 16px 0 0;
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
@ -443,29 +502,20 @@ onBeforeUnmount(() => {
|
|||||||
color: rgba(255, 255, 255, 0.72);
|
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;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
transform: translate(-50%, -50%) scale(1.3);
|
||||||
margin: 20px 0 0;
|
justify-content: center;
|
||||||
padding-top: 16px;
|
align-self: auto;
|
||||||
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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes login-hero-principle-in {
|
@keyframes login-hero-principle-in {
|
||||||
@ -542,6 +592,17 @@ onBeforeUnmount(() => {
|
|||||||
user-select: none;
|
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 {
|
.login-hero--light {
|
||||||
color: rgba(26, 45, 74, 0.88);
|
color: rgba(26, 45, 74, 0.88);
|
||||||
}
|
}
|
||||||
@ -607,30 +668,26 @@ onBeforeUnmount(() => {
|
|||||||
color: rgba(26, 45, 74, 0.68);
|
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) {
|
@media screen and (max-width: 1250px) {
|
||||||
.login-hero__visual {
|
.login-hero__visual {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-hero--admin .login-hero__visual {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.login-hero__content {
|
.login-hero__content {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.login-hero--admin .login-hero__visual {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
.login-hero__title {
|
.login-hero__title {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@ -653,10 +710,6 @@ onBeforeUnmount(() => {
|
|||||||
.login-hero__principle-title {
|
.login-hero__principle-title {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-hero__flow {
|
|
||||||
letter-spacing: 0.06em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
|||||||
@ -24,19 +24,36 @@
|
|||||||
:class="{ 'login-brand-corner--light': isLightMode }"
|
:class="{ 'login-brand-corner--light': isLightMode }"
|
||||||
>
|
>
|
||||||
<span class="login-brand-corner__name">{{ t('brand.name') }}</span>
|
<span class="login-brand-corner__name">{{ t('brand.name') }}</span>
|
||||||
<span class="login-brand-corner__suffix">I {{ t('brand.fullName') }}</span>
|
<span class="login-brand-corner__suffix">· {{ t('brand.fullName') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<aside :class="['login-hero-panel', { 'login-hero-panel--admin': !isCustomerLogin }]">
|
<aside v-if="isCustomerLogin" class="login-hero-panel">
|
||||||
<LoginHero
|
<LoginHero
|
||||||
:light="isLightMode"
|
:light="isLightMode"
|
||||||
:portal="isCustomerLogin ? 'customer' : 'admin'"
|
portal="customer"
|
||||||
/>
|
/>
|
||||||
</aside>
|
</aside>
|
||||||
<div class="login-characters-panel">
|
<div v-if="isCustomerLogin" class="login-characters-panel">
|
||||||
<LoginCharacters v-if="showCharacters" @register="registerLoginCharacters" />
|
<LoginCharacters v-if="showCharacters" @register="registerLoginCharacters" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<aside
|
||||||
|
v-if="shellReady && !isCustomerLogin"
|
||||||
|
class="login-hero-panel login-hero-panel--admin"
|
||||||
|
>
|
||||||
|
<LoginHero
|
||||||
|
:light="isLightMode"
|
||||||
|
portal="admin"
|
||||||
|
/>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="shellReady && !isCustomerLogin"
|
||||||
|
class="login-characters-panel login-characters-panel--admin"
|
||||||
|
>
|
||||||
|
<LoginCharacters v-if="showCharacters" @register="registerLoginCharacters" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="shellReady" ref="rightPaneRef" class="login-pane login-pane--right">
|
<div v-if="shellReady" ref="rightPaneRef" class="login-pane login-pane--right">
|
||||||
<div ref="loginFormRef" :class="['login-form', { 'login-form--ready': shellReady }]">
|
<div ref="loginFormRef" :class="['login-form', { 'login-form--ready': shellReady }]">
|
||||||
<div class="login-form-toolbar">
|
<div class="login-form-toolbar">
|
||||||
@ -72,10 +89,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer v-if="shellReady" class="login-footer">
|
|
||||||
{{ t('login.footer.copyright') }}
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -96,7 +109,6 @@ import { getLoginTypeFromRouteName } from '@/utils/login-portal';
|
|||||||
import { IconSunFill, IconMoonFill } from '@arco-design/web-vue/es/icon';
|
import { IconSunFill, IconMoonFill } from '@arco-design/web-vue/es/icon';
|
||||||
import LoginForm from './components/pwd-login/index.vue';
|
import LoginForm from './components/pwd-login/index.vue';
|
||||||
import LoginHero from './components/LoginHero.vue';
|
import LoginHero from './components/LoginHero.vue';
|
||||||
import LoginCareBanner from './components/LoginCareBanner.vue';
|
|
||||||
import LoginLangToggle from './components/LoginLangToggle.vue';
|
import LoginLangToggle from './components/LoginLangToggle.vue';
|
||||||
import {
|
import {
|
||||||
LOGIN_CHARACTERS_KEY,
|
LOGIN_CHARACTERS_KEY,
|
||||||
@ -112,6 +124,9 @@ const WechatLogin = defineAsyncComponent(
|
|||||||
const LoginCharacters = defineAsyncComponent(
|
const LoginCharacters = defineAsyncComponent(
|
||||||
() => import('./components/LoginCharacters.vue'),
|
() => import('./components/LoginCharacters.vue'),
|
||||||
);
|
);
|
||||||
|
const LoginCareBanner = defineAsyncComponent(
|
||||||
|
() => import('./components/LoginCareBanner.vue'),
|
||||||
|
);
|
||||||
|
|
||||||
const LOGIN_APPEARANCE_KEY = 'login-appearance';
|
const LOGIN_APPEARANCE_KEY = 'login-appearance';
|
||||||
const LOGIN_PAGE_SCROLL_LOCK_CLASS = 'login-page-no-scroll';
|
const LOGIN_PAGE_SCROLL_LOCK_CLASS = 'login-page-no-scroll';
|
||||||
@ -271,14 +286,18 @@ function prefetchWechatQr() {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.documentElement.classList.add(LOGIN_PAGE_SCROLL_LOCK_CLASS);
|
document.documentElement.classList.add(LOGIN_PAGE_SCROLL_LOCK_CLASS);
|
||||||
shellReady.value = true;
|
shellReady.value = true;
|
||||||
// 首屏先出表单,下一帧再挂角色动画分包
|
const idle = window.requestIdleCallback
|
||||||
requestAnimationFrame(() => {
|
? (cb: () => void, timeout = 1200) => window.requestIdleCallback(cb, { timeout })
|
||||||
|
: (cb: () => void, timeout = 1200) => window.setTimeout(cb, Math.min(timeout, 400));
|
||||||
|
// 表单先出,空闲后再挂角色,避免和首屏 JS/图抢带宽
|
||||||
|
idle(() => {
|
||||||
showCharacters.value = true;
|
showCharacters.value = true;
|
||||||
});
|
}, 1600);
|
||||||
// 后台预拉完整语言包,进系统时几乎不等
|
idle(() => {
|
||||||
void import('@/locale').then(({ ensureFullLocaleMessages }) => {
|
void import('@/locale').then(({ ensureFullLocaleMessages }) => {
|
||||||
void ensureFullLocaleMessages();
|
void ensureFullLocaleMessages();
|
||||||
});
|
});
|
||||||
|
}, 2500);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@ -318,24 +337,6 @@ onBeforeUnmount(() => {
|
|||||||
pointer-events: none;
|
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 {
|
.login-split {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@ -435,10 +436,22 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-hero-panel--admin {
|
.login-hero-panel--admin {
|
||||||
display: flex;
|
inset: 0;
|
||||||
align-items: center;
|
top: 0;
|
||||||
justify-content: center;
|
left: 0;
|
||||||
width: min(800px, calc((var(--login-split-top) + var(--login-split-bottom)) / 2 - 16px));
|
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 {
|
.login-characters-panel {
|
||||||
@ -451,6 +464,22 @@ onBeforeUnmount(() => {
|
|||||||
padding: 0 0 16px 8px;
|
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 {
|
.login-form-toolbar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 14px;
|
top: 14px;
|
||||||
|
|||||||
@ -46,9 +46,6 @@
|
|||||||
'login.hero.admin.pillar.reach.desc': 'Pickup to delivery · Clear flow · Fewer detours',
|
'login.hero.admin.pillar.reach.desc': 'Pickup to delivery · Clear flow · Fewer detours',
|
||||||
'login.hero.admin.ai':
|
'login.hero.admin.ai':
|
||||||
'Embrace AI: spot issues, protect SLAs, simplify flows — people decide, AI accelerates.',
|
'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.morning': 'Good morning — a fresh start',
|
||||||
'login.care.period.afternoon': 'Good afternoon — steady wins',
|
'login.care.period.afternoon': 'Good afternoon — steady wins',
|
||||||
'login.care.period.evening': 'Good evening — thanks for today',
|
'login.care.period.evening': 'Good evening — thanks for today',
|
||||||
|
|||||||
@ -45,9 +45,6 @@
|
|||||||
'login.hero.admin.pillar.reach.title': '更简单',
|
'login.hero.admin.pillar.reach.title': '更简单',
|
||||||
'login.hero.admin.pillar.reach.desc': '揽收到签收 · 链路清晰 · 少绕少错',
|
'login.hero.admin.pillar.reach.desc': '揽收到签收 · 链路清晰 · 少绕少错',
|
||||||
'login.hero.admin.ai': '积极拥抱 AI:帮你盯异常、催时效、简流程——人做决策,AI 做加速。',
|
'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.morning': '早上好,新的一天开始了',
|
||||||
'login.care.period.afternoon': '下午好,稳稳推进就好',
|
'login.care.period.afternoon': '下午好,稳稳推进就好',
|
||||||
'login.care.period.evening': '傍晚好,今天也辛苦了',
|
'login.care.period.evening': '傍晚好,今天也辛苦了',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user