feat: 加入对话请求
This commit is contained in:
@@ -17,7 +17,7 @@ export type CallMethod =
|
||||
"User.getMyRecentChats" |
|
||||
|
||||
"Chat.getInfo" |
|
||||
|
||||
|
||||
"Chat.updateSettings" |
|
||||
|
||||
"Chat.createGroup" |
|
||||
@@ -25,6 +25,10 @@ export type CallMethod =
|
||||
"Chat.getIdForPrivate" |
|
||||
"Chat.getAnotherUserIdFromPrivate" |
|
||||
|
||||
"Chat.processJoinRequest" |
|
||||
"Chat.sendJoinRequest" |
|
||||
"Chat.getJoinRequests" |
|
||||
|
||||
"Chat.sendMessage" |
|
||||
"Chat.getMessageHistory" |
|
||||
|
||||
|
||||
8
client/api/client_data/JoinRequest.ts
Normal file
8
client/api/client_data/JoinRequest.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export default class JoinRequest {
|
||||
declare user_id: string
|
||||
declare title: string
|
||||
declare avatar?: string
|
||||
declare reason?: string
|
||||
|
||||
[key: string]: unknown
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import Preference from '../preference/Preference.tsx'
|
||||
import GroupSettings from "../../api/client_data/GroupSettings.ts"
|
||||
import PreferenceUpdater from "../preference/PreferenceUpdater.ts"
|
||||
import SystemMessage from "./SystemMessage.tsx"
|
||||
import JoinRequestsList from "./JoinRequestsList.tsx";
|
||||
|
||||
interface Args extends React.HTMLAttributes<HTMLElement> {
|
||||
target: string
|
||||
@@ -86,7 +87,7 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
|
||||
setChatInfo(chatInfo)
|
||||
|
||||
if (chatInfo.is_member)
|
||||
await loadMore()
|
||||
await loadMore()
|
||||
|
||||
setTabItemSelected(chatInfo.is_member ? "Chat" : "RequestJoin")
|
||||
if (re.data!.type == 'group') {
|
||||
@@ -253,10 +254,13 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
|
||||
marginRight: '5px',
|
||||
}}></mdui-button-icon>
|
||||
}
|
||||
<mdui-tab value="Chat">{
|
||||
chatInfo.title
|
||||
}</mdui-tab>
|
||||
{chatInfo.type == 'group' && <mdui-tab value="NewMemberRequests">入群申请</mdui-tab>}
|
||||
{
|
||||
chatInfo.is_member ? <>
|
||||
<mdui-tab value="Chat">{chatInfo.title}</mdui-tab>
|
||||
{chatInfo.type == 'group' && chatInfo.is_admin && <mdui-tab value="NewMemberRequests">加入请求</mdui-tab>}
|
||||
</>
|
||||
: <mdui-tab value="RequestJoin">{chatInfo.title}</mdui-tab>
|
||||
}
|
||||
<mdui-tab value="Settings">设置</mdui-tab>
|
||||
<mdui-tab value="None" style={{ display: 'none' }}></mdui-tab>
|
||||
<div style={{
|
||||
@@ -268,6 +272,29 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
|
||||
marginRight: '5px',
|
||||
}}></mdui-button-icon>
|
||||
|
||||
<mdui-tab-panel slot="panel" value="RequestJoin" style={{
|
||||
display: tabItemSelected == "RequestJoin" ? "flex" : "none",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}>
|
||||
<div>
|
||||
<mdui-button onClick={async () => {
|
||||
const re = await Client.invoke("Chat.sendJoinRequest", {
|
||||
token: data.access_token,
|
||||
target: target,
|
||||
})
|
||||
if (re.code != 200)
|
||||
return checkApiSuccessOrSncakbar(re, "发送加入请求失败")
|
||||
|
||||
snackbar({
|
||||
message: '发送成功!',
|
||||
placement: 'top',
|
||||
})
|
||||
}}>请求加入对话</mdui-button>
|
||||
</div>
|
||||
</mdui-tab-panel>
|
||||
<mdui-tab-panel slot="panel" value="Chat" ref={chatPanelRef} style={{
|
||||
display: tabItemSelected == "Chat" ? "flex" : "none",
|
||||
flexDirection: "column",
|
||||
@@ -457,7 +484,7 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
}}>
|
||||
未制作
|
||||
{tabItemSelected == "NewMemberRequests" && <JoinRequestsList target={target} />}
|
||||
</mdui-tab-panel>
|
||||
}
|
||||
<mdui-tab-panel slot="panel" value="Settings" style={{
|
||||
|
||||
104
client/ui/chat/JoinRequestsList.tsx
Normal file
104
client/ui/chat/JoinRequestsList.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import { TextField } from "mdui"
|
||||
import RecentChat from "../../api/client_data/RecentChat.ts"
|
||||
import useEventListener from "../useEventListener.ts"
|
||||
import RecentsListItem from "./JoinRequestsListItem.tsx"
|
||||
import React from "react"
|
||||
import useAsyncEffect from "../useAsyncEffect.ts"
|
||||
import Client from "../../api/Client.ts"
|
||||
import { checkApiSuccessOrSncakbar } from "../snackbar.ts"
|
||||
import data from "../../Data.ts"
|
||||
import EventBus from "../../EventBus.ts"
|
||||
import isMobileUI from "../isMobileUI.ts"
|
||||
import JoinRequest from "../../api/client_data/JoinRequest.ts"
|
||||
import JoinRequestsListItem from "./JoinRequestsListItem.tsx";
|
||||
|
||||
interface Args extends React.HTMLAttributes<HTMLElement> {
|
||||
target: string
|
||||
}
|
||||
|
||||
export default function JoinRequestsList({
|
||||
target,
|
||||
...props
|
||||
}: Args) {
|
||||
const searchRef = React.useRef<HTMLElement>(null)
|
||||
const [searchText, setSearchText] = React.useState('')
|
||||
const [updateJoinRequests, setUpdateJoinRequests] = React.useState<JoinRequest[]>([])
|
||||
|
||||
useEventListener(searchRef, 'input', (e) => {
|
||||
setSearchText((e.target as unknown as TextField).value)
|
||||
})
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
async function updateJoinRequests() {
|
||||
const re = await Client.invoke("Chat.getJoinRequests", {
|
||||
token: data.access_token,
|
||||
target: target,
|
||||
})
|
||||
if (re.code != 200)
|
||||
return checkApiSuccessOrSncakbar(re, "获取加入请求列表失败")
|
||||
|
||||
setUpdateJoinRequests(re.data!.join_requests as JoinRequest[])
|
||||
}
|
||||
updateJoinRequests()
|
||||
EventBus.on('JoinRequestsList.updateJoinRequests', () => updateJoinRequests())
|
||||
setTimeout(() => updateJoinRequests(), 15 * 1000)
|
||||
})
|
||||
|
||||
async function removeJoinRequest(userId: string) {
|
||||
const re = await Client.invoke("Chat.processJoinRequest", {
|
||||
token: data.access_token,
|
||||
chat_id: target,
|
||||
user_id: userId,
|
||||
action: 'remove',
|
||||
})
|
||||
if (re.code != 200)
|
||||
return checkApiSuccessOrSncakbar(re, "删除加入请求失败")
|
||||
|
||||
EventBus.emit('JoinRequestsList.updateJoinRequests')
|
||||
}
|
||||
async function acceptJoinRequest(userId: string) {
|
||||
const re = await Client.invoke("Chat.processJoinRequest", {
|
||||
token: data.access_token,
|
||||
chat_id: target,
|
||||
user_id: userId,
|
||||
action: 'accept',
|
||||
})
|
||||
if (re.code != 200)
|
||||
return checkApiSuccessOrSncakbar(re, "通过加入请求失败")
|
||||
|
||||
EventBus.emit('JoinRequestsList.updateJoinRequests')
|
||||
}
|
||||
|
||||
return <mdui-list style={{
|
||||
overflowY: 'auto',
|
||||
paddingRight: '10px',
|
||||
paddingLeft: '10px',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}} {...props}>
|
||||
<mdui-text-field icon="search" type="search" clearable ref={searchRef} variant="outlined" placeholder="搜索..." style={{
|
||||
marginTop: '5px',
|
||||
marginBottom: '13px',
|
||||
}}></mdui-text-field>
|
||||
|
||||
<mdui-list-item rounded style={{
|
||||
width: '100%',
|
||||
marginBottom: '15px',
|
||||
}} icon="refresh" onClick={() => EventBus.emit('JoinRequestsList.updateJoinRequests')}>刷新</mdui-list-item>
|
||||
|
||||
{
|
||||
updateJoinRequests.filter((joinRequest) =>
|
||||
searchText == '' ||
|
||||
joinRequest.title.includes(searchText) ||
|
||||
joinRequest.reason?.includes(searchText) ||
|
||||
joinRequest.user_id.includes(searchText)
|
||||
).map((v) =>
|
||||
<JoinRequestsListItem
|
||||
key={v.user_id}
|
||||
acceptJoinRequest={acceptJoinRequest}
|
||||
removeJoinRequest={removeJoinRequest}
|
||||
joinRequest={v} />
|
||||
)
|
||||
}
|
||||
</mdui-list>
|
||||
}
|
||||
41
client/ui/chat/JoinRequestsListItem.tsx
Normal file
41
client/ui/chat/JoinRequestsListItem.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { $ } from "mdui/jq"
|
||||
import RecentChat from "../../api/client_data/RecentChat.ts"
|
||||
import Avatar from "../Avatar.tsx"
|
||||
import React from 'react'
|
||||
import JoinRequest from "../../api/client_data/JoinRequest.ts"
|
||||
|
||||
interface Args extends React.HTMLAttributes<HTMLElement> {
|
||||
joinRequest: JoinRequest
|
||||
acceptJoinRequest: (userId: string) => any
|
||||
removeJoinRequest: (userId: string) => any
|
||||
}
|
||||
|
||||
export default function JoinRequestsListItem({ joinRequest, acceptJoinRequest, removeJoinRequest }: Args) {
|
||||
const { user_id, title, avatar, reason } = joinRequest
|
||||
|
||||
const itemRef = React.useRef<HTMLElement>(null)
|
||||
React.useEffect(() => {
|
||||
$(itemRef.current!.shadowRoot).find('.headline').css('margin-top', '3px')
|
||||
})
|
||||
return (
|
||||
<mdui-list-item rounded style={{
|
||||
marginTop: '3px',
|
||||
marginBottom: '3px',
|
||||
}} ref={itemRef}>
|
||||
{title}
|
||||
<Avatar src={avatar} text={title} slot="icon" />
|
||||
<span slot="description"
|
||||
style={{
|
||||
width: "100%",
|
||||
display: "inline-block",
|
||||
whiteSpace: "nowrap", /* 禁止换行 */
|
||||
overflow: "hidden", /* 隐藏溢出内容 */
|
||||
textOverflow: "ellipsis", /* 显示省略号 */
|
||||
}}>请求原因: {reason || "无"}</span>
|
||||
<div slot="end-icon">
|
||||
<mdui-button-icon icon="check" onClick={() => acceptJoinRequest(user_id)}></mdui-button-icon>
|
||||
<mdui-button-icon icon="delete" onClick={() => removeJoinRequest(user_id)}></mdui-button-icon>
|
||||
</div>
|
||||
</mdui-list-item>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user