feat: 同步管理端、用户端与后端业务,并接通线上 Web 接口
补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。 Co-authored-by: Cursor <cursoragent@cursor.com>
这个提交包含在:
@@ -55,6 +55,8 @@ export type OmniMessageKey =
|
||||
| 'portal.telegram'
|
||||
| 'portal.twitter'
|
||||
| 'portal.wechat'
|
||||
| 'portal.line'
|
||||
| 'portal.kakao'
|
||||
| 'portal.email'
|
||||
| 'portal.phone'
|
||||
| 'portal.case'
|
||||
@@ -71,6 +73,8 @@ export type OmniMessageKey =
|
||||
| 'portal.copied_telegram'
|
||||
| 'portal.copied_twitter'
|
||||
| 'portal.copied_wechat'
|
||||
| 'portal.copied_line'
|
||||
| 'portal.copied_kakao'
|
||||
| 'portal.collect'
|
||||
| 'portal.collected'
|
||||
| 'portal.appointment'
|
||||
@@ -96,7 +100,15 @@ export type OmniMessageKey =
|
||||
| 'portal.appointment_submit'
|
||||
| 'portal.appointment_submitting'
|
||||
| 'portal.appointment_success_tip'
|
||||
| 'portal.appointment_fill_required';
|
||||
| 'portal.appointment_fill_required'
|
||||
| 'portal.cookie_notice'
|
||||
| 'portal.cookie_accept'
|
||||
| 'portal.cookie_reject'
|
||||
| 'tab.workplace'
|
||||
| 'tab.card'
|
||||
| 'tab.radar'
|
||||
| 'tab.leads'
|
||||
| 'tab.profile';
|
||||
|
||||
export interface OmniLocaleConfig {
|
||||
code: OmniLocale;
|
||||
@@ -146,6 +158,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'Telegram',
|
||||
'portal.twitter': 'X',
|
||||
'portal.wechat': '微信',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': '邮件',
|
||||
'portal.phone': '电话',
|
||||
'portal.case': '客户案例',
|
||||
@@ -162,6 +176,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Telegram 账号已复制',
|
||||
'portal.copied_twitter': 'X (Twitter) 链接已复制',
|
||||
'portal.copied_wechat': '微信号已复制',
|
||||
'portal.copied_line': 'LINE 链接已复制',
|
||||
'portal.copied_kakao': 'KakaoTalk 链接已复制',
|
||||
'portal.collect': '收入名片夹',
|
||||
'portal.collected': '已收入',
|
||||
'portal.appointment': '预约商谈',
|
||||
@@ -188,6 +204,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': '提交中...',
|
||||
'portal.appointment_success_tip': '预约已提交,将尽快与您联系',
|
||||
'portal.appointment_fill_required': '请填写姓名和有效联系方式',
|
||||
'portal.cookie_notice': '我们使用 Cookie 改善体验并分析访问。继续浏览前请确认是否同意。',
|
||||
'portal.cookie_accept': '同意',
|
||||
'portal.cookie_reject': '拒绝',
|
||||
'tab.workplace': '工作台',
|
||||
'tab.card': '名片',
|
||||
'tab.radar': '雷达',
|
||||
'tab.leads': '潜客',
|
||||
'tab.profile': '我的',
|
||||
},
|
||||
},
|
||||
'en-US': {
|
||||
@@ -230,6 +254,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'Telegram',
|
||||
'portal.twitter': 'X',
|
||||
'portal.wechat': 'WeChat',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': 'Email',
|
||||
'portal.phone': 'Call',
|
||||
'portal.case': 'Case Study',
|
||||
@@ -246,6 +272,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Telegram link copied',
|
||||
'portal.copied_twitter': 'X link copied',
|
||||
'portal.copied_wechat': 'WeChat ID copied',
|
||||
'portal.copied_line': 'LINE link copied',
|
||||
'portal.copied_kakao': 'KakaoTalk link copied',
|
||||
'portal.collect': 'Save to Hall',
|
||||
'portal.collected': 'Saved to Hall',
|
||||
'portal.appointment': 'Book Appointment',
|
||||
@@ -272,6 +300,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': 'Submitting...',
|
||||
'portal.appointment_success_tip': 'Appointment submitted! We will contact you shortly.',
|
||||
'portal.appointment_fill_required': 'Please provide your name and contact info',
|
||||
'portal.cookie_notice': 'We use cookies to improve your experience and understand visits. Please choose before continuing.',
|
||||
'portal.cookie_accept': 'Accept',
|
||||
'portal.cookie_reject': 'Reject',
|
||||
'tab.workplace': 'Workplace',
|
||||
'tab.card': 'Card',
|
||||
'tab.radar': 'Radar',
|
||||
'tab.leads': 'Leads',
|
||||
'tab.profile': 'Profile',
|
||||
},
|
||||
},
|
||||
'ar-SA': {
|
||||
@@ -314,6 +350,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'تيليجرام',
|
||||
'portal.twitter': 'إكس',
|
||||
'portal.wechat': 'وي تشات',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': 'البريد',
|
||||
'portal.phone': 'اتصال',
|
||||
'portal.case': 'دراسات الحالة',
|
||||
@@ -330,6 +368,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'تم نسخ رابط تيليجرام',
|
||||
'portal.copied_twitter': 'تم نسخ رابط إكس',
|
||||
'portal.copied_wechat': 'تم نسخ معرف وي تشات',
|
||||
'portal.copied_line': 'تم نسخ رابط LINE',
|
||||
'portal.copied_kakao': 'تم نسخ رابط KakaoTalk',
|
||||
'portal.collect': 'حفظ في القاعة',
|
||||
'portal.collected': 'تم الحفظ في القاعة',
|
||||
'portal.appointment': 'حجز موعد',
|
||||
@@ -356,6 +396,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': 'جاري الإرسال...',
|
||||
'portal.appointment_success_tip': 'تم إرسال طلبك بنجاح! سيتواصل معك صاحب البطاقة قريباً.',
|
||||
'portal.appointment_fill_required': 'يرجى إدخال الاسم ومعلومات التواصل',
|
||||
'portal.cookie_notice': 'نستخدم ملفات تعريف الارتباط لتحسين تجربتك وفهم الزيارات. يرجى الاختيار قبل المتابعة.',
|
||||
'portal.cookie_accept': 'موافق',
|
||||
'portal.cookie_reject': 'رفض',
|
||||
'tab.workplace': 'المكتب',
|
||||
'tab.card': 'بطاقتي',
|
||||
'tab.radar': 'الرادار',
|
||||
'tab.leads': 'العملاء',
|
||||
'tab.profile': 'حسابي',
|
||||
},
|
||||
},
|
||||
'es-ES': {
|
||||
@@ -398,6 +446,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'Telegram',
|
||||
'portal.twitter': 'X',
|
||||
'portal.wechat': 'WeChat',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': 'Correo',
|
||||
'portal.phone': 'Llamar',
|
||||
'portal.case': 'Caso de éxito',
|
||||
@@ -414,6 +464,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Enlace de Telegram copiado',
|
||||
'portal.copied_twitter': 'Enlace de X copiado',
|
||||
'portal.copied_wechat': 'ID de WeChat copiado',
|
||||
'portal.copied_line': 'Enlace de LINE copiado',
|
||||
'portal.copied_kakao': 'Enlace de KakaoTalk copiado',
|
||||
'portal.collect': 'Guardar en el hall',
|
||||
'portal.collected': 'Guardado en el hall',
|
||||
'portal.appointment': 'Agendar Reunión',
|
||||
@@ -440,6 +492,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': 'Enviando...',
|
||||
'portal.appointment_success_tip': '¡Solicitud enviada! El titular se pondrá en contacto pronto.',
|
||||
'portal.appointment_fill_required': 'Por favor indica tu nombre y contacto',
|
||||
'portal.cookie_notice': 'Usamos cookies para mejorar tu experiencia y entender las visitas. Elige antes de continuar.',
|
||||
'portal.cookie_accept': 'Aceptar',
|
||||
'portal.cookie_reject': 'Rechazar',
|
||||
'tab.workplace': 'Panel',
|
||||
'tab.card': 'Tarjeta',
|
||||
'tab.radar': 'Radar',
|
||||
'tab.leads': 'Clientes',
|
||||
'tab.profile': 'Perfil',
|
||||
},
|
||||
},
|
||||
'de-DE': {
|
||||
@@ -482,6 +542,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'Telegram',
|
||||
'portal.twitter': 'X',
|
||||
'portal.wechat': 'WeChat',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': 'E-Mail',
|
||||
'portal.phone': 'Anrufen',
|
||||
'portal.case': 'Fallstudie',
|
||||
@@ -498,6 +560,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Telegram-Link kopiert',
|
||||
'portal.copied_twitter': 'X-Link kopiert',
|
||||
'portal.copied_wechat': 'WeChat-ID kopiert',
|
||||
'portal.copied_line': 'LINE-Link kopiert',
|
||||
'portal.copied_kakao': 'KakaoTalk-Link kopiert',
|
||||
'portal.collect': 'In die Halle legen',
|
||||
'portal.collected': 'In der Halle gespeichert',
|
||||
'portal.appointment': 'Termin vereinbaren',
|
||||
@@ -524,6 +588,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': 'Wird gesendet...',
|
||||
'portal.appointment_success_tip': 'Anfrage gesendet! Der Karteninhaber meldet sich in Kürze.',
|
||||
'portal.appointment_fill_required': 'Bitte Namen und Kontaktdaten angeben',
|
||||
'portal.cookie_notice': 'Wir verwenden Cookies, um Ihr Erlebnis zu verbessern und Besuche zu verstehen. Bitte wählen Sie vor dem Fortfahren.',
|
||||
'portal.cookie_accept': 'Akzeptieren',
|
||||
'portal.cookie_reject': 'Ablehnen',
|
||||
'tab.workplace': 'Cockpit',
|
||||
'tab.card': 'Karte',
|
||||
'tab.radar': 'Radar',
|
||||
'tab.leads': 'Leads',
|
||||
'tab.profile': 'Profil',
|
||||
},
|
||||
},
|
||||
'fr-FR': {
|
||||
@@ -566,6 +638,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'Telegram',
|
||||
'portal.twitter': 'X',
|
||||
'portal.wechat': 'WeChat',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': 'E-mail',
|
||||
'portal.phone': 'Appeler',
|
||||
'portal.case': 'Étude de cas',
|
||||
@@ -582,6 +656,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Lien Telegram copié',
|
||||
'portal.copied_twitter': 'Lien X copié',
|
||||
'portal.copied_wechat': 'Identifiant WeChat copié',
|
||||
'portal.copied_line': 'Lien LINE copié',
|
||||
'portal.copied_kakao': 'Lien KakaoTalk copié',
|
||||
'portal.collect': 'Ajouter au hall',
|
||||
'portal.collected': 'Ajouté au hall',
|
||||
'portal.appointment': 'Prendre Rendez-vous',
|
||||
@@ -608,6 +684,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': 'Envoi en cours...',
|
||||
'portal.appointment_success_tip': 'Demande envoyée ! Le titulaire vous contactera sous peu.',
|
||||
'portal.appointment_fill_required': 'Veuillez renseigner votre nom et vos coordonnées',
|
||||
'portal.cookie_notice': 'Nous utilisons des cookies pour améliorer votre expérience et comprendre les visites. Merci de choisir avant de continuer.',
|
||||
'portal.cookie_accept': 'Accepter',
|
||||
'portal.cookie_reject': 'Refuser',
|
||||
'tab.workplace': 'Tableau',
|
||||
'tab.card': 'Carte',
|
||||
'tab.radar': 'Radar',
|
||||
'tab.leads': 'Contacts',
|
||||
'tab.profile': 'Profil',
|
||||
},
|
||||
},
|
||||
'ja-JP': {
|
||||
@@ -650,6 +734,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.telegram': 'Telegram',
|
||||
'portal.twitter': 'X',
|
||||
'portal.wechat': 'WeChat',
|
||||
'portal.line': 'LINE',
|
||||
'portal.kakao': 'KakaoTalk',
|
||||
'portal.email': 'メール',
|
||||
'portal.phone': '電話する',
|
||||
'portal.case': '導入事例',
|
||||
@@ -666,6 +752,8 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Telegram のリンクをコピーしました',
|
||||
'portal.copied_twitter': 'X のリンクをコピーしました',
|
||||
'portal.copied_wechat': 'WeChat ID をコピーしました',
|
||||
'portal.copied_line': 'LINE のリンクをコピーしました',
|
||||
'portal.copied_kakao': 'KakaoTalk のリンクをコピーしました',
|
||||
'portal.collect': 'ホールに保存',
|
||||
'portal.collected': 'ホールに保存しました',
|
||||
'portal.appointment': '日程を予約する',
|
||||
@@ -692,6 +780,14 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.appointment_submitting': '送信中...',
|
||||
'portal.appointment_success_tip': 'ご予約を送信しました。担当者より追ってご連絡いたします。',
|
||||
'portal.appointment_fill_required': 'お名前とご連絡先を入力してください',
|
||||
'portal.cookie_notice': 'Cookie を使用して体験を向上し、訪問状況を把握します。続行前にご選択ください。',
|
||||
'portal.cookie_accept': '同意する',
|
||||
'portal.cookie_reject': '拒否する',
|
||||
'tab.workplace': 'ワーク',
|
||||
'tab.card': '名刺',
|
||||
'tab.radar': 'レーダー',
|
||||
'tab.leads': '見込み客',
|
||||
'tab.profile': 'マイ',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -869,6 +965,31 @@ export function getCurrentLocale(): OmniLocale {
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据语言刷新底部原生 TabBar 5 大菜单标题 (工作台, 名片, 雷达, 潜客, 我的)
|
||||
*/
|
||||
export function updateTabBarTitles(locale?: OmniLocale): void {
|
||||
const targetLocale = locale != null ? locale : getCurrentLocale();
|
||||
const items: Array<{ index: number; key: OmniMessageKey }> = [
|
||||
{ index: 0, key: 'tab.workplace' },
|
||||
{ index: 1, key: 'tab.card' },
|
||||
{ index: 2, key: 'tab.radar' },
|
||||
{ index: 3, key: 'tab.leads' },
|
||||
{ index: 4, key: 'tab.profile' },
|
||||
];
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
if (typeof uni !== 'undefined' && typeof uni.setTabBarItem === 'function') {
|
||||
uni.setTabBarItem({
|
||||
index: items[i].index,
|
||||
text: getOmniText(targetLocale, items[i].key),
|
||||
});
|
||||
}
|
||||
} catch (_e) {}
|
||||
}
|
||||
}
|
||||
|
||||
export function setAppLocale(lang: string): void {
|
||||
const normalized = normalizeLocale(lang);
|
||||
overrideLocale = normalized;
|
||||
@@ -876,11 +997,18 @@ export function setAppLocale(lang: string): void {
|
||||
try {
|
||||
uni.setStorageSync(PORTAL_LOCALE_STORAGE_KEY, normalized);
|
||||
} catch (_e) {}
|
||||
updateTabBarTitles(normalized);
|
||||
try {
|
||||
if (typeof uni !== 'undefined' && typeof uni.$emit === 'function') {
|
||||
uni.$emit('omni_locale_changed', normalized);
|
||||
}
|
||||
} catch (_e) {}
|
||||
}
|
||||
|
||||
export function initAppLocale(): OmniLocale {
|
||||
const current = detectLocale();
|
||||
syncState(current);
|
||||
updateTabBarTitles(current);
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { ApiResponse } from './types.uts';
|
||||
import { getCurrentLocale } from './locale.uts';
|
||||
|
||||
let currentBaseUrl: string = 'http://127.0.0.1:9000';
|
||||
// #ifdef H5
|
||||
@@ -161,6 +162,13 @@ export function request<T>(config: RequestConfig): Promise<T> {
|
||||
headers['x-tenant-id'] = tenantId;
|
||||
}
|
||||
|
||||
// 自动挂载客户端当前 Locale
|
||||
const currentLocale = getCurrentLocale();
|
||||
if (currentLocale) {
|
||||
headers['Accept-Language'] = currentLocale;
|
||||
headers['x-locale'] = currentLocale;
|
||||
}
|
||||
|
||||
// 显式传入的 header 具有更高优先级
|
||||
if (config.header) {
|
||||
Object.assign(headers, config.header);
|
||||
|
||||
@@ -181,6 +181,11 @@ export interface SubmitLeadParams {
|
||||
|
||||
export type TouchType = 'nfc' | 'qr' | 'link';
|
||||
|
||||
export interface RadarViewedContent {
|
||||
key: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface RadarTrack {
|
||||
id: string | number;
|
||||
tenantId?: string | number;
|
||||
@@ -193,7 +198,13 @@ export interface RadarTrack {
|
||||
stayDurationMs: number;
|
||||
scrollDepth: number;
|
||||
viewedBlocks: string[];
|
||||
viewedContents?: RadarViewedContent[];
|
||||
visitorName?: string;
|
||||
visitorCompany?: string;
|
||||
avatarUrl?: string;
|
||||
cardTitle?: string;
|
||||
createdAt?: string | Date;
|
||||
createTime?: string | Date;
|
||||
}
|
||||
|
||||
export interface RadarHotInbox {
|
||||
@@ -264,13 +275,15 @@ export interface QuotaCheckResult {
|
||||
plan?: string;
|
||||
}
|
||||
|
||||
export type OwnerPagePagination = {
|
||||
page: number;
|
||||
size: number;
|
||||
total: number;
|
||||
};
|
||||
|
||||
export interface OwnerPageData<T> {
|
||||
list: T[];
|
||||
pagination: {
|
||||
page: number;
|
||||
size: number;
|
||||
total: number;
|
||||
};
|
||||
pagination: OwnerPagePagination;
|
||||
}
|
||||
|
||||
export type AiChatRole = 'user' | 'assistant' | 'system';
|
||||
|
||||
在新工单中引用
屏蔽一个用户