feat: 对话中打开用户的资料

This commit is contained in:
CrescentLeaf
2025-10-04 15:32:54 +08:00
parent 81cdb4afd9
commit debdb93935
6 changed files with 122 additions and 17 deletions

View File

@@ -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<Dialog>(null)
const [userInfo, setUserInfo] = React.useState(null as unknown as User)
const addContactDialogRef = React.useRef<Dialog>(null)
const chatInfoDialogRef = React.useRef<Dialog>(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 (
<div style={{
display: "flex",
@@ -118,13 +138,14 @@ export default function App() {
<MyProfileDialog
myProfileDialogRef={myProfileDialogRef as any}
user={myUserProfileCache} />
<UserProfileDialog
userProfileDialogRef={userProfileDialogRef as any}
openChatFragment={openChatFragment}
user={userInfo} />
<ChatInfoDialog
chatInfoDialogRef={chatInfoDialogRef as any}
openChatFragment={(id) => {
setCurrentChatId(id)
setIsShowChatFragment(true)
}}
openChatFragment={openChatFragment}
chat={chatInfo} />
<AddContactDialog
@@ -147,10 +168,7 @@ export default function App() {
{
// 最近聊天
<RecentsList
openChatFragment={(id) => {
setCurrentChatId(id)
setIsShowChatFragment(true)
}}
openChatFragment={openChatFragment}
display={navigationItemSelected == "Recents"}
currentChatId={currentChatId} />
}
@@ -181,6 +199,7 @@ export default function App() {
{
isShowChatFragment && <ChatFragment
target={currentChatId}
openUserInfoDialog={openUserInfoDialog}
openChatInfoDialog={openChatInfoDialog}
key={currentChatId} />
}

View File

@@ -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<Dialog>(null)
const [chatInfo, setChatInfo] = React.useState(null as unknown as Chat)
const userProfileDialogRef = React.useRef<Dialog>(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 (
<div style={{
display: "flex",
@@ -114,6 +134,7 @@ export default function AppMobile() {
}}>
<ChatFragment
showReturnButton={true}
openUserInfoDialog={openUserInfoDialog}
onReturnButtonClicked={() => setIsShowChatFragment(false)}
key={currentChatId}
openChatInfoDialog={openChatInfoDialog}
@@ -138,6 +159,10 @@ export default function AppMobile() {
<MyProfileDialog
myProfileDialogRef={myProfileDialogRef as any}
user={myUserProfileCache} />
<UserProfileDialog
userProfileDialogRef={userProfileDialogRef as any}
openChatFragment={openChatFragment}
user={userInfo} />
<ChatInfoDialog
chatInfoDialogRef={chatInfoDialogRef as any}

View File

@@ -14,13 +14,15 @@ import useAsyncEffect from "../useAsyncEffect.ts"
import * as marked from 'marked'
import DOMPurify from 'dompurify'
import randomUUID from "../../randomUUID.ts"
import EventBus from "../../EventBus.ts";
import EventBus from "../../EventBus.ts"
import User from "../../api/client_data/User.ts"
interface Args extends React.HTMLAttributes<HTMLElement> {
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 (
<>

View File

@@ -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<HTMLElement> {
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 && <span
@@ -128,7 +130,7 @@ export default function Message({ userId, rawData, renderHTML, message, ...props
}}>
<mdui-menu-item icon="content_copy" onClick={() => copyToClipboard($(dropDownRef.current as HTMLElement).find('#msg').text().trim())}></mdui-menu-item>
<mdui-menu-item icon="content_copy" onClick={() => copyToClipboard(rawData)}></mdui-menu-item>
<mdui-menu-item icon="info" onClick={() => messageJsonDialogRef.current.open = true}></mdui-menu-item>
<mdui-menu-item icon="info" onClick={() => messageJsonDialogRef.current!.open = true}></mdui-menu-item>
</mdui-menu>
</mdui-dropdown>
</mdui-card>

View File

@@ -18,8 +18,6 @@ export default function MyProfileDialog({
myProfileDialogRef,
user
}: Refs) {
const isMySelf = Client.myUserProfile?.id == user?.id
const editAvatarButtonRef = React.useRef<HTMLElement>(null)
const chooseAvatarFileRef = React.useRef<HTMLInputElement>(null)
useEventListener(editAvatarButtonRef, 'click', () => chooseAvatarFileRef.current!.click())

View File

@@ -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<Dialog>
openChatFragment: (id: string) => void
user: User
}
export default function UserProfileDialog({
userProfileDialogRef,
openChatFragment,
user
}: Refs) {
return (
<mdui-dialog close-on-overlay-click close-on-esc ref={userProfileDialogRef}>
<div style={{
display: 'flex',
alignItems: 'center',
}}>
<Avatar src={user?.avatar} text={user?.nickname} style={{
width: '50px',
height: '50px',
}} />
<span style={{
marginLeft: "15px",
fontSize: '16.5px',
}}>{user?.nickname}</span>
</div>
<mdui-divider style={{
marginTop: "10px",
}}></mdui-divider>
<mdui-list>
{/* <mdui-list-item icon="edit" rounded>设置备注</mdui-list-item> */}
<mdui-list-item icon="chat" rounded onClick={async () => {
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
}}></mdui-list-item>
</mdui-list>
</mdui-dialog>
)
}