| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- import env from '../config/env.js'
- // Loading 管理器
- const loadingManager = {
- loadingCount: 0,
- loadingTimer: null,
- isShowing: false, // 添加状态标记
- // 安全的隐藏toast方法
- safeHideToast() {
- try {
- // 不要直接调用hideToast,因为如果没有toast在显示会报错
- // 只是静默忽略这个错误
- } catch (error) {
- // 静默忽略错误
- }
- },
- // 显示 loading
- show(options = {}) {
- const config = {
- title: '加载中...',
- mask: true,
- delay: 300,
- ...options
- }
- // 如果已经有 loading 在显示,只增加计数
- if (this.loadingCount > 0) {
- this.loadingCount++
- return
- }
- // 延迟显示,避免快速请求造成闪烁
- this.loadingTimer = setTimeout(() => {
- if (this.loadingCount > 0 && !this.isShowing) {
- try {
- // 不要先隐藏toast,直接显示loading
- uni.showLoading({
- title: config.title,
- mask: config.mask
- })
- this.isShowing = true
- } catch (error) {
- console.warn('showLoading failed:', error)
- }
- }
- }, config.delay)
- this.loadingCount++
- },
- // 隐藏 loading
- hide() {
- this.loadingCount = Math.max(0, this.loadingCount - 1)
- if (this.loadingCount === 0) {
- // 清除延迟显示的定时器
- if (this.loadingTimer) {
- clearTimeout(this.loadingTimer)
- this.loadingTimer = null
- }
- // 隐藏 loading
- if (this.isShowing) {
- try {
- uni.hideLoading()
- } catch (error) {
- console.warn('hideLoading failed:', error)
- } finally {
- this.isShowing = false
- }
- }
- }
- },
- // 强制隐藏所有 loading
- forceHide() {
- this.loadingCount = 0
- if (this.loadingTimer) {
- clearTimeout(this.loadingTimer)
- this.loadingTimer = null
- }
-
- if (this.isShowing) {
- try {
- uni.hideLoading()
- } catch (error) {
- console.warn('forceHide failed:', error)
- } finally {
- this.isShowing = false
- }
- }
- },
- // 安全显示toast(确保loading已隐藏)
- safeShowToast(options) {
- // 如果有loading在显示,先隐藏它
- if (this.isShowing) {
- this.forceHide()
- // 等待loading完全隐藏后显示toast
- setTimeout(() => {
- uni.showToast(options)
- }, 100)
- } else {
- // 没有loading,直接显示toast
- uni.showToast(options)
- }
- }
- }
- const request = {
- async get(url, params = {}, options = {}) {
- return this.request(url, 'GET', params, options)
- },
- async post(url, data = {}, options = {}) {
- return this.request(url, 'POST', data, options)
- },
- async put(url, data = {}, options = {}) {
- return this.request(url, 'PUT', data, options)
- },
- async delete(url, data = {}, options = {}) {
- return this.request(url, 'DELETE', data, options)
- },
- async request(url, method, data, options = {}) {
- // 解析 loading 配置
- let loadingConfig
- if (options.loading === false) {
- // 如果明确设置为 false,则不显示 loading
- loadingConfig = false
- } else {
- // 否则使用默认配置并合并用户配置
- loadingConfig = {
- show: true,
- title: '加载中...',
- mask: true,
- delay: 300,
- timeout: 10000,
- ...(typeof options.loading === 'object' ? options.loading : {})
- }
- }
- // 解析请求配置
- const requestConfig = {
- timeout: 15000, // 默认网络超时 15 秒
- ...options.request
- }
- // 如果 loading 配置为 false,则不显示 loading
- const shouldShowLoading = loadingConfig !== false && loadingConfig.show !== false
- // 显示 loading
- if (shouldShowLoading) {
- loadingManager.show(loadingConfig)
- }
- // 获取设备信息
- const deviceInfo = uni.getStorageSync("deviceInfo") || {};
- const devId = deviceInfo.deviceId || '';
- const sbmc = deviceInfo.model || '';
- // 处理URL,添加设备参数
- const separator = url.includes('?') ? '&' : '?';
- const finalUrl = `${url}${separator}devId=${devId}&sbmc=${sbmc}`;
- // 超时处理
- let timeoutTimer = null
- if (shouldShowLoading && loadingConfig.timeout) {
- timeoutTimer = setTimeout(() => {
- loadingManager.hide()
- // 使用安全的toast显示方法
- loadingManager.safeShowToast({
- title: '请求超时',
- icon: 'none'
- })
- }, loadingConfig.timeout)
- }
- // 数据格式转换
- let requestData = data;
- if (options.formData && data && typeof data === 'object') {
- // 转换为表单格式
- requestData = Object.keys(data).map(key => {
- const value = data[key];
- if (Array.isArray(value)) {
- // 数组数据转换为多个同名参数
- return value.map(item => `${encodeURIComponent(key)}=${encodeURIComponent(item)}`).join('&');
- } else {
- return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
- }
- }).join('&');
- }
- return new Promise((resolve, reject) => {
- uni.request({
- url: `${env.baseUrl}${finalUrl}`,
- method,
- data: requestData,
- timeout: requestConfig.timeout, // 设置网络超时
- header: (() => {
- const headers = {};
- // 根据选项决定Content-Type
- if (options.formData) {
- // 使用表单格式,让浏览器自动设置Content-Type
- headers['content-type'] = 'application/x-www-form-urlencoded';
- } else {
- // 默认使用JSON格式
- headers['content-type'] = 'application/json';
- }
- const jsessionId = uni.getStorageSync('JSESSIONID');
- if (jsessionId) {
- headers['Cookie'] = `JSESSIONID=${jsessionId}`;
- }
- return headers;
- })(),
- success: (res) => {
- // 清除超时定时器
- if (timeoutTimer) {
- clearTimeout(timeoutTimer)
- }
- // 获取响应头
- const headers = res.header;
- // console.log('响应头:', headers);
- // 处理Set-Cookie,获取JSESSIONID
- const setCookie = headers['set-cookie'] || headers['Set-Cookie'];
- if (setCookie) {
- const match = setCookie.match(/JSESSIONID=([^;]+)/);
- if (match && match[1]) {
- // console.log('获取到新的JSESSIONID:', match[1]);
- uni.setStorageSync('JSESSIONID', match[1]);
- }
- }
- if (res.statusCode === 200) {
- // console.log('请求成功:', res.data);
- // 检查登录过期 - 根据实际响应体格式
- if (res && typeof res.data === 'string' && res.data.includes('页面执行时错误')) {
- // 统一处理错误响应
- reject({
- message: '服务器处理错误' + res.data,
- })
-
- loadingManager.safeShowToast({
- title: '服务器处理错误',
- icon: 'none'
- })
-
- return
- }
- if (res.data && (
- res.data.errorcode === 1 ||
- res.data.msg === '登录已失效,请重新登录' ||
- res.data.message === '登录过期' ||
- res.data.error === 'UNAUTHORIZED'
- )) {
- console.log('🔒 检测到登录过期,跳转自动登录');
- console.log('过期响应数据:', res.data);
- handleLoginExpired();
- reject({ code: 401, message: res.data.msg || '登录过期' });
- return;
- }
- // 将响应头信息附加到返回数据中
- const responseData = {
- data: res.data,
- };
- resolve(responseData);
- } else {
- reject(res);
- }
- },
- fail: (err) => {
- // 清除超时定时器
- if (timeoutTimer) {
- clearTimeout(timeoutTimer)
- }
- // 使用安全的toast显示方法
- loadingManager.safeShowToast({
- title: '网络请求失败',
- icon: 'none'
- })
- reject(err)
- },
- complete: () => {
- // 隐藏 loading
- if (shouldShowLoading) {
- loadingManager.hide()
- }
- // console.log('请求完成');
- }
- })
- })
- }
- }
- // 处理登录过期
- const handleLoginExpired = async () => {
-
- // 获取yhsbToken,有token就自动登录,没有就手动登录
- let userInfo = uni.getStorageSync('userInfo') || {};
- if(typeof userInfo === 'string'){
- userInfo = JSON.parse(userInfo);
- }
- let yhsbToken = userInfo.yhsbToken;
-
- console.log('🔒 处理登录过期 request.js:',userInfo);
- if (yhsbToken) {
- // 自动登录不需要wechatCode,直接用yhsbToken
- console.log('🔄 有token,跳转自动登录');
- uni.navigateTo({
- url: `/pages/common/webview?dest=autoLogin&title=自动登录&from=expired&yhsbToken=${yhsbToken}`
- });
- } else {
- // 手动登录需要获取wechatCode
- console.log('⚠️ 无token,获取微信授权码并跳转手动登录');
- try {
- // 获取微信授权码
- const loginRes = await uni.login({
- provider: 'weixin'
- });
- console.log('获取到微信授权码:', loginRes.code);
- uni.navigateTo({
- url: `/pages/common/webview?dest=login&title=登录&from=expired&wechatCode=${loginRes.code}`
- });
- } catch (error) {
- console.error('获取微信授权码失败:', error);
- // 降级处理:不传wechatCode
- uni.navigateTo({
- url: '/pages/common/webview?dest=login&title=登录&from=expired'
- });
- }
- }
- };
- // 添加一些便捷方法
- request.loadingManager = loadingManager
- // 静默请求(不显示 loading)
- request.silent = {
- get: (url, params = {}) => request.get(url, params, { loading: false }),
- post: (url, data = {}) => request.post(url, data, { loading: false }),
- put: (url, data = {}) => request.put(url, data, { loading: false }),
- delete: (url, data = {}) => request.delete(url, data, { loading: false })
- }
- // 带自定义 loading 文字的请求
- request.withLoading = (title) => ({
- get: (url, params = {}) => request.get(url, params, { loading: { title } }),
- post: (url, data = {}) => request.post(url, data, { loading: { title } }),
- put: (url, data = {}) => request.put(url, data, { loading: { title } }),
- delete: (url, data = {}) => request.delete(url, data, { loading: { title } })
- })
- export default request
|