excel-smoke-test.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. 'use strict';
  2. const assert = require('assert/strict');
  3. const fs = require('fs');
  4. const os = require('os');
  5. const path = require('path');
  6. const { readSheet } = require('read-excel-file/node');
  7. const writeXlsxFile = require('write-excel-file/node');
  8. async function assertWorkbook(filePath, expectedSheet, expectedRows) {
  9. assert(fs.existsSync(filePath), `未生成 Excel 文件: ${filePath}`);
  10. const rows = await readSheet(filePath, expectedSheet);
  11. assert.equal(rows.length, expectedRows + 1);
  12. assert(rows[0].length > 0, `工作表 ${expectedSheet} 缺少表头`);
  13. }
  14. async function main() {
  15. const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-excel-smoke-'));
  16. process.env.QIWEI_OUTPUTS_DIR = path.join(tempRoot, 'outputs');
  17. try {
  18. const inputFile = path.join(tempRoot, 'customers.xlsx');
  19. const inputRows = [
  20. ['手机号', '姓名', '验证消息', '群名称'],
  21. ['13800138000', '客户甲', '您好', '体验群'],
  22. ['13800138000', '重复客户', '', ''],
  23. ['not-a-phone', '无效客户', '', ''],
  24. ].map(row => row.map(value => ({ value })));
  25. await writeXlsxFile(inputRows, { sheet: 'customers' }).toFile(inputFile);
  26. const { normalizeCustomers } = require('../mcp/src/tools/qiwei-customer-ops-run');
  27. const imported = await normalizeCustomers({ filePath: inputFile });
  28. assert.equal(imported.customers.length, 1);
  29. assert.equal(imported.customers[0].phone, '13800138000');
  30. assert.equal(imported.customers[0].name, '客户甲');
  31. assert.equal(imported.duplicateRemoved, 1);
  32. assert.equal(imported.invalidRemoved, 1);
  33. const portraitDir = path.join(process.env.QIWEI_OUTPUTS_DIR, 'portraits');
  34. const playbookDir = path.join(process.env.QIWEI_OUTPUTS_DIR, 'broker-playbooks');
  35. fs.mkdirSync(portraitDir, { recursive: true });
  36. fs.mkdirSync(playbookDir, { recursive: true });
  37. fs.writeFileSync(path.join(portraitDir, 'customer-1.json'), JSON.stringify({
  38. externalUserId: 'customer-1',
  39. portrait: { intent: '咨询', confidence: 0.9 },
  40. updatedAt: new Date().toISOString(),
  41. }), 'utf8');
  42. fs.writeFileSync(path.join(playbookDir, 'broker-1.json'), JSON.stringify({
  43. brokerUserId: 'broker-1',
  44. playbook: { opening: '先确认需求', followUp: '次日回访' },
  45. updatedAt: new Date().toISOString(),
  46. }), 'utf8');
  47. const { qiweiExportCustomerPortraits } = require('../mcp/src/tools/qiwei-portrait-tags-run');
  48. const { qiweiExportBrokerPlaybooks } = require('../mcp/src/tools/qiwei-broker-playbook-run');
  49. const portraitResult = await qiweiExportCustomerPortraits({ externalUserIds: ['customer-1'] });
  50. const playbookResult = await qiweiExportBrokerPlaybooks({ brokerUserIds: ['broker-1'] });
  51. assert.equal(portraitResult.status, 'ok');
  52. assert.equal(playbookResult.status, 'ok');
  53. await assertWorkbook(portraitResult.files[0], 'portraits', 1);
  54. await assertWorkbook(playbookResult.files[0], 'playbooks', 1);
  55. process.stdout.write(`${JSON.stringify({
  56. status: 'ok',
  57. importedCustomers: imported.customers.length,
  58. duplicateRemoved: imported.duplicateRemoved,
  59. invalidRemoved: imported.invalidRemoved,
  60. exportsVerified: 2,
  61. }, null, 2)}\n`);
  62. } finally {
  63. fs.rmSync(tempRoot, { recursive: true, force: true });
  64. }
  65. }
  66. main().catch(error => {
  67. process.stderr.write(`${error.stack || error.message}\n`);
  68. process.exit(1);
  69. });