diff --git a/api/request.js b/api/request.js index c75cebb..0d16d66 100644 --- a/api/request.js +++ b/api/request.js @@ -4,6 +4,14 @@ import { const timeout = 5000; let showModal = false +// 定义错误码 +const ErrorCode = { + SUCCESS: 200, + UNAUTHORIZED: 401, + FORBIDDEN: 403, + SERVER_ERROR: 500 +} + // 定义公开API白名单 const publicApis = [ '/beer/list', // 啤酒列表 @@ -24,19 +32,60 @@ const publicApis = [ '/bar/brewery/getBreweryInfo', // 获取品牌详情 ] -// 检查是否是公开API +// 检查是否是公开API - 使用更精确的匹配 const isPublicApi = (url) => { - // 使用更精确的匹配方式 return publicApis.some(api => { - // 如果是完整路径匹配 - if (api.includes('/')) { - return url.includes(api); + if (api.endsWith('/')) { + return url.startsWith(api); } - // 如果是通配符匹配 - return url.split('/').includes(api); + return url === api || url.startsWith(api + '/'); }); } +// 处理错误提示 +const handleErrorMessage = (code, msg, url) => { + // 如果是公开API,不显示错误提示 + if (isPublicApi(url)) return; + + switch (code) { + case ErrorCode.UNAUTHORIZED: + if (!showModal) { + showModal = true; + // 直接触发登录事件,显示登录弹窗 + uni.$emit('needLogin'); + setTimeout(() => { + showModal = false; + }, 100); + } + break; + + case ErrorCode.FORBIDDEN: + uni.showToast({ + title: msg || '暂无权限', + icon: 'none', + duration: 2000 + }); + break; + + case ErrorCode.SERVER_ERROR: + uni.showToast({ + title: '服务器异常,请稍后重试', + icon: 'none', + duration: 2000 + }); + break; + + default: + if (msg) { + uni.showToast({ + title: msg, + icon: 'none', + duration: 2000 + }); + } + } +} + export default (params) => { let url = params.url; let method = params.method || "get"; @@ -65,50 +114,34 @@ export default (params) => { if (res.statusCode == 200) { console.log(res.data, '接口返回值') - if (res.data.code == 200) { + if (res.data.code == ErrorCode.SUCCESS) { resolve(res.data); - } else if (res.data.code == 401 && !isPublicApi(url)) { - uni.clearStorageSync() - if (showModal) return - showModal = true - uni.showModal({ - title: "提示", - content: res.data.msg || "身份已过期,请重新登录", - showCancel: false, - success() { - showModal = false - uni.navigateTo({ - url: '/pages/index/chooseLogin' - }) - }, - }); } else { - // 对于公开接口的401错误,不显示错误提示 - if (!isPublicApi(url)) { - uni.showToast({ - title: res.data.msg || '请求失败', - icon: 'none', - duration: 3000, - }) + // 处理401未授权错误 + if (res.data.code == ErrorCode.UNAUTHORIZED) { + // 只有非公开API才清除token + if (!isPublicApi(url)) { + uni.removeStorageSync('token') + } } + + // 显示错误提示 + handleErrorMessage(res.data.code, res.data.msg, url); reject(res.data) } - } else { - uni.showToast({ - title: '服务器异常', - icon: 'none', - duration: 2000 - }) + handleErrorMessage(res.statusCode, '服务器异常', url); reject(response) } }, fail(err) { - uni.showToast({ - title: '网络异常', - icon: 'none', - duration: 2000 - }) + if (!isPublicApi(url)) { + uni.showToast({ + title: '网络异常,请检查网络连接', + icon: 'none', + duration: 2000 + }) + } reject(err) }, // complete() { diff --git a/pages/index/index.vue b/pages/index/index.vue index 05abcc8..7ee4607 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -313,11 +313,6 @@ }) break; case 4: // 关注酒厂 - const token = uni.getStorageSync('token') - if (!token) { - this.$refs.loginRef.open() - return - } uni.navigateTo({ url: '/pagesMy/myAttention' }) diff --git a/pages/index/my.vue b/pages/index/my.vue index dfc6c44..b1f85f4 100644 --- a/pages/index/my.vue +++ b/pages/index/my.vue @@ -22,12 +22,12 @@ 登录/认证 - 您的门店未认证 + 请点击认证门店信息 正在认证审核中 - 请耐心等待 + diff --git a/pages/index/myJoin.vue b/pages/index/myJoin.vue index 69cbbc8..1567d6e 100644 --- a/pages/index/myJoin.vue +++ b/pages/index/myJoin.vue @@ -638,33 +638,35 @@ padding: 0 32rpx; background: #FFFFFF; height: 88rpx; - + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04); + .nav-item { position: relative; - padding: 28rpx 0; - margin: 0 48rpx; - color: #606060; + width: calc((100% - 56rpx) / 2); // 两等分宽度(减去间距) + margin: 0 14rpx; // 统一的间距 + height: 100%; + display: flex; + align-items: center; + justify-content: center; font-size: 32rpx; - font-weight: 400; - // margin-right: 24rpx; - + color: #1A1A1A; + font-weight: normal; + transition: all 0.3s ease; + &.nav-active { - font-size: 32rpx; + color: #4E63E0; font-weight: 600; - // padding: 32rpx; - color: #19367A; - // font-weight: 600; - } - - .nav-line { - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - width: 48rpx; - height: 4rpx; - background: #19367A; - border-radius: 2rpx; + + .nav-line { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: 48rpx; + height: 4rpx; + background: #4E63E0; + border-radius: 2rpx; + } } } } diff --git a/pagesMy/myAttention.vue b/pagesMy/myAttention.vue index 5db70d1..7336efc 100644 --- a/pagesMy/myAttention.vue +++ b/pagesMy/myAttention.vue @@ -10,57 +10,72 @@ - - @@ -73,9 +88,15 @@ favorBeer, favorBrewery } from '@/api/bar.js' + import loginPopup from '@/components/loginPopup.vue' export default { + components: { + loginPopup + }, data() { return { + isLogin: false, + isVerified: false, tabCur: 0, favoriteBeerList: [], // 收藏的酒款列表 favoriteBreweryList: [], // 收藏的酒厂列表 @@ -91,11 +112,60 @@ totalBrewery: 0 }; }, + onShow() { + this.checkLoginStatus() + }, onLoad() { - this.getFavoriteBeerList() - this.getFavoriteBreweryList() + // 监听需要登录的事件 + uni.$on('needLogin', () => { + this.toLogin() + }) + }, + onUnload() { + // 移除事件监听 + uni.$off('needLogin') }, methods: { + // 检查登录状态 + checkLoginStatus() { + const token = uni.getStorageSync('token') + const userInfo = uni.getStorageSync('userInfo') + this.isLogin = !!token + this.isVerified = userInfo?.isVerified === 1 + + if (this.isLogin && this.isVerified) { + this.getFavoriteBeerList() + this.getFavoriteBreweryList() + } else { + this.favoriteBeerList = [] + this.favoriteBreweryList = [] + } + }, + // 去登录 + toLogin() { + this.$refs.loginRef.open() + }, + // 去认证 + toVerify() { + uni.navigateTo({ + url: '/pages/index/registration' + }) + }, + // 登录成功 + loginSuccess() { + this.isLogin = true + const userInfo = uni.getStorageSync('userInfo') + this.isVerified = userInfo?.isVerified === 1 + + if (this.isVerified) { + this.favoriteBeerList = [] + this.favoriteBreweryList = [] + this.beerQuery.pageNum = 1 + this.breweryQuery.pageNum = 1 + this.getFavoriteBeerList() + this.getFavoriteBreweryList() + } + }, tabSelect(e) { console.log(e) this.tabCur = e.currentTarget.dataset.id; @@ -111,6 +181,8 @@ }, // 获取收藏的酒款列表 getFavoriteBeerList() { + if (!this.isLogin) return + listMyFavoriteBeer(this.beerQuery).then(res => { this.totalBeer = res.total if (res.rows && res.rows.length > 0) { @@ -118,9 +190,8 @@ this.favoriteBeerList.push(it) }) } - // for(let i = 0; i < 29; i++) { - // this.favoriteBeerList.push(res.rows[0]) - // } + }).catch(() => { + // 出错时不显示错误提示,因为已经在请求拦截器中处理了 }) }, // 酒款翻页 @@ -133,6 +204,8 @@ }, // 获取收藏的酒厂列表 getFavoriteBreweryList() { + if (!this.isLogin) return + listMyFavoriteBrewery(this.breweryQuery).then(res => { this.totalBrewery = res.total if (res.rows && res.rows.length > 0) { @@ -140,6 +213,8 @@ this.favoriteBreweryList.push(it) }) } + }).catch(() => { + // 出错时不显示错误提示,因为已经在请求拦截器中处理了 }) }, // 品牌方翻页 @@ -164,52 +239,48 @@ }, // 取消关注酒款 cancelFavBeer(item) { + if (!this.isLogin) { + this.toLogin() + return + } + let data = { beerId: item.beerId, status: 2 } favorBeer(data).then(res => { - // if (status == 1) { - // uni.showToast({ - // title: '收藏成功', - // icon: 'success' - // }) - // } else { uni.showToast({ title: '取消收藏', icon: 'none' }) - // } - /* */ this.favoriteBeerList = [] this.beerQuery.pageNum = 1 this.getFavoriteBeerList() - + }).catch(() => { + // 出错时不显示错误提示,因为已经在请求拦截器中处理了 }) }, // 取消关注酒厂 cancelFavBrewery(item) { + if (!this.isLogin) { + this.toLogin() + return + } + let data = { breweryId: item.breweryId, status: 2 } favorBrewery(data).then(res => { - // if (status == 1) { - // uni.showToast({ - // title: '收藏成功', - // icon: 'success' - // }) - // } else { uni.showToast({ title: '取消收藏', icon: 'none' }) - // } - this.favoriteBreweryList = [] this.breweryQuery.pageNum = 1 this.getFavoriteBreweryList() - + }).catch(() => { + // 出错时不显示错误提示,因为已经在请求拦截器中处理了 }) }, @@ -222,19 +293,56 @@ background: #F9F9F9; height: 100vh; - .tab { - color: #1A1A1A; - font-size: 32rpx; - font-weight: normal; - } + .nav { + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + padding: 0 32rpx; + background: #FFFFFF; + height: 88rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04); - .active { - color: #4E63E0; + .tab { + position: relative; + width: calc((100% - 56rpx) / 2); // 两等分宽度(减去间距) + margin: 0 14rpx; // 统一的间距 + height: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 32rpx; + color: #1A1A1A; + font-weight: normal; + transition: all 0.3s ease; + + &.active { + color: #4E63E0; + font-weight: 600; + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: 48rpx; + height: 4rpx; + background: #4E63E0; + border-radius: 2rpx; + } + } + } } .my-container { padding: 28rpx 36rpx; - height: calc(100vh - 100rpx); + margin-top: 88rpx; // 为固定定位的导航栏留出空间 + height: calc(100vh - 88rpx); .beer-grid { display: flex;