782 lines
27 KiB
JavaScript
782 lines
27 KiB
JavaScript
// 订单管理页面脚本
|
||
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 {
|
||
showLoading();
|
||
|
||
const params = new URLSearchParams();
|
||
if (search) params.append('search', search);
|
||
if (status) params.append('status', status);
|
||
|
||
const response = await fetch(`/api/admin/orders?${params}`);
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
currentOrders = data.orders;
|
||
updateOrdersTable(data.orders);
|
||
updateStats(data.stats);
|
||
} else {
|
||
throw new Error(data.error || '加载订单失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('Load orders error:', error);
|
||
showError('加载订单失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// 更新订单表格
|
||
function updateOrdersTable(orders) {
|
||
if (!orders || orders.length === 0) {
|
||
ordersTableBody.innerHTML = '<tr><td colspan="8" class="loading">暂无订单数据</td></tr>';
|
||
return;
|
||
}
|
||
|
||
ordersTableBody.innerHTML = orders.map(order => `
|
||
<tr>
|
||
<td>
|
||
<strong>${order.order_id}</strong>
|
||
</td>
|
||
<td>
|
||
<div style="line-height: 1.4;">
|
||
<strong>${order.customer_name}</strong>
|
||
<button class="copy-btn" onclick="copyOrderInfo('${order.order_id}')" title="复制收货信息" style="margin-left: 5px; font-size: 12px;">📋</button><br>
|
||
<small style="color: #666;">${order.customer_phone || '未提供电话'}</small><br>
|
||
<small style="color: #666; font-size: 11px; max-width: 200px; display: inline-block; word-wrap: break-word;">${order.shipping_address ? (order.shipping_address.length > 30 ? order.shipping_address.substring(0, 30) + '...' : order.shipping_address) : '未提供地址'}</small>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div>
|
||
${order.product_name}<br>
|
||
<small style="color: #888;">数量: ${order.quantity}</small>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<strong style="color: #ffd700;">$${order.total_amount.toFixed(2)}</strong>
|
||
</td>
|
||
<td>
|
||
<span class="status-badge status-${order.payment_status}">
|
||
${getStatusText(order.payment_status, 'payment')}
|
||
</span>
|
||
</td>
|
||
<td>
|
||
<span class="status-badge status-${order.shipping_status}">
|
||
${getStatusText(order.shipping_status, 'shipping')}
|
||
</span>
|
||
</td>
|
||
<td>
|
||
${formatDate(order.created_at)}
|
||
</td>
|
||
<td>
|
||
<button class="action-btn btn-ship" onclick="showShippingModal('${order.order_id}')">
|
||
📦 发货
|
||
</button>
|
||
<button class="action-btn btn-delete" onclick="confirmDeleteOrder('${order.order_id}')" title="删除订单">
|
||
🗑️ 删除
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
// 更新统计数据
|
||
function updateStats(stats) {
|
||
if (stats) {
|
||
const totalElement = document.getElementById('totalOrders');
|
||
const pendingElement = document.getElementById('pendingOrders');
|
||
const shippedElement = document.getElementById('shippedOrders');
|
||
|
||
if (totalElement) totalElement.textContent = stats.total || 0;
|
||
if (pendingElement) pendingElement.textContent = stats.pending_ship || 0;
|
||
if (shippedElement) shippedElement.textContent = stats.shipped || 0;
|
||
}
|
||
}
|
||
|
||
// 搜索订单
|
||
function searchOrders() {
|
||
const search = searchInput.value.trim();
|
||
const status = statusFilter.value;
|
||
loadOrders(search, status);
|
||
}
|
||
|
||
// 筛选订单
|
||
function filterOrders() {
|
||
const search = searchInput.value.trim();
|
||
const status = statusFilter.value;
|
||
loadOrders(search, status);
|
||
}
|
||
|
||
// 显示订单详情
|
||
async function showOrderDetail(orderId) {
|
||
try {
|
||
const response = await fetch(`/api/orders/${orderId}`);
|
||
const order = await response.json();
|
||
|
||
if (response.ok) {
|
||
const detailContent = document.getElementById('orderDetailContent');
|
||
detailContent.innerHTML = `
|
||
<div class="detail-section">
|
||
<h4>基本信息</h4>
|
||
<div class="detail-row">
|
||
<span class="detail-label">订单号:</span>
|
||
<span class="detail-value">${order.order_id}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">支付ID:</span>
|
||
<span class="detail-value">${order.payment_id || '未设置'}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">创建时间:</span>
|
||
<span class="detail-value">${formatDate(order.created_at)}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">更新时间:</span>
|
||
<span class="detail-value">${formatDate(order.updated_at)}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detail-section">
|
||
<h4>客户信息</h4>
|
||
<div class="detail-row">
|
||
<span class="detail-label">姓名:</span>
|
||
<span class="detail-value">${order.customer_name}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">邮箱:</span>
|
||
<span class="detail-value">${order.customer_email || '未提供'}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">电话:</span>
|
||
<span class="detail-value">${order.customer_phone || '未提供'}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">收货地址:</span>
|
||
<span class="detail-value">
|
||
${order.shipping_address}
|
||
<button class="copy-btn" onclick="copyText('${order.shipping_address.replace(/'/g, "\\'")}')">📋</button>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detail-section">
|
||
<h4>商品信息</h4>
|
||
<div class="detail-row">
|
||
<span class="detail-label">产品名称:</span>
|
||
<span class="detail-value">${order.product_name}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">单价:</span>
|
||
<span class="detail-value">$${order.unit_price.toFixed(2)}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">数量:</span>
|
||
<span class="detail-value">${order.quantity}</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">总金额:</span>
|
||
<span class="detail-value" style="color: #ffd700; font-weight: bold;">$${order.total_amount.toFixed(2)}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detail-section">
|
||
<h4>状态信息</h4>
|
||
<div class="detail-row">
|
||
<span class="detail-label">支付状态:</span>
|
||
<span class="detail-value">
|
||
<span class="status-badge status-${order.payment_status}">
|
||
${getStatusText(order.payment_status, 'payment')}
|
||
</span>
|
||
</span>
|
||
</div>
|
||
<div class="detail-row">
|
||
<span class="detail-label">发货状态:</span>
|
||
<span class="detail-value">
|
||
<span class="status-badge status-${order.shipping_status}">
|
||
${getStatusText(order.shipping_status, 'shipping')}
|
||
</span>
|
||
</span>
|
||
</div>
|
||
${order.tracking_number ? `
|
||
<div class="detail-row">
|
||
<span class="detail-label">快递单号:</span>
|
||
<span class="detail-value">${order.tracking_number}</span>
|
||
</div>` : ''}
|
||
${order.shipping_notes ? `
|
||
<div class="detail-row">
|
||
<span class="detail-label">发货备注:</span>
|
||
<span class="detail-value">${order.shipping_notes}</span>
|
||
</div>` : ''}
|
||
</div>
|
||
`;
|
||
|
||
orderDetailModal.style.display = 'flex';
|
||
} else {
|
||
throw new Error(order.error || '获取订单详情失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('Show order detail error:', error);
|
||
alert('获取订单详情失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// 复制订单收货信息
|
||
function copyOrderInfo(orderId) {
|
||
const order = currentOrders.find(o => o.order_id === orderId);
|
||
if (!order) return;
|
||
|
||
// 组合收货信息:姓名, 电话, 地址
|
||
let infoText = order.customer_name;
|
||
if (order.customer_phone) {
|
||
infoText += ', ' + order.customer_phone;
|
||
}
|
||
infoText += ', ' + order.shipping_address;
|
||
|
||
// 复制到剪贴板
|
||
copyText(infoText);
|
||
}
|
||
|
||
// 显示发货模态框
|
||
function showShippingModal(orderId) {
|
||
currentOrderId = orderId;
|
||
const order = currentOrders.find(o => o.order_id === orderId);
|
||
if (!order) return;
|
||
|
||
// 清空表单
|
||
document.getElementById('trackingNumber').value = '';
|
||
document.getElementById('shippingNotes').value = '';
|
||
|
||
// 显示模态框
|
||
shippingModal.style.display = 'flex';
|
||
document.getElementById('trackingNumber').focus();
|
||
}
|
||
|
||
// 关闭发货模态框
|
||
function closeShippingModal() {
|
||
shippingModal.style.display = 'none';
|
||
currentOrderId = null;
|
||
}
|
||
|
||
// 确认发货
|
||
async function confirmShipping() {
|
||
const trackingNumber = document.getElementById('trackingNumber').value.trim();
|
||
const shippingNotes = document.getElementById('shippingNotes').value.trim();
|
||
|
||
if (!trackingNumber) {
|
||
alert('请输入运单号');
|
||
document.getElementById('trackingNumber').focus();
|
||
return;
|
||
}
|
||
|
||
if (!currentOrderId) {
|
||
alert('订单ID错误');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`/api/admin/orders/${currentOrderId}/shipping`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
shipping_status: 'shipped',
|
||
tracking_number: trackingNumber,
|
||
shipping_notes: shippingNotes
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (response.ok) {
|
||
alert('订单已成功发货!');
|
||
closeShippingModal();
|
||
loadOrders(); // 重新加载订单列表
|
||
} else {
|
||
throw new Error(result.error || '发货失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('Shipping error:', error);
|
||
alert('发货失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// 确认并标记为已发货
|
||
function confirmMarkAsShipped(orderId) {
|
||
if (confirm('确认标记此订单为已发货吗?')) {
|
||
markAsShipped(orderId);
|
||
}
|
||
}
|
||
|
||
// 一键标记为已发货
|
||
async function markAsShipped(orderId) {
|
||
try {
|
||
const response = await fetch(`/api/admin/orders/${orderId}/shipping`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
shipping_status: 'shipped'
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (response.ok) {
|
||
alert('订单已标记为发货!');
|
||
loadOrders(); // 重新加载订单列表
|
||
} else {
|
||
throw new Error(result.error || '标记发货失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('Mark as shipped error:', error);
|
||
alert('标记发货失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// 复制文本到剪贴板
|
||
async function copyText(text) {
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
// 显示复制成功提示
|
||
showCopySuccess();
|
||
} catch (err) {
|
||
// 降级方案:使用传统方法
|
||
const textArea = document.createElement('textarea');
|
||
textArea.value = text;
|
||
document.body.appendChild(textArea);
|
||
textArea.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(textArea);
|
||
showCopySuccess();
|
||
}
|
||
}
|
||
|
||
// 显示复制成功提示
|
||
function showCopySuccess() {
|
||
// 创建提示元素
|
||
const toast = document.createElement('div');
|
||
toast.className = 'copy-toast';
|
||
toast.textContent = '已复制到剪贴板';
|
||
document.body.appendChild(toast);
|
||
|
||
// 3秒后移除提示
|
||
setTimeout(() => {
|
||
if (toast.parentNode) {
|
||
toast.parentNode.removeChild(toast);
|
||
}
|
||
}, 3000);
|
||
}
|
||
|
||
// 关闭订单详情模态框
|
||
function closeOrderDetail() {
|
||
orderDetailModal.style.display = 'none';
|
||
}
|
||
|
||
// 获取状态文本
|
||
function getStatusText(status, type) {
|
||
if (type === 'payment') {
|
||
switch(status) {
|
||
case 'pending': return '未支付';
|
||
case 'finished': return '已支付';
|
||
case 'failed': return '支付失败';
|
||
case 'confirming': return '确认中';
|
||
default: return status || '未知';
|
||
}
|
||
} else if (type === 'shipping') {
|
||
switch(status) {
|
||
case 'pending': return '未发货';
|
||
case 'shipped': return '已发货';
|
||
default: return status || '未知';
|
||
}
|
||
}
|
||
return status || '未知';
|
||
}
|
||
|
||
// 显示加载状态
|
||
function showLoading() {
|
||
ordersTableBody.innerHTML = '<tr><td colspan="8" class="loading">加载中...</td></tr>';
|
||
}
|
||
|
||
// 显示错误信息
|
||
function showError(message) {
|
||
ordersTableBody.innerHTML = `<tr><td colspan="8" class="loading" style="color: #ff4757;">错误: ${message}</td></tr>`;
|
||
}
|
||
|
||
// 格式化日期
|
||
function formatDate(dateString) {
|
||
if (!dateString) return '未设置';
|
||
const date = new Date(dateString);
|
||
return date.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
});
|
||
}
|
||
|
||
// 加载优惠码列表
|
||
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 = '<tr><td colspan="8" class="loading">暂无优惠码数据</td></tr>';
|
||
return;
|
||
}
|
||
|
||
couponsTableBody.innerHTML = coupons.map(coupon => `
|
||
<tr>
|
||
<td>
|
||
<strong style="font-family: monospace; color: #ffd700;">${coupon.code}</strong>
|
||
</td>
|
||
<td>${coupon.name}</td>
|
||
<td>
|
||
<strong style="color: #28a745;">
|
||
${coupon.discount_type === 'percentage' ? coupon.discount_value + '%' : '$' + coupon.discount_value.toFixed(2)}
|
||
</strong>
|
||
</td>
|
||
<td>
|
||
<span class="coupon-type coupon-${coupon.discount_type}">
|
||
${coupon.discount_type === 'percentage' ? '百分比' : '固定金额'}
|
||
</span>
|
||
</td>
|
||
<td>
|
||
<div style="font-size: 13px;">
|
||
已使用: <strong>${coupon.used_count}</strong> / ${coupon.max_uses === 999999 ? '无限' : coupon.max_uses}<br>
|
||
<small style="color: #888;">${coupon.is_reusable ? '可重复使用' : '一次性使用'}</small>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<span class="status-badge ${coupon.is_active ? 'coupon-active' : 'coupon-inactive'}">
|
||
${coupon.is_active ? '启用' : '禁用'}
|
||
</span>
|
||
</td>
|
||
<td>
|
||
${formatDate(coupon.created_at)}
|
||
</td>
|
||
<td>
|
||
<button class="action-btn ${coupon.is_active ? 'btn-disable' : 'btn-enable'}"
|
||
onclick="toggleCouponStatus(${coupon.id}, ${!coupon.is_active})"
|
||
title="${coupon.is_active ? '禁用' : '启用'}优惠码">
|
||
${coupon.is_active ? '禁用' : '启用'}
|
||
</button>
|
||
<button class="action-btn btn-delete" onclick="confirmDeleteCoupon(${coupon.id})" title="删除优惠码">
|
||
删除
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`).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 {
|
||
console.log('Creating coupon with data:', {
|
||
code, name, discount_type: discountType, discount_value: discountValue, is_reusable: isReusable, max_uses: maxUses
|
||
});
|
||
|
||
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
|
||
})
|
||
});
|
||
|
||
console.log('Response status:', response.status);
|
||
console.log('Response headers:', response.headers);
|
||
|
||
const responseText = await response.text();
|
||
console.log('Response text:', responseText);
|
||
|
||
let result;
|
||
try {
|
||
result = JSON.parse(responseText);
|
||
} catch (parseError) {
|
||
console.error('Failed to parse JSON:', parseError);
|
||
console.error('Response was:', responseText.substring(0, 200));
|
||
throw new Error('服务器返回了无效的响应格式');
|
||
}
|
||
|
||
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 = '<tr><td colspan="8" class="loading">加载中...</td></tr>';
|
||
}
|
||
|
||
// 显示优惠码错误信息
|
||
function showCouponsError(message) {
|
||
couponsTableBody.innerHTML = `<tr><td colspan="8" class="loading" style="color: #ff4757;">错误: ${message}</td></tr>`;
|
||
}
|
||
|
||
// 确认删除订单
|
||
function confirmDeleteOrder(orderId) {
|
||
const order = currentOrders.find(o => o.order_id === orderId);
|
||
if (!order) {
|
||
alert('订单未找到');
|
||
return;
|
||
}
|
||
|
||
const confirmMessage = `确认删除以下订单吗?\n\n订单号:${orderId}\n客户:${order.customer_name}\n金额:$${order.total_amount.toFixed(2)} USDT\n\n⚠️ 此操作不可撤销!`;
|
||
|
||
if (confirm(confirmMessage)) {
|
||
deleteOrder(orderId);
|
||
}
|
||
}
|
||
|
||
// 删除订单
|
||
async function deleteOrder(orderId) {
|
||
try {
|
||
const response = await fetch(`/api/admin/orders/${orderId}`, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (response.ok) {
|
||
alert('订单已成功删除!');
|
||
loadOrders(); // 重新加载订单列表
|
||
} else {
|
||
throw new Error(result.error || '删除订单失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('Delete order error:', error);
|
||
alert('删除订单失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// 键盘事件监听
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
closeOrderDetail();
|
||
closeShippingModal();
|
||
}
|
||
});
|
||
|
||
// 搜索框回车事件
|
||
searchInput.addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
searchOrders();
|
||
}
|
||
}); |