update
This commit is contained in:
parent
018bc7c640
commit
132eb9b063
@ -2,60 +2,62 @@
|
||||
<div class="map-picker-container">
|
||||
<a-form-item :label="label">
|
||||
<div class="region-search-container">
|
||||
<!-- 省市选择器 -->
|
||||
<div class="region-selector">
|
||||
<a-select
|
||||
v-model:value="selectedProvince"
|
||||
placeholder="选择省份"
|
||||
style="width: 48%"
|
||||
@change="handleProvinceChange"
|
||||
:options="provinceOptions"
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
/>
|
||||
<a-select
|
||||
v-model:value="selectedCity"
|
||||
placeholder="选择城市"
|
||||
style="width: 48%"
|
||||
@change="handleCityChange"
|
||||
:options="cityOptions"
|
||||
:disabled="!selectedProvince"
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
/>
|
||||
<div class="search-input-group">
|
||||
<a-input
|
||||
v-model:value="searchAddress"
|
||||
class="map-picker-input"
|
||||
placeholder="请输入详细地址"
|
||||
:loading="searchLoading"
|
||||
@change="handleAddressChange"
|
||||
>
|
||||
<template #suffix>
|
||||
<search-outlined />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-button type="primary" @click="handleSearch(searchAddress)" :loading="searchLoading">
|
||||
搜索
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 详细地址搜索 -->
|
||||
<a-auto-complete
|
||||
v-model:value="searchAddress"
|
||||
:options="searchOptions"
|
||||
placeholder="输入详细地址搜索"
|
||||
@change="handleSearch"
|
||||
@select="handleSelect"
|
||||
:loading="searchLoading"
|
||||
allow-clear
|
||||
class="map-picker-input"
|
||||
<!-- 搜索结果列表 -->
|
||||
<div v-if="searchOptions.length > 0" class="search-results">
|
||||
<div class="search-results-list">
|
||||
<div
|
||||
v-for="(option, index) in searchOptions"
|
||||
:key="index"
|
||||
class="search-result-item"
|
||||
@click="handleSelect(option.value, option)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-tip">地址搜索仅作为辅助填写小区地址的工具</div>
|
||||
|
||||
<div :id="mapContainerId" class="map-container" style="height: 300px;"></div>
|
||||
|
||||
<div class="address-display">
|
||||
<div class="address-label">
|
||||
<span class="required-mark">*</span>小区地址
|
||||
</div>
|
||||
<a-input
|
||||
v-model:value="address"
|
||||
placeholder="请选择小区地址"
|
||||
readonly
|
||||
class="address-input"
|
||||
/>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="地图选点" required>
|
||||
<div class="map-container">
|
||||
<div :id="mapContainerId" style="height: 300px;"></div>
|
||||
|
||||
<div class="form-item-tip">
|
||||
<div>提示: 可直接在地图上点击选择位置,或搜索地址后选择</div>
|
||||
</div>
|
||||
<div class="form-item-tip">在地图上点击选择准确位置,或通过上方搜索框搜索地址</div>
|
||||
|
||||
<!-- 隐藏的输入框,用于表单验证 -->
|
||||
<a-input v-model:value="longitude" style="display: none;" />
|
||||
<a-input v-model:value="latitude" style="display: none;" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="详细地址" required>
|
||||
<a-input v-model:value="address" placeholder="请输入详细地址" />
|
||||
<div class="form-item-tip">地址将用于配送员导航和定位,请确保准确</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 隐藏经纬度输入字段,但保持功能不变 -->
|
||||
<div style="display: none;">
|
||||
<a-input-number v-model:value="longitude" :min="-180" :max="180" disabled />
|
||||
<a-input-number v-model:value="latitude" :min="-90" :max="90" disabled />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -193,73 +195,11 @@ export default {
|
||||
const searchOptions = ref([])
|
||||
const searchLoading = ref(false)
|
||||
|
||||
// 省市选择
|
||||
const provinceOptions = ref(fallbackProvinces)
|
||||
const cityOptions = ref([])
|
||||
const selectedProvince = ref('')
|
||||
const selectedCity = ref('')
|
||||
|
||||
// 双向绑定的值
|
||||
const address = ref(props.modelValue.address)
|
||||
const longitude = ref(props.modelValue.longitude)
|
||||
const latitude = ref(props.modelValue.latitude)
|
||||
|
||||
// 下拉框筛选函数
|
||||
const filterOption = (input, option) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
// 处理省份变化
|
||||
const handleProvinceChange = (value) => {
|
||||
selectedProvince.value = value
|
||||
selectedCity.value = ''
|
||||
|
||||
// 获取城市数据
|
||||
cityOptions.value = fallbackCitiesMap[value] || []
|
||||
|
||||
// 如果有地图实例,尝试定位到选择的省份
|
||||
if (map.value) {
|
||||
try {
|
||||
// 使用地理编码获取省份中心点
|
||||
const geocoder = createGeocoder()
|
||||
geocoder.getLocation(value, (status, result) => {
|
||||
if (status === 'complete' && result.info === 'OK' && result.geocodes.length > 0) {
|
||||
const location = result.geocodes[0].location
|
||||
map.value.setCenter([location.lng, location.lat])
|
||||
map.value.setZoom(8) // 省级层面,缩放级别设置为8
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('设置地图中心点失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理城市变化
|
||||
const handleCityChange = (value) => {
|
||||
selectedCity.value = value
|
||||
|
||||
// 如果有地图实例,定位到选择的城市
|
||||
if (map.value) {
|
||||
try {
|
||||
// 使用地理编码获取城市中心点
|
||||
const geocoder = createGeocoder()
|
||||
geocoder.getLocation(value, (status, result) => {
|
||||
if (status === 'complete' && result.info === 'OK' && result.geocodes.length > 0) {
|
||||
const location = result.geocodes[0].location
|
||||
map.value.setCenter([location.lng, location.lat])
|
||||
map.value.setZoom(12) // 城市级别,缩放级别设置为12
|
||||
|
||||
// 清空搜索框,准备输入详细地址
|
||||
searchAddress.value = ''
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('设置地图中心点失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 监听props变化
|
||||
watch(() => props.modelValue, (newVal, oldVal) => {
|
||||
console.log('props变化:', newVal, oldVal)
|
||||
@ -302,24 +242,13 @@ export default {
|
||||
const city = addressComponent.city
|
||||
|
||||
// 更新省份选择
|
||||
const foundProvince = provinceOptions.value.find(p =>
|
||||
const foundProvince = fallbackProvinces.find(p =>
|
||||
province.includes(p.value) || p.value.includes(province)
|
||||
)
|
||||
|
||||
if (foundProvince) {
|
||||
selectedProvince.value = foundProvince.value
|
||||
|
||||
// 更新城市选择
|
||||
cityOptions.value = fallbackCitiesMap[foundProvince.value] || []
|
||||
|
||||
if (city) {
|
||||
const foundCity = cityOptions.value.find(c =>
|
||||
city.includes(c.value) || c.value.includes(city)
|
||||
)
|
||||
if (foundCity) {
|
||||
selectedCity.value = foundCity.value
|
||||
}
|
||||
}
|
||||
longitude.value = newVal.longitude
|
||||
latitude.value = newVal.latitude
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -349,7 +278,8 @@ export default {
|
||||
emit('update:modelValue', {
|
||||
address: address.value,
|
||||
longitude: longitude.value,
|
||||
latitude: latitude.value
|
||||
latitude: latitude.value,
|
||||
isValid: !!address.value && !!longitude.value && !!latitude.value
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -410,34 +340,21 @@ export default {
|
||||
const city = addressComponent.city
|
||||
|
||||
// 更新省份选择
|
||||
const foundProvince = provinceOptions.value.find(p =>
|
||||
const foundProvince = fallbackProvinces.find(p =>
|
||||
province.includes(p.value) || p.value.includes(province)
|
||||
)
|
||||
|
||||
if (foundProvince) {
|
||||
selectedProvince.value = foundProvince.value
|
||||
|
||||
// 更新城市选择
|
||||
cityOptions.value = fallbackCitiesMap[foundProvince.value] || []
|
||||
|
||||
if (city) {
|
||||
const foundCity = cityOptions.value.find(c =>
|
||||
city.includes(c.value) || c.value.includes(city)
|
||||
)
|
||||
if (foundCity) {
|
||||
selectedCity.value = foundCity.value
|
||||
}
|
||||
}
|
||||
longitude.value = lng
|
||||
latitude.value = lat
|
||||
}
|
||||
}
|
||||
|
||||
updateValue()
|
||||
} else {
|
||||
// 如果获取地址失败,使用经纬度作为地址
|
||||
if (selectedCity.value) {
|
||||
address.value = `${selectedProvince.value} ${selectedCity.value} (${lng.toFixed(6)},${lat.toFixed(6)})`
|
||||
} else if (selectedProvince.value) {
|
||||
address.value = `${selectedProvince.value} (${lng.toFixed(6)},${lat.toFixed(6)})`
|
||||
if (latitude.value) {
|
||||
address.value = `${fallbackProvinces.find(p => p.value === latitude.value.split(' ')[0]).label} (${lng.toFixed(6)},${lat.toFixed(6)})`
|
||||
} else {
|
||||
address.value = `位置坐标: ${lng.toFixed(6)},${lat.toFixed(6)}`
|
||||
}
|
||||
@ -498,25 +415,18 @@ export default {
|
||||
}
|
||||
|
||||
const autoComplete = createAutoComplete({
|
||||
city: selectedCity.value || selectedProvince.value || '全国',
|
||||
citylimit: !!selectedCity.value
|
||||
city: '全国',
|
||||
citylimit: false
|
||||
})
|
||||
|
||||
// 构建搜索关键词,包含省市信息
|
||||
let keyword = value
|
||||
if (selectedCity.value) {
|
||||
keyword = `${selectedCity.value} ${value}`
|
||||
} else if (selectedProvince.value) {
|
||||
keyword = `${selectedProvince.value} ${value}`
|
||||
}
|
||||
|
||||
autoComplete.search(keyword, (status, result) => {
|
||||
autoComplete.search(value, (status, result) => {
|
||||
if (status === 'complete' && result.tips && result.tips.length > 0) {
|
||||
searchOptions.value = result.tips.map(tip => ({
|
||||
value: tip.name,
|
||||
label: `${tip.name} (${tip.district || ''})`,
|
||||
location: tip.location
|
||||
}))
|
||||
console.log('搜索结果:', searchOptions.value)
|
||||
} else {
|
||||
// 如果搜索失败,添加一个手动输入选项
|
||||
searchOptions.value = [{
|
||||
@ -542,22 +452,36 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 地址输入变化
|
||||
const handleAddressChange = (e) => {
|
||||
// 从事件对象中获取值
|
||||
const value = e.target.value
|
||||
|
||||
// 保存输入值
|
||||
searchAddress.value = value
|
||||
|
||||
// 如果清空输入,也清空选项
|
||||
if (!value) {
|
||||
searchOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 选择地址
|
||||
const handleSelect = (value, option) => {
|
||||
// 清空搜索结果
|
||||
searchOptions.value = []
|
||||
|
||||
// 直接使用选中的值作为地址
|
||||
address.value = value
|
||||
|
||||
// 查找选中的地址信息
|
||||
const selected = searchOptions.value.find(opt => opt.value === value)
|
||||
|
||||
// 如果是手动输入的地址,或者没有位置信息
|
||||
if (!selected || selected.manualInput || !selected.location) {
|
||||
if (!option || option.manualInput || !option.location) {
|
||||
message.info('请在地图上选择具体位置')
|
||||
updateValue()
|
||||
return
|
||||
}
|
||||
|
||||
const { lng, lat } = selected.location
|
||||
const { lng, lat } = option.location
|
||||
|
||||
// 更新标记位置
|
||||
updateMarkerPosition(lng, lat)
|
||||
@ -582,24 +506,13 @@ export default {
|
||||
const city = addressComponent.city
|
||||
|
||||
// 更新省份选择
|
||||
const foundProvince = provinceOptions.value.find(p =>
|
||||
const foundProvince = fallbackProvinces.find(p =>
|
||||
province.includes(p.value) || p.value.includes(province)
|
||||
)
|
||||
|
||||
if (foundProvince) {
|
||||
selectedProvince.value = foundProvince.value
|
||||
|
||||
// 更新城市选择
|
||||
cityOptions.value = fallbackCitiesMap[foundProvince.value] || []
|
||||
|
||||
if (city) {
|
||||
const foundCity = cityOptions.value.find(c =>
|
||||
city.includes(c.value) || c.value.includes(city)
|
||||
)
|
||||
if (foundCity) {
|
||||
selectedCity.value = foundCity.value
|
||||
}
|
||||
}
|
||||
longitude.value = lng
|
||||
latitude.value = lat
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -630,14 +543,7 @@ export default {
|
||||
latitude,
|
||||
handleSearch,
|
||||
handleSelect,
|
||||
// 省市选择相关
|
||||
provinceOptions,
|
||||
cityOptions,
|
||||
selectedProvince,
|
||||
selectedCity,
|
||||
handleProvinceChange,
|
||||
handleCityChange,
|
||||
filterOption
|
||||
handleAddressChange
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -653,18 +559,69 @@ export default {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.region-selector {
|
||||
.search-input-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
align-items: stretch;
|
||||
height: 32px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.map-picker-input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.search-tip {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 8px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1001;
|
||||
background: white;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.search-results-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-result-item {
|
||||
cursor: pointer;
|
||||
padding: 10px 12px;
|
||||
transition: background-color 0.3s;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
line-height: 1.5;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.search-result-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.search-result-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.map-container {
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
@ -674,6 +631,37 @@ export default {
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.address-display {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.address-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
.required-mark {
|
||||
color: #ff4d4f;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.address-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.address-input .ant-input) {
|
||||
background-color: #f5f5f5;
|
||||
cursor: default;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.address-input .ant-input:hover),
|
||||
:deep(.address-input .ant-input:focus) {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.form-item-tip {
|
||||
margin-top: 8px;
|
||||
font-size: 0.8em;
|
||||
@ -693,7 +681,38 @@ export default {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper),
|
||||
:deep(.ant-btn) {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper) {
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: white;
|
||||
border: 1px solid #d9d9d9;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper:hover) {
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper-focused) {
|
||||
border-color: #40a9ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
|
||||
:deep(.ant-btn) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
:deep(.ant-input) {
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user