import Avatar from '@fastgpt/web/components/common/Avatar'; import { Box, Button, Flex, HStack, Table, TableContainer, Tbody, Td, Th, Thead, Tr, useDisclosure, VStack } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { useUserStore } from '@/web/support/user/useUserStore'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useEditTextarea } from '@fastgpt/web/hooks/useEditTextarea'; import { delRemoveMember, postRestoreMember, putUpdateMemberNameByManager } from '@/web/support/user/team/api'; import Tag from '@fastgpt/web/components/common/Tag'; import Icon from '@fastgpt/web/components/common/Icon'; import { useContextSelector } from 'use-context-selector'; import { TeamContext } from './context'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import MyIcon from '@fastgpt/web/components/common/Icon'; import dynamic from 'next/dynamic'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { delLeaveTeam } from '@/web/support/user/team/api'; import { GetSearchUserGroupOrg, postSyncMembers } from '@/web/support/user/api'; import MyLoading from '@fastgpt/web/components/common/MyLoading'; import { TeamMemberRoleEnum, TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant'; import format from 'date-fns/format'; import OrgTags from '@/components/support/user/team/OrgTags'; import SearchInput from '@fastgpt/web/components/common/Input/SearchInput'; import { useState } from 'react'; import { downloadFetch } from '@/web/common/system/utils'; import { TeamMemberItemType } from '@fastgpt/global/support/user/team/type'; const InviteModal = dynamic(() => import('./Invite/InviteModal')); const TeamTagModal = dynamic(() => import('@/components/support/user/team/TeamTagModal')); function MemberTable({ Tabs }: { Tabs: React.ReactNode }) { const { t } = useTranslation(); const { userInfo } = useUserStore(); const { feConfigs } = useSystemStore(); const { refetchGroups, myTeams, refetchTeams, members, refetchMembers, onSwitchTeam, MemberScrollData } = useContextSelector(TeamContext, (v) => v); const { isOpen: isOpenTeamTagsAsync, onOpen: onOpenTeamTagsAsync, onClose: onCloseTeamTagsAsync } = useDisclosure(); const { isOpen: isOpenInvite, onOpen: onOpenInvite, onClose: onCloseInvite } = useDisclosure(); const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm({ type: 'delete' }); const { ConfirmModal: ConfirmRestoreMemberModal, openConfirm: openRestoreMember } = useConfirm({ type: 'common', title: t('account_team:restore_tip_title'), iconSrc: 'common/confirm/restoreTip', iconColor: 'primary.500' }); const [searchText, setSearchText] = useState(''); const isSyncMember = feConfigs.register_method?.includes('sync'); const { data: searchMembersData } = useRequest2( () => GetSearchUserGroupOrg(searchText, { members: true, orgs: false, groups: false }), { manual: false, throttleWait: 500, debounceWait: 200, refreshDeps: [searchText] } ); const { runAsync: onLeaveTeam } = useRequest2( async () => { const defaultTeam = myTeams[0]; // change to personal team onSwitchTeam(defaultTeam.teamId); return delLeaveTeam(); }, { onSuccess() { refetchTeams(); refetchMembers(); }, errorToast: t('account_team:user_team_leave_team_failed') } ); const { ConfirmModal: ConfirmLeaveTeamModal, openConfirm: openLeaveConfirm } = useConfirm({ content: t('account_team:confirm_leave_team') }); const { runAsync: onSyncMember, loading: isSyncing } = useRequest2(postSyncMembers, { onSuccess() { refetchMembers(); }, successToast: t('account_team:sync_member_success'), errorToast: t('account_team:sync_member_failed') }); const { runAsync: onRestore, loading: isUpdateInvite } = useRequest2(postRestoreMember, { onSuccess() { refetchMembers(); }, successToast: t('common:user.team.invite.Accepted'), errorToast: t('common:user.team.invite.Reject') }); const isLoading = isUpdateInvite || isSyncing; const { EditModal: EditMemberNameModal, onOpenModal: openEditMemberName } = useEditTextarea({ title: t('account_team:edit_member'), tip: t('account_team:edit_member_tip'), canEmpty: false, rows: 1 }); const handleEditMemberName = (tmbId: string, memberName: string) => { openEditMemberName({ defaultVal: memberName, onSuccess: (newName: string) => { return putUpdateMemberNameByManager(tmbId, newName).then(() => { Promise.all([refetchGroups(), refetchMembers()]); }); }, onError: (err) => { toast({ title: '', status: 'error' }); } }); }; return ( <> {isLoading && } {Tabs} setSearchText(e.target.value)} /> {userInfo?.team.permission.hasManagePer && feConfigs?.show_team_chat && ( )} {userInfo?.team.permission.hasManagePer && isSyncMember && ( )} {userInfo?.team.permission.hasManagePer && !isSyncMember && ( )} {userInfo?.team.permission.isOwner && isSyncMember && ( )} {!userInfo?.team.permission.isOwner && ( )} {(searchText && searchMembersData ? searchMembersData.members : members).map( (member) => ( ) )}
{t('account_team:user_name')} {t('common:contact_way')} {t('account_team:org')} {t('account_team:join_update_time')} {t('common:common.Action')}
{member.memberName} {member.status !== 'active' && ( {t('account_team:leave')} )} {member.contact || '-'} {(() => { return ; })()} {format(new Date(member.createTime), 'yyyy-MM-dd HH:mm:ss')} {member.updateTime ? format(new Date(member.updateTime), 'yyyy-MM-dd HH:mm:ss') : '-'} {userInfo?.team.permission.hasManagePer && member.role !== TeamMemberRoleEnum.owner && member.tmbId !== userInfo?.team.tmbId && (member.status === TeamMemberStatusEnum.active ? ( <> handleEditMemberName(member.tmbId, member.memberName) } /> { openRemoveMember( () => delRemoveMember(member.tmbId).then(() => Promise.all([refetchGroups(), refetchMembers()]) ), undefined, t('account_team:remove_tip', { username: member.memberName }) )(); }} /> ) : ( member.status === TeamMemberStatusEnum.forbidden && ( { openRestoreMember( () => onRestore(member.tmbId), undefined, t('account_team:restore_tip', { username: member.memberName }) )(); }} /> ) ))}
{isOpenInvite && userInfo?.team?.teamId && } {isOpenTeamTagsAsync && } ); } export default MemberTable;