diff --git a/pages/myTicketsDetail/index.vue b/pages/myTicketsDetail/index.vue index f118b7d..e721e69 100644 --- a/pages/myTicketsDetail/index.vue +++ b/pages/myTicketsDetail/index.vue @@ -111,7 +111,7 @@ @@ -154,6 +155,12 @@ tempImagePaths: [] // 临时存储上传的图片路径 }; }, + computed: { + showWithdrawButton() { + // 使用数组includes方法简化条件判断 + return [1, 2, 99].includes(this.detailObj.status); + } + }, mounted() { let obj = uni.getStorageSync("Detail"); this.detailObj = {...obj}; @@ -249,6 +256,7 @@ }); }, + // 修改/保存操作 async handleModify() { if (!this.isEditing) { @@ -300,7 +308,11 @@ uni.showToast({ title: '修改成功', - icon: 'success' + icon: 'success', + success: () => { + // 修改成功后跳转到列表页 + this.redirectToList(); + } }); this.isEditing = false; @@ -343,7 +355,11 @@ if (res && res.success) { uni.showToast({ title: '撤回成功', - icon: 'success' + icon: 'success', + success: () => { + // 撤回成功后跳转到列表页 + this.redirectToList(); + } }); } else { uni.showToast({ @@ -351,6 +367,12 @@ icon: 'none' }); } + }, + // 跳转到列表页 + redirectToList() { + uni.redirectTo({ + url: '/pages/myTickets/index' + }); } } }; diff --git a/pages/serviceNoticeList/index.vue b/pages/serviceNoticeList/index.vue index abf7c7d..a706ae1 100644 --- a/pages/serviceNoticeList/index.vue +++ b/pages/serviceNoticeList/index.vue @@ -5,13 +5,29 @@ + + + + + + + + + + + + + + mode="aspectFill" + lazy-load + :show-menu-by-longpress="true" + @error="handleImageError(index)"> {{item.title}} @@ -22,8 +38,13 @@ + + + {{isLoading ? '加载中...' : '上拉加载更多'}} + + - + 暂无公告 @@ -49,45 +70,102 @@ formatTime, IMAGE_BASE_URL, noticesList: [], + cachedNotices: uni.getStorageSync('cachedNotices') || [], isLoading: false, currentPage: 1, - totalPages: 1 + totalPages: 1, + lastRequestTime: 0 }; }, mounted() { this.getNotices(); + this.initScrollListener(); + }, + beforeDestroy() { + this.removeScrollListener(); }, methods: { async getNotices() { - if (this.isLoading) return; + // 防止重复请求 + const now = Date.now(); + if (this.isLoading || (now - this.lastRequestTime < 1000)) return; + this.lastRequestTime = now; + + // 第一页尝试使用缓存 + if (this.currentPage === 1 && this.cachedNotices.length > 0) { + this.noticesList = [...this.cachedNotices]; + // 仍然在后台更新数据 + setTimeout(() => this.fetchNotices(), 300); + return; + } + + await this.fetchNotices(); + }, + + async fetchNotices() { this.isLoading = true; + uni.showLoading({ title: '加载中...', mask: true }); try { const res = await get('/api/v1/apps/home/notices', { current: this.currentPage, pageSize: 10, + }, { + timeout: 5000 // 设置超时时间 }); if (res?.success) { const processedData = res.data.map(item => ({ ...item, - cover: item.cover.startsWith('http') ? item.cover : IMAGE_BASE_URL + item.cover + cover: this.processImageUrl(item.cover), + desc: this.filterHtmlTags(item.desc) // 过滤HTML标签防止XSS })); - this.noticesList = [...this.noticesList, ...processedData]; + if (this.currentPage === 1) { + this.noticesList = processedData; + // 缓存第一页数据 + uni.setStorage({ + key: 'cachedNotices', + data: processedData, + expire: 3600 // 1小时缓存 + }); + } else { + this.noticesList = this.noticesList.concat(processedData); + } + this.totalPages = Math.ceil(res.total / 10); } } catch (err) { console.error('获取公告失败:', err); - uni.showToast({ - title: '加载公告失败', - icon: 'none' - }); + if (this.currentPage === 1) { + uni.showToast({ + title: '加载公告失败', + icon: 'none' + }); + } } finally { + uni.hideLoading(); this.isLoading = false; } }, + processImageUrl(url) { + if (!url) return '/static/images/default-cover.jpg'; + return url.startsWith('http') ? url : IMAGE_BASE_URL + url; + }, + + filterHtmlTags(str) { + if (!str) return ''; + return str.replace(/<[^>]+>/g, '').replace(/ /g, ' '); + }, + + handleImageError(index) { + this.$set(this.noticesList, index, { + ...this.noticesList[index], + cover: '/static/images/default-cover.jpg' + }); + }, + goNoticeDetail(id) { uni.navigateTo({ url: `/pages/serviceNoticeDetail/index?Id=${id}`, @@ -95,10 +173,27 @@ }); }, - loadMore() { - if (this.currentPage < this.totalPages) { - this.currentPage++; - this.getNotices(); + initScrollListener() { + this.onScroll = () => { + const scrollHeight = document.documentElement.scrollHeight; + const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; + const clientHeight = document.documentElement.clientHeight; + + // 距离底部200px时加载更多 + if (scrollTop + clientHeight >= scrollHeight - 200 && + this.currentPage < this.totalPages && + !this.isLoading) { + this.currentPage++; + this.getNotices(); + } + }; + + window.addEventListener('scroll', this.onScroll); + }, + + removeScrollListener() { + if (this.onScroll) { + window.removeEventListener('scroll', this.onScroll); } } } @@ -163,6 +258,8 @@ height: 220rpx; flex-shrink: 0; background-color: #f5f5f5; + will-change: transform; + image-rendering: -webkit-optimize-contrast; } .notice-content { @@ -204,6 +301,13 @@ } } + .load-more { + text-align: center; + padding: 30rpx 0; + color: var(--text-light); + font-size: 26rpx; + } + .empty-state { display: flex; flex-direction: column; @@ -223,6 +327,62 @@ color: var(--text-light); } } + + /* 骨架屏样式 */ + .skeleton-wrapper { + display: flex; + flex-direction: column; + gap: 24rpx; + + .skeleton-item { + display: flex; + background: #fff; + border-radius: var(--radius); + overflow: hidden; + height: 220rpx; + + .skeleton-image { + width: 220rpx; + height: 220rpx; + background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 50%, #f2f2f2 75%); + background-size: 400% 100%; + animation: loading 1.5s ease infinite; + } + + .skeleton-content { + flex: 1; + padding: 24rpx; + display: flex; + flex-direction: column; + justify-content: space-between; + + .skeleton-line { + height: 32rpx; + background: #f2f2f2; + border-radius: 8rpx; + margin-bottom: 16rpx; + animation: loading 1.5s ease infinite; + + &.short { + width: 60%; + } + + &.shorter { + width: 40%; + } + } + } + } + } + + @keyframes loading { + 0% { + background-position: 100% 50%; + } + 100% { + background-position: 0 50%; + } + } } } } diff --git a/utils/config.js b/utils/config.js index d0d2290..63ed52e 100644 --- a/utils/config.js +++ b/utils/config.js @@ -1,7 +1,8 @@ export const BASE_URL = 'https://jinshan.nantong.info'; export const IMAGE_BASE_URL = `https://jinshan.nantong.info` export const WS_BASE_URL = `wss://jinshan.nantong.info` - +// export const BASE_URL = 'http://10.10.1.6:8071'; +// export const IMAGE_BASE_URL = `http://10.10.1.6:8071`; // http://36.212.197.253:8071