feat: 增加全平台核心跨端数据契约与 TypeScript 类型体系
这个提交包含在:
254
admin/src/types/omni.ts
普通文件
254
admin/src/types/omni.ts
普通文件
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* OmniCard AI (CRMmp) - 全平台跨端核心数据契约与 TypeScript 类型体系
|
||||
*
|
||||
* 遵循出海 SaaS 规范、Bento Grid 便当盒美学与 RFC 6350 国际标准。
|
||||
* 供 后端服务 (Cool-Admin) 与 管理后台 (Arco Pro React) 共享镜像复用。
|
||||
* 严格类型安全,杜绝 any。
|
||||
*/
|
||||
|
||||
// ==========================================
|
||||
// 1. 名片与微官网契约 (Card Profile & Bento)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 名片生命周期状态
|
||||
*/
|
||||
export type CardStatus = 'draft' | 'published' | 'archived';
|
||||
|
||||
/**
|
||||
* CardProfile - 名片基础资料契约
|
||||
*/
|
||||
export interface CardProfile {
|
||||
/** 名片主键 ID */
|
||||
id: string | number;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 关联用户账号 ID */
|
||||
userId: string | number;
|
||||
/** 姓名 */
|
||||
name: string;
|
||||
/** 职业头衔/职位 */
|
||||
title: string;
|
||||
/** 所属企业/组织名称 */
|
||||
company: string;
|
||||
/** 个人签名 / 品牌 Slogan */
|
||||
slogan?: string;
|
||||
/** 头像 / 形象照 URL */
|
||||
avatarUrl?: string;
|
||||
/** 国际电话号码 (E.164 规范) */
|
||||
phone?: string;
|
||||
/** 电子邮箱 */
|
||||
email?: string;
|
||||
/** WhatsApp 国际直达账号/号码 */
|
||||
whatsapp?: string;
|
||||
/** LinkedIn 个人/企业主页链接 */
|
||||
linkedin?: string;
|
||||
/** 所在地时区 (如 'UTC+8', 'America/New_York') */
|
||||
timezone?: string;
|
||||
/** 姓名双语发音音频 URL (RFC 6350 语音扩展) */
|
||||
audioPronunciationUrl?: string;
|
||||
/** 名片状态 */
|
||||
status: CardStatus;
|
||||
/** 主题样式代码 (如 'corporate_navy', 'tech_dark', 'gold_luxe') */
|
||||
themeCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bento Grid 网格块类型
|
||||
*/
|
||||
export type BentoBlockType = 'hero' | 'case' | 'article' | 'social' | 'video' | 'form';
|
||||
|
||||
/**
|
||||
* Bento Grid 列跨度 (1列 / 2列满宽)
|
||||
*/
|
||||
export type BentoColSpan = 1 | 2;
|
||||
|
||||
/**
|
||||
* Bento Grid 行跨度 (1行 / 2行加高)
|
||||
*/
|
||||
export type BentoRowSpan = 1 | 2;
|
||||
|
||||
/**
|
||||
* BentoBlock - Bento Grid 网格块契约
|
||||
*/
|
||||
export interface BentoBlock {
|
||||
/** 网格块主键 ID */
|
||||
id: string | number;
|
||||
/** 所属名片 ID */
|
||||
cardId: string | number;
|
||||
/** 组件类型 */
|
||||
type: BentoBlockType;
|
||||
/** 栅格跨列 (1 | 2) */
|
||||
colSpan: BentoColSpan;
|
||||
/** 栅格跨行 (1 | 2) */
|
||||
rowSpan: BentoRowSpan;
|
||||
/** 排序序号 (从小到大排列) */
|
||||
sortOrder: number;
|
||||
/** 块标题 */
|
||||
title?: string;
|
||||
/** 块正文 / 描述 / 嵌入内容 */
|
||||
content?: string;
|
||||
/** 多媒体资源 URL (图片/视频封面/音频) */
|
||||
mediaUrl?: string;
|
||||
/** 目标跳转外链 URL */
|
||||
linkUrl?: string;
|
||||
/** 扩展元数据 JSON (支持序列化字符串或键值对字典,禁止 any) */
|
||||
metaJson?: string | Record<string, unknown>;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. 访客雷达与轻量级出海 CRM 契约 (Radar & Lead)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 潜客线索全生命周期跟进状态
|
||||
*/
|
||||
export type LeadStatus = 'new' | 'contacted' | 'hot' | 'won' | 'archived';
|
||||
|
||||
/**
|
||||
* 线索触达来源渠道
|
||||
*/
|
||||
export type LeadSource = 'nfc' | 'qr' | 'link' | 'ai_chat';
|
||||
|
||||
/**
|
||||
* LeadEntity - 潜客线索关系模型契约
|
||||
*/
|
||||
export interface LeadEntity {
|
||||
/** 线索主键 ID */
|
||||
id: string | number;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 来源名片 ID */
|
||||
cardId: string | number;
|
||||
/** 访客唯一追踪指纹 ID */
|
||||
visitorId: string;
|
||||
/** 客户姓名 */
|
||||
name: string;
|
||||
/** 客户所属企业名称 */
|
||||
company?: string;
|
||||
/** 联系电话 */
|
||||
phone?: string;
|
||||
/** 电子邮箱 */
|
||||
email?: string;
|
||||
/** 跟进状态 */
|
||||
status: LeadStatus;
|
||||
/** 意向度评分 (0 - 100) */
|
||||
intentScore: number;
|
||||
/** 触达来源途径 */
|
||||
source: LeadSource;
|
||||
/** 跟进备忘录 / 需求备注 */
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 访客触碰/打开途径
|
||||
*/
|
||||
export type TouchType = 'nfc' | 'qr' | 'link';
|
||||
|
||||
/**
|
||||
* RadarTrack - 实时访客足迹契约
|
||||
*/
|
||||
export interface RadarTrack {
|
||||
/** 轨迹记录主键 ID */
|
||||
id: string | number;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 访问的目标名片 ID */
|
||||
cardId: string | number;
|
||||
/** 访客唯一追踪指纹 ID */
|
||||
visitorId: string;
|
||||
/** 访客公网 IP 地址 */
|
||||
ip: string;
|
||||
/** 访客所在国家/地区 */
|
||||
country: string;
|
||||
/** 访客所在城市 */
|
||||
city: string;
|
||||
/** 触碰方式途径 */
|
||||
touchType: TouchType;
|
||||
/** 页面停留时长 (毫秒) */
|
||||
stayDurationMs: number;
|
||||
/** 页面最大滚动深度百分比 (0 - 100) */
|
||||
scrollDepth: number;
|
||||
/** 浏览过的 Bento 组件块标识列表 */
|
||||
viewedBlocks: string[];
|
||||
/** 访问时间戳 */
|
||||
createdAt: string | Date;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 3. NFC 实体卡设备台账契约 (NFC Fleet)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* NFC 卡片实体物理材质
|
||||
*/
|
||||
export type NFCMaterial = 'wood' | 'metal' | 'pvc';
|
||||
|
||||
/**
|
||||
* NFC 硬件设备生命周期状态
|
||||
*/
|
||||
export type NFCStatus = 'active' | 'suspended' | 'unbound';
|
||||
|
||||
/**
|
||||
* NFC 场景模式
|
||||
*/
|
||||
export type NFCSceneMode = 'business' | 'social';
|
||||
|
||||
/**
|
||||
* NFCRecord - NFC 实体卡设备台账契约
|
||||
*/
|
||||
export interface NFCRecord {
|
||||
/** 台账主键 ID */
|
||||
id: string | number;
|
||||
/** 硬件唯一识别芯片 UID (如 '04:7A:B2:8F:1C:6D:80') */
|
||||
uid: string;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 当前绑定的名片 ID (未绑定时为 null 或空) */
|
||||
cardId?: string | number | null;
|
||||
/** 硬件制造/下发批次号 */
|
||||
batchNo: string;
|
||||
/** 物理材质 */
|
||||
material: NFCMaterial;
|
||||
/** 设备状态 */
|
||||
status: NFCStatus;
|
||||
/** 场景模式 (如白天商务/夜晚社交) */
|
||||
sceneMode: NFCSceneMode;
|
||||
/** 最后一次被触碰扫描时间 */
|
||||
lastScannedAt?: string | Date | null;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 4. 企业租户与品牌 VI 契约 (Tenant & BrandKit)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 租户订阅商业版本套餐
|
||||
*/
|
||||
export type TenantPlanType = 'free' | 'pro' | 'enterprise';
|
||||
|
||||
/**
|
||||
* 品牌 VI 规范套件
|
||||
*/
|
||||
export interface BrandKit {
|
||||
/** 官方企业 Logo 图标 URL */
|
||||
logoUrl: string;
|
||||
/** 品牌标准主色调 (Hex 颜色代码,如 '#0B5CFF') */
|
||||
primaryColor: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* TenantProfile - 企业租户及品牌 VI 契约
|
||||
*/
|
||||
export interface TenantProfile {
|
||||
/** 租户主键 ID */
|
||||
id: string | number;
|
||||
/** 企业/团队官方名称 */
|
||||
companyName: string;
|
||||
/** 商业订阅版本 */
|
||||
planType: TenantPlanType;
|
||||
/** 自定义独立主域名 (如 'me.brand.com') */
|
||||
customDomain?: string | null;
|
||||
/** 统一品牌 VI 套件 */
|
||||
brandKit: BrandKit;
|
||||
}
|
||||
254
backend/src/comm/types/omni.ts
普通文件
254
backend/src/comm/types/omni.ts
普通文件
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* OmniCard AI (CRMmp) - 全平台跨端核心数据契约与 TypeScript 类型体系
|
||||
*
|
||||
* 遵循出海 SaaS 规范、Bento Grid 便当盒美学与 RFC 6350 国际标准。
|
||||
* 供 后端服务 (Cool-Admin) 与 管理后台 (Arco Pro React) 共享镜像复用。
|
||||
* 严格类型安全,杜绝 any。
|
||||
*/
|
||||
|
||||
// ==========================================
|
||||
// 1. 名片与微官网契约 (Card Profile & Bento)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 名片生命周期状态
|
||||
*/
|
||||
export type CardStatus = 'draft' | 'published' | 'archived';
|
||||
|
||||
/**
|
||||
* CardProfile - 名片基础资料契约
|
||||
*/
|
||||
export interface CardProfile {
|
||||
/** 名片主键 ID */
|
||||
id: string | number;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 关联用户账号 ID */
|
||||
userId: string | number;
|
||||
/** 姓名 */
|
||||
name: string;
|
||||
/** 职业头衔/职位 */
|
||||
title: string;
|
||||
/** 所属企业/组织名称 */
|
||||
company: string;
|
||||
/** 个人签名 / 品牌 Slogan */
|
||||
slogan?: string;
|
||||
/** 头像 / 形象照 URL */
|
||||
avatarUrl?: string;
|
||||
/** 国际电话号码 (E.164 规范) */
|
||||
phone?: string;
|
||||
/** 电子邮箱 */
|
||||
email?: string;
|
||||
/** WhatsApp 国际直达账号/号码 */
|
||||
whatsapp?: string;
|
||||
/** LinkedIn 个人/企业主页链接 */
|
||||
linkedin?: string;
|
||||
/** 所在地时区 (如 'UTC+8', 'America/New_York') */
|
||||
timezone?: string;
|
||||
/** 姓名双语发音音频 URL (RFC 6350 语音扩展) */
|
||||
audioPronunciationUrl?: string;
|
||||
/** 名片状态 */
|
||||
status: CardStatus;
|
||||
/** 主题样式代码 (如 'corporate_navy', 'tech_dark', 'gold_luxe') */
|
||||
themeCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bento Grid 网格块类型
|
||||
*/
|
||||
export type BentoBlockType = 'hero' | 'case' | 'article' | 'social' | 'video' | 'form';
|
||||
|
||||
/**
|
||||
* Bento Grid 列跨度 (1列 / 2列满宽)
|
||||
*/
|
||||
export type BentoColSpan = 1 | 2;
|
||||
|
||||
/**
|
||||
* Bento Grid 行跨度 (1行 / 2行加高)
|
||||
*/
|
||||
export type BentoRowSpan = 1 | 2;
|
||||
|
||||
/**
|
||||
* BentoBlock - Bento Grid 网格块契约
|
||||
*/
|
||||
export interface BentoBlock {
|
||||
/** 网格块主键 ID */
|
||||
id: string | number;
|
||||
/** 所属名片 ID */
|
||||
cardId: string | number;
|
||||
/** 组件类型 */
|
||||
type: BentoBlockType;
|
||||
/** 栅格跨列 (1 | 2) */
|
||||
colSpan: BentoColSpan;
|
||||
/** 栅格跨行 (1 | 2) */
|
||||
rowSpan: BentoRowSpan;
|
||||
/** 排序序号 (从小到大排列) */
|
||||
sortOrder: number;
|
||||
/** 块标题 */
|
||||
title?: string;
|
||||
/** 块正文 / 描述 / 嵌入内容 */
|
||||
content?: string;
|
||||
/** 多媒体资源 URL (图片/视频封面/音频) */
|
||||
mediaUrl?: string;
|
||||
/** 目标跳转外链 URL */
|
||||
linkUrl?: string;
|
||||
/** 扩展元数据 JSON (支持序列化字符串或键值对字典,禁止 any) */
|
||||
metaJson?: string | Record<string, unknown>;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. 访客雷达与轻量级出海 CRM 契约 (Radar & Lead)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 潜客线索全生命周期跟进状态
|
||||
*/
|
||||
export type LeadStatus = 'new' | 'contacted' | 'hot' | 'won' | 'archived';
|
||||
|
||||
/**
|
||||
* 线索触达来源渠道
|
||||
*/
|
||||
export type LeadSource = 'nfc' | 'qr' | 'link' | 'ai_chat';
|
||||
|
||||
/**
|
||||
* LeadEntity - 潜客线索关系模型契约
|
||||
*/
|
||||
export interface LeadEntity {
|
||||
/** 线索主键 ID */
|
||||
id: string | number;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 来源名片 ID */
|
||||
cardId: string | number;
|
||||
/** 访客唯一追踪指纹 ID */
|
||||
visitorId: string;
|
||||
/** 客户姓名 */
|
||||
name: string;
|
||||
/** 客户所属企业名称 */
|
||||
company?: string;
|
||||
/** 联系电话 */
|
||||
phone?: string;
|
||||
/** 电子邮箱 */
|
||||
email?: string;
|
||||
/** 跟进状态 */
|
||||
status: LeadStatus;
|
||||
/** 意向度评分 (0 - 100) */
|
||||
intentScore: number;
|
||||
/** 触达来源途径 */
|
||||
source: LeadSource;
|
||||
/** 跟进备忘录 / 需求备注 */
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 访客触碰/打开途径
|
||||
*/
|
||||
export type TouchType = 'nfc' | 'qr' | 'link';
|
||||
|
||||
/**
|
||||
* RadarTrack - 实时访客足迹契约
|
||||
*/
|
||||
export interface RadarTrack {
|
||||
/** 轨迹记录主键 ID */
|
||||
id: string | number;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 访问的目标名片 ID */
|
||||
cardId: string | number;
|
||||
/** 访客唯一追踪指纹 ID */
|
||||
visitorId: string;
|
||||
/** 访客公网 IP 地址 */
|
||||
ip: string;
|
||||
/** 访客所在国家/地区 */
|
||||
country: string;
|
||||
/** 访客所在城市 */
|
||||
city: string;
|
||||
/** 触碰方式途径 */
|
||||
touchType: TouchType;
|
||||
/** 页面停留时长 (毫秒) */
|
||||
stayDurationMs: number;
|
||||
/** 页面最大滚动深度百分比 (0 - 100) */
|
||||
scrollDepth: number;
|
||||
/** 浏览过的 Bento 组件块标识列表 */
|
||||
viewedBlocks: string[];
|
||||
/** 访问时间戳 */
|
||||
createdAt: string | Date;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 3. NFC 实体卡设备台账契约 (NFC Fleet)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* NFC 卡片实体物理材质
|
||||
*/
|
||||
export type NFCMaterial = 'wood' | 'metal' | 'pvc';
|
||||
|
||||
/**
|
||||
* NFC 硬件设备生命周期状态
|
||||
*/
|
||||
export type NFCStatus = 'active' | 'suspended' | 'unbound';
|
||||
|
||||
/**
|
||||
* NFC 场景模式
|
||||
*/
|
||||
export type NFCSceneMode = 'business' | 'social';
|
||||
|
||||
/**
|
||||
* NFCRecord - NFC 实体卡设备台账契约
|
||||
*/
|
||||
export interface NFCRecord {
|
||||
/** 台账主键 ID */
|
||||
id: string | number;
|
||||
/** 硬件唯一识别芯片 UID (如 '04:7A:B2:8F:1C:6D:80') */
|
||||
uid: string;
|
||||
/** 所属企业租户 ID */
|
||||
tenantId: string | number;
|
||||
/** 当前绑定的名片 ID (未绑定时为 null 或空) */
|
||||
cardId?: string | number | null;
|
||||
/** 硬件制造/下发批次号 */
|
||||
batchNo: string;
|
||||
/** 物理材质 */
|
||||
material: NFCMaterial;
|
||||
/** 设备状态 */
|
||||
status: NFCStatus;
|
||||
/** 场景模式 (如白天商务/夜晚社交) */
|
||||
sceneMode: NFCSceneMode;
|
||||
/** 最后一次被触碰扫描时间 */
|
||||
lastScannedAt?: string | Date | null;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 4. 企业租户与品牌 VI 契约 (Tenant & BrandKit)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 租户订阅商业版本套餐
|
||||
*/
|
||||
export type TenantPlanType = 'free' | 'pro' | 'enterprise';
|
||||
|
||||
/**
|
||||
* 品牌 VI 规范套件
|
||||
*/
|
||||
export interface BrandKit {
|
||||
/** 官方企业 Logo 图标 URL */
|
||||
logoUrl: string;
|
||||
/** 品牌标准主色调 (Hex 颜色代码,如 '#0B5CFF') */
|
||||
primaryColor: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* TenantProfile - 企业租户及品牌 VI 契约
|
||||
*/
|
||||
export interface TenantProfile {
|
||||
/** 租户主键 ID */
|
||||
id: string | number;
|
||||
/** 企业/团队官方名称 */
|
||||
companyName: string;
|
||||
/** 商业订阅版本 */
|
||||
planType: TenantPlanType;
|
||||
/** 自定义独立主域名 (如 'me.brand.com') */
|
||||
customDomain?: string | null;
|
||||
/** 统一品牌 VI 套件 */
|
||||
brandKit: BrandKit;
|
||||
}
|
||||
170
backend/test/comm/omni.test.ts
普通文件
170
backend/test/comm/omni.test.ts
普通文件
@@ -0,0 +1,170 @@
|
||||
import {
|
||||
CardProfile,
|
||||
CardStatus,
|
||||
BentoBlock,
|
||||
BentoBlockType,
|
||||
BentoColSpan,
|
||||
BentoRowSpan,
|
||||
LeadEntity,
|
||||
LeadStatus,
|
||||
LeadSource,
|
||||
RadarTrack,
|
||||
TouchType,
|
||||
NFCRecord,
|
||||
NFCMaterial,
|
||||
NFCStatus,
|
||||
NFCSceneMode,
|
||||
TenantProfile,
|
||||
TenantPlanType,
|
||||
BrandKit,
|
||||
} from '../../src/comm/types/omni';
|
||||
|
||||
describe('OmniCard AI 核心跨端数据契约与 TypeScript 类型体系测试', () => {
|
||||
it('应正确支持 CardProfile 契约及其字段与状态枚举', () => {
|
||||
const cardStatus: CardStatus = 'published';
|
||||
const card: CardProfile = {
|
||||
id: 'card_1001',
|
||||
tenantId: 'tenant_888',
|
||||
userId: 'user_001',
|
||||
name: 'Alex Rivera',
|
||||
title: 'Global VP of Business Development',
|
||||
company: 'OmniCard Global Ltd.',
|
||||
slogan: 'Empowering global trade with AI',
|
||||
avatarUrl: 'https://cdn.omnicard.ai/avatars/alex.jpg',
|
||||
phone: '+1-555-892-0199',
|
||||
email: 'alex@omnicard.ai',
|
||||
whatsapp: '+15558920199',
|
||||
linkedin: 'https://linkedin.com/in/alex-rivera-global',
|
||||
timezone: 'UTC+8',
|
||||
audioPronunciationUrl: 'https://cdn.omnicard.ai/audio/alex.mp3',
|
||||
status: cardStatus,
|
||||
themeCode: 'corporate_navy',
|
||||
};
|
||||
|
||||
expect(card.id).toBe('card_1001');
|
||||
expect(card.name).toBe('Alex Rivera');
|
||||
expect(card.status).toBe('published');
|
||||
expect(card.themeCode).toBe('corporate_navy');
|
||||
});
|
||||
|
||||
it('应正确支持 BentoBlock 契约与尺寸、网格类型约束', () => {
|
||||
const blockType: BentoBlockType = 'hero';
|
||||
const colSpan: BentoColSpan = 2;
|
||||
const rowSpan: BentoRowSpan = 1;
|
||||
|
||||
const block: BentoBlock = {
|
||||
id: 101,
|
||||
cardId: 1001,
|
||||
type: blockType,
|
||||
colSpan,
|
||||
rowSpan,
|
||||
sortOrder: 0,
|
||||
title: 'Hero Profile',
|
||||
content: 'Leading AI-driven digital identity across MENA and APAC markets.',
|
||||
mediaUrl: 'https://cdn.omnicard.ai/media/hero.png',
|
||||
linkUrl: 'https://omnicard.ai',
|
||||
metaJson: {
|
||||
accentColor: '#0B5CFF',
|
||||
badge: 'Top Speaker',
|
||||
},
|
||||
};
|
||||
|
||||
expect(block.type).toBe('hero');
|
||||
expect(block.colSpan).toBe(2);
|
||||
expect(block.rowSpan).toBe(1);
|
||||
expect(typeof block.sortOrder).toBe('number');
|
||||
});
|
||||
|
||||
it('应正确支持 LeadEntity 潜客线索契约与意向评分、状态流转', () => {
|
||||
const leadStatus: LeadStatus = 'hot';
|
||||
const leadSource: LeadSource = 'nfc';
|
||||
|
||||
const lead: LeadEntity = {
|
||||
id: 'lead_5001',
|
||||
tenantId: 'tenant_888',
|
||||
cardId: 'card_1001',
|
||||
visitorId: 'vis_ae_9921',
|
||||
name: 'Tariq Mansour',
|
||||
company: 'Dubai Energy Holding',
|
||||
phone: '+971-50-1234567',
|
||||
email: 'tariq@dubaienergy.ae',
|
||||
status: leadStatus,
|
||||
intentScore: 92,
|
||||
source: leadSource,
|
||||
notes: 'Met at GITEX 2026. Very interested in enterprise NFC fleet and multi-tenant branding.',
|
||||
};
|
||||
|
||||
expect(lead.status).toBe('hot');
|
||||
expect(lead.intentScore).toBe(92);
|
||||
expect(lead.source).toBe('nfc');
|
||||
expect(lead.company).toBe('Dubai Energy Holding');
|
||||
});
|
||||
|
||||
it('应正确支持 RadarTrack 实时访客足迹契约与时空数据追踪', () => {
|
||||
const touch: TouchType = 'qr';
|
||||
const now = new Date();
|
||||
|
||||
const track: RadarTrack = {
|
||||
id: 'radar_8001',
|
||||
tenantId: 'tenant_888',
|
||||
cardId: 'card_1001',
|
||||
visitorId: 'vis_de_4432',
|
||||
ip: '194.12.88.4',
|
||||
country: 'Germany',
|
||||
city: 'Frankfurt',
|
||||
touchType: touch,
|
||||
stayDurationMs: 185000,
|
||||
scrollDepth: 88,
|
||||
viewedBlocks: ['hero', 'case_energy', 'article_ai_2026'],
|
||||
createdAt: now,
|
||||
};
|
||||
|
||||
expect(track.touchType).toBe('qr');
|
||||
expect(track.country).toBe('Germany');
|
||||
expect(track.stayDurationMs).toBeGreaterThan(0);
|
||||
expect(track.viewedBlocks).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('应正确支持 NFCRecord 实体卡设备台账契约与生命周期状态', () => {
|
||||
const material: NFCMaterial = 'metal';
|
||||
const status: NFCStatus = 'active';
|
||||
const sceneMode: NFCSceneMode = 'business';
|
||||
|
||||
const nfcCard: NFCRecord = {
|
||||
id: 'nfc_9001',
|
||||
uid: '04:7A:B2:8F:1C:6D:80',
|
||||
tenantId: 'tenant_888',
|
||||
cardId: 'card_1001',
|
||||
batchNo: 'BATCH-2026-Q1-METAL',
|
||||
material,
|
||||
status,
|
||||
sceneMode,
|
||||
lastScannedAt: '2026-09-20T14:30:00.000Z',
|
||||
};
|
||||
|
||||
expect(nfcCard.material).toBe('metal');
|
||||
expect(nfcCard.status).toBe('active');
|
||||
expect(nfcCard.sceneMode).toBe('business');
|
||||
expect(nfcCard.uid).toBe('04:7A:B2:8F:1C:6D:80');
|
||||
});
|
||||
|
||||
it('应正确支持 TenantProfile 企业租户与 BrandKit 品牌 VI 契约', () => {
|
||||
const planType: TenantPlanType = 'enterprise';
|
||||
const brandKit: BrandKit = {
|
||||
logoUrl: 'https://cdn.omnicard.ai/brands/omnitech-logo.svg',
|
||||
primaryColor: '#0B5CFF',
|
||||
};
|
||||
|
||||
const tenant: TenantProfile = {
|
||||
id: 'tenant_888',
|
||||
companyName: 'OmniTech Global Inc.',
|
||||
planType,
|
||||
customDomain: 'vip.omnitech.com',
|
||||
brandKit,
|
||||
};
|
||||
|
||||
expect(tenant.planType).toBe('enterprise');
|
||||
expect(tenant.brandKit.primaryColor).toBe('#0B5CFF');
|
||||
expect(tenant.customDomain).toBe('vip.omnitech.com');
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户