From 7d9f9fbd084ce662621d665f0ac1136dfa5a1104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Tue, 18 Nov 2025 11:57:54 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=20=E6=B7=BB=E5=8A=A0=E6=88=90?= =?UTF-8?q?=E5=91=98=E5=8A=9F=E8=83=BD=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TwoColumnSelection/TwoColumnSelection.tsx | 34 ++- .../components/ProfileModules/index.tsx | 198 +++++++++++++----- 2 files changed, 173 insertions(+), 59 deletions(-) diff --git a/Touchkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx b/Touchkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx index e5400bf6..6ba96274 100644 --- a/Touchkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx +++ b/Touchkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx @@ -17,6 +17,7 @@ const FriendListItem = memo<{ onClick={() => onSelect(friend)} > +     {friend.nickname?.charAt(0)} @@ -41,6 +42,9 @@ interface TwoColumnSelectionProps { deviceIds?: number[]; enableDeviceFilter?: boolean; dataSource?: FriendSelectionItem[]; + onLoadMore?: () => void; // 加载更多回调 + hasMore?: boolean; // 是否有更多数据 + loading?: boolean; // 是否正在加载 } const TwoColumnSelection: React.FC = ({ @@ -51,13 +55,16 @@ const TwoColumnSelection: React.FC = ({ deviceIds = [], enableDeviceFilter = true, dataSource, + onLoadMore, + hasMore = false, + loading = false, }) => { const [rawFriends, setRawFriends] = useState([]); const [selectedFriends, setSelectedFriends] = useState( [], ); const [searchQuery, setSearchQuery] = useState(""); - const [loading, setLoading] = useState(false); + const [isLoading, setIsLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); @@ -81,10 +88,10 @@ const TwoColumnSelection: React.FC = ({ const [displayPage, setDisplayPage] = useState(1); const friends = useMemo(() => { - const startIndex = 0; - const endIndex = displayPage * ITEMS_PER_PAGE; - return filteredFriends.slice(startIndex, endIndex); - }, [filteredFriends, displayPage]); + // 直接使用完整的过滤列表,不再进行本地分页 + // 因为我们已经在外部进行了分页加载 + return filteredFriends; + }, [filteredFriends]); const hasMoreFriends = filteredFriends.length > friends.length; @@ -100,7 +107,7 @@ const TwoColumnSelection: React.FC = ({ // 获取好友列表 const fetchFriends = useCallback( async (page: number, keyword: string = "") => { - setLoading(true); + setIsLoading(true); try { const params: any = { page, @@ -128,7 +135,7 @@ const TwoColumnSelection: React.FC = ({ console.error("获取好友列表失败:", error); message.error("获取好友列表失败"); } finally { - setLoading(false); + setIsLoading(false); } }, [deviceIds, enableDeviceFilter], @@ -148,7 +155,7 @@ const TwoColumnSelection: React.FC = ({ if (visible) { setSearchQuery(""); setSelectedFriends([]); - setLoading(false); + setIsLoading(false); } }, [visible]); @@ -257,7 +264,7 @@ const TwoColumnSelection: React.FC = ({
- {loading ? ( + {isLoading && !loading ? (
加载中...
) : friends.length > 0 ? ( // 使用 React.memo 优化列表项渲染 @@ -280,9 +287,14 @@ const TwoColumnSelection: React.FC = ({
)} - {hasMoreFriends && ( + {/* 使用外部传入的加载更多 */} + {hasMore && (
-
diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx index b71db1e0..150e9ceb 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx @@ -25,7 +25,7 @@ import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import { useCustomerStore } from "@/store/module/weChat/customer"; import { useWebSocketStore } from "@/store/module/websocket/websocket"; import { useWeChatStore } from "@/store/module/weChat/weChat"; -import { useContactStore } from "@/store/module/weChat/contacts"; +import { contactUnifiedService } from "@/utils/db"; import { generateAiText } from "@/api/ai"; import TwoColumnSelection from "@/components/TwoColumnSelection/TwoColumnSelection"; import TwoColumnMemberSelection from "@/components/MemberSelection/TwoColumnMemberSelection"; @@ -216,7 +216,7 @@ const Person: React.FC = ({ contract }) => { return matchedCustomer || null; }, [customerList, contract.wechatAccountId]); - const { getContactsByCustomer } = useContactStore(); + // 不再需要从useContactStore获取getContactsByCustomer const { sendCommand } = useWebSocketStore(); @@ -516,6 +516,125 @@ const Person: React.FC = ({ contract }) => { bio: contract.bio || contract.signature || "-", }; + // 分页状态 + const [currentContactPage, setCurrentContactPage] = useState(1); + const [contactPageSize] = useState(10); + const [isLoadingContacts, setIsLoadingContacts] = useState(false); + + // 从数据库获取联系人数据的通用函数 + const fetchContacts = async (page = 1) => { + try { + const { databaseManager, initializeDatabaseFromPersistedUser } = + await import("@/utils/db"); + + // 检查数据库初始化状态 + if (!databaseManager.isInitialized()) { + await initializeDatabaseFromPersistedUser(); + } + + // 获取当前用户ID + const userId = kfSelectedUser?.userId || 0; + const storeUserId = databaseManager.getCurrentUserId(); + const effectiveUserId = storeUserId || userId; + + if (!effectiveUserId) { + messageApi.error("无法获取用户信息,请尝试重新登录"); + return []; + } + + // 查询联系人数据 + const allContacts = await contactUnifiedService.findWhereMultiple([ + { field: "userId", operator: "equals", value: effectiveUserId }, + { + field: "wechatAccountId", + operator: "equals", + value: contract.wechatAccountId, + }, + { field: "type", operator: "equals", value: "friend" }, + ]); + + // 手动分页 + const startIndex = (page - 1) * contactPageSize; + const endIndex = startIndex + contactPageSize; + return allContacts.slice(startIndex, endIndex); + } catch (error) { + console.error("获取联系人数据失败:", error); + messageApi.error("获取联系人数据失败"); + return []; + } + }; + + const addMember = async () => { + try { + setIsLoadingContacts(true); + const pagedContacts = await fetchContacts(currentContactPage); + // 转换为选择器需要的数据格式 + const friendSelectionData = pagedContacts.map(item => ({ + id: item.id || item.serverId, + wechatId: item.wechatId, + nickname: item.nickname, + avatar: item.avatar || "", + conRemark: item.conRemark, + name: item.conRemark || item.nickname, // 用于搜索显示 + })); + + setContractList(friendSelectionData); + setIsFriendSelectionVisible(true); + + // 如果没有联系人数据,显示提示 + if (friendSelectionData.length === 0) { + messageApi.info("未找到可添加的联系人,可能需要先同步联系人数据"); + } + } catch (error) { + console.error("获取联系人列表失败:", error); + messageApi.error("获取联系人列表失败"); + } finally { + setIsLoadingContacts(false); + } + }; + + // 加载更多联系人 + const loadMoreContacts = async () => { + if (isLoadingContacts) return; + try { + setIsLoadingContacts(true); + const nextPage = currentContactPage + 1; + setCurrentContactPage(nextPage); + // 使用通用函数获取下一页联系人数据 + const pagedContacts = await fetchContacts(nextPage); + // 转换数据格式 + const newFriendSelectionData = pagedContacts.map(item => ({ + id: item.id || item.serverId, + wechatId: item.wechatId, + nickname: item.nickname, + avatar: item.avatar || "", + conRemark: item.conRemark, + name: item.conRemark || item.nickname, + })); + + // 更新列表并去重 + setContractList(prev => { + const newList = [...prev, ...newFriendSelectionData]; + // 确保列表中没有重复项 + const uniqueMap = new Map(); + const uniqueList = newList.filter(item => { + if (uniqueMap.has(item.id)) { + return false; + } + uniqueMap.set(item.id, true); + return true; + }); + return uniqueList; + }); + + messageApi.success(`已加载${pagedContacts.length}条联系人数据`); + } catch (error) { + console.error("加载更多联系人失败:", error); + messageApi.error("加载更多联系人失败"); + } finally { + setIsLoadingContacts(false); + } + }; return ( <> {contextHolder} @@ -774,27 +893,25 @@ const Person: React.FC = ({ contract }) => {
{/* 渲染所有可用标签,选中的排在前面 */} - {[...new Set([...selectedTags, ...allAvailableTags])].map( - (tag, index) => { - const isSelected = selectedTags.includes(tag); - return ( - handleTagToggle(tag)} - > - {tag} - - ); - }, - )} + {[...new Set([...selectedTags, ...allAvailableTags])].map(tag => { + const isSelected = selectedTags.includes(tag); + return ( + handleTagToggle(tag)} + > + {tag} + + ); + })} {/* 新增标签区域 */} {isAddingTag ? ( @@ -917,29 +1034,7 @@ const Person: React.FC = ({ contract }) => { >