文件
OmniCard/mpuniapp/pages/owner/workplace/useWorkplace.uts
wikiboss 62e0ae4435 feat: 同步管理端、用户端与后端业务,并接通线上 Web 接口
补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 18:01:47 +08:00

331 行
8.7 KiB
Plaintext

/**
* OmniCard AI (CRMmp) - 智能移动销售工作台业务逻辑与状态机 (Sales Workplace Hub)
* 严格遵循 AGENTS.md 规范与 uts 强类型设计
*/
import {
CardProfile,
LeadEntity,
WorkplaceKpi,
WorkplaceOverviewResult,
WorkplaceRadarItem,
} from '../../../common/types.uts';
import {
fetchCardQrcodeSvg,
fetchOwnerCardPage,
fetchOwnerLeadPage,
fetchWorkplaceOverview,
} from '../../../common/api.uts';
import { getCurrentLocale } from '../../../common/locale.uts';
export interface WorkplaceState {
loading: boolean;
errorMessage: string;
activeCard: CardProfile | null;
cardList: CardProfile[];
activeQrSvg: string;
activeShareUrl: string;
kpis: WorkplaceKpi;
hotRadarItem: WorkplaceRadarItem | null;
recentLeads: LeadEntity[];
radarOnline: boolean;
}
export function createWorkplaceState(): WorkplaceState {
return {
loading: true,
errorMessage: '',
activeCard: null,
cardList: [],
activeQrSvg: '',
activeShareUrl: '',
kpis: {
tapCount: 0,
viewCount: 0,
newLeadCount: 0,
conversionRate: 0,
tapDelta: 0,
viewDelta: 0,
newLeadDelta: 0,
},
hotRadarItem: null,
recentLeads: [],
radarOnline: true,
};
}
export async function loadWorkplaceData(state: WorkplaceState): Promise<void> {
state.loading = true;
state.errorMessage = '';
try {
// 1. 并行获取工作台概览、名片列表、最新待跟进线索
const overviewPromise = fetchWorkplaceOverview(5).then((data: WorkplaceOverviewResult) => {
state.radarOnline = true;
return data;
}).catch(() => {
state.radarOnline = false;
const emptyKpi: WorkplaceKpi = {
tapCount: 0,
viewCount: 0,
newLeadCount: 0,
conversionRate: 0,
tapDelta: 0,
viewDelta: 0,
newLeadDelta: 0,
};
const emptyResult: WorkplaceOverviewResult = {
kpis: emptyKpi,
radarFeed: [],
};
return emptyResult;
});
const cardsPromise = fetchOwnerCardPage({ page: 1, size: 10 }).catch(() => null);
const leadsPromise = fetchOwnerLeadPage({ page: 1, size: 3 }).catch(() => null);
const [overview, cardPage, leadPage] = await Promise.all([
overviewPromise,
cardsPromise,
leadsPromise,
]);
// 2. 赋值 KPI 与雷达高光
if (overview != null && overview.kpis != null) {
state.kpis = overview.kpis;
}
state.hotRadarItem = null;
if (overview != null && overview.radarFeed != null && overview.radarFeed.length > 0) {
state.hotRadarItem = overview.radarFeed[0];
}
if (leadPage != null && leadPage.list != null) {
state.recentLeads = leadPage.list;
} else {
state.recentLeads = [];
}
if (cardPage != null && cardPage.list != null && cardPage.list.length > 0) {
state.cardList = cardPage.list;
const published = cardPage.list.find((c: CardProfile) => c.status === 'published');
state.activeCard = published != null ? published : cardPage.list[0];
} else {
state.activeCard = null;
state.cardList = [];
state.activeQrSvg = '';
state.activeShareUrl = '';
}
if (state.activeCard != null) {
state.activeQrSvg = '';
state.activeShareUrl = '';
try {
const slugOrId = state.activeCard!.slug || String(state.activeCard!.id);
const qrRes = await fetchCardQrcodeSvg(slugOrId);
if (qrRes != null && qrRes.svg != null && qrRes.svg !== '') {
state.activeQrSvg = qrRes.svg;
} else {
state.activeQrSvg = '';
}
if (qrRes != null && qrRes.url != null && qrRes.url !== '') {
state.activeShareUrl = qrRes.url;
} else if (state.activeCard!.url != null && state.activeCard!.url !== '') {
state.activeShareUrl = state.activeCard!.url!;
}
} catch (_e) {
state.activeQrSvg = '';
state.activeShareUrl = '';
}
} else {
state.activeQrSvg = '';
state.activeShareUrl = '';
}
if (state.activeCard == null && state.recentLeads.length === 0 && state.radarOnline === false) {
state.errorMessage = resolveWorkplaceText('workplace.load_error');
}
} catch (_err) {
state.errorMessage = resolveWorkplaceText('workplace.load_error');
state.activeQrSvg = '';
state.activeShareUrl = '';
} finally {
state.loading = false;
}
}
export function buildPortalPreviewUrl(card: CardProfile): string {
if (card.slug != null && card.slug !== '') {
return `/pages/portal/index?slug=${card.slug}&mode=owner`;
}
if (card.id != null) {
return `/pages/portal/index?id=${card.id}&mode=owner`;
}
return '/pages/portal/index?mode=owner';
}
export function openCardPreview(card: CardProfile): void {
uni.navigateTo({
url: buildPortalPreviewUrl(card),
});
}
export function openCardQrcode(card: CardProfile): void {
const targetId = card.slug || String(card.id || '');
uni.navigateTo({
url: `/pages/owner/card/qrcode?id=${targetId}`,
});
}
export function openLeadDetail(leadId: string | number): void {
uni.navigateTo({
url: `/pages/owner/leads-detail?id=${leadId}`,
});
}
export function openRadarPage(): void {
uni.switchTab({
url: '/pages/owner/radar',
});
}
export function openCardsPage(): void {
uni.switchTab({
url: '/pages/owner/card/index',
});
}
export function openLeadsPage(): void {
uni.switchTab({
url: '/pages/owner/leads',
});
}
export function resolveWorkplaceText(key: string, locale?: string): string {
const targetLocale = locale != null ? locale : getCurrentLocale();
const isZh = targetLocale.startsWith('zh');
const dict: Record<string, Record<string, string>> = {
'workplace.title': {
zh: '销售工作台',
en: 'Sales Workplace',
},
'workplace.greeting': {
zh: '今日业务概况与线索跟进',
en: 'Today business overview & lead follow-up',
},
'workplace.radar_active': {
zh: '雷达在线监测中',
en: 'Radar Live Active',
},
'workplace.quick_showcase': {
zh: '出示名片',
en: 'Show Card',
},
'workplace.view_portal': {
zh: '预览微官网',
en: 'View Micro-Site',
},
'workplace.copy_link': {
zh: '复制直链',
en: 'Copy Link',
},
'workplace.link_copied': {
zh: '名片直链已复制',
en: 'Card link copied to clipboard',
},
'workplace.nfc_active': {
zh: 'NFC 展会模式就绪',
en: 'NFC Business Mode Ready',
},
'workplace.kpi_title': {
zh: '今日数据',
en: 'Today KPIs',
},
'workplace.kpi_taps': {
zh: '触碰/扫码',
en: 'Taps & Scans',
},
'workplace.kpi_visitors': {
zh: '官网访客数',
en: 'Visitors',
},
'workplace.kpi_leads': {
zh: '新增线索',
en: 'New Leads',
},
'workplace.kpi_conversion': {
zh: '意向转化率',
en: 'Intent Rate',
},
'workplace.radar_pulse_title': {
zh: '实时访客',
en: 'Live Visitors',
},
'workplace.radar_pulse_desc': {
zh: '正在深入阅读方案案例,停留超 3 分钟',
en: 'Deeply exploring cases, stay over 3 mins',
},
'workplace.radar_action_whatsapp': {
zh: '立即联系',
en: 'Contact Now',
},
'workplace.leads_todo_title': {
zh: '今日待办商机',
en: 'Actionable Leads',
},
'workplace.leads_view_all': {
zh: '查看全部',
en: 'View All',
},
'workplace.ai_tip_title': {
zh: '跟进建议',
en: 'Follow-up Suggestion',
},
'workplace.ai_tip_desc': {
zh: '近期重点客户对解决方案案例关注度上升,建议及时跟进。',
en: 'Prospect engagement on solution cases is rising. Follow-up recommended.',
},
'workplace.primary_cta': {
zh: '出示名片码',
en: 'Show Card QR',
},
'workplace.qr_empty': {
zh: '暂无二维码',
en: 'QR code unavailable',
},
'workplace.empty_card': {
zh: '还没有名片',
en: 'No card yet',
},
'workplace.empty_leads': {
zh: '今天还没有要跟进的线索',
en: 'No leads to follow up',
},
'workplace.empty_radar': {
zh: '还没有新的访客',
en: 'No new visitors',
},
'workplace.switch_card': {
zh: '切换',
en: 'Switch',
},
'workplace.published': {
zh: '已发布',
en: 'Published',
},
'workplace.load_error': {
zh: '工作台暂时没加载出来',
en: 'Workplace could not be loaded',
},
'workplace.score': {
zh: '意向',
en: 'Intent',
},
};
const item = dict[key];
if (item != null) {
return isZh ? item.zh : item.en;
}
return key;
}