diff --git a/pages/address/search.nvue b/pages/address/search-副本.nvue similarity index 100% rename from pages/address/search.nvue rename to pages/address/search-副本.nvue diff --git a/pages/address/search.vue b/pages/address/search.vue index e598e88..3931abb 100644 --- a/pages/address/search.vue +++ b/pages/address/search.vue @@ -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 = [ - province || '', - city && city !== province ? city : '', - district || '' - ].join('') - - if (prefix && text.startsWith(prefix)) { - text = text.slice(prefix.length).trim() - } - - return text + // 接口没给详细地址时,再从原始文本里扣掉省市区 + return this.stripLeadingRegionParts( + sanitizedText, + [ + province || '', + city && city !== province ? city : '', + district || '' + ] + ) }, 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) { @@ -1644,6 +1647,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() diff --git a/pages/shop/sj-info-change.vue b/pages/shop/sj-info-change.vue index 08ec4fb..10322e0 100644 --- a/pages/shop/sj-info-change.vue +++ b/pages/shop/sj-info-change.vue @@ -914,67 +914,177 @@ 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'; - if (isIOS) { - this._navigateToAddress(); - } else { - this.isShowLocationPer = true; - const { granted } = await permissionUtils.checkPermission('location', '需要定位权限以获取您的位置'); - if (granted) { - this.isShowLocationPer = false; - this._navigateToAddress(); - return; - } - this.isShowLocationPer = false; - const confirm = await this.showPermissionDialog('定位权限申请', '我们需要访问您的位置权限,以便为您选择更精准的地址'); - if (!confirm) return; - const result = await permissionUtils.requestPermission('location', '需要定位权限以获取您的位置'); - if (result) { - this._navigateToAddress(); - } else { - locationService.openAppSettings(); - } - } - }, + 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; - _navigateToAddress() { + // iOS不走你这套权限工具的二次弹窗逻辑,直接进搜索页 + // 如果当前没有任何地址信息,则让搜索页自己只尝试一次定位 + if (isIOS) { + 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; + + // 不管用户同不同意,都进入搜索地址页 + // 同意:按当前位置初始化 + // 不同意/没给权限:进入页面但不自动精确定位 + this._navigateToAddress({ + canInitCurrentLocation: granted + }); + }, + + _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('成功跳转到地址选择页面'), fail: (err) => console.error('跳转地址选择页面失败:', err) }); - }, + }, 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 {