更新
This commit is contained in:
1 parent
012f8edf8b
commit
36ff960fbd
33 files changed
+1644
-344
No files matched your search
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 游客轻身份接口(后端 controllers/guest.go)
|
||||
* 失败均由调用方静默处理,不弹全局 toast。
|
||||
*/
|
||||
import { request } from '@/api/request.js'
|
||||
|
||||
/**
|
||||
* 游客登录:微信手机号动态凭证换游客令牌
|
||||
* @param {{ code: string, phoneCode: string, appid?: string }} params code=uni.login 的登录凭证
|
||||
* @returns {Promise<{ token: string, guest_id: number, phone_mask: string, expires_in: number }>}
|
||||
*/
|
||||
export function guestMiniLogin({ code = '', phoneCode = '', appid = '' } = {}) {
|
||||
return request({
|
||||
url: '/api/guest/mini-login',
|
||||
method: 'POST',
|
||||
data: { code, phone_code: phoneCode, appid },
|
||||
silent: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 转正合并:正式登录令牌调用,把该手机号下的游客数据并入账号
|
||||
* @returns {Promise<object>} 各模块合并条数,如 { notebook: 3, schedule: 1, passwordStore: 2 }
|
||||
*/
|
||||
export function guestMerge() {
|
||||
return request({
|
||||
url: '/api/guest/merge',
|
||||
method: 'POST',
|
||||
data: {},
|
||||
silent: true
|
||||
})
|
||||
}
|
||||
+45
-10
@@ -2,7 +2,8 @@
|
||||
* 统一请求封装:baseURL、Bearer Token、业务 code 处理。
|
||||
* 接口地址统一从 .env 的 VITE_API_BASE_URL 读取(见 api/config.js)。
|
||||
*/
|
||||
import { getToken, logout, isSSOEnabled, getRefreshToken, setAuthTokens } from '@/utils/auth.js'
|
||||
import { getToken, logout, isSSOEnabled, getRefreshToken, setAuthTokens, isLoggedIn } from '@/utils/auth.js'
|
||||
import { getGuestToken, clearGuestToken } from '@/utils/guest.js'
|
||||
import { resolveBaseURL, getBaseURL } from '@/api/config.js'
|
||||
|
||||
export { getBaseURL }
|
||||
@@ -74,14 +75,11 @@ async function replayRequest(options) {
|
||||
*/
|
||||
export function request(options = {}) {
|
||||
const { url, method = 'GET', data, header = {}, silent = false, timeout = 30000 } = options
|
||||
const token = getToken()
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
...header
|
||||
}
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
applyAuth(headers)
|
||||
|
||||
const fullUrl = buildFullUrl(url)
|
||||
|
||||
@@ -97,6 +95,19 @@ export function request(options = {}) {
|
||||
const body = res.data || {}
|
||||
|
||||
if (status === 401 || body.code === 401) {
|
||||
// 游客令牌过期/被吊销:只清游客态并回门户重新授权,
|
||||
// 不进登录引导(免登录模块对游客令牌报 403 端不匹配,不会走到这里)。
|
||||
if (!isLoggedIn() && getGuestToken()) {
|
||||
clearGuestToken()
|
||||
if (!silent) {
|
||||
uni.showToast({ title: '免登录授权已过期,请重新授权', icon: 'none' })
|
||||
}
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({ url: '/pages/nav/nav' })
|
||||
}, 400)
|
||||
reject(new Error(body.msg || '未授权'))
|
||||
return
|
||||
}
|
||||
// 统一认证模式:先用 refresh_token 静默续期并重放请求,
|
||||
// 续期失败(令牌过期/被吊销/被踢下线)才真正登出。
|
||||
if (isSSOEnabled()) {
|
||||
@@ -111,8 +122,19 @@ export function request(options = {}) {
|
||||
if (!silent) {
|
||||
uni.showToast({ title: body.msg || '请重新登录', icon: 'none' })
|
||||
}
|
||||
// 门户首页 nav 是默认落地页,允许游客停留。
|
||||
// 若 401 发生在 nav(多为残留/过期令牌触发的 /api/home),
|
||||
// 登出后回 nav 以游客态重载,而不是强跳统一认证登录页;
|
||||
// 业务内页(需登录)仍照常引导到登录。
|
||||
const onNav = (() => {
|
||||
const ps = (typeof getCurrentPages === 'function' && getCurrentPages()) || []
|
||||
const cur = ps.length ? ps[ps.length - 1] : null
|
||||
if (!cur) return false
|
||||
const route = cur.route || (cur.$page && cur.$page.path) || ''
|
||||
return String(route).replace(/^\//, '') === 'pages/nav/nav'
|
||||
})()
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({ url: '/pages/login/login' })
|
||||
uni.reLaunch({ url: onNav ? '/pages/nav/nav' : '/pages/login/login' })
|
||||
}, 400)
|
||||
reject(new Error(body.msg || '未授权'))
|
||||
return
|
||||
@@ -157,17 +179,30 @@ export function request(options = {}) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入 Authorization:正式令牌优先;未登录但持有游客令牌(手机号授权签发)时带游客令牌,
|
||||
* 由后端各控制器自行决定是否放行 guest 端(不放行者报 403,不影响游客态浏览)。
|
||||
*/
|
||||
function applyAuth(headers) {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`
|
||||
return
|
||||
}
|
||||
const guestToken = getGuestToken()
|
||||
if (guestToken) {
|
||||
headers.Authorization = `Bearer ${guestToken}`
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回完整响应体(含 code/msg),用于需要自行判断 code 的场景 */
|
||||
export function requestRaw(options = {}) {
|
||||
const { url, method = 'GET', data, header = {} } = options
|
||||
const token = getToken()
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
...header
|
||||
}
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
applyAuth(headers)
|
||||
|
||||
const fullUrl = buildFullUrl(url)
|
||||
|
||||
|
||||
@@ -33,3 +33,32 @@ export function clearHomeCache() {
|
||||
cache = null
|
||||
cacheAt = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 免登录模块宫格:GET /api/modules/public(公开接口,无需 token)。
|
||||
* 返回 [{ id, code, name, icon, path, description, require_login }]。
|
||||
* 供未登录用户渲染 nav 首页,按 require_login 决定点击是「进登录引导」还是「直接进入」。
|
||||
*/
|
||||
export function fetchPublicModules() {
|
||||
return request({
|
||||
url: '/api/modules/public',
|
||||
method: 'GET',
|
||||
silent: true,
|
||||
timeout: 15000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 免登录菜单:GET /api/menus/public(公开接口,无需 token)。
|
||||
* 返回 [{ id, pid, title, path, icon, type, sort, module, leaf }],
|
||||
* 菜单级 require_login=0 的集合:游客(持游客令牌)可用功能的唯一入口清单,
|
||||
* nav 宫格据此判定模块是否可免登录进入,子系统据此渲染游客功能列表。
|
||||
*/
|
||||
export function fetchPublicMenus() {
|
||||
return request({
|
||||
url: '/api/menus/public',
|
||||
method: 'GET',
|
||||
silent: true,
|
||||
timeout: 15000
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user