mirror of https://github.com/msgbyte/tailchat
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
5.4 KiB
TypeScript
167 lines
5.4 KiB
TypeScript
import {
|
|
DefaultFullModalInputEditorRender,
|
|
FullModalField,
|
|
} from '@/components/FullModal/Field';
|
|
import { IconBtn } from '@/components/IconBtn';
|
|
import { Loading } from '@/components/Loading';
|
|
import { PillTabPane, PillTabs } from '@/components/PillTabs';
|
|
import { UserListItem } from '@/components/UserListItem';
|
|
import { Button, Input } from 'antd';
|
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
import { Icon } from 'tailchat-design';
|
|
import { t, useGroupInfo, useSearch, useUserInfoList } from 'tailchat-shared';
|
|
import { permissionList } from './const';
|
|
import { PermissionItem } from './PermissionItem';
|
|
import { RoleItem } from './RoleItem';
|
|
import { useModifyPermission } from './useModifyPermission';
|
|
import { useRoleActions } from './useRoleActions';
|
|
|
|
interface GroupPermissionProps {
|
|
groupId: string;
|
|
}
|
|
export const GroupRole: React.FC<GroupPermissionProps> = React.memo((props) => {
|
|
const { groupId } = props;
|
|
const [roleId, setRoleId] = useState('');
|
|
const groupInfo = useGroupInfo(groupId);
|
|
const roles = groupInfo?.roles ?? [];
|
|
const members = (groupInfo?.members ?? []).filter((m) => m.role === roleId);
|
|
const userInfoList = useUserInfoList(members.map((m) => m.userId));
|
|
const {
|
|
searchText,
|
|
setSearchText,
|
|
isSearching,
|
|
searchResult: filterMembers,
|
|
} = useSearch({
|
|
dataSource: userInfoList,
|
|
filterFn: (item, searchText) => item.nickname.includes(searchText),
|
|
});
|
|
const currentRoleInfo = useMemo(
|
|
() => roles.find((r) => r._id === roleId),
|
|
[roles, roleId]
|
|
);
|
|
const currentRolePermissions = useMemo(
|
|
() => currentRoleInfo?.permissions ?? [],
|
|
[currentRoleInfo]
|
|
);
|
|
|
|
const {
|
|
loading,
|
|
handleCreateRole,
|
|
handleSavePermission,
|
|
handleChangeRoleName,
|
|
} = useRoleActions(groupId, roleId);
|
|
|
|
const {
|
|
isEditing,
|
|
editingPermission,
|
|
setEditingPermission,
|
|
handleSwitchPermission,
|
|
} = useModifyPermission(currentRolePermissions);
|
|
|
|
const handleAddMember = useCallback(() => {}, []);
|
|
|
|
const handleResetPermission = useCallback(() => {
|
|
setEditingPermission(
|
|
permissionList.filter((p) => p.default === true).map((p) => p.key)
|
|
);
|
|
}, []);
|
|
|
|
return (
|
|
<Loading spinning={loading}>
|
|
<div className="flex h-full">
|
|
<div className="pr-2 mr-2 w-40 border-r border-white border-opacity-20">
|
|
{/* 角色列表 */}
|
|
<RoleItem active={roleId === ''} onClick={() => setRoleId('')}>
|
|
{t('所有人')}
|
|
</RoleItem>
|
|
|
|
{roles.map((r) => (
|
|
<RoleItem
|
|
key={r._id}
|
|
active={roleId === r._id}
|
|
onClick={() => setRoleId(r._id)}
|
|
>
|
|
{r.name}
|
|
</RoleItem>
|
|
))}
|
|
|
|
<RoleItem active={false} onClick={handleCreateRole}>
|
|
{t('添加角色')}
|
|
</RoleItem>
|
|
</div>
|
|
|
|
<div className="flex-1 overflow-y-auto">
|
|
<PillTabs defaultActiveKey="permission">
|
|
<PillTabPane key="summary" tab={t('概述')} disabled={!roleId}>
|
|
{/* 权限概述 */}
|
|
{currentRoleInfo && (
|
|
<div className="px-2">
|
|
<FullModalField
|
|
title={t('角色名称')}
|
|
value={currentRoleInfo.name}
|
|
editable={true}
|
|
renderEditor={DefaultFullModalInputEditorRender}
|
|
onSave={handleChangeRoleName}
|
|
/>
|
|
</div>
|
|
)}
|
|
</PillTabPane>
|
|
<PillTabPane key="permission" tab={t('权限')}>
|
|
<div className="mb-2 space-x-2 text-right">
|
|
<Button onClick={handleResetPermission}>
|
|
{t('重置为默认值')}
|
|
</Button>
|
|
<Button
|
|
type="primary"
|
|
disabled={!isEditing}
|
|
onClick={() => handleSavePermission(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)}
|
|
/>
|
|
))}
|
|
</PillTabPane>
|
|
<PillTabPane key="member" tab={t('管理成员')} disabled={!roleId}>
|
|
{/* 管理成员 */}
|
|
<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" />]}
|
|
/>
|
|
))}
|
|
</PillTabPane>
|
|
</PillTabs>
|
|
</div>
|
|
</div>
|
|
</Loading>
|
|
);
|
|
});
|
|
GroupRole.displayName = 'GroupRole';
|