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');
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<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);
|
||||
initAuthKeepAlive();
|
||||
|
||||
// PC 登录/首页可后台预热;H5 全程跳过,避免全局 CSS 打乱首屏
|
||||
if ((light || isHomePath(entryPath)) && !isH5LikePath(entryPath)) {
|
||||
// 登录页勿预热 VXE/Element:体积大且会注入全局 CSS,和首屏抢带宽
|
||||
if (isHomePath(entryPath) && !isH5LikePath(entryPath) && !light) {
|
||||
void ensureHeavyPlugins();
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +26,6 @@
|
||||
|
||||
<template v-else>
|
||||
<div class="login-hero__admin-stack">
|
||||
<p class="login-hero__brief">{{ t('login.hero.admin.brief') }}</p>
|
||||
|
||||
<ol
|
||||
class="login-hero__principles"
|
||||
@mouseenter="hovered = true"
|
||||
@ -38,12 +36,12 @@
|
||||
<li
|
||||
v-for="(pillar, index) in adminPillars"
|
||||
:key="pillar.key"
|
||||
class="login-hero__principle"
|
||||
class="login-hero__principle login-hero__spine-item login-hero__spine-item--left"
|
||||
:class="{
|
||||
'is-active': activePrinciple === index,
|
||||
'is-dim': activePrinciple >= 0 && activePrinciple !== index,
|
||||
}"
|
||||
:style="{ '--i': index }"
|
||||
:style="{ '--i': index, '--t': pillar.t }"
|
||||
tabindex="0"
|
||||
@mouseenter="activePrinciple = index"
|
||||
@focus="activePrinciple = index"
|
||||
@ -61,27 +59,23 @@
|
||||
</li>
|
||||
</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">
|
||||
<icon-robot :size="14" />
|
||||
AI
|
||||
</span>
|
||||
<p class="login-hero__ai-text">{{ t('login.hero.admin.ai') }}</p>
|
||||
</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>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="login-hero__visual">
|
||||
<picture>
|
||||
<picture v-if="isCustomer">
|
||||
<source srcset="/login-assets/hero-plane.webp" type="image/webp" />
|
||||
<img
|
||||
class="login-hero__plane"
|
||||
@ -90,6 +84,13 @@
|
||||
draggable="false"
|
||||
/>
|
||||
</picture>
|
||||
<img
|
||||
v-else
|
||||
class="login-hero__truck"
|
||||
src="/login-assets/hero-truck.png"
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -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<typeof window.setInterval> | 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) {
|
||||
|
||||
@ -24,19 +24,36 @@
|
||||
:class="{ 'login-brand-corner--light': isLightMode }"
|
||||
>
|
||||
<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>
|
||||
<aside :class="['login-hero-panel', { 'login-hero-panel--admin': !isCustomerLogin }]">
|
||||
<aside v-if="isCustomerLogin" class="login-hero-panel">
|
||||
<LoginHero
|
||||
:light="isLightMode"
|
||||
:portal="isCustomerLogin ? 'customer' : 'admin'"
|
||||
portal="customer"
|
||||
/>
|
||||
</aside>
|
||||
<div class="login-characters-panel">
|
||||
<div v-if="isCustomerLogin" class="login-characters-panel">
|
||||
<LoginCharacters v-if="showCharacters" @register="registerLoginCharacters" />
|
||||
</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 ref="loginFormRef" :class="['login-form', { 'login-form--ready': shellReady }]">
|
||||
<div class="login-form-toolbar">
|
||||
@ -72,10 +89,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer v-if="shellReady" class="login-footer">
|
||||
{{ t('login.footer.copyright') }}
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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': '傍晚好,今天也辛苦了',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user