Laravel裁切公司下单选包装公司后联动地址获取与配送选择
功能实现落地步骤
1. 调整后端数据查询逻辑
原来的控制器加载包装公司数据时,不需要把全表字段都取出来,只保留前端需要的基础字段+地址关联字段,减少资源冗余:
public function createCutting() { // 仅查询需要的字段,关联取出包装公司对接人的名称 $packaging_company = PackagingCompany::select('id', 'address', 'lat', 'lng') ->with('staffs:id,name') ->get(); return view('web.cutting.working_orders.create', compact('packaging_company')); }
2. 调整前端下拉框的附属数据传递
(1)改造包装公司选择下拉框
给每个<option>标签加自定义属性,把对应公司的地址、经纬度存在标签上,减少后续冗余Ajax请求:
<div class="form-group col-lg-6" id="packaging_company"> <label style="color: #44484d;">Select Packaging Company <span class="text-danger">*</span></label> <select class="form-control kt-selectpicker" required data-live-search="true" name="packaging_company"> @foreach ($packaging_company as $company) <option value="{{ $company->id }}" data-address="{{ $company->address }}" data-lat="{{ $company->lat }}" data-lng="{{ $company->lng }}" > {{ $company->staffs->name }} </option> @endforeach </select> <span class="text-danger p-1">{{ $errors->first('packaging_company') }}</span> </div>
(2)改造配送目的地选择下拉框,新增联动区块
给下拉框加id方便事件监听,同时补充两个不同场景的地址展示/输入区块,默认隐藏,匹配对应条件再展示:
<div class="form-group col-lg-6"> <label style="color: #44484d;">Fruit delivery destination <span class="text-danger">*</span></label> <select class="form-control kt-selectpicker" data-live-search="true" name="fruit_delivery_location" id="delivery_type"> <option value="company"> Packaging Company Location </option> <option value="custom"> Other </option> </select> <span class="text-danger p-1">{{ $errors->first('fruit_delivery_location') }}</span> </div> <!-- 区块1:选中“包装公司地址”时展示,只读展示公司获取到的地址 --> <div class="form-group col-lg-12 d-none" id="company_address_block"> <label style="color: #44484d;">Packaging Company Address</label> <input type="text" class="form-control" name="company_delivery_address" id="company_address_input" readonly> </div> <!-- 区块2:选中“其他地址”时展示,支持手动输入+谷歌地图选点 --> <div class="form-group col-lg-12 d-none" id="custom_address_block"> <label style="color: #44484d;">Custom Delivery Address</label> <input type="text" class="form-control" name="custom_delivery_address" id="custom_address_input" placeholder="Search or select on map below"> <div id="google_map_container" style="height: 300px; width: 100%; margin-top: 10px;"></div> <!-- 隐藏域存储地图选点的经纬度,提交后端使用 --> <input type="hidden" name="custom_delivery_lat" id="custom_lat"> <input type="hidden" name="custom_delivery_lng" id="custom_lng"> </div>
3. 编写前端联动交互逻辑
// 全局缓存当前选中的包装公司地址数据 let selectedCompanyData = { address: '', lat: '', lng: '' } // 监听包装公司下拉选择事件 $('select[name="packaging_company"]').on('change', function() { const selectedOption = $(this).find('option:selected'); // 从option的自定义属性中取出公司地址、经纬度 selectedCompanyData = { address: selectedOption.data('address'), lat: selectedOption.data('lat'), lng: selectedOption.data('lng') } // 触发一次配送目的地的选择事件,自动匹配显示对应地址区块 $('#delivery_type').trigger('change') }) // 监听配送目的地下拉选择事件 $('#delivery_type').on('change', function() { const selectedType = $(this).val() // 先隐藏所有地址区块 $('#company_address_block').addClass('d-none') $('#custom_address_block').addClass('d-none') if (selectedType === 'company') { // 选择使用包装公司地址的场景校验 if (!selectedCompanyData.address) { alert('Please select a packaging company first') $(this).val('') return } // 展示公司地址区块,填充缓存的地址信息 $('#company_address_block').removeClass('d-none') $('#company_address_input').val(selectedCompanyData.address) } else if (selectedType === 'custom') { // 选择自定义地址的场景:展示自定义区块,初始化谷歌地图 $('#custom_address_block').removeClass('d-none') initGoogleMap() } }) // 谷歌地图选点核心逻辑 let map, marker; function initGoogleMap() { // 地图初始中心点:优先用已选包装公司的坐标,无则用默认城市坐标 const centerPoint = selectedCompanyData.lat ? {lat: parseFloat(selectedCompanyData.lat), lng: parseFloat(selectedCompanyData.lng)} : {lat: 0, lng: 0} // 替换为业务覆盖的默认城市坐标 map = new google.maps.Map(document.getElementById('google_map_container'), { zoom: 15, center: centerPoint }) marker = new google.maps.Marker({ position: centerPoint, map: map, draggable: true // 支持拖拽Marker选点 }) // Marker拖拽结束后自动反查对应地址,填充表单字段 google.maps.event.addListener(marker, 'dragend', function(event) { updateAddressByLatLng(event.latLng.lat(), event.latLng.lng()) }) // 给自定义地址输入框绑定谷歌地址搜索自动补全 const searchBox = new google.maps.places.SearchBox(document.getElementById('custom_address_input')) map.addListener('bounds_changed', function() { searchBox.setBounds(map.getBounds()) }) searchBox.addListener('places_changed', function() { const places = searchBox.getPlaces() if (places.length == 0) return const place = places[0] // 搜索选中地址后,自动更新地图位置和Marker map.setCenter(place.geometry.location) marker.setPosition(place.geometry.location) // 填充地址和经纬度到表单字段 $('#custom_address_input').val(place.formatted_address) $('#custom_lat').val(place.geometry.location.lat()) $('#custom_lng').val(place.geometry.location.lng()) }) } // 通过经纬度反查格式化地址 function updateAddressByLatLng(lat, lng) { const geocoder = new google.maps.Geocoder() geocoder.geocode({location: {lat: lat, lng: lng}}, function(results) { if (results[0]) { $('#custom_address_input').val(results[0].formatted_address) } $('#custom_lat').val(lat) $('#custom_lng').val(lng) }) }
4. 落地注意事项
- 针对kt-selectpicker组件:事件绑定要等组件初始化完成后再执行,避免因组件重绘DOM导致事件监听失效。
- 针对表单提交:提交前需要根据选中的配送目的地类型,校验对应区块的字段完整性——选公司地址时不用校验自定义字段,选自定义地址时需确认经纬度是否获取成功。
- 针对大数据量场景:如果包装公司总数超过100家,不建议将地址存在option的自定义属性中,可改为选中公司后发送Ajax请求获取对应地址,避免页面加载性能下降。
内容的提问来源于stack exchange,提问作者Saad Ramay
相关产品推荐
相关产品推荐

