搜索地址完备版
This commit is contained in:
parent
5f0f22e62a
commit
5638873295
|
|
@ -1107,16 +1107,12 @@
|
|||
},
|
||||
|
||||
cleanRecognizedDetail(detail, province, city, district, town) {
|
||||
let text = (detail || '').trim()
|
||||
|
||||
const parts = [province, city, district, town]
|
||||
.filter(Boolean)
|
||||
.map(item => this.escapeRegExp(item))
|
||||
|
||||
if (parts.length) {
|
||||
const reg = new RegExp(`^(${parts.join('|')})+`)
|
||||
text = text.replace(reg, '')
|
||||
}
|
||||
let text = this.stripLeadingRegionParts(detail, [
|
||||
province,
|
||||
city,
|
||||
district,
|
||||
town
|
||||
])
|
||||
|
||||
text = text
|
||||
.replace(/(收货人|联系人|姓名)[::].*$/g, '')
|
||||
|
|
@ -1152,24 +1148,20 @@
|
|||
''
|
||||
).trim()
|
||||
|
||||
// 接口已经给了明确详细地址,就直接用,不再清洗、不再删镇街
|
||||
// 接口已经给了明确详细地址,就直接返回
|
||||
if (directDetail) {
|
||||
return directDetail
|
||||
}
|
||||
|
||||
// 接口没单独给详细地址时,再从原始识别文本里扣掉省市区,保留后面的完整内容
|
||||
let text = (sanitizedText || '').trim()
|
||||
const prefix = [
|
||||
// 接口没给详细地址时,再从原始文本里扣掉省市区
|
||||
return this.stripLeadingRegionParts(
|
||||
sanitizedText,
|
||||
[
|
||||
province || '',
|
||||
city && city !== province ? city : '',
|
||||
district || ''
|
||||
].join('')
|
||||
|
||||
if (prefix && text.startsWith(prefix)) {
|
||||
text = text.slice(prefix.length).trim()
|
||||
}
|
||||
|
||||
return text
|
||||
]
|
||||
)
|
||||
},
|
||||
|
||||
getRecognizeLevel(hit, detailText, rawText) {
|
||||
|
|
@ -1209,7 +1201,6 @@
|
|||
const hasLongLetterChunk = /[A-Za-z]{2,}/.test(input)
|
||||
const hasInvalidNoise = this.containsObviousInvalidNoise(input)
|
||||
|
||||
// 像“付i啊不符合可不vi了哈女本办法本办法v就看不上”这种,
|
||||
// 既不像正常地址,又夹杂明显乱码/字母串,同时还没有有效详细地址时,只提示不回填
|
||||
if (!hasAddressFeature && !hasRegionKeyword && !detailText) {
|
||||
if (hasLongLetterChunk || hasInvalidNoise || detailRejected) {
|
||||
|
|
@ -1467,6 +1458,33 @@
|
|||
})
|
||||
},
|
||||
|
||||
stripLeadingRegionParts(text, parts = []) {
|
||||
let result = String(text || '').trim()
|
||||
const validParts = parts
|
||||
.map(item => String(item || '').trim())
|
||||
.filter(Boolean)
|
||||
|
||||
if (!result || !validParts.length) return result
|
||||
|
||||
let changed = true
|
||||
|
||||
while (changed && result) {
|
||||
changed = false
|
||||
result = result.replace(/^\s+/, '')
|
||||
|
||||
for (const part of validParts) {
|
||||
const reg = new RegExp(`^${this.escapeRegExp(part)}(?:\\s+|\\b)?`)
|
||||
if (reg.test(result)) {
|
||||
result = result.replace(reg, '').trim()
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
async onSmartRecognize() {
|
||||
this.clearBlankPageInitLock()
|
||||
this.userSelectedRegion = false
|
||||
|
|
@ -1580,21 +1598,6 @@
|
|||
detailRejected = !detailDecision.valid && !!detailCandidate
|
||||
detailText = detailDecision.valid ? detailDecision.cleaned : ''
|
||||
|
||||
// ====== 回填到页面下方的位置 ======
|
||||
this.currentProvince = province
|
||||
this.currentCity = city
|
||||
this.currentDistrict = district
|
||||
this.currentRegion = regionText
|
||||
|
||||
this.selectedProvinceCode = hit.province_code || ''
|
||||
this.selectedCityCode = hit.city_code || ''
|
||||
this.selectedDistrictCode = hit.county_code || ''
|
||||
|
||||
this.detailAddress = detailText
|
||||
this.manualDetail = detailText
|
||||
this.currentDetail = detailText
|
||||
this.isManualDetail = !!detailText
|
||||
// =================================
|
||||
|
||||
// 如果详细地址被判定为无效,则退回到仅用省市区定位,避免把脏文本带进详情页
|
||||
if (!detailText) {
|
||||
|
|
@ -1645,6 +1648,58 @@
|
|||
|
||||
const level = this.getRecognizeLevel(hit, detailText, sanitizedText)
|
||||
|
||||
const shouldOnlyToast = this.shouldOnlyToastForGarbageRecognize(
|
||||
sanitizedText,
|
||||
hit,
|
||||
detailText,
|
||||
detailRejected
|
||||
)
|
||||
|
||||
// 低可信度,或者明显像乱码/乱写文本时:只提示,不回填
|
||||
if (level === 'low' || shouldOnlyToast) {
|
||||
uni.hideLoading()
|
||||
|
||||
if (shouldOnlyToast) {
|
||||
uni.showModal({
|
||||
title: '未识别到有效地址',
|
||||
content: '当前输入内容更像无效文本,系统未自动填入所在地区和详细地址,请检查后重新输入,或手动选择地址。',
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
const tip = this.getRecognizeToast(level, removedNoise, geocodeOk, hit, detailText, detailRejected)
|
||||
if (tip.type === 'modal') {
|
||||
uni.showModal({
|
||||
title: tip.title,
|
||||
content: tip.content,
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: tip.title,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ====== 回填到页面下方的位置 ======
|
||||
this.currentProvince = province
|
||||
this.currentCity = city
|
||||
this.currentDistrict = district
|
||||
this.currentRegion = regionText
|
||||
|
||||
this.selectedProvinceCode = hit.province_code || ''
|
||||
this.selectedCityCode = hit.city_code || ''
|
||||
this.selectedDistrictCode = hit.county_code || ''
|
||||
|
||||
this.detailAddress = detailText
|
||||
this.manualDetail = detailText
|
||||
this.currentDetail = detailText
|
||||
this.isManualDetail = !!detailText
|
||||
// =================================
|
||||
|
||||
this.smartBtnText = '已识别'
|
||||
uni.hideLoading()
|
||||
|
||||
|
|
|
|||
|
|
@ -914,48 +914,140 @@
|
|||
this.hideLocationPopup();
|
||||
},
|
||||
|
||||
// 获取详细地址(原有)
|
||||
buildRegionTextForSearch() {
|
||||
const dependency = String(this.displayData.dependency || '').trim();
|
||||
if (!dependency) return '';
|
||||
|
||||
const parts = dependency.split('-');
|
||||
const province = parts[0] || '';
|
||||
const city = parts[1] || '';
|
||||
const district = parts[2] || '';
|
||||
|
||||
let regionText = '';
|
||||
if (province) regionText += province;
|
||||
if (city && city !== province) regionText += city;
|
||||
if (district) regionText += district;
|
||||
|
||||
return regionText;
|
||||
},
|
||||
|
||||
getAddressValueForSearch() {
|
||||
const rawAddress = String(this.displayData.address || '').trim();
|
||||
if (!rawAddress) return '';
|
||||
|
||||
const dependencyText = String(this.displayData.dependency || '').trim();
|
||||
const regionText = this.buildRegionTextForSearch();
|
||||
|
||||
let detail = rawAddress;
|
||||
|
||||
// 兼容“完整地址被存进address字段”的情况,进入搜索页时只传详细地址
|
||||
if (regionText && detail.indexOf(regionText) === 0) {
|
||||
detail = detail.slice(regionText.length).trim();
|
||||
} else if (dependencyText && detail.indexOf(dependencyText) === 0) {
|
||||
detail = detail.slice(dependencyText.length).trim();
|
||||
}
|
||||
|
||||
detail = detail.replace(/^[\s,-]+/, '').trim();
|
||||
|
||||
return detail || rawAddress;
|
||||
},
|
||||
|
||||
async getAddressInfo() {
|
||||
if (!this.editable) return;
|
||||
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const isIOS = systemInfo.platform === 'ios';
|
||||
|
||||
const hasDependency = !!String(this.displayData.dependency || '').trim();
|
||||
const hasAddress = !!String(this.getAddressValueForSearch() || '').trim();
|
||||
const hasLocation = !!(this.displayData.longitude && this.displayData.latitude);
|
||||
const hasExistingAddressData = hasDependency || hasAddress || hasLocation;
|
||||
|
||||
// iOS不走你这套权限工具的二次弹窗逻辑,直接进搜索页
|
||||
// 如果当前没有任何地址信息,则让搜索页自己只尝试一次定位
|
||||
if (isIOS) {
|
||||
this._navigateToAddress();
|
||||
} else {
|
||||
this.isShowLocationPer = true;
|
||||
const { granted } = await permissionUtils.checkPermission('location', '需要定位权限以获取您的位置');
|
||||
if (granted) {
|
||||
this.isShowLocationPer = false;
|
||||
this._navigateToAddress();
|
||||
this._navigateToAddress({
|
||||
canInitCurrentLocation: !hasExistingAddressData
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 已有所在地/详细地址/经纬度时,直接带现有值进入,不再额外申请定位
|
||||
if (hasExistingAddressData) {
|
||||
this._navigateToAddress({
|
||||
canInitCurrentLocation: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 只有完全空白进入时,才申请一次定位权限
|
||||
this.isShowLocationPer = true;
|
||||
|
||||
let granted = false;
|
||||
|
||||
try {
|
||||
const checkRes = await permissionUtils.checkPermission('location', '需要定位权限以获取您的位置');
|
||||
granted = typeof checkRes === 'boolean' ? checkRes : !!(checkRes && checkRes.granted);
|
||||
|
||||
if (!granted) {
|
||||
const requestRes = await permissionUtils.requestPermission('location', '需要定位权限以获取您的位置');
|
||||
granted = typeof requestRes === 'boolean' ? requestRes : !!(requestRes && requestRes.granted);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('定位权限申请流程异常:', error);
|
||||
granted = false;
|
||||
}
|
||||
|
||||
this.isShowLocationPer = false;
|
||||
const confirm = await this.showPermissionDialog('定位权限申请', '我们需要访问您的位置权限,以便为您选择更精准的地址');
|
||||
if (!confirm) return;
|
||||
const result = await permissionUtils.requestPermission('location', '需要定位权限以获取您的位置');
|
||||
if (result) {
|
||||
this._navigateToAddress();
|
||||
} else {
|
||||
locationService.openAppSettings();
|
||||
}
|
||||
}
|
||||
|
||||
// 不管用户同不同意,都进入搜索地址页
|
||||
// 同意:按当前位置初始化
|
||||
// 不同意/没给权限:进入页面但不自动精确定位
|
||||
this._navigateToAddress({
|
||||
canInitCurrentLocation: granted
|
||||
});
|
||||
},
|
||||
|
||||
_navigateToAddress() {
|
||||
_navigateToAddress({ canInitCurrentLocation = false } = {}) {
|
||||
let params = 'source=sj_info';
|
||||
if (this.displayData.dependency) {
|
||||
const locationStr = encodeURIComponent(this.displayData.dependency);
|
||||
params += `&dependency=${locationStr}`;
|
||||
if (this.displayData.dependency_code) {
|
||||
params += `&dependency_code=${this.displayData.dependency_code}`;
|
||||
|
||||
const dependency = String(this.displayData.dependency || '').trim();
|
||||
const dependencyCode = String(this.displayData.dependency_code || '').trim();
|
||||
const address = this.getAddressValueForSearch();
|
||||
const longitude = this.displayData.longitude;
|
||||
const latitude = this.displayData.latitude;
|
||||
|
||||
const hasDependency = !!dependency;
|
||||
const hasAddress = !!address;
|
||||
const hasLocation = !!(longitude && latitude);
|
||||
|
||||
if (hasDependency) {
|
||||
params += `&dependency=${encodeURIComponent(dependency)}`;
|
||||
if (dependencyCode) {
|
||||
params += `&dependency_code=${dependencyCode}`;
|
||||
}
|
||||
}
|
||||
if (this.displayData.longitude && this.displayData.latitude) {
|
||||
params += `&longitude=${this.displayData.longitude}&latitude=${this.displayData.latitude}`;
|
||||
|
||||
// 关键修复:把详细地址带过去,搜索页才能回填
|
||||
if (hasAddress) {
|
||||
params += `&address=${encodeURIComponent(address)}`;
|
||||
}
|
||||
|
||||
if (hasLocation) {
|
||||
params += `&longitude=${longitude}&latitude=${latitude}`;
|
||||
}
|
||||
|
||||
// 当前门店信息页没有任何已知地址数据时,再决定搜索页是否初始化当前位置
|
||||
if (!hasDependency && !hasAddress && !hasLocation) {
|
||||
if (canInitCurrentLocation) {
|
||||
params += '&init_current_location=1&silent_locate=1';
|
||||
} else {
|
||||
params += '&skip_auto_locate=1';
|
||||
}
|
||||
}
|
||||
|
||||
this.fromAddressPage = true;
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/address/search?${params}`,
|
||||
success: () => console.log('成功跳转到地址选择页面'),
|
||||
|
|
@ -965,16 +1057,34 @@
|
|||
|
||||
handleAddressSelected(addressData) {
|
||||
if (!addressData) return;
|
||||
let address = '';
|
||||
if (addressData.name) {
|
||||
address = addressData.name;
|
||||
} else if (addressData.address) {
|
||||
address = addressData.address;
|
||||
}
|
||||
if (!address) return;
|
||||
|
||||
this.displayData.address = address;
|
||||
this.pendingData.address = address;
|
||||
// 详细地址只取 address,不再优先取 name
|
||||
let detailAddress = '';
|
||||
if (addressData.address) {
|
||||
detailAddress = String(addressData.address).trim();
|
||||
} else if (addressData.name) {
|
||||
// 兜底:老数据里如果只有name,就尝试去掉前面的省市区
|
||||
detailAddress = String(addressData.name).trim();
|
||||
|
||||
const regionParts = [];
|
||||
if (addressData.pname) regionParts.push(addressData.pname);
|
||||
if (addressData.cityname && addressData.cityname !== addressData.pname) regionParts.push(addressData.cityname);
|
||||
if (addressData.adname) regionParts.push(addressData.adname);
|
||||
|
||||
const regionText = regionParts.join('');
|
||||
const regionTextWithDash = regionParts.join('-');
|
||||
|
||||
if (regionText && detailAddress.indexOf(regionText) === 0) {
|
||||
detailAddress = detailAddress.slice(regionText.length).trim();
|
||||
} else if (regionTextWithDash && detailAddress.indexOf(regionTextWithDash) === 0) {
|
||||
detailAddress = detailAddress.slice(regionTextWithDash.length).trim();
|
||||
}
|
||||
|
||||
detailAddress = detailAddress.replace(/^[\s,-]+/, '').trim();
|
||||
}
|
||||
|
||||
this.displayData.address = detailAddress;
|
||||
this.pendingData.address = detailAddress;
|
||||
|
||||
if (addressData.location) {
|
||||
const [longitude, latitude] = addressData.location.split(',');
|
||||
|
|
@ -989,8 +1099,20 @@
|
|||
if (addressData.pname) locationParts.push(addressData.pname);
|
||||
if (addressData.cityname) locationParts.push(addressData.cityname);
|
||||
if (addressData.adname) locationParts.push(addressData.adname);
|
||||
this.displayData.dependency = locationParts.join('-');
|
||||
this.pendingData.dependency = locationParts.join('-');
|
||||
|
||||
const dependency = locationParts.join('-');
|
||||
this.displayData.dependency = dependency;
|
||||
this.pendingData.dependency = dependency;
|
||||
}
|
||||
|
||||
if (addressData.provinceCode || addressData.cityCode || addressData.districtCode) {
|
||||
this.displayData.dependency_province = addressData.provinceCode || '';
|
||||
this.displayData.dependency_city = addressData.cityCode || '';
|
||||
this.displayData.dependency_code = addressData.districtCode || '';
|
||||
|
||||
this.pendingData.dependency_province = addressData.provinceCode || '';
|
||||
this.pendingData.dependency_city = addressData.cityCode || '';
|
||||
this.pendingData.dependency_code = addressData.districtCode || '';
|
||||
}
|
||||
|
||||
console.log('地址更新完成:', {
|
||||
|
|
@ -1178,10 +1300,9 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
/* 调整表单项为 flex 布局,左侧固定宽度,右侧自适应 */
|
||||
.form-item-two {
|
||||
display: flex;
|
||||
align-items: flex-start; /* 顶部对齐,适应多行文本 */
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
|
@ -1205,12 +1326,11 @@
|
|||
color: #999999;
|
||||
}
|
||||
|
||||
/* 右侧内容区域:占据剩余空间,内部使用 flex 行内布局 */
|
||||
.picker-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
justify-content: center;
|
||||
gap: 16rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
|
@ -1229,7 +1349,7 @@
|
|||
width: 14rpx;
|
||||
height: 26rpx;
|
||||
flex-shrink: 0;
|
||||
margin-left: 16rpx;
|
||||
/* margin-left: 16rpx; */
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
|
|
|
|||
Loading…
Reference in New Issue