// Checkout Page JavaScript - 完全重写版本 // 全局状态 const checkoutState = { cartItems: [], // 购物车商品 addresses: [], // 用户地址列表 selectedAddress: null, // 选中的地址 coupons: [], // 可用优惠券 selectedCoupon: null, // 选中的优惠券 orderNotes: '', // 订单备注 checkoutType: 'cart', // 结算类型:'cart'(购物车) 或 'buynow'(立即购买) paymentMethod: 'wechat', // 支付方式:'wechat'(微信) 或 'alipay'(支付宝) paymentTimer: null, // 支付轮询定时器 countdownTimer: null, // 倒计时定时器 }; $(document).ready(function() { initCheckoutPage(); }); function initCheckoutPage() { const pageStartTime = Date.now(); console.log('\n=== 结算页面加载开始 ==='); // 检查结算类型 const urlParams = new URLSearchParams(window.location.search); const type = urlParams.get('type'); const productId = urlParams.get('product_id'); const skuId = urlParams.get('sku_id'); const quantity = urlParams.get('quantity'); // 绑定事件(立即绑定,不等待数据加载) bindCheckoutEvents(); // 并行加载所有数据,提升页面加载速度 console.log('🚀 开始并行加载所有数据...'); console.log('⏱️ 请求开始时间:', new Date().toLocaleTimeString()); let dataPromise; if (type === 'buynow' && productId) { // 立即购买模式 checkoutState.checkoutType = 'buynow'; console.log(' [1/3] 发起商品详情 API 请求...'); dataPromise = loadBuyNowProduct(productId, skuId, quantity); } else { // 购物车结算模式 checkoutState.checkoutType = 'cart'; console.log(' [1/3] 发起购物车 API 请求...'); dataPromise = loadCartItems(); } // 并行加载地址和商品数据 console.log(' [2/3] 发起地址 API 请求...'); const addressPromise = loadAddresses(); console.log(' [3/3] 所有并行请求已发起!'); console.log('⏱️ 请求发起时间:', new Date().toLocaleTimeString()); // 等待主要数据加载完成(地址和商品) Promise.all([addressPromise, dataPromise]) .then(() => { const pageLoadTime = Date.now() - pageStartTime; console.log(`\n✅ 页面主要内容加载完成`); console.log(` 总耗时: ${pageLoadTime}ms`); console.log(` 完成时间: ${new Date().toLocaleTimeString()}`); console.log(` 说明: 由于地址和商品并行加载,总耗时 ≈ max(地址耗时, 商品耗时)\n`); // 异步加载优惠券(不阻塞页面显示) // 使用 setTimeout 让页面先渲染,然后再加载优惠券 setTimeout(() => { loadCoupons(); }, 0); }) .catch(error => { const pageLoadTime = Date.now() - pageStartTime; console.error(`❌ 页面加载失败 (耗时: ${pageLoadTime}ms):`, error); }); } // 加载立即购买的商品 function loadBuyNowProduct(productId, skuId, quantity) { const startTime = Date.now(); console.log(' → 商品详情 API: 请求中...'); // 显示加载状态 $('#goodsList').html(`

加载中...

`); // 返回 Promise return API.get(`/products/${productId}`) .then(data => { const loadTime = Date.now() - startTime; console.log(` ✓ 商品详情 API: 完成 (耗时: ${loadTime}ms)`); console.log(' 商品:', data.data?.name || data.name || '未知'); // 支持多种数据格式 const product = data.data || data; // 构建购买商品数据 const item = { product_id: parseInt(productId), product: product, quantity: parseInt(quantity) || 1, selected: true }; // 如果指定了SKU if (skuId) { const sku = product.skus?.find(s => s.id == skuId || s.sku_id == skuId); if (sku) { item.sku_id = parseInt(skuId); item.sku = sku; } } checkoutState.cartItems = [item]; renderGoodsList([item]); updatePriceSummary(); }) .catch(error => { const loadTime = Date.now() - startTime; console.error(` ✗ 商品详情 API: 失败 (耗时: ${loadTime}ms)`, error.message); Toast.error('加载商品失败'); showEmptyCart(); }); } // 加载购物车商品 function loadCartItems() { const startTime = Date.now(); console.log(' → 购物车 API: 请求中...'); // 显示加载状态 $('#goodsList').html(`

加载中...

`); // 返回 Promise return API.get('/cart') .then(data => { const loadTime = Date.now() - startTime; console.log(` ✓ 购物车 API: 完成 (耗时: ${loadTime}ms)`); console.log(` 商品数: ${data.items?.length || 0}`); console.log(` 总金额: ${data.total || '0'}`); // 支持多种数据格式 let items = []; if (Array.isArray(data)) { // 直接返回数组 items = data; } else if (data.data) { // 数据在 data.data 中 if (Array.isArray(data.data)) { items = data.data; } else if (data.data.items) { items = data.data.items; } else if (data.data.list) { items = data.data.list; } } else if (data.items) { // 数据在 data.items 中 items = data.items; } else if (data.list) { // 数据在 data.list 中 items = data.list; } console.log('解析到的商品列表:', items); checkoutState.cartItems = items; if (items.length === 0) { showEmptyCart(); return; } renderGoodsList(items); updatePriceSummary(); }) .catch(error => { const loadTime = Date.now() - startTime; console.error(` ✗ 购物车 API: 失败 (耗时: ${loadTime}ms)`, error.message); Toast.error('加载商品失败'); showEmptyCart(); }); } // 显示空购物车 function showEmptyCart() { $('#goodsList').html(`

购物车是空的

去逛逛
`); $('#payNowBtn').prop('disabled', true); } // 渲染商品列表 function renderGoodsList(items) { const goodsHtml = items.map(item => { // 字段映射 - 支持多种格式(嵌套结构优先) const productName = item.product_name || item.productName || item.name || item.title || item.goods_name || (item.product && (item.product.name || item.product.title)) || '未知商品'; // SKU 规格名称提取(支持多种格式) let skuName = item.sku_name || item.skuName || item.specs || item.spec || ''; // 处理 spec_values 对象格式 if (!skuName && item.sku && item.sku.spec_values) { const specValues = item.sku.spec_values; if (typeof specValues === 'object' && specValues !== null) { // 将对象转换为 "key:value" 格式,如 "颜色:红色 尺寸:XL" skuName = Object.entries(specValues) .map(([key, value]) => `${key}:${value}`) .join(' '); } else if (typeof specValues === 'string') { skuName = specValues; } } // 价格提取(优先从嵌套的 product 或 sku 对象中获取) const price = parseInt( item.price || item.sale_price || item.salePrice || (item.sku && item.sku.price) || (item.product && item.product.price) || 0 ); const quantity = item.quantity || item.num || item.count || 1; // 图片提取(支持嵌套的 product.main_image) const image = item.image || item.thumb || item.main_image || item.mainImage || item.pic || (item.product && item.product.main_image) || 'https://via.placeholder.com/80'; console.log('商品数据:', { 原始数据: item, 解析结果: { productName, skuName, price, quantity, image } }); return `
${productName}
${productName}
${skuName ? `
${skuName}
` : ''}
¥${PriceUtils.fenToYuan(price).toFixed(2)}
x${quantity}
`; }).join(''); $('#goodsList').html(goodsHtml); } // 加载用户地址 function loadAddresses() { const startTime = Date.now(); console.log(' → 地址 API: 请求中...'); // 返回 Promise return API.get('/addresses') .then(data => { const loadTime = Date.now() - startTime; console.log(` ✓ 地址 API: 完成 (耗时: ${loadTime}ms)`); // 支持多种数据格式 let addresses = []; if (Array.isArray(data)) { // 直接返回数组 addresses = data; } else if (data.data) { // 数据在 data.data 中 addresses = Array.isArray(data.data) ? data.data : (data.data.list || []); } else if (data.list) { // 数据在 data.list 中 addresses = data.list; } console.log(' 地址数: ' + addresses.length); checkoutState.addresses = addresses; if (addresses.length > 0) { // 查找默认地址 const defaultAddress = addresses.find(addr => addr.is_default || addr.isDefault); checkoutState.selectedAddress = defaultAddress || addresses[0]; console.log(' 选中地址:', checkoutState.selectedAddress.name || '无名称'); renderSelectedAddress(checkoutState.selectedAddress); } else { console.log(' 没有可用地址'); } }) .catch(error => { const loadTime = Date.now() - startTime; console.error(` ✗ 地址 API: 失败 (耗时: ${loadTime}ms)`, error.message); // 非登录用户或没有地址时不显示错误 }); } // 渲染选中的地址 function renderSelectedAddress(address) { if (!address) { $('#noAddress').show(); $('#addressInfo').hide(); return; } $('#noAddress').hide(); $('#addressInfo').show(); // 字段映射 - 支持多种格式 const name = address.receiver_name || address.name || ''; const phone = address.receiver_phone || address.phone || ''; const province = address.province_name || address.provinceName || address.province || ''; const city = address.city_name || address.cityName || address.city || ''; const district = address.district_name || address.districtName || address.district || ''; const detail = address.detail_address || address.detailAddress || address.detail || ''; const isDefault = address.is_default || address.isDefault; const tag = address.address_tag || address.addressTag || (isDefault ? '默认' : ''); $('#addressName').text(name); $('#addressPhone').text(phone); $('#addressDetail').text(`${province} ${city} ${district} ${detail}`); if (tag) { $('#addressTag').text(tag).show(); } else { $('#addressTag').hide(); } } // 加载优惠券 function loadCoupons() { const startTime = Date.now(); console.log('\n🎫 加载优惠券(异步,不阻塞页面)...'); // 计算总价(支持嵌套结构) const totalAmount = checkoutState.cartItems.reduce((sum, item) => { const price = parseInt( item.price || item.sale_price || item.salePrice || (item.sku && item.sku.price) || (item.product && item.product.price) || 0 ); const quantity = item.quantity || 1; return sum + (price * quantity); }, 0); console.log(' 订单总额(分):', totalAmount); // 如果订单金额为0,不加载优惠券 if (totalAmount <= 0) { console.log(' 订单金额为0,跳过加载优惠券\n'); checkoutState.coupons = []; updateCouponDisplay(); return; } // 使用订单可用优惠券 API,添加超时控制 const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('请求超时')), 5000); // 5秒超时 }); const apiPromise = API.get('/coupons/order/available', { order_amount: totalAmount }); Promise.race([apiPromise, timeoutPromise]) .then(data => { const loadTime = Date.now() - startTime; console.log(` ✓ 优惠券 API: 完成 (耗时: ${loadTime}ms)\n`); // 检查数据是否为空 if (!data) { console.warn(' ⚠️ 优惠券 API 返回空数据\n'); checkoutState.coupons = []; updateCouponDisplay(); return; } // 支持多种数据格式 let coupons = []; if (Array.isArray(data)) { coupons = data; } else if (data.data) { coupons = Array.isArray(data.data) ? data.data : (data.data.list || data.data.coupons || []); } else if (data.list) { coupons = data.list; } else if (data.coupons) { coupons = data.coupons; } console.log(' 优惠券数量:', coupons.length, '\n'); checkoutState.coupons = coupons; // 更新优惠券显示 updateCouponDisplay(); }) .catch(error => { const loadTime = Date.now() - startTime; console.error(` ✗ 优惠券 API: 失败 (耗时: ${loadTime}ms)`, error.message); console.log(' 优惠券加载失败不影响结算,继续使用\n'); // 优惠券加载失败不影响结算流程,只是没有优惠券可用 checkoutState.coupons = []; updateCouponDisplay(); }); } // 更新优惠券显示 function updateCouponDisplay() { const availableCount = checkoutState.coupons.length; if (checkoutState.selectedCoupon) { const discount = parseInt(checkoutState.selectedCoupon.discount_amount || 0); $('#couponText').text(`-¥${PriceUtils.fenToYuan(discount).toFixed(2)}`); } else if (availableCount > 0) { $('#couponText').text(`${availableCount}张可用`); } else { $('#couponText').text('暂无可用优惠券'); } } // 更新价格汇总 function updatePriceSummary() { // 计算商品总额(支持嵌套结构) const subtotal = checkoutState.cartItems.reduce((sum, item) => { const price = parseInt( item.price || item.sale_price || item.salePrice || (item.sku && item.sku.price) || (item.product && item.product.price) || 0 ); const quantity = item.quantity || 1; return sum + (price * quantity); }, 0); // 运费(满一定金额免运费) const shippingFee = subtotal >= 5900 ? 0 : 0; // 满 59 元免运费 // 活动优惠(从商品信息中获取) const promotionAmount = 0; // TODO: 从 API 获取 // 优惠券优惠 const couponAmount = checkoutState.selectedCoupon ? parseInt(checkoutState.selectedCoupon.discount_amount || 0) : 0; // 应付总额 const totalAmount = subtotal + shippingFee - promotionAmount - couponAmount; // 更新显示 $('#subtotalAmount').text(`¥${PriceUtils.fenToYuan(subtotal).toFixed(2)}`); if (shippingFee > 0) { $('#shippingAmount').text(`¥${PriceUtils.fenToYuan(shippingFee).toFixed(2)}`); } else { $('#shippingAmount').text('免运费'); } if (promotionAmount > 0) { $('#promotionRow').show(); $('#promotionAmount').text(`-¥${PriceUtils.fenToYuan(promotionAmount).toFixed(2)}`); } else { $('#promotionRow').hide(); } if (couponAmount > 0) { $('#couponRow').show(); $('#couponAmount').text(`-¥${PriceUtils.fenToYuan(couponAmount).toFixed(2)}`); } else { $('#couponRow').hide(); } $('#totalAmount').text(`¥${PriceUtils.fenToYuan(totalAmount).toFixed(2)}`); } // 绑定事件 function bindCheckoutEvents() { // 选择地址按钮 $('#selectAddressBtn, #changeAddressBtn').on('click', function() { showAddressModal(); }); // 编辑选中的地址 $('#editSelectedAddressBtn').on('click', function() { if (checkoutState.selectedAddress) { editAddress(checkoutState.selectedAddress); } }); // 关闭地址弹窗 $('#closeAddressModal').on('click', function() { hideAddressModal(); }); // 选择优惠券 $('#couponSelector').on('click', function() { if (checkoutState.coupons.length === 0) { Toast.info('暂无可用优惠券'); return; } showCouponModal(); }); // 关闭优惠券弹窗 $('#closeCouponModal').on('click', function() { hideCouponModal(); }); // 确认优惠券 $('#confirmCouponBtn').on('click', function() { hideCouponModal(); updatePriceSummary(); }); // 新增地址按钮 $('#addAddressBtn').on('click', function() { hideAddressModal(); showAddAddressModal(); }); // 关闭新增地址弹窗 $('#closeAddAddressModal, #cancelAddAddressBtn').on('click', function() { hideAddAddressModal(); }); // 保存地址 $('#saveAddressBtn').on('click', function() { saveNewAddress(); }); // 提交订单 $('#payNowBtn').on('click', function(e) { e.preventDefault(); submitOrder(); }); // 选择支付方式 $('.payment-method:not(.disabled)').on('click', function() { $('.payment-method').removeClass('active'); $(this).addClass('active'); checkoutState.paymentMethod = $(this).data('payment'); }); // 关闭支付弹窗 $('#closePaymentModal').on('click', function() { hidePaymentModal(); }); // 点击弹窗背景关闭 $('.modal').on('click', function(e) { if ($(e.target).hasClass('modal')) { $(this).removeClass('show'); } }); } // 显示地址选择弹窗 function showAddressModal() { renderAddressList(); $('#addressModal').addClass('show'); } function hideAddressModal() { $('#addressModal').removeClass('show'); } // 渲染地址列表 function renderAddressList() { if (checkoutState.addresses.length === 0) { $('#addressList').html(`

暂无收货地址

`); return; } const addressHtml = checkoutState.addresses.map(address => { // 字段映射 - 支持多种格式 const name = address.receiver_name || address.name || ''; const phone = address.receiver_phone || address.phone || ''; const province = address.province_name || address.provinceName || address.province || ''; const city = address.city_name || address.cityName || address.city || ''; const district = address.district_name || address.districtName || address.district || ''; const detail = address.detail_address || address.detailAddress || address.detail || ''; const isDefault = address.is_default || address.isDefault; const addressId = address.id || address.address_id || address.addressId; const isSelected = checkoutState.selectedAddress && (checkoutState.selectedAddress.id === addressId || checkoutState.selectedAddress.address_id === addressId || checkoutState.selectedAddress.addressId === addressId); return `
${name} ${phone}
${isDefault ? '默认' : ''}
${province} ${city} ${district} ${detail}
${isSelected ? '
' : ''}
`; }).join(''); $('#addressList').html(addressHtml); // 绑定地址选择事件 $('.address-item').on('click', function() { const addressId = $(this).data('address-id'); const address = checkoutState.addresses.find(addr => (addr.id == addressId || addr.address_id == addressId || addr.addressId == addressId) ); if (address) { checkoutState.selectedAddress = address; renderSelectedAddress(address); hideAddressModal(); // 重新加载优惠券(地址可能影响可用优惠券) loadCoupons(); } }); // 绑定编辑按钮事件 $('.btn-edit-address').on('click', function(e) { e.stopPropagation(); const addressId = $(this).data('address-id'); const address = checkoutState.addresses.find(addr => (addr.id == addressId || addr.address_id == addressId || addr.addressId == addressId) ); if (address) { editAddress(address); } }); // 绑定删除按钮事件 $('.btn-delete-address').on('click', function(e) { e.stopPropagation(); const addressId = $(this).data('address-id'); deleteAddress(addressId); }); } // 显示优惠券选择弹窗 function showCouponModal() { renderCouponList(); $('#couponModal').addClass('show'); } function hideCouponModal() { $('#couponModal').removeClass('show'); } // 渲染优惠券列表 function renderCouponList() { if (checkoutState.coupons.length === 0) { $('#couponList').html(`

暂无可用优惠券

`); return; } const couponHtml = checkoutState.coupons.map(coupon => { const name = coupon.coupon_name || coupon.name || '优惠券'; const discount = parseInt(coupon.discount_amount || 0); const minAmount = parseInt(coupon.min_amount || 0); const isSelected = checkoutState.selectedCoupon && checkoutState.selectedCoupon.coupon_id === coupon.coupon_id; return `
¥${PriceUtils.fenToYuan(discount).toFixed(0)}
${minAmount > 0 ? `满¥${PriceUtils.fenToYuan(minAmount).toFixed(0)}可用` : '无门槛'}
${name}
${formatCouponDate(coupon.start_time, coupon.end_time)}
${isSelected ? '
' : ''}
`; }).join(''); // 添加“不使用优惠券”选项 const noCouponHtml = `
不使用
不使用优惠券
${!checkoutState.selectedCoupon ? '
' : ''}
`; $('#couponList').html(noCouponHtml + couponHtml); // 绑定优惠券选择事件 $('.coupon-item').on('click', function() { const couponId = $(this).data('coupon-id'); if (couponId) { const coupon = checkoutState.coupons.find(c => c.coupon_id === couponId); checkoutState.selectedCoupon = coupon || null; } else { checkoutState.selectedCoupon = null; } // 重新渲染列表显示选中状态 renderCouponList(); // 更新优惠券显示 updateCouponDisplay(); }); } // 格式化优惠券日期 function formatCouponDate(startTime, endTime) { if (!endTime) return ''; const end = new Date(endTime); return `有效期至 ${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, '0')}-${String(end.getDate()).padStart(2, '0')}`; } // 显示新增地址弹窗 function showAddAddressModal() { // 清空表单 $('#addAddressForm')[0].reset(); // 初始化省份选择器 initProvinceSelector(); // 禁用城市和区县选择器 $('#newAddressCity').prop('disabled', true).html(''); $('#newAddressDistrict').prop('disabled', true).html(''); // 绑定级联事件 bindRegionCascade(); // 绑定字数统计 bindCharCount(); $('#addAddressModal').addClass('show'); } function hideAddAddressModal() { $('#addAddressModal').removeClass('show'); } // 初始化省份选择器 function initProvinceSelector() { const provinceSelect = $('#newAddressProvince'); provinceSelect.html(''); ChinaRegions.provinces.forEach(province => { provinceSelect.append(``); }); } // 绑定级联事件 function bindRegionCascade() { // 省份变化 $('#newAddressProvince').off('change').on('change', function() { const provinceCode = $(this).val(); const citySelect = $('#newAddressCity'); const districtSelect = $('#newAddressDistrict'); if (provinceCode) { const cities = ChinaRegions.getCities(provinceCode); citySelect.html(''); cities.forEach(city => { citySelect.append(``); }); citySelect.prop('disabled', false); districtSelect.html('').prop('disabled', true); } else { citySelect.html('').prop('disabled', true); districtSelect.html('').prop('disabled', true); } }); // 城市变化 $('#newAddressCity').off('change').on('change', function() { const cityCode = $(this).val(); const districtSelect = $('#newAddressDistrict'); if (cityCode) { const districts = ChinaRegions.getDistricts(cityCode); districtSelect.html(''); if (districts.length > 0) { districts.forEach(district => { districtSelect.append(``); }); districtSelect.prop('disabled', false); } else { // 没有区县数据时,也启用选择器,但显示提示 districtSelect.html(''); districtSelect.prop('disabled', false); } } else { districtSelect.html('').prop('disabled', true); } }); } // 绑定字数统计 function bindCharCount() { $('#newAddressDetail').off('input').on('input', function() { const length = $(this).val().length; $('#detailCharCount').text(length); if (length > 100) { $(this).val($(this).val().substring(0, 100)); $('#detailCharCount').text(100); } }); } // 保存新地址 function saveNewAddress() { const name = $('#newAddressName').val().trim(); const phone = $('#newAddressPhone').val().trim(); const provinceSelect = $('#newAddressProvince'); const citySelect = $('#newAddressCity'); const districtSelect = $('#newAddressDistrict'); const provinceCode = provinceSelect.val(); const provinceName = provinceSelect.find('option:selected').data('name') || provinceSelect.find('option:selected').text(); const cityCode = citySelect.val(); const cityName = citySelect.find('option:selected').data('name') || citySelect.find('option:selected').text(); const districtCode = districtSelect.val(); const districtName = districtSelect.find('option:selected').data('name') || districtSelect.find('option:selected').text(); const detail = $('#newAddressDetail').val().trim(); const isDefault = $('#newAddressIsDefault').is(':checked'); // 验证 if (!name) { Toast.error('请输入收货人姓名'); return; } if (!phone) { Toast.error('请输入联系电话'); return; } // 验证手机号格式 const phoneRegex = /^1[3-9]\d{9}$/; if (!phoneRegex.test(phone)) { Toast.error('请输入11位有效的手机号'); return; } if (!provinceCode || !cityCode || !districtCode) { Toast.error('请选择完整的所在地区'); return; } if (!detail) { Toast.error('请输入详细地址'); return; } if (detail.length < 5) { Toast.error('详细地址至少需要5个字符'); return; } // 调用 API 保存地址 API.post('/users/addresses', { name: name, phone: phone, province: provinceName, city: cityName, district: districtName, detail: detail, is_default: isDefault ? 1 : 0 }) .then(data => { Toast.success('地址保存成功'); hideAddAddressModal(); // 重新加载地址列表 loadAddresses(); }) .catch(error => { console.error('保存地址失败:', error); Toast.error(error.message || '保存失败'); }); } // 提交订单 function submitOrder() { // 验证 if (!checkoutState.selectedAddress) { Toast.error('请选择收货地址'); return; } if (checkoutState.cartItems.length === 0) { Toast.error('购物车是空的'); return; } // 获取订单备注 checkoutState.orderNotes = $('#orderNotes').val().trim(); // 显示加载状态 const payBtn = $('#payNowBtn'); const originalText = payBtn.html(); payBtn.prop('disabled', true).html('提交中...'); // 获取地址ID - 支持多种字段名,转换为数字类型 const addressId = parseInt( checkoutState.selectedAddress.id || checkoutState.selectedAddress.address_id || checkoutState.selectedAddress.addressId ); // 构造订单数据 const orderData = { address_id: addressId, // 确保是数字类型 coupon_id: checkoutState.selectedCoupon ? parseInt(checkoutState.selectedCoupon.coupon_id) : null, remark: checkoutState.orderNotes, items: checkoutState.cartItems.map(item => ({ product_id: parseInt(item.product_id), sku_id: item.sku_id ? parseInt(item.sku_id) : null, quantity: parseInt(item.quantity) })) }; console.log('订单数据:', orderData); console.log('结算类型:', checkoutState.checkoutType); // 调用创建订单 API API.post('/orders', orderData) .then(data => { console.log('订单创建成功:', data); const orderId = data.data?.order_id || data.order_id || data.data?.orderId || data.orderId; Toast.success('订单创建成功!'); // 恢复按钮状态 payBtn.prop('disabled', false).html(originalText); // 清空购物车(后端已清空) if (window.cart && window.cart.updateCartCount) { window.cart.updateCartCount(); } // 根据支付方式处理 if (checkoutState.paymentMethod === 'wechat' && orderId) { // 微信支付,展示二维码 showWechatPayment(orderId); } else { // 其他支付方式或无订单ID,跳转到订单详情 setTimeout(() => { if (orderId) { window.location.href = `order-detail.html?id=${orderId}`; } else { window.location.href = 'user-center.html#orders'; } }, 1000); } }) .catch(error => { console.error('订单创建失败:', error); Toast.error(error.message || '订单创建失败'); // 恢复按钮状态 payBtn.prop('disabled', false).html(originalText); }); } // 编辑地址 function editAddress(address) { // 隐藏地址选择弹窗 hideAddressModal(); // 填充表单数据 const name = address.receiver_name || address.name || ''; const phone = address.receiver_phone || address.phone || ''; const province = address.province_name || address.provinceName || address.province || ''; const city = address.city_name || address.cityName || address.city || ''; const district = address.district_name || address.districtName || address.district || ''; const detail = address.detail_address || address.detailAddress || address.detail || ''; const isDefault = address.is_default || address.isDefault; const addressId = address.id || address.address_id || address.addressId; $('#newAddressName').val(name); $('#newAddressPhone').val(phone); $('#newAddressDetail').val(detail); $('#newAddressIsDefault').prop('checked', isDefault); // 初始化省份选择器 initProvinceSelector(); // 绑定级联事件 bindRegionCascade(); // 绑定字数统计 bindCharCount(); // 更新字数显示 $('#detailCharCount').text(detail.length); // TODO: 需要根据省市区名称反查 code,然后设置选中 // 这里简化处理,直接根据名称匹配 setTimeout(() => { // 设置省份 const provinceOption = $('#newAddressProvince option').filter(function() { return $(this).data('name') === province || $(this).text() === province; }); if (provinceOption.length > 0) { $('#newAddressProvince').val(provinceOption.val()).trigger('change'); // 等待城市加载后设置 setTimeout(() => { const cityOption = $('#newAddressCity option').filter(function() { return $(this).data('name') === city || $(this).text() === city; }); if (cityOption.length > 0) { $('#newAddressCity').val(cityOption.val()).trigger('change'); // 等待区县加载后设置 setTimeout(() => { const districtOption = $('#newAddressDistrict option').filter(function() { return $(this).data('name') === district || $(this).text() === district; }); if (districtOption.length > 0) { $('#newAddressDistrict').val(districtOption.val()); } }, 100); } }, 100); } }, 100); // 修改按钮文字和事件 $('#saveAddressBtn').text('保存修改').off('click').on('click', function() { updateAddress(addressId); }); // 显示弹窗 $('#addAddressModal').addClass('show'); } // 更新地址 function updateAddress(addressId) { const name = $('#newAddressName').val().trim(); const phone = $('#newAddressPhone').val().trim(); const provinceSelect = $('#newAddressProvince'); const citySelect = $('#newAddressCity'); const districtSelect = $('#newAddressDistrict'); const provinceCode = provinceSelect.val(); const provinceName = provinceSelect.find('option:selected').data('name') || provinceSelect.find('option:selected').text(); const cityCode = citySelect.val(); const cityName = citySelect.find('option:selected').data('name') || citySelect.find('option:selected').text(); const districtCode = districtSelect.val(); const districtName = districtSelect.find('option:selected').data('name') || districtSelect.find('option:selected').text(); const detail = $('#newAddressDetail').val().trim(); const isDefault = $('#newAddressIsDefault').is(':checked'); // 验证 if (!name) { Toast.error('请输入收货人姓名'); return; } if (!phone) { Toast.error('请输入联系电话'); return; } // 验证手机号格式 const phoneRegex = /^1[3-9]\d{9}$/; if (!phoneRegex.test(phone)) { Toast.error('请输入11位有效的手机号'); return; } if (!provinceCode || !cityCode || !districtCode) { Toast.error('请选择完整的所在地区'); return; } if (!detail) { Toast.error('请输入详细地址'); return; } if (detail.length < 5) { Toast.error('详细地址至少需要5个字符'); return; } // 调用 API 更新地址 API.put(`/users/addresses/${addressId}`, { name: name, phone: phone, province: provinceName, city: cityName, district: districtName, detail: detail, is_default: isDefault ? 1 : 0 }) .then(data => { Toast.success('地址更新成功'); hideAddAddressModal(); // 恢复按钮为新增模式 $('#saveAddressBtn').text('保存').off('click').on('click', function() { saveNewAddress(); }); // 重新加载地址列表 loadAddresses(); }) .catch(error => { console.error('更新地址失败:', error); Toast.error(error.message || '更新失败'); }); } // 删除地址 function deleteAddress(addressId) { Toast.confirm({ title: '确认删除', message: '确定要删除这个地址吗?', confirmText: '删除', cancelText: '取消', confirmColor: '#ff6b6b' }).then(confirmed => { if (confirmed) { API.delete(`/users/addresses/${addressId}`) .then(() => { Toast.success('地址删除成功'); // 如果删除的是当前选中的地址,清空选中状态 if (checkoutState.selectedAddress && (checkoutState.selectedAddress.id == addressId || checkoutState.selectedAddress.address_id == addressId || checkoutState.selectedAddress.addressId == addressId)) { checkoutState.selectedAddress = null; $('#noAddress').show(); $('#addressInfo').hide(); } // 重新加载地址列表 loadAddresses(); }) .catch(error => { console.error('删除地址失败:', error); Toast.error(error.message || '删除失败'); }); } }); } // ===================== 支付相关 ===================== // 显示微信支付弹窗 function showWechatPayment(orderId) { console.log('开始微信支付流程,订单ID:', orderId); // 计算总金额 const totalAmount = calculateTotalAmount(); // 显示支付金额 $('#paymentAmount').text(`¥${PriceUtils.fenToYuan(totalAmount).toFixed(2)}`); // 显示弹窗 $('#paymentModal').addClass('show'); // 调用支付 API 获取二维码 API.post(`/orders/${orderId}/pay`, { payment_method: 'wechat' }) .then(data => { console.log('支付响应:', 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) { // 替换 loading 为二维码图片 $('#qrcodeContainer').html(` 微信支付二维码 `); } // 开始轮询支付状态 function startPaymentPolling(orderId) { // 清除之前的定时器 if (checkoutState.paymentTimer) { clearInterval(checkoutState.paymentTimer); } // 每 2 秒查询一次 checkoutState.paymentTimer = setInterval(() => { checkPaymentStatus(orderId); }, 2000); } // 检查支付状态 function checkPaymentStatus(orderId) { API.get(`/orders/${orderId}/payment/status`) .then(data => { const status = data.data?.status || data.status; console.log('支付状态:', status); if (status === 'paid' || status === 'success') { // 支付成功 handlePaymentSuccess(orderId); } else if (status === 'failed' || status === 'cancelled') { // 支付失败 handlePaymentFailure(); } // 其他状态继续轮询 }) .catch(error => { console.error('查询支付状态失败:', error); // 继续轮询,不中断 }); } // 支付成功处理 function handlePaymentSuccess(orderId) { // 停止轮询 clearInterval(checkoutState.paymentTimer); clearInterval(checkoutState.countdownTimer); // 显示成功消息 Toast.success('支付成功!'); // 关闭弹窗 hidePaymentModal(); // 跳转到订单详情 setTimeout(() => { window.location.href = `order-detail.html?id=${orderId}`; }, 1000); } // 支付失败处理 function handlePaymentFailure() { // 停止轮询 clearInterval(checkoutState.paymentTimer); clearInterval(checkoutState.countdownTimer); // 显示失败消息 Toast.error('支付失败,请重试'); // 关闭弹窗 hidePaymentModal(); } // 开始倒计时 function startCountdown(seconds) { // 清除之前的定时器 if (checkoutState.countdownTimer) { clearInterval(checkoutState.countdownTimer); } let remainingSeconds = seconds; // 更新显示 updateCountdownDisplay(remainingSeconds); // 每秒更新 checkoutState.countdownTimer = setInterval(() => { remainingSeconds--; if (remainingSeconds <= 0) { // 倒计时结束 clearInterval(checkoutState.countdownTimer); clearInterval(checkoutState.paymentTimer); Toast.warning('二维码已过期,请重新生成'); hidePaymentModal(); } else { updateCountdownDisplay(remainingSeconds); } }, 1000); } // 更新倒计时显示 function updateCountdownDisplay(seconds) { const minutes = Math.floor(seconds / 60); const secs = seconds % 60; $('#countdownTime').text(`${minutes}:${String(secs).padStart(2, '0')}`); } // 隐藏支付弹窗 function hidePaymentModal() { // 清除定时器 if (checkoutState.paymentTimer) { clearInterval(checkoutState.paymentTimer); checkoutState.paymentTimer = null; } if (checkoutState.countdownTimer) { clearInterval(checkoutState.countdownTimer); checkoutState.countdownTimer = null; } // 关闭弹窗 $('#paymentModal').removeClass('show'); // 重置二维码区域 $('#qrcodeContainer').html(`

正在生成二维码...

`); } // 计算总金额 function calculateTotalAmount() { // 计算商品总额 const subtotal = checkoutState.cartItems.reduce((sum, item) => { const price = parseInt( item.price || item.sale_price || item.salePrice || (item.sku && item.sku.price) || (item.product && item.product.price) || 0 ); const quantity = item.quantity || 1; return sum + (price * quantity); }, 0); // 运费 const shippingFee = subtotal >= 5900 ? 0 : 0; // 优惠券优惠 const couponAmount = checkoutState.selectedCoupon ? parseInt(checkoutState.selectedCoupon.discount_amount || 0) : 0; // 总金额 return subtotal + shippingFee - couponAmount; }