fix(auth): 修复活动页和商品详情页未登录即弹登录框导致审核失败

问题背景:
- 平台审核结论:页面未完整浏览、体验详情时即要求授权登录,属于不合规
- 用户应能先浏览页面内容,仅在执行操作(抽奖/兑换/购买)时才引导登录

根因分析:
1. api/appUser.js 中活动浏览类 API(getActivityDetail 等)使用 authRequest,
   虽然后端接口是公开的,但同页面的 getGamePasses 等需认证接口返回 401
   触发全局登录弹窗
2. getProductDetail 使用 authRequest 调用认证接口,未登录直接 401
3. 全局 401 拦截器不区分浏览请求和操作请求

修改内容:
1. api/appUser.js: 6 个浏览类 API 函数从 authRequest 改为 request
   - getActivityDetail, getActivityIssues, getActivityIssueRewards
   - getIssueDrawLogs, getMatchingCardTypes, getProductDetail
   这些接口在后端均为公开路由,不需要携带 token

2. 活动页面 onLoad 中条件调用认证接口:
   - wuxianshang/index.vue: fetchPasses() 仅在已登录时调用
   - yifanshang/index.vue: fetchPasses() 仅在已登录时调用
   - duiduipeng/index.vue: fetchGamePasses() 仅在已登录时调用
   次数卡(game passes)接口需要认证,未登录时跳过即可,
   不影响页面浏览体验

3. utils/request.js: request() 函数增加 suppressAuthModal 参数
   支持调用方按需静默 401 弹窗,作为安全兜底机制

验证场景:
- 未登录 → 打开无限赏/一番赏/对对碰/商品详情 → 正常显示,无登录弹窗
- 未登录 → 点击抽奖/兑换按钮 → 弹出登录提示(符合平台规范)
- 已登录 → 所有功能正常,次数卡信息正常加载
This commit is contained in:
Zuncle 2026-03-26 14:35:26 +08:00
parent 7487e7224a
commit 27a05210ee
5 changed files with 18 additions and 12 deletions

View File

@ -117,19 +117,19 @@ export function setDefaultAddress(user_id, address_id) {
}
export function getActivityDetail(activity_id) {
return authRequest({ url: `/api/app/activities/${activity_id}`, method: 'GET' })
return request({ url: `/api/app/activities/${activity_id}`, method: 'GET' })
}
export function getActivityIssues(activity_id) {
return authRequest({ url: `/api/app/activities/${activity_id}/issues`, method: 'GET' })
return request({ url: `/api/app/activities/${activity_id}/issues`, method: 'GET' })
}
export function getActivityIssueRewards(activity_id, issue_id) {
return authRequest({ url: `/api/app/activities/${activity_id}/issues/${issue_id}/rewards`, method: 'GET' })
return request({ url: `/api/app/activities/${activity_id}/issues/${issue_id}/rewards`, method: 'GET' })
}
export function getIssueDrawLogs(activity_id, issue_id) {
return authRequest({ url: `/api/app/activities/${activity_id}/issues/${issue_id}/draw_logs`, method: 'GET' })
return request({ url: `/api/app/activities/${activity_id}/issues/${issue_id}/draw_logs`, method: 'GET' })
}
export function drawActivityIssue(activity_id, issue_id) {
@ -141,7 +141,7 @@ export function getIssueChoices(activity_id, issue_id) {
}
export function getProductDetail(product_id) {
return authRequest({ url: `/api/app/products/${product_id}`, method: 'GET' })
return request({ url: `/api/app/products/${product_id}`, method: 'GET' })
}
export function redeemInventory(user_id, ids) {
@ -346,7 +346,7 @@ export function playMatchingGame(game_id) {
* 获取所有启用的卡牌配置
*/
export function getMatchingCardTypes() {
return authRequest({ url: '/api/app/matching/card_types', method: 'GET' })
return request({ url: '/api/app/matching/card_types', method: 'GET' })
}
export function createMatchingPreorder({ issue_id, position, coupon_id = 0, item_card_id = 0, use_game_pass = false }) {

View File

@ -1589,8 +1589,10 @@ onLoad((opts) => {
syncResumeGame(id)
fetchDetail(id)
fetchIssues(id)
//
fetchGamePasses()
//
if (uni.getStorageSync('token')) {
fetchGamePasses()
}
}
fetchCardTypes()
})

View File

@ -476,7 +476,9 @@ onLoad(async (opts) => {
if (currentIssueId.value) {
fetchWinRecords(id, currentIssueId.value)
}
fetchPasses()
if (uni.getStorageSync('token')) {
fetchPasses()
}
})
//

View File

@ -774,7 +774,9 @@ onLoad(async (opts) => {
fetchWinRecords(id, currentIssueId.value)
}
//
fetchPasses()
if (uni.getStorageSync('token')) {
fetchPasses()
}
})
onUnload(() => {

View File

@ -23,7 +23,7 @@ function handleAuthExpired() {
// 不再脱敏,直接打印原始数据
export function request({ url, method = 'GET', data = {}, header = {} }) {
export function request({ url, method = 'GET', data = {}, header = {}, suppressAuthModal = false }) {
return new Promise((resolve, reject) => {
const finalHeader = { ...buildDefaultHeaders(), ...header }
uni.request({
@ -39,7 +39,7 @@ export function request({ url, method = 'GET', data = {}, header = {} }) {
resolve(body && body.data !== undefined ? body.data : body)
} else {
if (code === 401) {
const suppress = finalHeader && (finalHeader['X-Suppress-Auth-Modal'] || finalHeader['x-suppress-auth-modal'])
const suppress = suppressAuthModal || finalHeader && (finalHeader['X-Suppress-Auth-Modal'] || finalHeader['x-suppress-auth-modal'])
if (!suppress) {
handleAuthExpired()
}