feat: 增加移出群组的前端操作

并优化了踢出用户的操作退出流程
pull/64/head
moonrailgun 2 years ago
parent 49ca9ca3ae
commit 070a762e4d

@ -394,3 +394,15 @@ export async function muteGroupMember(
muteMs,
});
}
/**
*
* @param groupId ID
* @param memberId ID
*/
export async function deleteGroupMember(groupId: string, memberId: string) {
await request.post('/api/group/deleteGroupMember', {
groupId,
memberId,
});
}

@ -1,5 +1,5 @@
import { Icon } from 'tailchat-design';
import { openReconfirmModalP } from '@/components/Modal';
import { openReconfirmModal, openReconfirmModalP } from '@/components/Modal';
import { GroupUserPopover } from '@/components/popover/GroupUserPopover';
import { UserListItem } from '@/components/UserListItem';
import { Divider, Dropdown, Input, MenuProps, Skeleton } from 'antd';
@ -20,6 +20,7 @@ import {
useSearch,
useUserInfoList,
} from 'tailchat-shared';
import _compact from 'lodash/compact';
interface MembersPanelProps {
groupId: string;
@ -133,6 +134,22 @@ export const MembersPanel: React.FC<MembersPanelProps> = React.memo((props) => {
userInfoList
);
/**
*
*/
const [, handleRemoveGroupMember] = useAsyncRequest(
async (memberId: string) => {
const confirm = await openReconfirmModalP({
title: t('确认要将该用户移出群组么'),
});
if (confirm) {
await model.group.deleteGroupMember(groupId, memberId);
showToasts(t('操作成功'), 'success');
}
},
[groupId]
);
if (userInfoList.length === 0) {
return <Skeleton />;
}
@ -141,61 +158,71 @@ export const MembersPanel: React.FC<MembersPanelProps> = React.memo((props) => {
const hasMute = getMembersHasMute(members, member._id);
if (allowManageUser) {
const muteItems: MenuProps['items'] = hasMute
? [
{
key: 'unmute',
label: t('解除禁言'),
onClick: () => handleUnmuteMember(member._id),
},
]
: [
{
key: 'mute',
label: t('禁言'),
children: [
{
key: '1m',
label: t('1分钟'),
onClick: () => handleMuteMember(member._id, 1 * 60 * 1000),
},
{
key: '5m',
label: t('5分钟'),
onClick: () => handleMuteMember(member._id, 5 * 60 * 1000),
},
{
key: '10m',
label: t('10分钟'),
onClick: () => handleMuteMember(member._id, 10 * 60 * 1000),
},
{
key: '30m',
label: t('30分钟'),
onClick: () => handleMuteMember(member._id, 30 * 60 * 1000),
},
{
key: '1d',
label: t('1天'),
onClick: () =>
handleMuteMember(member._id, 1 * 24 * 60 * 60 * 1000),
},
{
key: '7d',
label: t('7天'),
onClick: () =>
handleMuteMember(member._id, 7 * 24 * 60 * 60 * 1000),
},
{
key: '30d',
label: t('30天'),
onClick: () =>
handleMuteMember(member._id, 30 * 24 * 60 * 60 * 1000),
},
],
},
];
const menu: MenuProps = {
items: hasMute
? [
{
key: 'unmute',
label: t('解除禁言'),
onClick: () => handleUnmuteMember(member._id),
},
]
: [
{
key: 'mute',
label: t('禁言'),
children: [
{
key: '1m',
label: t('1分钟'),
onClick: () => handleMuteMember(member._id, 1 * 60 * 1000),
},
{
key: '5m',
label: t('5分钟'),
onClick: () => handleMuteMember(member._id, 5 * 60 * 1000),
},
{
key: '10m',
label: t('10分钟'),
onClick: () => handleMuteMember(member._id, 10 * 60 * 1000),
},
{
key: '30m',
label: t('30分钟'),
onClick: () => handleMuteMember(member._id, 30 * 60 * 1000),
},
{
key: '1d',
label: t('1天'),
onClick: () =>
handleMuteMember(member._id, 1 * 24 * 60 * 60 * 1000),
},
{
key: '7d',
label: t('7天'),
onClick: () =>
handleMuteMember(member._id, 7 * 24 * 60 * 60 * 1000),
},
{
key: '30d',
label: t('30天'),
onClick: () =>
handleMuteMember(member._id, 30 * 24 * 60 * 60 * 1000),
},
],
},
],
items: _compact([
...muteItems,
{
key: 'delete',
label: t('移出群组'),
danger: true,
onClick: () => handleRemoveGroupMember(member._id),
},
] as MenuProps['items']),
};
return (

@ -1,9 +1,9 @@
import { LoadingSpinner } from '@/components/LoadingSpinner';
import { Problem } from '@/components/Problem';
import { SplitPanel } from '@/components/SplitPanel';
import { GroupIdContextProvider } from '@/context/GroupIdContext';
import React from 'react';
import { Route, Routes, useParams } from 'react-router-dom';
import { isValidStr, useGroupInfo } from 'tailchat-shared';
import { isValidStr, t, useGroupInfo } from 'tailchat-shared';
import { PageContent } from '../PageContent';
import { GroupPanelRender, GroupPanelRoute } from './Panel';
import { GroupPanelRedirect } from './PanelRedirect';
@ -16,7 +16,7 @@ export const Group: React.FC = React.memo(() => {
const groupInfo = useGroupInfo(groupId);
if (!groupInfo) {
return <LoadingSpinner />;
return <Problem text={t('群组未找到')} />;
}
const pinnedPanelId = groupInfo.pinnedPanelId;

@ -466,19 +466,7 @@ class GroupService extends TcService {
const group: Group = await this.transformDocuments(ctx, {}, doc);
// 先将自己退出房间, 然后再进行房间级别通知
await ctx.call('gateway.leaveRoom', {
roomIds: [
groupId,
...group.panels
.filter((p) => p.type === GroupPanelType.TEXT)
.map((p) => p.id),
], // 离开群组和所有面板房间
userId,
});
this.unicastNotify(ctx, userId, 'remove', { groupId });
this.notifyGroupInfoUpdate(ctx, group);
await this.memberLeaveGroup(ctx, group, userId);
}
}
@ -984,6 +972,12 @@ class GroupService extends TcService {
const userId = ctx.meta.userId;
const t = ctx.meta.t;
// 检查是否在踢自己
if (String(memberId) === String(userId)) {
throw new Error(t('不允许踢出自己'));
}
// 检查是否有权限
const [hasPermission] = await call(ctx).checkUserPermissions(
groupId,
userId,
@ -993,8 +987,10 @@ class GroupService extends TcService {
throw new NoPermissionError(t('没有操作权限'));
}
if (String(memberId) === String(userId)) {
throw new Error(t('不允许踢出自己'));
// 检查是否踢出了不该踢出的人
const groupInfo = await call(ctx).getGroupInfo(groupId);
if (String(memberId) === String(groupInfo.owner)) {
throw new Error(t('不允许踢出群组OP'));
}
const group = await this.adapter.model.findByIdAndUpdate(
@ -1009,7 +1005,7 @@ class GroupService extends TcService {
{ new: true }
);
this.notifyGroupInfoUpdate(ctx, group);
await this.memberLeaveGroup(ctx, group, memberId);
const memberInfo = await call(ctx).getUserInfo(memberId);
await call(ctx).addGroupSystemMessage(
@ -1018,6 +1014,34 @@ class GroupService extends TcService {
);
}
/**
* 退
* 退
*
* 退
*/
private async memberLeaveGroup(
ctx: TcContext,
group: Group,
memberId: string
) {
const groupId = String(group._id);
await ctx.call('gateway.leaveRoom', {
roomIds: [
groupId,
...group.panels
.filter((p) => p.type === GroupPanelType.TEXT)
.map((p) => p.id),
], // 离开群组和所有面板房间
memberId,
});
await Promise.all([
this.unicastNotify(ctx, memberId, 'remove', { groupId }),
this.notifyGroupInfoUpdate(ctx, group),
]);
}
/**
*
*

Loading…
Cancel
Save