feat: 同步管理端、用户端与后端业务,并接通线上 Web 接口

补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。

Co-authored-by: Cursor <cursoragent@cursor.com>
这个提交包含在:
wikiboss
2026-09-23 18:01:47 +08:00
父节点 8ea9c25386
当前提交 62e0ae4435
共有 227 个文件被更改,包括 21855 次插入 和 5264 次删除

查看文件

@@ -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';