地址bug
This commit is contained in:
parent
7f432b6bf6
commit
48cc4f66a9
|
|
@ -140,6 +140,7 @@
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
useApiRawRecognize: false, // API直出:true
|
||||||
mapVisible: true,
|
mapVisible: true,
|
||||||
showMapSnapshot: false,
|
showMapSnapshot: false,
|
||||||
mapSnapshotUrl: '',
|
mapSnapshotUrl: '',
|
||||||
|
|
@ -394,6 +395,64 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
// 直辖市处理
|
||||||
|
normalizeMunicipalityName(name) {
|
||||||
|
const value = String(name || '').trim()
|
||||||
|
|
||||||
|
const map = {
|
||||||
|
'北京': '北京市',
|
||||||
|
'北京市': '北京市',
|
||||||
|
'上海': '上海市',
|
||||||
|
'上海市': '上海市',
|
||||||
|
'天津': '天津市',
|
||||||
|
'天津市': '天津市',
|
||||||
|
'重庆': '重庆市',
|
||||||
|
'重庆市': '重庆市',
|
||||||
|
'香港': '香港特别行政区',
|
||||||
|
'香港特别行政区': '香港特别行政区',
|
||||||
|
'澳门': '澳门特别行政区',
|
||||||
|
'澳门特别行政区': '澳门特别行政区'
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[value] || value
|
||||||
|
},
|
||||||
|
|
||||||
|
normalizeRecognizedRegionParts(province, city, district) {
|
||||||
|
let p = this.normalizeMunicipalityName(province)
|
||||||
|
let c = this.normalizeMunicipalityName(city)
|
||||||
|
const d = String(district || '').trim()
|
||||||
|
|
||||||
|
const municipalities = [
|
||||||
|
'北京市',
|
||||||
|
'上海市',
|
||||||
|
'天津市',
|
||||||
|
'重庆市',
|
||||||
|
'香港特别行政区',
|
||||||
|
'澳门特别行政区'
|
||||||
|
]
|
||||||
|
|
||||||
|
if (!p && municipalities.includes(c)) {
|
||||||
|
p = c
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c && municipalities.includes(p)) {
|
||||||
|
c = p
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
province: p,
|
||||||
|
city: c,
|
||||||
|
district: d
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
buildRegionText(province, city, district) {
|
||||||
|
let text = ''
|
||||||
|
if (province) text += province
|
||||||
|
if (city && city !== province) text += city
|
||||||
|
if (district) text += district
|
||||||
|
return text
|
||||||
|
},
|
||||||
|
|
||||||
startDependencyInitLock(duration = 800) {
|
startDependencyInitLock(duration = 800) {
|
||||||
this.dependencyInitLock = true
|
this.dependencyInitLock = true
|
||||||
|
|
@ -1036,28 +1095,46 @@
|
||||||
const value = String(text || '').trim()
|
const value = String(text || '').trim()
|
||||||
if (!value) return true
|
if (!value) return true
|
||||||
|
|
||||||
// 1. 检查是否包含常见的地址特征词
|
// 明显无效词
|
||||||
const addressKeywords = [
|
if (/(价格|价钱|多少钱|举报|投诉|建议|咨询|测试|示例|比如|比方|假设|无效|乱填)/i.test(value)) {
|
||||||
'路', '街', '巷', '道', '号', '栋', '幢', '楼', '层', '室', '单元',
|
return true
|
||||||
'门', '里', '弄', '小区', '花园', '广场', '大厦', '中心', '苑', '园',
|
}
|
||||||
'村', '镇', '乡', '街', '大道', '胡同', '巷子', '店', '场', '城'
|
|
||||||
]
|
|
||||||
const hasKeyword = addressKeywords.some(kw => value.includes(kw))
|
|
||||||
// 2. 检查是否有中文 + 数字/字母的乱码模式(例如“165160ugf8oe”)
|
|
||||||
const hasChinese = /[\u4e00-\u9fa5]/.test(value)
|
|
||||||
const hasDigitOrLetter = /[a-zA-Z0-9]/.test(value)
|
|
||||||
const isLikelyGarbage = hasChinese && hasDigitOrLetter && !hasKeyword
|
|
||||||
|
|
||||||
// 3. 检查纯英文长串
|
// 纯数字或纯字母长串
|
||||||
const longPureLetters = /\b[A-Za-z]{4,}\b/.test(value) && !/[A-Za-z]\d|\d[A-Za-z]/.test(value)
|
if (/^\d{6,}$/.test(value) || /^[A-Za-z]{6,}$/.test(value)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 4. 检查明显的无效词(原有逻辑)
|
// 特殊符号过多
|
||||||
const hasInvalidNoise = /(价格|价钱|多少钱|举报|投诉|建议|咨询|测试|示例|比如|比方|假设|无效|乱填)/i.test(value)
|
const specialChars = (value.match(/[^\u4e00-\u9fa5a-zA-Z0-9]/g) || []).length
|
||||||
|
if (specialChars / value.length > 0.3) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
if (hasInvalidNoise && !hasKeyword && !hasDigitOrLetter) return true
|
// 长度过短
|
||||||
if (longPureLetters && !hasKeyword && !hasDigitOrLetter) return true
|
if (value.length < 2) {
|
||||||
if (isLikelyGarbage) return true
|
return true
|
||||||
if (!hasChinese && !hasDigitOrLetter && !hasKeyword) return true
|
}
|
||||||
|
|
||||||
|
// 新增:长英文乱码片段
|
||||||
|
const hasLongLetterChunk = /[A-Za-z]{6,}/.test(value)
|
||||||
|
|
||||||
|
// 新增:英文字母占比过高
|
||||||
|
const letterCount = (value.match(/[A-Za-z]/g) || []).length
|
||||||
|
const letterRatio = value.length ? (letterCount / value.length) : 0
|
||||||
|
|
||||||
|
// 是否包含正常地址特征
|
||||||
|
const hasAddressFeature = this.hasStrongAddressFeature(value)
|
||||||
|
|
||||||
|
// 既有长英文串,又没有门牌/楼栋/道路等地址特征,判为无效
|
||||||
|
if (hasLongLetterChunk && !hasAddressFeature) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 英文占比过高,且没有地址特征,也判为无效
|
||||||
|
if (letterRatio > 0.35 && !hasAddressFeature) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
|
@ -1076,31 +1153,32 @@
|
||||||
|
|
||||||
validateRecognizedDetail(detailText, geo, requireKeyword = true) {
|
validateRecognizedDetail(detailText, geo, requireKeyword = true) {
|
||||||
const cleaned = String(detailText || '').trim()
|
const cleaned = String(detailText || '').trim()
|
||||||
|
|
||||||
if (!cleaned) {
|
if (!cleaned) {
|
||||||
return { valid: false, cleaned: '', reason: 'empty' }
|
return { valid: false, cleaned: '', reason: 'empty' }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 要求必须包含地址特征词(除非地理编码级别极高)
|
// 先做详细地址本身的有效性判断
|
||||||
const hasKeyword = /(路|街|巷|道|号|栋|幢|楼|层|室|单元|门|里|弄|小区|花园|广场|大厦|中心|苑|园|村|镇|乡)/.test(cleaned)
|
|
||||||
if (requireKeyword && !hasKeyword) {
|
|
||||||
return { valid: false, cleaned: '', reason: 'no_address_keyword' }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isLikelyInvalidRecognizedDetail(cleaned)) {
|
if (this.isLikelyInvalidRecognizedDetail(cleaned)) {
|
||||||
return { valid: false, cleaned: '', reason: 'invalid_text' }
|
return { valid: false, cleaned: '', reason: 'invalid_detail' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 有些地址虽然没有“号栋室”,但高德返回到了较精确层级,也可以放行
|
||||||
|
const geoLevel = String(geo?.level || '').trim()
|
||||||
|
const preciseLevel = this.isPreciseGeocodeLevel(geoLevel)
|
||||||
|
const hasAddressFeature = this.hasStrongAddressFeature(cleaned)
|
||||||
|
|
||||||
|
// 没有地理编码结果,直接无效
|
||||||
if (!geo) {
|
if (!geo) {
|
||||||
return { valid: false, cleaned: '', reason: 'geocode_failed' }
|
return { valid: false, cleaned: '', reason: 'geocode_failed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 允许低精度级别但带关键词的地址(比如“某某村”)
|
// 需要至少满足一项:有明确地址特征,或高德定位层级较精确
|
||||||
if (!this.isPreciseGeocodeLevel(geo.level) && !hasKeyword) {
|
if (hasAddressFeature || preciseLevel) {
|
||||||
return { valid: false, cleaned: '', reason: 'low_precision' }
|
return { valid: true, cleaned, reason: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
return { valid: true, cleaned, reason: '' }
|
// 否则认为地区虽然能定位,但详细地址本身不够可信
|
||||||
|
return { valid: false, cleaned: '', reason: 'detail_not_precise' }
|
||||||
},
|
},
|
||||||
|
|
||||||
cleanRecognizedDetail(detail, province, city, district, town) {
|
cleanRecognizedDetail(detail, province, city, district, town) {
|
||||||
|
|
@ -1136,29 +1214,23 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
buildExactRecognizedDetail(hit, sanitizedText, province, city, district) {
|
buildExactRecognizedDetail(hit, sanitizedText, province, city, district) {
|
||||||
const directDetail = (
|
const directDetail = (hit?.detail || hit?.address || hit?.addr || hit?.full_address_detail || hit?.address_detail || '').trim();
|
||||||
hit?.detail ||
|
|
||||||
hit?.address ||
|
|
||||||
hit?.addr ||
|
|
||||||
hit?.full_address_detail ||
|
|
||||||
hit?.address_detail ||
|
|
||||||
''
|
|
||||||
).trim()
|
|
||||||
|
|
||||||
// 接口已经给了明确详细地址,就直接返回
|
// 计算从原始文本中扣除省市区后的详细地址
|
||||||
if (directDetail) {
|
const stripped = this.stripLeadingRegionParts(
|
||||||
return directDetail
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接口没给详细地址时,再从原始文本里扣掉省市区
|
|
||||||
return this.stripLeadingRegionParts(
|
|
||||||
sanitizedText,
|
sanitizedText,
|
||||||
[
|
[province, city, district].filter(Boolean)
|
||||||
province || '',
|
).trim();
|
||||||
city && city !== province ? city : '',
|
|
||||||
district || ''
|
// 如果 directDetail 存在且长度合理,优先使用;否则使用 stripped
|
||||||
]
|
if (directDetail && directDetail.length >= 4) {
|
||||||
)
|
// 如果 stripped 更长,且 directDetail 是 stripped 的前缀,说明接口返回的不完整,使用 stripped
|
||||||
|
if (stripped.length > directDetail.length && stripped.startsWith(directDetail)) {
|
||||||
|
return stripped;
|
||||||
|
}
|
||||||
|
return directDetail;
|
||||||
|
}
|
||||||
|
return stripped;
|
||||||
},
|
},
|
||||||
|
|
||||||
getRecognizeLevel(hit, detailText, rawText) {
|
getRecognizeLevel(hit, detailText, rawText) {
|
||||||
|
|
@ -1457,9 +1529,12 @@
|
||||||
|
|
||||||
stripLeadingRegionParts(text, parts = []) {
|
stripLeadingRegionParts(text, parts = []) {
|
||||||
let result = String(text || '').trim()
|
let result = String(text || '').trim()
|
||||||
const validParts = parts
|
|
||||||
|
const validParts = [...new Set(
|
||||||
|
parts
|
||||||
.map(item => String(item || '').trim())
|
.map(item => String(item || '').trim())
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
)].sort((a, b) => b.length - a.length)
|
||||||
|
|
||||||
if (!result || !validParts.length) return result
|
if (!result || !validParts.length) return result
|
||||||
|
|
||||||
|
|
@ -1500,9 +1575,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasNetwork = await this.ensureRecognizeNetworkAvailable()
|
const hasNetwork = await this.ensureRecognizeNetworkAvailable()
|
||||||
if (!hasNetwork) {
|
if (!hasNetwork) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const sanitizedText = this.sanitizeRawAddress(originalRawText)
|
const sanitizedText = this.sanitizeRawAddress(originalRawText)
|
||||||
const removedNoise = sanitizedText !== originalRawText
|
const removedNoise = sanitizedText !== originalRawText
|
||||||
|
|
@ -1531,15 +1604,18 @@
|
||||||
|
|
||||||
console.log('智能识别标准化结果:', hit)
|
console.log('智能识别标准化结果:', hit)
|
||||||
|
|
||||||
const province = (hit.province_name || '').trim()
|
const normalizedRegion = this.normalizeRecognizedRegionParts(
|
||||||
const city = (hit.city_name || '').trim()
|
hit.province_name,
|
||||||
const district = (hit.county_name || '').trim()
|
hit.city_name,
|
||||||
|
hit.county_name
|
||||||
|
)
|
||||||
|
|
||||||
|
const province = normalizedRegion.province
|
||||||
|
const city = normalizedRegion.city
|
||||||
|
const district = normalizedRegion.district
|
||||||
const town = (hit.town_name || '').trim()
|
const town = (hit.town_name || '').trim()
|
||||||
|
|
||||||
let regionText = ''
|
const regionText = this.buildRegionText(province, city, district)
|
||||||
if (province) regionText += province
|
|
||||||
if (city && city !== province) regionText += city
|
|
||||||
if (district) regionText += district
|
|
||||||
|
|
||||||
if (!regionText) {
|
if (!regionText) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
@ -1591,8 +1667,8 @@
|
||||||
|
|
||||||
geo = fullGeoResult.data
|
geo = fullGeoResult.data
|
||||||
|
|
||||||
// 使用增强版验证,要求详细地址必须包含地址特征词(除非地理编码为精确级别且由接口直接返回)
|
// ========== 改进1:使用增强的 validateRecognizedDetail ==========
|
||||||
// 这里先尝试用候选详细地址验证
|
// 该方法内部会结合地理编码级别和强/弱关键词进行判断
|
||||||
const detailDecision = this.validateRecognizedDetail(detailCandidate, geo, true)
|
const detailDecision = this.validateRecognizedDetail(detailCandidate, geo, true)
|
||||||
detailRejected = !detailDecision.valid && !!detailCandidate
|
detailRejected = !detailDecision.valid && !!detailCandidate
|
||||||
detailText = detailDecision.valid ? detailDecision.cleaned : ''
|
detailText = detailDecision.valid ? detailDecision.cleaned : ''
|
||||||
|
|
@ -1606,8 +1682,7 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
geo = regionGeoResult.data
|
geo = regionGeoResult.data
|
||||||
// 地区定位成功,但详细地址无效,标记详细地址留空
|
detailText = '' // 详细地址留空
|
||||||
detailText = ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (geo) {
|
if (geo) {
|
||||||
|
|
@ -1650,6 +1725,7 @@
|
||||||
detailRejected
|
detailRejected
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// 低可信度或明显无效 → 只提示,不回填
|
// 低可信度或明显无效 → 只提示,不回填
|
||||||
if (level === 'low' || shouldOnlyToast) {
|
if (level === 'low' || shouldOnlyToast) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
@ -1678,7 +1754,25 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====== 回填到页面下方的位置 ======
|
// 正常回填
|
||||||
|
this.commitRecognizedResult(province, city, district, regionText, detailText, geo, level, removedNoise, geocodeOk, hit, detailRejected)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('智能识别失败:', error)
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
if (this.isLikelyNetworkError(error)) {
|
||||||
|
this.showRecognizeNetworkError()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '识别失败,请稍后重试',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
commitRecognizedResult(province, city, district, regionText, detailText, geo, level, removedNoise, geocodeOk, hit, detailRejected) {
|
||||||
this.currentProvince = province
|
this.currentProvince = province
|
||||||
this.currentCity = city
|
this.currentCity = city
|
||||||
this.currentDistrict = district
|
this.currentDistrict = district
|
||||||
|
|
@ -1688,12 +1782,10 @@
|
||||||
this.selectedCityCode = hit.city_code || ''
|
this.selectedCityCode = hit.city_code || ''
|
||||||
this.selectedDistrictCode = hit.county_code || ''
|
this.selectedDistrictCode = hit.county_code || ''
|
||||||
|
|
||||||
// 关键:只有详细地址有效时才回填,否则留空
|
|
||||||
this.detailAddress = detailText
|
this.detailAddress = detailText
|
||||||
this.manualDetail = detailText
|
this.manualDetail = detailText
|
||||||
this.currentDetail = detailText
|
this.currentDetail = detailText
|
||||||
this.isManualDetail = !!detailText
|
this.isManualDetail = !!detailText
|
||||||
// =================================
|
|
||||||
|
|
||||||
this.smartBtnText = '已识别'
|
this.smartBtnText = '已识别'
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
@ -1711,20 +1803,6 @@
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('智能识别失败:', error)
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (this.isLikelyNetworkError(error)) {
|
|
||||||
this.showRecognizeNetworkError()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.showToast({
|
|
||||||
title: '识别失败,请稍后重试',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 更新地图中心
|
// 更新地图中心
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue