feat(round-12): 实体卡外贸生产工单/雷达多渠道归因漏斗/AI地道外联草拟/现代图片自适应协商 (87套件1007测试全绿)

这个提交包含在:
wikiboss
2026-09-21 02:06:55 +08:00
父节点 76f0dc17c0
当前提交 3cfbed9e6a
共有 8 个文件被更改,包括 897 次插入 和 0 次删除

查看文件

@@ -0,0 +1,82 @@
import {
AiOutreachDraftService,
OutreachDraftRequest,
formatOutreachPrompt,
} from '../../../src/modules/ai/service/outreach';
describe('Point 47: AI 销售潜客智能跟进邮件/消息地道草拟引擎', () => {
let service: AiOutreachDraftService;
beforeEach(() => {
service = new AiOutreachDraftService();
});
describe('1. formatOutreachPrompt (出海商务邮件地道提示词组装)', () => {
it('英语场景应包含地道商务开场、兴趣针对性提及与日程预约呼吁', () => {
const req: OutreachDraftRequest = {
leadName: 'Arthur Pendelton',
company: 'Global Retail Alliance',
targetLanguage: 'en',
interestTopics: ['Bento Grid Micro-portal', 'Smart NFC Card'],
calendarUrl: 'https://calendar.google.com/render?action=TEMPLATE...',
tone: 'professional',
};
const prompt = formatOutreachPrompt(req);
expect(prompt).toContain('Arthur Pendelton');
expect(prompt).toContain('Global Retail Alliance');
expect(prompt).toContain('Bento Grid Micro-portal');
expect(prompt).toContain('professional');
expect(prompt).toContain('Call to Action');
});
it('阿拉伯语场景应要求符合中东商业礼仪与敬语规范', () => {
const req: OutreachDraftRequest = {
leadName: 'Sheikh Tariq Al-Mansoor',
company: 'Riyadh Holdings',
targetLanguage: 'ar',
interestTopics: ['NFC VIP Cards'],
tone: 'respectful',
};
const prompt = formatOutreachPrompt(req);
expect(prompt).toContain('Sheikh Tariq Al-Mansoor');
expect(prompt).toContain('Arabic');
expect(prompt).toContain('respectful');
});
});
describe('2. AiOutreachDraftService 草稿生成与结构化解析', () => {
it('应生成包含邮件主题、正文与预约链接的结构化草案', async () => {
const draft = await service.generateDraft({
leadName: 'Elena Rostova',
company: 'Nordic Trade Hub',
targetLanguage: 'en',
interestTopics: ['Visitor Radar CRM'],
senderName: 'Alex Zheng',
senderTitle: 'VP of International Sales',
});
expect(draft.subject).toBeDefined();
expect(draft.subject.length).toBeGreaterThan(0);
expect(draft.body).toContain('Elena Rostova');
expect(draft.body).toContain('Visitor Radar CRM');
expect(draft.body).toContain('Alex Zheng');
expect(draft.targetLanguage).toBe('en');
});
it('支持生成 WhatsApp 极简短消息格式 (short_im)', async () => {
const draft = await service.generateDraft({
leadName: 'Carlos Gomez',
company: 'Madrid Ventures',
targetLanguage: 'es',
channel: 'whatsapp',
senderName: 'Alex',
});
expect(draft.channel).toBe('whatsapp');
expect(draft.body).toContain('Carlos Gomez');
expect(draft.body.length).toBeLessThan(300); // 移动端短消息克制简洁
});
});
});

查看文件

@@ -0,0 +1,78 @@
import {
negotiateOptimalMediaUrl,
MediaNegotiationContext,
SupportedImageFormat,
} from '../../../src/modules/card/service/media-negotiator';
describe('Point 48: 移动微官网现代图片自适应协商与弱网资源压缩', () => {
const originalUrl = 'https://cdn.omnicard.ai/uploads/cards/vip-avatar.png';
describe('1. 格式协商 (Image Format Negotiation: AVIF > WebP > JPEG/PNG)', () => {
it('客户端声明支持 AVIF 时应优先协商为 AVIF 格式', () => {
const ctx: MediaNegotiationContext = {
acceptHeader: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
networkType: '4g',
};
const result = negotiateOptimalMediaUrl(originalUrl, ctx);
expect(result.format).toBe('avif');
expect(result.optimizedUrl).toContain('format=avif');
});
it('客户端不支持 AVIF 但支持 WebP 时应协商为 WebP', () => {
const ctx: MediaNegotiationContext = {
acceptHeader: 'image/webp,*/*',
networkType: 'wifi',
};
const result = negotiateOptimalMediaUrl(originalUrl, ctx);
expect(result.format).toBe('webp');
expect(result.optimizedUrl).toContain('format=webp');
});
it('旧版客户端不包含新现代格式时保留原有格式或转为 jpg', () => {
const ctx: MediaNegotiationContext = {
acceptHeader: 'image/png,image/*,*/*',
};
const result = negotiateOptimalMediaUrl(originalUrl, ctx);
expect(result.format).toBe('png');
expect(result.optimizedUrl).toContain('format=png');
});
});
describe('2. 网络环境与屏幕自适应 (Network & DPR Adaptive Scaling)', () => {
it('弱网 (2g/3g) 环境应自动降低图片质量与宽度以保障极致加载速度', () => {
const ctx: MediaNegotiationContext = {
acceptHeader: 'image/webp,*/*',
networkType: '3g',
targetWidth: 800,
};
const result = negotiateOptimalMediaUrl(originalUrl, ctx);
expect(result.quality).toBeLessThanOrEqual(70);
expect(result.width).toBeLessThanOrEqual(600);
expect(result.optimizedUrl).toContain(`w=${result.width}`);
expect(result.optimizedUrl).toContain(`q=${result.quality}`);
});
it('高速 WiFi 且高 DPR (dpr >= 2) 时应保障高清晰度', () => {
const ctx: MediaNegotiationContext = {
acceptHeader: 'image/avif,image/webp',
networkType: 'wifi',
targetWidth: 400,
dpr: 2,
};
const result = negotiateOptimalMediaUrl(originalUrl, ctx);
expect(result.width).toBe(800); // 400 * 2 = 800
expect(result.quality).toBeGreaterThanOrEqual(85);
expect(result.optimizedUrl).toContain('w=800');
});
it('无效或空 URL 时应安全回退', () => {
const res = negotiateOptimalMediaUrl('', {});
expect(res.optimizedUrl).toBe('');
});
});
});

查看文件

@@ -0,0 +1,82 @@
import {
RadarAttributionService,
normalizeTrafficChannel,
calculateAttributionFunnel,
ChannelAttributionEvent,
} from '../../../src/modules/crm/service/attribution';
describe('Point 46: 访客雷达多渠道来源归因与出海转化漏斗分析', () => {
let service: RadarAttributionService;
beforeEach(() => {
service = new RadarAttributionService();
});
describe('1. 流量渠道归一化解析 (normalizeTrafficChannel)', () => {
it('应精准识别 NFC 碰一碰与展位二维码', () => {
expect(normalizeTrafficChannel('nfc', 'tap')).toBe('nfc_tap');
expect(normalizeTrafficChannel('booth', 'qrcode')).toBe('booth_qr');
});
it('应精准识别 WhatsApp 与 LinkedIn 社交出海渠道', () => {
expect(normalizeTrafficChannel('whatsapp', 'im')).toBe('whatsapp_chat');
expect(normalizeTrafficChannel('linkedin', 'social')).toBe('linkedin_share');
expect(normalizeTrafficChannel('email', 'sig')).toBe('email_signature');
});
it('未知或直接访问归入 direct_or_organic', () => {
expect(normalizeTrafficChannel('', '')).toBe('direct_or_organic');
expect(normalizeTrafficChannel(undefined, undefined)).toBe('direct_or_organic');
});
});
describe('2. calculateAttributionFunnel (5阶段留资转化漏斗计算)', () => {
const mockEvents: ChannelAttributionEvent[] = [
// 访客 1: 全链路完成
{ visitorId: 'v1', channel: 'nfc_tap', stage: 'impression' },
{ visitorId: 'v1', channel: 'nfc_tap', stage: 'interactive' },
{ visitorId: 'v1', channel: 'nfc_tap', stage: 'ai_consult' },
{ visitorId: 'v1', channel: 'nfc_tap', stage: 'lead_submitted' },
{ visitorId: 'v1', channel: 'nfc_tap', stage: 'meeting_booked' },
// 访客 2: 停留于 AI 咨询
{ visitorId: 'v2', channel: 'nfc_tap', stage: 'impression' },
{ visitorId: 'v2', channel: 'nfc_tap', stage: 'interactive' },
{ visitorId: 'v2', channel: 'nfc_tap', stage: 'ai_consult' },
// 访客 3: WhatsApp 渠道完成留资
{ visitorId: 'v3', channel: 'whatsapp_chat', stage: 'impression' },
{ visitorId: 'v3', channel: 'whatsapp_chat', stage: 'lead_submitted' },
// 访客 4: 仅浏览展位
{ visitorId: 'v4', channel: 'booth_qr', stage: 'impression' },
];
it('应精确统计各漏斗阶段的独立访客数与流失率', () => {
const funnel = calculateAttributionFunnel(mockEvents);
expect(funnel.totalVisitors).toBe(4);
expect(funnel.stages.impression).toBe(4);
expect(funnel.stages.interactive).toBe(2);
expect(funnel.stages.ai_consult).toBe(2);
expect(funnel.stages.lead_submitted).toBe(2);
expect(funnel.stages.meeting_booked).toBe(1);
// 留资总体转化率: 2 / 4 = 50%
expect(funnel.overallConversionRate).toBe(0.5);
});
it('应支持按渠道拆分多维度漏斗表现', () => {
const breakdown = service.analyzeChannelPerformance(mockEvents);
expect(breakdown['nfc_tap']).toBeDefined();
expect(breakdown['nfc_tap'].visitors).toBe(2);
expect(breakdown['nfc_tap'].leads).toBe(1);
expect(breakdown['nfc_tap'].leadRate).toBe(0.5);
expect(breakdown['whatsapp_chat'].visitors).toBe(1);
expect(breakdown['whatsapp_chat'].leads).toBe(1);
expect(breakdown['whatsapp_chat'].leadRate).toBe(1.0);
});
});
});

查看文件

@@ -0,0 +1,104 @@
import {
NfcManufacturingService,
ManufacturingBatchStatus,
CreateManufacturingBatchDto,
calculateBatchYieldRate,
canTransitionBatchStatus,
} from '../../../src/modules/nfc/service/manufacturing';
describe('Point 45: 跨境实体卡供应链生产批次工单生命周期与良率检验', () => {
let service: NfcManufacturingService;
beforeEach(() => {
service = new NfcManufacturingService();
});
describe('1. 生产工单状态机流转规则 (canTransitionBatchStatus)', () => {
it('应允许合法正向生命周期流转: draft -> ordered -> manufacturing -> qa_inspected -> in_stock', () => {
expect(canTransitionBatchStatus('draft', 'ordered')).toBe(true);
expect(canTransitionBatchStatus('ordered', 'manufacturing')).toBe(true);
expect(canTransitionBatchStatus('manufacturing', 'qa_inspected')).toBe(true);
expect(canTransitionBatchStatus('qa_inspected', 'in_stock')).toBe(true);
});
it('质检不合格可流转为 rejected 废品或返工', () => {
expect(canTransitionBatchStatus('qa_inspected', 'rejected')).toBe(true);
expect(canTransitionBatchStatus('manufacturing', 'cancelled')).toBe(true);
expect(canTransitionBatchStatus('draft', 'cancelled')).toBe(true);
});
it('逆向或跨阶段非法流转应坚决拒绝', () => {
expect(canTransitionBatchStatus('in_stock', 'draft')).toBe(false);
expect(canTransitionBatchStatus('draft', 'in_stock')).toBe(false);
expect(canTransitionBatchStatus('rejected', 'in_stock')).toBe(false);
});
});
describe('2. calculateBatchYieldRate (出厂质检良率与损耗统计)', () => {
it('应精确计算生产良品率 (Yield Rate)', () => {
// 计划生产 1000 张,实际合格 985 张,报废 15 张
const result = calculateBatchYieldRate(1000, 985, 15);
expect(result.yieldRate).toBe(0.985);
expect(result.defectRate).toBe(0.015);
expect(result.isQualified).toBe(true); // 默认合格线 >= 95%
});
it('良率低于阈值 (如 95%) 时应标记为未达标', () => {
const result = calculateBatchYieldRate(1000, 920, 80, 0.95);
expect(result.yieldRate).toBe(0.92);
expect(result.isQualified).toBe(false);
expect(result.defectCount).toBe(80);
});
it('非法入参处理 (如数量为负或超过总数) 应安全抛出异常', () => {
expect(() => calculateBatchYieldRate(0, 0, 0)).toThrow();
expect(() => calculateBatchYieldRate(100, 105, 0)).toThrow();
expect(() => calculateBatchYieldRate(100, -5, 0)).toThrow();
});
});
describe('3. NfcManufacturingService 批次工单管理', () => {
it('应能创建生产批次并初始化为 draft 状态', () => {
const batchDto: CreateManufacturingBatchDto = {
batchNo: 'MFG-2026-Q4-001',
materialType: 'MATTE_BLACK_METAL', // 磨砂黑金属卡
targetQuantity: 500,
factoryName: 'Shenzhen Smart Chip Technology Co.',
chipModel: 'NTAG216',
cardFinishing: 'GOLD_LASER_ENGRAVING', // 激光金雕
};
const batch = service.createBatch(batchDto);
expect(batch.id).toBeDefined();
expect(batch.batchNo).toBe('MFG-2026-Q4-001');
expect(batch.status).toBe('draft');
expect(batch.targetQuantity).toBe(500);
expect(batch.qualifiedQuantity).toBe(0);
});
it('更新生产状态并在达到 qa_inspected 时记录质检指标', () => {
const batch = service.createBatch({
batchNo: 'MFG-2026-Q4-002',
materialType: 'ECO_BAMBOO_WOOD', // 环保竹木卡
targetQuantity: 200,
factoryName: 'EcoCard Global Ltd.',
chipModel: 'NTAG213',
});
// 流转为 ordered -> manufacturing
service.updateBatchStatus(batch.batchNo, 'ordered');
service.updateBatchStatus(batch.batchNo, 'manufacturing');
// 质检录入
const updated = service.recordBatchInspection(batch.batchNo, 196, 4);
expect(updated.status).toBe('qa_inspected');
expect(updated.qualifiedQuantity).toBe(196);
expect(updated.defectQuantity).toBe(4);
expect(updated.yieldRate).toBe(0.98);
// 入库
const inStock = service.updateBatchStatus(batch.batchNo, 'in_stock');
expect(inStock.status).toBe('in_stock');
});
});
});