From 937af276985c5e75922e737341a2a7edc5840fc9 Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Sun, 26 Oct 2025 23:04:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4=E6=94=B6=E8=97=8F?= =?UTF-8?q?=E7=9A=84=E5=AF=B9=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/ui/main/ContactsList.tsx | 96 ++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/client/ui/main/ContactsList.tsx b/client/ui/main/ContactsList.tsx index d91473f..17ac21d 100644 --- a/client/ui/main/ContactsList.tsx +++ b/client/ui/main/ContactsList.tsx @@ -1,11 +1,10 @@ import React from "react" import ContactsListItem from "./ContactsListItem.tsx" import useEventListener from "../useEventListener.ts" -import { Dialog, ListItem, TextField } from "mdui" -import useAsyncEffect from "../useAsyncEffect.ts" +import { dialog, Dialog, TextField } from "mdui" import Client from "../../api/Client.ts" import data from "../../Data.ts" -import { checkApiSuccessOrSncakbar } from "../snackbar.ts" +import { checkApiSuccessOrSncakbar, snackbar } from "../snackbar.ts" import Chat from "../../api/client_data/Chat.ts" import EventBus from "../../EventBus.ts" @@ -27,24 +26,29 @@ export default function ContactsList({ const [isMultiSelecting, setIsMultiSelecting] = React.useState(false) const [searchText, setSearchText] = React.useState('') const [contactsList, setContactsList] = React.useState([]) + const [checkedList, setCheckedList] = React.useState<{ [key: string]: boolean }>({}) useEventListener(searchRef, 'input', (e) => { setSearchText((e.target as unknown as TextField).value) }) - useAsyncEffect(async () => { + React.useEffect(() => { async function updateContacts() { const re = await Client.invoke("User.getMyContacts", { token: data.access_token, }) if (re.code != 200) return checkApiSuccessOrSncakbar(re, "获取所有对话列表失败") - + setContactsList(re.data!.contacts_list as Chat[]) } updateContacts() EventBus.on('ContactsList.updateContacts', () => updateContacts()) - }) + return () => { + EventBus.off('ContactsList.updateContacts') + } + // 警告: 不添加 deps 導致無限執行 + }, []) return EventBus.emit('ContactsList.updateContacts')}>刷新 - {/* setIsMultiSelecting(!isMultiSelecting)}>{ isMultiSelecting ? "關閉多選" : "多選模式" } */} + }} icon={isMultiSelecting ? "done" : "edit"} onClick={() => { + if (isMultiSelecting) + setCheckedList({}) + setIsMultiSelecting(!isMultiSelecting) + }}>{isMultiSelecting ? "关闭多选" : "多选模式"} + { + isMultiSelecting && <> + dialog({ + headline: "删除所选", + description: "确定要删除所选的收藏对话吗? 这并不会删除您的聊天记录, 也不会丢失对话成员身份", + actions: [ + { + text: "取消", + onClick: () => { + return true + }, + }, + { + text: "确定", + onClick: async () => { + const ls = Object.keys(checkedList).filter((chatId) => checkedList[chatId] == true) + const re = await Client.invoke("User.removeContacts", { + token: data.access_token, + targets: ls, + }) + if (re.code != 200) + checkApiSuccessOrSncakbar(re, "删除所选收藏失败") + else { + setCheckedList({}) + setIsMultiSelecting(false) + EventBus.emit('ContactsList.updateContacts') + snackbar({ + message: "已删除所选", + placement: "top", + action: "撤销操作", + onActionClick: async () => { + const re = await Client.invoke("User.addContacts", { + token: data.access_token, + targets: ls, + }) + if (re.code != 200) + checkApiSuccessOrSncakbar(re, "恢复所选收藏失败") + EventBus.emit('ContactsList.updateContacts') + } + }) + } + }, + } + ], + })}>删除所选 + + } +
{ contactsList.filter((chat) => @@ -82,14 +140,16 @@ export default function ContactsList({ chat.id.includes(searchText) ).map((v) => { - const self = (e.target as ListItem) - /*if (isMultiSelecting) - self.active = !self.active - else*/ - openChatInfoDialog(v) - }} + active={checkedList[v.id] == true} + onClick={() => { + if (isMultiSelecting) + setCheckedList({ + ...checkedList, + [v.id]: !checkedList[v.id], + }) + else + openChatInfoDialog(v) + }} key={v.id} contact={v} /> )