import {useState, useEffect, useCallback} from 'react' import {View, Text} from '@tarojs/components' import Taro, {useDidShow} from '@tarojs/taro' import {Loading, InfiniteLoading, Empty, Space, Tabs, TabPane, Tag, Button, SearchBar} from '@nutui/nutui-react-taro' import {Phone, AngleDoubleLeft} from '@nutui/icons-react-taro' import type {ShopDealerApply, ShopDealerApply as UserType} from "@/api/shop/shopDealerApply/model"; import { CustomerStatus, getStatusText, getStatusTagType, getStatusOptions, mapApplyStatusToCustomerStatus, mapCustomerStatusToApplyStatus } from '@/utils/customerStatus'; import FixedButton from "@/components/FixedButton"; import navTo from "@/utils/common"; import {pageShopDealerApply, removeShopDealerApply, updateShopDealerApply} from "@/api/shop/shopDealerApply"; import {addShopDealerRecord} from "@/api/shop/shopDealerRecord"; // 扩展User类型,添加客户状态和保护天数 interface CustomerUser extends UserType { customerStatus?: CustomerStatus; protectDays?: number; // 剩余保护天数 } const CustomerIndex = () => { const [list, setList] = useState([]) const [loading, setLoading] = useState(false) const [activeTab, setActiveTab] = useState('all') const [searchValue, setSearchValue] = useState('') const [displaySearchValue, setDisplaySearchValue] = useState('') const [page, setPage] = useState(1) const [hasMore, setHasMore] = useState(true) // Tab配置 const tabList = getStatusOptions(); // 复制手机号 const copyPhone = (phone: string) => { Taro.setClipboardData({ data: phone, success: () => { Taro.showToast({ title: '手机号已复制', icon: 'success', duration: 1500 }); } }); }; // 一键拨打 const makePhoneCall = (phone: string) => { Taro.makePhoneCall({ phoneNumber: phone, fail: () => { Taro.showToast({ title: '拨打取消', icon: 'error' }); } }); }; // 编辑跟进情况 const editComments = (customer: CustomerUser) => { Taro.showModal({ title: '编辑跟进情况', // @ts-ignore editable: true, placeholderText: '请输入跟进情况', content: customer.comments || '', success: async (res) => { // @ts-ignore if (res.confirm && res.content !== undefined) { try { // 添加跟进记录 await addShopDealerRecord({ dealerId: customer.userId, // @ts-ignore content: res.content.trim() }) // 更新跟进情况 await updateShopDealerApply({ ...customer, // @ts-ignore comments: res.content.trim() }); Taro.showToast({ title: '更新成功', icon: 'success' }); // 刷新列表 setList([]); setPage(1); setHasMore(true); fetchCustomerData(activeTab, true); } catch (error) { console.error('更新跟进情况失败:', error); Taro.showToast({ title: '更新失败,请重试', icon: 'error' }); } } } }); }; // 计算剩余保护天数(基于过期时间) const calculateProtectDays = (expirationTime?: string, applyTime?: string): number => { try { // 优先使用过期时间字段 if (expirationTime) { const expDate = new Date(expirationTime.replace(' ', 'T')); const now = new Date(); // 计算剩余毫秒数 const remainingMs = expDate.getTime() - now.getTime(); // 转换为天数,向上取整 const remainingDays = Math.ceil(remainingMs / (1000 * 60 * 60 * 24)); console.log('=== 基于过期时间计算 ==='); console.log('过期时间:', expirationTime); console.log('当前时间:', now.toLocaleString()); console.log('剩余天数:', remainingDays); console.log('======================'); return Math.max(0, remainingDays); } // 如果没有过期时间,回退到基于申请时间计算 if (!applyTime) return 0; const protectionPeriod = 7; // 保护期7天 // 解析申请时间 let applyDate: Date; if (applyTime.includes('T')) { applyDate = new Date(applyTime); } else { applyDate = new Date(applyTime.replace(' ', 'T')); } // 获取当前时间 const now = new Date(); // 只比较日期部分,忽略时间 const applyDateOnly = new Date(applyDate.getFullYear(), applyDate.getMonth(), applyDate.getDate()); const currentDateOnly = new Date(now.getFullYear(), now.getMonth(), now.getDate()); // 计算已经过去的天数 const timeDiff = currentDateOnly.getTime() - applyDateOnly.getTime(); const daysPassed = Math.floor(timeDiff / (1000 * 60 * 60 * 24)); // 计算剩余保护天数 const remainingDays = protectionPeriod - daysPassed; console.log('=== 基于申请时间计算 ==='); console.log('申请时间:', applyTime); console.log('已过去天数:', daysPassed); console.log('剩余保护天数:', remainingDays); console.log('======================'); return Math.max(0, remainingDays); } catch (error) { console.error('日期计算错误:', error); return 0; } }; // 获取客户数据 const fetchCustomerData = useCallback(async (statusFilter?: CustomerStatus, resetPage = false, targetPage?: number) => { setLoading(true); try { const currentPage = resetPage ? 1 : (targetPage || page); // 构建API参数,根据状态筛选 const params: any = { type: 4, page: currentPage }; const applyStatus = mapCustomerStatusToApplyStatus(statusFilter || activeTab); if (applyStatus !== undefined) { params.applyStatus = applyStatus; } const res = await pageShopDealerApply(params); if (res?.list && res.list.length > 0) { // 正确映射状态并计算保护天数 const mappedList = res.list.map(customer => ({ ...customer, customerStatus: mapApplyStatusToCustomerStatus(customer.applyStatus || 10), protectDays: calculateProtectDays(customer.expirationTime, customer.applyTime || customer.createTime || '') })); // 如果是重置页面或第一页,直接设置新数据;否则追加数据 if (resetPage || currentPage === 1) { setList(mappedList); } else { setList(prevList => prevList.concat(mappedList)); } // 正确判断是否还有更多数据 const hasMoreData = res.list.length >= 10; // 假设每页10条数据 setHasMore(hasMoreData); } else { if (resetPage || currentPage === 1) { setList([]); } setHasMore(false); } setPage(currentPage); } catch (error) { console.error('获取客户数据失败:', error); Taro.showToast({ title: '加载失败,请重试', icon: 'none' }); } finally { setLoading(false); } }, [activeTab, page]); const reloadMore = async () => { if (loading || !hasMore) return; // 防止重复加载 const nextPage = page + 1; await fetchCustomerData(activeTab, false, nextPage); } // 防抖搜索功能 useEffect(() => { const timer = setTimeout(() => { setDisplaySearchValue(searchValue); }, 300); // 300ms 防抖 return () => clearTimeout(timer); }, [searchValue]); // 根据搜索条件筛选数据(状态筛选已在API层面处理) const getFilteredList = () => { let filteredList = list; // 按搜索关键词筛选 if (displaySearchValue.trim()) { const keyword = displaySearchValue.trim().toLowerCase(); filteredList = filteredList.filter(customer => (customer.realName && customer.realName.toLowerCase().includes(keyword)) || (customer.dealerName && customer.dealerName.toLowerCase().includes(keyword)) || (customer.dealerCode && customer.dealerCode.toLowerCase().includes(keyword)) || (customer.mobile && customer.mobile.includes(keyword)) || (customer.userId && customer.userId.toString().includes(keyword)) ); } return filteredList; }; // 获取各状态的统计数量 const [statusCounts, setStatusCounts] = useState({ all: 0, pending: 0, signed: 0, cancelled: 0 }); // 获取所有状态的统计数量 const fetchStatusCounts = useCallback(async () => { try { // 并行获取各状态的数量 const [allRes, pendingRes, signedRes, cancelledRes] = await Promise.all([ pageShopDealerApply({type: 4}), // 全部 pageShopDealerApply({applyStatus: 10, type: 4}), // 跟进中 pageShopDealerApply({applyStatus: 20, type: 4}), // 已签约 pageShopDealerApply({applyStatus: 30, type: 4}) // 已取消 ]); setStatusCounts({ all: allRes?.count || 0, pending: pendingRes?.count || 0, signed: signedRes?.count || 0, cancelled: cancelledRes?.count || 0 }); } catch (error) { console.error('获取状态统计失败:', error); } }, []); const getStatusCounts = () => statusCounts; // 取消操作 const handleCancel = (customer: ShopDealerApply) => { updateShopDealerApply({ ...customer, applyStatus: 30 }).then(() => { Taro.showToast({ title: '取消成功', icon: 'success' }); // 重新加载当前tab的数据 setList([]); setPage(1); setHasMore(true); fetchCustomerData(activeTab, true).then(); fetchStatusCounts().then(); }) }; // 删除 const handleDelete = (customer: ShopDealerApply) => { removeShopDealerApply(customer.applyId).then(() => { Taro.showToast({ title: '删除成功', icon: 'success' }); // 刷新当前tab的数据 setList([]); setPage(1); setHasMore(true); fetchCustomerData(activeTab, true).then(); fetchStatusCounts().then(); }) } // 初始化数据 useEffect(() => { fetchCustomerData(activeTab, true).then(); fetchStatusCounts().then(); }, []); // 当activeTab变化时重新获取数据 useEffect(() => { setList([]); // 清空列表 setPage(1); // 重置页码 setHasMore(true); // 重置加载状态 fetchCustomerData(activeTab, true); }, [activeTab]); // 监听页面显示,当从其他页面返回时刷新数据 useDidShow(() => { // 刷新当前tab的数据和统计信息 setList([]); setPage(1); setHasMore(true); fetchCustomerData(activeTab, true); fetchStatusCounts(); }); // 渲染客户项 const renderCustomerItem = (customer: CustomerUser) => ( {customer.dealerName} {customer.customerStatus && ( {getStatusText(customer.customerStatus)} )} 联系人:{customer.realName} { e.stopPropagation(); makePhoneCall(customer.mobile || ''); }}>联系电话:{customer.mobile} { e.stopPropagation(); makePhoneCall(customer.mobile || ''); }} /> { e.stopPropagation(); copyPhone(customer.mobile || ''); }} > 复制 添加时间:{customer.createTime} {/* 保护天数显示 */} {customer.applyStatus === 10 && ( 保护期: {customer.protectDays && customer.protectDays > 0 ? ( 剩余{customer.protectDays}天 ) : ( 已过期 )} )} 报备人:{customer?.nickName} {customer?.refereeName} {/* 显示 comments 字段 */} 跟进情况:{customer.comments || '暂无'} { e.stopPropagation(); editComments(customer); }} > 编辑 {/* 跟进中状态显示操作按钮 */} {(customer.applyStatus === 10 && customer.userId == Taro.getStorageSync('UserId')) && ( )} {(customer.applyStatus === 30 && customer.userId == Taro.getStorageSync('UserId')) && ( )} ); // 渲染客户列表 const renderCustomerList = () => { const filteredList = getFilteredList(); const isSearching = displaySearchValue.trim().length > 0; return ( {/* 搜索结果统计 */} {isSearching && ( 搜索 "{displaySearchValue}" 的结果,共找到 {filteredList.length} 条记录 )} { // 滚动事件处理 }} onScrollToUpper={() => { // 滚动到顶部事件处理 }} loadingText={ <> 加载中... } loadMoreText={ filteredList.length === 0 ? ( ) : ( 没有更多了 ) } > {loading && filteredList.length === 0 ? ( 加载中... ) : ( filteredList.map(renderCustomerItem) )} ); }; return ( {/* 搜索栏 */} setSearchValue(value)} onClear={() => { setSearchValue(''); setDisplaySearchValue(''); }} clearable /> {/* 顶部Tabs */} setActiveTab(value as CustomerStatus)} > {tabList.map(tab => { const counts = getStatusCounts(); const count = counts[tab.value as keyof typeof counts] || 0; return ( 0 ? `(${count})` : ''}`} value={tab.value} /> ); })} {/* 客户列表 */} {renderCustomerList()} Taro.navigateTo({url: '/dealer/customer/add'})}/> ); }; export default CustomerIndex;