From 4ff89802687e57611479b89bfeab4389f46c13fe Mon Sep 17 00:00:00 2001 From: aaron <> Date: Mon, 11 Aug 2025 13:19:45 +0800 Subject: [PATCH] update --- public/admin.html | 159 ++++++++++++++++++------ public/css/admin.css | 224 ++++++++++++++++++++++++++++++++++ public/css/style.css | 95 +++++++++++++++ public/index.html | 13 ++ public/js/admin.js | 280 +++++++++++++++++++++++++++++++++++++++++++ public/js/main.js | 158 +++++++++++++++++++++--- server.js | 274 ++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 1144 insertions(+), 59 deletions(-) diff --git a/public/admin.html b/public/admin.html index 138693f..6ffc1a8 100644 --- a/public/admin.html +++ b/public/admin.html @@ -29,44 +29,135 @@ -
-
-

订单列表

-
- + + +
+
+ + +
+ +
diff --git a/public/js/admin.js b/public/js/admin.js index 3a2532e..6b1dc4a 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -1,19 +1,47 @@ // 订单管理页面脚本 let currentOrders = []; +let currentCoupons = []; let currentOrderId = null; // DOM 元素 const ordersTableBody = document.getElementById('ordersTableBody'); +const couponsTableBody = document.getElementById('couponsTableBody'); const searchInput = document.getElementById('searchOrder'); const statusFilter = document.getElementById('statusFilter'); const orderDetailModal = document.getElementById('orderDetailModal'); const shippingModal = document.getElementById('shippingModal'); +const createCouponModal = document.getElementById('createCouponModal'); // 页面加载时初始化 document.addEventListener('DOMContentLoaded', function() { loadOrders(); + loadCoupons(); }); +// 选项卡切换功能 +function showTab(tabName) { + // 隐藏所有选项卡内容 + const tabs = document.querySelectorAll('.tab-content'); + tabs.forEach(tab => tab.classList.remove('active')); + + // 移除所有按钮的活动状态 + const buttons = document.querySelectorAll('.tab-btn'); + buttons.forEach(btn => btn.classList.remove('active')); + + // 显示选中的选项卡内容 + document.getElementById(tabName + 'Tab').classList.add('active'); + + // 激活相应按钮 + event.target.classList.add('active'); + + // 根据选项卡加载数据 + if (tabName === 'coupons') { + loadCoupons(); + } else if (tabName === 'orders') { + loadOrders(); + } +} + // 加载订单列表 async function loadOrders(search = '', status = '') { try { @@ -430,6 +458,258 @@ function formatDate(dateString) { }); } +// 加载优惠码列表 +async function loadCoupons() { + try { + showCouponsLoading(); + + const response = await fetch('/api/admin/coupons'); + const data = await response.json(); + + if (response.ok) { + currentCoupons = data.coupons; + updateCouponsTable(data.coupons); + } else { + throw new Error(data.error || '加载优惠码失败'); + } + } catch (error) { + console.error('Load coupons error:', error); + showCouponsError('加载优惠码失败: ' + error.message); + } +} + +// 更新优惠码表格 +function updateCouponsTable(coupons) { + if (!coupons || coupons.length === 0) { + couponsTableBody.innerHTML = '暂无优惠码数据'; + return; + } + + couponsTableBody.innerHTML = coupons.map(coupon => ` + + + ${coupon.code} + + ${coupon.name} + + + ${coupon.discount_type === 'percentage' ? coupon.discount_value + '%' : '$' + coupon.discount_value.toFixed(2)} + + + + + ${coupon.discount_type === 'percentage' ? '百分比' : '固定金额'} + + + +
+ 已使用: ${coupon.used_count} / ${coupon.max_uses === 999999 ? '无限' : coupon.max_uses}
+ ${coupon.is_reusable ? '可重复使用' : '一次性使用'} +
+ + + + ${coupon.is_active ? '启用' : '禁用'} + + + + ${formatDate(coupon.created_at)} + + + + + + + `).join(''); +} + +// 显示创建优惠码模态框 +function showCreateCouponModal() { + // 清空表单 + document.getElementById('couponCode').value = ''; + document.getElementById('couponName').value = ''; + document.getElementById('discountType').value = 'percentage'; + document.getElementById('discountValue').value = ''; + document.getElementById('isReusable').checked = false; + document.getElementById('maxUses').value = '1'; + document.getElementById('maxUsesGroup').style.display = 'none'; + onDiscountTypeChange(); // 更新提示文本 + + createCouponModal.style.display = 'flex'; + document.getElementById('couponCode').focus(); +} + +// 关闭创建优惠码模态框 +function closeCreateCouponModal() { + createCouponModal.style.display = 'none'; +} + +// 折扣类型变化处理 +function onDiscountTypeChange() { + const discountType = document.getElementById('discountType').value; + const hint = document.getElementById('discountHint'); + + if (discountType === 'percentage') { + hint.textContent = '输入百分比数值,如:10 表示10%折扣'; + } else { + hint.textContent = '输入固定金额,如:5 表示减5美元'; + } +} + +// 可重复使用变化处理 +function onReusableChange() { + const isReusable = document.getElementById('isReusable').checked; + const maxUsesGroup = document.getElementById('maxUsesGroup'); + + if (isReusable) { + maxUsesGroup.style.display = 'block'; + document.getElementById('maxUses').value = '10'; // 默认10次 + } else { + maxUsesGroup.style.display = 'none'; + document.getElementById('maxUses').value = '1'; + } +} + +// 创建优惠码 +async function createCoupon() { + const code = document.getElementById('couponCode').value.trim(); + const name = document.getElementById('couponName').value.trim(); + const discountType = document.getElementById('discountType').value; + const discountValue = parseFloat(document.getElementById('discountValue').value); + const isReusable = document.getElementById('isReusable').checked; + const maxUses = parseInt(document.getElementById('maxUses').value); + + // 验证表单 + if (!code || !name || !discountValue) { + alert('请填写所有必填字段'); + return; + } + + if (discountValue <= 0) { + alert('折扣值必须大于0'); + return; + } + + if (discountType === 'percentage' && discountValue > 100) { + alert('百分比折扣不能超过100%'); + return; + } + + if (isReusable && (!maxUses || maxUses < 1)) { + alert('最大使用次数必须大于0'); + return; + } + + try { + const response = await fetch('/api/admin/coupons', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + code: code, + name: name, + discount_type: discountType, + discount_value: discountValue, + is_reusable: isReusable, + max_uses: maxUses + }) + }); + + const result = await response.json(); + + if (response.ok) { + alert('优惠码创建成功!'); + closeCreateCouponModal(); + loadCoupons(); // 重新加载优惠码列表 + } else { + throw new Error(result.error || '创建优惠码失败'); + } + } catch (error) { + console.error('Create coupon error:', error); + alert('创建优惠码失败: ' + error.message); + } +} + +// 切换优惠码状态 +async function toggleCouponStatus(couponId, isActive) { + try { + const response = await fetch(`/api/admin/coupons/${couponId}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + is_active: isActive + }) + }); + + const result = await response.json(); + + if (response.ok) { + alert(`优惠码已${isActive ? '启用' : '禁用'}!`); + loadCoupons(); // 重新加载优惠码列表 + } else { + throw new Error(result.error || '更新优惠码状态失败'); + } + } catch (error) { + console.error('Toggle coupon status error:', error); + alert('更新优惠码状态失败: ' + error.message); + } +} + +// 确认删除优惠码 +function confirmDeleteCoupon(couponId) { + const coupon = currentCoupons.find(c => c.id === couponId); + if (!coupon) { + alert('优惠码未找到'); + return; + } + + const confirmMessage = `确认删除以下优惠码吗?\n\n优惠码:${coupon.code}\n名称:${coupon.name}\n已使用次数:${coupon.used_count}\n\n⚠️ 此操作不可撤销!`; + + if (confirm(confirmMessage)) { + deleteCoupon(couponId); + } +} + +// 删除优惠码 +async function deleteCoupon(couponId) { + try { + const response = await fetch(`/api/admin/coupons/${couponId}`, { + method: 'DELETE' + }); + + const result = await response.json(); + + if (response.ok) { + alert('优惠码已成功删除!'); + loadCoupons(); // 重新加载优惠码列表 + } else { + throw new Error(result.error || '删除优惠码失败'); + } + } catch (error) { + console.error('Delete coupon error:', error); + alert('删除优惠码失败: ' + error.message); + } +} + +// 显示优惠码加载状态 +function showCouponsLoading() { + couponsTableBody.innerHTML = '加载中...'; +} + +// 显示优惠码错误信息 +function showCouponsError(message) { + couponsTableBody.innerHTML = `错误: ${message}`; +} + // 确认删除订单 function confirmDeleteOrder(orderId) { const order = currentOrders.find(o => o.order_id === orderId); diff --git a/public/js/main.js b/public/js/main.js index 0bcc358..a4a2d8c 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,6 +1,7 @@ // 全局变量 let currentProduct = null; let currentOrder = null; +let appliedCoupon = null; // 当前应用的优惠码 // DOM 元素 const productPrice = document.getElementById('product-price'); @@ -99,6 +100,24 @@ function setupEventListeners() { } }); + // 优惠码输入监听 + document.getElementById('coupon-code').addEventListener('input', function(e) { + // 自动转换为大写 + e.target.value = e.target.value.toUpperCase(); + // 清除已应用的优惠码状态 + if (appliedCoupon) { + clearAppliedCoupon(); + } + }); + + // 优惠码回车键应用 + document.getElementById('coupon-code').addEventListener('keypress', function(e) { + if (e.key === 'Enter') { + e.preventDefault(); + applyCoupon(); + } + }); + // 支付状态检查 document.getElementById('check-status-btn').addEventListener('click', checkPaymentStatus); @@ -118,41 +137,61 @@ function updateTotalPrice() { const unitPrice = currentProduct.price; const originalTotal = unitPrice * quantity; - // 计算折扣 - let discount = 0; - let discountText = ''; - let finalTotal = originalTotal; + // 计算数量折扣 + let quantityDiscount = 0; + let quantityDiscountText = ''; + let afterQuantityDiscount = originalTotal; if (quantity >= 5) { - discount = 0.1; // 9折,优惠10% - discountText = '5个及以上 9折优惠'; - finalTotal = originalTotal * 0.9; + quantityDiscount = originalTotal * 0.1; // 9折,优惠10% + quantityDiscountText = '5个及以上 9折优惠'; + afterQuantityDiscount = originalTotal * 0.9; } else if (quantity >= 2) { - discount = 0.05; // 9.5折,优惠5% - discountText = '2个 9.5折优惠'; - finalTotal = originalTotal * 0.95; + quantityDiscount = originalTotal * 0.05; // 9.5折,优惠5% + quantityDiscountText = '2个 9.5折优惠'; + afterQuantityDiscount = originalTotal * 0.95; + } + + // 计算优惠码折扣 + let couponDiscount = 0; + let finalTotal = afterQuantityDiscount; + + if (appliedCoupon) { + if (appliedCoupon.discount_type === 'percentage') { + couponDiscount = afterQuantityDiscount * (appliedCoupon.discount_value / 100); + } else if (appliedCoupon.discount_type === 'fixed') { + couponDiscount = Math.min(appliedCoupon.discount_value, afterQuantityDiscount); + } + finalTotal = afterQuantityDiscount - couponDiscount; } // 更新显示 const discountLine = document.getElementById('discount-line'); const subtotalLine = document.getElementById('subtotal-line'); + const couponDiscountLine = document.getElementById('coupon-discount-line'); const discountTextElement = document.getElementById('discount-text'); const subtotalPriceElement = document.getElementById('subtotal-price'); + const couponDiscountTextElement = document.getElementById('coupon-discount-text'); - // 始终显示优惠和小计信息 - if (discount > 0) { - // 显示优惠信息 - const discountAmount = originalTotal - finalTotal; - discountTextElement.textContent = `-$${discountAmount.toFixed(2)} USDT (${discountText})`; + // 数量折扣显示 + if (quantityDiscount > 0) { + discountTextElement.textContent = `-$${quantityDiscount.toFixed(2)} USDT (${quantityDiscountText})`; subtotalPriceElement.textContent = `$${originalTotal.toFixed(2)} USDT`; discountLine.classList.remove('no-discount'); } else { - // 显示无优惠 discountTextElement.textContent = `$0.00 USDT (无优惠)`; subtotalPriceElement.textContent = `$${originalTotal.toFixed(2)} USDT`; discountLine.classList.add('no-discount'); } + // 优惠码折扣显示 + if (appliedCoupon && couponDiscount > 0) { + couponDiscountTextElement.textContent = `-$${couponDiscount.toFixed(2)} USDT (${appliedCoupon.name})`; + couponDiscountLine.style.display = 'flex'; + } else { + couponDiscountLine.style.display = 'none'; + } + discountLine.style.display = 'flex'; subtotalLine.style.display = 'flex'; @@ -221,6 +260,87 @@ function validatePhoneField(phoneInput) { } } +// 应用优惠码 +async function applyCoupon() { + const couponCode = document.getElementById('coupon-code').value.trim(); + const applyBtn = document.getElementById('apply-coupon-btn'); + const messageEl = document.getElementById('coupon-message'); + + if (!couponCode) { + showCouponMessage('请输入优惠码', 'error'); + return; + } + + // 禁用按钮 + applyBtn.disabled = true; + applyBtn.textContent = '验证中...'; + + try { + const response = await fetch('/api/coupons/validate', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ code: couponCode }) + }); + + const result = await response.json(); + + if (response.ok && result.valid) { + // 优惠码有效,应用优惠 + appliedCoupon = result.coupon; + updateTotalPrice(); + + // 更新UI状态 + document.getElementById('coupon-code').readOnly = true; + applyBtn.textContent = '移除'; + applyBtn.onclick = clearAppliedCoupon; + + const discountText = result.coupon.discount_type === 'percentage' + ? `${result.coupon.discount_value}%折扣` + : `$${result.coupon.discount_value}减免`; + showCouponMessage(`✓ 优惠码"${result.coupon.name}"已应用 (${discountText})`, 'success'); + } else { + showCouponMessage(result.message || '优惠码无效', 'error'); + } + } catch (error) { + console.error('Apply coupon error:', error); + showCouponMessage('验证优惠码失败,请稍后重试', 'error'); + } finally { + if (!appliedCoupon) { + applyBtn.disabled = false; + applyBtn.textContent = '使用'; + } + } +} + +// 清除已应用的优惠码 +function clearAppliedCoupon() { + appliedCoupon = null; + updateTotalPrice(); + + // 重置UI状态 + document.getElementById('coupon-code').readOnly = false; + document.getElementById('coupon-code').value = ''; + const applyBtn = document.getElementById('apply-coupon-btn'); + applyBtn.disabled = false; + applyBtn.textContent = '使用'; + applyBtn.onclick = applyCoupon; + + showCouponMessage('优惠码已移除', 'info'); + setTimeout(() => { + document.getElementById('coupon-message').style.display = 'none'; + }, 2000); +} + +// 显示优惠码消息 +function showCouponMessage(message, type = 'info') { + const messageEl = document.getElementById('coupon-message'); + messageEl.textContent = message; + messageEl.className = `coupon-message ${type}`; + messageEl.style.display = 'block'; +} + // 验证数量 function validateQuantity() { const value = parseInt(quantityInput.value); @@ -264,7 +384,8 @@ async function handleOrderSubmit(e) { customer_name: formData.get('customer_name').trim(), customer_email: formData.get('customer_email').trim(), customer_phone: formData.get('customer_phone').trim(), - shipping_address: formData.get('shipping_address').trim() + shipping_address: formData.get('shipping_address').trim(), + coupon_code: appliedCoupon ? appliedCoupon.code : null }; // 验证必填字段 @@ -608,7 +729,8 @@ async function handleShippingOrderSubmit(e) { customer_name: formData.get('customer_name').trim(), customer_email: formData.get('customer_email').trim(), customer_phone: formData.get('customer_phone').trim(), - shipping_address: formData.get('shipping_address').trim() + shipping_address: formData.get('shipping_address').trim(), + coupon_code: appliedCoupon ? appliedCoupon.code : null }; // 验证必填字段 diff --git a/server.js b/server.js index 4efa365..22d5870 100644 --- a/server.js +++ b/server.js @@ -36,9 +36,36 @@ db.serialize(() => { shipping_status TEXT DEFAULT 'pending', tracking_number TEXT, shipping_notes TEXT, + coupon_code TEXT, + coupon_discount REAL DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP )`); + + // 创建优惠码表 + db.run(`CREATE TABLE IF NOT EXISTS coupons ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + code TEXT UNIQUE NOT NULL, + name TEXT NOT NULL, + discount_type TEXT NOT NULL, -- 'percentage' 或 'fixed' + discount_value REAL NOT NULL, + is_reusable INTEGER DEFAULT 0, -- 0:一次性 1:可重复使用 + used_count INTEGER DEFAULT 0, + max_uses INTEGER DEFAULT 1, + is_active INTEGER DEFAULT 1, -- 0:禁用 1:启用 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP + )`); + + // 创建优惠码使用记录表 + db.run(`CREATE TABLE IF NOT EXISTS coupon_uses ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + coupon_id INTEGER NOT NULL, + order_id TEXT NOT NULL, + used_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (coupon_id) REFERENCES coupons(id), + FOREIGN KEY (order_id) REFERENCES orders(order_id) + )`); }); // UPay 配置 @@ -85,7 +112,8 @@ app.post('/api/orders', async (req, res) => { customer_name, customer_email, customer_phone, - shipping_address + shipping_address, + coupon_code } = req.body; // 验证产品 @@ -99,12 +127,53 @@ app.post('/api/orders', async (req, res) => { const expectedUnitPrice = product.price; const originalTotal = expectedUnitPrice * quantity; let expectedTotal = originalTotal; + let quantityDiscount = 0; + let couponDiscount = 0; + let appliedCoupon = null; - // 服务器端折扣计算验证 + // 数量折扣计算 if (quantity >= 5) { - expectedTotal = originalTotal * 0.9; // 9折 + quantityDiscount = originalTotal * 0.1; // 9折,优惠10% + expectedTotal = originalTotal * 0.9; } else if (quantity >= 2) { - expectedTotal = originalTotal * 0.95; // 9.5折 + quantityDiscount = originalTotal * 0.05; // 9.5折,优惠5% + expectedTotal = originalTotal * 0.95; + } + + // 处理优惠码 + if (coupon_code) { + const coupon = await new Promise((resolve, reject) => { + db.get(` + SELECT * FROM coupons + WHERE code = ? AND is_active = 1 + `, [coupon_code.toUpperCase()], (err, row) => { + if (err) reject(err); + else resolve(row); + }); + }); + + if (coupon) { + // 检查使用次数限制 + if (!coupon.is_reusable && coupon.used_count >= coupon.max_uses) { + return res.status(400).json({ error: '优惠码已被使用' }); + } + + if (coupon.is_reusable && coupon.used_count >= coupon.max_uses) { + return res.status(400).json({ error: '优惠码使用次数已达上限' }); + } + + // 计算优惠码折扣(基于数量折扣后的价格) + if (coupon.discount_type === 'percentage') { + couponDiscount = expectedTotal * (coupon.discount_value / 100); + } else if (coupon.discount_type === 'fixed') { + couponDiscount = Math.min(coupon.discount_value, expectedTotal); + } + + expectedTotal -= couponDiscount; + appliedCoupon = coupon; + } else { + return res.status(400).json({ error: '优惠码不存在或已失效' }); + } } // 价格验证(允许小数点误差) @@ -117,23 +186,41 @@ app.post('/api/orders', async (req, res) => { // 保存订单到数据库 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 (?, ?, ?, ?, ?, ?, ?, ?, ?) + customer_name, customer_email, customer_phone, shipping_address, + coupon_code, coupon_discount) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); stmt.run([ order_id, product.name, quantity, expectedTotal / quantity, expectedTotal, - customer_name, customer_email, customer_phone, shipping_address + customer_name, customer_email, customer_phone, shipping_address, + appliedCoupon ? appliedCoupon.code : null, + couponDiscount ], function(err) { if (err) { console.error(err); return res.status(500).json({ error: '订单创建失败' }); } + // 如果使用了优惠码,更新使用次数和记录 + if (appliedCoupon) { + db.run(` + UPDATE coupons + SET used_count = used_count + 1, updated_at = CURRENT_TIMESTAMP + WHERE id = ? + `, [appliedCoupon.id]); + + db.run(` + INSERT INTO coupon_uses (coupon_id, order_id) + VALUES (?, ?) + `, [appliedCoupon.id, order_id]); + } + res.json({ success: true, order_id, total_amount: expectedTotal, + coupon_discount: couponDiscount, message: '订单创建成功' }); }); @@ -411,6 +498,179 @@ app.put('/api/admin/orders/:order_id/shipping', (req, res) => { ); }); +// 验证优惠码 +app.post('/api/coupons/validate', (req, res) => { + const { code } = req.body; + + if (!code) { + return res.status(400).json({ error: '请输入优惠码' }); + } + + db.get(` + SELECT * FROM coupons + WHERE code = ? AND is_active = 1 + `, [code], (err, coupon) => { + if (err) { + console.error('Query coupon error:', err); + return res.status(500).json({ error: '查询优惠码失败' }); + } + + if (!coupon) { + return res.json({ valid: false, message: '优惠码不存在或已失效' }); + } + + // 检查使用次数限制 + if (!coupon.is_reusable && coupon.used_count >= coupon.max_uses) { + return res.json({ valid: false, message: '优惠码已被使用' }); + } + + if (coupon.is_reusable && coupon.used_count >= coupon.max_uses) { + return res.json({ valid: false, message: '优惠码使用次数已达上限' }); + } + + res.json({ + valid: true, + coupon: { + id: coupon.id, + code: coupon.code, + name: coupon.name, + discount_type: coupon.discount_type, + discount_value: coupon.discount_value + } + }); + }); +}); + +// 获取所有优惠码(管理员) +app.get('/api/admin/coupons', (req, res) => { + const { limit = 50, offset = 0 } = req.query; + + db.all(` + SELECT * FROM coupons + ORDER BY created_at DESC + LIMIT ? OFFSET ? + `, [parseInt(limit), parseInt(offset)], (err, coupons) => { + if (err) { + console.error('Query coupons error:', err); + return res.status(500).json({ error: '查询优惠码失败' }); + } + + res.json({ coupons }); + }); +}); + +// 创建优惠码(管理员) +app.post('/api/admin/coupons', (req, res) => { + const { + code, + name, + discount_type, + discount_value, + is_reusable, + max_uses + } = req.body; + + // 验证必填字段 + if (!code || !name || !discount_type || discount_value === undefined) { + return res.status(400).json({ error: '请填写所有必填字段' }); + } + + // 验证折扣类型 + if (!['percentage', 'fixed'].includes(discount_type)) { + return res.status(400).json({ error: '无效的折扣类型' }); + } + + // 验证折扣值 + if (discount_value <= 0) { + return res.status(400).json({ error: '折扣值必须大于0' }); + } + + if (discount_type === 'percentage' && discount_value > 100) { + return res.status(400).json({ error: '百分比折扣不能超过100%' }); + } + + const stmt = db.prepare(` + INSERT INTO coupons (code, name, discount_type, discount_value, is_reusable, max_uses) + VALUES (?, ?, ?, ?, ?, ?) + `); + + stmt.run([ + code.toUpperCase(), + name, + discount_type, + discount_value, + is_reusable ? 1 : 0, + max_uses || 1 + ], function(err) { + if (err) { + console.error('Create coupon error:', err); + if (err.message.includes('UNIQUE constraint failed')) { + return res.status(400).json({ error: '优惠码已存在' }); + } + return res.status(500).json({ error: '创建优惠码失败' }); + } + + res.json({ + success: true, + message: '优惠码创建成功', + coupon_id: this.lastID + }); + }); + + stmt.finalize(); +}); + +// 更新优惠码状态(管理员) +app.put('/api/admin/coupons/:id', (req, res) => { + const { id } = req.params; + const { is_active } = req.body; + + if (is_active === undefined) { + return res.status(400).json({ error: '请提供状态参数' }); + } + + db.run(` + UPDATE coupons + SET is_active = ?, updated_at = CURRENT_TIMESTAMP + WHERE id = ? + `, [is_active ? 1 : 0, id], function(err) { + if (err) { + console.error('Update coupon error:', err); + return res.status(500).json({ error: '更新优惠码失败' }); + } + + if (this.changes === 0) { + return res.status(404).json({ error: '优惠码未找到' }); + } + + res.json({ + success: true, + message: '优惠码状态更新成功' + }); + }); +}); + +// 删除优惠码(管理员) +app.delete('/api/admin/coupons/:id', (req, res) => { + const { id } = req.params; + + db.run('DELETE FROM coupons WHERE id = ?', [id], function(err) { + if (err) { + console.error('Delete coupon error:', err); + return res.status(500).json({ error: '删除优惠码失败' }); + } + + if (this.changes === 0) { + return res.status(404).json({ error: '优惠码未找到' }); + } + + res.json({ + success: true, + message: '优惠码已删除' + }); + }); +}); + // 删除订单(管理员) app.delete('/api/admin/orders/:order_id', (req, res) => { const { order_id } = req.params;