const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const crypto = require('crypto'); const axios = require('axios'); const app = express(); const PORT = process.env.PORT || 3000; // 中间件 app.use(cors()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static('public')); // 数据库初始化 const db = new sqlite3.Database('./database/shop.db'); // 创建订单表 db.serialize(() => { db.run(`CREATE TABLE IF NOT EXISTS orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, order_id TEXT UNIQUE NOT NULL, product_name TEXT NOT NULL, quantity INTEGER NOT NULL, unit_price REAL NOT NULL, total_amount REAL NOT NULL, customer_name TEXT NOT NULL, customer_email TEXT, customer_phone TEXT, shipping_address TEXT NOT NULL, payment_id TEXT, payment_status TEXT DEFAULT 'pending', shipping_status TEXT DEFAULT 'pending', tracking_number TEXT, shipping_notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP )`); }); // UPay 配置 // const UPAY_APP_ID = process.env.UPAY_APP_ID || 'E7c4dss9'; // const UPAY_APP_SECRET = process.env.UPAY_APP_SECRET || 'Hwc56INsabRau2yn'; // const UPAY_API_URL = 'https://api.upay.ink/v1/api/open'; const UPAY_APP_ID = process.env.UPAY_APP_ID || 'M1C40DvS'; const UPAY_APP_SECRET = process.env.UPAY_APP_SECRET || 'a2nqkkqRb09LIe87'; const UPAY_API_URL = 'https://api-test.upay.ink/v1/api/open'; // 产品配置 const PRODUCTS = { 'premium-product': { name: '比特币彩票抽奖机', price: 100, description: '这是我们的比特币彩票抽奖机,质量优秀' } }; // 路由 app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // 获取产品信息 app.get('/api/products', (req, res) => { res.json(PRODUCTS); }); // 创建订单 app.post('/api/orders', async (req, res) => { try { const { product_id, quantity, customer_name, customer_email, customer_phone, shipping_address } = req.body; // 验证产品 if (!PRODUCTS[product_id]) { return res.status(400).json({ error: '无效的产品ID' }); } const product = PRODUCTS[product_id]; const total_amount = product.price * quantity; const order_id = 'ORDER_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); // 保存订单到数据库 const stmt = db.prepare(` INSERT INTO orders (order_id, product_name, quantity, unit_price, total_amount, customer_name, customer_email, customer_phone, shipping_address) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `); stmt.run([ order_id, product.name, quantity, product.price, total_amount, customer_name, customer_email, customer_phone, shipping_address ], function(err) { if (err) { console.error(err); return res.status(500).json({ error: '订单创建失败' }); } res.json({ success: true, order_id, total_amount, message: '订单创建成功' }); }); stmt.finalize(); } catch (error) { console.error(error); res.status(500).json({ error: '服务器错误' }); } }); // UPay 签名生成函数 function generateUpaySignature(params, appSecret) { // 1. 过滤需要签名的参数,排除signature字段 const signParams = {}; Object.keys(params).forEach(key => { if (key !== 'signature' && params[key] !== null && params[key] !== undefined && params[key] !== '') { signParams[key] = params[key]; } }); // 2. 按ASCII字典序排序参数 const sortedKeys = Object.keys(signParams).sort(); // 3. 拼接参数字符串 key1=value1&key2=value2 let signStr = ''; sortedKeys.forEach((key, index) => { signStr += `${key}=${signParams[key]}`; if (index < sortedKeys.length - 1) { signStr += '&'; } }); // 4. 在末尾追加&appSecret=密钥 signStr += `&appSecret=${appSecret}`; console.log('Signature string:', signStr); // 5. MD5加密并转大写 return crypto.createHash('md5').update(signStr, 'utf8').digest('hex').toUpperCase(); } // 创建支付 app.post('/api/payment/create', async (req, res) => { try { const { order_id } = req.body; // 从数据库获取订单信息 db.get('SELECT * FROM orders WHERE order_id = ?', [order_id], async (err, order) => { if (err || !order) { return res.status(404).json({ error: '订单未找到' }); } // 创建 UPay 支付订单 const paymentData = { appId: UPAY_APP_ID, merchantOrderNo: order_id, chainType: '1', // USDT TRC20 fiatAmount: order.total_amount.toFixed(2), fiatCurrency: 'USD', notifyUrl: `${req.protocol}://${req.get('host')}/api/payment/callback`, redirectUrl: `${req.protocol}://${req.get('host')}/success.html?order_id=${order_id}` }; // 生成签名 paymentData.signature = generateUpaySignature(paymentData, UPAY_APP_SECRET); try { const response = await axios.post(`${UPAY_API_URL}/order/apply`, paymentData, { headers: { 'Content-Type': 'application/json' } }); console.log('UPay API Response:', response.data); if (response.data.code === '1' && response.data.message === 'success') { // 更新订单支付信息 db.run( 'UPDATE orders SET payment_id = ?, updated_at = CURRENT_TIMESTAMP WHERE order_id = ?', [response.data.data.orderNo, order_id] ); res.json({ success: true, payment_url: response.data.data.payUrl, payment_id: response.data.data.orderNo, order_no: response.data.data.orderNo }); } else { throw new Error(response.data.message || '创建支付订单失败'); } } catch (error) { console.error('UPay API Error:', error.response?.data || error.message); // 如果API失败,返回手动支付页面 const manualPaymentUrl = `/manual-payment.html?order_id=${order_id}`; res.json({ success: true, payment_url: manualPaymentUrl, payment_id: 'MANUAL_' + order_id, message: 'API不可用,请使用手动支付模式', manual_mode: true }); } }); } catch (error) { console.error(error); res.status(500).json({ error: '服务器错误' }); } }); // UPay 支付回调验证 function verifyUpayCallback(params, signature, appSecret) { const expectedSignature = generateUpaySignature(params, appSecret); console.log('Expected signature:', expectedSignature); console.log('Received signature:', signature); return expectedSignature === signature; } // 支付回调 app.post('/api/payment/callback', (req, res) => { try { console.log('Received callback:', req.body); const callbackData = req.body; const { signature, merchantOrderNo, orderNo, status } = callbackData; // 验证签名 const paramsForSign = { ...callbackData }; delete paramsForSign.signature; if (!verifyUpayCallback(paramsForSign, signature, UPAY_APP_SECRET)) { console.error('UPay callback signature verification failed'); return res.status(400).send('FAIL'); } // 映射支付状态 let paymentStatus = 'pending'; switch (status.toString()) { case '1': // 订单完成 paymentStatus = 'finished'; break; case '2': // 订单超时 case '3': // 订单失败 paymentStatus = 'failed'; break; case '0': // 处理中 default: paymentStatus = 'pending'; } // 更新订单支付状态 db.run( 'UPDATE orders SET payment_status = ?, payment_id = ?, updated_at = CURRENT_TIMESTAMP WHERE order_id = ?', [paymentStatus, orderNo, merchantOrderNo], (err) => { if (err) { console.error('Database update error:', err); return res.status(500).send('FAIL'); } console.log(`Order ${merchantOrderNo} payment status updated to: ${paymentStatus}`); res.send('OK'); } ); } catch (error) { console.error('Callback error:', error); res.status(500).send('FAIL'); } }); // 获取订单状态 app.get('/api/orders/:order_id', (req, res) => { const { order_id } = req.params; db.get('SELECT * FROM orders WHERE order_id = ?', [order_id], (err, order) => { if (err || !order) { return res.status(404).json({ error: '订单未找到' }); } res.json(order); }); }); // 获取所有订单列表(管理员) app.get('/api/admin/orders', (req, res) => { const { status, search, limit = 50, offset = 0 } = req.query; let query = 'SELECT * FROM orders'; let params = []; let conditions = []; if (status) { conditions.push('payment_status = ? OR shipping_status = ?'); params.push(status, status); } if (search) { conditions.push('(order_id LIKE ? OR customer_name LIKE ? OR customer_email LIKE ?)'); const searchTerm = `%${search}%`; params.push(searchTerm, searchTerm, searchTerm); } if (conditions.length > 0) { query += ' WHERE ' + conditions.join(' AND '); } query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?'; params.push(parseInt(limit), parseInt(offset)); db.all(query, params, (err, orders) => { if (err) { console.error('Database error:', err); return res.status(500).json({ error: '查询订单失败' }); } // 获取订单统计 db.all(` SELECT COUNT(*) as total, SUM(CASE WHEN payment_status = 'finished' AND shipping_status = 'pending' THEN 1 ELSE 0 END) as pending_ship, SUM(CASE WHEN shipping_status = 'shipped' THEN 1 ELSE 0 END) as shipped, SUM(CASE WHEN shipping_status = 'completed' THEN 1 ELSE 0 END) as completed FROM orders `, [], (err, stats) => { if (err) { console.error('Stats error:', err); return res.json({ orders, stats: null }); } res.json({ orders, stats: stats[0] || { total: 0, pending_ship: 0, shipped: 0, completed: 0 } }); }); }); }); // 更新订单发货状态 app.put('/api/admin/orders/:order_id/shipping', (req, res) => { const { order_id } = req.params; const { shipping_status, tracking_number, shipping_notes } = req.body; if (!['pending', 'shipped', 'completed'].includes(shipping_status)) { return res.status(400).json({ error: '无效的发货状态' }); } db.run( `UPDATE orders SET shipping_status = ?, tracking_number = ?, shipping_notes = ?, updated_at = CURRENT_TIMESTAMP WHERE order_id = ?`, [shipping_status, tracking_number || null, shipping_notes || null, order_id], function(err) { if (err) { console.error('Update shipping error:', err); return res.status(500).json({ error: '更新发货状态失败' }); } if (this.changes === 0) { return res.status(404).json({ error: '订单未找到' }); } res.json({ success: true, message: '发货状态更新成功', changes: this.changes }); } ); }); app.listen(PORT, () => { console.log(`服务器运行在 http://localhost:${PORT}`); });