| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- #!/usr/bin/env node
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const { spawnSync } = require('child_process');
- const { buildLocalSeedToIntakeWorklist } = require('./local-seed-to-intake-worklist');
- const ROOT = path.resolve(__dirname, '..');
- function main() {
- const fakeSeedIndex = {
- proofLevel: 'not_business_proof',
- directCustomerProof: false,
- canCloseProofGap: false,
- materialCount: 2,
- existingMaterialCount: 2,
- materials: [
- {
- id: 'dha-brief-workbook',
- path: '../dha_brief.xlsx',
- exists: true,
- workbook: {
- sheets: [
- {
- name: '参考链接解析',
- sampleRows: [
- ['视频', 'http://xhslink.com/o/example', 'note-1', '参考妈妈', 'uid-1', 'xhs-1', '', '', '已解析', 'https://www.xiaohongshu.com/discovery/item/note-1?xsec_token=secret#frag']
- ]
- }
- ]
- }
- },
- {
- id: 'dha-poc-recommendation-workbook',
- path: '../output/dha-tihao-poc/poc.xlsx',
- exists: true,
- workbook: {
- sheets: [
- {
- name: '主推账号',
- sampleRows: [
- ['主推', '小爱十月', 'aixiaolan94', '山东 潍坊', '30454', '3800', '4500', '视频', '4500', '172419', '6545', '0.026'],
- ['主推', '我是在在吖', 'wangshuyun711', '浙江 宁波', '16631', '2400', '3200', '图文', '2400', '7475', '815', '0.321']
- ]
- },
- {
- name: '备选复核',
- sampleRows: [
- ['备选/补充', '育婴师 Joyce', '567679811', '安徽 亳州', '26297', '4000', '4800', '图文', '4000', '18964', '0', '0.211']
- ]
- }
- ]
- }
- }
- ]
- };
- const summary = buildLocalSeedToIntakeWorklist({ root: ROOT, seedIndex: fakeSeedIndex });
- assert(summary.proofLevel === 'not_business_proof', 'worklist should stay not_business_proof');
- assert(summary.directCustomerProof === false, 'worklist should not be direct customer proof');
- assert(summary.canCloseProofGap === false, 'worklist should not close proof gaps');
- assert(summary.historyDraftRows.length === 3, 'worklist should expand candidate seeds into history draft rows');
- assert(summary.reviewDraftRows.length === 3, 'worklist should create manual review draft rows');
- assert(summary.referenceSeedRows.length === 1, 'worklist should extract reference seed rows');
- assert(summary.referenceSeedRows[0].finalLink === 'https://www.xiaohongshu.com/discovery/item/note-1', 'worklist should sanitize reference URLs');
- assert(summary.candidateSeedRows.length === 3, 'worklist should extract candidate seed rows');
- assert(summary.proofGapMaterialBridge.length === 3, 'worklist should map seed material to the three real proof gaps');
- assert(summary.videoWorklistRows.some(row => row.role === '候选视频' && row.creatorName === '小爱十月'), 'worklist should create candidate video fill row');
- assert(summary.missingProofRequirements.includes('customer-effect:audit overallPass=true'), 'worklist should keep customer-effect missing proof');
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-seed-worklist-'));
- const output = path.join(temp, 'worklist');
- const result = spawnSync(process.execPath, [
- 'scripts/local-seed-to-intake-worklist.js',
- '--workspace-root',
- path.join(temp, 'workspace'),
- '--outputs',
- path.join(temp, 'outputs'),
- '--output',
- output,
- '--strict'
- ], {
- cwd: ROOT,
- encoding: 'utf8',
- shell: false
- });
- if (result.stdout) process.stdout.write(result.stdout);
- if (result.stderr) process.stderr.write(result.stderr);
- assert(result.status === 0, 'CLI should pass even when no seed files exist');
- const cliSummary = readJson(path.join(output, 'local-seed-to-intake-worklist-summary.json'));
- const report = fs.readFileSync(path.join(output, 'local-seed-to-intake-worklist.md'), 'utf8');
- const csv = fs.readFileSync(path.join(output, 'local-seed-to-intake-worklist.csv'), 'utf8');
- assert(cliSummary.proofLevel === 'not_business_proof', 'CLI summary should keep proof boundary');
- assert(cliSummary.canCloseProofGap === false, 'CLI summary should not close proof gap');
- assert(report.includes('本地种子转 intake 补表 worklist'), 'report should render title');
- assert(csv.includes('类型'), 'unified CSV should render headers');
- assert(fs.existsSync(path.join(output, 'history-intake-draft.csv')), 'CLI should write history draft CSV');
- assert(fs.existsSync(path.join(output, 'manual-review-draft.csv')), 'CLI should write manual review draft CSV');
- assert(fs.existsSync(path.join(output, 'video-resource-worklist.csv')), 'CLI should write video worklist CSV');
- assert(fs.existsSync(path.join(output, 'candidate-seed-worklist.csv')), 'CLI should write candidate worklist CSV');
- assert(!report.includes('xsec_token'), 'report should not leak xsec token');
- assert(!csv.includes('xsec_token'), 'csv should not leak xsec token');
- console.log(JSON.stringify({
- ok: true,
- historyDraftRows: summary.historyDraftRows.length,
- reviewDraftRows: summary.reviewDraftRows.length,
- referenceSeedRows: summary.referenceSeedRows.length,
- candidateSeedRows: summary.candidateSeedRows.length,
- cliHistoryDraftRows: cliSummary.historyDraftRows.length
- }, null, 2));
- }
- function readJson(file) {
- return JSON.parse(fs.readFileSync(file, 'utf8'));
- }
- function assert(condition, message) {
- if (!condition) throw new Error(message);
- }
- main();
|