// pages/freight-calculator/index.js const API = require('../../utils/api.js'); Page({ data: { // 出发地信息 origin: { province: '', city: '', district: '', detail: '' }, // 目的地信息 destination: { province: '', city: '', district: '', detail: '' }, // 货物信息 goodsInfo: { weight: '', // 重量(kg) volume: '', // 体积(m³) quantity: 1, // 数量 type: 'egg' // 货物类型,默认为鸡蛋 }, // 物流车辆信息 vehicleInfo: { type: '', // 车辆类型 capacity: '', // 载重能力(吨) number: '', // 车辆编号 driver: '', // 司机姓名 phone: '' // 联系电话 }, // 物流人员信息 logisticsPersonnel: [ { id: 1, name: '张三', position: '物流经理', experience: 5, phone: '13800138000' }, { id: 2, name: '李四', position: '物流经理', experience: 3, phone: '13900139000' }, { id: 3, name: '王五', position: '物流经理', experience: 2, phone: '13700137000' } ], // 车辆类型列表 vehicleTypes: ['厢式货车', '冷藏车', '平板车', '高栏车', '自卸车'], // 选中的车辆类型索引 selectedVehicleTypeIndex: 0, // 选中的货源信息 selectedGoods: {}, // 选中的规格索引 selectedSpecIndex: 0, // 计算结果 calculationResult: null, // 地址选择器状态 showOriginPicker: false, showDestinationPicker: false, // 加载状态 loading: false, // 历史记录 historyRecords: [], // 地址选择器数据 regionList: { provinces: [], cities: [], districts: [] }, // 地址选择器当前选中 pickerValues: { origin: [0, 0, 0], destination: [0, 0, 0] } }, onLoad: function (options) { // 页面加载时的初始化逻辑 console.log('物流运费估算页面加载,options:', options); // 加载历史记录 this.loadHistoryRecords(); // 初始化地址选择器数据 this.initRegionData(); // 如果从商品详情页跳转过来,获取商品信息 if (options.goodsId) { this.loadGoodsInfo(options.goodsId); } // 如果直接传递了货源信息 (goodsInfo) if (options.goodsInfo) { try { const goodsInfo = JSON.parse(options.goodsInfo); this.setData({ selectedGoods: goodsInfo, 'goodsInfo.weight': goodsInfo.grossWeight || '', 'goodsInfo.quantity': 1 }); } catch (e) { console.error('解析货源信息失败:', e); } } // 如果直接传递了货源信息 (goodsData) if (options.goodsData) { try { // 尝试直接解析 let goodsData; try { goodsData = JSON.parse(options.goodsData); } catch (e1) { // 如果直接解析失败,尝试解码后再解析 try { const decodedGoodsData = decodeURIComponent(options.goodsData); goodsData = JSON.parse(decodedGoodsData); } catch (e2) { console.error('解析货源信息失败 (已尝试解码):', e2); throw e2; } } this.setData({ selectedGoods: goodsData, 'goodsInfo.weight': goodsData.grossWeight || '', 'goodsInfo.quantity': 1 }); // 设置出发地为商品所在地 if (goodsData.region) { const regionInfo = this.parseRegion(goodsData.region); this.setData({ 'origin.province': regionInfo.province || '', 'origin.city': regionInfo.city || '', 'origin.district': regionInfo.district || '' }); } } catch (e) { console.error('解析货源信息失败:', e); } } }, // 初始化地址选择器数据 initRegionData: function () { // 这里可以从API获取地址数据,或者使用本地数据 const provinces = [ '北京市', '上海市', '广东省', '江苏省', '浙江省', '山东省', '河南省', '四川省', '湖北省', '福建省', '湖南省', '安徽省', '河北省', '辽宁省', '陕西省', '江西省', '云南省', '黑龙江省', '山西省', '广西壮族自治区', '内蒙古自治区', '吉林省', '贵州省', '新疆维吾尔自治区', '甘肃省', '重庆市', '宁夏回族自治区', '青海省', '西藏自治区', '海南省' ]; this.setData({ 'regionList.provinces': provinces }); }, // 加载商品信息 loadGoodsInfo: function (goodsId) { // 从本地存储获取商品信息 const goods = wx.getStorageSync('goods') || []; const goodsItem = goods.find(item => item.id === goodsId || item.productId === goodsId); if (goodsItem) { // 设置选中的货源信息 this.setData({ selectedGoods: goodsItem }); // 设置出发地为商品所在地 if (goodsItem.region) { const regionInfo = this.parseRegion(goodsItem.region); this.setData({ 'origin.province': regionInfo.province || '', 'origin.city': regionInfo.city || '', 'origin.district': regionInfo.district || '' }); } // 设置货物重量(如果有) if (goodsItem.grossWeight) { this.setData({ 'goodsInfo.weight': goodsItem.grossWeight }); } } }, // 解析地区信息 parseRegion: function (region) { if (!region) return {}; // 简单的地区解析逻辑,实际项目中可能需要更复杂的解析 const parts = region.split(' '); return { province: parts[0] || '', city: parts[1] || '', district: parts[2] || '' }; }, // 加载历史记录 loadHistoryRecords: function () { const history = wx.getStorageSync('freightCalculatorHistory') || []; this.setData({ historyRecords: history.slice(0, 10) // 只显示最近10条记录 }); }, // 保存历史记录 saveHistoryRecord: function (result) { const history = wx.getStorageSync('freightCalculatorHistory') || []; const record = { id: Date.now(), origin: this.data.origin, destination: this.data.destination, goodsInfo: this.data.goodsInfo, vehicleInfo: this.data.vehicleInfo, transportMode: this.data.transportMode, result: result, timestamp: new Date().toISOString() }; // 添加到历史记录开头 history.unshift(record); // 只保留最近20条记录 const newHistory = history.slice(0, 20); wx.setStorageSync('freightCalculatorHistory', newHistory); // 更新页面数据 this.setData({ historyRecords: newHistory.slice(0, 10) }); }, // 输入出发地 bindOriginInput: function (e) { const { key } = e.currentTarget.dataset; this.setData({ [`origin.${key}`]: e.detail.value }); }, // 输入目的地 bindDestinationInput: function (e) { const { key } = e.currentTarget.dataset; this.setData({ [`destination.${key}`]: e.detail.value }); }, // 输入货物信息 bindGoodsInfoInput: function (e) { const { key } = e.currentTarget.dataset; this.setData({ [`goodsInfo.${key}`]: e.detail.value }); }, // 选择规格组合 bindSpecChange: function (e) { const index = e.detail.value; this.setData({ selectedSpecIndex: index }); }, // 选择车辆类型 bindVehicleTypeChange: function (e) { const index = e.detail.value; this.setData({ selectedVehicleTypeIndex: index, 'vehicleInfo.type': this.data.vehicleTypes[index] }); }, // 输入车辆信息 bindVehicleInfoInput: function (e) { const { key } = e.currentTarget.dataset; this.setData({ [`vehicleInfo.${key}`]: e.detail.value }); }, // 地址选择器值变化 bindRegionChange: function (e) { const { type } = e.currentTarget.dataset; const values = e.detail.value; // 更新地址信息 if (type === 'origin') { this.setData({ 'origin.province': values[0], 'origin.city': values[1], 'origin.district': values[2] }); } else if (type === 'destination') { this.setData({ 'destination.province': values[0], 'destination.city': values[1], 'destination.district': values[2] }); } }, // 打开出发地选择器 openOriginPicker: function () { this.setData({ showOriginPicker: true }); }, // 打开目的地选择器 openDestinationPicker: function () { this.setData({ showDestinationPicker: true }); }, // 关闭地址选择器 closePicker: function () { this.setData({ showOriginPicker: false, showDestinationPicker: false }); }, // 选择地址 selectAddress: function (e) { const { type, address } = e.detail; if (type === 'origin') { this.setData({ origin: address, showOriginPicker: false }); } else if (type === 'destination') { this.setData({ destination: address, showDestinationPicker: false }); } }, // 使用当前位置作为出发地 useCurrentLocation: function () { const that = this; wx.getLocation({ type: 'wgs84', success: function (res) { // 显示加载提示 wx.showLoading({ title: '获取地址中...', mask: true }); // 使用微信的地址解析服务获取详细地址 wx.request({ url: 'https://apis.map.qq.com/ws/geocoder/v1/', data: { location: `${res.latitude},${res.longitude}`, key: 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77' // 这里使用腾讯地图API密钥,实际项目中应该替换为自己的密钥 }, success: function (response) { wx.hideLoading(); if (response.data.status === 0) { const result = response.data.result; that.setData({ destination: { province: result.address_component.province || '', city: result.address_component.city || '', district: result.address_component.district || '', detail: result.address || '', latitude: res.latitude, longitude: res.longitude } }); wx.showToast({ title: '地址获取成功', icon: 'success' }); } else { wx.showToast({ title: '地址解析失败,请手动输入', icon: 'none' }); } }, fail: function (err) { wx.hideLoading(); console.error('地址解析失败:', err); wx.showToast({ title: '地址解析失败,请手动输入', icon: 'none' }); } }); }, fail: function (err) { console.error('获取位置失败:', err); wx.showToast({ title: '获取位置失败,请手动输入', icon: 'none' }); } }); }, // 手动选择出发地位置 chooseOriginLocation: function () { const that = this; wx.chooseLocation({ success(res) { console.log('用户选择的出发地位置信息:', res); const name = res.name; const address = res.address; const latitude = res.latitude; const longitude = res.longitude; // 使用腾讯地图API进行逆地理编码,获取详细地址信息 wx.request({ url: 'https://apis.map.qq.com/ws/geocoder/v1/', data: { location: `${latitude},${longitude}`, key: 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77' }, success: function (response) { if (response.data.status === 0) { const result = response.data.result; that.setData({ origin: { province: result.address_component.province || '', city: result.address_component.city || '', district: result.address_component.district || '', detail: `${name} ${address}`, latitude: latitude, longitude: longitude } }); wx.showToast({ title: '出发地选择成功', icon: 'success' }); } else { wx.showToast({ title: '地址解析失败,请手动输入', icon: 'none' }); } }, fail: function (err) { console.error('地址解析失败:', err); wx.showToast({ title: '地址解析失败,请手动输入', icon: 'none' }); } }); }, fail(err) { console.error('选择出发地位置失败:', err); if (err.errMsg === 'chooseLocation:fail auth deny') { wx.showToast({ title: '需要位置授权才能选择地点', icon: 'none', duration: 2000 }); // 引导用户重新授权 that.requestLocationAuth(); } else { wx.showToast({ title: '选择位置失败', icon: 'none', duration: 2000 }); } } }); }, // 手动选择目的地位置 chooseDestinationLocation: function () { const that = this; wx.chooseLocation({ success(res) { console.log('用户选择的目的地位置信息:', res); const name = res.name; const address = res.address; const latitude = res.latitude; const longitude = res.longitude; // 使用腾讯地图API进行逆地理编码,获取详细地址信息 wx.request({ url: 'https://apis.map.qq.com/ws/geocoder/v1/', data: { location: `${latitude},${longitude}`, key: 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77' }, success: function (response) { if (response.data.status === 0) { const result = response.data.result; that.setData({ destination: { province: result.address_component.province || '', city: result.address_component.city || '', district: result.address_component.district || '', detail: `${name} ${address}`, latitude: latitude, longitude: longitude } }); wx.showToast({ title: '目的地选择成功', icon: 'success' }); } else { wx.showToast({ title: '地址解析失败,请手动输入', icon: 'none' }); } }, fail: function (err) { console.error('地址解析失败:', err); wx.showToast({ title: '地址解析失败,请手动输入', icon: 'none' }); } }); }, fail(err) { console.error('选择目的地位置失败:', err); if (err.errMsg === 'chooseLocation:fail auth deny') { wx.showToast({ title: '需要位置授权才能选择地点', icon: 'none', duration: 2000 }); // 引导用户重新授权 that.requestLocationAuth(); } else { wx.showToast({ title: '选择位置失败', icon: 'none', duration: 2000 }); } } }); }, // 请求位置授权 requestLocationAuth: function () { const that = this; console.log('开始请求位置授权'); wx.showLoading({ title: '请求授权中...', mask: true }); // 检查用户是否已经拒绝过授权 wx.getSetting({ success(res) { wx.hideLoading(); if (res.authSetting['scope.userLocation'] === false) { // 用户已经拒绝过授权,直接引导到设置页面 wx.showModal({ title: '需要位置授权', content: '请在设置中开启位置授权,以便我们为您提供相关服务', showCancel: true, cancelText: '取消', confirmText: '去授权', success: (res) => { if (res.confirm) { // 打开设置页面让用户手动开启授权 wx.openSetting({ success: (settingRes) => { console.log('设置页面返回结果:', settingRes); if (settingRes.authSetting['scope.userLocation']) { // 用户在设置中开启了位置授权 wx.showToast({ title: '授权成功', icon: 'success', duration: 1500 }); } else { // 用户在设置中仍未开启位置授权 wx.showToast({ title: '您已拒绝位置授权', icon: 'none' }); } }, fail: (err) => { console.error('打开设置失败:', err); wx.showToast({ title: '打开设置失败', icon: 'none' }); } }); } } }); } else { // 用户未拒绝过授权,调用 authorize wx.authorize({ scope: 'scope.userLocation', success() { console.log('位置授权成功'); wx.showToast({ title: '授权成功', icon: 'success', duration: 1500 }); }, fail(err) { console.log('位置授权失败:', err); // 授权失败,弹出模态框引导用户重新授权 wx.showModal({ title: '需要位置授权', content: '请在设置中开启位置授权,以便我们为您提供相关服务', showCancel: true, cancelText: '取消', confirmText: '去授权', success: (res) => { if (res.confirm) { // 打开设置页面让用户手动开启授权 wx.openSetting({ success: (settingRes) => { console.log('设置页面返回结果:', settingRes); if (settingRes.authSetting['scope.userLocation']) { // 用户在设置中开启了位置授权 wx.showToast({ title: '授权成功', icon: 'success', duration: 1500 }); } else { // 用户在设置中仍未开启位置授权 wx.showToast({ title: '您已拒绝位置授权', icon: 'none' }); } }, fail: (err) => { console.error('打开设置失败:', err); wx.showToast({ title: '打开设置失败', icon: 'none' }); } }); } } }); } }); } }, fail(err) { wx.hideLoading(); console.error('获取设置失败:', err); wx.showToast({ title: '获取设置失败', icon: 'none' }); } }); }, // 计算运费 calculateFreight: function () { // 验证输入 if (!this.data.origin.province || !this.data.destination.province) { wx.showToast({ title: '请填写完整的出发地和目的地', icon: 'none' }); return; } // 如果没有重量和体积,使用默认值 1 if (!this.data.goodsInfo.weight && !this.data.goodsInfo.volume) { this.setData({ 'goodsInfo.weight': 1 }); } this.setData({ loading: true }); // 构建请求参数 const params = { origin: this.data.origin, destination: this.data.destination, goodsInfo: this.data.goodsInfo, vehicleInfo: this.data.vehicleInfo }; // 调用API计算运费 API.calculateFreight(params).then(res => { this.setData({ loading: false }); if (res.success) { this.setData({ calculationResult: res.data }); // 保存历史记录 this.saveHistoryRecord(res.data); } else { wx.showToast({ title: res.message || '计算失败,请稍后重试', icon: 'none' }); } }).catch(err => { this.setData({ loading: false }); console.error('计算运费失败:', err); wx.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); }); }, // 清空输入 clearInput: function () { this.setData({ origin: { province: '', city: '', district: '', detail: '' }, destination: { province: '', city: '', district: '', detail: '' }, goodsInfo: { weight: '', volume: '', quantity: 1 }, vehicleInfo: { type: '', capacity: '', number: '', driver: '', phone: '' }, selectedVehicleTypeIndex: 0, calculationResult: null }); }, // 使用历史记录 useHistoryRecord: function (e) { const index = e.currentTarget.dataset.index; const record = this.data.historyRecords[index]; this.setData({ origin: record.origin, destination: record.destination, goodsInfo: record.goodsInfo, vehicleInfo: record.vehicleInfo || {}, transportMode: record.transportMode, calculationResult: record.result }); // 恢复车辆类型选择 if (record.vehicleInfo && record.vehicleInfo.type) { const vehicleTypeIndex = this.data.vehicleTypes.indexOf(record.vehicleInfo.type); if (vehicleTypeIndex !== -1) { this.setData({ selectedVehicleTypeIndex: vehicleTypeIndex }); } } }, // 删除历史记录 deleteHistoryRecord: function (e) { const index = e.currentTarget.dataset.index; const history = wx.getStorageSync('freightCalculatorHistory') || []; history.splice(index, 1); wx.setStorageSync('freightCalculatorHistory', history); this.setData({ historyRecords: history.slice(0, 10) }); }, // 清空历史记录 clearHistory: function () { wx.setStorageSync('freightCalculatorHistory', []); this.setData({ historyRecords: [] }); }, // 返回上一页 navigateBack: function () { wx.navigateBack({ delta: 1 }); }, // 拨打电话 makePhoneCall: function (e) { const phone = e.currentTarget.dataset.phone; if (phone) { wx.makePhoneCall({ phoneNumber: phone, success: function () { console.log('拨打电话成功'); }, fail: function (err) { console.error('拨打电话失败:', err); wx.showToast({ title: '拨打电话失败', icon: 'none' }); } }); } }, });