|
|
|
@ -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.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 { |
|
|
|
// 保存历史记录
|
|
|
|
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, |
|
|
|
|