const API = require("../../lib/API.js") const db = require("../../plugin/DataBase/db.js") const Redis = require('../../plugin/DataBase/Redis') const { BaseStdResponse } = require("../../BaseStdResponse.js") const AccessControl = require("../../lib/AccessControl.js") const crypto = require('crypto') const axios = require('axios') const config = require('../../config.json') function generateOrderId() { const now = new Date() const pad = (n, w = 2) => n.toString().padStart(w, '0') return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` + `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}` + `${pad(now.getMilliseconds(), 3)}` } function generatePaymentSign(params, key) { const sorted = Object.keys(params).sort() const query = sorted.map(k => `${k}=${params[k]}`).join('&') + key return crypto.createHash('md5').update(query, 'utf8').digest('hex') } // async function getPayStatus(order_no) { // const endpoint = config.pay.url + '/api/findorder' // try { // const res = await axios.post(endpoint, {order_no, type: 1}) // } catch (error) { // } // } class CreateOrder extends API { constructor() { super() this.setPath('/Order/CreateOrder') this.setMethod('POST') } async onRequest(req, res) { const { uuid, session, goods_id, pay_type } = req.body if ([uuid, session, goods_id, pay_type].some(v => v === '' || v === null || v === undefined)) { return res.json({ ...BaseStdResponse.MISSING_PARAMETER, endpoint: 1513126 }) } const sessionValid = await AccessControl.checkSession(uuid, session) if (!sessionValid) { return res.status(401).json({ ...BaseStdResponse.ACCESS_DENIED }) } try { const goodsSql = 'SELECT name, price, num, state FROM goods WHERE id = ?' const goodsRows = await db.query(goodsSql, [goods_id]) if (!goodsRows || goodsRows.length !== 1) { return res.json({ ...BaseStdResponse.ERR, msg: '商品不存在', endpoint: 1513126 }) } const goods = goodsRows[0] if (goods.num < 1 || goods.state !== 1) { return res.json({ ...BaseStdResponse.ERR, msg: '商品已下架或库存不足', endpoint: 1513126 }) } const createTime = Date.now() const orderId = generateOrderId() const insertSql = ` INSERT INTO orders (orderId, create_user, create_time, goods_id, price, pay_type) VALUES (?, ?, ?, ?, ?, ?) ` const result = await db.query(insertSql, [ orderId, uuid, createTime, goods_id, goods.price, pay_type ]) const updateSql = 'UPDATE goods SET num = num - 1 WHERE id = ?' await db.query(updateSql, [goods_id]) if (result && result.affectedRows > 0) { const paymentConfig = config.pay || {} if (!paymentConfig.pid || !paymentConfig.url || !paymentConfig.key || !paymentConfig.return_url) { return res.json({ ...BaseStdResponse.ERR, msg: '支付配置错误,请联系管理员' }) } const payParams = { pid: paymentConfig.pid, type: pay_type, out_trade_no: orderId, notify_url: `${config.url}/Order/CallBack`, return_url: paymentConfig.return_url + orderId, name: goods.name, money: goods.price } const sign = generatePaymentSign(payParams, paymentConfig.key) payParams.sign = sign payParams.sign_type = 'MD5' await Redis.set(`payData:${orderId}`, JSON.stringify(payParams), { EX: 300 }) res.json({ ...BaseStdResponse.OK, id: orderId, pay: { payUrl: `${paymentConfig.url}/submit.php`, payData: payParams } }) // 定时器轮询订单状态 // try { // // 定时轮询订单状态,最多持续5分钟(300秒),每次间隔5秒 // const MAX_RETRIES = 60 // 5分钟 / 5秒 // const DELAY = 5000 // 5秒 // const queryUrl = `${paymentConfig.url}/api.php?act=order&pid=${paymentConfig.pid}&key=${paymentConfig.key}&out_trade_no=${orderId}` // const pollOrderStatus = async (retry = 0) => { // if (retry >= MAX_RETRIES) { // this.logger.info(`订单超时未支付,订单号:${orderId}`) // await db.query('UPDATE orders SET state = 3 WHERE orderId = ?', [orderId]); // return // } // try { // const queryRes = await axios.get(queryUrl) // const queryData = queryRes.data // if (queryData.code === 1 && queryData.status === 1) { // const { trade_no, out_trade_no, type } = queryData // const time = Date.now() // let sql = 'UPDATE orders SET state = 1, pay_type = ?, pay_id = ?, pay_time = ? WHERE orderId = ? AND state = 0' // const result = await db.query(sql, [type, trade_no, time, out_trade_no]) // if (result.affectedRows > 0) { // // 查询订单与商品信息 // sql = ` // SELECT // g.lepao_count, // g.ic_count, // g.vip, // a.create_user // FROM // orders a // LEFT JOIN // goods g // ON // a.goods_id = g.id // WHERE // a.orderId = ? // ` // const rows = await db.query(sql, [out_trade_no]) // if (!rows || rows.length !== 1) { // this.logger.error(`订单商品信息异常,订单号:${out_trade_no}`) // await db.query('UPDATE orders SET state = 4 WHERE orderId = ?', [out_trade_no]) // return // } // const { lepao_count, ic_count, vip, create_user } = rows[0] // sql = 'UPDATE users SET lepao_count = lepao_count + ?, ic_count = ic_count + ?, vip = ? WHERE uuid = ?' // const updateUser = await db.query(sql, [lepao_count, ic_count, vip, create_user]) // if (!updateUser || updateUser.affectedRows !== 1) { // this.logger.error(`更新用户失败,UUID: ${create_user}`) // await db.query('UPDATE orders SET state = 4 WHERE orderId = ?', [out_trade_no]) // } // sql = 'UPDATE orders SET state = 2 WHERE orderId = ?' // await db.query(sql, [out_trade_no]) // this.logger.info(`订单处理成功:${out_trade_no}`) // return // 成功处理后终止轮询 // } else { // this.logger.warn(`订单不存在或已处理:${out_trade_no}`) // } // } // // 未支付,继续轮询 // setTimeout(() => pollOrderStatus(retry + 1), DELAY) // } catch (error) { // this.logger.warn(`轮询支付状态失败:${error.stack}`) // setTimeout(() => pollOrderStatus(retry + 1), DELAY) // } // } // // 启动轮询 // pollOrderStatus() // } catch { // this.logger.info(`获取订单支付状态失败!${error.stack}`) // } } else { return res.json({ ...BaseStdResponse.ERR, msg: '创建订单失败', endpoint: 7894378 }) } } catch (err) { this.logger.error(`创建订单失败!${err.stack}`) return res.json({ ...BaseStdResponse.ERR, msg: "创建订单异常,请联系管理员" }) } } } module.exports.CreateOrder = CreateOrder