feat(mpuniapp): 落地微官网商务日程预约与日历排期功能 (TDD)
- 新增 common/calendar.uts 日历工具,支持 Google Calendar、Outlook Live 与后端 RFC 5545 ICS 一键下载 - 扩展 common/types.uts,支持 appointment 卡片类型与日历预约参数契约 - 补齐 common/locale.uts 全球 7 种语言(含阿语 RTL)商务预约词条 - 在 pages/portal/index.uvue 中集成 Bento 预约卡片与底部预约抽屉 (Bottom Sheet) - 在 pages/portal/usePortal.uts 中增加预约雷达轨迹上报 (touchType: appointment) 闭环联动 CRM - 新增 mpuniapp/tests/appointment.test.ts 自动化单元测试套件并通过全部验证
这个提交包含在:
@@ -68,7 +68,16 @@ export type OmniMessageKey =
|
||||
| 'portal.copied_email'
|
||||
| 'portal.copied_telegram'
|
||||
| 'portal.copied_twitter'
|
||||
| 'portal.copied_wechat';
|
||||
| 'portal.copied_wechat'
|
||||
| 'portal.collect'
|
||||
| 'portal.collected'
|
||||
| 'portal.appointment'
|
||||
| 'portal.appointment_desc'
|
||||
| 'portal.book_now'
|
||||
| 'portal.google_cal'
|
||||
| 'portal.outlook_cal'
|
||||
| 'portal.ics_download'
|
||||
| 'portal.copied_meeting_link';
|
||||
|
||||
export interface OmniLocaleConfig {
|
||||
code: OmniLocale;
|
||||
@@ -132,6 +141,15 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': '已复制 Telegram 链接',
|
||||
'portal.copied_twitter': '已复制 X 链接',
|
||||
'portal.copied_wechat': '已复制微信号',
|
||||
'portal.collect': '收入大厅',
|
||||
'portal.collected': '已收入大厅',
|
||||
'portal.appointment': '商务预约',
|
||||
'portal.appointment_desc': '预约 30 分钟跨国视频会谈或展会现场洽谈',
|
||||
'portal.book_now': '立即排期',
|
||||
'portal.google_cal': 'Google 日历',
|
||||
'portal.outlook_cal': 'Outlook 日历',
|
||||
'portal.ics_download': '下载日历文件 (ICS)',
|
||||
'portal.copied_meeting_link': '已复制预约日历链接',
|
||||
},
|
||||
},
|
||||
'en-US': {
|
||||
@@ -188,6 +206,15 @@ 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.collect': 'Save to Hall',
|
||||
'portal.collected': 'Saved to Hall',
|
||||
'portal.appointment': 'Schedule Meeting',
|
||||
'portal.appointment_desc': 'Book a 30-min global video sync or in-person talk',
|
||||
'portal.book_now': 'Book Now',
|
||||
'portal.google_cal': 'Google Calendar',
|
||||
'portal.outlook_cal': 'Outlook Calendar',
|
||||
'portal.ics_download': 'Download ICS File',
|
||||
'portal.copied_meeting_link': 'Calendar link copied',
|
||||
},
|
||||
},
|
||||
'ar-SA': {
|
||||
@@ -244,6 +271,15 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'تم نسخ رابط تيليجرام',
|
||||
'portal.copied_twitter': 'تم نسخ رابط إكس',
|
||||
'portal.copied_wechat': 'تم نسخ معرف وي تشات',
|
||||
'portal.collect': 'حفظ في القاعة',
|
||||
'portal.collected': 'تم الحفظ في القاعة',
|
||||
'portal.appointment': 'حجز موعد',
|
||||
'portal.appointment_desc': 'احجز اجتماع فيديو عالمي لمدة 30 دقيقة أو محادثة شخصية',
|
||||
'portal.book_now': 'احجز الآن',
|
||||
'portal.google_cal': 'تقويم Google',
|
||||
'portal.outlook_cal': 'تقويم Outlook',
|
||||
'portal.ics_download': 'تنزيل ملف التقويم (ICS)',
|
||||
'portal.copied_meeting_link': 'تم نسخ رابط التقويم',
|
||||
},
|
||||
},
|
||||
'es-ES': {
|
||||
@@ -300,6 +336,15 @@ 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.collect': 'Guardar en el hall',
|
||||
'portal.collected': 'Guardado en el hall',
|
||||
'portal.appointment': 'Agendar Reunión',
|
||||
'portal.appointment_desc': 'Reserva una reunión virtual de 30 min o charla presencial',
|
||||
'portal.book_now': 'Agendar Ahora',
|
||||
'portal.google_cal': 'Google Calendar',
|
||||
'portal.outlook_cal': 'Outlook Calendar',
|
||||
'portal.ics_download': 'Descargar Archivo ICS',
|
||||
'portal.copied_meeting_link': 'Enlace de calendario copiado',
|
||||
},
|
||||
},
|
||||
'de-DE': {
|
||||
@@ -356,6 +401,15 @@ 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.collect': 'In die Halle legen',
|
||||
'portal.collected': 'In der Halle gespeichert',
|
||||
'portal.appointment': 'Termin vereinbaren',
|
||||
'portal.appointment_desc': 'Buchen Sie ein 30-minütiges globales Meeting',
|
||||
'portal.book_now': 'Jetzt buchen',
|
||||
'portal.google_cal': 'Google Kalender',
|
||||
'portal.outlook_cal': 'Outlook Kalender',
|
||||
'portal.ics_download': 'ICS-Datei herunterladen',
|
||||
'portal.copied_meeting_link': 'Kalenderlink kopiert',
|
||||
},
|
||||
},
|
||||
'fr-FR': {
|
||||
@@ -412,6 +466,15 @@ 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.collect': 'Ajouter au hall',
|
||||
'portal.collected': 'Ajouté au hall',
|
||||
'portal.appointment': 'Prendre Rendez-vous',
|
||||
'portal.appointment_desc': 'Réservez une réunion vidéo globale de 30 minutes',
|
||||
'portal.book_now': 'Réserver maintenant',
|
||||
'portal.google_cal': 'Google Agenda',
|
||||
'portal.outlook_cal': 'Outlook Calendrier',
|
||||
'portal.ics_download': 'Télécharger le fichier ICS',
|
||||
'portal.copied_meeting_link': 'Lien de calendrier copié',
|
||||
},
|
||||
},
|
||||
'ja-JP': {
|
||||
@@ -468,6 +531,15 @@ export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||||
'portal.copied_telegram': 'Telegram のリンクをコピーしました',
|
||||
'portal.copied_twitter': 'X のリンクをコピーしました',
|
||||
'portal.copied_wechat': 'WeChat ID をコピーしました',
|
||||
'portal.collect': 'ホールに保存',
|
||||
'portal.collected': 'ホールに保存しました',
|
||||
'portal.appointment': '日程を予約する',
|
||||
'portal.appointment_desc': '30分間のオンライン面談または商談を予約',
|
||||
'portal.book_now': '今すぐ予約',
|
||||
'portal.google_cal': 'Google カレンダー',
|
||||
'portal.outlook_cal': 'Outlook カレンダー',
|
||||
'portal.ics_download': 'ICSファイルをダウンロード',
|
||||
'portal.copied_meeting_link': 'カレンダーのリンクをコピーしました',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -495,7 +567,7 @@ function syncState(target: OmniLocale): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将任意语言标识规范化为 7 种主流语言之一(回退 en-US 出海默认)
|
||||
* 将任意语言标识规范化为 7 种主流语言之一(回退 en-US 国际默认)
|
||||
*/
|
||||
export function normalizeLocale(raw: string): OmniLocale {
|
||||
if (!raw || typeof raw !== 'string') {
|
||||
@@ -542,7 +614,7 @@ export function resolveDeviceLocale(raw: string): OmniLocale {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据出海访客的国家码映射主流语言或回退 fallback(默认 en-US)
|
||||
* 根据访客的国家码映射主流语言或回退 fallback(默认 en-US)
|
||||
*/
|
||||
export function resolveGeoLocale(countryCode?: string, fallback: string = 'en-US'): OmniLocale {
|
||||
if (!countryCode || !countryCode.trim()) {
|
||||
|
||||
在新工单中引用
屏蔽一个用户