/** * 打印插件客户端 - 模拟版本 * * 功能: * 1. 注册到ERP系统 * 2. 发送心跳 * 3. 获取打印任务 * 4. 模拟打印 * * 使用方法: * node print-plugin-client.js <命令> [参数] * * 示例: * node print-plugin-client.js register cainiao * node print-plugin-client.js heartbeat * node print-plugin-client.js getjob */ const http = require('http'); // 配置 const CONFIG = { API_BASE: 'http://localhost:10088/api', // 后端API地址 DEVICE_ID: 'PLUGIN-' + Date.now().toString(36).toUpperCase(), DEVICE_NAME: process.env.COMPUTERNAME || 'Unknown-PC', OS_VERSION: process.release.name + ' ' + process.platform, POLL_INTERVAL: 5000, // 5秒轮询一次 }; // 模拟插件信息 const PLUGIN_INFO = { cainiao: { code: 'cainiao', name: '菜鸟打印插件', version: '2.5.8' }, pdd: { code: 'pdd', name: '拼多多打印插件', version: '1.8.3' }, douyin: { code: 'douyin', name: '抖音小店打印插件', version: '3.2.1' }, kuaishou: { code: 'kuaishou', name: '快手小店打印插件', version: '2.1.5' }, }; // API请求封装 function apiRequest(method, path, data = null) { return new Promise((resolve, reject) => { const url = new URL(path, CONFIG.API_BASE); const options = { hostname: url.hostname, port: url.port || 80, path: url.pathname + url.search, method: method, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', } }; const req = http.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { resolve(JSON.parse(body)); } catch { resolve(body); } }); }); req.on('error', (err) => { // API不可用时返回模拟数据 resolve({ code: 200, data: getMockResponse(method, path, data) }); }); if (data) { req.write(JSON.stringify(data)); } req.end(); }); } // 模拟API响应 function getMockResponse(method, path, data) { if (path.includes('/heartbeat')) { return { success: true }; } if (path.includes('/register')) { return { success: true, installation_id: Date.now(), has_update: false, latest_version: '2.5.8' }; } if (path.includes('/next-job')) { // 模拟返回打印任务 return { id: Math.floor(Math.random() * 1000), job_no: 'PJ' + Date.now().toString().slice(-10), platform: 'pdd', plugin_code: 'pdd', print_data: { receiverName: '张三', receiverPhone: '138****8000', receiverAddress: '北京市朝阳区某某街道某某小区', expressNo: 'SF' + Math.random().toString().slice(2, 14), goodsName: '商品测试', quantity: 1, }, status: 'pending', priority: 0, }; } return {}; } // 打印任务到控制台 function printJob(job) { console.log('\n╔══════════════════════════════════════════════╗'); console.log('║ 🎯 收到打印任务 ║'); console.log('╠══════════════════════════════════════════════╣'); console.log(`║ 任务编号: ${job.job_no.padEnd(30)}║`); console.log(`║ 平台: ${job.platform.padEnd(36)}║`); console.log(`║ 收件人: ${(job.print_data?.receiverName || '-').padEnd(34)}║`); console.log(`║ 电话: ${(job.print_data?.receiverPhone || '-').padEnd(35)}║`); console.log(`║ 地址: ${(job.print_data?.receiverAddress || '-').substring(0, 30).padEnd(30)}║`); console.log(`║ 快递单号: ${(job.print_data?.expressNo || '-').padEnd(31)}║`); console.log('╠══════════════════════════════════════════════╣'); console.log('║ 📄 正在模拟打印... ║'); return new Promise((resolve) => { setTimeout(() => { console.log('║ ✅ 打印完成! ║'); console.log('╚══════════════════════════════════════════════╝\n'); resolve(true); }, 1500); }); } // 命令处理 async function handleCommand(cmd, args) { switch (cmd) { case 'register': await registerPlugin(args[0] || 'cainiao'); break; case 'heartbeat': await sendHeartbeat(); break; case 'getjob': await getNextJob(); break; case 'daemon': await runDaemon(args[0] || 'cainiao'); break; case 'info': showInfo(); break; default: showHelp(); } } // 注册插件 async function registerPlugin(pluginCode) { const plugin = PLUGIN_INFO[pluginCode] || PLUGIN_INFO.cainiao; console.log(`\n📦 正在注册 ${plugin.name}...`); console.log(` 设备ID: ${CONFIG.DEVICE_ID}`); console.log(` 设备名称: ${CONFIG.DEVICE_NAME}`); console.log(` 插件版本: ${plugin.version}`); const result = await apiRequest('POST', '/print-plugins/auth/register', { plugin_code: plugin.code, version: plugin.version, device_id: CONFIG.DEVICE_ID, device_name: CONFIG.DEVICE_NAME, os_version: CONFIG.OS_VERSION, }); if (result.success || result.code === 200) { console.log('✅ 注册成功!'); console.log(` 安装ID: ${result.installation_id}`); if (result.has_update) { console.log(` ⚠️ 有新版本: ${result.latest_version}`); } } else { console.log('❌ 注册失败:', result.message || '未知错误'); } } // 发送心跳 async function sendHeartbeat() { const result = await apiRequest('POST', '/print-plugins/auth/heartbeat', { device_id: CONFIG.DEVICE_ID, }); if (result.success || result.code === 200) { console.log('💓 心跳发送成功'); } else { console.log('❌ 心跳失败'); } } // 获取打印任务 async function getNextJob() { const result = await apiRequest('GET', `/print-device/next-job?device_id=${CONFIG.DEVICE_ID}`); if (result && result.id) { await printJob(result); // 标记完成 await apiRequest('POST', '/print-device/complete', { job_id: result.id, device_id: CONFIG.DEVICE_ID, }); } else { console.log('📭 暂无打印任务'); } } // 运行守护进程 async function runDaemon(pluginCode) { const plugin = PLUGIN_INFO[pluginCode] || PLUGIN_INFO.cainiao; console.log('\n🚀 启动打印插件守护进程...'); console.log(` 插件: ${plugin.name}`); console.log(` 轮询间隔: ${CONFIG.POLL_INTERVAL / 1000}秒`); console.log(' 按 Ctrl+C 停止\n'); // 先注册 await registerPlugin(pluginCode); // 启动心跳 setInterval(async () => { await sendHeartbeat(); }, 30000); // 轮询打印任务 setInterval(async () => { await getNextJob(); }, CONFIG.POLL_INTERVAL); } // 显示信息 function showInfo() { console.log('\n📋 插件客户端信息'); console.log('═══════════════════════════════'); console.log(` 设备ID: ${CONFIG.DEVICE_ID}`); console.log(` 设备名称: ${CONFIG.DEVICE_NAME}`); console.log(` 操作系统: ${CONFIG.OS_VERSION}`); console.log(` API地址: ${CONFIG.API_BASE}`); console.log(` 轮询间隔: ${CONFIG.POLL_INTERVAL / 1000}秒`); console.log('═══════════════════════════════════════\n'); } // 帮助 function showHelp() { console.log(` 🔌 打印插件客户端 - 使用说明 用法: node print-plugin-client.js <命令> [参数] 命令: register <插件> 注册插件 (cainiao|pdd|douyin|kuaishou) heartbeat 发送心跳 getjob 获取一个打印任务 daemon <插件> 运行守护进程模式 info 显示客户端信息 help 显示帮助 示例: node print-plugin-client.js register cainiao node print-plugin-client.js daemon pdd node print-plugin-client.js info 注意: - 默认API地址为 http://localhost:10088/api - 如需修改,请编辑 CONFIG.API_BASE - 守护进程模式会自动注册并每30秒发送心跳 `); } // 主入口 const [,, cmd, ...args] = process.argv; handleCommand(cmd, args).catch(console.error);