diff --git a/Cunkebao/src/components/FriendSelection/TwoColumnSelection.module.scss b/Cunkebao/src/components/TwoColumnSelection/TwoColumnSelection.module.scss similarity index 99% rename from Cunkebao/src/components/FriendSelection/TwoColumnSelection.module.scss rename to Cunkebao/src/components/TwoColumnSelection/TwoColumnSelection.module.scss index d54b8ea1..5f53a343 100644 --- a/Cunkebao/src/components/FriendSelection/TwoColumnSelection.module.scss +++ b/Cunkebao/src/components/TwoColumnSelection/TwoColumnSelection.module.scss @@ -27,7 +27,7 @@ .searchWrapper { padding: 16px; border-bottom: 1px solid #e8e8e8; - + .ant-input { border-radius: 6px; } @@ -45,15 +45,15 @@ padding: 12px 16px; cursor: pointer; transition: background-color 0.2s; - + &:hover { background-color: #f5f5f5; } - + &.selected { background-color: #e6f7ff; } - + .ant-checkbox { margin-right: 12px; } @@ -119,7 +119,7 @@ display: flex; align-items: center; justify-content: center; - + &:hover { color: #ff4d4f; background: #fff2f0; @@ -150,4 +150,4 @@ height: 100px; color: #999; font-size: 14px; -} \ No newline at end of file +} diff --git a/Cunkebao/src/components/FriendSelection/TwoColumnSelection.tsx b/Cunkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx similarity index 74% rename from Cunkebao/src/components/FriendSelection/TwoColumnSelection.tsx rename to Cunkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx index 78858b89..e5400bf6 100644 --- a/Cunkebao/src/components/FriendSelection/TwoColumnSelection.tsx +++ b/Cunkebao/src/components/TwoColumnSelection/TwoColumnSelection.tsx @@ -1,9 +1,9 @@ -import React, { useState, useCallback, useEffect, useMemo, memo } from 'react'; -import { Modal, Input, Avatar, Button, Checkbox, message } from 'antd'; -import { SearchOutlined } from '@ant-design/icons'; -import { getFriendList } from './api'; -import type { FriendSelectionItem } from './data'; -import styles from './TwoColumnSelection.module.scss'; +import React, { useState, useCallback, useEffect, useMemo, memo } from "react"; +import { Modal, Input, Avatar, Button, Checkbox, message } from "antd"; +import { SearchOutlined } from "@ant-design/icons"; +import { getFriendList } from "../FriendSelection/api"; +import type { FriendSelectionItem } from "../FriendSelection/data"; +import styles from "./TwoColumnSelection.module.scss"; // 使用 React.memo 优化好友列表项组件 const FriendListItem = memo<{ @@ -13,7 +13,7 @@ const FriendListItem = memo<{ }>(({ friend, isSelected, onSelect }) => { return (
onSelect(friend)} > @@ -28,12 +28,15 @@ const FriendListItem = memo<{ ); }); -FriendListItem.displayName = 'FriendListItem'; +FriendListItem.displayName = "FriendListItem"; interface TwoColumnSelectionProps { visible: boolean; onCancel: () => void; - onConfirm: (selectedIds: string[], selectedItems: FriendSelectionItem[]) => void; + onConfirm: ( + selectedIds: string[], + selectedItems: FriendSelectionItem[], + ) => void; title?: string; deviceIds?: number[]; enableDeviceFilter?: boolean; @@ -44,14 +47,16 @@ const TwoColumnSelection: React.FC = ({ visible, onCancel, onConfirm, - title = '选择好友', + title = "选择好友", deviceIds = [], enableDeviceFilter = true, dataSource, }) => { const [rawFriends, setRawFriends] = useState([]); - const [selectedFriends, setSelectedFriends] = useState([]); - const [searchQuery, setSearchQuery] = useState(''); + const [selectedFriends, setSelectedFriends] = useState( + [], + ); + const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); @@ -64,9 +69,10 @@ const TwoColumnSelection: React.FC = ({ } const query = searchQuery.toLowerCase(); - return sourceData.filter(item => - item.name?.toLowerCase().includes(query) || - item.nickname?.toLowerCase().includes(query) + return sourceData.filter( + item => + item.name?.toLowerCase().includes(query) || + item.nickname?.toLowerCase().includes(query), ); }, [dataSource, rawFriends, searchQuery]); @@ -92,38 +98,41 @@ const TwoColumnSelection: React.FC = ({ }, [selectedFriends]); // 获取好友列表 - const fetchFriends = useCallback(async (page: number, keyword: string = '') => { - setLoading(true); - try { - const params: any = { - page, - pageSize: 20, - }; + const fetchFriends = useCallback( + async (page: number, keyword: string = "") => { + setLoading(true); + try { + const params: any = { + page, + pageSize: 20, + }; - if (keyword) { - params.keyword = keyword; + if (keyword) { + params.keyword = keyword; + } + + if (enableDeviceFilter && deviceIds.length > 0) { + params.deviceIds = deviceIds; + } + + const response = await getFriendList(params); + + if (response.success) { + setRawFriends(response.data.list || []); + setTotalPages(Math.ceil((response.data.total || 0) / 20)); + } else { + setRawFriends([]); + message.error(response.message || "获取好友列表失败"); + } + } catch (error) { + console.error("获取好友列表失败:", error); + message.error("获取好友列表失败"); + } finally { + setLoading(false); } - - if (enableDeviceFilter && deviceIds.length > 0) { - params.deviceIds = deviceIds; - } - - const response = await getFriendList(params); - - if (response.success) { - setRawFriends(response.data.list || []); - setTotalPages(Math.ceil((response.data.total || 0) / 20)); - } else { - setRawFriends([]); - message.error(response.message || '获取好友列表失败'); - } - } catch (error) { - console.error('获取好友列表失败:', error); - message.error('获取好友列表失败'); - } finally { - setLoading(false); - } - }, [deviceIds, enableDeviceFilter]); + }, + [deviceIds, enableDeviceFilter], + ); // 初始化数据加载 useEffect(() => { @@ -137,7 +146,7 @@ const TwoColumnSelection: React.FC = ({ // 重置搜索状态 useEffect(() => { if (visible) { - setSearchQuery(''); + setSearchQuery(""); setSelectedFriends([]); setLoading(false); } @@ -158,11 +167,14 @@ const TwoColumnSelection: React.FC = ({ }, [dataSource, fetchFriends])(); // API搜索处理(当没有外部数据源时) - const handleApiSearch = useCallback(async (keyword: string) => { - if (!dataSource) { - await fetchFriends(1, keyword); - } - }, [dataSource, fetchFriends]); + const handleApiSearch = useCallback( + async (keyword: string) => { + if (!dataSource) { + await fetchFriends(1, keyword); + } + }, + [dataSource, fetchFriends], + ); // 加载更多好友 const handleLoadMore = useCallback(() => { @@ -201,13 +213,13 @@ const TwoColumnSelection: React.FC = ({ const selectedIds = selectedFriends.map(f => f.id.toString()); onConfirm(selectedIds, selectedFriends); setSelectedFriends([]); - setSearchQuery(''); + setSearchQuery(""); }, [selectedFriends, onConfirm]); // 取消选择 - 使用 useCallback 优化性能 const handleCancel = useCallback(() => { setSelectedFriends([]); - setSearchQuery(''); + setSearchQuery(""); onCancel(); }, [onCancel]); @@ -232,15 +244,15 @@ const TwoColumnSelection: React.FC = ({
{ - const value = e.target.value; - setSearchQuery(value); // 立即更新显示 - handleSearch(value); // 防抖处理搜索 - }} - prefix={} - allowClear + placeholder="请输入昵称或微信号" + value={searchQuery} + onChange={e => { + const value = e.target.value; + setSearchQuery(value); // 立即更新显示 + handleSearch(value); // 防抖处理搜索 + }} + prefix={} + allowClear />
@@ -262,17 +274,15 @@ const TwoColumnSelection: React.FC = ({ }) ) : (
- {searchQuery ? `没有找到包含"${searchQuery}"的好友` : '暂无好友'} + {searchQuery + ? `没有找到包含"${searchQuery}"的好友` + : "暂无好友"}
)} {hasMoreFriends && (
-
@@ -307,9 +317,7 @@ const TwoColumnSelection: React.FC = ({
)) ) : ( -
- 暂无选择 -
+
暂无选择
)}
diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/index.tsx b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/index.tsx index 159e304a..d217d876 100644 --- a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/index.tsx @@ -34,14 +34,13 @@ import { useWebSocketStore } from "@/store/module/websocket/websocket"; import styles from "./Person.module.scss"; import { useWeChatStore } from "@/store/module/weChat/weChat"; import FriendSelection from "@/components/FriendSelection"; -import TwoColumnSelection from "@/components/FriendSelection/TwoColumnSelection"; +import TwoColumnSelection from "@/components/TwoColumnSelection/TwoColumnSelection"; import MemberSelection from "@/components/MemberSelection"; import TwoColumnMemberSelection from "@/components/MemberSelection/TwoColumnMemberSelection"; import { FriendSelectionItem } from "@/components/FriendSelection/data"; const { Sider } = Layout; - interface PersonProps { contract: ContractData | weChatGroup; showProfile: boolean; @@ -64,87 +63,100 @@ const Person: React.FC = ({ const [newTagValue, setNewTagValue] = useState(""); // 判断是否为群聊 - const isGroup = 'chatroomId' in contract; + const isGroup = "chatroomId" in contract; // 群聊相关状态 const [isEditingGroupName, setIsEditingGroupName] = useState(false); - const [groupNameValue, setGroupNameValue] = useState(contract.name || ''); + const [groupNameValue, setGroupNameValue] = useState(contract.name || ""); const [isEditingGroupNotice, setIsEditingGroupNotice] = useState(false); - const [groupNoticeValue, setGroupNoticeValue] = useState(contract.notice || ''); - const [isEditingSelfDisplayName, setIsEditingSelfDisplayName] = useState(false); - const [selfDisplayNameValue, setSelfDisplayNameValue] = useState(contract.selfDisplyName || ''); - const [isGroupNoticeModalVisible, setIsGroupNoticeModalVisible] = useState(false); + const [groupNoticeValue, setGroupNoticeValue] = useState( + contract.notice || "", + ); + const [isEditingSelfDisplayName, setIsEditingSelfDisplayName] = + useState(false); + const [selfDisplayNameValue, setSelfDisplayNameValue] = useState( + contract.selfDisplyName || "", + ); + const [isGroupNoticeModalVisible, setIsGroupNoticeModalVisible] = + useState(false); const [confirmLoading, setConfirmLoading] = useState(false); - - const currentGroupMembers = useWeChatStore( + const currentGroupMembers = useWeChatStore( state => state.currentGroupMembers, ); - const [hoveredMember, setHoveredMember] = useState(null); const [isAddFriendModalVisible, setIsAddFriendModalVisible] = useState(false); const [selectedMember, setSelectedMember] = useState(null); const [greeting, setGreeting] = useState(""); // 群管理弹窗状态 - const [isFriendSelectionVisible, setIsFriendSelectionVisible] = useState(false); - const [isMemberSelectionVisible, setIsMemberSelectionVisible] = useState(false); + const [isFriendSelectionVisible, setIsFriendSelectionVisible] = + useState(false); + const [isMemberSelectionVisible, setIsMemberSelectionVisible] = + useState(false); const [isAdminSelectionVisible, setIsAdminSelectionVisible] = useState(false); - const [isRemoveAdminSelectionVisible, setIsRemoveAdminSelectionVisible] = useState(false); - const [isTransferOwnerSelectionVisible, setIsTransferOwnerSelectionVisible] = useState(false); - const [selectedFriends, setSelectedFriends] = useState([]); + const [isRemoveAdminSelectionVisible, setIsRemoveAdminSelectionVisible] = + useState(false); + const [isTransferOwnerSelectionVisible, setIsTransferOwnerSelectionVisible] = + useState(false); + const [selectedFriends, setSelectedFriends] = useState( + [], + ); const [contractList, setContractList] = useState([]); - const handleAddFriend = (member) => { + const handleAddFriend = member => { setSelectedMember(member); setGreeting(`你好, 我来自群聊${contractInfo.name}`); setIsAddFriendModalVisible(true); }; // 群管理操作处理函数 - const handleAddMember = (selectedIds: number[], selectedItems: FriendSelectionItem[]) => { - console.log('添加成员:', selectedIds, selectedItems); - sendCommand("CmdChatroomInvite", { - wechatChatroomId: contract.id, - wechatFriendIds: selectedIds - }); + const handleAddMember = ( + selectedIds: number[], + selectedItems: FriendSelectionItem[], + ) => { + console.log("添加成员:", selectedIds, selectedItems); + sendCommand("CmdChatroomInvite", { + wechatChatroomId: contract.id, + wechatFriendIds: selectedIds, + }); messageApi.success(`已添加 ${selectedItems.length} 个成员`); setIsFriendSelectionVisible(false); }; //删除群成员 const handleRemoveMember = (selectedIds: string[]) => { - console.log('删除成员:', selectedIds); + console.log("删除成员:", selectedIds); sendCommand("CmdChatroomOperate", { - wechatAccountId: contract.wechatAccountId, - wechatChatroomId: contract.id, - chatroomOperateType: 2, - extra: JSON.stringify({ - friendIdList: selectedIds - }) - }); + wechatAccountId: contract.wechatAccountId, + wechatChatroomId: contract.id, + chatroomOperateType: 2, + extra: JSON.stringify({ + friendIdList: selectedIds, + }), + }); messageApi.success(`已删除 ${selectedIds.length} 个成员`); setIsMemberSelectionVisible(false); }; - //添加管理员 + //添加管理员 const handleAddAdmin = (selectedIds: string[]) => { - console.log('添加管理员:', selectedIds); - sendCommand("CmdChatroomOperate", { - wechatAccountId: contract.wechatAccountId, - wechatChatroomId: contract.id, - chatroomOperateType: 12, - extra: JSON.stringify({ - wechatIds: selectedIds - }) - }); + console.log("添加管理员:", selectedIds); + sendCommand("CmdChatroomOperate", { + wechatAccountId: contract.wechatAccountId, + wechatChatroomId: contract.id, + chatroomOperateType: 12, + extra: JSON.stringify({ + wechatIds: selectedIds, + }), + }); messageApi.success(`已添加 ${selectedIds.length} 个管理员`); setIsAdminSelectionVisible(false); }; //删除管理员 const handleRemoveAdmin = (selectedIds: string[]) => { - console.log('删除管理员:', selectedIds); + console.log("删除管理员:", selectedIds); selectedIds.forEach(wechatId => { sendCommand("CmdChatroomOperate", { @@ -152,8 +164,8 @@ const Person: React.FC = ({ wechatChatroomId: contract.id, chatroomOperateType: 8, // 8 for remove admin extra: JSON.stringify({ - wechatId: wechatId - }) + wechatId: wechatId, + }), }); }); @@ -164,7 +176,7 @@ const Person: React.FC = ({ //群主转让 √ const handleTransferOwner = (selectedIds: string[]) => { if (selectedIds.length !== 1) { - messageApi.error('只能选择一个成员作为新群主'); + messageApi.error("只能选择一个成员作为新群主"); return; } sendCommand("CmdChatroomOperate", { @@ -172,10 +184,10 @@ const Person: React.FC = ({ wechatChatroomId: contract.id, chatroomOperateType: 10, extra: JSON.stringify({ - wechatId: selectedIds[0] - }) + wechatId: selectedIds[0], + }), }); - messageApi.success('群主转让成功'); + messageApi.success("群主转让成功"); setIsTransferOwnerSelectionVisible(false); }; @@ -192,19 +204,19 @@ const Person: React.FC = ({ wechatChatroomId: contract.id, }); - messageApi.success('好友请求已发送'); + messageApi.success("好友请求已发送"); setIsAddFriendModalVisible(false); setSelectedMember(null); - setGreeting(''); + setGreeting(""); }; // 构建联系人或群聊详细信息 - const kfSelectedUser = useCkChatStore( - state => state.getKfUserInfo(contract.wechatAccountId || 0), + const kfSelectedUser = useCkChatStore(state => + state.getKfUserInfo(contract.wechatAccountId || 0), ); -const getSomeContractList = useCkChatStore( + const getSomeContractList = useCkChatStore( state => state.getSomeContractList, ); @@ -240,14 +252,21 @@ const getSomeContractList = useCkChatStore( setSelectedTags(contract.labels || []); if (isGroup) { - setGroupNameValue(contract.name || ''); + setGroupNameValue(contract.name || ""); setIsEditingGroupName(false); - setGroupNoticeValue(contract.notice || ''); + setGroupNoticeValue(contract.notice || ""); setIsEditingGroupNotice(false); - setSelfDisplayNameValue(contract.selfDisplyName || ''); + setSelfDisplayNameValue(contract.selfDisplyName || ""); setIsEditingSelfDisplayName(false); } - }, [contract.conRemark, contract.labels, contract.name, contract.notice, contract.selfDisplyName, isGroup]); + }, [ + contract.conRemark, + contract.labels, + contract.name, + contract.notice, + contract.selfDisplyName, + isGroup, + ]); // 处理备注保存 const handleSaveRemark = () => { @@ -287,7 +306,7 @@ const getSomeContractList = useCkChatStore( // 点击编辑群名称按钮 const handleEditGroupName = () => { - setGroupNameValue(contractInfo.name || ''); + setGroupNameValue(contractInfo.name || ""); setIsEditingGroupName(true); }; @@ -311,7 +330,7 @@ const getSomeContractList = useCkChatStore( // 点击编辑群公告按钮 const handleEditGroupNotice = () => { - setGroupNoticeValue(contract.notice || ''); + setGroupNoticeValue(contract.notice || ""); setIsGroupNoticeModalVisible(true); }; @@ -330,7 +349,7 @@ const getSomeContractList = useCkChatStore( // 点击编辑群昵称按钮 const handleEditSelfDisplayName = () => { - setSelfDisplayNameValue(contract.selfDisplyName || ''); + setSelfDisplayNameValue(contract.selfDisplyName || ""); setIsEditingSelfDisplayName(true); }; @@ -594,7 +613,9 @@ const getSomeContractList = useCkChatStore(
群主: - {contractInfo.chatroomOwner} + + {contractInfo.chatroomOwner} +
@@ -610,7 +631,9 @@ const getSomeContractList = useCkChatStore( > setSelfDisplayNameValue(e.target.value)} + onChange={e => + setSelfDisplayNameValue(e.target.value) + } placeholder="请输入群昵称" size="small" style={{ flex: 1 }} @@ -627,7 +650,9 @@ const getSomeContractList = useCkChatStore( size="small" icon={} onClick={() => { - setSelfDisplayNameValue(contract.selfDisplyName || ''); + setSelfDisplayNameValue( + contract.selfDisplyName || "", + ); setIsEditingSelfDisplayName(false); }} style={{ color: "#ff4d4f" }} @@ -641,7 +666,9 @@ const getSomeContractList = useCkChatStore( gap: "8px", }} > - {contractInfo.selfDisplyName || "点击添加群昵称"} + + {contractInfo.selfDisplyName || "点击添加群昵称"} +
)} @@ -815,7 +844,10 @@ const getSomeContractList = useCkChatStore( )} {/* 个人简介或群公告 */} - + {isGroup ? ( // 群聊简介(原群公告)
-
-
+
+
{hasGroupManagePermission() && ( -
+
- - - - )} - - setIsAddFriendModalVisible(false)} - okText="确定" - cancelText="取消" - > - setGreeting(e.target.value)} - placeholder="请输入招呼语" - rows={4} - /> - - + + + )} + setIsAddFriendModalVisible(false)} + okText="确定" + cancelText="取消" + > + setGreeting(e.target.value)} + placeholder="请输入招呼语" + rows={4} + /> +
@@ -1054,7 +1105,10 @@ const getSomeContractList = useCkChatStore( open={isGroupNoticeModalVisible} onCancel={() => setIsGroupNoticeModalVisible(false)} footer={[ - ,