This commit is contained in:
houjunxiang
2025-10-09 18:19:55 +08:00
parent f2ffc65094
commit 386f1e7466
1553 changed files with 284685 additions and 32820 deletions

384
nx/request/index.js Normal file
View File

@@ -0,0 +1,384 @@
/**
* 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)
// }
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 === 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