const http = require('http'); const fs = require('fs'); const path = require('path'); const mysql = require('mysql2/promise'); const OssUploader = require('./oss-uploader'); const port = 3008; // 数据库配置 const dbConfig = { host: process.env.DB_HOST || '1.95.162.61', user: process.env.DB_USER || 'root', password: process.env.DB_PASSWORD || 'schl@2025', database: process.env.DB_NAME || 'wechat_app', waitForConnections: true, connectionLimit: 20, queueLimit: 0, connectTimeout: 10000, timezone: '+08:00' }; // 创建数据库连接池 const pool = mysql.createPool(dbConfig); // 测试数据库连接 async function testDbConnection() { try { const connection = await pool.getConnection(); console.log('数据库连接成功'); connection.release(); } catch (error) { console.error('数据库连接失败:', error.message); } } testDbConnection(); const server = http.createServer(async (req, res) => { // 健康检查端点 if (req.method === 'GET' && req.url === '/health') { try { // 测试数据库连接 const [rows] = await pool.execute('SELECT 1'); // 测试OSS连接 const ossStatus = await OssUploader.testConnection(); res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: true, status: 'healthy', database: 'connected', oss: ossStatus.success ? 'connected' : 'disconnected', timestamp: new Date().toISOString() })); } catch (error) { console.error('健康检查失败:', error.message); res.writeHead(503, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: false, status: 'unhealthy', error: error.message, timestamp: new Date().toISOString() })); } return; } // 处理GET请求,获取最新的合格证信息 if (req.method === 'GET' && req.url === '/getLatestCertificate') { try { // 从数据库获取最新的合格证信息 const [rows] = await pool.execute( 'SELECT company as subjectName, phoneNumber as contact, productName, grossWeight as weight, commitBasis as basis, origin, issueDate, DATE_FORMAT(issueDate, "%Y-%m-%d") as date, signature FROM certificate ORDER BY id DESC LIMIT 1' ); const certificate = rows.length > 0 ? rows[0] : null; console.log('从数据库获取的最新合格证信息:', certificate); // 返回成功响应 res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: true, certificate })); } catch (error) { console.error('获取合格证信息失败:', error.message); res.writeHead(500, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: false, error: '获取失败,请重试' })); } return; } // 处理POST请求 if (req.method === 'POST' && req.url === '/submit') { try { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { try { // 解析表单数据 const formData = new URLSearchParams(body); // 使用当前的北京时间(精确到秒)作为开具日期 const now = new Date(); const beijingTime = new Date(now.getTime() + 8 * 60 * 60 * 1000); // 转换为北京时间 const certificate = { subjectName: formData.get('subjectName'), contact: formData.get('contact'), productName: formData.get('productName'), weight: formData.get('weight'), basis: formData.get('basis'), origin: formData.get('origin'), date: beijingTime, signature: formData.get('signature') }; console.log('接收到的表单数据:', { subjectName: certificate.subjectName, contact: certificate.contact, productName: certificate.productName, weight: certificate.weight, basis: certificate.basis, origin: certificate.origin, date: certificate.date.toISOString(), hasSignature: !!certificate.signature }); // 处理手写签名,上传到OSS let signatureUrl = null; if (certificate.signature) { try { // 从base64字符串中提取图片数据 const base64Data = certificate.signature.replace(/^data:image\/png;base64,/, ''); const buffer = Buffer.from(base64Data, 'base64'); // 生成唯一的文件名,包含合格证信息的标识 const timestamp = Date.now(); const filename = `certificate_signature_${timestamp}.png`; // 上传到OSS,指定文件夹为certificate/signatures signatureUrl = await OssUploader.uploadBuffer(buffer, filename, 'certificate/signatures', 'image'); console.log('手写签名上传到OSS成功:', signatureUrl); } catch (error) { console.error('上传手写签名到OSS失败:', error.message); // 即使上传失败,也继续处理,将签名数据存储为base64 signatureUrl = certificate.signature; } } // 插入数据到数据库 await pool.execute( 'INSERT INTO certificate (company, phoneNumber, productName, grossWeight, commitBasis, origin, issueDate, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [certificate.subjectName, certificate.contact, certificate.productName, certificate.weight, certificate.basis, certificate.origin, certificate.date, signatureUrl] ); console.log('数据插入数据库成功'); // 返回成功响应,确保返回的signature是OSS URL const responseCertificate = { ...certificate, signature: signatureUrl }; res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: true, certificate: responseCertificate })); } catch (error) { console.error('处理表单数据失败:', error.message); res.writeHead(500, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: false, error: '处理数据失败,请重试' })); } }); } catch (error) { console.error('保存合格证信息失败:', error.message); res.writeHead(500, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(JSON.stringify({ success: false, error: '保存失败,请重试' })); } return; } // 处理GET请求 // 解析请求路径 let filePath = '.' + req.url; if (filePath === './') { filePath = './certificate.html'; } // 获取文件扩展名 const extname = String(path.extname(filePath)).toLowerCase(); // 定义MIME类型 const mimeTypes = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.wav': 'audio/wav', '.mp4': 'video/mp4', '.woff': 'application/font-woff', '.ttf': 'application/font-ttf', '.eot': 'application/vnd.ms-fontobject', '.otf': 'application/font-otf', '.wasm': 'application/wasm' }; // 获取对应的MIME类型 const contentType = mimeTypes[extname] || 'application/octet-stream'; // 读取文件 fs.readFile(filePath, (error, content) => { if (error) { if(error.code == 'ENOENT') { // 文件不存在 fs.readFile('./404.html', (error, content) => { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end(content, 'utf-8'); }); } else { // 服务器错误 res.writeHead(500); res.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n'); res.end(); } } else { // 成功读取文件 res.writeHead(200, { 'Content-Type': contentType }); res.end(content, 'utf-8'); } }); }); // 启动服务器 server.listen(port, () => { console.log(`Server running at http://localhost:${port}/`); }); console.log(`Server starting on port ${port}...`);