mirror of https://github.com/msgbyte/tailchat
refactor: 拆分身份组管理逻辑
parent
a4f0c9389e
commit
12431a2c97
@ -0,0 +1,116 @@
|
||||
import { IconBtn } from '@/components/IconBtn';
|
||||
import { closeModal, openModal } from '@/components/Modal';
|
||||
import { SelectGroupMember } from '@/components/modals/SelectGroupMember';
|
||||
import { UserListItem } from '@/components/UserListItem';
|
||||
import { Button, Input } from 'antd';
|
||||
import React, { useCallback } from 'react';
|
||||
import { Icon } from 'tailchat-design';
|
||||
import {
|
||||
model,
|
||||
showErrorToasts,
|
||||
showSuccessToasts,
|
||||
t,
|
||||
useAsyncRequest,
|
||||
useGroupInfo,
|
||||
useSearch,
|
||||
useUserId,
|
||||
useUserInfoList,
|
||||
} from 'tailchat-shared';
|
||||
import _compact from 'lodash/compact';
|
||||
|
||||
interface RoleMemberProps {
|
||||
groupId: string;
|
||||
currentRoleInfo: model.group.GroupRole;
|
||||
}
|
||||
export const RoleMember: React.FC<RoleMemberProps> = React.memo((props) => {
|
||||
const roleId = props.currentRoleInfo._id;
|
||||
const userId = useUserId();
|
||||
const groupInfo = useGroupInfo(props.groupId);
|
||||
const members = (groupInfo?.members ?? []).filter((m) =>
|
||||
m.roles.includes(roleId)
|
||||
);
|
||||
const memberIds = members.map((m) => m.userId);
|
||||
const userInfoList = useUserInfoList(memberIds);
|
||||
const {
|
||||
searchText,
|
||||
setSearchText,
|
||||
isSearching,
|
||||
searchResult: filterMembers,
|
||||
} = useSearch({
|
||||
dataSource: userInfoList,
|
||||
filterFn: (item, searchText) => item.nickname.includes(searchText),
|
||||
});
|
||||
|
||||
const handleAddMember = useCallback(() => {
|
||||
const key = openModal(
|
||||
<SelectGroupMember
|
||||
groupId={props.groupId}
|
||||
withoutMemberIds={_compact([...memberIds, userId])}
|
||||
onConfirm={async (selectedIds) => {
|
||||
try {
|
||||
await model.group.appendGroupMemberRoles(
|
||||
props.groupId,
|
||||
selectedIds,
|
||||
[props.currentRoleInfo._id]
|
||||
);
|
||||
showSuccessToasts();
|
||||
closeModal(key);
|
||||
} catch (err) {
|
||||
showErrorToasts(err);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}, [userId, props.groupId, memberIds, props.currentRoleInfo._id]);
|
||||
|
||||
const [, handleRemoveMember] = useAsyncRequest(
|
||||
async (memberId: string) => {
|
||||
if (!props.currentRoleInfo?._id) {
|
||||
showErrorToasts(t('当前没有选择任何角色组'));
|
||||
return;
|
||||
}
|
||||
|
||||
await model.group.removeGroupMemberRoles(
|
||||
props.groupId,
|
||||
[memberId],
|
||||
[props.currentRoleInfo._id]
|
||||
);
|
||||
showSuccessToasts();
|
||||
},
|
||||
[props.groupId, props.currentRoleInfo?._id]
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 管理成员 */}
|
||||
<div className="text-right mb-2 flex space-x-1">
|
||||
<Input
|
||||
placeholder={t('搜索成员')}
|
||||
size="middle"
|
||||
suffix={<Icon fontSize={20} color="grey" icon="mdi:magnify" />}
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
/>
|
||||
|
||||
<Button type="primary" onClick={handleAddMember}>
|
||||
{t('添加成员')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{(isSearching ? filterMembers : userInfoList).map((m) => (
|
||||
<UserListItem
|
||||
key={m._id}
|
||||
userId={m._id}
|
||||
actions={[
|
||||
<IconBtn
|
||||
key="remove"
|
||||
icon="mdi:close"
|
||||
onClick={() => handleRemoveMember(m._id)}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
RoleMember.displayName = 'RoleMember';
|
@ -0,0 +1,65 @@
|
||||
import { AllPermission, permissionList } from '@/utils/role-helper';
|
||||
import { Button } from 'antd';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { model, t } from 'tailchat-shared';
|
||||
import { PermissionItem } from '../PermissionItem';
|
||||
import { useModifyPermission } from '../useModifyPermission';
|
||||
|
||||
interface RolePermissionProps {
|
||||
roleId: typeof AllPermission | string;
|
||||
currentRoleInfo?: model.group.GroupRole;
|
||||
fallbackPermissions: string[];
|
||||
onSavePermission: (permissions: string[]) => Promise<void>;
|
||||
}
|
||||
export const RolePermission: React.FC<RolePermissionProps> = React.memo(
|
||||
(props) => {
|
||||
const currentRolePermissions: string[] = useMemo(() => {
|
||||
if (props.roleId === AllPermission) {
|
||||
return props.fallbackPermissions;
|
||||
}
|
||||
|
||||
return props.currentRoleInfo?.permissions ?? [];
|
||||
}, [props.roleId, props.fallbackPermissions, props.currentRoleInfo]);
|
||||
|
||||
const {
|
||||
isEditing,
|
||||
editingPermission,
|
||||
setEditingPermission,
|
||||
handleSwitchPermission,
|
||||
} = useModifyPermission(currentRolePermissions);
|
||||
|
||||
const handleResetPermission = useCallback(() => {
|
||||
setEditingPermission(
|
||||
permissionList.filter((p) => p.default === true).map((p) => p.key)
|
||||
);
|
||||
}, []);
|
||||
|
||||
// 权限概述
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-2 space-x-2 text-right">
|
||||
<Button onClick={handleResetPermission}>{t('重置为默认值')}</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
disabled={!isEditing}
|
||||
onClick={() => props.onSavePermission(editingPermission)}
|
||||
>
|
||||
{t('保存')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 权限详情 */}
|
||||
{permissionList.map((p) => (
|
||||
<PermissionItem
|
||||
key={p.key}
|
||||
title={p.title}
|
||||
desc={p.desc}
|
||||
checked={editingPermission.includes(p.key)}
|
||||
onChange={(checked) => handleSwitchPermission(p.key, checked)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
RolePermission.displayName = 'RolePermission';
|
@ -0,0 +1,26 @@
|
||||
import {
|
||||
DefaultFullModalInputEditorRender,
|
||||
FullModalField,
|
||||
} from '@/components/FullModal/Field';
|
||||
import React from 'react';
|
||||
import { model, t } from 'tailchat-shared';
|
||||
|
||||
interface RoleSummaryProps {
|
||||
currentRoleInfo: model.group.GroupRole;
|
||||
onChangeRoleName: (roleName: string) => void;
|
||||
}
|
||||
export const RoleSummary: React.FC<RoleSummaryProps> = React.memo((props) => {
|
||||
// 权限概述
|
||||
return (
|
||||
<div className="px-2">
|
||||
<FullModalField
|
||||
title={t('身份组名称')}
|
||||
value={props.currentRoleInfo.name}
|
||||
editable={true}
|
||||
renderEditor={DefaultFullModalInputEditorRender}
|
||||
onSave={props.onChangeRoleName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
RoleSummary.displayName = 'RoleSummary';
|
Loading…
Reference in New Issue