This commit is contained in:
Archer
2024-06-12 15:17:21 +08:00
committed by GitHub
parent bc6864c3dc
commit d0085a23e6
61 changed files with 558 additions and 348 deletions

View File

@@ -3,12 +3,18 @@ import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next';
import { ModalCloseButton, ModalBody, Box, ModalFooter, Button } from '@chakra-ui/react';
import TagTextarea from '@/components/common/Textarea/TagTextarea';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { postInviteTeamMember } from '@/web/support/user/team/api';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import type { InviteMemberResponse } from '@fastgpt/global/support/user/team/controller.d';
import MySelect from '@fastgpt/web/components/common/MySelect';
import {
ManagePermissionVal,
ReadPermissionVal,
WritePermissionVal
} from '@fastgpt/global/support/permission/constant';
import { useI18n } from '@/web/context/I18n';
import { useUserStore } from '@/web/support/user/useUserStore';
const InviteModal = ({
teamId,
@@ -20,25 +26,37 @@ const InviteModal = ({
onSuccess: () => void;
}) => {
const { t } = useTranslation();
const { userT } = useI18n();
const { ConfirmModal, openConfirm } = useConfirm({
title: t('user.team.Invite Member Result Tip'),
showCancel: false
});
const { userInfo } = useUserStore();
const [inviteUsernames, setInviteUsernames] = useState<string[]>([]);
const inviteTypes = useMemo(
() => [
{
alias: t('user.team.Invite Role Visitor Alias'),
label: t('user.team.Invite Role Visitor Tip'),
value: TeamMemberRoleEnum.visitor
label: userT('permission.Read'),
description: userT('permission.Read desc'),
value: ReadPermissionVal
},
{
alias: t('user.team.Invite Role Admin Alias'),
label: t('user.team.Invite Role Admin Tip'),
value: TeamMemberRoleEnum.admin
}
label: userT('permission.Write'),
description: userT('permission.Write tip'),
value: WritePermissionVal
},
...(userInfo?.team?.permission.isOwner
? [
{
label: userT('permission.Manage'),
description: userT('permission.Manage tip'),
value: ManagePermissionVal
}
]
: [])
],
[t]
[userInfo?.team?.permission.isOwner, userT]
);
const [selectedInviteType, setSelectInviteType] = useState(inviteTypes[0].value);
@@ -47,7 +65,7 @@ const InviteModal = ({
return postInviteTeamMember({
teamId,
usernames: inviteUsernames,
role: selectedInviteType
permission: selectedInviteType
});
},
onSuccess(res: InviteMemberResponse) {

View File

@@ -1,47 +1,51 @@
import Avatar from '@/components/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { Box, MenuButton, Table, TableContainer, Tbody, Td, Th, Thead, Tr } from '@chakra-ui/react';
import {
Box,
HStack,
MenuButton,
Table,
TableContainer,
Tbody,
Td,
Th,
Thead,
Tr
} from '@chakra-ui/react';
import {
TeamMemberRoleEnum,
TeamMemberRoleMap,
TeamMemberStatusMap
} from '@fastgpt/global/support/user/team/constant';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useTranslation } from 'next-i18next';
import { useContextSelector } from 'use-context-selector';
import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamModalContext } from '../context';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { delRemoveMember } from '@/web/support/user/team/api';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import MyBox from '@fastgpt/web/components/common/MyBox';
import PermissionTags from '@/components/support/permission/PermissionTags';
import { TeamPermissionList } from '@fastgpt/global/support/permission/user/constant';
import PermissionSelect from '@/components/support/permission/MemberManager/PermissionSelect';
import { CollaboratorContext } from '@/components/support/permission/MemberManager/context';
import { delRemoveMember } from '@/web/support/user/team/api';
function MemberTable() {
const { userInfo } = useUserStore();
const { t } = useTranslation();
const { members, refetchMembers } = useContextSelector(TeamModalContext, (v) => v);
const { onUpdateCollaborators } = useContextSelector(CollaboratorContext, (v) => v);
const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm({
type: 'delete'
});
const { mutate: onRemoveMember, isLoading: isRemovingMember } = useRequest({
mutationFn: delRemoveMember,
onSuccess() {
refetchMembers();
},
successToast: t('user.team.Remove Member Success'),
errorToast: t('user.team.Remove Member Failed')
});
return (
<MyBox isLoading={isRemovingMember}>
<MyBox>
<TableContainer overflow={'unset'} fontSize={'sm'}>
<Table overflow={'unset'}>
<Thead bg={'myWhite.400'}>
<Tr>
<Th borderRadius={'none !important'}>{t('common.Username')}</Th>
<Th>{t('user.team.Role')}</Th>
<Th>{t('common.Permission')}</Th>
<Th>{t('common.Status')}</Th>
<Th borderRadius={'none !important'}>{t('common.Action')}</Th>
</Tr>
@@ -49,13 +53,20 @@ function MemberTable() {
<Tbody>
{members.map((item) => (
<Tr key={item.userId} overflow={'unset'}>
<Td display={'flex'} alignItems={'center'}>
<Avatar src={item.avatar} w={['18px', '22px']} />
<Box flex={'1 0 0'} w={0} ml={1} className={'textEllipsis'}>
{item.memberName}
</Box>
<Td>
<HStack>
<Avatar src={item.avatar} w={['18px', '22px']} />
<Box maxW={'150px'} className={'textEllipsis'}>
{item.memberName}
</Box>
</HStack>
</Td>
<Td>
<PermissionTags
permission={item.permission}
permissionList={TeamPermissionList}
/>
</Td>
<Td>{t(TeamMemberRoleMap[item.role]?.label || '')}</Td>
<Td color={TeamMemberStatusMap[item.status].color}>
{t(TeamMemberStatusMap[item.status]?.label || '')}
</Td>
@@ -63,9 +74,8 @@ function MemberTable() {
{userInfo?.team.permission.hasManagePer &&
item.role !== TeamMemberRoleEnum.owner &&
item.tmbId !== userInfo?.team.tmbId && (
<MyMenu
width={20}
trigger="hover"
<PermissionSelect
value={item.permission.value}
Button={
<MenuButton
_hover={{
@@ -79,27 +89,21 @@ function MemberTable() {
<MyIcon name={'edit'} cursor={'pointer'} w="1rem" />
</MenuButton>
}
menuList={[
{
children: [
{
label: t('user.team.Remove Member Tip'),
onClick: () =>
openRemoveMember(
() =>
onRemoveMember({
teamId: item.teamId,
memberId: item.tmbId
}),
undefined,
t('user.team.Remove Member Confirm Tip', {
username: item.memberName
})
)()
}
]
}
]}
onChange={(permission) => {
onUpdateCollaborators({
tmbIds: [item.tmbId],
permission
});
}}
onDelete={() => {
openRemoveMember(
() => delRemoveMember(item.tmbId).then(refetchMembers),
undefined,
t('user.team.Remove Member Confirm Tip', {
username: item.memberName
})
)();
}}
/>
)}
</Td>

View File

@@ -38,7 +38,7 @@ function AddManagerModal({ onClose, onSuccess }: { onClose: () => void; onSucces
mutationFn: async () => {
return updateMemberPermission({
permission: ManagePermissionVal,
memberIds: selected.map((item) => {
tmbIds: selected.map((item) => {
return item.tmbId;
})
});

View File

@@ -1,14 +1,26 @@
import React, { ReactNode, useState } from 'react';
import React, { ReactNode, useCallback, useState } from 'react';
import { createContext } from 'use-context-selector';
import type { EditTeamFormDataType } from './components/EditInfoModal';
import dynamic from 'next/dynamic';
import { useQuery } from '@tanstack/react-query';
import { getTeamList, getTeamMembers, putSwitchTeam } from '@/web/support/user/team/api';
import {
delMemberPermission,
getTeamList,
getTeamMembers,
putSwitchTeam,
updateMemberPermission
} from '@/web/support/user/team/api';
import { TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant';
import { useUserStore } from '@/web/support/user/useUserStore';
import type { TeamTmbItemType, TeamMemberItemType } from '@fastgpt/global/support/user/team/type';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useTranslation } from 'next-i18next';
import CollaboratorContextProvider from '@/components/support/permission/MemberManager/context';
import { TeamPermissionList } from '@fastgpt/global/support/permission/user/constant';
import {
CollaboratorItemType,
UpdateClbPermissionProps
} from '@fastgpt/global/support/permission/collaborator';
const EditInfoModal = dynamic(() => import('./components/EditInfoModal'));
@@ -55,12 +67,35 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
// member action
const {
data: members = [],
refetch: refetchMembers,
isLoading: loadingMembers
} = useQuery(['getMembers', userInfo?.team?.teamId], () => {
if (!userInfo?.team?.teamId) return [];
return getTeamMembers();
});
runAsync: refetchMembers,
loading: loadingMembers
} = useRequest2(
() => {
if (!userInfo?.team?.teamId) return Promise.resolve([]);
return getTeamMembers();
},
{
manual: false,
refreshDeps: [userInfo?.team?.teamId]
}
);
const onGetClbList = useCallback(() => {
return refetchMembers().then((res) =>
res.map<CollaboratorItemType>((member) => ({
teamId: member.teamId,
tmbId: member.tmbId,
permission: member.permission,
name: member.memberName,
avatar: member.avatar
}))
);
}, [refetchMembers]);
const { runAsync: onUpdatePer, loading: isUpdatingPer } = useRequest2(
(props: UpdateClbPermissionProps) => {
return updateMemberPermission(props);
}
);
const { mutate: onSwitchTeam, isLoading: isSwitchingTeam } = useRequest({
mutationFn: async (teamId: string) => {
@@ -70,7 +105,7 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
errorToast: t('user.team.Switch Team Failed')
});
const isLoading = isLoadingTeams || isSwitchingTeam || loadingMembers;
const isLoading = isLoadingTeams || isSwitchingTeam || loadingMembers || isUpdatingPer;
const contextValue = {
myTeams,
@@ -86,16 +121,30 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
return (
<TeamModalContext.Provider value={contextValue}>
{children}
{!!editTeamData && (
<EditInfoModal
defaultData={editTeamData}
onClose={() => setEditTeamData(undefined)}
onSuccess={() => {
refetchTeams();
initUserInfo();
}}
/>
{userInfo?.team?.permission && (
<CollaboratorContextProvider
permission={userInfo?.team?.permission}
permissionList={TeamPermissionList}
onGetCollaboratorList={onGetClbList}
onUpdateCollaborators={onUpdatePer}
onDelOneCollaborator={delMemberPermission}
>
{() => (
<>
{children}
{!!editTeamData && (
<EditInfoModal
defaultData={editTeamData}
onClose={() => setEditTeamData(undefined)}
onSuccess={() => {
refetchTeams();
initUserInfo();
}}
/>
)}
</>
)}
</CollaboratorContextProvider>
)}
</TeamModalContext.Provider>
);