diff --git a/pages/freight-calculator/index.js b/pages/freight-calculator/index.js index 4c867b4..bc8d66f 100644 --- a/pages/freight-calculator/index.js +++ b/pages/freight-calculator/index.js @@ -73,7 +73,7 @@ Page({ destination: [0, 0, 0] }, // 运输模式 - transportModes: ['货拉拉', '运满满', '零担拼车'], + transportModes: ['整车运输', '零担拼车'], transportModeIndex: 0, // 包装类型 @@ -116,6 +116,7 @@ Page({ complianceStatus: '', isCompliant: true, detailText: '', + showDetail: false, // 车型和车长对应关系 vehicleLengthMap: { @@ -156,9 +157,6 @@ Page({ // 页面加载时的初始化逻辑 console.log('物流运费估算页面加载,options:', options); - // 加载历史记录 - this.loadHistoryRecords(); - // 初始化地址选择器数据 this.initRegionData(); @@ -206,18 +204,26 @@ Page({ }); // 设置出发地为商品所在地 - if (goodsData.region) { - const regionInfo = this.parseRegion(goodsData.region); + const regionToUse = goodsData.fullRegion || goodsData.region; + if (regionToUse) { + console.log('商品所在地原始地址:', regionToUse); + const regionInfo = this.parseRegion(regionToUse); + console.log('解析后的地址:', regionInfo); this.setData({ 'origin.province': regionInfo.province || '', 'origin.city': regionInfo.city || '', - 'origin.district': regionInfo.district || '' + 'origin.district': regionInfo.district || '', + 'origin.detail': regionInfo.detail || '' }); + console.log('已设置出发地为商品所在地:', regionInfo); } } catch (e) { console.error('解析货源信息失败:', e); } } + + // 加载历史记录(在设置完 selectedGoods 后) + this.loadHistoryRecords(); }, // 初始化地址选择器数据 @@ -248,12 +254,16 @@ Page({ // 设置出发地为商品所在地 if (goodsItem.region) { + console.log('商品所在地原始地址:', goodsItem.region); const regionInfo = this.parseRegion(goodsItem.region); + console.log('解析后的地址:', regionInfo); this.setData({ 'origin.province': regionInfo.province || '', 'origin.city': regionInfo.city || '', - 'origin.district': regionInfo.district || '' + 'origin.district': regionInfo.district || '', + 'origin.detail': regionInfo.detail || '' }); + console.log('已设置出发地为商品所在地:', regionInfo); } // 设置货物重量(如果有) @@ -269,12 +279,35 @@ Page({ parseRegion: function (region) { if (!region) return {}; - // 简单的地区解析逻辑,实际项目中可能需要更复杂的解析 - const parts = region.split(' '); + // 尝试多种分隔符解析地址 + let parts = region.split(' '); + if (parts.length === 1) { + // 尝试使用其他分隔符 + parts = region.split('\n'); + if (parts.length === 1) { + parts = region.split(','); + } + } + + console.log('地址解析 - 原始地址:', region); + console.log('地址解析 - 分割后:', parts); + + // 提取省份、城市、区县 + const province = parts[0] || ''; + const city = parts[1] || ''; + const district = parts[2] || ''; + + // 收集区级后面的详细地址信息 + let detail = ''; + if (parts.length > 3) { + detail = parts.slice(3).join(' '); + } + return { - province: parts[0] || '', - city: parts[1] || '', - district: parts[2] || '' + province: province, + city: city, + district: district, + detail: detail }; }, @@ -282,20 +315,22 @@ Page({ loadHistoryRecords: function () { this.setData({ loading: true }); + const productId = this.data.selectedGoods ? (this.data.selectedGoods.productId || this.data.selectedGoods.id) : undefined; + API.getFreightHistory({ - productId: this.data.selectedGoods.productId || this.data.selectedGoods.id + productId: productId }).then(res => { this.setData({ loading: false }); if (res.success) { this.setData({ - historyRecords: res.data.records || [] + historyRecords: (res.data.records || []).slice(0, 3) // 只显示最近3条记录 }); } else { console.error('获取历史记录失败:', res.message); // 失败时使用本地存储作为 fallback const history = wx.getStorageSync('freightCalculatorHistory') || []; this.setData({ - historyRecords: history.slice(0, 10) // 只显示最近10条记录 + historyRecords: history.slice(0, 3) // 只显示最近3条记录 }); } }).catch(err => { @@ -304,7 +339,7 @@ Page({ // 失败时使用本地存储作为 fallback const history = wx.getStorageSync('freightCalculatorHistory') || []; this.setData({ - historyRecords: history.slice(0, 10) // 只显示最近10条记录 + historyRecords: history.slice(0, 3) // 只显示最近3条记录 }); }); }, @@ -331,7 +366,7 @@ Page({ // 更新页面数据 this.setData({ - historyRecords: newHistory.slice(0, 10) + historyRecords: newHistory.slice(0, 3) }); }, @@ -907,13 +942,14 @@ Page({ volume: '', vehicleInfo: '面包车(1.4米): 0-500kg, 0-5m³', // 计算结果 - showResult: false, - feeRange: '', - marketPrice: '', - complianceStatus: '', - isCompliant: true, - detailText: '', - calculationResult: null + showResult: false, + feeRange: '', + marketPrice: '', + complianceStatus: '', + isCompliant: true, + detailText: '', + calculationResult: null, + showDetail: false }); }, @@ -978,6 +1014,109 @@ Page({ } }, + // 将地址转换为经纬度 + convertAddressToCoordinates: function (origin, destination) { + return new Promise((resolve, reject) => { + // 转换出发地地址 + const convertOrigin = new Promise((resolveOrigin) => { + // 如果出发地已经有经纬度,直接返回 + if (origin.latitude && origin.longitude) { + resolveOrigin(origin); + return; + } + + // 构建出发地完整地址 + const originAddress = `${origin.province}${origin.city}${origin.district}${origin.detail}`; + if (!originAddress) { + resolveOrigin(origin); + return; + } + + // 使用腾讯地图地理编码API + wx.request({ + url: 'https://apis.map.qq.com/ws/geocoder/v1/', + data: { + address: originAddress, + key: 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77' + }, + success: function (res) { + if (res.data.status === 0) { + const location = res.data.result.location; + resolveOrigin({ + ...origin, + latitude: location.lat, + longitude: location.lng + }); + } else { + console.error('出发地地址转换失败:', res.data); + resolveOrigin(origin); + } + }, + fail: function (err) { + console.error('出发地地址转换失败:', err); + resolveOrigin(origin); + } + }); + }); + + // 转换目的地地址 + const convertDestination = new Promise((resolveDestination) => { + // 如果目的地已经有经纬度,直接返回 + if (destination.latitude && destination.longitude) { + resolveDestination(destination); + return; + } + + // 构建目的地完整地址 + const destinationAddress = `${destination.province}${destination.city}${destination.district}${destination.detail}`; + if (!destinationAddress) { + resolveDestination(destination); + return; + } + + // 使用腾讯地图地理编码API + wx.request({ + url: 'https://apis.map.qq.com/ws/geocoder/v1/', + data: { + address: destinationAddress, + key: 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77' + }, + success: function (res) { + if (res.data.status === 0) { + const location = res.data.result.location; + resolveDestination({ + ...destination, + latitude: location.lat, + longitude: location.lng + }); + } else { + console.error('目的地地址转换失败:', res.data); + resolveDestination(destination); + } + }, + fail: function (err) { + console.error('目的地地址转换失败:', err); + resolveDestination(destination); + } + }); + }); + + // 等待两个地址转换完成 + Promise.all([convertOrigin, convertDestination]).then(([originWithCoords, destinationWithCoords]) => { + resolve({ originWithCoords, destinationWithCoords }); + }).catch(err => { + reject(err); + }); + }); + }, + + // 切换费用明细显示/隐藏 + toggleDetail: function () { + this.setData({ + showDetail: !this.data.showDetail + }); + }, + // 运输模式选择 bindTransportModeChange: function(e) { this.setData({ @@ -1099,52 +1238,69 @@ Page({ packagingType: packagingType }; - // 调用API计算运费,获取距离信息 - API.calculateFreight(params).then(res => { - this.setData({ loading: false }); - if (res.success) { - // 使用API返回的距离 - const distance = res.data.distance || 100; - - // 自动获取当前时间、天气情况和是否节假日 - const { weather, holiday, timePeriod } = this.getAutoData(); - - // 调用计算函数(使用默认等候时间40分钟) - const result = this.calculateEggShippingFee( - transportMode, distance, weight, volume, packagingType, vehicleType, truckLength, 40, weather, holiday, timePeriod - ); - - // 更新结果 - this.setData({ - showResult: true, - feeRange: `${result.feeMin} - ${result.feeMax}元`, - marketPrice: `${result.marketPrice}元`, - complianceStatus: result.compliance.isCompliant ? '✓ 运输方案合规' : '✗ 运输方案不合规', - isCompliant: result.compliance.isCompliant, - detailText: this.generateDetailText(result, transportMode, weight, volume, packagingType, 40), - calculationResult: res.data // 保存API返回的结果 - }); - - // 保存历史记录 - this.saveHistoryRecord({ - freight: (result.feeMin + result.feeMax) / 2, - distance: distance, - deliveryTime: Math.ceil(distance / 80), // 简单估算,假设平均速度80km/h - feeRange: `${result.feeMin} - ${result.feeMax}元`, - marketPrice: result.marketPrice, - complianceStatus: result.compliance.isCompliant ? '合规' : '不合规' - }); - } else { + // 先将手写地址转换为经纬度 + this.convertAddressToCoordinates(this.data.origin, this.data.destination).then(({ originWithCoords, destinationWithCoords }) => { + // 更新参数中的地址信息,包含经纬度 + const paramsWithCoords = { + ...params, + origin: originWithCoords, + destination: destinationWithCoords + }; + + // 调用API计算运费,获取距离信息 + API.calculateFreight(paramsWithCoords).then(res => { + this.setData({ loading: false }); + if (res.success) { + // 使用API返回的距离 + const distance = res.data.distance || 100; + + // 自动获取当前时间、天气情况和是否节假日 + const { weather, holiday, timePeriod } = this.getAutoData(); + + // 调用计算函数(使用默认等候时间40分钟) + const result = this.calculateEggShippingFee( + transportMode, distance, weight, volume, packagingType, vehicleType, truckLength, 40, weather, holiday, timePeriod + ); + + // 更新结果 + this.setData({ + showResult: true, + feeRange: `${result.feeMin} - ${result.feeMax}元/车`, + marketPrice: `${result.marketPrice}元`, + complianceStatus: result.compliance.isCompliant ? '✓ 运输方案合规' : '✗ 运输方案不合规', + isCompliant: result.compliance.isCompliant, + detailText: this.generateDetailText(result, transportMode, weight, volume, packagingType, 40), + calculationResult: res.data // 保存API返回的结果 + }); + + // 保存历史记录 + this.saveHistoryRecord({ + freight: (result.feeMin + result.feeMax) / 2, + distance: distance, + deliveryTime: Math.ceil(distance / 80), // 简单估算,假设平均速度80km/h + feeRange: `${result.feeMin} - ${result.feeMax}元/车`, + marketPrice: result.marketPrice, + complianceStatus: result.compliance.isCompliant ? '合规' : '不合规' + }); + } else { + wx.showToast({ + title: res.message || '计算失败,请稍后重试', + icon: 'none' + }); + } + }).catch(err => { + this.setData({ loading: false }); + console.error('计算运费失败:', err); wx.showToast({ - title: res.message || '计算失败,请稍后重试', + title: '网络错误,请稍后重试', icon: 'none' }); - } + }); }).catch(err => { this.setData({ loading: false }); - console.error('计算运费失败:', err); + console.error('地址转换失败:', err); wx.showToast({ - title: '网络错误,请稍后重试', + title: '地址转换失败,请稍后重试', icon: 'none' }); }); @@ -1369,7 +1525,8 @@ Page({ // 检查车型载重 if (complianceParams.maxWeightPerVehicle[vehicleType]) { - if (chargeWeight > complianceParams.maxWeightPerVehicle[vehicleType]) { + // 对于轻泡货物,使用实际重量进行合规性检查,而不是体积重量 + if (weight > complianceParams.maxWeightPerVehicle[vehicleType]) { compliance.isCompliant = false; compliance.issues.push(`${vehicleType}载重不能超过${complianceParams.maxWeightPerVehicle[vehicleType]}公斤`); } @@ -1385,9 +1542,9 @@ Page({ // 检查包装要求 const estimatedPackages = Math.max(weight / complianceParams.weightPerPackage, volume / complianceParams.volumePerPackage); - if (estimatedPackages > 100) { + if (estimatedPackages > 300) { compliance.isCompliant = false; - compliance.issues.push('包装数量过多,建议分批运输'); + compliance.issues.push('包装数量较多,建议考虑多车运输'); } // 检查是否合规 @@ -1398,8 +1555,8 @@ Page({ if (transportMode === '货拉拉') { // 货拉拉收费标准 [feeMin, feeMax, breakdown] = this.calculateHuolalaFee(distance, vehicleType, truckLength, waitTime, packagingType); - } else if (transportMode === '运满满') { - // 运满满收费标准 + } else if (transportMode === '整车运输') { + // 整车运输收费标准 [feeMin, feeMax, breakdown] = this.calculateYunmanmanFee(distance, weight, volume, vehicleType, truckLength); } else { // 零担拼车收费标准 @@ -1693,7 +1850,7 @@ Page({ return [feeMin, feeMax, breakdown]; }, - // 运满满运费计算 + // 整车运输运费计算 calculateYunmanmanFee: function(distance, weight, volume, vehicleType, truckLength) { // 车长系数计算 const getTruckLengthFactor = (truckLength) => { @@ -1721,7 +1878,7 @@ Page({ } }; - // 运满满收费标准 + // 整车运输收费标准 const rates = { '面包车': { startFee: 80, @@ -1966,8 +2123,8 @@ Page({ marketPrice = rates[vehicleType] || rates['面包车']; // 应用车长系数 marketPrice *= truckLengthFactor; - } else if (transportMode === '运满满') { - // 基于运满满真实收费标准 + } else if (transportMode === '整车运输') { + // 基于整车运输真实收费标准 const rates = { '面包车': { startFee: 80, diff --git a/pages/freight-calculator/index.wxml b/pages/freight-calculator/index.wxml index e4d69dd..aec0a3a 100644 --- a/pages/freight-calculator/index.wxml +++ b/pages/freight-calculator/index.wxml @@ -166,8 +166,13 @@ - 费用明细 - {{detailText}} + + 费用明细 + + + {{detailText}} diff --git a/pages/freight-calculator/index.wxss b/pages/freight-calculator/index.wxss index 7cd7156..a6b4e56 100644 --- a/pages/freight-calculator/index.wxss +++ b/pages/freight-calculator/index.wxss @@ -683,6 +683,27 @@ word-break: break-all; } +/* 切换按钮样式 */ +.toggle-btn { + background: none; + border: none; + font-size: 20rpx; + color: #1989fa; + padding: 8rpx 16rpx; + border-radius: 4rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.toggle-btn:hover { + background-color: rgba(25, 137, 250, 0.1); +} + +.toggle-btn:active { + background-color: rgba(25, 137, 250, 0.2); +} + /* 动画效果 */ @keyframes fadeInUp { from { diff --git a/pages/goods-detail/goods-detail.js b/pages/goods-detail/goods-detail.js index 7726602..b9a4782 100644 --- a/pages/goods-detail/goods-detail.js +++ b/pages/goods-detail/goods-detail.js @@ -1526,6 +1526,8 @@ Page({ id: goodsDetail.id || goodsDetail.productId, name: goodsDetail.name || '未命名商品', region: goodsDetail.region || '', + // 尝试获取原始的完整地区信息,而不是处理过的省份信息 + fullRegion: goodsDetail.originalRegion || goodsDetail.region || '', specification: goodsDetail.specification || goodsDetail.spec || '', quantity: goodsDetail.quantity || goodsDetail.minOrder || '', price: goodsDetail.price || '', @@ -1535,6 +1537,7 @@ Page({ weightQuantityData: goodsDetail.weightQuantityData || [], imageUrl: (goodsDetail.imageUrls && goodsDetail.imageUrls.length > 0) ? goodsDetail.imageUrls[0] : '' }; + console.log('构建的selectedGoods:', selectedGoods); // 导航到运费计算器页面 this.navigateLock(() => { @@ -2348,6 +2351,9 @@ Page({ } } + // 保存原始的完整地区信息 + const originalRegion = product.region || ''; + // 转换商品数据格式 const formattedGoods = { // 优先设置售空状态标记,放在最前面确保不被覆盖 @@ -2387,6 +2393,8 @@ Page({ // 确保imageUrls和mediaItems被正确设置 imageUrls: imageUrls || [], mediaItems: mediaItems, + // 保存原始的完整地区信息 + originalRegion: originalRegion, // 确保region使用提取后的省份信息,放在最后覆盖所有展开操作 region: region, // 添加价格波动信息 diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index b4579b8..fd4b7fa 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -393,17 +393,20 @@ app.post('/api/freight/calculate', (req, res) => { data: result }); } catch (error) { - console.error('处理腾讯地图API响应时出错:', error); - // 如果处理响应时出错,使用固定距离作为fallback - const distance = 200; // 示例距离:200公里 - const freight = Math.floor(distance * baseRate * weight); - const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天 - - const result = { - freight: freight, - distance: distance, - deliveryTime: deliveryTime - }; + console.error('处理腾讯地图API响应时出错:', error); + // 如果处理响应时出错,使用固定距离作为fallback + const distance = 200; // 示例距离:200公里 + // 计算运费区间 + const [feeMin, feeMax] = calculateYunmanmanFee(distance, goodsInfo.weight || 1, goodsInfo.volume || 0, vehicleType || '平板', truckLength || '5米'); + const deliveryTime = Math.ceil(distance / 80); // 公路:80公里/天 + + const result = { + freight: Math.floor((feeMin + feeMax) / 2), // 中间值 + feeMin: feeMin, + feeMax: feeMax, + distance: distance, + deliveryTime: deliveryTime + }; // 保存运费估算历史记录 if (userId && phoneNumber) { @@ -436,11 +439,14 @@ app.post('/api/freight/calculate', (req, res) => { console.error('腾讯地图API调用失败:', error); // 如果API调用失败,使用固定距离作为fallback const distance = 200; // 示例距离:200公里 - const freight = Math.floor(distance * baseRate * weight); - const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天 + // 计算运费区间 + const [feeMin, feeMax] = calculateYunmanmanFee(distance, goodsInfo.weight || 1, goodsInfo.volume || 0, vehicleType || '平板', truckLength || '5米'); + const deliveryTime = Math.ceil(distance / 80); // 公路:80公里/天 const result = { - freight: freight, + freight: Math.floor((feeMin + feeMax) / 2), // 中间值 + feeMin: feeMin, + feeMax: feeMax, distance: distance, deliveryTime: deliveryTime }; @@ -474,11 +480,14 @@ app.post('/api/freight/calculate', (req, res) => { } else { // 没有经纬度信息,使用固定距离作为fallback const distance = 200; // 示例距离:200公里 - const freight = Math.floor(distance * baseRate * weight); - const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天 + // 计算运费区间 + const [feeMin, feeMax] = calculateYunmanmanFee(distance, goodsInfo.weight || 1, goodsInfo.volume || 0, vehicleType || '平板', truckLength || '5米'); + const deliveryTime = Math.ceil(distance / 80); // 公路:80公里/天 const result = { - freight: freight, + freight: Math.floor((feeMin + feeMax) / 2), // 中间值 + feeMin: feeMin, + feeMax: feeMax, distance: distance, deliveryTime: deliveryTime };