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 自动化单元测试套件并通过全部验证
这个提交包含在:
wikiboss
2026-09-21 15:16:39 +08:00
父节点 e4882c7707
当前提交 2d3ff2f5bd
共有 6 个文件被更改,包括 600 次插入 和 4 次删除

查看文件

@@ -1325,6 +1325,235 @@ onUnload(() => {
margin-inline-start: 4px;
}
/* 6. 商务预约排期卡片与抽屉样式 (Bento Grid Appointment & Bottom Sheet) */
.appointment-card {
background: linear-gradient(135deg, #FFFFFF 0%, #F5F9FF 100%);
border: 1px solid rgba(0, 136, 255, 0.15);
}
.appointment-tag {
background-color: var(--oc-primary-soft, #EBF5FF);
}
.appointment-card-body {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.appointment-info-col {
flex: 1;
display: flex;
flex-direction: column;
}
.appointment-card-title {
font-size: 15px;
font-weight: 700;
color: var(--oc-text, #101828);
margin-block-end: 4px;
line-height: 1.3;
}
.appointment-card-desc {
font-size: 13px;
color: var(--oc-text-2, #64748B);
line-height: 1.45;
margin-block-end: 8px;
}
.appointment-tz-badge {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 6px;
padding: 3px 8px;
background-color: #FFFFFF;
border: 1px solid var(--oc-border, #EBF1F7);
border-radius: 9999px;
width: fit-content;
}
.appointment-tz-text {
font-size: 11px;
color: var(--oc-text-2, #64748B);
font-weight: 500;
}
.appointment-action-pill {
height: 40px;
min-height: 40px;
min-width: 90px;
padding: 0 16px;
background: var(--oc-primary-gradient, linear-gradient(135deg, #00A3FF 0%, #0B63E5 100%));
border-radius: var(--oc-radius-pill, 9999px);
border-width: 0;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 136, 255, 0.2);
cursor: pointer;
}
.appointment-action-pill:active {
opacity: 0.85;
}
.appointment-action-text {
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
}
/* 预约底部抽屉 */
.appointment-sheet-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(16, 24, 40, 0.45);
backdrop-filter: blur(4px);
z-index: 200;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.appointment-sheet {
background-color: #FFFFFF;
border-top-left-radius: 24px;
border-top-right-radius: 24px;
padding: 12px 20px calc(24px + env(safe-area-inset-bottom, 0px));
box-shadow: var(--oc-shadow-float, 0 12px 36px rgba(16, 24, 40, 0.08));
}
.sheet-handle {
width: 36px;
height: 4px;
background-color: #D0D5DD;
border-radius: 2px;
margin: 0 auto 16px;
}
.sheet-header {
margin-block-end: 16px;
}
.sheet-title-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin-block-end: 4px;
}
.sheet-title {
font-size: 18px;
font-weight: 700;
color: var(--oc-text, #101828);
}
.sheet-close {
font-size: 18px;
color: #98A2B3;
padding: 4px 8px;
cursor: pointer;
}
.sheet-subtitle {
font-size: 13px;
color: var(--oc-text-2, #64748B);
}
.sheet-meeting-details {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
background-color: var(--oc-bg, #F5F8FC);
border-radius: 12px;
padding: 10px 14px;
margin-block-end: 16px;
}
.sheet-detail-row {
display: flex;
flex-direction: column;
}
.sheet-detail-label {
font-size: 10px;
font-weight: 600;
color: #98A2B3;
letter-spacing: 0.5px;
}
.sheet-detail-val {
font-size: 13px;
font-weight: 600;
color: var(--oc-text, #101828);
margin-top: 2px;
}
.calendar-channels-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.calendar-channel-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 12px 14px;
min-height: 44px;
background-color: #FFFFFF;
border: 1px solid var(--oc-border, #EBF1F7);
border-radius: 14px;
cursor: pointer;
transition: border-color 150ms ease;
}
.calendar-channel-item:active {
background-color: #F8FAFC;
border-color: #B2D7FF;
}
.channel-info {
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
}
.channel-icon-badge {
width: 36px;
height: 36px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.google-badge {
background-color: #FEF3F2;
}
.outlook-badge {
background-color: #EFF8FF;
}
.ics-badge {
background-color: #ECFDF3;
}
.channel-icon-text {
font-size: 12px;
font-weight: 700;
}
.google-badge .channel-icon-text {
color: #D92D20;
}
.outlook-badge .channel-icon-text {
color: #026AA2;
}
.ics-badge .channel-icon-text {
color: #027A48;
}
.channel-texts {
display: flex;
flex-direction: column;
}
.channel-name {
font-size: 14px;
font-weight: 600;
color: var(--oc-text, #101828);
}
.channel-sub {
font-size: 11px;
color: var(--oc-text-2, #64748B);
margin-top: 2px;
}
.channel-action-arrow {
font-size: 14px;
font-weight: 600;
color: #98A2B3;
}
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;

查看文件

@@ -435,6 +435,31 @@ export function resolvePortalCollectText(
return getOmniText(loc, 'portal.collect');
}
/**
* 预约动作雷达轨迹上报,自动推进 CRM 商机流转
*/
export async function trackAppointmentAction(
state: PortalState,
meetingSummary?: string
): Promise<boolean> {
if (state.card == null || state.card!.id == null) {
return false;
}
try {
await recordRadarTrack({
cardId: state.card!.id,
visitorId: state.visitorId,
touchType: 'appointment',
stayDurationMs: Math.max(0, Date.now() - state.enterTime),
scrollDepth: 100,
});
return true;
} catch (_e) {
return false;
}
}
export const OWNER_CARD_IDS_STORAGE_KEY = 'omni_owner_card_ids';
/**