From 6fb1f4fd66bfae0efabba1949b809c8f0bf09952 Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Tue, 1 Sep 2026 19:09:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8E=A5=E5=85=A5=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=AE=A2=E6=9C=8D=EF=BC=8C=E5=B9=B6=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=B7=A5=E4=BD=9C=E5=8F=B0=E4=B8=8E=E4=B8=8B=E5=8D=95?= =?UTF-8?q?=E9=A1=B5=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 官网/H5 支持企微客服跳转;用户资料新增 WecomKfUrl;工作台与下单相关体验一并更新。 Co-authored-by: Cursor --- IDE官网/assets/css/ai-advisor.css | 240 +++++++++++-- IDE官网/assets/js/ai-advisor.js | 218 +++++++++--- IDE官网/assets/js/main.js | 8 +- IDE官网/index.html | 6 +- src/api/customer/index.ts | 1 + src/api/order/index.ts | 6 +- src/assets/icons/workplace/order-bind.svg | 12 + src/assets/icons/workplace/order-dispatch.svg | 12 + src/assets/icons/workplace/order-inbound.svg | 14 + src/assets/icons/workplace/order-payment.svg | 13 + src/assets/icons/workplace/order-pick.svg | 13 + src/assets/icons/workplace/order-pickup.svg | 12 + src/assets/icons/workplace/order-transit.svg | 17 + .../NanaAssistant/AiAdvisorShell.vue | 21 +- src/components/NanaAssistant/ai-advisor.css | 29 ++ src/components/UserEditDrawer/index.vue | 9 + src/components/UserProfileFields/index.vue | 5 + src/locale/en-US.ts | 25 +- src/locale/zh-CN.ts | 25 +- src/types/rbac-user-profile.ts | 4 + src/utils/wecomKf.ts | 39 +++ src/views/h5/customer-center/locale/en-US.ts | 1 + src/views/h5/customer-center/locale/zh-CN.ts | 1 + src/views/h5/customer-center/me/index.vue | 13 + .../components/AdminBusinessTrend.vue | 32 +- .../workplace/components/AdminOpsQueue.vue | 4 +- .../workplace/components/AdminStatsPanel.vue | 8 +- .../workplace/components/AdminWorkplace.vue | 97 ++---- .../workplace/components/CareTodayPanel.vue | 322 +++++++++++++----- .../components/CustomerWorkplace.vue | 15 +- .../workplace/components/announcement.vue | 111 +++--- .../useWorkplaceFulfillPickupStats.ts | 25 +- src/views/home/workplace/locale/en-US.ts | 2 +- src/views/home/workplace/locale/zh-CN.ts | 2 +- .../components/SelectDeclarationSkuModal.vue | 2 + src/views/order/placeOrder/index.vue | 292 +++++++++++----- src/views/system/organization/index.vue | 4 + src/views/system/organization/user/index.vue | 4 + 38 files changed, 1239 insertions(+), 425 deletions(-) create mode 100644 src/assets/icons/workplace/order-bind.svg create mode 100644 src/assets/icons/workplace/order-dispatch.svg create mode 100644 src/assets/icons/workplace/order-inbound.svg create mode 100644 src/assets/icons/workplace/order-payment.svg create mode 100644 src/assets/icons/workplace/order-pick.svg create mode 100644 src/assets/icons/workplace/order-pickup.svg create mode 100644 src/assets/icons/workplace/order-transit.svg create mode 100644 src/utils/wecomKf.ts diff --git a/IDE官网/assets/css/ai-advisor.css b/IDE官网/assets/css/ai-advisor.css index 486f7a1..3629100 100644 --- a/IDE官网/assets/css/ai-advisor.css +++ b/IDE官网/assets/css/ai-advisor.css @@ -2312,9 +2312,74 @@ body.command-home .ai-stage-map--eu { /* Composer + trust strip */ .ai-composer-wrap { + position: relative; flex-shrink: 0; } +.ai-new-chat-tip { + position: absolute; + left: 50%; + bottom: calc(100% + 10px); + z-index: 6; + display: inline-flex; + align-items: center; + max-width: min(92%, 360px); + padding: 8px 14px; + border-radius: 999px; + border: 1px solid rgba(255, 255, 255, 0.78); + background: rgba(5, 79, 116, 0.92); + color: #fff; + font-size: 0.78rem; + font-weight: 600; + line-height: 1.3; + letter-spacing: 0.01em; + white-space: nowrap; + pointer-events: none; + transform: translate(-50%, 6px); + opacity: 0; + box-shadow: 0 10px 28px rgba(5, 79, 116, 0.22); + transition: + opacity 0.28s var(--ai-ease), + transform 0.28s var(--ai-ease); +} + +.ai-new-chat-tip::after { + content: ''; + position: absolute; + left: 50%; + top: 100%; + width: 10px; + height: 10px; + margin-left: -5px; + background: rgba(5, 79, 116, 0.92); + border-right: 1px solid rgba(255, 255, 255, 0.5); + border-bottom: 1px solid rgba(255, 255, 255, 0.5); + transform: rotate(45deg) translateY(-4px); +} + +.ai-new-chat-tip[hidden] { + display: none !important; +} + +.ai-new-chat-tip.is-visible { + opacity: 1; + transform: translate(-50%, 0); +} + +.ai-composer-wrap.has-new-chat-tip .ai-composer { + animation: ai-composer-tip-pulse 1.1s var(--ai-ease) 2; +} + +@keyframes ai-composer-tip-pulse { + 0%, + 100% { + box-shadow: none; + } + 45% { + box-shadow: 0 0 0 3px rgba(5, 79, 116, 0.18); + } +} + .ai-composer-wrap.is-welcome { padding: 0; border-top: none; @@ -2444,16 +2509,22 @@ body.command-home .ai-stage-map--eu { @media (prefers-reduced-motion: reduce) { .ai-composer__sheen, .ai-composer__caustic, - .ai-intent-door::after { + .ai-intent-door::after, + .ai-composer-wrap.has-new-chat-tip .ai-composer { animation: none; } + + .ai-new-chat-tip { + transition: none; + } } .ai-trust-bar { display: flex; - flex-direction: column; - align-items: stretch; - gap: 10px; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 8px 18px; margin-top: 4px; padding: 14px 4px 16px; border-top: 1px solid color-mix(in srgb, var(--ai-border) 55%, transparent); @@ -2461,23 +2532,6 @@ body.command-home .ai-stage-map--eu { font-size: 0.72rem; } -.ai-trust-bar__contacts { - display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: center; - gap: 10px 22px; -} - -.ai-trust-bar__meta { - display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: center; - gap: 8px 18px; - text-align: center; -} - .ai-trust-bar a, .ai-trust-wechat { display: inline-flex; @@ -2526,19 +2580,19 @@ body.command-home .ai-stage-map--eu { .ai-trust-address { display: inline-flex; - align-items: flex-start; + align-items: center; justify-content: center; gap: 6px; margin: 0; - max-width: min(100%, 560px); color: var(--ai-text-3); font-size: 0.72rem; line-height: 1.45; text-align: left; + white-space: nowrap; } .ai-trust-address i { - margin-top: 2px; + margin-top: 0; font-size: 0.88rem; line-height: 1; color: var(--ai-action); @@ -2722,15 +2776,8 @@ body.command-home .ai-stage-map--eu { font-size: 0.9rem; } - .ai-trust-bar__contacts { - flex-direction: column; - align-items: center; - gap: 10px; - } - - .ai-trust-bar__meta { - flex-direction: column; - gap: 8px; + .ai-trust-bar { + gap: 8px 14px; } .ai-trust-address { @@ -2738,6 +2785,13 @@ body.command-home .ai-stage-map--eu { justify-content: center; } + .ai-new-chat-tip { + max-width: min(94vw, 320px); + white-space: normal; + text-align: center; + border-radius: 14px; + } + .ai-composer { min-height: 76px; padding: 12px 12px 12px 18px; @@ -2754,3 +2808,123 @@ body.command-home .ai-stage-map--eu { height: 46px; } } + +/* 企业微信客服 — PC 扫码浮层 */ +.ide-kf-modal { + position: fixed; + inset: 0; + z-index: 10050; + display: grid; + place-items: center; + padding: 24px; +} + +.ide-kf-modal__backdrop { + position: absolute; + inset: 0; + background: rgba(12, 18, 28, 0.55); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); +} + +.ide-kf-modal__panel { + position: relative; + z-index: 1; + width: min(100%, 360px); + padding: 28px 24px 22px; + border-radius: 16px; + border: 1px solid color-mix(in srgb, var(--ai-border) 80%, transparent); + background: var(--ai-surface, #fff); + box-shadow: 0 24px 64px rgba(12, 18, 28, 0.22); + text-align: center; +} + +.ide-kf-modal__close { + position: absolute; + top: 10px; + right: 10px; + width: 36px; + height: 36px; + display: grid; + place-items: center; + margin: 0; + padding: 0; + border: none; + border-radius: 8px; + background: transparent; + color: var(--ai-text-3, #6b7280); + cursor: pointer; +} + +.ide-kf-modal__close:hover { + color: var(--ai-text, #111); + background: color-mix(in srgb, var(--ai-border) 40%, transparent); +} + +.ide-kf-modal__kicker { + margin: 0 0 6px; + font-size: 0.75rem; + letter-spacing: 0.04em; + color: var(--ai-text-3, #6b7280); +} + +.ide-kf-modal__title { + margin: 0 0 8px; + font-size: 1.15rem; + font-weight: 650; + color: var(--ai-text, #111); +} + +.ide-kf-modal__hint { + margin: 0 0 18px; + font-size: 0.84rem; + line-height: 1.5; + color: var(--ai-text-2, #4b5563); +} + +.ide-kf-modal__qr-wrap { + display: grid; + place-items: center; + margin: 0 auto 16px; + padding: 12px; + width: fit-content; + border-radius: 12px; + background: #fff; + border: 1px solid color-mix(in srgb, var(--ai-border) 70%, transparent); +} + +.ide-kf-modal__qr { + display: block; + width: 220px; + height: 220px; +} + +.ide-kf-modal__qr-fallback { + margin: 0; + max-width: 220px; + font-size: 0.8rem; + line-height: 1.45; + color: var(--ai-text-2, #4b5563); +} + +.ide-kf-modal__open { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 36px; + padding: 0 14px; + border-radius: 8px; + font-size: 0.84rem; + font-weight: 600; + color: var(--ai-action, #1d7281); + text-decoration: none; +} + +.ide-kf-modal__open:hover { + text-decoration: underline; +} + +button.ai-card-link { + font: inherit; + cursor: pointer; +} diff --git a/IDE官网/assets/js/ai-advisor.js b/IDE官网/assets/js/ai-advisor.js index 6788fca..653efcf 100644 --- a/IDE官网/assets/js/ai-advisor.js +++ b/IDE官网/assets/js/ai-advisor.js @@ -10,6 +10,8 @@ const PHONE = '18123959245'; const EMAIL = 'bd01@1st56.com'; const WECHAT = 'ydgjzzh'; + // 企业微信管理后台 → 微信客服 → 在微信外接入 → 复制客服链接(勿带尾部空格) + const WECOM_KF_URL = 'https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a'; const ICP = '粤ICP备2025463970号-2'; const ADDRESS_ZH = '深圳宝安区福永怀德翠岗5区36栋'; const ADDRESS_EN = 'Bldg 36, Cuigang 5, Fuyong, Bao’an, Shenzhen'; @@ -33,8 +35,8 @@ const COPY = { en: { - welcomeTitle: 'IDE, a digital one-stop cross-border logistics provider', - welcomeTitleShort: 'IDE · Cross-border logistics', + welcomeTitle: 'IDE, your cross-border logistics advisor', + welcomeTitleShort: 'IDE · Your logistics advisor', welcomeSubLead: 'Parcels, express, dropship, and 9610 clearance — ', welcomeSubAccent: 'built for SMB cross-border sellers', welcomeSubTail: '.', @@ -44,11 +46,12 @@ you: 'You', historyTitle: 'Chat history', newChat: 'New chat', + newChatHint: 'New chat started — ask here', emptyHistory: 'No conversations yet', fallback: 'Quotes are in the customer system after you register. You can also talk to an advisor.', trustPhone: PHONE, trustAddress: ADDRESS_EN, - trustWechat: 'WeChat ' + WECHAT, + trustWechat: 'WeChat support', trustEmail: EMAIL, trustIcp: ICP, guide9610Title: 'Ship first, tax second', @@ -64,8 +67,8 @@ composeLead: 'Ask about a lane, or pick a shortcut below', }, zh: { - welcomeTitle: 'IDE,全球数字化一站式跨境物流服务商', - welcomeTitleShort: 'IDE · 一站式跨境物流', + welcomeTitle: 'IDE,您身边的跨境物流顾问', + welcomeTitleShort: 'IDE · 跨境物流顾问', welcomeSubLead: '专线小包、国际快递、一件代发与 9610 报关,', welcomeSubAccent: '专为中小跨境卖家而生', welcomeSubTail: '。', @@ -75,11 +78,12 @@ you: '你', historyTitle: '历史记录', newChat: '新会话', + newChatHint: '已开启新会话,在这里提问', emptyHistory: '暂无会话', fallback: '官网不提供询价。完成注册登记后,即可在客户系统里看明码价。也可以先联系顾问。', trustPhone: PHONE, trustAddress: ADDRESS_ZH, - trustWechat: '微信 ' + WECHAT, + trustWechat: '微信客服', trustEmail: EMAIL, trustIcp: ICP, guide9610Title: '先发货,再办税', @@ -365,6 +369,7 @@ let historyListEl; let globeController = null; let coverageOpen = false; + let newChatTipTimer = null; const MAP_REGION_EU = new Set(['eu'].concat(COVER_EU.map((item) => item.mapId))); const MAP_REGION_AM = new Set(['us', 'mx', 'ca']); @@ -696,7 +701,8 @@ const rows = el('div', 'ai-card__rows'); [ [zh ? '电话' : 'Phone', PHONE], - [zh ? '微信' : 'WeChat', WECHAT], + [zh ? '微信客服' : 'WeCom', zh ? '扫码 / 手机直达' : 'Scan or tap to chat'], + [zh ? '微信号' : 'WeChat ID', WECHAT], [zh ? '邮箱' : 'Email', EMAIL], [zh ? '地址' : 'Address', zh ? ADDRESS_ZH : ADDRESS_EN], ].forEach(([label, value]) => { @@ -710,7 +716,9 @@ el( 'p', 'ai-card__body', - zh ? '要询价请先注册登记,或直接打电话、加微信。' : 'Register first to quote, or call / WeChat us directly.' + zh + ? '点「在线咨询」用微信对接顾问。询价请先注册登记。' + : 'Tap Live chat to reach an advisor on WeChat. Register first if you need a quote.' ) ); wrap.appendChild(contactActions()); @@ -817,15 +825,90 @@ return actions; } + function isWeChatEnv() { + return /MicroMessenger/i.test(navigator.userAgent); + } + + function isMobileEnv() { + return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent); + } + + function closeKfQrModal() { + document.getElementById('ide-kf-modal')?.remove(); + } + + function showKfQrModal(url) { + closeKfQrModal(); + const zh = lang === 'zh'; + const modal = document.createElement('div'); + modal.id = 'ide-kf-modal'; + modal.className = 'ide-kf-modal'; + modal.setAttribute('role', 'dialog'); + modal.setAttribute('aria-modal', 'true'); + modal.setAttribute('aria-label', zh ? '微信扫码咨询' : 'Scan to chat on WeChat'); + const qrSrc = + 'https://api.qrserver.com/v1/create-qr-code/?size=220x220&margin=8&data=' + + encodeURIComponent(url); + modal.innerHTML = ` +
+
+ +

${zh ? '企业微信客服' : 'WeCom support'}

+

${zh ? '微信扫码咨询' : 'Scan with WeChat'}

+

${zh ? '打开手机微信,扫一扫下方二维码即可对话顾问' : 'Open WeChat on your phone and scan the code to chat'}

+
+ WeCom QR + +
+ ${zh ? '在新窗口打开客服页' : 'Open support page'} +
+ `; + const qrImg = modal.querySelector('.ide-kf-modal__qr'); + const qrFallback = modal.querySelector('.ide-kf-modal__qr-fallback'); + qrImg?.addEventListener('error', () => { + qrImg.hidden = true; + if (qrFallback) qrFallback.hidden = false; + }); + modal.addEventListener('click', (e) => { + if (e.target.closest('[data-kf-close]')) closeKfQrModal(); + }); + document.addEventListener( + 'keydown', + function onEsc(e) { + if (e.key === 'Escape') { + closeKfQrModal(); + document.removeEventListener('keydown', onEsc); + } + }, + { once: true } + ); + document.body.appendChild(modal); + } + + /** 手机 / 微信内:直跳唤起会话;PC:弹二维码浮层 */ + function openWecomKf(e) { + if (e) e.preventDefault(); + const url = WECOM_KF_URL; + if (isWeChatEnv() || isMobileEnv()) { + window.location.href = url; + return; + } + showKfQrModal(url); + } + function contactActions() { const actions = el('div', 'ai-card__actions'); - const tel = el('a', 'ai-card-link is-primary', PHONE); + const kf = el('button', 'ai-card-link is-primary', lang === 'zh' ? '在线咨询' : 'Live chat'); + kf.type = 'button'; + kf.addEventListener('click', openWecomKf); + const tel = el('a', 'ai-card-link', PHONE); tel.href = `tel:${PHONE}`; const mail = el('a', 'ai-card-link', EMAIL); mail.href = `mailto:${EMAIL}`; - const wx = el('span', 'ai-card-link', (lang === 'zh' ? '微信 ' : 'WeChat ') + WECHAT); + actions.appendChild(kf); actions.appendChild(tel); - actions.appendChild(wx); actions.appendChild(mail); return actions; } @@ -899,6 +982,9 @@
+
@@ -909,31 +995,27 @@
-
- - - - - - - - - - -
-
-

- - -

- - - - -
+ + + + + + + + + + +

+ + +

+ + + +
@@ -987,19 +1069,7 @@ sendUserMessage(card.dataset.guideAsk, { intentId: card.dataset.guideIntent || 'hard' }); }); - shell.querySelector('.ai-trust-wechat').addEventListener('click', async () => { - const btn = shell.querySelector('.ai-trust-wechat'); - const label = btn.querySelector('.ai-trust-label'); - try { - await navigator.clipboard.writeText(WECHAT); - if (label) label.textContent = lang === 'zh' ? '微信已复制' : 'WeChat copied'; - } catch { - if (label) label.textContent = WECHAT; - } - window.setTimeout(() => { - if (label) label.textContent = t('trustWechat'); - }, 1600); - }); + shell.querySelector('.ai-trust-wechat').addEventListener('click', openWecomKf); shell.querySelector('.ai-composer-form').addEventListener('submit', (e) => { e.preventDefault(); @@ -1014,6 +1084,7 @@ }); inputEl.addEventListener('input', () => { + hideNewChatTip(); inputEl.style.height = 'auto'; inputEl.style.height = Math.min(inputEl.scrollHeight, 160) + 'px'; syncComposerSendState(); @@ -1344,6 +1415,7 @@ closeHistorySidebar(); return; } + hideNewChatTip(); syncActiveThreadMessages(); activeThreadId = threadId; applyThreadMessages(getActiveThread()); @@ -1355,13 +1427,45 @@ inputEl.focus(); } + function hideNewChatTip() { + const tip = shell?.querySelector('.ai-new-chat-tip'); + const wrap = shell?.querySelector('.ai-composer-wrap'); + if (newChatTipTimer) { + clearTimeout(newChatTipTimer); + newChatTipTimer = null; + } + if (tip) { + tip.classList.remove('is-visible'); + tip.hidden = true; + } + wrap?.classList.remove('has-new-chat-tip'); + } + + function showNewChatTip() { + const tip = shell?.querySelector('.ai-new-chat-tip'); + const wrap = shell?.querySelector('.ai-composer-wrap'); + const textEl = tip?.querySelector('.ai-new-chat-tip__text'); + if (!tip || !wrap || !textEl) return; + if (newChatTipTimer) clearTimeout(newChatTipTimer); + textEl.textContent = t('newChatHint'); + tip.hidden = false; + wrap.classList.add('has-new-chat-tip'); + // Restart enter animation if already visible + tip.classList.remove('is-visible'); + void tip.offsetWidth; + tip.classList.add('is-visible'); + newChatTipTimer = setTimeout(() => hideNewChatTip(), 4200); + } + function startNewChat() { if (isBusy) return; syncActiveThreadMessages(); const current = getActiveThread(); if (current && current.messages.length === 0) { closeHistorySidebar(); + updateViewMode(); inputEl.focus(); + showNewChatTip(); return; } createThread(true); @@ -1371,6 +1475,7 @@ closeHistorySidebar(); setNavActive('home'); inputEl.focus(); + showNewChatTip(); } function toggleHistorySidebar() { @@ -1462,6 +1567,8 @@ shell.querySelector('.ai-history-sidebar__title').textContent = t('historyTitle'); shell.querySelector('.ai-new-chat-btn__label').textContent = t('newChat'); shell.querySelector('.ai-new-chat-ghost__label').textContent = t('newChat'); + const tipText = shell.querySelector('.ai-new-chat-tip__text'); + if (tipText) tipText.textContent = t('newChatHint'); applyWelcomeTitle(); renderWelcomeSub(); const heroCta = shell.querySelector('.ai-welcome-cta'); @@ -1597,7 +1704,9 @@ if (intentId === 'human') { flow = null; return { - text: zh ? '直接打给我们或加微信。询价请先注册登记。' : 'Call or WeChat us. Register first if you need a quote.', + text: zh + ? '点「在线咨询」用微信对接顾问,也可打电话。询价请先注册登记。' + : 'Tap Live chat for WeChat support, or call us. Register first if you need a quote.', card: { type: 'contact' }, }; } @@ -1793,6 +1902,7 @@ } function sendUserMessage(text, extra) { + hideNewChatTip(); if (!text || isBusy || !shell) return; appendMessageRow('user', text, null, true); @@ -1895,6 +2005,8 @@ e.preventDefault(); openNavTopic('contact'); }); + + window.IDEOpenWecomKf = openWecomKf; } function init() { @@ -1913,7 +2025,10 @@ }); window.addEventListener('keydown', (e) => { - if (e.key === 'Escape') closeDrawers(); + if (e.key === 'Escape') { + closeKfQrModal(); + closeDrawers(); + } }); const bootTopic = (location.hash || '').replace('#', ''); @@ -1933,6 +2048,7 @@ if (!isHomePage()) window.location.href = '/'; }, close: () => closeDrawers(), + openWecomKf, }; if (document.readyState === 'loading') { diff --git a/IDE官网/assets/js/main.js b/IDE官网/assets/js/main.js index db67105..d8e5520 100644 --- a/IDE官网/assets/js/main.js +++ b/IDE官网/assets/js/main.js @@ -115,8 +115,9 @@ document.addEventListener('DOMContentLoaded', () => { const languageStorageKey = 'ide-language'; const pageTitleMap = { - 'IDE | Global Digital One-Stop Cross-Border Logistics': 'IDE | 全球数字化一站式跨境物流服务商', - 'IDE|Immediate Delivery Express — Cross-Border Logistics': 'IDE | 全球数字化一站式跨境物流服务商', + 'IDE - Cross-border Logistics, Delivered Globally': 'IDE - 跨境物流,全球即递', + 'IDE | Global Digital One-Stop Cross-Border Logistics': 'IDE - 跨境物流,全球即递', + 'IDE|Immediate Delivery Express — Cross-Border Logistics': 'IDE - 跨境物流,全球即递', 'Faster & Simpler': '更快 · 更简单', '|Faster & Simpler': '更快 · 更简单', 'IDE - About': 'IDE - 关于我们', @@ -394,7 +395,8 @@ document.addEventListener('DOMContentLoaded', () => { 'IDE logo': 'IDE标志', 'Immediate Delivery Express': 'Immediate Delivery Express' ,'IDE is a global digital one-stop cross-border logistics provider for SMB sellers and difficult orders — with smart systems and dedicated advisors at every step.': '体量不大、线路偏门?IDE 照样发。全球订单一站搞定,专属顾问从报价跟到签收,疑难单也有人管。' - ,'IDE | Global one-stop cross-border logistics solution provider': 'IDE | 全球一站式跨境物流解决方案服务商' + ,'IDE | Global one-stop cross-border logistics solution provider': 'IDE - 跨境物流,全球即递' + ,'IDE - Cross-border Logistics, Delivered Globally': 'IDE - 跨境物流,全球即递' ,'Explore Services': '了解服务' ,'Quote Response': '报价响应' ,'Global Routes': '全球线路' diff --git a/IDE官网/index.html b/IDE官网/index.html index 5d80eb9..eb0214e 100644 --- a/IDE官网/index.html +++ b/IDE官网/index.html @@ -5,7 +5,7 @@ - IDE | 全球数字化一站式跨境物流服务商 + IDE - 跨境物流,全球即递 @@ -20,7 +20,7 @@ - + @@ -85,7 +85,7 @@ - + diff --git a/src/api/customer/index.ts b/src/api/customer/index.ts index 290d807..ba74576 100644 --- a/src/api/customer/index.ts +++ b/src/api/customer/index.ts @@ -98,6 +98,7 @@ export interface CustomerServiceAdvisorDto { name?: string wechatId?: string wechatQrCode?: string + wecomKfUrl?: string } export const CustomerService = { diff --git a/src/api/order/index.ts b/src/api/order/index.ts index d6f054d..71f556b 100644 --- a/src/api/order/index.ts +++ b/src/api/order/index.ts @@ -1720,7 +1720,8 @@ export async function deleteOrderTemplateCustom(templateId: number) { export async function postOrderUpload( file: File, templateId: number, - senderAddressId?: number + senderAddressId?: number, + customerId?: number ): Promise<{ jobId: number; async: boolean }> { const form = new FormData() form.append('file', file) @@ -1728,6 +1729,9 @@ export async function postOrderUpload( if (senderAddressId != null && senderAddressId > 0) { form.append('senderAddressId', String(senderAddressId)) } + if (customerId != null && customerId > 0) { + form.append('customerId', String(customerId)) + } const res = await axiosInstance.post(orderUrl('/order/upload'), form) assertBusinessOk(res.data) const d = unwrapApiData(res.data) diff --git a/src/assets/icons/workplace/order-bind.svg b/src/assets/icons/workplace/order-bind.svg new file mode 100644 index 0000000..990f506 --- /dev/null +++ b/src/assets/icons/workplace/order-bind.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/workplace/order-dispatch.svg b/src/assets/icons/workplace/order-dispatch.svg new file mode 100644 index 0000000..ecc016e --- /dev/null +++ b/src/assets/icons/workplace/order-dispatch.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/workplace/order-inbound.svg b/src/assets/icons/workplace/order-inbound.svg new file mode 100644 index 0000000..e4b44bb --- /dev/null +++ b/src/assets/icons/workplace/order-inbound.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/icons/workplace/order-payment.svg b/src/assets/icons/workplace/order-payment.svg new file mode 100644 index 0000000..74a3135 --- /dev/null +++ b/src/assets/icons/workplace/order-payment.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/icons/workplace/order-pick.svg b/src/assets/icons/workplace/order-pick.svg new file mode 100644 index 0000000..7253d13 --- /dev/null +++ b/src/assets/icons/workplace/order-pick.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/icons/workplace/order-pickup.svg b/src/assets/icons/workplace/order-pickup.svg new file mode 100644 index 0000000..b91b7f8 --- /dev/null +++ b/src/assets/icons/workplace/order-pickup.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/workplace/order-transit.svg b/src/assets/icons/workplace/order-transit.svg new file mode 100644 index 0000000..28d96e2 --- /dev/null +++ b/src/assets/icons/workplace/order-transit.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/components/NanaAssistant/AiAdvisorShell.vue b/src/components/NanaAssistant/AiAdvisorShell.vue index b90a94e..aefcf60 100644 --- a/src/components/NanaAssistant/AiAdvisorShell.vue +++ b/src/components/NanaAssistant/AiAdvisorShell.vue @@ -252,8 +252,16 @@ {{ t('nanaAssistant.copyWechat') }} + -

{{ t('nanaAssistant.noAdvisor') }}

+
+

{{ t('nanaAssistant.noAdvisor') }}

+ +
@@ -303,6 +311,7 @@ import { type McpCapabilityId, } from '@/composables/assistantMcpGuide'; import { isMobileUserAgent, isWeChatBrowser } from '@/utils/device'; +import { openWecomKf } from '@/utils/wecomKf'; import { providerModelTags, } from '@/views/system/aiAssistant/providerCatalog'; @@ -690,6 +699,16 @@ async function loadAdvisor() { } function openAdvisorView() { + // H5 / 微信 / 手机:优先企业微信客服(即时会话);顾问个人链接优先 + if (route.path.startsWith('/h5') || isWeChatBrowser() || isMobileUserAgent()) { + void (async () => { + if (!advisorLoaded.value) { + await loadAdvisor(); + } + openWecomKf(advisor.value.wecomKfUrl); + })(); + return; + } advisorDrawerOpen.value = true; if (!advisorLoaded.value) { void loadAdvisor(); diff --git a/src/components/NanaAssistant/ai-advisor.css b/src/components/NanaAssistant/ai-advisor.css index 6b1e51b..515d305 100644 --- a/src/components/NanaAssistant/ai-advisor.css +++ b/src/components/NanaAssistant/ai-advisor.css @@ -1520,6 +1520,35 @@ background: rgba(45, 140, 140, 0.06); } +.ai-advisor-drawer__kf { + display: inline-flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 40px; + margin-top: 16px; + padding: 0 14px; + border: none; + border-radius: 4px; + background: var(--app-primary-color, #2d8c8c); + color: #fff; + font-size: 0.88rem; + font-weight: 600; + cursor: pointer; +} + +.ai-advisor-drawer__kf:hover { + filter: brightness(1.05); +} + +.ai-advisor-drawer__empty-wrap { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + width: 100%; +} + .ai-advisor-drawer__empty { font-size: 0.88rem; color: var(--kc-secondary, #6a75b8); diff --git a/src/components/UserEditDrawer/index.vue b/src/components/UserEditDrawer/index.vue index b890db7..a88716b 100644 --- a/src/components/UserEditDrawer/index.vue +++ b/src/components/UserEditDrawer/index.vue @@ -179,6 +179,15 @@ /> + + + + + + + + + ('phone', { default: '' }) const employeeNo = defineModel('employeeNo', { default: '' }) const wechatId = defineModel('wechatId', { default: '' }) +const wecomKfUrl = defineModel('wecomKfUrl', { default: '' }) const wechatQrFiles = defineModel('wechatQrFiles', { default: () => [] }) async function handleWechatCustomRequest(options: any) { diff --git a/src/locale/en-US.ts b/src/locale/en-US.ts index 51e4fef..0bf35d7 100644 --- a/src/locale/en-US.ts +++ b/src/locale/en-US.ts @@ -466,6 +466,7 @@ export default { 'user.senderAddress.table.senderName': 'Contact', 'user.senderAddress.table.phone': 'Phone', 'user.senderAddress.table.destCountry': 'Country', + 'user.senderAddress.table.country': 'Country', 'user.senderAddress.table.province': 'Province', 'user.senderAddress.table.city': 'City', 'user.senderAddress.table.address': 'Address', @@ -477,6 +478,7 @@ export default { 'user.senderAddress.form.phone': 'Phone', 'user.senderAddress.form.company': 'Company', 'user.senderAddress.form.destCountryCode': 'Country Code', + 'user.senderAddress.form.countryCode': 'Country Code', 'user.senderAddress.form.province': 'Province', 'user.senderAddress.form.city': 'City', 'user.senderAddress.form.zipCode': 'Zip Code', @@ -1256,7 +1258,8 @@ export default { 'nanaAssistant.mcp.field.product': 'Sales product code/name', 'nanaAssistant.mcp.field.cargoName': 'Cargo name', 'nanaAssistant.mcp.field.customsOrderNo': 'Waybill No.', - 'nanaAssistant.human': 'Talk to a human advisor →', + 'nanaAssistant.human': 'Talk to online advisor', + 'nanaAssistant.wecomKf': 'Chat on WeCom', 'nanaAssistant.you': 'You', 'nanaAssistant.backToChat': 'Back to chat', 'nanaAssistant.quickSmall': 'Small or difficult orders?', @@ -1265,7 +1268,7 @@ export default { 'nanaAssistant.quickTrack': 'Track my shipment', 'nanaAssistant.quickVisibility': 'Real-time tracking?', 'nanaAssistant.quickAfterSales': 'Something went wrong?', - 'nanaAssistant.quickHuman': 'Talk to human advisor', + 'nanaAssistant.quickHuman': 'Talk to online advisor', 'nanaAssistant.replySmall': 'Yes. IDE focuses on SMB sellers and shipments others decline — special routes, complex cargo, and low-volume orders are in scope. Tell me origin, destination, and cargo type to get started.', 'nanaAssistant.replyPrice': 'For a quote, destination destCountry + actual weight (kg) is enough — e.g. US 0.5kg. Postal code/dims help; origin city is not required.', 'nanaAssistant.replyQuoteSpeed': 'With destCountry + weight we can return an indicative quote right away; final billing follows inbound weight and product rules.', @@ -2050,6 +2053,7 @@ export default { 'order.priceCheck.table.viewGuide': 'Channel guide', 'order.priceCheck.table.viewGuideHint': 'Click to view route guide', 'order.priceCheck.table.customsOrderNow': 'Place order', + 'order.priceCheck.table.orderNow': 'Place order', 'order.priceCheck.table.askAi': 'Ask AI', 'order.priceCheck.table.askAiCanShip': 'Can this ship?', 'order.priceCheck.table.askAiCheaper': 'Anything cheaper?', @@ -2150,10 +2154,14 @@ export default { 'order.placeOrder.template.updatedAt': 'Updated: {time}', 'order.placeOrder.upload.dropText': 'Drag file here, or click to upload', - 'order.placeOrder.upload.tip1': 'Download the template: red headers are required; use dropdowns where provided.', - 'order.placeOrder.upload.tip2': 'Up to 2000 orders per upload. Pick a default sender below — do not put sender info in Excel.', 'order.placeOrder.batch.senderLabel': 'Default sender address', - 'order.placeOrder.batch.templateTip': 'Simple (recommended) and Standard (extended fields) templates available. Red headers are required; pick sender below.', + 'order.placeOrder.batch.senderPlaceholder': 'Select a sender address', + 'order.placeOrder.selectCustomer': 'Select customer', + 'order.placeOrder.customerLabel': 'Customer', + 'order.placeOrder.selectCustomerRequired': 'Select a customer first', + 'order.placeOrder.batch.templateTip': 'Red headers are required. Up to 2000 orders.', + 'order.placeOrder.batch.addressCardTitle': 'Customer & sender', + 'order.placeOrder.batch.addressTip': 'Choose sender here, not in Excel.', 'order.placeOrder.batch.block.noSender': 'Please select a default sender address', 'order.placeOrder.batchOrder': 'Batch order', 'order.placeOrder.fromPriceCheck.filled': @@ -2185,7 +2193,7 @@ export default { 'order.placeOrder.batch.stepUpload': 'Upload Excel', 'order.placeOrder.batch.stepSubmit': 'Submit', 'order.placeOrder.batch.guideHint': 'Click a step to jump · pick template on the right, then upload & submit', - 'order.placeOrder.batch.pickTemplateHint': 'Select a template from the library on the right', + 'order.placeOrder.batch.pickTemplateHint': 'Select a template', 'order.placeOrder.batch.block.noTemplate': 'Please select an order template on the right first', 'order.placeOrder.batch.block.templateDraft': 'Finish mapping this custom template before submitting', 'order.placeOrder.batch.block.noFile': 'Please upload an Excel file first', @@ -2222,7 +2230,6 @@ export default { 'order.placeOrder.single.senderEmpty': 'No sender address yet. Add one in Address Management first.', 'order.placeOrder.single.senderRequired': 'Please select a sender address', 'order.placeOrder.single.senderPickHint': 'Select sender address first', - 'order.placeOrder.single.senderClear': 'Clear sender', 'order.placeOrder.single.senderManage': 'Manage addresses', 'order.placeOrder.single.senderEditHint': 'Click to change sender', 'order.placeOrder.single.senderLoadFailed': 'Failed to load sender addresses', @@ -2241,6 +2248,8 @@ export default { 'order.placeOrder.contact.blockTitle': 'Complete your contact info', 'order.placeOrder.contact.blockDesc': 'Add phone and email to continue placing orders', 'order.placeOrder.contact.blockAction': 'Complete now', + 'order.placeOrder.contact.adminCustomerIncomplete': + 'The selected customer is missing phone or email. Complete their profile before placing the order.', 'order.placeOrder.single.viewCustomerGuide': 'View customer guide', 'order.placeOrder.single.declaredCurrencyHint': 'Default is USD; enter declared prices in that currency', 'order.placeOrder.single.exportCustomsPlaceholder': 'Optional (defaults to simplified declaration)', @@ -2760,6 +2769,8 @@ export default { 'system.user.form.employeeNoPlaceholder': 'Auto-generated', 'system.user.form.wechatId': 'WeChat ID', 'system.user.form.wechatIdPlaceholder': 'Enter WeChat ID', + 'system.user.form.wecomKfUrl': 'WeCom support link', + 'system.user.form.wecomKfUrlPlaceholder': 'e.g. https://work.weixin.qq.com/kfid/...', 'system.user.form.wechatQrCode': 'WeChat QR Code', 'system.user.form.wechatQrUpload': 'Upload QR code', 'system.user.table.employeeNo': 'Employee No.', diff --git a/src/locale/zh-CN.ts b/src/locale/zh-CN.ts index 6b5a000..5dded2a 100644 --- a/src/locale/zh-CN.ts +++ b/src/locale/zh-CN.ts @@ -467,6 +467,7 @@ export default { 'user.senderAddress.table.senderName': '联系人', 'user.senderAddress.table.phone': '手机', 'user.senderAddress.table.destCountry': '国家', + 'user.senderAddress.table.country': '国家', 'user.senderAddress.table.province': '省/州', 'user.senderAddress.table.city': '城市', 'user.senderAddress.table.address': '地址', @@ -478,6 +479,7 @@ export default { 'user.senderAddress.form.phone': '手机', 'user.senderAddress.form.company': '公司', 'user.senderAddress.form.destCountryCode': '国家二字码', + 'user.senderAddress.form.countryCode': '国家二字码', 'user.senderAddress.form.province': '省/州', 'user.senderAddress.form.city': '城市', 'user.senderAddress.form.zipCode': '邮编', @@ -1071,7 +1073,8 @@ export default { 'nanaAssistant.mcp.field.product': '销售产品代码/名称', 'nanaAssistant.mcp.field.cargoName': '客户品名', 'nanaAssistant.mcp.field.customsOrderNo': '运单号', - 'nanaAssistant.human': '联系人工顾问 →', + 'nanaAssistant.human': '联系在线顾问', + 'nanaAssistant.wecomKf': '企业微信在线咨询', 'nanaAssistant.you': '你', 'nanaAssistant.backToChat': '返回对话', 'nanaAssistant.quickSmall': '小批量 / 疑难单能发吗?', @@ -1080,7 +1083,7 @@ export default { 'nanaAssistant.quickTrack': '查物流单号', 'nanaAssistant.quickVisibility': '能实时追踪吗?', 'nanaAssistant.quickAfterSales': '出问题了怎么办?', - 'nanaAssistant.quickHuman': '联系人工顾问', + 'nanaAssistant.quickHuman': '联系在线顾问', 'nanaAssistant.replySmall': '可以。IDE 专注中小卖家和别人不接的单 — 特殊线路、复杂货型、小批量都在服务范围内。告诉我起运地、目的地和货型即可开始。', 'nanaAssistant.replyPrice': '查价只需目的国和实重(kg)。例如:美国 0.5kg。有邮编/尺寸会更准;不需要起运地。', 'nanaAssistant.replyQuoteSpeed': '提交目的国和重量后可即时试算参考价;正式出账以入仓重与产品规则为准。', @@ -1969,6 +1972,7 @@ export default { 'order.priceCheck.table.viewGuide': '渠道说明', 'order.priceCheck.table.viewGuideHint': '点击查看线路说明', 'order.priceCheck.table.customsOrderNow': '立刻下单', + 'order.priceCheck.table.orderNow': '立刻下单', 'order.priceCheck.table.askAi': '问 AI', 'order.priceCheck.table.askAiCanShip': '这个能不能发?', 'order.priceCheck.table.askAiCheaper': '有没有更便宜?', @@ -2070,10 +2074,14 @@ export default { 'order.placeOrder.template.updatedAt': '更新: {time}', 'order.placeOrder.upload.dropText': '将文件拖到此处,或点击上传', - 'order.placeOrder.upload.tip1': '请下载模板填写:红色表头为必填,带下拉的列请点选编码。', - 'order.placeOrder.upload.tip2': '单次最多 2000 单;发件人请在下方选择,无需写入 Excel。', 'order.placeOrder.batch.senderLabel': '默认发件地址', - 'order.placeOrder.batch.templateTip': '提供精简版(日常推荐)与标准版(含扩展字段);红色表头必填,发件人在下方选择。', + 'order.placeOrder.batch.senderPlaceholder': '请选择发件人地址', + 'order.placeOrder.selectCustomer': '请选择客户', + 'order.placeOrder.customerLabel': '客户', + 'order.placeOrder.selectCustomerRequired': '请先选择客户', + 'order.placeOrder.batch.templateTip': '红色表头必填,单次最多 2000 单。', + 'order.placeOrder.batch.addressCardTitle': '客户地址', + 'order.placeOrder.batch.addressTip': '发件人在此选择,不必写入 Excel。', 'order.placeOrder.batch.block.noSender': '请选择默认发件地址', 'order.placeOrder.batchOrder': '批量下单', 'order.placeOrder.fromPriceCheck.filled': '已带入查价所选渠道与包裹信息,请继续完善收件人', @@ -2104,7 +2112,7 @@ export default { 'order.placeOrder.batch.stepUpload': '上传 Excel', 'order.placeOrder.batch.stepSubmit': '提交下单', 'order.placeOrder.batch.guideHint': '点步骤可定位 · 右侧选模板,左侧上传后提交', - 'order.placeOrder.batch.pickTemplateHint': '请在右侧模板库点击选择模板', + 'order.placeOrder.batch.pickTemplateHint': '请选择模板', 'order.placeOrder.batch.block.noTemplate': '请先在右侧选择下单模板', 'order.placeOrder.batch.block.templateDraft': '当前自定义模板待编辑完成映射后才能提交', 'order.placeOrder.batch.block.noFile': '请先上传 Excel 文件', @@ -2141,7 +2149,6 @@ export default { 'order.placeOrder.single.senderEmpty': '暂无发件人地址,请先在地址管理中新增', 'order.placeOrder.single.senderRequired': '请选择发件人地址', 'order.placeOrder.single.senderPickHint': '请先选择发件地址', - 'order.placeOrder.single.senderClear': '清空发件人', 'order.placeOrder.single.senderManage': '去地址管理', 'order.placeOrder.single.senderEditHint': '点击可更换发件人', 'order.placeOrder.single.senderLoadFailed': '加载发件地址失败', @@ -2160,6 +2167,8 @@ export default { 'order.placeOrder.contact.blockTitle': '请先完善联系方式', 'order.placeOrder.contact.blockDesc': '补全手机号和邮箱后,即可继续下单', 'order.placeOrder.contact.blockAction': '去完善', + 'order.placeOrder.contact.adminCustomerIncomplete': + '所选客户尚未完善手机号和邮箱,请先在客户资料中补全后再下单', 'order.placeOrder.single.viewCustomerGuide': '查看对客说明', 'order.placeOrder.single.declaredCurrencyHint': '默认美元,请按币种填写申报价格', 'order.placeOrder.single.exportCustomsPlaceholder': '请选择(可不选,默认简易申报)', @@ -2684,6 +2693,8 @@ export default { 'system.user.form.employeeNoPlaceholder': '自动生成', 'system.user.form.wechatId': '微信号', 'system.user.form.wechatIdPlaceholder': '请输入微信号', + 'system.user.form.wecomKfUrl': '企业微信接入链接', + 'system.user.form.wecomKfUrlPlaceholder': '如 https://work.weixin.qq.com/kfid/...', 'system.user.form.wechatQrCode': '微信二维码', 'system.user.form.wechatQrUpload': '上传二维码', 'system.user.table.employeeNo': '工号', diff --git a/src/types/rbac-user-profile.ts b/src/types/rbac-user-profile.ts index 2125f9b..df4b171 100644 --- a/src/types/rbac-user-profile.ts +++ b/src/types/rbac-user-profile.ts @@ -3,6 +3,8 @@ export type UserProfileExt = { employeeNo?: string wechatId?: string wechatQrCode?: string + /** 企业微信客服接入链接(微信外接入) */ + wecomKfUrl?: string } export type UserFormExtState = UserProfileExt & { @@ -32,6 +34,7 @@ export function pickUserProfileExt( employeeNo: pickStr(user, 'employeeNo', 'EmployeeNo'), wechatId: pickStr(user, 'wechatId', 'WechatId'), wechatQrCode: pickStr(user, 'wechatQrCode', 'WechatQrCode'), + wecomKfUrl: pickStr(user, 'wecomKfUrl', 'WecomKfUrl'), } } @@ -45,5 +48,6 @@ export function toUserProfilePayload(state: UserFormExtState): UserProfileExt { employeeNo: state.employeeNo?.trim() || undefined, wechatId: state.wechatId?.trim() || undefined, wechatQrCode: (fromFile ? String(fromFile) : state.wechatQrCode?.trim()) || undefined, + wecomKfUrl: state.wecomKfUrl?.trim() || undefined, } } diff --git a/src/utils/wecomKf.ts b/src/utils/wecomKf.ts new file mode 100644 index 0000000..7bbeedc --- /dev/null +++ b/src/utils/wecomKf.ts @@ -0,0 +1,39 @@ +import { isMobileUserAgent, isWeChatBrowser } from '@/utils/device'; + +/** + * 企业微信客服(微信外接入链接) + * 管理后台 → 微信客服 → 在微信外接入 → 复制 + * 可用 VITE_WECOM_KF_URL 覆盖;顾问资料里的 wecomKfUrl 优先 + */ +export const WECOM_KF_URL = ( + (import.meta.env.VITE_WECOM_KF_URL as string | undefined) || + 'https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a' +).trim(); + +/** + * 微信内 / 手机:直跳唤起客服会话 + * PC:打开企业微信客服页(自带扫码) + * @param url 可选,优先使用顾问个人接入链接 + */ +export function openWecomKf(url?: string | null): void { + const target = (url?.trim() || WECOM_KF_URL).trim(); + if (!target) return; + + if (isWeChatBrowser() || isMobileUserAgent()) { + window.location.href = target; + return; + } + + const w = 480; + const h = 720; + const left = Math.max(0, Math.round((window.screen.width - w) / 2)); + const top = Math.max(0, Math.round((window.screen.height - h) / 2)); + const popup = window.open( + target, + 'ide_wecom_kf', + `width=${w},height=${h},left=${left},top=${top},noopener,noreferrer`, + ); + if (!popup) { + window.location.href = target; + } +} diff --git a/src/views/h5/customer-center/locale/en-US.ts b/src/views/h5/customer-center/locale/en-US.ts index 89bb1dc..1a73a22 100644 --- a/src/views/h5/customer-center/locale/en-US.ts +++ b/src/views/h5/customer-center/locale/en-US.ts @@ -530,6 +530,7 @@ export default { 'h5.me.placeOrderDesc': 'Ship in a few taps', 'h5.me.section.services': 'Services', 'h5.me.section.account': 'Account', + 'h5.me.onlineKf': 'Dedicated advisor', 'h5.me.section.journey': 'Shipping guide', 'h5.storeOrders.title': 'Store orders', diff --git a/src/views/h5/customer-center/locale/zh-CN.ts b/src/views/h5/customer-center/locale/zh-CN.ts index b03d27f..14f2898 100644 --- a/src/views/h5/customer-center/locale/zh-CN.ts +++ b/src/views/h5/customer-center/locale/zh-CN.ts @@ -526,6 +526,7 @@ export default { 'h5.me.placeOrderDesc': '填好收件,一键寄出', 'h5.me.section.services': '常用服务', 'h5.me.section.account': '账户设置', + 'h5.me.onlineKf': '专属顾问', 'h5.me.section.journey': '发货指引', 'h5.storeOrders.title': '店铺订单', diff --git a/src/views/h5/customer-center/me/index.vue b/src/views/h5/customer-center/me/index.vue index 52156b3..7c3eec3 100644 --- a/src/views/h5/customer-center/me/index.vue +++ b/src/views/h5/customer-center/me/index.vue @@ -134,6 +134,13 @@ + - + +