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 { delRemoveMember, updateStatus } 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 { useToast } from '@fastgpt/web/hooks/useToast'; import { TeamErrEnum } from '@fastgpt/global/common/error/code/team'; 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'; const InviteModal = dynamic(() => import('./InviteModal')); const TeamTagModal = dynamic(() => import('@/components/support/user/team/TeamTagModal')); function MemberTable({ Tabs }: { Tabs: React.ReactNode }) { const { t } = useTranslation(); const { toast } = useToast(); const { userInfo, teamPlanStatus } = useUserStore(); const { feConfigs, setNotSufficientModalType } = useSystemStore(); const { refetchGroups, myTeams, refetchTeams, members, refetchMembers, onSwitchTeam, MemberScrollData, orgs } = 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, 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(updateStatus, { onSuccess() { refetchMembers(); }, successToast: t('common:user.team.invite.Accepted'), errorToast: t('common:user.team.invite.Reject') }); const isLoading = isUpdateInvite || isSyncing; 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('account_team:contact')} {t('account_team:org')} {t('account_team:join_update_time')} {t('common:common.Action')}
{member.memberName} {member.status === 'waiting' && ( {t('account_team:waiting')} )} {member.status === 'leave' && ( {t('account_team:leave')} )} {member.contact || '-'} {(() => { const memberOrgs = orgs.filter((org) => org.members.find((v) => String(v.tmbId) === String(member.tmbId)) ); const memberPathIds = memberOrgs.map((org) => (org.path + '/' + org.pathId).split('/').slice(0) ); const memberOrgNames = memberPathIds.map((pathIds) => pathIds.map((id) => orgs.find((v) => v.pathId === id)?.name).join('/') ); 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.leave ? ( { openRemoveMember( () => delRemoveMember(member.tmbId).then(() => Promise.all([refetchGroups(), refetchMembers()]) ), undefined, t('account_team:remove_tip', { username: member.memberName }) )(); }} /> ) : ( { openRestoreMember( () => onRestore({ tmbId: member.tmbId, status: TeamMemberStatusEnum.active }), undefined, t('account_team:restore_tip', { username: member.memberName }) )(); }} /> ))}
{isOpenInvite && userInfo?.team?.teamId && ( )} {isOpenTeamTagsAsync && } ); } export default MemberTable;