首次提交:初始化项目代码

This commit is contained in:
sunct
2026-07-31 14:42:05 +08:00
commit ecca407485
84 changed files with 24158 additions and 0 deletions
+245
View File
@@ -0,0 +1,245 @@
import AES from './aes.js'
import { getToken, checkLogin, removeToken, setToken } from './auth'
import { login } from '../api'
import { getDomain, getEnvName } from './env'
import { cachedRequest, getCacheKey, clearCache } from './apiCache.js'
const API_PREFIX = '/api/app'
const config = {
BASE_URL: getDomain() + API_PREFIX,
API_PREFIX: API_PREFIX,
DOMAIN: getDomain(),
ENV_NAME: getEnvName(),
TIMEOUT: 15000,
LOGIN_PAGE: '/pages/login/login',
CODE: {
SUCCESS: 200,
NEED_LOGIN: 1000,
TOKEN_EXPIRED: 1001,
TOKEN_INVALID: 1002
},
MAX_RETRY: 2
}
let isRefreshing = false
let refreshPromise = null
const isLoginPage = () => {
try {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
return currentPage?.route === 'pages/login/login'
} catch (err) {
return false
}
}
const getCurrentPageInfo = () => {
try {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
return {
route: currentPage?.route || 'unknown',
options: currentPage?.options || {}
}
} catch (err) {
return { route: 'unknown', options: {} }
}
}
const refreshToken = async () => {
if (isRefreshing) {
return refreshPromise
}
const currentPage = getCurrentPageInfo()
console.log(`📋 当前页面: ${currentPage.route}`)
if (isLoginPage()) {
console.log('⚠️ 当前在登录页,不执行自动刷新Token')
return Promise.reject(new Error('当前在登录页'))
}
isRefreshing = true
refreshPromise = new Promise(async (resolve, reject) => {
try {
console.log(`🔄 尝试自动刷新Token... (触发页面: ${currentPage.route})`)
const loginRes = await uni.login()
if (!loginRes.code) {
throw new Error('获取微信code失败')
}
const tokenData = await login(loginRes.code)
if (!tokenData?.token) {
throw new Error('刷新Token失败')
}
setToken(tokenData.token)
console.log(`✅ Token刷新成功 (触发页面: ${currentPage.route})`)
resolve(tokenData.token)
} catch (err) {
console.error(`❌ Token刷新失败(触发页面: ${currentPage.route}):`, err)
removeToken()
clearCache()
reject(err)
} finally {
isRefreshing = false
refreshPromise = null
}
})
return refreshPromise
}
const executeRequest = async (options, retryCount = 0) => {
const { url, data = {}, needLogin = true, showLoading = true, encrypt = true } = options
if (showLoading) {
uni.showLoading({ title: '处理中...', mask: true })
}
try {
if (needLogin && url !== '/user/login' && !checkLogin()) {
const currentPage = getCurrentPageInfo()
console.log(`🔴 未登录检测 - 页面: ${currentPage.route}, 接口: ${url}`)
if (retryCount === 0) {
try {
console.log(`🟡 准备调用 refreshToken - 页面: ${currentPage.route}`)
await refreshToken()
console.log(`🟢 refreshToken 成功,重试请求 - 页面: ${currentPage.route}`)
return await executeRequest(options, retryCount + 1)
} catch (err) {
console.log(`🔴 refreshToken 失败: ${err.message} - 页面: ${currentPage.route}`)
uni.showToast({ title: '请先登录', icon: 'none' })
redirectToLogin()
return Promise.reject(new Error('请先登录'))
}
}
uni.showToast({ title: '请先登录', icon: 'none' })
redirectToLogin()
return Promise.reject(new Error('请先登录'))
}
const token = getToken()
console.log(`🔵 [POST] 请求接口:${url},参数:`, data)
let requestData = {}
if (encrypt) {
requestData.data = await AES.encrypt(data)
} else {
requestData = data
}
const response = await new Promise((resolve, reject) => {
const requestTask = uni.request({
url: config.BASE_URL + url,
method: 'POST',
header: { token: token || '', 'Content-Type': 'application/json' },
data: requestData,
timeout: config.TIMEOUT,
success: (res) => resolve(res),
fail: (err) => reject(new Error(err.errMsg?.includes('timeout') ? '请求超时' : '网络异常'))
})
setTimeout(() => requestTask.abort(), config.TIMEOUT)
})
if (response.statusCode !== 200) {
console.log(`🔵 [POST] 请求接口:${url}Error${response.statusCode}`)
throw new Error(`请求出错啦 o(╥﹏╥)o`)
}
const encryptRes = response.data.data || ''
let result = {}
if (encrypt && encryptRes) {
const decryptStr = await AES.decrypt(encryptRes)
result = typeof decryptStr === 'string' ? JSON.parse(decryptStr) : decryptStr
} else {
result = response.data
}
console.log(`🟢 [POST] 请求接口:${url} 响应结果:`, result)
if (result.code === config.CODE.SUCCESS) {
return result.data ?? true
} else if (result.code === config.CODE.NEED_LOGIN ||
result.code === config.CODE.TOKEN_EXPIRED ||
result.code === config.CODE.TOKEN_INVALID) {
if (retryCount < config.MAX_RETRY) {
console.log(`🔄 Token失效,尝试刷新(第${retryCount + 1}次)`)
try {
await refreshToken()
return await executeRequest(options, retryCount + 1)
} catch (err) {
uni.showToast({ title: '登录已过期', icon: 'none' })
removeToken()
clearCache()
setTimeout(() => redirectToLogin(), 1500)
return Promise.reject(new Error('登录已过期'))
}
}
uni.showToast({ title: '登录已过期', icon: 'none' })
removeToken()
clearCache()
setTimeout(() => redirectToLogin(), 1500)
return Promise.reject(new Error('登录已过期'))
} else {
throw new Error(result.msg || '请求失败')
}
} catch (err) {
console.error(`🔴 [POST] 请求异常:`, err)
if (err.message.includes('网络异常')) {
uni.showToast({ title: '网络连接异常,请检查网络', icon: 'none', duration: 2000 })
} else if (err.message.includes('请求超时')) {
uni.showToast({ title: '请求超时,请稍后重试', icon: 'none', duration: 2000 })
} else {
uni.showToast({ title: err.message || '系统异常', icon: 'none', duration: 2000 })
}
return Promise.reject(err)
} finally {
if (showLoading) uni.hideLoading()
}
}
const request = async (options, retryCount = 0) => {
const { cache } = options
if (cache === true && retryCount === 0) {
const cacheKey = getCacheKey(options.url, options.data)
return cachedRequest(cacheKey, () => executeRequest(options, retryCount), options.cacheTTL)
}
if (cache === 'bypass' && retryCount === 0) {
const cacheKey = getCacheKey(options.url, options.data)
clearCache(cacheKey)
}
return executeRequest(options, retryCount)
}
function redirectToLogin() {
try {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
if (currentPage?.route !== 'pages/login/login') {
uni.redirectTo({ url: config.LOGIN_PAGE })
}
} catch (err) {
uni.reLaunch({ url: config.LOGIN_PAGE })
}
}
request.post = function (url, data = {}, options = {}) {
return this({ url, data, ...options })
}
export const getRequestConfig = () => ({
domain: config.DOMAIN,
apiPrefix: config.API_PREFIX,
baseUrl: config.BASE_URL,
envName: config.ENV_NAME
})
export { clearCache }
export default request