/** * 生成1000个完整的账号数据(用于手动测试Stripe通过率) */ const AccountDataGenerator = require('./src/shared/libs/account-generator'); const CardGenerator = require('./src/shared/libs/card-generator'); const fs = require('fs'); const path = require('path'); console.log('\n========== 生成1000个账号数据 ==========\n'); async function generate() { const accountGen = new AccountDataGenerator(); const cardGen = new CardGenerator(); // 不连接数据库,只生成 const accounts = []; const stats = { total: 0, success: 0, failed: 0, binDistribution: {} }; console.log('开始生成...\n'); const startTime = Date.now(); for (let i = 0; i < 1000; i++) { try { // 生成账号 const account = accountGen.generateAccount(); // 生成卡号 const card = await cardGen.generate('unionpay'); // 组合数据 const fullAccount = { id: i + 1, email: account.email, password: account.password, firstName: account.firstName, lastName: account.lastName, cardNumber: card.number, expMonth: card.month, expYear: card.year, cvv: card.cvv, issuer: card.issuer, country: card.country, countryName: card.countryName }; accounts.push(fullAccount); stats.success++; stats.total++; // 统计BIN分布(前6位) const bin6 = card.number.substring(0, 6); stats.binDistribution[bin6] = (stats.binDistribution[bin6] || 0) + 1; // 进度显示 if ((i + 1) % 100 === 0) { console.log(` 进度: ${i + 1}/1000 (${((i + 1) / 10).toFixed(1)}%)`); } } catch (error) { stats.failed++; stats.total++; console.log(` ❌ 第 ${i + 1} 个生成失败: ${error.message}`); } } const endTime = Date.now(); const duration = ((endTime - startTime) / 1000).toFixed(2); console.log(`\n✅ 生成完成!耗时: ${duration}秒`); console.log(` 成功: ${stats.success}个`); console.log(` 失败: ${stats.failed}个\n`); // 保存为多种格式 const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0]; const outputDir = path.join(__dirname, 'generated-accounts'); // 创建输出目录 if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // 1. JSON格式(完整数据) const jsonFile = path.join(outputDir, `accounts-1000-${timestamp}.json`); fs.writeFileSync(jsonFile, JSON.stringify(accounts, null, 2), 'utf-8'); console.log(`✅ JSON文件: ${jsonFile}`); // 2. CSV格式(便于Excel打开) const csvFile = path.join(outputDir, `accounts-1000-${timestamp}.csv`); const csvHeader = 'ID,Email,Password,FirstName,LastName,CardNumber,ExpMonth,ExpYear,CVV,Issuer,Country,CountryName\n'; const csvRows = accounts.map(a => `${a.id},${a.email},${a.password},${a.firstName},${a.lastName},${a.cardNumber},${a.expMonth},${a.expYear},${a.cvv},${a.issuer},${a.country},${a.countryName}` ).join('\n'); fs.writeFileSync(csvFile, csvHeader + csvRows, 'utf-8'); console.log(`✅ CSV文件: ${csvFile}`); // 3. 可读格式(用于快速查看) const txtFile = path.join(outputDir, `accounts-1000-${timestamp}.txt`); let txtContent = '========== 1000个Windsurf测试账号 ==========\n\n'; txtContent += `生成时间: ${new Date().toLocaleString('zh-CN')}\n`; txtContent += `总数: ${stats.success}个\n\n`; txtContent += '=' .repeat(80) + '\n\n'; accounts.forEach((a, index) => { txtContent += `【账号 ${a.id}】\n`; txtContent += ` 邮箱: ${a.email}\n`; txtContent += ` 密码: ${a.password}\n`; txtContent += ` 姓名: ${a.firstName} ${a.lastName}\n`; txtContent += ` 卡号: ${a.cardNumber}\n`; txtContent += ` 有效期: ${a.expMonth}/${a.expYear}\n`; txtContent += ` CVV: ${a.cvv}\n`; txtContent += ` 银行: ${a.issuer}\n`; txtContent += ` 国家: ${a.countryName} (${a.country})\n`; txtContent += '\n'; if ((index + 1) % 50 === 0) { txtContent += '-'.repeat(80) + '\n\n'; } }); fs.writeFileSync(txtFile, txtContent, 'utf-8'); console.log(`✅ TXT文件: ${txtFile}`); // 4. Stripe测试专用格式(卡号|有效期|CVV) const stripeFile = path.join(outputDir, `stripe-test-cards-${timestamp}.txt`); let stripeContent = '========== Stripe测试卡号列表 ==========\n\n'; stripeContent += '格式: 卡号|有效期|CVV|邮箱\n\n'; accounts.forEach(a => { stripeContent += `${a.cardNumber}|${a.expMonth}/${a.expYear}|${a.cvv}|${a.email}\n`; }); fs.writeFileSync(stripeFile, stripeContent, 'utf-8'); console.log(`✅ Stripe测试文件: ${stripeFile}`); // 统计报告 console.log('\n========== 统计报告 ==========\n'); console.log('BIN分布(前6位):'); const sortedBins = Object.entries(stats.binDistribution) .sort((a, b) => b[1] - a[1]); sortedBins.forEach(([bin, count], index) => { if (index < 5) { console.log(` ${bin}: ${count}张 (${(count / stats.success * 100).toFixed(1)}%)`); } }); console.log(`\n唯一BIN数: ${sortedBins.length}个`); console.log(`平均每个BIN: ${(stats.success / sortedBins.length).toFixed(1)}张`); // 示例账号 console.log('\n========== 示例账号(前3个)==========\n'); accounts.slice(0, 3).forEach(a => { console.log(`${a.id}. ${a.email} | ${a.password}`); console.log(` 卡号: ${a.cardNumber} | ${a.expMonth}/${a.expYear} | CVV: ${a.cvv}`); console.log(` 国家: ${a.countryName}\n`); }); console.log('\n========== 使用说明 ==========\n'); console.log('1. 打开 CSV 文件用 Excel 查看'); console.log('2. 打开 TXT 文件查看完整信息'); console.log('3. 使用 stripe-test-cards 文件手动测试Stripe'); console.log('4. 建议测试方法:'); console.log(' - 先测试前50个,记录通过率'); console.log(' - 如果通过率高,再测试更多'); console.log(' - 记录失败原因(卡被拒/金额不足/其他)'); console.log('\n================================\n'); } generate().catch(console.error);