- 新增 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 自动化单元测试套件并通过全部验证
121 行
3.9 KiB
Plaintext
121 行
3.9 KiB
Plaintext
/**
|
|
/**
|
|
* OmniCard AI (CRMmp) - 商务日程预约与日历服务 (UTS 强类型版本)
|
|
* 严格对齐 backend/src/modules/card/service/calendar.ts 规范
|
|
*/
|
|
|
|
import { MeetingInviteOptions, CalendarInviteBundle } from './types.uts';
|
|
import { getBaseUrl } from './request.uts';
|
|
|
|
/**
|
|
* 格式化 UTC 时间为 RFC 5545 日期时间戳 (YYYYMMDDTHHmmssZ)
|
|
*/
|
|
export function formatIcsDate(date: Date | string | number): string {
|
|
const d = date instanceof Date ? date : new Date(date);
|
|
if (isNaN(d.getTime())) {
|
|
return '';
|
|
}
|
|
const pad = (n: number): string => (n < 10 ? '0' + n : String(n));
|
|
const year = d.getUTCFullYear();
|
|
const month = pad(d.getUTCMonth() + 1);
|
|
const day = pad(d.getUTCDate());
|
|
const hours = pad(d.getUTCHours());
|
|
const minutes = pad(d.getUTCMinutes());
|
|
const seconds = pad(d.getUTCSeconds());
|
|
return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;
|
|
}
|
|
|
|
/**
|
|
* 格式化为 ISO 8601 字符串 (用于 Outlook)
|
|
*/
|
|
export function toIsoDate(date: Date | string | number): string {
|
|
const d = date instanceof Date ? date : new Date(date);
|
|
if (isNaN(d.getTime())) {
|
|
return '';
|
|
}
|
|
return d.toISOString();
|
|
}
|
|
|
|
/**
|
|
* 生成 Google Calendar Web 一键预约 URL
|
|
*/
|
|
export function generateGoogleCalendarUrl(meeting: MeetingInviteOptions): string {
|
|
const summary = meeting.summary || meeting.title || '商务洽谈';
|
|
const dtStart = formatIcsDate(meeting.startTime);
|
|
const dtEnd = formatIcsDate(meeting.endTime);
|
|
|
|
let details = meeting.description || '';
|
|
if (meeting.organizerEmail) {
|
|
details += `\nOrganizer: ${meeting.organizerEmail}`;
|
|
}
|
|
|
|
const queryParts: string[] = [
|
|
'action=TEMPLATE',
|
|
`text=${encodeURIComponent(summary)}`,
|
|
`dates=${encodeURIComponent(`${dtStart}/${dtEnd}`)}`,
|
|
`details=${encodeURIComponent(details.trim())}`,
|
|
`location=${encodeURIComponent(meeting.location || '')}`,
|
|
];
|
|
|
|
return `https://calendar.google.com/calendar/render?${queryParts.join('&')}`;
|
|
}
|
|
|
|
/**
|
|
* 生成 Outlook Live 一键预约 URL
|
|
*/
|
|
export function generateOutlookCalendarUrl(meeting: MeetingInviteOptions): string {
|
|
const summary = meeting.summary || meeting.title || '商务洽谈';
|
|
const startDt = toIsoDate(meeting.startTime);
|
|
const endDt = toIsoDate(meeting.endTime);
|
|
|
|
const queryParts: string[] = [
|
|
'path=%2Fcalendar%2Faction%2Fcompose',
|
|
'rru=addevent',
|
|
`subject=${encodeURIComponent(summary)}`,
|
|
`startdt=${encodeURIComponent(startDt)}`,
|
|
`enddt=${encodeURIComponent(endDt)}`,
|
|
`body=${encodeURIComponent(meeting.description || '')}`,
|
|
`location=${encodeURIComponent(meeting.location || '')}`,
|
|
];
|
|
|
|
return `https://outlook.live.com/calendar/0/deeplink/compose?${queryParts.join('&')}`;
|
|
}
|
|
|
|
/**
|
|
* 获取后端 RFC 5545 ICS 订阅文件下载 URL
|
|
*/
|
|
export function getMeetingIcsDownloadUrl(meeting: MeetingInviteOptions): string {
|
|
const baseUrl = getBaseUrl();
|
|
const summary = meeting.summary || meeting.title || '商务洽谈';
|
|
const dtStart = formatIcsDate(meeting.startTime);
|
|
const dtEnd = formatIcsDate(meeting.endTime);
|
|
|
|
const queryParts: string[] = [
|
|
`summary=${encodeURIComponent(summary)}`,
|
|
`startTime=${encodeURIComponent(dtStart)}`,
|
|
`endTime=${encodeURIComponent(dtEnd)}`,
|
|
`description=${encodeURIComponent(meeting.description || '')}`,
|
|
`location=${encodeURIComponent(meeting.location || '')}`,
|
|
];
|
|
|
|
if (meeting.organizerName) {
|
|
queryParts.push(`organizerName=${encodeURIComponent(meeting.organizerName)}`);
|
|
}
|
|
if (meeting.organizerEmail) {
|
|
queryParts.push(`organizerEmail=${encodeURIComponent(meeting.organizerEmail)}`);
|
|
}
|
|
|
|
return `${baseUrl}/open/card/portal/meeting-ics?${queryParts.join('&')}`;
|
|
}
|
|
|
|
/**
|
|
* 综合生成全平台日历预约包
|
|
*/
|
|
export function buildCalendarInviteBundle(meeting: MeetingInviteOptions): CalendarInviteBundle {
|
|
return {
|
|
googleUrl: generateGoogleCalendarUrl(meeting),
|
|
outlookUrl: generateOutlookCalendarUrl(meeting),
|
|
icsUrl: getMeetingIcsDownloadUrl(meeting),
|
|
};
|
|
}
|