全局自动loading管理

This commit is contained in:
minimaxagent1 2025-08-02 14:03:12 +08:00
parent ce6ee8413d
commit 092c2e6b9b
13 changed files with 205 additions and 157 deletions

View File

@ -16,7 +16,5 @@ import { get, post } from '@/utils/request'
* @returns {Promise} 返回捐款记录列表 * @returns {Promise} 返回捐款记录列表
*/ */
export function getDonorList(params) { export function getDonorList(params) {
return get('/app/donor/listDonor', params, { return get('/app/donor/listDonor', params)
showLoading: false // 使用页面级别的loading管理
})
} }

View File

@ -18,9 +18,7 @@ export function getInstitutionalList(params = {}) {
isAsc: 'descending' isAsc: 'descending'
} }
return get('/app/formed/listFormed', { ...defaultParams, ...params }, { return get('/app/formed/listFormed', { ...defaultParams, ...params })
showLoading: false // 使用页面级别的loading管理
})
} }
/** /**

View File

@ -7,9 +7,7 @@ import { get, put, del } from '@/utils/request'
* @returns {Promise} 返回建制详情 * @returns {Promise} 返回建制详情
*/ */
export function getInstitutionalDetail(formedId) { export function getInstitutionalDetail(formedId) {
return get('/app/formed/formedDetail', { formedId }, { return get('/app/formed/formedDetail', { formedId })
showLoading: false // 使用页面级别的loading管理
})
} }
/** /**

View File

@ -6,7 +6,5 @@ import { get } from '@/utils/request.js'
* @returns {Promise} * @returns {Promise}
*/ */
export function getMonkList(params = {}) { export function getMonkList(params = {}) {
return get('/app/monk/listMonk', params, { return get('/app/monk/listMonk', params)
showLoading: false // 使用页面级别的loading管理
})
} }

View File

@ -9,9 +9,7 @@ import { get, post, put, del } from '../../utils/request.js';
* @returns {Promise} 返回高僧详情数据 * @returns {Promise} 返回高僧详情数据
*/ */
export function getMonkDetail(monkId) { export function getMonkDetail(monkId) {
return get('/app/monk/monkById', { monkId }, { return get('/app/monk/monkById', { monkId });
showLoading: false // 使用页面级别的loading管理
});
} }
/** /**
@ -27,8 +25,6 @@ export function getMonkList(params = {}) {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
...params ...params
}, {
showLoading: false // 使用页面级别的loading管理
}); });
} }

View File

@ -51,7 +51,6 @@ import ProjectInfo from "./components/project-info.vue";
import DonationSummary from "./components/donation-summary.vue"; import DonationSummary from "./components/donation-summary.vue";
import DonationList from "./components/donation-list.vue"; import DonationList from "./components/donation-list.vue";
import { donationMixin } from "./mixins/donation-mixin.js"; import { donationMixin } from "./mixins/donation-mixin.js";
import { PageLoadingManager } from "../../utils/request.js";
export default { export default {
mixins: [donationMixin], mixins: [donationMixin],
@ -70,19 +69,10 @@ export default {
} }
}, },
onLoad(options) { onLoad(options) {
// loading
this.pageLoading = new PageLoadingManager()
// //
if (options.formedId) { if (options.formedId) {
this.initData(options.formedId) this.initData(options.formedId)
} }
},
onUnload() {
// loading
if (this.pageLoading) {
this.pageLoading.destroy()
}
} }
} }
</script> </script>

View File

@ -37,7 +37,6 @@ import StatusDisplay from "../../components/status-display/status-display.vue";
import { InstitutionalDataFormatter } from "./utils/data-formatter.js"; import { InstitutionalDataFormatter } from "./utils/data-formatter.js";
import { dataManagerMixin } from "./mixins/data-manager.js"; import { dataManagerMixin } from "./mixins/data-manager.js";
import CommonEnum from "../../enum/common"; import CommonEnum from "../../enum/common";
import { PageLoadingManager } from "../../utils/request.js";
export default { export default {
mixins: [dataManagerMixin], mixins: [dataManagerMixin],
@ -58,27 +57,14 @@ export default {
} }
}, },
onLoad() { onLoad() {
// loading
this.pageLoading = new PageLoadingManager()
// //
this.getInstitutionalData() this.getInstitutionalData()
}, },
onUnload() {
// loading
if (this.pageLoading) {
this.pageLoading.destroy()
}
},
methods: { methods: {
// //
async getInstitutionalData(isLoadMore = false) { async getInstitutionalData(isLoadMore = false) {
console.log('开始获取建制数据, isLoadMore:', isLoadMore) console.log('开始获取建制数据, isLoadMore:', isLoadMore)
// loading
if (this.pageLoading && !isLoadMore) {
this.pageLoading.show('努力加载中~')
}
try { try {
const result = await this.fetchData( const result = await this.fetchData(
isLoadMore, isLoadMore,
@ -95,12 +81,6 @@ export default {
title: '获取数据失败', title: '获取数据失败',
icon: 'none' icon: 'none'
}) })
} finally {
// loading
if (this.pageLoading && !isLoadMore) {
this.pageLoading.hide()
console.log('页面loading已隐藏')
}
} }
}, },

View File

@ -26,7 +26,7 @@ export const dataManagerMixin = {
async fetchData(isLoadMore = false, apiCall, dataTransformer) { async fetchData(isLoadMore = false, apiCall, dataTransformer) {
// 只在加载更多时设置loading状态初始加载使用页面级别loading // 只在加载更多时设置loading状态初始加载使用页面级别loading
if (isLoadMore) { if (isLoadMore) {
this.loading = true this.loading = true
} }
try { try {
@ -69,7 +69,7 @@ export const dataManagerMixin = {
} finally { } finally {
// 只在加载更多时清除loading状态 // 只在加载更多时清除loading状态
if (isLoadMore) { if (isLoadMore) {
this.loading = false this.loading = false
} }
} }
}, },

View File

@ -217,11 +217,6 @@ export const donationMixin = {
async initData(formedId) { async initData(formedId) {
console.log('初始化捐款记录数据, formedId:', formedId) console.log('初始化捐款记录数据, formedId:', formedId)
// 显示页面loading
if (this.pageLoading) {
this.pageLoading.show('努力加载中~')
}
try { try {
this.formedId = formedId this.formedId = formedId
await this.loadProjectInfo() await this.loadProjectInfo()
@ -233,12 +228,6 @@ export const donationMixin = {
title: '初始化数据失败', title: '初始化数据失败',
icon: 'none' icon: 'none'
}) })
} finally {
// 隐藏页面loading
if (this.pageLoading) {
this.pageLoading.hide()
console.log('页面loading已隐藏')
}
} }
} }
} }

View File

@ -88,7 +88,7 @@ import { forceHideLoading, PageLoadingManager } from "../../utils/request.js";
}); });
// //
setTimeout(() => { setTimeout(() => {
that.ceshi() that.ceshi()
}, 1500); }, 1500);
} else { } else {
// //

View File

@ -50,7 +50,6 @@ import MonkEnum from "../../enum/monk";
import {getMonkDetail} from "../../api/monk/monkDetail.js"; import {getMonkDetail} from "../../api/monk/monkDetail.js";
import CustomNavbar from "../../components/custom-navbar/custom-navbar.vue"; import CustomNavbar from "../../components/custom-navbar/custom-navbar.vue";
import BaseBackground from "../../components/base-background/base-background.vue"; import BaseBackground from "../../components/base-background/base-background.vue";
import { PageLoadingManager } from "../../utils/request.js";
export default { export default {
components: { components: {
@ -73,20 +72,11 @@ export default {
} }
}, },
onLoad(options) { onLoad(options) {
// loading
this.pageLoading = new PageLoadingManager()
// //
if (options.id) { if (options.id) {
this.fetchMonkDetail(options.id); this.fetchMonkDetail(options.id);
} }
}, },
onUnload() {
// loading
if (this.pageLoading) {
this.pageLoading.destroy()
}
},
methods: { methods: {
// //
switchTab(index) { switchTab(index) {
@ -96,11 +86,6 @@ export default {
async fetchMonkDetail(monkId) { async fetchMonkDetail(monkId) {
console.log('开始获取高僧详情, monkId:', monkId) console.log('开始获取高僧详情, monkId:', monkId)
// loading
if (this.pageLoading) {
this.pageLoading.show('努力加载中~')
}
try { try {
const res = await getMonkDetail(monkId); const res = await getMonkDetail(monkId);
console.log('高僧详情API响应:', res) console.log('高僧详情API响应:', res)
@ -123,12 +108,6 @@ export default {
title: '网络错误', title: '网络错误',
icon: 'none' icon: 'none'
}); });
} finally {
// loading
if (this.pageLoading) {
this.pageLoading.hide()
console.log('页面loading已隐藏')
}
} }
}, },
// //

View File

@ -0,0 +1,119 @@
<template>
<view class="simple-loading-demo">
<view class="demo-section">
<text class="section-title">简化Loading使用示例</text>
<text class="description">现在所有API调用都会自动显示loading无需手动管理</text>
<button @click="testAutoLoading" class="demo-btn">测试自动Loading</button>
<button @click="testNoLoading" class="demo-btn">测试无Loading</button>
<button @click="testMultipleRequests" class="demo-btn">测试多个请求</button>
</view>
<view class="result-section">
<text class="section-title">测试结果</text>
<text class="result-text">{{ testResult }}</text>
</view>
</view>
</template>
<script>
import { get } from '@/utils/request.js'
export default {
data() {
return {
testResult: ''
}
},
methods: {
// loading
async testAutoLoading() {
try {
this.testResult = '正在测试自动loading...'
// loading
const result = await get('/app/monk/listMonk', { pageNum: 1, pageSize: 5 })
this.testResult = `自动loading测试成功:\n${JSON.stringify(result, null, 2)}`
} catch (error) {
this.testResult = `自动loading测试失败: ${error.message}`
}
},
// loading
async testNoLoading() {
try {
this.testResult = '正在测试无loading...'
// loading
const result = await get('/app/monk/listMonk', { pageNum: 1, pageSize: 5 }, {
showLoading: false
})
this.testResult = `无loading测试成功:\n${JSON.stringify(result, null, 2)}`
} catch (error) {
this.testResult = `无loading测试失败: ${error.message}`
}
},
//
async testMultipleRequests() {
try {
this.testResult = '正在测试多个并发请求...'
// loading
const promises = [
get('/app/monk/listMonk', { pageNum: 1, pageSize: 3 }),
get('/app/formed/listFormed', { pageNum: 1, pageSize: 3 }),
get('/app/donor/listDonor', { formedId: '1', pageNum: 1, pageSize: 3 })
]
const results = await Promise.all(promises)
this.testResult = `多个请求测试成功:\n${JSON.stringify(results, null, 2)}`
} catch (error) {
this.testResult = `多个请求测试失败: ${error.message}`
}
}
}
}
</script>
<style lang="scss">
.simple-loading-demo {
padding: 40rpx;
}
.demo-section {
margin-bottom: 40rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
display: block;
}
.description {
font-size: 28rpx;
color: #666;
margin-bottom: 30rpx;
display: block;
line-height: 1.5;
}
.demo-btn {
margin: 20rpx 0;
padding: 20rpx;
background-color: #007aff;
color: white;
border-radius: 10rpx;
}
.result-section {
margin-top: 40rpx;
}
.result-text {
font-size: 24rpx;
color: #666;
word-break: break-all;
white-space: pre-wrap;
}
</style>

View File

@ -32,9 +32,10 @@ const getCurrentConfig = () => {
const config = getCurrentConfig() const config = getCurrentConfig()
const BASE_URL = config.baseUrl const BASE_URL = config.baseUrl
// 全局loading状态管理 // 全局自动loading管理
let isLoading = false let isLoading = false
let loadingTimer = null let loadingTimer = null
let loadingCount = 0 // 请求计数器
// 设置loading超时自动清除 // 设置loading超时自动清除
const setLoadingTimeout = () => { const setLoadingTimeout = () => {
@ -134,6 +135,7 @@ function handleResponseError(res, reject, options = {}) {
*/ */
function showLoading(text = config.loadingText) { function showLoading(text = config.loadingText) {
try { try {
loadingCount++
if (!isLoading) { if (!isLoading) {
isLoading = true isLoading = true
uni.showLoading({ uni.showLoading({
@ -153,6 +155,10 @@ function showLoading(text = config.loadingText) {
*/ */
function hideLoading() { function hideLoading() {
try { try {
loadingCount--
if (loadingCount > 0) {
return // 还有其他请求在进行
}
if (isLoading) { if (isLoading) {
isLoading = false isLoading = false
// 清除超时定时器 // 清除超时定时器
@ -176,7 +182,7 @@ function hideLoading() {
* @param {Object} options.data - 请求体数据 * @param {Object} options.data - 请求体数据
* @param {Object} options.header - 请求头 * @param {Object} options.header - 请求头
* @param {number} options.timeout - 超时时间 * @param {number} options.timeout - 超时时间
* @param {boolean} options.showLoading - 是否显示加载状态 * @param {boolean} options.showLoading - 是否显示加载状态默认true
* @param {string} options.loadingText - 加载提示文字 * @param {string} options.loadingText - 加载提示文字
* @param {boolean} options.noToken - 是否需要token * @param {boolean} options.noToken - 是否需要token
* @returns {Promise} 返回请求结果 * @returns {Promise} 返回请求结果
@ -237,12 +243,14 @@ export function request(options = {}) {
originalUrl: options.url originalUrl: options.url
}) })
// 根据错误类型显示不同的提示 // 网络错误处理
let errorMessage = '网络错误' let errorMessage = '网络错误'
if (err.errMsg && err.errMsg.includes('invalid url')) { if (err.errMsg) {
errorMessage = '请求地址无效' if (err.errMsg.includes('timeout')) {
} else if (err.errMsg && err.errMsg.includes('timeout')) { errorMessage = '请求超时'
errorMessage = '请求超时' } else if (err.errMsg.includes('fail')) {
errorMessage = '网络连接失败'
}
} }
uni.showToast({ uni.showToast({
@ -250,31 +258,27 @@ export function request(options = {}) {
icon: 'none', icon: 'none',
duration: 2000 duration: 2000
}) })
reject(err) reject(err)
} }
} }
// 特殊接口处理 // 特殊接口处理不需要token的接口
if (url === '/login/login' || url === '/wxLogin' || url === '/user/login') { const noTokenUrls = ['/wxLogin', '/user/login']
requestOptions.header.noToken = true if (noTokenUrls.includes(url) || options.noToken) {
delete requestOptions.header.Authorization
console.log('跳过token验证的接口:', url)
} }
// 添加参数 // 处理请求参数
if (options.params) { if (options.params && Object.keys(options.params).length > 0) {
requestOptions.data = options.params requestOptions.data = options.params
} }
if (options.data) { if (options.data && Object.keys(options.data).length > 0) {
requestOptions.data = options.data requestOptions.data = options.data
} }
// 显示加载状态
if (options.showLoading !== false) {
setTimeout(() => {
showLoading(options.loadingText || config.loadingText)
}, config.loadingTime)
}
// 发起请求 // 发起请求
console.log('发起请求:', { console.log('发起请求:', {
url: requestOptions.url, url: requestOptions.url,
@ -284,6 +288,12 @@ export function request(options = {}) {
timeout: requestOptions.timeout, timeout: requestOptions.timeout,
baseUrl: BASE_URL baseUrl: BASE_URL
}) })
// 显示loading默认显示但减少延迟
if (options.showLoading !== false) {
showLoading(options.loadingText || config.loadingText)
}
uni.request(requestOptions) uni.request(requestOptions)
}) })
} }
@ -292,7 +302,7 @@ export function request(options = {}) {
* GET请求 * GET请求
* @param {string} url - 请求地址 * @param {string} url - 请求地址
* @param {Object} params - 查询参数 * @param {Object} params - 查询参数
* @param {Object} options - 请求选项 * @param {Object} options - 请求配置
* @returns {Promise} 返回请求结果 * @returns {Promise} 返回请求结果
*/ */
export function get(url, params = {}, options = {}) { export function get(url, params = {}, options = {}) {
@ -308,7 +318,7 @@ export function get(url, params = {}, options = {}) {
* POST请求 * POST请求
* @param {string} url - 请求地址 * @param {string} url - 请求地址
* @param {Object} data - 请求体数据 * @param {Object} data - 请求体数据
* @param {Object} options - 请求选项 * @param {Object} options - 请求配置
* @returns {Promise} 返回请求结果 * @returns {Promise} 返回请求结果
*/ */
export function post(url, data = {}, options = {}) { export function post(url, data = {}, options = {}) {
@ -324,7 +334,7 @@ export function post(url, data = {}, options = {}) {
* PUT请求 * PUT请求
* @param {string} url - 请求地址 * @param {string} url - 请求地址
* @param {Object} data - 请求体数据 * @param {Object} data - 请求体数据
* @param {Object} options - 请求选项 * @param {Object} options - 请求配置
* @returns {Promise} 返回请求结果 * @returns {Promise} 返回请求结果
*/ */
export function put(url, data = {}, options = {}) { export function put(url, data = {}, options = {}) {
@ -339,7 +349,7 @@ export function put(url, data = {}, options = {}) {
/** /**
* DELETE请求 * DELETE请求
* @param {string} url - 请求地址 * @param {string} url - 请求地址
* @param {Object} options - 请求选项 * @param {Object} options - 请求配置
* @returns {Promise} 返回请求结果 * @returns {Promise} 返回请求结果
*/ */
export function del(url, options = {}) { export function del(url, options = {}) {
@ -352,15 +362,16 @@ export function del(url, options = {}) {
/** /**
* 设置请求配置 * 设置请求配置
* @param {Object} newConfig - 新的配置对象 * @param {Object} newConfig - 新的配置
*/ */
export function setRequestConfig(newConfig) { export function setRequestConfig(newConfig) {
Object.assign(config, newConfig) Object.assign(config, newConfig)
console.log('更新请求配置:', config)
} }
/** /**
* 获取当前配置 * 获取请求配置
* @returns {Object} 当前配置对象 * @returns {Object} 当前配置
*/ */
export function getRequestConfig() { export function getRequestConfig() {
return { ...config } return { ...config }
@ -371,7 +382,7 @@ export function getRequestConfig() {
*/ */
export function clearToken() { export function clearToken() {
uni.removeStorageSync('token') uni.removeStorageSync('token')
uni.removeStorageSync('refreshToken') console.log('Token已清除')
} }
/** /**
@ -380,6 +391,7 @@ export function clearToken() {
*/ */
export function setToken(token) { export function setToken(token) {
uni.setStorageSync('token', token) uni.setStorageSync('token', token)
console.log('Token已设置')
} }
/** /**
@ -391,91 +403,82 @@ export function getToken() {
} }
/** /**
* 强制清除loading状态 * 强制隐藏loading
*/ */
export function forceHideLoading() { export function forceHideLoading() {
isLoading = false
// 清除超时定时器
if (loadingTimer) {
clearTimeout(loadingTimer)
loadingTimer = null
}
try { try {
isLoading = false
loadingCount = 0
if (loadingTimer) {
clearTimeout(loadingTimer)
loadingTimer = null
}
uni.hideLoading() uni.hideLoading()
} catch (error) { } catch (error) {
console.warn('强制清除loading失败:', error) console.warn('强制隐藏loading失败:', error)
} }
} }
/** /**
* 初始化全局loading管理 * 初始化全局loading管理
*/ */
export function initGlobalLoadingManager() { export function initGlobalLoadingManager() {
// 监听页面显示事件 // 监听页面显示事件
uni.$on('page-show', () => { uni.$on('page-show', () => {
forceHideLoading() console.log('页面显示检查loading状态')
// 页面显示时检查loading状态如果超时则清除
if (isLoading && loadingTimer) {
const remainingTime = 30000 - (Date.now() - (loadingTimer._startTime || Date.now()))
if (remainingTime <= 0) {
console.warn('页面显示时发现超时loading强制清除')
forceHideLoading()
}
}
}) })
// 监听页面隐藏事件 // 监听页面隐藏事件
uni.$on('page-hide', () => { uni.$on('page-hide', () => {
forceHideLoading() console.log('页面隐藏')
}) })
// 监听应用进入前台 // 监听应用显示事件
uni.$on('app-show', () => { uni.$on('app-show', () => {
forceHideLoading() console.log('应用显示')
}) })
// 监听应用进入后台 // 监听应用隐藏事件
uni.$on('app-hide', () => { uni.$on('app-hide', () => {
console.log('应用隐藏清除loading')
forceHideLoading() forceHideLoading()
}) })
console.log('全局loading管理器已初始化') console.log('全局loading管理器已初始化')
} }
/** // 简化的自动loading管理类
* 页面级别的loading管理 export class AutoLoadingManager {
*/
export class PageLoadingManager {
constructor() { constructor() {
this.isLoading = false this.isActive = false
this.timer = null
} }
// 显示loading可选
show(text = '加载中...') { show(text = '加载中...') {
this.hide() // 先清除之前的loading this.isActive = true
this.isLoading = true // 这里可以选择是否显示额外的loading
try { // 默认情况下所有API调用都会自动显示loading
uni.showLoading({
title: text,
mask: true
})
// 设置超时
this.timer = setTimeout(() => {
console.warn('页面Loading超时强制清除')
this.hide()
}, 30000)
} catch (error) {
console.warn('显示页面loading失败:', error)
}
} }
// 隐藏loading可选
hide() { hide() {
this.isLoading = false this.isActive = false
if (this.timer) { // 这里可以选择是否手动隐藏loading
clearTimeout(this.timer) // 默认情况下API调用完成后会自动隐藏loading
this.timer = null
}
try {
uni.hideLoading()
} catch (error) {
console.warn('隐藏页面loading失败:', error)
}
} }
// 页面卸载时清理 // 销毁管理器
destroy() { destroy() {
this.hide() this.isActive = false
// 页面卸载时可以选择是否强制清除loading
// forceHideLoading()
} }
} }