From debdb939353fca5a6e809f9a8b3395d617dd9950 Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Sat, 4 Oct 2025 15:32:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9=E8=AF=9D=E4=B8=AD=E6=89=93?= =?UTF-8?q?=E5=BC=80=E7=94=A8=E6=88=B7=E7=9A=84=E8=B5=84=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/ui/App.tsx | 35 ++++++++++++---- client/ui/AppMobile.tsx | 25 +++++++++++ client/ui/chat/ChatFragment.tsx | 9 ++-- client/ui/chat/Message.tsx | 10 +++-- client/ui/dialog/MyProfileDialog.tsx | 2 - client/ui/dialog/UserProfileDialog.tsx | 58 ++++++++++++++++++++++++++ 6 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 client/ui/dialog/UserProfileDialog.tsx diff --git a/client/ui/App.tsx b/client/ui/App.tsx index 0f05267..d15416d 100644 --- a/client/ui/App.tsx +++ b/client/ui/App.tsx @@ -21,6 +21,8 @@ import useAsyncEffect from "./useAsyncEffect.ts" import ChatInfoDialog from "./dialog/ChatInfoDialog.tsx" import Chat from "../api/client_data/Chat.ts" import AddContactDialog from './dialog/AddContactDialog.tsx' +import UserProfileDialog from "./dialog/UserProfileDialog.tsx" +import DataCaches from "../api/DataCaches.ts" declare global { namespace React { @@ -56,6 +58,9 @@ export default function App() { myProfileDialogRef.current!.open = true }) + const userProfileDialogRef = React.useRef(null) + const [userInfo, setUserInfo] = React.useState(null as unknown as User) + const addContactDialogRef = React.useRef(null) const chatInfoDialogRef = React.useRef(null) @@ -94,6 +99,21 @@ export default function App() { chatInfoDialogRef.current!.open = true } + function openChatFragment(chatId: string) { + setCurrentChatId(chatId) + setIsShowChatFragment(true) + } + + async function openUserInfoDialog(user: User | string) { + if (user instanceof User) { + setUserInfo(user) + } else { + setUserInfo(await DataCaches.getUserProfile(user)) + + } + userProfileDialogRef.current!.open = true + } + return (
+ { - setCurrentChatId(id) - setIsShowChatFragment(true) - }} + openChatFragment={openChatFragment} chat={chatInfo} /> { - setCurrentChatId(id) - setIsShowChatFragment(true) - }} + openChatFragment={openChatFragment} display={navigationItemSelected == "Recents"} currentChatId={currentChatId} /> } @@ -181,6 +199,7 @@ export default function App() { { isShowChatFragment && } diff --git a/client/ui/AppMobile.tsx b/client/ui/AppMobile.tsx index c6f3093..f7bf11e 100644 --- a/client/ui/AppMobile.tsx +++ b/client/ui/AppMobile.tsx @@ -20,6 +20,8 @@ import useAsyncEffect from "./useAsyncEffect.ts" import ChatInfoDialog from "./dialog/ChatInfoDialog.tsx" import Chat from "../api/client_data/Chat.ts" import AddContactDialog from './dialog/AddContactDialog.tsx' +import UserProfileDialog from "./dialog/UserProfileDialog.tsx" +import DataCaches from "../api/DataCaches.ts" declare global { namespace React { @@ -60,6 +62,9 @@ export default function AppMobile() { const chatInfoDialogRef = React.useRef(null) const [chatInfo, setChatInfo] = React.useState(null as unknown as Chat) + const userProfileDialogRef = React.useRef(null) + const [userInfo, setUserInfo] = React.useState(null as unknown as User) + const [myUserProfileCache, setMyUserProfileCache] = React.useState(null as unknown as User) const [isShowChatFragment, setIsShowChatFragment] = React.useState(false) @@ -96,6 +101,21 @@ export default function AppMobile() { chatInfoDialogRef.current!.open = true } + function openChatFragment(chatId: string) { + setCurrentChatId(chatId) + setIsShowChatFragment(true) + } + + async function openUserInfoDialog(user: User | string) { + if (user instanceof User) { + setUserInfo(user) + } else { + setUserInfo(await DataCaches.getUserProfile(user)) + + } + userProfileDialogRef.current!.open = true + } + return (
setIsShowChatFragment(false)} key={currentChatId} openChatInfoDialog={openChatInfoDialog} @@ -138,6 +159,10 @@ export default function AppMobile() { + { target: string showReturnButton?: boolean openChatInfoDialog: (chat: Chat) => void onReturnButtonClicked?: () => void + openUserInfoDialog: (user: User | string) => void } const markedInstance = new marked.Marked({ @@ -47,7 +49,7 @@ const markedInstance = new marked.Marked({ } }) -export default function ChatFragment({ target, showReturnButton, onReturnButtonClicked, openChatInfoDialog, ...props }: Args) { +export default function ChatFragment({ target, showReturnButton, onReturnButtonClicked, openChatInfoDialog, openUserInfoDialog, ...props }: Args) { const [messagesList, setMessagesList] = React.useState([] as Message[]) const [chatInfo, setChatInfo] = React.useState({ title: '加載中...' @@ -305,7 +307,8 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC key={msg.id} slot="trigger" id={`chat_${target}_message_${msg.id}`} - userId={msg.user_id} /> + userId={msg.user_id} + openUserInfoDialog={openUserInfoDialog} /> return ( <> diff --git a/client/ui/chat/Message.tsx b/client/ui/chat/Message.tsx index 45ab6b2..207a421 100644 --- a/client/ui/chat/Message.tsx +++ b/client/ui/chat/Message.tsx @@ -8,18 +8,19 @@ import copyToClipboard from "../copyToClipboard.ts" import useAsyncEffect from "../useAsyncEffect.ts" import useEventListener from "../useEventListener.ts" import React from "react" -import useEventListener from "../useEventListener.ts" import isMobileUI from "../isMobileUI.ts" import ReactJson from 'react-json-view' +import User from "../../api/client_data/User.ts" interface Args extends React.HTMLAttributes { userId: string rawData: string renderHTML: string message: Data_Message + openUserInfoDialog: (user: User | string) => void } -export default function Message({ userId, rawData, renderHTML, message, ...props }: Args) { +export default function Message({ userId, rawData, renderHTML, message, openUserInfoDialog, ...props }: Args) { const isAtRight = Client.myUserProfile?.id == userId const [nickName, setNickName] = React.useState("") @@ -87,7 +88,8 @@ export default function Message({ userId, rawData, renderHTML, message, ...props width: "43px", height: "43px", margin: "11px" - }} /> + }} + onClick={() => openUserInfoDialog(userId)} /> { // 发送者昵称(右) !isAtRight && copyToClipboard($(dropDownRef.current as HTMLElement).find('#msg').text().trim())}>複製文字 copyToClipboard(rawData)}>複製原文 - messageJsonDialogRef.current.open = true}>查看詳情 + messageJsonDialogRef.current!.open = true}>查看詳情 diff --git a/client/ui/dialog/MyProfileDialog.tsx b/client/ui/dialog/MyProfileDialog.tsx index 95978cf..4f0b616 100644 --- a/client/ui/dialog/MyProfileDialog.tsx +++ b/client/ui/dialog/MyProfileDialog.tsx @@ -18,8 +18,6 @@ export default function MyProfileDialog({ myProfileDialogRef, user }: Refs) { - const isMySelf = Client.myUserProfile?.id == user?.id - const editAvatarButtonRef = React.useRef(null) const chooseAvatarFileRef = React.useRef(null) useEventListener(editAvatarButtonRef, 'click', () => chooseAvatarFileRef.current!.click()) diff --git a/client/ui/dialog/UserProfileDialog.tsx b/client/ui/dialog/UserProfileDialog.tsx new file mode 100644 index 0000000..2644347 --- /dev/null +++ b/client/ui/dialog/UserProfileDialog.tsx @@ -0,0 +1,58 @@ +import * as React from 'react' +import { Button, Dialog, TextField, dialog } from "mdui" +import useEventListener from "../useEventListener.ts" +import { checkApiSuccessOrSncakbar, snackbar } from "../snackbar.ts" +import Client from "../../api/Client.ts" + +import * as CryptoJS from 'crypto-js' +import data from "../../Data.ts" +import Avatar from "../Avatar.tsx" +import User from "../../api/client_data/User.ts" + +interface Refs { + userProfileDialogRef: React.MutableRefObject + openChatFragment: (id: string) => void + user: User +} + +export default function UserProfileDialog({ + userProfileDialogRef, + openChatFragment, + user +}: Refs) { + return ( + +
+ + {user?.nickname} +
+ + + + {/* 设置备注 */} + { + const re = await Client.invoke("Chat.getIdForPrivate", { + token: data.access_token, + target: user.id, + }) + if (re.code != 200) + return checkApiSuccessOrSncakbar(re, '获取对话失败') + + openChatFragment(re.data!.chat_id as string) + userProfileDialogRef.current!.open = false + }}>对话 + +
+ ) +} \ No newline at end of file