Files
ai_dianshang/web/assets/js/user-center.js
2025-11-28 15:18:10 +08:00

1369 lines
48 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// User Center JavaScript
$(document).ready(function() {
initUserCenter();
});
function initUserCenter() {
// 清除旧版本的本地订单数据(确保使用新的状态码和价格格式)
const user = JSON.parse(localStorage.getItem('currentUser'));
if (user && user.email) {
const oldOrders = localStorage.getItem('orders_' + user.email);
if (oldOrders) {
try {
const orders = JSON.parse(oldOrders);
// 检查第一个订单的price如果小于1000则认为是旧版本元单位
if (orders.length > 0 && orders[0].items && orders[0].items[0]) {
const firstPrice = orders[0].items[0].price;
if (firstPrice < 1000) {
console.log('[用户中心] 检测到旧版本订单数据,清除以使用新格式');
localStorage.removeItem('orders_' + user.email);
}
}
} catch (e) {
console.error('[用户中心] 检查订单数据版本失败:', e);
}
}
}
checkLoginStatus();
loadUserInfo();
loadOrderHistory();
bindUserCenterEvents();
// i18n初始化后重新更新显示
setTimeout(() => {
const user = JSON.parse(localStorage.getItem('currentUser'));
if (user) {
updateAccountDetails(user);
}
}, 100);
}
// 检查登录状态
function checkLoginStatus() {
const user = localStorage.getItem('currentUser');
if (!user) {
// 未登录,跳转到登录页
window.location.href = 'login.html';
return false;
}
return true;
}
// 加载用户信息
function loadUserInfo() {
const user = JSON.parse(localStorage.getItem('currentUser'));
if (user) {
// 侧边栏显示
const displayName = user.nickname || user.email?.split('@')[0] || '用户';
$('#userName').text(displayName);
$('#userEmail').text(user.email || '');
// 账户详情显示
updateAccountDetails(user);
}
}
// 更新账户详情
function updateAccountDetails(user) {
// 用户名
if (user.nickname) {
$('#nicknameValue').text(user.nickname).removeClass('not-set');
$('#editNickname').attr('data-i18n', 'edit_btn').text(i18n.t('edit_btn') || '编辑');
} else {
$('#nicknameValue').addClass('not-set').attr('data-i18n', 'not_set').text(i18n.t('not_set') || '未设置');
$('#editNickname').attr('data-i18n', 'set_btn').text(i18n.t('set_btn') || '设置');
}
// 邮箱
if (user.email) {
$('#emailValue').text(user.email).removeClass('not-set');
$('#editEmail').attr('data-i18n', 'edit_btn').text(i18n.t('edit_btn') || '编辑');
} else {
$('#emailValue').addClass('not-set').attr('data-i18n', 'not_set').text(i18n.t('not_set') || '未设置');
$('#editEmail').attr('data-i18n', 'set_btn').text(i18n.t('set_btn') || '设置');
}
// 手机号
if (user.phone) {
$('#phoneValue').text(user.phone).removeClass('not-set');
$('#editPhone').attr('data-i18n', 'edit_btn').text(i18n.t('edit_btn') || '编辑');
} else {
$('#phoneValue').addClass('not-set').attr('data-i18n', 'not_set').text(i18n.t('not_set') || '未设置');
$('#editPhone').attr('data-i18n', 'set_btn').text(i18n.t('set_btn') || '设置');
}
}
// 绑定事件
function bindUserCenterEvents() {
console.log('Binding user center events...');
// 退出登录
$('#logoutLink').on('click', function(e) {
e.preventDefault();
console.log('Logout clicked');
handleLogout();
});
// 设置用户名
$('#editNickname').on('click', function(e) {
e.preventDefault();
console.log('Edit nickname clicked');
showEditDialog('nickname');
});
// 设置邮箱
$('#editEmail').on('click', function(e) {
e.preventDefault();
console.log('Edit email clicked');
showEditDialog('email');
});
// 设置手机号
$('#editPhone').on('click', function(e) {
e.preventDefault();
console.log('Edit phone clicked');
showEditDialog('phone');
});
console.log('Event binding complete. Buttons found:', {
nickname: $('#editNickname').length,
email: $('#editEmail').length,
phone: $('#editPhone').length
});
}
// 加载订单历史
function loadOrderHistory() {
const user = JSON.parse(localStorage.getItem('currentUser'));
if (!user) return;
const $container = $('#orderHistorySection');
const $emptyMessage = $container.find('.empty-message');
// 显示加载状态
$emptyMessage.html('<p>加载中...</p>');
// 调用API获取订单列表
OrderAPI.getList({
page: 1,
page_size: 10
})
.then(function(data) {
console.log('订单数据:', data);
// 检查是否有订单
if (data && data.list && data.list.length > 0) {
// 移除空状态消息
$emptyMessage.remove();
// 渲染订单列表
renderOrders(data.list);
} else {
// 显示空状态
$emptyMessage.html(`<p data-i18n="no_orders_placed">${i18n.t('no_orders_placed') || '您还没有下过任何订单。'}</p>`);
}
})
.catch(function(error) {
console.error('获取订单失败:', error);
// 如果API调用失败使用本地模拟数据作为降级方案
const orders = getLocalOrders(user.email);
if (orders && orders.length > 0) {
$emptyMessage.remove();
renderOrders(orders);
} else {
$emptyMessage.html(`<p data-i18n="no_orders_placed">${i18n.t('no_orders_placed') || '您还没有下过任何订单。'}</p>`);
}
});
}
// 获取本地模拟订单数据(降级方案)
function getLocalOrders(email) {
let orders = JSON.parse(localStorage.getItem('orders_' + email) || 'null');
if (!orders) {
// 创建模拟订单数据(使用与后端一致的状态码和字段名)
orders = [
{
id: 'ORD-2024-001',
order_no: 'ORD-2024-001',
created_at: '2024-11-15',
status: 6, // 已完成
total_amount: 29999, // 分为单位299.99元
items: [
{
product_name: '手工陶艺套装',
quantity: 1,
price: 29999, // 分为单位
product_image: 'https://picsum.photos/200/200?random=1'
}
]
},
{
id: 'ORD-2024-002',
order_no: 'ORD-2024-002',
created_at: '2024-11-10',
status: 4, // 已发货
total_amount: 45998, // 分为单位459.98元
items: [
{
product_name: '1000片拼图 - 星空',
quantity: 2,
price: 22999, // 分为单位
product_image: 'https://picsum.photos/200/200?random=2'
}
]
},
{
id: 'ORD-2024-003',
order_no: 'ORD-2024-003',
created_at: '2024-11-05',
status: 1, // 未付款
total_amount: 18999, // 分为单位189.99元
items: [
{
product_name: '水彩画套装',
quantity: 1,
price: 18999, // 分为单位
product_image: 'https://picsum.photos/200/200?random=3'
}
]
}
];
localStorage.setItem('orders_' + email, JSON.stringify(orders));
}
return orders;
}
// 渲染订单
function renderOrders(orders) {
const $container = $('#orderHistorySection');
if (!orders || orders.length === 0) {
return;
}
// 移除空状态消息
$container.find('.empty-message').remove();
// 清空现有的订单列表,避免重复显示
$container.find('.orders-list').remove();
// 创建订单列表
const ordersHtml = orders.map(order => {
// 处理订单状态兼容API返回的数字状态和本地模拟的字符串状态
let statusCode = order.status;
let statusStr = '';
// 如果是字符串状态,转换为数字
if (typeof statusCode === 'string') {
const statusMap = {
'pending': 1,
'processing': 1,
'paid': 2,
'shipped': 3,
'delivered': 4,
'completed': 4,
'cancelled': 5
};
statusCode = statusMap[statusCode] || 1;
}
// 根据数字状态码获取显示文本和CSS类
const statusInfo = getOrderStatusInfo(statusCode);
// 处理订单字段(兼容不同命名)
const orderNo = order.order_no || order.id;
const orderDate = order.created_at || order.date || '';
// 价格转换:后端返回的是分,需要转换为元
const orderTotal = PriceUtils.fenToYuan(order.total_amount || order.total || 0);
const orderItems = order.items || [];
const itemsHtml = orderItems.map(item => {
const itemName = item.product_name || item.name || '未知商品';
// 修复:后端返回的字段是 product_image
const itemImage = item.product_image || item.image_url || item.image || 'https://picsum.photos/200/200?random=default';
// 价格转换:分 → 元
const itemPrice = PriceUtils.fenToYuan(item.price || 0);
const itemQuantity = item.quantity || 1;
return `
<div class="order-item">
<img src="${itemImage}" alt="${itemName}" class="order-item-image">
<div class="order-item-info">
<div class="order-item-name">${itemName}</div>
<div class="order-item-quantity">数量: ${itemQuantity}</div>
</div>
<div class="order-item-price">¥${itemPrice.toFixed(2)}</div>
</div>
`;
}).join('');
// 生成操作按钮(参考小程序逻辑)
const buttons = order.buttonVOs || order.button_vos || getOrderListButtons(statusCode);
const buttonsHtml = buttons.map(btn => {
const btnClass = (btn.is_primary || btn.isPrimary) ? 'btn-primary' : 'btn-secondary';
const btnType = btn.type;
const btnText = btn.text || btn.name || '操作';
return `<button class="btn ${btnClass} btn-sm order-list-action" data-type="${btnType}" data-order-no="${orderNo}">${btnText}</button>`;
}).join('');
return `
<div class="order-card" data-order-no="${orderNo}">
<div class="order-header">
<div class="order-id">
<span class="order-label" data-i18n="order_number">订单号:</span>
<span>${orderNo}</span>
</div>
<div class="order-date">${orderDate}</div>
<div class="order-status ${statusInfo.className}">${statusInfo.text}</div>
</div>
<div class="order-items">
${itemsHtml}
</div>
<div class="order-footer">
<div class="order-total">
<span data-i18n="order_total">总计:</span>
<span class="order-total-amount">¥${orderTotal.toFixed(2)}</span>
</div>
<div class="order-actions">
${buttonsHtml}
</div>
</div>
</div>
`;
}).join('');
$container.append(`<div class="orders-list">${ordersHtml}</div>`);
// 绑定操作按钮事件
$('.order-list-action').on('click', function(e) {
e.preventDefault();
e.stopPropagation(); // 阻止事件冒泡
const btnType = parseInt($(this).data('type'));
const orderNo = $(this).data('order-no');
console.log('订单列表操作按钮点击:', btnType, orderNo);
handleOrderListAction(btnType, orderNo);
});
// 绑定订单卡片点击事件,打开详情弹窗
$('.order-card').on('click', function(e) {
// 如果点击的是按钮,不触发卡片点击
if ($(e.target).hasClass('order-list-action') || $(e.target).closest('.order-list-action').length > 0) {
return;
}
const orderNo = $(this).data('order-no');
console.log('订单卡片点击,打开详情:', orderNo);
showOrderDetail(orderNo);
});
}
// 获取订单列表按钮(参考小程序逻辑)
function getOrderListButtons(status) {
switch (status) {
case 1: // 未付款
return [
{ type: 1, name: '取消订单', is_primary: false },
{ type: 2, name: '立即付款', is_primary: true }
];
case 2: // 待发货
case 3:
return [
{ type: 7, name: '申请退款', is_primary: false },
{ type: 3, name: '提醒发货', is_primary: true }
];
case 4: // 已发货
case 5: // 待收货
return [
{ type: 4, name: '确认收货', is_primary: true }
];
case 6: // 已完成
return [
{ type: 6, name: '评价', is_primary: true }
];
case 8: // 退货中
case 9: // 已退款
return [];
default:
return [];
}
}
// 处理订单列表操作按钮点击
function handleOrderListAction(btnType, orderId) {
console.log('处理订单列表操作:', btnType, orderId);
switch (btnType) {
case 1: // 取消订单
handleCancelOrderFromList(orderId);
break;
case 2: // 立即付款
handlePayOrderFromList(orderId);
break;
case 3: // 提醒发货
handleRemindShipFromList(orderId);
break;
case 4: // 确认收货
handleConfirmReceiveFromList(orderId);
break;
case 6: // 评价
Toast.info('评价功能开发中');
break;
case 7: // 申请退款
handleApplyRefundFromList(orderId);
break;
default:
console.log('未知按钮类型:', btnType);
}
}
// 获取订单状态信息
function getOrderStatusInfo(statusCode) {
const lang = i18n.currentLang;
// 状态映射:与小程序和后端保持一致
// 1=未付款, 2=待发货, 3=待发货, 4=已发货, 5=待收货, 6=已完成, 7=已取消, 8=退货中, 9=已退款
const statusMap = {
'zh-CN': {
1: { text: '未付款', className: 'status-processing' },
2: { text: '待发货', className: 'status-processing' },
3: { text: '待发货', className: 'status-processing' },
4: { text: '已发货', className: 'status-shipped' },
5: { text: '待收货', className: 'status-shipped' },
6: { text: '已完成', className: 'status-delivered' },
7: { text: '已取消', className: 'status-cancelled' },
8: { text: '退货中', className: 'status-cancelled' },
9: { text: '已退款', className: 'status-cancelled' }
},
'en-US': {
1: { text: 'Unpaid', className: 'status-processing' },
2: { text: 'To be shipped', className: 'status-processing' },
3: { text: 'To be shipped', className: 'status-processing' },
4: { text: 'Shipped', className: 'status-shipped' },
5: { text: 'To be received', className: 'status-shipped' },
6: { text: 'Completed', className: 'status-delivered' },
7: { text: 'Cancelled', className: 'status-cancelled' },
8: { text: 'Returning', className: 'status-cancelled' },
9: { text: 'Refunded', className: 'status-cancelled' }
},
'ja-JP': {
1: { text: '未払い', className: 'status-processing' },
2: { text: '発送待ち', className: 'status-processing' },
3: { text: '発送待ち', className: 'status-processing' },
4: { text: '発送済み', className: 'status-shipped' },
5: { text: '受け取り待ち', className: 'status-shipped' },
6: { text: '完了', className: 'status-delivered' },
7: { text: 'キャンセル済み', className: 'status-cancelled' },
8: { text: '返品中', className: 'status-cancelled' },
9: { text: '返金済み', className: 'status-cancelled' }
}
};
return statusMap[lang]?.[statusCode] || { text: '未知状态', className: 'status-processing' };
}
// 显示订单详情
function showOrderDetail(orderId) {
console.log('获取订单详情:', orderId);
// 调用API获取订单详情
OrderAPI.getDetail(orderId)
.then(function(data) {
console.log('订单详情数据:', data);
renderOrderDetailModal(data);
})
.catch(function(error) {
console.error('获取订单详情失败:', error);
Toast.error(error.message || '获取订单详情失败');
});
}
// 渲染订单详情弹窗
function renderOrderDetailModal(order) {
// 创建遗罩层
const overlay = document.createElement('div');
overlay.className = 'order-detail-overlay';
// 处理订单状态优先使用orderStatus
const statusInfo = getOrderStatusInfo(order.orderStatus || order.order_status || order.status);
// 处理价格(后端返回的是分为单位)
const totalAmount = PriceUtils.fenToYuan(order.totalAmount || order.total_amount || 0);
const payAmount = PriceUtils.fenToYuan(order.payAmount || order.pay_amount || order.paymentAmount || order.payment_amount || 0);
// 构建订单项HTML优先使用orderItemVOs
const orderItems = order.orderItemVOs || order.order_item_vos || order.items || [];
const itemsHtml = orderItems.map(item => {
const itemName = item.goodsName || item.goods_name || item.product_name || '未知商品';
const itemImage = item.goodsPictureUrl || item.goods_picture_url || item.product_image || 'https://picsum.photos/200/200?random=default';
const itemPrice = PriceUtils.fenToYuan(item.actualPrice || item.actual_price || item.price || 0);
const itemQuantity = item.buyQuantity || item.buy_quantity || item.quantity || 1;
// 处理规格信息
let specsHtml = '';
if (item.specifications && item.specifications.length > 0) {
specsHtml = item.specifications.map(spec =>
`<div class="item-spec">${spec.specTitle || spec.spec_title}: ${spec.specValue || spec.spec_value}</div>`
).join('');
}
return `
<div class="detail-order-item">
<img src="${itemImage}" alt="${itemName}" class="detail-item-image">
<div class="detail-item-info">
<div class="detail-item-name">${itemName}</div>
${specsHtml}
<div class="detail-item-quantity">数量: ${itemQuantity}</div>
</div>
<div class="detail-item-price">¥${itemPrice.toFixed(2)}</div>
</div>
`;
}).join('');
// 构建收货地址HTML优先使用logisticsVO
const logistics = order.logisticsVO || order.logistics_vo || {};
const addressHtml = logistics.receiverAddress || logistics.receiver_address ? `
<div class="detail-section">
<h3>收货信息</h3>
<div class="detail-address">
<div class="address-info">
<div><strong>${logistics.receiverName || logistics.receiver_name || ''}</strong> ${logistics.receiverPhone || logistics.receiver_phone || ''}</div>
<div>${logistics.receiverAddress || logistics.receiver_address || ''}</div>
</div>
</div>
</div>
` : '';
// 构建操作按钮HTML使用后端返回的buttonVOs
const buttons = order.buttonVOs || order.button_vos || [];
const buttonsHtml = buttons.length > 0 ? `
<div class="detail-section">
<div class="detail-actions">
${buttons.map(btn => {
const btnClass = (btn.is_primary || btn.isPrimary) ? 'btn-primary' : 'btn-secondary';
const btnType = btn.type;
const btnText = btn.text || btn.name || '操作';
return `<button class="btn ${btnClass} btn-action" data-type="${btnType}" data-order-id="${order.orderNo || order.order_no}">${btnText}</button>`;
}).join('')}
</div>
</div>
` : '';
// 构建订单详情HTML
const detailHtml = `
<div class="order-detail-modal">
<div class="order-detail-header">
<h2 data-i18n="order_detail_title">订单详情</h2>
<button class="close-detail-btn" aria-label="Close">&times;</button>
</div>
<div class="order-detail-content">
<div class="detail-section">
<div class="detail-status">
<span class="status-badge ${statusInfo.className}">${statusInfo.text}</span>
</div>
<div class="detail-info-grid">
<div class="info-item">
<span class="info-label" data-i18n="order_number">订单号:</span>
<span class="info-value">${order.orderNo || order.order_no || ''}</span>
</div>
<div class="info-item">
<span class="info-label" data-i18n="order_time">下单时间:</span>
<span class="info-value">${order.createdAt || order.created_at || ''}</span>
</div>
</div>
</div>
<div class="detail-section">
<h3 data-i18n="order_items">商品信息</h3>
<div class="detail-items-list">
${itemsHtml}
</div>
</div>
${addressHtml}
<div class="detail-section">
<h3 data-i18n="order_summary">订单金额</h3>
<div class="detail-summary">
<div class="summary-row">
<span data-i18n="goods_amount">商品总额:</span>
<span>¥${totalAmount.toFixed(2)}</span>
</div>
<div class="summary-row summary-total">
<span data-i18n="order_total">实付金额:</span>
<span class="total-amount">¥${payAmount.toFixed(2)}</span>
</div>
</div>
</div>
${buttonsHtml}
</div>
</div>
`;
overlay.innerHTML = detailHtml;
document.body.appendChild(overlay);
// 显示动画
setTimeout(() => {
overlay.classList.add('active');
}, 10);
// 绑定关闭事件
const closeBtn = overlay.querySelector('.close-detail-btn');
closeBtn.addEventListener('click', () => {
closeOrderDetail(overlay);
});
// 绑定操作按钮事件
const actionBtns = overlay.querySelectorAll('.btn-action');
actionBtns.forEach(btn => {
btn.addEventListener('click', () => {
const btnType = parseInt(btn.getAttribute('data-type'));
const orderId = btn.getAttribute('data-order-id');
handleOrderAction(btnType, orderId, overlay);
});
});
// 点击遗罩层关闭
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
closeOrderDetail(overlay);
}
});
}
// 关闭订单详情弹窗
function closeOrderDetail(overlay) {
overlay.classList.remove('active');
setTimeout(() => {
overlay.remove();
}, 300);
}
// 处理订单操作按钮
function handleOrderAction(actionType, orderId, overlay) {
console.log('订单操作:', { actionType, orderId });
// 按钮类型定义(与小程序保持一致)
// 1: 取消订单
// 2: 立即付款
// 3: 提醒发货
// 4: 确认收货
// 5: 申请售后
// 6: 评价
// 7: 申请退款
switch (actionType) {
case 1: // 取消订单
handleCancelOrder(orderId, overlay);
break;
case 2: // 立即付款
handlePayOrder(orderId, overlay);
break;
case 3: // 提醒发货
handleRemindShip(orderId, overlay);
break;
case 4: // 确认收货
handleConfirmReceive(orderId, overlay);
break;
case 5: // 申请售后
handleApplyAfterSale(orderId, overlay);
break;
case 6: // 评价
handleComment(orderId, overlay);
break;
case 7: // 申请退款
handleApplyRefund(orderId, overlay);
break;
default:
Toast.warning('未知操作类型');
}
}
// 取消订单
function handleCancelOrder(orderId, overlay) {
Toast.confirm({
title: '取消订单',
message: '确定要取消该订单吗?取消后无法恢复。',
confirmText: '确认取消',
cancelText: '我再想想'
}).then(confirmed => {
if (confirmed) {
// 调用取消订单API
API.put('/orders/' + orderId + '/cancel', {
order_no: orderId
})
.then(() => {
Toast.success('订单已取消');
// 关闭当前详情弹窗
closeOrderDetail(overlay);
// 刷新订单列表
setTimeout(() => {
// 清空现有订单列表
$('#orderHistorySection .orders-list').remove();
// 重新加载订单
loadOrderHistory();
}, 500);
})
.catch(error => {
Toast.error(error.message || '取消失败');
});
}
});
}
// 立即付款
function handlePayOrder(orderId, overlay) {
// 调用创建支付订单API
API.post('/payments/orders/' + orderId)
.then(data => {
console.log('支付数据:', data);
// Web端支付逻辑显示支付二维码或跳转支付页面
if (data.payInfo) {
// 有支付参数显示支付二维码Web端需要生成二维码扫码支付
Toast.info('请扫码完成支付');
// 这里可以显示支付二维码弹窗
} else {
// 沙盒环境或模拟支付成功
Toast.success('支付成功');
closeOrderDetail(overlay);
setTimeout(() => {
loadOrderHistory();
}, 1000);
}
})
.catch(error => {
Toast.error(error.message || '创建支付订单失败');
});
}
// 提醒发货
function handleRemindShip(orderId, overlay) {
Toast.confirm({
title: '提醒发货',
message: '确定要提醒商家尽快发货吗?提醒后商家会收到通知。',
confirmText: '确定提醒',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
// 调用提醒发货API
API.put('/orders/' + orderId + '/remind-ship')
.then(() => {
Toast.success('提醒发货成功,商家已收到通知');
})
.catch(error => {
let errorMessage = '提醒失败';
if (error.message) {
if (error.message.includes('订单不存在')) {
errorMessage = '订单信息异常,请刷新页面重试';
} else if (error.message.includes('状态')) {
errorMessage = '订单状态不支持提醒发货';
} else {
errorMessage = error.message;
}
}
Toast.error(errorMessage);
});
}
});
}
// 确认收货
function handleConfirmReceive(orderId, overlay) {
Toast.confirm({
title: '确认收货',
message: '确定已收到商品吗?确认后将无法撤销。',
confirmText: '确认收货',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
// 调用确认收货API
API.post('/orders/' + orderId + '/confirm', {
order_no: orderId
})
.then(() => {
Toast.success('确认收货成功');
// 关闭当前详情弹窗
closeOrderDetail(overlay);
// 刷新订单列表
setTimeout(() => {
// 清空现有订单列表
$('#orderHistorySection .orders-list').remove();
// 重新加载订单
loadOrderHistory();
}, 500);
})
.catch(error => {
Toast.error(error.message || '确认收货失败');
});
}
});
}
// 申请售后
function handleApplyAfterSale(orderId, overlay) {
// 跳转到售后申请页面
Toast.info('跳转到售后申请页面...');
// window.location.href = 'after-sale.html?order_id=' + orderId;
}
// 评价
function handleComment(orderId, overlay) {
// 跳转到评价页面
Toast.info('跳转到评价页面...');
// window.location.href = 'comment.html?order_id=' + orderId;
}
// 申请退款
function handleApplyRefund(orderId, overlay) {
Toast.confirm({
title: '申请退款',
message: '确定要申请退款吗?',
confirmText: '确定',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
// 先获取订单详情获取order_id和退款金额
OrderAPI.getDetail(orderId)
.then(orderData => {
// 调用申请退款API
API.post('/refunds', {
order_id: parseInt(orderData.orderId || orderData.order_id),
refund_amount: (orderData.payAmount || orderData.pay_amount || orderData.paymentAmount || orderData.payment_amount) / 100, // 分转元
refund_reason: '用户主动申请退款',
refund_type: 1 // 1=仅退款
})
.then(() => {
Toast.success('退款申请已提交');
// 关闭当前详情弹窗
closeOrderDetail(overlay);
// 刷新订单列表
setTimeout(() => {
// 清空现有订单列表
$('#orderHistorySection .orders-list').remove();
// 重新加载订单
loadOrderHistory();
}, 500);
})
.catch(error => {
Toast.error(error.message || '申请退款失败');
});
})
.catch(error => {
Toast.error(error.message || '获取订单信息失败');
});
}
});
}
// ========== 订单列表操作函数 ==========
// 从列表取消订单
function handleCancelOrderFromList(orderId) {
Toast.confirm({
title: '取消订单',
message: '确定要取消该订单吗?取消后无法恢复。',
confirmText: '确认取消',
cancelText: '我再想想'
}).then(confirmed => {
if (confirmed) {
API.put('/orders/' + orderId + '/cancel', {
order_no: orderId
})
.then(() => {
Toast.success('订单已取消');
refreshOrderList();
})
.catch(error => {
Toast.error(error.message || '取消失败');
});
}
});
}
// 从列表立即付款
function handlePayOrderFromList(orderId) {
API.post('/payments/orders/' + orderId)
.then(data => {
if (data.payInfo) {
Toast.info('请扫码完成支付');
} else {
Toast.success('支付成功');
setTimeout(() => {
refreshOrderList();
}, 1000);
}
})
.catch(error => {
Toast.error(error.message || '创建支付订单失败');
});
}
// 从列表提醒发货
function handleRemindShipFromList(orderId) {
Toast.confirm({
title: '提醒发货',
message: '确定要提醒商家尽快发货吗?提醒后商家会收到通知。',
confirmText: '确定提醒',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
API.put('/orders/' + orderId + '/remind-ship')
.then(() => {
Toast.success('提醒发货成功,商家已收到通知');
})
.catch(error => {
let errorMessage = '提醒失败';
if (error.message) {
if (error.message.includes('订单不存在')) {
errorMessage = '订单信息异常,请刷新页面重试';
} else if (error.message.includes('状态')) {
errorMessage = '订单状态不支持提醒发货';
} else {
errorMessage = error.message;
}
}
Toast.error(errorMessage);
});
}
});
}
// 从列表确认收货
function handleConfirmReceiveFromList(orderId) {
Toast.confirm({
title: '确认收货',
message: '确定已收到商品吗?确认后将无法撤销。',
confirmText: '确认收货',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
API.post('/orders/' + orderId + '/confirm', {
order_no: orderId
})
.then(() => {
Toast.success('确认收货成功');
refreshOrderList();
})
.catch(error => {
Toast.error(error.message || '确认收货失败');
});
}
});
}
// 从列表申请退款
function handleApplyRefundFromList(orderId) {
Toast.confirm({
title: '申请退款',
message: '确定要申请退款吗?',
confirmText: '确定',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
OrderAPI.getDetail(orderId)
.then(orderData => {
API.post('/refunds', {
order_id: parseInt(orderData.orderId || orderData.order_id),
refund_amount: (orderData.payAmount || orderData.pay_amount || orderData.paymentAmount || orderData.payment_amount) / 100,
refund_reason: '用户主动申请退款',
refund_type: 1
})
.then(() => {
Toast.success('退款申请已提交');
refreshOrderList();
})
.catch(error => {
Toast.error(error.message || '申请退款失败');
});
})
.catch(error => {
Toast.error(error.message || '获取订单信息失败');
});
}
});
}
// 刷新订单列表
function refreshOrderList() {
setTimeout(() => {
$('#orderHistorySection .orders-list').remove();
loadOrderHistory();
}, 500);
}
// 显示编辑对话框
function showEditDialog(field) {
console.log('showEditDialog called with field:', field);
const user = JSON.parse(localStorage.getItem('currentUser'));
console.log('Current user:', user);
const fieldMap = {
'nickname': {
title: i18n.t('edit_nickname_title') || '设置用户名',
placeholder: i18n.t('nickname_placeholder') || '请输入用户名',
currentValue: user.nickname || '',
maxLength: 20,
validate: (value) => {
if (!value || value.trim() === '') {
return i18n.t('nickname_required') || '请输入用户名';
}
if (value.length < 2 || value.length > 20) {
return i18n.t('nickname_length_error') || '用户名长度2-20个字符';
}
return null;
}
},
'email': {
title: i18n.t('edit_email_title') || '设置邮箱',
placeholder: i18n.t('email_placeholder') || '请输入邮箱',
currentValue: user.email || '',
inputType: 'email',
validate: (value) => {
if (!value || value.trim() === '') {
return i18n.t('email_required') || '请输入邮箱';
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) {
return i18n.t('invalid_email') || '请输入有效的邮箱地址';
}
return null;
}
},
'phone': {
title: i18n.t('edit_phone_title') || '设置手机号',
placeholder: i18n.t('phone_placeholder') || '请输入手机号',
currentValue: user.phone || '',
inputType: 'tel',
maxLength: 11,
validate: (value) => {
if (!value || value.trim() === '') {
return i18n.t('phone_required') || '请输入手机号';
}
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(value)) {
return i18n.t('invalid_phone') || '请输入有效的手机号';
}
return null;
}
}
};
const config = fieldMap[field];
if (!config) {
console.error('Invalid field:', field);
return;
}
console.log('Config:', config);
// 使用Toast.prompt替代原生prompt
Toast.prompt({
title: config.title,
placeholder: config.placeholder,
defaultValue: config.currentValue,
inputType: config.inputType || 'text',
maxLength: config.maxLength,
confirmText: i18n.t('confirm') || '确定',
cancelText: i18n.t('cancel') || '取消'
}).then(newValue => {
console.log('New value:', newValue);
if (newValue !== null && newValue !== config.currentValue) {
// 验证
const error = config.validate(newValue);
if (error) {
Toast.error(error);
return;
}
// 调用API更新后端数据
const updateData = {};
updateData[field] = newValue;
console.log('Calling API to update:', field, '=', newValue);
UserAPI.updateProfile(updateData)
.then(function(updatedUser) {
console.log('API response:', updatedUser);
// API更新成功同步更新localStorage
user[field] = newValue;
// 如果API返回了其他字段也一并更新
if (updatedUser) {
Object.assign(user, updatedUser);
}
localStorage.setItem('currentUser', JSON.stringify(user));
console.log('User updated:', user);
// 刷新显示
updateAccountDetails(user);
Toast.success(i18n.t('update_success') || '修改成功');
})
.catch(function(error) {
// API调用失败
console.error('更新用户信息失败:', error);
Toast.error(error.message || i18n.t('update_failed') || '更新失败,请稍后重试');
});
}
});
}
// 退出登录
function handleLogout() {
Toast.confirm({
title: i18n.t('logout_confirm_title') || '退出登录',
message: i18n.t('logout_confirm_message') || '确定要退出当前账号吗?',
confirmText: i18n.t('confirm') || '确定',
cancelText: i18n.t('cancel') || '取消'
}).then(confirmed => {
if (confirmed) {
// 清除登录状态和重定向URL
localStorage.removeItem('currentUser');
localStorage.removeItem('redirectUrl');
// 更新用户图标显示
if (typeof window.updateUserIcon === 'function') {
window.updateUserIcon();
}
Toast.success(i18n.t('logout_success') || '已退出登录');
setTimeout(() => {
window.location.href = 'login.html';
}, 500);
}
});
}
// ===================== 支付相关 =====================
// 全局支付状态
const paymentState = {
paymentTimer: null,
countdownTimer: null,
currentOrderId: null,
countdownEndTime: null // 倒计时结束时间戳
};
// 处理订单列表的立即付款
function handlePayOrderFromList(orderId) {
// 获取订单详情以获取金额
OrderAPI.getDetail(orderId)
.then(data => {
const order = data.data || data;
// 尝试多种可能的字段名
const totalAmount = order.total_amount || order.totalAmount || order.total || order.amount || 0;
// 显示支付弹窗
showWechatPayment(orderId, totalAmount);
})
.catch(error => {
console.error('获取订单详情失败:', error);
Toast.error('获取订单信息失败');
});
}
// 显示微信支付弹窗
function showWechatPayment(orderId, totalAmount) {
paymentState.currentOrderId = orderId;
// 显示支付金额(后端返回的是分,需要转换为元)
const amountInYuan = (totalAmount / 100).toFixed(2);
$('#paymentAmount').text(`¥${amountInYuan}`);
// 显示弹窗
$('#paymentModal').addClass('show');
// 绑定关闭事件
$('#closePaymentModal').off('click').on('click', function() {
hidePaymentModal();
});
// 调用支付 API 获取二维码
API.put(`/orders/${orderId}/pay`, {
payment_method: 'wechat'
})
.then(data => {
// 支持多种数据格式
const paymentData = data.data || data;
const qrcodeUrl = paymentData.qrcode_url || paymentData.qrcodeUrl || paymentData.code_url || paymentData.codeUrl;
if (qrcodeUrl) {
// 显示二维码
displayQRCode(qrcodeUrl);
// 开始轮询支付状态
startPaymentPolling(orderId);
// 开始倒计时5分钟
startCountdown(300);
} else {
Toast.error('获取支付二维码失败');
hidePaymentModal();
}
})
.catch(error => {
console.error('创建支付失败:', error);
Toast.error(error.message || '创建支付失败');
hidePaymentModal();
});
}
// 显示二维码
function displayQRCode(url) {
// 清空容器
const container = document.getElementById('qrcodeContainer');
container.innerHTML = '';
// 使用 QRCode.js 生成二维码
new QRCode(container, {
text: url,
width: 256,
height: 256,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
}
// 开始轮询支付状态
function startPaymentPolling(orderId) {
if (paymentState.paymentTimer) {
clearInterval(paymentState.paymentTimer);
}
paymentState.paymentTimer = setInterval(() => {
checkPaymentStatus(orderId);
}, 2000);
}
// 检查支付状态
function checkPaymentStatus(orderId) {
API.get(`/orders/${orderId}/payment/status`)
.then(data => {
const status = data.data?.status || data.status;
if (status === 'paid' || status === 'success') {
handlePaymentSuccess();
} else if (status === 'failed' || status === 'cancelled') {
handlePaymentFailure();
}
})
.catch(error => {
console.error('查询支付状态失败:', error);
});
}
// 支付成功处理
function handlePaymentSuccess() {
clearInterval(paymentState.paymentTimer);
clearInterval(paymentState.countdownTimer);
Toast.success('支付成功!');
hidePaymentModal();
// 刷新订单列表
setTimeout(() => {
loadOrderHistory();
}, 1000);
}
// 支付失败处理
function handlePaymentFailure() {
clearInterval(paymentState.paymentTimer);
clearInterval(paymentState.countdownTimer);
Toast.error('支付失败,请重试');
hidePaymentModal();
}
// 开始倒计时(使用时间戳避免切换标签页时间不准)
function startCountdown(seconds) {
if (paymentState.countdownTimer) {
clearInterval(paymentState.countdownTimer);
}
// 记录倒计时结束的绝对时间戳
paymentState.countdownEndTime = Date.now() + (seconds * 1000);
// 更新显示
updateCountdownDisplay();
// 每秒更新一次
paymentState.countdownTimer = setInterval(() => {
updateCountdownDisplay();
}, 1000);
}
// 更新倒计时显示(基于时间戳计算)
function updateCountdownDisplay() {
if (!paymentState.countdownEndTime) {
return;
}
const now = Date.now();
const remainingMs = paymentState.countdownEndTime - now;
// 倒计时结束
if (remainingMs <= 0) {
clearInterval(paymentState.countdownTimer);
clearInterval(paymentState.paymentTimer);
paymentState.countdownTimer = null;
paymentState.countdownEndTime = null;
$('#countdownTime').text('0:00');
Toast.warning('二维码已过期,请重新生成');
hidePaymentModal();
return;
}
// 计算剩余秒数
const remainingSeconds = Math.ceil(remainingMs / 1000);
const minutes = Math.floor(remainingSeconds / 60);
const secs = remainingSeconds % 60;
$('#countdownTime').text(`${minutes}:${String(secs).padStart(2, '0')}`);
}
// 隐藏支付弹窗
function hidePaymentModal() {
if (paymentState.paymentTimer) {
clearInterval(paymentState.paymentTimer);
paymentState.paymentTimer = null;
}
if (paymentState.countdownTimer) {
clearInterval(paymentState.countdownTimer);
paymentState.countdownTimer = null;
}
// 清除倒计时时间戳
paymentState.countdownEndTime = null;
$('#paymentModal').removeClass('show');
$('#qrcodeContainer').html(`
<div class="qrcode-loading">
<div class="spinner"></div>
<p>正在生成二维码...</p>
</div>
`);
paymentState.currentOrderId = null;
}