Files
zgty-mas-m/nx/request/index.js
2025-10-10 18:16:14 +08:00

390 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* nx-request
* @description api模块管理loading配置请求拦截错误处理
*/
import Request from 'luch-request'
import { getBaseUrl, getTenantId } from '@/defaultBaseUrl'
import $store from '@/nx/store'
import { ApiEncryption } from '@/nx/utils/crypto.js'
const apiEncryption = new ApiEncryption()
const options = {
// 显示操作成功消息 默认不显示
showSuccess: false,
// 成功提醒 默认使用后端返回值
successMsg: '操作成功',
// 显示失败消息 默认显示
showError: true,
// 失败提醒 默认使用后端返回信息
errorMsg: '操作失败',
// 显示请求时loading模态框 默认显示
showLoading: true,
// loading提醒文字
loadingMsg: '加载中',
// 需要授权才能请求 默认放开
auth: false,
// 是否处理请求结果
isTransformResponse: true
}
const COMPANY_DEPT_RETRY_HEADER = '__companyDeptRetried'
const VISIT_COMPANY_STORAGE_KEY = 'visit-company-info'
const VISIT_DEPT_STORAGE_KEY = 'visit-dept-info'
// Loading全局实例
let LoadingInstance = {
target: null,
count: 0
}
/**
* 关闭loading
*/
function closeLoading() {
if (LoadingInstance.count > 0) LoadingInstance.count--
if (LoadingInstance.count === 0) uni.hideLoading()
}
/**
* @description 请求基础配置 可直接使用访问自定义请求
*/
const http = new Request({
timeout: 8000,
method: 'GET',
header: {
'Content-Type': 'application/json;charset=UTF-8'
},
// #ifdef APP-PLUS
sslVerify: false,
// #endif
// #ifdef H5
// 跨域请求时是否携带凭证cookies仅H5支持HBuilderX 2.6.15+
withCredentials: false,
// #endif
custom: options
})
/**
* @description 请求拦截器
*/
http.interceptors.request.use(
config => {
if (config.custom.showLoading) {
LoadingInstance.count++
LoadingInstance.count === 1 &&
uni.showLoading({
title: config.custom.loadingMsg,
mask: true,
fail: () => {
uni.hideLoading()
}
})
}
config.baseURL = getBaseUrl()
// 可使用async await 做异步操作
config.header['X-TIMESTAMP'] = new Date().getTime()
const token = getAccessToken()
if (token) config.header['Authorization'] = token
config.header['Accept'] = '*/*'
config.header['tenant-id'] = getTenantId()
let params = config.params || {}
let data = config.data || false
if (process.env.NODE_ENV == 'development') console.log('development--params', params)
if (process.env.NODE_ENV == 'development') console.log('development--data', data)
const visitCompanyId = getVisitCompanyId()
if (visitCompanyId !== undefined && visitCompanyId !== null && visitCompanyId !== '') {
config.header['visit-company-id'] = visitCompanyId
const visitCompanyName = getVisitCompanyName()
if (visitCompanyName !== undefined && visitCompanyName !== null) {
config.header['visit-company-name'] = encodeURIComponent(visitCompanyName || '')
}
}
const visitDeptId = getVisitDeptId()
if (visitDeptId !== undefined && visitDeptId !== null && visitDeptId !== '') {
config.header['visit-dept-id'] = visitDeptId
const visitDeptName = getVisitDeptName()
if (visitDeptName !== undefined && visitDeptName !== null) {
config.header['visit-dept-name'] = encodeURIComponent(visitDeptName || '')
}
}
return config
},
error => {
return Promise.reject(error)
}
)
/**
* @description 响应拦截器
*/
http.interceptors.response.use(
response => {
// 自动设置登陆令牌
// if (response.header.authorization || response.header.Authorization) {
// $store('user').setToken(response.header.authorization || response.header.Authorization)
// }
const userStore = $store('user')
const isLogin = userStore.isLogin
response.config.custom.showLoading && closeLoading()
console.log('response', JSON.parse(JSON.stringify(response.data)))
if (!response.config.custom.isTransformResponse) {
return Promise.resolve(response.data)
}
const { code, data, msg } = response.data
// 统一处理【公司/部门二次选择】:参考 PC 端逻辑,自动补全或提示选择后重试
if (code === 400 && Array.isArray(data)) {
debugger
const companyDeptList = data
const config = response.config
config.header = config.header || {}
if (companyDeptList.length === 1) {
const item = companyDeptList[0]
if (!config.header[COMPANY_DEPT_RETRY_HEADER]) {
applyCompanyDeptSelection(item, config)
return request(config)
}
uni.showToast({
title: '公司/部门信息缺失,且自动补全失败,请联系管理员',
icon: 'none',
mask: true
})
return Promise.resolve(data)
} else if (companyDeptList.length > 1) {
const groupedList = normalizeCompanyDeptList(companyDeptList)
const companyDeptDialogStore = $store('company-dept')
return new Promise(resolve => {
companyDeptDialogStore.open({
companyList: groupedList,
onConfirm: ({ companyId, deptId }) => {
const selectedCompany = groupedList.find(company => company.companyId === companyId)
const selectedDept = selectedCompany?.depts.find(dept => dept.deptId === deptId)
applyCompanyDeptSelection(
{
companyId,
companyName: selectedCompany?.companyName || '',
deptId,
deptName: selectedDept?.deptName || ''
},
config
)
resolve(request(config))
},
onCancel: () => {
uni.showToast({
title: '已取消公司/部门选择',
icon: 'none',
mask: true
})
resolve(data)
}
})
})
}
}
if (code !== 0) {
uni.showToast({
title: msg || response.config.custom.errorMsg,
icon: 'none'
})
if (code === 401) {
userStore.logout(true)
}
}
if ((code === 0 || code === 200) && response.config.custom.showSuccess) {
setTimeout(() => {
uni.showToast({
title: msg || response.config.custom.successMsg,
icon: 'none'
})
}, 100)
}
$store('user').updateLastRequestTime()
return Promise.resolve(data)
},
error => {
console.log('error', error)
const userStore = $store('user')
const isLogin = userStore.isLogin
let errorMessage = '网络请求出错'
if (error !== undefined) {
switch (error.statusCode) {
case 400:
errorMessage = '请求错误'
break
case 401:
if (isLogin) {
errorMessage = '您的登陆已过期'
} else {
errorMessage = '请先登录'
}
userStore.logout(true)
break
case 403:
errorMessage = '拒绝访问'
break
case 404:
errorMessage = '请求出错'
break
case 408:
errorMessage = '请求超时'
break
case 429:
errorMessage = '请求频繁, 请稍后再访问'
break
case 500:
errorMessage = '服务器开小差啦,请稍后再试~'
break
case 501:
errorMessage = '服务未实现'
break
case 502:
errorMessage = '网络错误'
break
case 503:
errorMessage = '服务不可用'
break
case 504:
errorMessage = '网络超时'
break
case 505:
errorMessage = 'HTTP版本不受支持'
break
}
if (error.errMsg.includes('timeout')) errorMessage = '请求超时'
// #ifdef H5
if (error.errMsg.includes('Network')) errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接'
// #endif
}
if (error && error.config) {
if (error.config.custom.showError === true) {
uni.showToast({
title: error.data?.msg || errorMessage,
icon: 'none',
mask: true
})
}
error.config.custom.showLoading && closeLoading()
}
return Promise.reject(error)
}
)
/** 获得访问令牌 */
export const getAccessToken = () => {
return uni.getStorageSync('token')
}
const getStorageObject = key => {
const value = uni.getStorageSync(key)
if (!value) {
return {}
}
if (typeof value === 'string') {
try {
return JSON.parse(value)
} catch (error) {
console.warn(`解析本地存储 ${key} 失败:`, error)
return {}
}
}
return value
}
const setStorageObject = (key, value) => {
if (value === undefined || value === null) {
uni.removeStorageSync(key)
return
}
uni.setStorageSync(key, value)
}
export const getVisitCompanyId = () => {
const info = getStorageObject(VISIT_COMPANY_STORAGE_KEY)
return info?.id ?? info?.companyId ?? null
}
export const getVisitCompanyName = () => {
const info = getStorageObject(VISIT_COMPANY_STORAGE_KEY)
return info?.name ?? info?.companyName ?? ''
}
export const getVisitDeptId = () => {
const info = getStorageObject(VISIT_DEPT_STORAGE_KEY)
return info?.id ?? info?.deptId ?? null
}
export const getVisitDeptName = () => {
const info = getStorageObject(VISIT_DEPT_STORAGE_KEY)
return info?.name ?? info?.deptName ?? ''
}
export const setVisitCompany = (companyId, companyName) => {
if (companyId === undefined || companyId === null || companyId === '') {
uni.removeStorageSync(VISIT_COMPANY_STORAGE_KEY)
return
}
setStorageObject(VISIT_COMPANY_STORAGE_KEY, {
id: companyId,
name: companyName || ''
})
}
export const setVisitDept = (deptId, deptName) => {
if (deptId === undefined || deptId === null || deptId === '') {
uni.removeStorageSync(VISIT_DEPT_STORAGE_KEY)
return
}
setStorageObject(VISIT_DEPT_STORAGE_KEY, {
id: deptId,
name: deptName || ''
})
}
const applyCompanyDeptSelection = (item, config) => {
setVisitCompany(item.companyId, item.companyName)
setVisitDept(item.deptId, item.deptName)
config.header['visit-company-id'] = item.companyId
config.header['visit-company-name'] = encodeURIComponent(item.companyName || '')
config.header['visit-dept-id'] = item.deptId
config.header['visit-dept-name'] = encodeURIComponent(item.deptName || '')
config.header[COMPANY_DEPT_RETRY_HEADER] = '1'
}
const normalizeCompanyDeptList = (list = []) => {
const companyMap = new Map()
list.forEach(item => {
if (!companyMap.has(item.companyId)) {
companyMap.set(item.companyId, {
companyId: item.companyId,
companyName: item.companyName,
depts: []
})
}
const company = companyMap.get(item.companyId)
if (!company.depts.some(dept => dept.deptId === item.deptId)) {
company.depts.push({
deptId: item.deptId,
deptName: item.deptName
})
}
})
return Array.from(companyMap.values())
}
const request = config => {
return http.middleware(config)
}
export default request