feat(金币代理收支明细页面): 调整接口并新增上拉加载功能

This commit is contained in:
hzj 2025-12-09 18:37:28 +08:00
parent 2c9c63ca52
commit 60468f1d70
2 changed files with 153 additions and 46 deletions

View File

@ -124,10 +124,17 @@ export function freightRecharge(data) {
* @param {string} data * @param {string} data
* @returns {Promise} 返回交易流水记录 * @returns {Promise} 返回交易流水记录
*/ */
export function getFreightWaterFlow(data) { export const getFreightWaterFlow = async (data) => {
return get( try {
`/wallet/freight/balance/running/water/client/flowByUserId?userId=${data.userId}&type=${data.type}&searchId=${data.searchId}` const response = await get(
) `/wallet/freight/balance/running/water/client/flowByUserId?userId=${data.userId}&type=${data.type}&searchId=${data.searchId}&lastId=${data.lastId}`
)
return response
} catch (error) {
console.error('Failed to fetch bank card list:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
} }
/** /**

View File

@ -55,7 +55,7 @@
v-for="tab in tabs" v-for="tab in tabs"
:key="tab.id" :key="tab.id"
ref="tabItems" ref="tabItems"
@click="switchTab(tab.id)" @click="switchTab(tab)"
:style="{ :style="{
flex: 1, flex: 1,
padding: '8px 16px', padding: '8px 16px',
@ -63,7 +63,7 @@
border: 'none', border: 'none',
fontWeight: '600', fontWeight: '600',
fontSize: '14px', fontSize: '14px',
color: activeTabId === tab.id ? '#8B5CF6' : 'rgba(0, 0, 0, 0.6)', color: selectedTab.id === tab.id ? '#8B5CF6' : 'rgba(0, 0, 0, 0.6)',
cursor: 'pointer', cursor: 'pointer',
transition: 'all 0.3s', transition: 'all 0.3s',
position: 'relative', position: 'relative',
@ -80,7 +80,7 @@
<!-- 用户列表(加载中...) --> <!-- 用户列表(加载中...) -->
<div <div
v-if="loading" v-if="loading && !records.length"
style=" style="
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -125,6 +125,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px;
" "
> >
<!-- 头像 --> <!-- 头像 -->
@ -155,6 +156,7 @@
/> />
</div> </div>
<!-- 个人资料 -->
<div <div
style=" style="
flex: 1; flex: 1;
@ -214,6 +216,18 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 收入列表触发加载功能 -->
<div
ref="incomeLoadmore"
v-show="incomeRecords.length != 0 && selectedTab?.langKey === 'income'"
></div>
<!-- 支出列表触发加载功能 -->
<div
ref="expenditureLoadmore"
v-show="expenditureRecords.length != 0 && selectedTab?.langKey === 'expenditure'"
></div>
</div> </div>
<!-- 用户列表(加载完且列表为空) --> <!-- 用户列表(加载完且列表为空) -->
@ -240,28 +254,46 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, computed } from 'vue' import { ref, onMounted, computed, nextTick } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import GeneralHeader from '@/components/GeneralHeader.vue' import { setDocumentDirection } from '@/locales/i18n'
import { getFreightWaterFlow } from '@/api/wallet.js'
import { formatUTCCustom } from '@/utils/utcFormat.js' import { formatUTCCustom } from '@/utils/utcFormat.js'
import { getUserId } from '@/utils/userStore.js' import { getUserId } from '@/utils/userStore.js'
import { setDocumentDirection } from '@/locales/i18n'
import { handleAvatarImageError } from '@/utils/imageHandler.js' import { handleAvatarImageError } from '@/utils/imageHandler.js'
import { useDebounce, useThrottle } from '@/utils/useDebounce'
import { getFreightWaterFlow } from '@/api/wallet.js'
import GeneralHeader from '@/components/GeneralHeader.vue'
const { t, locale } = useI18n() const { t, locale } = useI18n()
// //
locale.value && setDocumentDirection(locale.value) locale.value && setDocumentDirection(locale.value)
const userId = ref(getUserId())
const loading = ref(false) const loading = ref(false)
const records = ref([])
const incomeRecords = ref([]) //
const expenditureRecords = ref([]) //
const records = computed(() => {
if (selectedTab.value.langKey === 'income') {
return incomeRecords.value
} else {
return expenditureRecords.value
}
})
// div
const incomeLoadmore = ref(null)
const expenditureLoadmore = ref(null)
const searchQuery = ref('') const searchQuery = ref('')
const searchResults = ref([]) const searchResults = ref([]) //
const isSearching = ref(false) const isSearching = ref(false)
const hasSearched = ref(false) const hasSearched = ref(false)
const activeTabId = ref(0) const selectedTab = ref({ id: 0, langKey: 'income' })
const tabItems = ref([]) // DOM const tabItems = ref([]) // DOM
// //
const tabs = ref([ const tabs = ref([
@ -270,9 +302,11 @@ const tabs = ref([
]) ])
// //
const switchTab = (tabId) => { const switchTab = async (tab) => {
activeTabId.value = tabId selectedTab.value = tab
fetchRecords()
await fetchRecords() //
reSetObserve() //
} }
// 线 // 线
@ -280,7 +314,7 @@ const underlineStyle = computed(() => {
console.log('计算属性') console.log('计算属性')
if (tabItems.value.length === 0) return {} // if (tabItems.value.length === 0) return {} //
const activeTab = tabItems.value[activeTabId.value] const activeTab = tabItems.value[selectedTab.value.id]
console.log('选中元素的左边距', activeTab.offsetLeft) console.log('选中元素的左边距', activeTab.offsetLeft)
return { return {
@ -298,43 +332,50 @@ const getAmountDisplay = (type, quantity) => {
} }
// //
const fetchRecords = async () => { const fetchRecords = async (lastId = '') => {
loading.value = true loading.value = true
try { try {
// ID if (!userId.value) {
const userId = getUserId()
if (!userId) {
console.error('无法获取用户ID') console.error('无法获取用户ID')
records.value = []
return return
} }
//
if (records.value.length != 0 && lastId == '') {
return
}
//
let data = { let data = {
userId: userId, userId: userId.value, //id
type: activeTabId.value, type: selectedTab.value.id, //
searchId: searchQuery.value, searchId: searchQuery.value, //id
lastId, //id
} }
const response = await getFreightWaterFlow(data) const response = await getFreightWaterFlow(data)
if (response && response.status && response.body) { if (response && response.status && response.body) {
// //
records.value = response.body.map((item) => ({ let records = response.body.map((item) => ({
...item, ...item,
amount: getAmountDisplay(item.type, item.quantity), //± amount: getAmountDisplay(item.type, item.quantity), //±
time: formatUTCCustom(item.createTime), // time: formatUTCCustom(item.createTime), //
})) }))
} else {
records.value = [] if (selectedTab.value.id == 1) {
expenditureRecords.value.push(...records)
} else {
incomeRecords.value.push(...records)
}
} }
} catch (error) { } catch (error) {
console.error('获取记录失败:', error) console.error('获取记录失败:', error)
records.value = []
} finally { } finally {
loading.value = false loading.value = false
console.log('加载完毕')
} }
} }
@ -342,33 +383,92 @@ const fetchRecords = async () => {
const clearSearch = () => { const clearSearch = () => {
hasSearched.value = false hasSearched.value = false
searchQuery.value = '' searchQuery.value = ''
searchResults.value = members.value searchResults.value = []
incomeRecords.value = [] //
expenditureRecords.value = [] //
fetchRecords() //
} }
// //
const performSearch = async () => { const performSearch = useDebounce(
console.log('searchQuery.value:', searchQuery.value) async () => {
console.log('searchQuery.value:', searchQuery.value)
if (!searchQuery.value.trim()) { if (!searchQuery.value.trim()) {
searchResults.value = members.value searchResults.value = []
return return
} }
isSearching.value = true isSearching.value = true
hasSearched.value = false hasSearched.value = false
searchResults.value = [] searchResults.value = []
if (searchQuery.value.trim()) { if (searchQuery.value.trim()) {
fetchRecords() incomeRecords.value = [] //
} expenditureRecords.value = [] //
await fetchRecords() //
}
isSearching.value = false isSearching.value = false
hasSearched.value = true hasSearched.value = true
},
500,
true
)
const throttleFetch = useThrottle((fetchFn) => {
fetchFn()
}, 1000)
// IntersectionObserver
const obsever = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
console.log('监控到底部')
let lastId = records.value[records.value.length - 1].id
console.log('lastId:', lastId)
if (entry.target === incomeLoadmore.value) {
console.log('incomeLoadmore')
throttleFetch(() => {
fetchRecords(lastId) //income
})
}
if (entry.target === expenditureLoadmore.value) {
console.log('expenditureLoadmore')
throttleFetch(() => {
fetchRecords(lastId) //expenditure
})
}
}
})
})
//
const reSetObserve = () => {
nextTick(() => {
if (incomeLoadmore.value) {
obsever.unobserve(incomeLoadmore.value)
obsever.observe(incomeLoadmore.value)
}
if (expenditureLoadmore.value) {
obsever.unobserve(expenditureLoadmore.value)
obsever.observe(expenditureLoadmore.value)
}
})
} }
onMounted(async () => { onMounted(async () => {
await fetchRecords() await fetchRecords()
underlineStyle.value // underlineStyle.value //
if (incomeLoadmore.value) {
obsever.observe(incomeLoadmore.value) //
}
if (expenditureLoadmore.value) {
obsever.observe(expenditureLoadmore.value) //
}
}) })
</script> </script>