team member 分页修改

This commit is contained in:
tianfeng 2025-09-23 10:50:49 +08:00
parent 20a0e462aa
commit 8ff23c000e
2 changed files with 237 additions and 19 deletions

View File

@ -3,11 +3,20 @@ import {get, post} from '../utils/http.js'
/**
* 获取团队成员列表
* @param {string} teamId - 团队ID
* @param {object} params - 可选参数包含lastId等分页参数
* @returns {Promise}
*/
export const getTeamMembers = async (teamId) => {
export const getTeamMembers = async (teamId, params = {}) => {
try {
const response = await get(`/team/members?id=${teamId}`)
// 构建查询参数
const queryParams = new URLSearchParams({ id: teamId })
console.log('params', queryParams)
// 添加分页参数
if (params.lastId) {
queryParams.append('lastId', params.lastId)
}
const response = await get(`/team/members?${queryParams.toString()}`)
return response
} catch (error) {
console.error('Failed to fetch team members:', error)
@ -17,11 +26,24 @@ export const getTeamMembers = async (teamId) => {
/**
* 获取BD代理商列表
* @param {object} params - 可选参数包含lastId等分页参数
* @returns {Promise}
*/
export const getBdAgentList = async () => {
export const getBdAgentList = async (params = {}) => {
try {
const response = await get('/team/bd/bd-agent/list')
// 构建查询参数
const queryParams = new URLSearchParams()
// 添加分页参数
if (params.lastId) {
queryParams.append('lastId', params.lastId)
}
const url = queryParams.toString()
? `/team/bd/bd-agent/list?${queryParams.toString()}`
: '/team/bd/bd-agent/list'
const response = await get(url)
return response
} catch (error) {
console.error('Failed to fetch BD agent list:', error)

View File

@ -10,7 +10,7 @@
</div>
<!-- 成员列表 -->
<div v-else-if="members.length > 0" class="member-list">
<div v-else-if="members.length > 0" class="member-list" ref="memberListRef">
<div
v-for="member in members"
:key="member.id"
@ -41,6 +41,20 @@
<span v-else>🗑</span>
</button>-->
</div>
<!-- 加载更多状态 -->
<div v-if="loadingMore" class="loading-more">
<div class="loading-spinner small"></div>
<p>Loading more...</p>
</div>
<!-- 没有更多数据提示 -->
<div v-else-if="noMoreData && members.length > 0" class="no-more-data">
<p>No more members</p>
</div>
<!-- 无形的加载触发器 -->
<div v-if="!noMoreData && members.length > 0" ref="loadMoreTrigger" class="load-more-trigger"></div>
</div>
<!-- 空状态 -->
@ -72,7 +86,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, nextTick, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue'
import {
@ -91,6 +105,14 @@ const membersTotal = ref(0)
const deletingMemberId = ref(null)
const showDeleteModal = ref(false)
const memberToDelete = ref(null)
const memberListRef = ref(null)
//
const loadingMore = ref(false)
const noMoreData = ref(false)
const lastId = ref(null)
const intersectionObserver = ref(null)
const loadMoreTrigger = ref(null)
// BD Center
const isFromBdCenter = ref(false)
@ -103,30 +125,76 @@ const fetchTeamTotal = async () => {
}
//
const fetchTeamMembers = async () => {
const fetchTeamMembers = async (isLoadMore = false) => {
try {
loading.value = true
if (isLoadMore) {
loadingMore.value = true
} else {
loading.value = true
//
lastId.value = null
noMoreData.value = false
}
let response
const params = {}
if (lastId.value) {
params.lastId = lastId.value
}
if (isFromBdCenter.value) {
// BD CenterBD
response = await getBdAgentList()
// BD
response = await getBdAgentList(params)
} else {
//
//
const teamId = getTeamId()
response = await getTeamMembers(teamId)
response = await getTeamMembers(teamId, params)
}
if (response.status && response.body) {
members.value = response.body || []
const newMembers = response.body || []
if (isLoadMore) {
//
members.value = [...members.value, ...newMembers]
} else {
//
members.value = newMembers
}
// lastId
if (newMembers.length > 0) {
lastId.value = newMembers[newMembers.length - 1].id
}
// 20
// 20API
if (newMembers.length < 20) {
noMoreData.value = true
}
console.log('Fetched members:', {
isLoadMore,
newCount: newMembers.length,
totalCount: members.value.length,
lastId: lastId.value,
noMoreData: noMoreData.value
})
} else {
members.value = []
if (!isLoadMore) {
members.value = []
}
noMoreData.value = true
}
} catch (error) {
console.error('Failed to fetch team members:', error)
members.value = []
if (!isLoadMore) {
members.value = []
}
showError('Failed to load team members')
} finally {
loading.value = false
loadingMore.value = false
}
}
@ -146,7 +214,7 @@ const formatAccount = (userProfile) => {
//
const handleImageError = (event) => {
event.target.style.display = 'none'
event.target.nextElementSibling.style.display = 'flex'
// event.target.nextElementSibling.style.display = 'flex'
}
//
@ -180,12 +248,103 @@ const confirmDelete = async () => {
}
}
//
const handleScroll = () => {
console.log('handleScroll triggered')
if (loadingMore.value || noMoreData.value) {
console.log('Skip loading:', { loadingMore: loadingMore.value, noMoreData: noMoreData.value })
return
}
const scrollTop = window.pageYOffset || document.documentElement.scrollTop
const windowHeight = window.innerHeight
const documentHeight = document.documentElement.scrollHeight
console.log('Scroll info:', {
scrollTop,
windowHeight,
documentHeight,
distanceToBottom: documentHeight - (scrollTop + windowHeight)
})
// 100px
if (scrollTop + windowHeight >= documentHeight - 100) {
console.log('Triggering load more')
fetchTeamMembers(true)
}
}
// Intersection Observer
const setupIntersectionObserver = () => {
if (!loadMoreTrigger.value) return
intersectionObserver.value = new IntersectionObserver(
(entries) => {
const entry = entries[0]
console.log('Intersection observer triggered:', entry.isIntersecting)
if (entry.isIntersecting && !loadingMore.value && !noMoreData.value) {
console.log('Loading more via intersection observer')
fetchTeamMembers(true)
}
},
{
rootMargin: '100px'
}
)
intersectionObserver.value.observe(loadMoreTrigger.value)
console.log('Intersection observer set up')
}
//
onMounted(() => {
onMounted(async () => {
console.log('Component mounted')
// BD Center
isFromBdCenter.value = route.query.source === 'bd-center'
fetchTeamMembers()
fetchTeamTotal()
await fetchTeamMembers()
await fetchTeamTotal()
//
await nextTick()
console.log('Adding scroll listener')
window.addEventListener('scroll', handleScroll, { passive: true })
// document
document.addEventListener('scroll', handleScroll, { passive: true })
// Intersection Observer
setTimeout(() => {
setupIntersectionObserver()
const windowHeight = window.innerHeight
const documentHeight = document.documentElement.scrollHeight
console.log('Page height check:', {
windowHeight,
documentHeight,
hasScroll: documentHeight > windowHeight
})
//
if (documentHeight <= windowHeight + 50 && !noMoreData.value && members.value.length > 0) {
console.log('Auto loading more due to insufficient content height')
fetchTeamMembers(true)
}
}, 500)
})
//
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
document.removeEventListener('scroll', handleScroll)
if (intersectionObserver.value) {
intersectionObserver.value.disconnect()
}
})
</script>
@ -221,11 +380,48 @@ onMounted(() => {
margin-bottom: 12px;
}
.loading-spinner.small {
width: 20px;
height: 20px;
border-width: 2px;
margin-bottom: 8px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 加载更多状态 */
.loading-more {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
color: #666;
font-size: 14px;
}
/* 没有更多数据提示 */
.no-more-data {
display: flex;
justify-content: center;
padding: 20px;
color: #999;
font-size: 14px;
}
.no-more-data p {
margin: 0;
}
/* 加载触发器 */
.load-more-trigger {
height: 1px;
width: 100%;
margin: 10px 0;
}
/* 成员列表 */
.member-list {
display: flex;