feat(dealer/customer): 实现客户列表的无限滚动和搜索功能- 在客户列表页面添加 InfiniteLoading 组件,实现无限滚动加载- 添加搜索功能,支持按关键词搜索客户
- 优化数据加载逻辑,解决重复请求问题 - 在 Header 组件中增加用户登录状态和信息的检查
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import {useState, useEffect, useCallback} from 'react'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {Loading, Space, Tabs, TabPane, Tag, Button} from '@nutui/nutui-react-taro'
|
||||
import {Loading, InfiniteLoading, Empty, Space, Tabs, TabPane, Tag, Button} from '@nutui/nutui-react-taro'
|
||||
import {Phone} from '@nutui/icons-react-taro'
|
||||
import type {ShopDealerApply, ShopDealerApply as UserType} from "@/api/shop/shopDealerApply/model";
|
||||
import {
|
||||
@@ -26,18 +26,23 @@ const CustomerIndex = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [activeTab, setActiveTab] = useState<CustomerStatus>('all')
|
||||
const [searchValue, _] = useState<string>('')
|
||||
const [page, setPage] = useState(1)
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
|
||||
// Tab配置
|
||||
const tabList = getStatusOptions();
|
||||
|
||||
|
||||
// 获取客户数据
|
||||
const fetchCustomerData = useCallback(async (statusFilter?: CustomerStatus) => {
|
||||
const fetchCustomerData = useCallback(async (statusFilter?: CustomerStatus, resetPage = false, targetPage?: number) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const currentPage = resetPage ? 1 : (targetPage || page);
|
||||
|
||||
// 构建API参数,根据状态筛选
|
||||
const params: any = {
|
||||
type: 0
|
||||
type: 0,
|
||||
page: currentPage
|
||||
};
|
||||
const applyStatus = mapCustomerStatusToApplyStatus(statusFilter || activeTab);
|
||||
if (applyStatus !== undefined) {
|
||||
@@ -45,21 +50,45 @@ const CustomerIndex = () => {
|
||||
}
|
||||
|
||||
const res = await pageShopDealerApply(params);
|
||||
if (res?.list) {
|
||||
let newList: CustomerUser[];
|
||||
|
||||
if (res?.list && res.list.length > 0) {
|
||||
// 正确映射状态
|
||||
const mappedList = res.list.map(customer => ({
|
||||
...customer,
|
||||
customerStatus: mapApplyStatusToCustomerStatus(customer.applyStatus || 10)
|
||||
}));
|
||||
setList(mappedList);
|
||||
|
||||
// 如果是重置页面或第一页,直接设置新数据;否则追加数据
|
||||
newList = resetPage ? mappedList : list.concat(mappedList);
|
||||
|
||||
// 正确判断是否还有更多数据
|
||||
const hasMoreData = res.list.length >= 10; // 假设每页10条数据
|
||||
setHasMore(hasMoreData);
|
||||
} else {
|
||||
newList = resetPage ? [] : list;
|
||||
setHasMore(false);
|
||||
}
|
||||
|
||||
setList(newList);
|
||||
setPage(currentPage);
|
||||
} catch (error) {
|
||||
console.error('获取客户数据失败:', error);
|
||||
Taro.showToast({
|
||||
title: '加载失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [activeTab]);
|
||||
|
||||
const reloadMore = async () => {
|
||||
if (loading || !hasMore) return; // 防止重复加载
|
||||
const nextPage = page + 1;
|
||||
await fetchCustomerData(activeTab, false, nextPage);
|
||||
}
|
||||
|
||||
|
||||
// 根据搜索条件筛选数据(状态筛选已在API层面处理)
|
||||
const getFilteredList = () => {
|
||||
@@ -93,10 +122,10 @@ const CustomerIndex = () => {
|
||||
try {
|
||||
// 并行获取各状态的数量
|
||||
const [allRes, pendingRes, signedRes, cancelledRes] = await Promise.all([
|
||||
pageShopDealerApply({type:0}), // 全部
|
||||
pageShopDealerApply({applyStatus: 10,type:0}), // 跟进中
|
||||
pageShopDealerApply({applyStatus: 20,type:0}), // 已签约
|
||||
pageShopDealerApply({applyStatus: 30,type:0}) // 已取消
|
||||
pageShopDealerApply({type: 0}), // 全部
|
||||
pageShopDealerApply({applyStatus: 10, type: 0}), // 跟进中
|
||||
pageShopDealerApply({applyStatus: 20, type: 0}), // 已签约
|
||||
pageShopDealerApply({applyStatus: 30, type: 0}) // 已取消
|
||||
]);
|
||||
|
||||
setStatusCounts({
|
||||
@@ -122,26 +151,34 @@ const CustomerIndex = () => {
|
||||
title: '取消成功',
|
||||
icon: 'success'
|
||||
});
|
||||
fetchCustomerData().then();
|
||||
// 重新加载当前tab的数据
|
||||
setList([]);
|
||||
setPage(1);
|
||||
setHasMore(true);
|
||||
fetchCustomerData(activeTab, true).then();
|
||||
fetchStatusCounts().then();
|
||||
})
|
||||
};
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
fetchCustomerData().then();
|
||||
fetchCustomerData(activeTab, true).then();
|
||||
fetchStatusCounts().then();
|
||||
}, [fetchCustomerData, fetchStatusCounts]);
|
||||
}, []);
|
||||
|
||||
// 当activeTab变化时重新获取数据
|
||||
useEffect(() => {
|
||||
fetchCustomerData(activeTab);
|
||||
setList([]); // 清空列表
|
||||
setPage(1); // 重置页码
|
||||
setHasMore(true); // 重置加载状态
|
||||
fetchCustomerData(activeTab, true);
|
||||
}, [activeTab]);
|
||||
|
||||
// 渲染客户项
|
||||
const renderCustomerItem = (customer: CustomerUser) => (
|
||||
<View key={customer.userId} className="bg-white rounded-lg p-4 mb-3 shadow-sm">
|
||||
<View className="flex items-center mb-3" onClick={() => navTo(`/dealer/customer/add?id=${customer.applyId}`, true)}>
|
||||
<View className="flex items-center mb-3"
|
||||
onClick={() => navTo(`/dealer/customer/add?id=${customer.applyId}`, true)}>
|
||||
<View className="flex-1">
|
||||
<View className="flex items-center justify-between mb-1">
|
||||
<Text className="font-semibold text-gray-800 mr-2">
|
||||
@@ -192,26 +229,49 @@ const CustomerIndex = () => {
|
||||
const renderCustomerList = () => {
|
||||
const filteredList = getFilteredList();
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Space className="flex items-center justify-center py-8">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
if (filteredList.length === 0) {
|
||||
return (
|
||||
<View className="flex items-center justify-center py-8">
|
||||
<Text className="text-gray-500">暂无客户数据</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="p-4">
|
||||
{filteredList.map(renderCustomerItem)}
|
||||
<View className="p-4" style={{
|
||||
height: '75vh',
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden'
|
||||
}}>
|
||||
<InfiniteLoading
|
||||
target="scroll"
|
||||
hasMore={hasMore}
|
||||
onLoadMore={reloadMore}
|
||||
onScroll={() => {
|
||||
// 滚动事件处理
|
||||
}}
|
||||
onScrollToUpper={() => {
|
||||
// 滚动到顶部事件处理
|
||||
}}
|
||||
loadingText={
|
||||
<>
|
||||
加载中...
|
||||
</>
|
||||
}
|
||||
loadMoreText={
|
||||
filteredList.length === 0 ? (
|
||||
<Empty
|
||||
style={{backgroundColor: 'transparent'}}
|
||||
description={loading ? "加载中..." : "暂无客户数据"}
|
||||
/>
|
||||
) : (
|
||||
<View className={'h-12 flex items-center justify-center'}>
|
||||
<Text className="text-gray-500 text-sm">没有更多了</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
>
|
||||
{loading && filteredList.length === 0 ? (
|
||||
<View className="flex items-center justify-center py-8">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-2 ml-2">加载中...</Text>
|
||||
</View>
|
||||
) : (
|
||||
filteredList.map(renderCustomerItem)
|
||||
)}
|
||||
</InfiniteLoading>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user