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, getTeamMembers, putUpdateMemberNameByManager, postRestoreMember } 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 { 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 { useCallback, useEffect, useState } from 'react'; import { downloadFetch } from '@/web/common/system/utils'; import { TeamMemberItemType } from '@fastgpt/global/support/user/team/type'; import { useToast } from '@fastgpt/web/hooks/useToast'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination'; import { PaginationResponse } from '@fastgpt/web/common/fetch/type'; import _ from 'lodash'; import MySelect from '@fastgpt/web/components/common/MySelect'; import { useEditTitle } from '@/web/common/hooks/useEditTitle'; 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 { toast } = useToast(); const statusOptions = [ { label: t('common:common.All'), value: undefined }, { label: t('common:user.team.member.active'), value: 'active' }, { label: t('account_team:leave'), value: 'inactive' } ]; const { userInfo } = useUserStore(); const { feConfigs } = useSystemStore(); const isSyncMember = feConfigs?.register_method?.includes('sync'); const { myTeams, onSwitchTeam } = useContextSelector(TeamContext, (v) => v); const [status, setStatus] = useState(); const { isOpen: isOpenTeamTagsAsync, onOpen: onOpenTeamTagsAsync, onClose: onCloseTeamTagsAsync } = useDisclosure(); // member action const [searchKey, setSearchKey] = useState(''); const { data: members = [], isLoading: loadingMembers, refreshList: refetchMemberList, ScrollData: MemberScrollData } = useScrollPagination< any, PaginationResponse> >(getTeamMembers, { pageSize: 20, params: { status, withPermission: true, withOrgs: true, searchKey } }); const refreshList = _.debounce(() => { refetchMemberList(); }, 200); useEffect(() => { refreshList(); }, [searchKey, status]); const onRefreshMembers = useCallback(() => { refetchMemberList(); }, [refetchMemberList]); const { isOpen: isOpenInvite, onOpen: onOpenInvite, onClose: onCloseInvite } = useDisclosure(); const { runAsync: onSyncMember, loading: isSyncing } = useRequest2(postSyncMembers, { onSuccess: onRefreshMembers, successToast: t('account_team:sync_member_success'), errorToast: t('account_team:sync_member_failed') }); const { ConfirmModal: ConfirmLeaveTeamModal, openConfirm: openLeaveConfirm } = useConfirm({ content: t('account_team:confirm_leave_team') }); const { runAsync: onLeaveTeam } = useRequest2(delLeaveTeam, { onSuccess() { const defaultTeam = myTeams[0]; onSwitchTeam(defaultTeam.teamId); }, errorToast: t('account_team:user_team_leave_team_failed') }); const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm({ type: 'delete' }); const { runAsync: onRemoveMember } = useRequest2(delRemoveMember, { onSuccess: onRefreshMembers }); const { ConfirmModal: ConfirmRestoreMemberModal, openConfirm: openRestoreMember } = useConfirm({ type: 'common', title: t('account_team:restore_tip_title'), iconSrc: 'common/confirm/restoreTip', iconColor: 'primary.500' }); const { runAsync: onRestore } = useRequest2(postRestoreMember, { onSuccess: onRefreshMembers, successToast: t('common:common.Success'), errorToast: t('common:user.team.invite.Reject') }); const isLoading = loadingMembers || isSyncing; const { EditModal: EditMemberNameModal, onOpenModal: openEditMemberName } = useEditTitle({ title: t('account_team:edit_member'), tip: t('account_team:edit_member_tip'), canEmpty: false }); const handleEditMemberName = (tmbId: string, memberName: string) => { openEditMemberName({ defaultVal: memberName, onSuccess: (newName: string) => { return putUpdateMemberNameByManager(tmbId, newName).then(() => { onRefreshMembers(); }); }, onError: (err) => { toast({ title: '', status: 'error' }); } }); }; return ( <> {Tabs} setStatus(v)} /> setSearchKey(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 && ( )} {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( () => onRemoveMember(member.tmbId), 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;