const assert = require('assert'); const fs = require('fs'); const os = require('os'); const path = require('path'); const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-customer-journey-')); process.env.QIWEI_OUTPUTS_DIR = tempDir; async function main() { let updateCall = null; const conversation = { id: 'conversation-1', channelId: 'external-test-1', displayName: '测试客户', maskedId: 'ex***-1', source: 'live', mode: 'review', analysis: { completenessScore: 50 }, messages: [ { id: 'm1', role: 'customer', source: 'live', content: '预算 15 万,想了解企业服务方案', timestamp: '2026-07-17T00:00:00Z' }, { id: 'm2', role: 'human', source: 'live', content: '收到,我先确认您的计划时间。', timestamp: '2026-07-17T00:05:00Z' }, ], customerIntelligence: { profile: { need: '企业服务方案', budgetWan: 15, timeline: '待确认' }, profileEvidence: { need: { text: '想了解企业服务方案', sourceMessageId: 'm1', source: 'live-message', updatedAt: '2026-07-17T00:00:00Z' }, }, tags: ['企业客户'], tasks: [{ id: 't1', title: '确认计划时间', status: 'open', evidence: '计划时间未确认', updatedAt: '2026-07-17T00:10:00Z' }], alerts: [{ id: 'a1', title: '重点跟进', severity: 'high', status: 'open', evidence: '客户已明确需求和预算', updatedAt: '2026-07-17T00:11:00Z' }], summary: { openTasks: 1, openAlerts: 1, highAlerts: 1 }, }, lastMessageAt: '2026-07-17T00:05:00Z', updatedAt: '2026-07-17T00:11:00Z', }; const { createCustomerMasterService } = require('../mcp/src/dashboard/customer-master-service'); const service = createCustomerMasterService({ projectionPath: path.join(tempDir, 'customers', 'index.json'), getConversations: () => ({ data: { conversations: [conversation] } }), updateCustomerProfile: (customerId, input) => { updateCall = { customerId, input }; conversation.customerIntelligence.profile = { ...conversation.customerIntelligence.profile, ...(input.profile || {}) }; return { status: 'ok', assistantMessage: '客户主档已更新。', summary: { updated: true } }; }, }); const hub = service.hub(); const customer = hub.data.customers[0]; assert.equal(hub.status, 'ok'); assert.equal(hub.summary.customerCount, 1); assert.equal(hub.summary.priorityCount, 1); assert.equal(customer.stage.key, 'priority'); assert.equal(customer.evidenceCoverage, 33); assert(customer.nextActions.some(item => item.id === 'confirm-purpose') === false); assert(customer.nextActions.some(item => item.id === 'confirm-timeline')); assert(customer.timeline.some(item => item.type === 'inbound-message')); assert(customer.timeline.some(item => item.type === 'outbound-message')); assert(customer.timeline.some(item => item.type === 'task')); assert(customer.timeline.some(item => item.type === 'alert')); assert.equal(customer.openTaskCount, 1); assert.equal(customer.highAlertCount, 1); assert.equal(fs.existsSync(path.join(tempDir, 'customers', 'index.json')), true); const updated = service.update(conversation.id, { profile: { timeline: '本月内' }, reason: '客户确认' }); assert.equal(updated.status, 'ok'); assert.equal(updateCall.customerId, conversation.id); assert.equal(updateCall.input.profile.timeline, '本月内'); process.stdout.write(`${JSON.stringify({ status: 'ok', checks: 16, customerCount: hub.summary.customerCount, nextActions: customer.nextActions.length, timelineEvents: customer.timeline.length, }, null, 2)}\n`); } main().catch(error => { process.stderr.write(`${error.stack || error.message}\n`); process.exitCode = 1; }).finally(() => { try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {} });