8816dd2867
根因:定位链路用区县「中文名」查 sys_area,重名区县(白云区=广州/贵阳、
朝阳区=北京/长春、南山区=深圳/鹤岗…)命中多条,后端 getOne 默认
throwEx=true 抛 TooManyResultsException,页面表现为「有时能定位、有时不能」
——取决于用户当前所在区县名是否唯一。
改动:
- 新增 util/geo.js(纯函数):buildGeocodeUrl / normalizeAdcode /
parseGeocodeResult / formatLocationText
· 天地图 postStr 补 URL 编码:实测未编码时接口返回 HTTP 400
「参数格式错误」(admin 端 merchantEdit.vue 已是正确写法)
· 严格校验响应结构,限流(429)/参数错误(400) 一律返回 null
· 补直辖市 city 为空时用省名兜底(天地图对上海/北京/天津/重庆返回 city:"")
- util/index.js:抽出 locateOnce / fetchGeocode / resolveAreaInfo 共用
· 清除两处模块作用域的 this.areaId 误用(严格模式下抛 TypeError 会让
Promise 永久悬空,locating 再也回不到 false,即「反复点没反应」)
· 优先按天地图 county_code(去 156 前缀 = sys_area.id)精确查询,
从根上绕开重名;按中文名仅作降级,并注释其歧义风险
· 行政区划查不到不再阻断定位:返回 null,仍给出经纬度与地址
(area_id/city_id/province_id 全仓库无消费方)
- api/request.js:get/del 不再吞掉非 2xx 的 reject,避免调用方状态永久悬空
- pages/visit/index.vue:fetchLocation 加 15s 超时兜底 + 运行号丢弃迟到结果,
保证失败后仍可重试;静默失败也给出可见提示
- 新增 util/geo.test.mjs(10 个单测),package.json 补 test 脚本
验证:前端单测 10/10;真实天地图 + 生产后端端到端 5 个重名区县全部可正常
定位(后端修复尚未部署即已生效)。
100 lines
3.0 KiB
JavaScript
100 lines
3.0 KiB
JavaScript
import Request from '@/js_sdk/luch-request/luch-request/index.js'
|
||
import {API} from '@/config'
|
||
import {getUserInfo, clearUserInfo} from "@/util/user";
|
||
|
||
const http = new Request();
|
||
http.config.baseURL = API
|
||
|
||
http.interceptors.request.use((config) => {
|
||
// uni.showLoading({title: '加载中'})
|
||
const token = getUserInfo().token
|
||
if (token && token !== 'undefined') {
|
||
config.header.Authorization = token
|
||
}
|
||
config.header.tenantId = 10325
|
||
return config
|
||
}, config => {
|
||
return Promise.reject(config)
|
||
})
|
||
|
||
http.interceptors.response.use((response) => {
|
||
const url = response.config.url
|
||
// uni.hideLoading()
|
||
switch (parseInt(response.data.code)) {
|
||
case 401: {
|
||
if (['user-cart-num', 'new-order', 'user-cart-add', 'user-info'].indexOf(url) === -1) {
|
||
uni.showToast({
|
||
title: '请登录',
|
||
icon: 'error',
|
||
duration: 2000,
|
||
})
|
||
setTimeout(() => {
|
||
clearUserInfo()
|
||
}, 2000)
|
||
}
|
||
}
|
||
break;
|
||
case 500: {
|
||
if (['/user/change-pay-password', 'new-order-from-goods-list'].indexOf(url) === -1) {
|
||
console.log(response.data)
|
||
uni.showToast({
|
||
icon: 'none',
|
||
title: response.data.content.msg,
|
||
duration: 2000,
|
||
})
|
||
}
|
||
}
|
||
break;
|
||
case 502: {
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: '系统维护中',
|
||
duration: 2000,
|
||
})
|
||
}
|
||
}
|
||
return response
|
||
}, (error) => {
|
||
if (error.code === 502) {
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: '系统维护中',
|
||
duration: 2000,
|
||
})
|
||
}
|
||
return Promise.reject(error)
|
||
})
|
||
|
||
const post = (url, formData, options) => {
|
||
return new Promise((resolve, reject) => {
|
||
http.post(url, formData, options).then(res => {
|
||
if (res.data.code === 0) resolve(res.data)
|
||
else if (res.data.code === 401) reject(res.data)
|
||
else reject(res.data)
|
||
})
|
||
})
|
||
}
|
||
|
||
export const get = (url, options) => {
|
||
// 直接返回,不再用 new Promise 包一层纯转发:
|
||
// http.get 成功时给出 {data},失败(非 2xx,如天地图 400/429)时 reject,
|
||
// 链式 then 会让错误自然向下传递。若吞掉 reject,调用方的 loading /
|
||
// locating 等状态将再也回不到初始值,表现为「点了没反应」。
|
||
return http.get(url, options).then(res => res.data)
|
||
}
|
||
|
||
export const del = (url, options) => {
|
||
return http.delete(url, options).then(res => res.data)
|
||
}
|
||
|
||
export const put = (url, formData, options) => {
|
||
return new Promise((resolve, reject) => {
|
||
http.put(url, formData, options).then(res => {
|
||
if (res.data.code === 0) resolve(res.data)
|
||
else if (res.data.code === 401) reject(res.data)
|
||
else reject(res.data)
|
||
})
|
||
})
|
||
}
|
||
|
||
export default post |