|
|
@ -4,6 +4,149 @@ function getCurrentTime() { |
|
|
return new Date(); |
|
|
return new Date(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 运费计算辅助函数 - 计算运满满运费区间
|
|
|
|
|
|
function calculateYunmanmanFee(distance, weight, volume, vehicleType, truckLength) { |
|
|
|
|
|
// 车长系数计算
|
|
|
|
|
|
const getTruckLengthFactor = (truckLength) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const length = parseFloat(truckLength.replace('米', '')); |
|
|
|
|
|
if (length <= 3.8) { |
|
|
|
|
|
return 0.8; |
|
|
|
|
|
} else if (length <= 4.2) { |
|
|
|
|
|
return 0.9; |
|
|
|
|
|
} else if (length <= 5) { |
|
|
|
|
|
return 1.0; |
|
|
|
|
|
} else if (length <= 6.8) { |
|
|
|
|
|
return 1.1; |
|
|
|
|
|
} else if (length <= 7.7) { |
|
|
|
|
|
return 1.2; |
|
|
|
|
|
} else if (length <= 9.6) { |
|
|
|
|
|
return 1.3; |
|
|
|
|
|
} else if (length <= 13) { |
|
|
|
|
|
return 1.4; |
|
|
|
|
|
} else { |
|
|
|
|
|
return 1.5; |
|
|
|
|
|
} |
|
|
|
|
|
} catch { |
|
|
|
|
|
return 1.0; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 运满满收费标准
|
|
|
|
|
|
const rates = { |
|
|
|
|
|
'面包车': { |
|
|
|
|
|
startFee: 80, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 1.0, |
|
|
|
|
|
unitPriceMax: 1.3 |
|
|
|
|
|
}, |
|
|
|
|
|
'依维柯': { |
|
|
|
|
|
startFee: 160, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 1.5, |
|
|
|
|
|
unitPriceMax: 1.8 |
|
|
|
|
|
}, |
|
|
|
|
|
'平板': { |
|
|
|
|
|
startFee: 300, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.5, |
|
|
|
|
|
unitPriceMax: 2.9 |
|
|
|
|
|
}, |
|
|
|
|
|
'厢式': { |
|
|
|
|
|
startFee: 220, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.1, |
|
|
|
|
|
unitPriceMax: 2.4 |
|
|
|
|
|
}, |
|
|
|
|
|
'高栏车': { |
|
|
|
|
|
startFee: 200, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.5, |
|
|
|
|
|
unitPriceMax: 2.8 |
|
|
|
|
|
}, |
|
|
|
|
|
'集装箱': { |
|
|
|
|
|
startFee: 300, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.8, |
|
|
|
|
|
unitPriceMax: 3.1 |
|
|
|
|
|
}, |
|
|
|
|
|
'自卸': { |
|
|
|
|
|
startFee: 250, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.2, |
|
|
|
|
|
unitPriceMax: 2.5 |
|
|
|
|
|
}, |
|
|
|
|
|
'冷藏': { |
|
|
|
|
|
startFee: 300, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.5, |
|
|
|
|
|
unitPriceMax: 2.8 |
|
|
|
|
|
}, |
|
|
|
|
|
'保温': { |
|
|
|
|
|
startFee: 280, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.3, |
|
|
|
|
|
unitPriceMax: 2.6 |
|
|
|
|
|
}, |
|
|
|
|
|
'棉被车': { |
|
|
|
|
|
startFee: 260, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.2, |
|
|
|
|
|
unitPriceMax: 2.5 |
|
|
|
|
|
}, |
|
|
|
|
|
'爬梯车': { |
|
|
|
|
|
startFee: 280, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.3, |
|
|
|
|
|
unitPriceMax: 2.6 |
|
|
|
|
|
}, |
|
|
|
|
|
'飞翼车': { |
|
|
|
|
|
startFee: 270, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.2, |
|
|
|
|
|
unitPriceMax: 2.5 |
|
|
|
|
|
}, |
|
|
|
|
|
'高低板': { |
|
|
|
|
|
startFee: 350, |
|
|
|
|
|
startDistance: 10, |
|
|
|
|
|
unitPriceMin: 2.8, |
|
|
|
|
|
unitPriceMax: 3.1 |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const rate = rates[vehicleType] || rates['平板']; |
|
|
|
|
|
|
|
|
|
|
|
// 获取车长系数
|
|
|
|
|
|
const truckLengthFactor = getTruckLengthFactor(truckLength); |
|
|
|
|
|
|
|
|
|
|
|
// 计算距离费用
|
|
|
|
|
|
let feeMin, feeMax; |
|
|
|
|
|
if (distance <= rate.startDistance) { |
|
|
|
|
|
feeMin = rate.startFee; |
|
|
|
|
|
feeMax = rate.startFee; |
|
|
|
|
|
} else { |
|
|
|
|
|
const extraDistance = distance - rate.startDistance; |
|
|
|
|
|
feeMin = rate.startFee + extraDistance * rate.unitPriceMin; |
|
|
|
|
|
feeMax = rate.startFee + extraDistance * rate.unitPriceMax; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 应用车长系数
|
|
|
|
|
|
feeMin *= truckLengthFactor; |
|
|
|
|
|
feeMax *= truckLengthFactor; |
|
|
|
|
|
|
|
|
|
|
|
// 根据货物重量和体积调整价格
|
|
|
|
|
|
if (weight > 1000 || volume > 10) { |
|
|
|
|
|
feeMin *= 1.1; |
|
|
|
|
|
feeMax *= 1.1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 添加平台佣金(运费的5%左右)
|
|
|
|
|
|
feeMin *= 1.05; |
|
|
|
|
|
feeMax *= 1.05; |
|
|
|
|
|
|
|
|
|
|
|
return [Math.floor(feeMin), Math.floor(feeMax)]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
function getCurrentTimeISOString() { |
|
|
function getCurrentTimeISOString() { |
|
|
return getCurrentTime().toISOString(); |
|
|
return getCurrentTime().toISOString(); |
|
|
} |
|
|
} |
|
|
@ -131,7 +274,7 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
console.log('===== 运费计算接口被调用 ====='); |
|
|
console.log('===== 运费计算接口被调用 ====='); |
|
|
console.log('1. 收到请求体:', JSON.stringify(req.body, null, 2)); |
|
|
console.log('1. 收到请求体:', JSON.stringify(req.body, null, 2)); |
|
|
|
|
|
|
|
|
const { origin, destination, goodsInfo: originalGoodsInfo } = req.body; |
|
|
const { origin, destination, goodsInfo: originalGoodsInfo, productId, userId, phoneNumber, vehicleInfo, transportMode, vehicleType, truckLength, packagingType } = req.body; |
|
|
let goodsInfo = originalGoodsInfo; |
|
|
let goodsInfo = originalGoodsInfo; |
|
|
|
|
|
|
|
|
// 验证参数
|
|
|
// 验证参数
|
|
|
@ -149,10 +292,6 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
goodsInfo = { ...goodsInfo, weight: 1 }; |
|
|
goodsInfo = { ...goodsInfo, weight: 1 }; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 计算运费(使用默认费率,用户可根据自己的物流标准调整)
|
|
|
|
|
|
const baseRate = 0.5; // 默认基础费率(元/公里/公斤)
|
|
|
|
|
|
const weight = goodsInfo.weight || 1; |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有经纬度信息
|
|
|
// 检查是否有经纬度信息
|
|
|
if (origin.latitude && origin.longitude && destination.latitude && destination.longitude) { |
|
|
if (origin.latitude && origin.longitude && destination.latitude && destination.longitude) { |
|
|
// 直接使用经纬度计算距离
|
|
|
// 直接使用经纬度计算距离
|
|
|
@ -175,37 +314,84 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
const response = JSON.parse(data); |
|
|
const response = JSON.parse(data); |
|
|
console.log('腾讯地图API响应:', response); |
|
|
console.log('腾讯地图API响应:', response); |
|
|
|
|
|
|
|
|
if (response.status === 0 && response.result && response.result.elements && response.result.elements.length > 0) { |
|
|
let result; |
|
|
const distance = response.result.elements[0].distance / 1000; // 转换为公里
|
|
|
if (response.status === 0 && response.result && response.result.rows && response.result.rows.length > 0) { |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
// 检查rows[0]是否有elements属性
|
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
const row = response.result.rows[0]; |
|
|
|
|
|
if (row.elements && row.elements.length > 0) { |
|
|
console.log('腾讯地图API距离计算成功,距离:', distance, '公里'); |
|
|
const distance = row.elements[0].distance / 1000; // 转换为公里
|
|
|
|
|
|
// 计算运费区间
|
|
|
res.json({ |
|
|
const [feeMin, feeMax] = calculateYunmanmanFee(distance, goodsInfo.weight || 1, goodsInfo.volume || 0, vehicleType || '平板', truckLength || '5米'); |
|
|
success: true, |
|
|
const deliveryTime = Math.ceil(distance / 80); // 公路:80公里/天
|
|
|
data: { |
|
|
|
|
|
freight: freight, |
|
|
console.log('腾讯地图API距离计算成功,距离:', distance, '公里'); |
|
|
|
|
|
console.log('运费区间:', feeMin, '-', feeMax, '元'); |
|
|
|
|
|
|
|
|
|
|
|
result = { |
|
|
|
|
|
freight: Math.floor((feeMin + feeMax) / 2), // 中间值
|
|
|
|
|
|
feeMin: feeMin, |
|
|
|
|
|
feeMax: feeMax, |
|
|
distance: Math.round(distance * 10) / 10, // 保留一位小数
|
|
|
distance: Math.round(distance * 10) / 10, // 保留一位小数
|
|
|
deliveryTime: deliveryTime |
|
|
deliveryTime: deliveryTime |
|
|
} |
|
|
}; |
|
|
}); |
|
|
} else { |
|
|
|
|
|
console.error('腾讯地图API距离计算失败: 响应格式错误', response); |
|
|
|
|
|
// 如果腾讯地图API调用失败,使用固定距离作为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公里/天
|
|
|
|
|
|
|
|
|
|
|
|
result = { |
|
|
|
|
|
freight: Math.floor((feeMin + feeMax) / 2), // 中间值
|
|
|
|
|
|
feeMin: feeMin, |
|
|
|
|
|
feeMax: feeMax, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.error('腾讯地图API距离计算失败:', response); |
|
|
console.error('腾讯地图API距离计算失败:', response); |
|
|
// 如果腾讯地图API调用失败,使用固定距离作为fallback
|
|
|
// 如果腾讯地图API调用失败,使用固定距离作为fallback
|
|
|
const distance = 200; // 示例距离:200公里
|
|
|
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公里/天
|
|
|
|
|
|
|
|
|
|
|
|
result = { |
|
|
|
|
|
freight: Math.floor((feeMin + feeMax) / 2), // 中间值
|
|
|
|
|
|
feeMin: feeMin, |
|
|
|
|
|
feeMax: feeMax, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
res.json({ |
|
|
// 保存运费估算历史记录
|
|
|
success: true, |
|
|
if (userId && phoneNumber) { |
|
|
data: { |
|
|
FreightCalculationHistory.create({ |
|
|
freight: freight, |
|
|
productId: productId || '', |
|
|
distance: distance, |
|
|
userId: userId, |
|
|
deliveryTime: deliveryTime |
|
|
phoneNumber: phoneNumber, |
|
|
} |
|
|
origin: JSON.stringify(origin), |
|
|
|
|
|
destination: JSON.stringify(destination), |
|
|
|
|
|
weight: goodsInfo.weight, |
|
|
|
|
|
volume: goodsInfo.volume, |
|
|
|
|
|
goodsInfo: JSON.stringify(goodsInfo), |
|
|
|
|
|
vehicleInfo: vehicleInfo, |
|
|
|
|
|
transportMode: transportMode, |
|
|
|
|
|
result: JSON.stringify(result) |
|
|
|
|
|
}).then(() => { |
|
|
|
|
|
console.log('运费估算历史记录保存成功'); |
|
|
|
|
|
}).catch((error) => { |
|
|
|
|
|
console.error('保存运费估算历史记录失败:', error); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
res.json({ |
|
|
|
|
|
success: true, |
|
|
|
|
|
data: result |
|
|
|
|
|
}); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('处理腾讯地图API响应时出错:', error); |
|
|
console.error('处理腾讯地图API响应时出错:', error); |
|
|
// 如果处理响应时出错,使用固定距离作为fallback
|
|
|
// 如果处理响应时出错,使用固定距离作为fallback
|
|
|
@ -213,13 +399,36 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
|
|
|
|
|
|
|
|
|
const result = { |
|
|
|
|
|
freight: freight, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 保存运费估算历史记录
|
|
|
|
|
|
if (userId && phoneNumber) { |
|
|
|
|
|
FreightCalculationHistory.create({ |
|
|
|
|
|
productId: productId || '', |
|
|
|
|
|
userId: userId, |
|
|
|
|
|
phoneNumber: phoneNumber, |
|
|
|
|
|
origin: JSON.stringify(origin), |
|
|
|
|
|
destination: JSON.stringify(destination), |
|
|
|
|
|
weight: goodsInfo.weight, |
|
|
|
|
|
volume: goodsInfo.volume, |
|
|
|
|
|
goodsInfo: JSON.stringify(goodsInfo), |
|
|
|
|
|
vehicleInfo: vehicleInfo, |
|
|
|
|
|
transportMode: transportMode, |
|
|
|
|
|
result: JSON.stringify(result) |
|
|
|
|
|
}).then(() => { |
|
|
|
|
|
console.log('运费估算历史记录保存成功'); |
|
|
|
|
|
}).catch((error) => { |
|
|
|
|
|
console.error('保存运费估算历史记录失败:', error); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
res.json({ |
|
|
res.json({ |
|
|
success: true, |
|
|
success: true, |
|
|
data: { |
|
|
data: result |
|
|
freight: freight, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
@ -230,13 +439,36 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
|
|
|
|
|
|
|
|
|
const result = { |
|
|
|
|
|
freight: freight, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 保存运费估算历史记录
|
|
|
|
|
|
if (userId && phoneNumber) { |
|
|
|
|
|
FreightCalculationHistory.create({ |
|
|
|
|
|
productId: productId || '', |
|
|
|
|
|
userId: userId, |
|
|
|
|
|
phoneNumber: phoneNumber, |
|
|
|
|
|
origin: JSON.stringify(origin), |
|
|
|
|
|
destination: JSON.stringify(destination), |
|
|
|
|
|
weight: goodsInfo.weight, |
|
|
|
|
|
volume: goodsInfo.volume, |
|
|
|
|
|
goodsInfo: JSON.stringify(goodsInfo), |
|
|
|
|
|
vehicleInfo: vehicleInfo, |
|
|
|
|
|
transportMode: transportMode, |
|
|
|
|
|
result: JSON.stringify(result) |
|
|
|
|
|
}).then(() => { |
|
|
|
|
|
console.log('运费估算历史记录保存成功'); |
|
|
|
|
|
}).catch((error) => { |
|
|
|
|
|
console.error('保存运费估算历史记录失败:', error); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
res.json({ |
|
|
res.json({ |
|
|
success: true, |
|
|
success: true, |
|
|
data: { |
|
|
data: result |
|
|
freight: freight, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
} else { |
|
|
} else { |
|
|
@ -245,13 +477,36 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
const freight = Math.floor(distance * baseRate * weight); |
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
const deliveryTime = Math.ceil(distance / 200); // 公路:200公里/天
|
|
|
|
|
|
|
|
|
|
|
|
const result = { |
|
|
|
|
|
freight: freight, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 保存运费估算历史记录
|
|
|
|
|
|
if (userId && phoneNumber) { |
|
|
|
|
|
FreightCalculationHistory.create({ |
|
|
|
|
|
productId: productId || '', |
|
|
|
|
|
userId: userId, |
|
|
|
|
|
phoneNumber: phoneNumber, |
|
|
|
|
|
origin: JSON.stringify(origin), |
|
|
|
|
|
destination: JSON.stringify(destination), |
|
|
|
|
|
weight: goodsInfo.weight, |
|
|
|
|
|
volume: goodsInfo.volume, |
|
|
|
|
|
goodsInfo: JSON.stringify(goodsInfo), |
|
|
|
|
|
vehicleInfo: vehicleInfo, |
|
|
|
|
|
transportMode: transportMode, |
|
|
|
|
|
result: JSON.stringify(result) |
|
|
|
|
|
}).then(() => { |
|
|
|
|
|
console.log('运费估算历史记录保存成功'); |
|
|
|
|
|
}).catch((error) => { |
|
|
|
|
|
console.error('保存运费估算历史记录失败:', error); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
res.json({ |
|
|
res.json({ |
|
|
success: true, |
|
|
success: true, |
|
|
data: { |
|
|
data: result |
|
|
freight: freight, |
|
|
|
|
|
distance: distance, |
|
|
|
|
|
deliveryTime: deliveryTime |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -264,6 +519,75 @@ app.post('/api/freight/calculate', (req, res) => { |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 获取运费估算历史记录接口
|
|
|
|
|
|
app.get('/api/freight/history', async (req, res) => { |
|
|
|
|
|
try { |
|
|
|
|
|
console.log('===== 获取运费估算历史记录接口被调用 ====='); |
|
|
|
|
|
console.log('1. 收到查询参数:', req.query); |
|
|
|
|
|
|
|
|
|
|
|
const { userId, productId, page = 1, pageSize = 10 } = req.query; |
|
|
|
|
|
|
|
|
|
|
|
// 构建查询条件
|
|
|
|
|
|
const whereCondition = {}; |
|
|
|
|
|
if (userId) { |
|
|
|
|
|
whereCondition.userId = userId; |
|
|
|
|
|
} |
|
|
|
|
|
if (productId) { |
|
|
|
|
|
whereCondition.productId = productId; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 计算分页偏移量
|
|
|
|
|
|
const offset = (parseInt(page) - 1) * parseInt(pageSize); |
|
|
|
|
|
|
|
|
|
|
|
// 查询历史记录
|
|
|
|
|
|
const historyRecords = await FreightCalculationHistory.findAll({ |
|
|
|
|
|
where: whereCondition, |
|
|
|
|
|
order: [['created_at', 'DESC']], |
|
|
|
|
|
limit: parseInt(pageSize), |
|
|
|
|
|
offset: offset |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 计算总记录数
|
|
|
|
|
|
const totalCount = await FreightCalculationHistory.count({ |
|
|
|
|
|
where: whereCondition |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 格式化响应数据
|
|
|
|
|
|
const formattedRecords = historyRecords.map(record => { |
|
|
|
|
|
const recordData = record.toJSON(); |
|
|
|
|
|
try { |
|
|
|
|
|
recordData.origin = JSON.parse(recordData.origin); |
|
|
|
|
|
recordData.destination = JSON.parse(recordData.destination); |
|
|
|
|
|
recordData.goodsInfo = JSON.parse(recordData.goodsInfo); |
|
|
|
|
|
recordData.result = JSON.parse(recordData.result); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('解析JSON字段失败:', error); |
|
|
|
|
|
} |
|
|
|
|
|
return recordData; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
res.json({ |
|
|
|
|
|
success: true, |
|
|
|
|
|
data: { |
|
|
|
|
|
records: formattedRecords, |
|
|
|
|
|
pagination: { |
|
|
|
|
|
page: parseInt(page), |
|
|
|
|
|
pageSize: parseInt(pageSize), |
|
|
|
|
|
total: totalCount, |
|
|
|
|
|
totalPages: Math.ceil(totalCount / parseInt(pageSize)) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('获取运费估算历史记录失败:', error); |
|
|
|
|
|
res.status(500).json({ |
|
|
|
|
|
success: false, |
|
|
|
|
|
message: '获取运费估算历史记录失败: ' + error.message |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Eggbar 帖子创建接口
|
|
|
// Eggbar 帖子创建接口
|
|
|
app.post('/api/eggbar/posts', async (req, res) => { |
|
|
app.post('/api/eggbar/posts', async (req, res) => { |
|
|
@ -1784,7 +2108,7 @@ Product.init({ |
|
|
allowNull: false |
|
|
allowNull: false |
|
|
}, |
|
|
}, |
|
|
region: { |
|
|
region: { |
|
|
type: DataTypes.STRING(100), |
|
|
type: DataTypes.STRING(255), |
|
|
}, |
|
|
}, |
|
|
price: { |
|
|
price: { |
|
|
type: DataTypes.STRING(10), |
|
|
type: DataTypes.STRING(10), |
|
|
@ -2775,6 +3099,105 @@ UserFollowupHistory.init({ |
|
|
timestamps: false |
|
|
timestamps: false |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 定义运费估算历史记录模型
|
|
|
|
|
|
class FreightCalculationHistory extends Model { } |
|
|
|
|
|
FreightCalculationHistory.init({ |
|
|
|
|
|
id: { |
|
|
|
|
|
type: DataTypes.INTEGER, |
|
|
|
|
|
autoIncrement: true, |
|
|
|
|
|
primaryKey: true |
|
|
|
|
|
}, |
|
|
|
|
|
productId: { |
|
|
|
|
|
type: DataTypes.STRING(100), |
|
|
|
|
|
allowNull: true, |
|
|
|
|
|
defaultValue: null, |
|
|
|
|
|
comment: '产品id' |
|
|
|
|
|
}, |
|
|
|
|
|
userId: { |
|
|
|
|
|
type: DataTypes.STRING(100), |
|
|
|
|
|
allowNull: false, |
|
|
|
|
|
comment: '用户id' |
|
|
|
|
|
}, |
|
|
|
|
|
phoneNumber: { |
|
|
|
|
|
type: DataTypes.STRING(20), |
|
|
|
|
|
allowNull: false, |
|
|
|
|
|
comment: '电话号码' |
|
|
|
|
|
}, |
|
|
|
|
|
origin: { |
|
|
|
|
|
type: DataTypes.STRING(255), |
|
|
|
|
|
defaultValue: '', |
|
|
|
|
|
comment: '出发地信息' |
|
|
|
|
|
}, |
|
|
|
|
|
destination: { |
|
|
|
|
|
type: DataTypes.STRING(255), |
|
|
|
|
|
defaultValue: '', |
|
|
|
|
|
comment: '目的地信息' |
|
|
|
|
|
}, |
|
|
|
|
|
weight: { |
|
|
|
|
|
type: DataTypes.DECIMAL(10, 2), |
|
|
|
|
|
allowNull: true, |
|
|
|
|
|
comment: '货物重量(kg)' |
|
|
|
|
|
}, |
|
|
|
|
|
volume: { |
|
|
|
|
|
type: DataTypes.DECIMAL(10, 2), |
|
|
|
|
|
allowNull: true, |
|
|
|
|
|
comment: '货物体积(m³)' |
|
|
|
|
|
}, |
|
|
|
|
|
goodsInfo: { |
|
|
|
|
|
type: DataTypes.TEXT, |
|
|
|
|
|
allowNull: false, |
|
|
|
|
|
comment: '货物信息' |
|
|
|
|
|
}, |
|
|
|
|
|
vehicleInfo: { |
|
|
|
|
|
type: DataTypes.STRING(255), |
|
|
|
|
|
allowNull: true, |
|
|
|
|
|
comment: '车型信息' |
|
|
|
|
|
}, |
|
|
|
|
|
transportMode: { |
|
|
|
|
|
type: DataTypes.STRING(50), |
|
|
|
|
|
allowNull: true, |
|
|
|
|
|
comment: '运输模式' |
|
|
|
|
|
}, |
|
|
|
|
|
result: { |
|
|
|
|
|
type: DataTypes.TEXT, |
|
|
|
|
|
allowNull: false, |
|
|
|
|
|
comment: '计算结果' |
|
|
|
|
|
}, |
|
|
|
|
|
created_at: { |
|
|
|
|
|
type: DataTypes.DATE, |
|
|
|
|
|
defaultValue: Sequelize.NOW, |
|
|
|
|
|
comment: '创建时间' |
|
|
|
|
|
}, |
|
|
|
|
|
updated_at: { |
|
|
|
|
|
type: DataTypes.DATE, |
|
|
|
|
|
defaultValue: Sequelize.NOW, |
|
|
|
|
|
onUpdate: Sequelize.NOW, |
|
|
|
|
|
comment: '更新时间' |
|
|
|
|
|
} |
|
|
|
|
|
}, { |
|
|
|
|
|
sequelize, |
|
|
|
|
|
modelName: 'FreightCalculationHistory', |
|
|
|
|
|
tableName: 'freight_calculation_history', |
|
|
|
|
|
timestamps: false, |
|
|
|
|
|
indexes: [ |
|
|
|
|
|
{ |
|
|
|
|
|
fields: ['productId'], |
|
|
|
|
|
name: 'idx_productId', |
|
|
|
|
|
comment: '产品ID索引' |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
fields: ['created_at'], |
|
|
|
|
|
name: 'idx_created_at', |
|
|
|
|
|
comment: '创建时间索引' |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
fields: ['productId', 'created_at'], |
|
|
|
|
|
name: 'idx_productId_created_at', |
|
|
|
|
|
comment: '产品ID和创建时间联合索引' |
|
|
|
|
|
} |
|
|
|
|
|
] |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 定义模型之间的关联关系
|
|
|
// 定义模型之间的关联关系
|
|
|
|
|
|
|
|
|
// 用户和商品的一对多关系 (卖家发布商品)
|
|
|
// 用户和商品的一对多关系 (卖家发布商品)
|
|
|
|