shinnosuke
2026-08-28 02e8805610f2f267d21ecaca235c37a349e11eab
fix: refresh usage records and paginate benefit search
2个文件已修改
115 ■■■■■ 已修改文件
rencaika/pages/benefit-search/benefit-search.uvue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rencaika/pages/order/order.uvue 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rencaika/pages/benefit-search/benefit-search.uvue
@@ -16,7 +16,7 @@
            </view>
        </view>
        <scroll-view class="page-scroll" scroll-y="true" :show-scrollbar="false" lower-threshold="80" @scrolltolower="loadMoreMerchants">
        <scroll-view class="page-scroll" scroll-y="true" :show-scrollbar="false" lower-threshold="200" @scrolltolower="loadMoreMerchants">
            <view v-if="!isAllMode && !hasSearched" class="history-section">
                <view class="history-head">
                    <text>搜索历史</text>
@@ -47,6 +47,7 @@
                <view v-else-if="hasLoaded" class="result-empty"><text>暂未搜索到相关店铺</text></view>
                <view v-if="loadingMore" class="loading-row"><view class="loading-spinner"></view><text>正在加载</text></view>
                <view v-else-if="loadMoreError" class="loading-row load-error" @tap="retryLoadMore"><text>加载失败,点击重试</text></view>
                <view v-else-if="hasLoaded && hasMore && visibleMerchants.length > 0" class="load-more-action" @tap="loadMoreMerchants"><text>加载更多商家</text></view>
                <view v-else-if="hasLoaded && !hasMore && visibleMerchants.length > 0" class="no-more"><view></view><text>已经到底了</text><view></view></view>
                <view class="list-bottom"></view>
            </view>
@@ -70,7 +71,7 @@
    const keyword = ref('')
    const hasSearched = ref(false)
    const isAllMode = ref(false)
    const pageSize = 6
    const pageSize = 10
    const allModePageSize = 100
    const talentId = ref('')
    const merchantPool = ref([])
@@ -166,8 +167,10 @@
            visibleMerchants.value = next
            merchantPool.value = next
            loadedCount.value = next.length
            currentPage.value = currentPage.value + 1
            hasMore.value = data != null && data.total != null ? next.length < data.total : false
            const responsePage = data != null && data.page != null ? Number(data.page) : currentPage.value + 1
            const total = data != null && data.total != null ? Number(data.total) : -1
            currentPage.value = responsePage > 0 ? responsePage : currentPage.value + 1
            hasMore.value = records.length > 0 && (total >= 0 ? next.length < total : records.length >= requestSize)
            initialLoading.value = false
            loadingMore.value = false
            hasLoaded.value = true
@@ -430,6 +433,8 @@
    .loading-spinner { width: 28rpx; height: 28rpx; margin-right: 13rpx; box-sizing: border-box; border-width: 3rpx; border-style: solid; border-color: #FFD6C4; border-top-color: #FF6C2B; border-radius: 50%; animation: merchant-loading 720ms linear infinite; }
    .loading-row text { color: #989DA5; font-size: 22rpx; }
    .load-error text { color: #F26A38; }
    .load-more-action { display: flex; height: 90rpx; justify-content: center; align-items: center; }
    .load-more-action text { color: #F26A38; font-size: 23rpx; }
    .no-more { display: flex; height: 90rpx; flex-direction: row; justify-content: center; align-items: center; }
    .no-more view { width: 70rpx; height: 1rpx; background-color: #E7E7E7; }
    .no-more text { margin: 0 18rpx; color: #B1B3B7; font-size: 21rpx; }
rencaika/pages/order/order.uvue
@@ -12,7 +12,9 @@
            </view>
        </view>
        <scroll-view class="record-scroll" scroll-y="true" show-scrollbar="false" lower-threshold="80" @scrolltolower="loadMoreRecords">
        <scroll-view class="record-scroll" scroll-y="true" show-scrollbar="false" lower-threshold="80"
            refresher-enabled="true" :refresher-triggered="refreshing" refresher-background="#F4F6F9"
            @refresherrefresh="handlePullDownRefresh" @refresherabort="finishPullRefresh" @scrolltolower="loadMoreRecords">
            <view v-if="initialLoading" class="empty-state"><view class="loading-spinner"></view><text class="empty-title">正在加载使用记录</text></view>
            <view v-else-if="initialError" class="empty-state"><text class="empty-title">使用记录加载失败</text><text class="retry-text" @tap="retryInitialLoad">重新加载</text></view>
            <view v-else-if="hasLoaded && visibleRecords.length == 0" class="empty-state"><text class="empty-title">暂无相关使用记录</text><text class="empty-desc">切换其他状态查看记录</text></view>
@@ -52,6 +54,7 @@
    ]
    const activeStatus = ref('')
    const pageSize = 8
    const autoRefreshInterval = 15000
    const currentPage = ref(1)
    const talentId = ref('')
    const isPreviewMember = ref(false)
@@ -61,10 +64,16 @@
    const hasMore = ref(true)
    const initialError = ref(false)
    const loadMoreError = ref(false)
    const refreshing = ref(false)
    const failInitialOnce = ref(false)
    const failLoadMoreOnce = ref(false)
    const listRequestVersion = ref(0)
    const visibleRecords = ref([])
    let cancelRecordsRequest: (() => void) | null = null
    let autoRefreshTimer = 0
    let hasShown = false
    let pageVisible = false
    let refreshInProgress = false
    const getMerchantIcon = (merchantType: string) => {
        if (merchantType == 'food') return '/static/order-assets/utensils.svg'
@@ -169,16 +178,54 @@
        }
        resetRecords()
    })
    onShow(() => {
        pageVisible = true
        if (hasShown) refreshRecords(false)
        else hasShown = true
        startAutoRefresh()
    })
    onHide(() => {
        pageVisible = false
        stopAutoRefresh()
    })
    onUnload(() => {
        pageVisible = false
        refreshInProgress = false
        stopAutoRefresh()
        listRequestVersion.value = listRequestVersion.value + 1
        cancelActiveRequest()
    })
    const cancelActiveRequest = () => {
        if (cancelRecordsRequest == null) return
        cancelRecordsRequest()
        cancelRecordsRequest = null
    }
    const stopAutoRefresh = () => {
        if (autoRefreshTimer == 0) return
        clearInterval(autoRefreshTimer)
        autoRefreshTimer = 0
    }
    const startAutoRefresh = () => {
        stopAutoRefresh()
        if (talentId.value == '') return
        autoRefreshTimer = setInterval(() => {
            if (pageVisible) refreshRecords(false)
        }, autoRefreshInterval)
    }
    const resetRecords = () => {
        const requestVersion = listRequestVersion.value + 1
        listRequestVersion.value = requestVersion
        cancelActiveRequest()
        currentPage.value = 1
        initialLoading.value = true
        initialError.value = false
        loadMoreError.value = false
        hasLoaded.value = false
        loadingMore.value = false
        refreshing.value = false
        refreshInProgress = false
        visibleRecords.value = []
        hasMore.value = true
        if (failInitialOnce.value) {
@@ -187,11 +234,12 @@
            initialError.value = true
            return
        }
        requestRecords(requestVersion, 1, true)
        requestRecords(requestVersion, 1, pageSize, true)
    }
    const requestRecords = (requestVersion: number, page: number, initial: boolean) => {
        getUsageRecords(talentId.value, activeStatus.value, page, pageSize, (data: any) => {
    const requestRecords = (requestVersion: number, page: number, size: number, initial: boolean) => {
        cancelRecordsRequest = getUsageRecords(talentId.value, activeStatus.value, page, size, (data: any) => {
            if (requestVersion != listRequestVersion.value) return
            cancelRecordsRequest = null
            const sourceRecords: any[] = data != null && data.records instanceof Array ? data.records as any[] : []
            const records: any[] = []
            for (let index = 0; index < sourceRecords.length; index++) records.push(mapRecord(sourceRecords[index]))
@@ -209,6 +257,7 @@
            hasLoaded.value = true
        }, (error: any) => {
            if (requestVersion != listRequestVersion.value) return
            cancelRecordsRequest = null
            initialLoading.value = false
            loadingMore.value = false
            if (error != null && error.statusCode == 401) {
@@ -220,6 +269,47 @@
            else loadMoreError.value = true
        })
    }
    const refreshRecords = (fromPullDown: boolean) => {
        if (talentId.value == '' || initialLoading.value || loadingMore.value || refreshInProgress) {
            if (fromPullDown) refreshing.value = false
            return
        }
        const requestVersion = listRequestVersion.value + 1
        listRequestVersion.value = requestVersion
        cancelActiveRequest()
        refreshInProgress = true
        refreshing.value = fromPullDown
        loadMoreError.value = false
        const refreshSize = Math.min(48, Math.max(pageSize, currentPage.value * pageSize))
        cancelRecordsRequest = getUsageRecords(talentId.value, activeStatus.value, 1, refreshSize, (data: any) => {
            if (requestVersion != listRequestVersion.value) return
            cancelRecordsRequest = null
            refreshInProgress = false
            const sourceRecords: any[] = data != null && data.records instanceof Array ? data.records as any[] : []
            const records: any[] = []
            for (let index = 0; index < sourceRecords.length; index++) records.push(mapRecord(sourceRecords[index]))
            visibleRecords.value = records
            const total = data != null && data.total != null ? Number(data.total) : records.length
            currentPage.value = Math.max(1, Math.ceil(records.length / pageSize))
            hasMore.value = records.length < total
            initialError.value = false
            hasLoaded.value = true
            refreshing.value = false
        }, (error: any) => {
            if (requestVersion != listRequestVersion.value) return
            cancelRecordsRequest = null
            refreshInProgress = false
            refreshing.value = false
            if (error != null && error.statusCode == 401) {
                clearSession()
                uni.reLaunch({ url: '/pages/login/login' })
                return
            }
            if (fromPullDown) uni.showToast({ title: '刷新失败,请稍后重试', icon: 'none' })
        })
    }
    const handlePullDownRefresh = () => refreshRecords(true)
    const finishPullRefresh = () => { refreshing.value = false }
    const retryInitialLoad = () => resetRecords()
    const retryLoadMore = () => loadMoreRecords()
    const changeTab = (name: string) => {
@@ -228,7 +318,7 @@
        resetRecords()
    }
    const loadMoreRecords = () => {
        if (initialLoading.value || loadingMore.value || !hasMore.value) return
        if (initialLoading.value || loadingMore.value || refreshInProgress || !hasMore.value) return
        const requestVersion = listRequestVersion.value
        loadMoreError.value = false
        loadingMore.value = true
@@ -238,7 +328,7 @@
            loadMoreError.value = true
            return
        }
        requestRecords(requestVersion, currentPage.value + 1, false)
        requestRecords(requestVersion, currentPage.value + 1, pageSize, false)
    }
    const goBack = () => {
        const previewQuery = isPreviewMember.value ? '?preview=member&talentId=' + encodeURIComponent(talentId.value) : ''