From 4cb75222512a7c111e32690a928cf1e0e11bd7c5 Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Sat, 22 Nov 2025 01:25:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BE=A4=E7=BB=84=E6=88=90=E5=91=98?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/ui/chat/ChatFragment.tsx | 20 ++++--- client/ui/chat/GroupMembersList.tsx | 74 +++++++++++++++++++++++++ client/ui/chat/GroupMembersListItem.tsx | 28 ++++++++++ server/api/ChatApi.ts | 43 ++++++++++++++ 4 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 client/ui/chat/GroupMembersList.tsx create mode 100644 client/ui/chat/GroupMembersListItem.tsx diff --git a/client/ui/chat/ChatFragment.tsx b/client/ui/chat/ChatFragment.tsx index ed357c6..eae0c26 100644 --- a/client/ui/chat/ChatFragment.tsx +++ b/client/ui/chat/ChatFragment.tsx @@ -30,6 +30,7 @@ import SystemMessage from "./SystemMessage.tsx" import JoinRequestsList from "./JoinRequestsList.tsx" import getUrlForFileByHash from "../../getUrlForFileByHash.ts" import escapeHTML from "../../escapeHtml.ts" +import GroupMembersList from "./GroupMembersList.tsx" interface Args extends React.HTMLAttributes { target: string @@ -89,7 +90,7 @@ const markedInstance = new marked.Marked({ case "ChatMention": return `PH` } - return `${ escapeHTML(`[无效数据 (<${text}>=${href})]`) }` + return `${escapeHTML(`[无效数据 (<${text}>=${href})]`)}` }, } }) @@ -339,6 +340,7 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC chatInfo.is_member ? <> {chatInfo.title} {chatInfo.type == 'group' && chatInfo.is_admin && 加入请求} + {chatInfo.type == 'group' && 群组成员} : {chatInfo.title} } @@ -559,6 +561,15 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC + { + chatInfo.type == 'group' && + {tabItemSelected == "GroupMembers" && } + + } { chatInfo.type == 'group' && - {/* - */} { + target: string +} + +export default function GroupMembersList({ + target, + ...props +}: Args) { + const searchRef = React.useRef(null) + const [searchText, setSearchText] = React.useState('') + const [groupMembers, setGroupMembers] = React.useState([]) + + useEventListener(searchRef, 'input', (e) => { + setSearchText((e.target as unknown as TextField).value) + }) + + useAsyncEffect(async () => { + async function updateMembers() { + const re = await Client.invoke("Chat.getMembers", { + token: data.access_token, + target: target, + }) + if (re.code != 200) + return checkApiSuccessOrSncakbar(re, "获取群组成员列表失败") + + setGroupMembers(re.data!.members as User[]) + } + updateMembers() + EventBus.on('GroupMembersList.updateMembers', () => updateMembers()) + setTimeout(() => updateMembers(), 15 * 1000) + }) + + return + + + EventBus.emit('GroupMembersList.updateMembers')}>刷新 + + { + groupMembers.filter((user) => + searchText == '' || + user.nickname.includes(searchText) || + user.username?.includes(searchText) || + user.id.includes(searchText) + ).map((v) => + + ) + } + +} \ No newline at end of file diff --git a/client/ui/chat/GroupMembersListItem.tsx b/client/ui/chat/GroupMembersListItem.tsx new file mode 100644 index 0000000..8020a8f --- /dev/null +++ b/client/ui/chat/GroupMembersListItem.tsx @@ -0,0 +1,28 @@ +import { $ } from "mdui/jq" +import Avatar from "../Avatar.tsx" +import React from 'react' +import User from "../../api/client_data/User.ts" +import getUrlForFileByHash from "../../getUrlForFileByHash.ts" + +interface Args extends React.HTMLAttributes { + user: User +} + +export default function GroupMembersListItem({ user }: Args) { + const { nickname, avatar_file_hash } = user + + const itemRef = React.useRef(null) + return ( + + {nickname} + + {/*
+ + +
*/} +
+ ) +} diff --git a/server/api/ChatApi.ts b/server/api/ChatApi.ts index 4620745..694e38a 100644 --- a/server/api/ChatApi.ts +++ b/server/api/ChatApi.ts @@ -620,5 +620,48 @@ export default class ChatApi extends BaseApi { msg: "非私聊对话", } }) + /** + * 获取所有的加入对话申请 + * @param token 令牌 + * @param target ID + */ + this.registerEvent("Chat.getMembers", (args, { deviceId }) => { + if (this.checkArgsMissing(args, ['token', 'target'])) return { + msg: "参数缺失", + code: 400, + } + + const token = TokenManager.decode(args.token as string) + if (!this.checkToken(token, deviceId)) return { + code: 401, + msg: "令牌无效", + } + + const chat = Chat.findById(args.target as string) + if (chat == null) return { + code: 404, + msg: "对话不存在", + } + if (!UserChatLinker.checkUserIsLinkedToChat(token.author, chat!.bean.id)) return { + code: 403, + msg: "用户无权访问此对话", + } + + return { + code: 200, + msg: '成功', + data: { + members: chat.getMembersList().map((v) => { + const user = User.findById(v) + return user && { + id: user?.bean.id, + nickname: user.getNickName(), + username: user.getUserName(), + avatar_file_hash: user.getAvatarFileHash(), + } + }), + } + } + }) } } \ No newline at end of file