Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
4871a698
authored
Mar 26, 2025
by
Archer
Committed by
archer
Mar 27, 2025
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: member group (#4324)
* sync collection * remove lock * perf: member group
parent
64fb0914
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
202 additions
and
244 deletions
+202
-244
packages/global/support/permission/memberGroup/api.d.ts
+4
-0
packages/global/support/permission/memberGroup/type.d.ts
+18
-15
packages/global/support/user/api.d.ts
+4
-1
packages/service/support/user/team/controller.ts
+8
-0
projects/app/src/components/support/permission/MemberManager/MemberModal.tsx
+5
-6
projects/app/src/components/support/user/team/Info/MemberTag.tsx
+4
-4
projects/app/src/pageComponents/account/team/GroupManage/GroupInfoModal.tsx
+17
-25
projects/app/src/pageComponents/account/team/GroupManage/GroupManageMember.tsx
+6
-11
projects/app/src/pageComponents/account/team/GroupManage/GroupTransferOwnerModal.tsx
+21
-26
projects/app/src/pageComponents/account/team/GroupManage/index.tsx
+44
-76
projects/app/src/pageComponents/account/team/MemberTable.tsx
+57
-70
projects/app/src/pageComponents/account/team/OrgManage/index.tsx
+1
-4
projects/app/src/pageComponents/account/team/context.tsx
+6
-4
projects/app/src/web/support/user/team/group/api.ts
+7
-2
No files found.
packages/global/support/permission/memberGroup/api.d.ts
0 → 100644
View file @
4871a698
export
type
GetGroupListBody
=
{
searchKey
?:
string
;
withMembers
?:
boolean
;
};
packages/global/support/permission/memberGroup/type.d.ts
View file @
4871a698
import
{
TeamMemberItemType
}
from
'support/user/team/type'
;
import
{
TeamMemberItemType
}
from
'support/user/team/type'
;
import
{
TeamPermission
}
from
'../user/controller'
;
import
{
TeamPermission
}
from
'../user/controller'
;
import
{
GroupMemberRole
}
from
'./constant'
;
import
{
GroupMemberRole
}
from
'./constant'
;
import
{
Permission
}
from
'../controller'
;
type
MemberGroupSchemaType
=
{
type
MemberGroupSchemaType
=
{
_id
:
string
;
_id
:
string
;
...
@@ -16,23 +17,25 @@ type GroupMemberSchemaType = {
...
@@ -16,23 +17,25 @@ type GroupMemberSchemaType = {
role
:
`
${
GroupMemberRole
}
`
;
role
:
`
${
GroupMemberRole
}
`
;
};
};
type
MemberGroupType
=
MemberGroupSchemaType
&
{
type
MemberGroupListItemType
<
T
extends
boolean
|
undefined
>
=
MemberGroupSchemaType
&
{
members
:
{
members
:
T
extends
true
tmbId
:
string
;
?
{
name
:
string
;
tmbId
:
string
;
avatar
:
string
;
name
:
string
;
}[];
avatar
:
string
;
count
:
number
;
}[]
owner
:
{
:
undefined
;
tmbId
:
string
;
count
:
T
extends
true
?
number
:
undefined
;
name
:
string
;
owner
?:
T
extends
true
avatar
:
string
;
?
{
};
tmbId
:
string
;
canEdit
:
boolean
;
name
:
string
;
avatar
:
string
;
}
:
undefined
;
permission
:
T
extends
true
?
Permission
:
undefined
;
};
};
type
MemberGroupListType
=
MemberGroupType
[];
type
GroupMemberItemType
=
{
type
GroupMemberItemType
=
{
tmbId
:
string
;
tmbId
:
string
;
name
:
string
;
name
:
string
;
...
...
packages/global/support/user/api.d.ts
View file @
4871a698
import
{
MemberGroupSchemaType
,
MemberGroupType
}
from
'support/permission/memberGroup/type'
;
import
{
MemberGroupSchemaType
,
MemberGroupListItemType
}
from
'support/permission/memberGroup/type'
;
import
{
OAuthEnum
}
from
'./constant'
;
import
{
OAuthEnum
}
from
'./constant'
;
import
{
TrackRegisterParams
}
from
'./login/api'
;
import
{
TrackRegisterParams
}
from
'./login/api'
;
import
{
TeamMemberStatusEnum
}
from
'./team/constant'
;
import
{
TeamMemberStatusEnum
}
from
'./team/constant'
;
...
...
packages/service/support/user/team/controller.ts
View file @
4871a698
...
@@ -55,6 +55,14 @@ async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemTyp
...
@@ -55,6 +55,14 @@ async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemTyp
};
};
}
}
export
const
getTeamOwner
=
async
(
teamId
:
string
)
=>
{
const
tmb
=
await
MongoTeamMember
.
findOne
({
teamId
,
role
:
TeamMemberRoleEnum
.
owner
}).
lean
();
return
tmb
;
};
export
async
function
getTmbInfoByTmbId
({
tmbId
}:
{
tmbId
:
string
})
{
export
async
function
getTmbInfoByTmbId
({
tmbId
}:
{
tmbId
:
string
})
{
if
(
!
tmbId
)
{
if
(
!
tmbId
)
{
return
Promise
.
reject
(
'tmbId or userId is required'
);
return
Promise
.
reject
(
'tmbId or userId is required'
);
...
...
projects/app/src/components/support/permission/MemberManager/MemberModal.tsx
View file @
4871a698
...
@@ -28,20 +28,17 @@ import {
...
@@ -28,20 +28,17 @@ import {
DEFAULT_USER_AVATAR
DEFAULT_USER_AVATAR
}
from
'@fastgpt/global/common/system/constants'
;
}
from
'@fastgpt/global/common/system/constants'
;
import
Path
from
'@/components/common/folder/Path'
;
import
Path
from
'@/components/common/folder/Path'
;
import
{
getOrgChildrenPath
}
from
'@fastgpt/global/support/user/team/org/constant'
;
import
{
ParentTreePathItemType
}
from
'@fastgpt/global/common/parentFolder/type'
;
import
{
OrgListItemType
,
OrgType
}
from
'@fastgpt/global/support/user/team/org/type'
;
import
{
OrgListItemType
,
OrgType
}
from
'@fastgpt/global/support/user/team/org/type'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
CollaboratorContext
}
from
'./context'
;
import
{
CollaboratorContext
}
from
'./context'
;
import
{
getTeamMembers
}
from
'@/web/support/user/team/api'
;
import
{
getTeamMembers
}
from
'@/web/support/user/team/api'
;
import
{
getGroupList
}
from
'@/web/support/user/team/group/api'
;
import
{
getGroupList
}
from
'@/web/support/user/team/group/api'
;
import
{
getOrgList
,
getOrgMembers
}
from
'@/web/support/user/team/org/api'
;
import
{
useScrollPagination
}
from
'@fastgpt/web/hooks/useScrollPagination'
;
import
{
useScrollPagination
}
from
'@fastgpt/web/hooks/useScrollPagination'
;
import
MemberItemCard
from
'./MemberItemCard'
;
import
MemberItemCard
from
'./MemberItemCard'
;
import
{
GetSearchUserGroupOrg
}
from
'@/web/support/user/api'
;
import
{
GetSearchUserGroupOrg
}
from
'@/web/support/user/api'
;
import
useOrg
from
'@/web/support/user/team/org/hooks/useOrg'
;
import
useOrg
from
'@/web/support/user/team/org/hooks/useOrg'
;
import
{
MemberGroupListType
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
TeamMemberItemType
}
from
'@fastgpt/global/support/user/team/type'
;
import
{
TeamMemberItemType
}
from
'@fastgpt/global/support/user/team/type'
;
import
{
MemberGroupListItemType
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
const
HoverBoxStyle
=
{
const
HoverBoxStyle
=
{
bgColor
:
'myGray.50'
,
bgColor
:
'myGray.50'
,
...
@@ -76,7 +73,9 @@ function MemberModal({
...
@@ -76,7 +73,9 @@ function MemberModal({
const
{
data
:
groups
=
[],
loading
:
loadingGroupsAndOrgs
}
=
useRequest2
(
const
{
data
:
groups
=
[],
loading
:
loadingGroupsAndOrgs
}
=
useRequest2
(
async
()
=>
{
async
()
=>
{
if
(
!
userInfo
?.
team
?.
teamId
)
return
[];
if
(
!
userInfo
?.
team
?.
teamId
)
return
[];
return
getGroupList
();
return
getGroupList
<
false
>
({
withMembers
:
false
});
},
},
{
{
manual
:
false
,
manual
:
false
,
...
@@ -117,7 +116,7 @@ function MemberModal({
...
@@ -117,7 +116,7 @@ function MemberModal({
return
members
;
return
members
;
},
[
searchText
,
members
,
searchedData
?.
members
]);
},
[
searchText
,
members
,
searchedData
?.
members
]);
const
[
selectedGroupList
,
setSelectedGroupList
]
=
useState
<
MemberGroupList
Type
>
([]);
const
[
selectedGroupList
,
setSelectedGroupList
]
=
useState
<
MemberGroupList
ItemType
<
false
>
[]
>
([]);
const
filterGroups
=
useMemo
(()
=>
{
const
filterGroups
=
useMemo
(()
=>
{
if
(
searchText
)
{
if
(
searchText
)
{
return
searchedData
?.
groups
.
map
((
item
)
=>
({
return
searchedData
?.
groups
.
map
((
item
)
=>
({
...
...
projects/app/src/components/support/user/team/Info/MemberTag.tsx
View file @
4871a698
...
@@ -3,16 +3,16 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
...
@@ -3,16 +3,16 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import
React
from
'react'
;
import
React
from
'react'
;
type
Props
=
{
type
Props
=
{
name
:
string
;
name
?
:
string
;
avatar
:
string
;
avatar
?
:
string
;
};
};
function
MemberTag
({
name
,
avatar
}:
Props
)
{
function
MemberTag
({
name
,
avatar
}:
Props
)
{
return
(
return
(
<
HStack
>
<
HStack
>
<
Avatar
src=
{
avatar
}
w=
{
[
'18px'
,
'22px'
]
}
rounded=
"50%"
/>
{
avatar
&&
<
Avatar
src=
{
avatar
}
w=
{
[
'18px'
,
'22px'
]
}
rounded=
"50%"
/>
}
<
Box
maxW=
{
'150px'
}
className=
{
'textEllipsis'
}
>
<
Box
maxW=
{
'150px'
}
className=
{
'textEllipsis'
}
>
{
name
}
{
name
||
'-'
}
</
Box
>
</
Box
>
</
HStack
>
</
HStack
>
);
);
...
...
projects/app/src/pageComponents/account/team/GroupManage/GroupInfoModal.tsx
View file @
4871a698
...
@@ -4,15 +4,13 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
...
@@ -4,15 +4,13 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import
FormLabel
from
'@fastgpt/web/components/common/MyBox/FormLabel'
;
import
FormLabel
from
'@fastgpt/web/components/common/MyBox/FormLabel'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
React
,
{
useMemo
}
from
'react'
;
import
React
from
'react'
;
import
{
useSelectFile
}
from
'@/web/common/file/hooks/useSelectFile'
;
import
{
useSelectFile
}
from
'@/web/common/file/hooks/useSelectFile'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
TeamContext
}
from
'../context'
;
import
{
postCreateGroup
,
putUpdateGroup
}
from
'@/web/support/user/team/group/api'
;
import
{
postCreateGroup
,
putUpdateGroup
}
from
'@/web/support/user/team/group/api'
;
import
{
DEFAULT_TEAM_AVATAR
}
from
'@fastgpt/global/common/system/constants'
;
import
{
DEFAULT_TEAM_AVATAR
}
from
'@fastgpt/global/common/system/constants'
;
import
{
MemberGroupListType
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
MemberGroupList
Item
Type
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
export
type
GroupFormType
=
{
export
type
GroupFormType
=
{
avatar
:
string
;
avatar
:
string
;
...
@@ -21,17 +19,15 @@ export type GroupFormType = {
...
@@ -21,17 +19,15 @@ export type GroupFormType = {
function
GroupInfoModal
({
function
GroupInfoModal
({
onClose
,
onClose
,
editGroupId
,
editGroup
,
groups
,
onSuccess
refetchGroups
}:
{
}:
{
onClose
:
()
=>
void
;
onClose
:
()
=>
void
;
editGroupId
?:
string
;
editGroup
?:
MemberGroupListItemType
<
true
>
;
groups
:
MemberGroupListType
;
onSuccess
:
()
=>
void
;
refetchGroups
:
()
=>
void
;
})
{
})
{
const
{
refetchMembers
}
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
);
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
const
{
File
:
AvatarSelect
,
File
:
AvatarSelect
,
onOpen
:
onOpenSelectAvatar
,
onOpen
:
onOpenSelectAvatar
,
...
@@ -41,14 +37,10 @@ function GroupInfoModal({
...
@@ -41,14 +37,10 @@ function GroupInfoModal({
multiple
:
false
multiple
:
false
});
});
const
group
=
useMemo
(()
=>
{
return
groups
.
find
((
item
)
=>
item
.
_id
===
editGroupId
);
},
[
editGroupId
,
groups
]);
const
{
register
,
handleSubmit
,
getValues
,
setValue
}
=
useForm
<
GroupFormType
>
({
const
{
register
,
handleSubmit
,
getValues
,
setValue
}
=
useForm
<
GroupFormType
>
({
defaultValues
:
{
defaultValues
:
{
name
:
g
roup
?.
name
||
''
,
name
:
editG
roup
?.
name
||
''
,
avatar
:
g
roup
?.
avatar
||
DEFAULT_TEAM_AVATAR
avatar
:
editG
roup
?.
avatar
||
DEFAULT_TEAM_AVATAR
}
}
});
});
...
@@ -74,21 +66,21 @@ function GroupInfoModal({
...
@@ -74,21 +66,21 @@ function GroupInfoModal({
});
});
},
},
{
{
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
refetchGroups
(),
refetchMember
s
()])
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
onSucces
s
()])
}
}
);
);
const
{
runAsync
:
onUpdate
,
loading
:
isLoadingUpdate
}
=
useRequest2
(
const
{
runAsync
:
onUpdate
,
loading
:
isLoadingUpdate
}
=
useRequest2
(
async
(
data
:
GroupFormType
)
=>
{
async
(
data
:
GroupFormType
)
=>
{
if
(
!
editGroup
Id
)
return
;
if
(
!
editGroup
)
return
;
return
putUpdateGroup
({
return
putUpdateGroup
({
groupId
:
editGroup
I
d
,
groupId
:
editGroup
.
_i
d
,
name
:
data
.
name
,
name
:
data
.
name
,
avatar
:
data
.
avatar
avatar
:
data
.
avatar
});
});
},
},
{
{
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
refetchGroups
(),
refetchMember
s
()])
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
onSucces
s
()])
}
}
);
);
...
@@ -97,8 +89,8 @@ function GroupInfoModal({
...
@@ -97,8 +89,8 @@ function GroupInfoModal({
return
(
return
(
<
MyModal
<
MyModal
onClose=
{
onClose
}
onClose=
{
onClose
}
title=
{
editGroup
Id
?
t
(
'user:team.group.edit'
)
:
t
(
'user:team.group.create'
)
}
title=
{
editGroup
?
t
(
'user:team.group.edit'
)
:
t
(
'user:team.group.create'
)
}
iconSrc=
{
g
roup
?.
avatar
??
DEFAULT_TEAM_AVATAR
}
iconSrc=
{
editG
roup
?.
avatar
??
DEFAULT_TEAM_AVATAR
}
>
>
<
ModalBody
flex=
{
1
}
overflow=
{
'auto'
}
display=
{
'flex'
}
flexDirection=
{
'column'
}
gap=
{
4
}
>
<
ModalBody
flex=
{
1
}
overflow=
{
'auto'
}
display=
{
'flex'
}
flexDirection=
{
'column'
}
gap=
{
4
}
>
<
FormLabel
w=
"80px"
>
{
t
(
'user:team.avatar_and_name'
)
}
</
FormLabel
>
<
FormLabel
w=
"80px"
>
{
t
(
'user:team.avatar_and_name'
)
}
</
FormLabel
>
...
@@ -120,14 +112,14 @@ function GroupInfoModal({
...
@@ -120,14 +112,14 @@ function GroupInfoModal({
<
Button
<
Button
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
onClick=
{
handleSubmit
((
data
)
=>
{
onClick=
{
handleSubmit
((
data
)
=>
{
if
(
editGroup
Id
)
{
if
(
editGroup
)
{
onUpdate
(
data
);
onUpdate
(
data
);
}
else
{
}
else
{
onCreate
(
data
);
onCreate
(
data
);
}
}
})
}
})
}
>
>
{
editGroup
Id
?
t
(
'common:common.Save'
)
:
t
(
'common:new_create'
)
}
{
editGroup
?
t
(
'common:common.Save'
)
:
t
(
'common:new_create'
)
}
</
Button
>
</
Button
>
</
ModalFooter
>
</
ModalFooter
>
<
AvatarSelect
onSelect=
{
onSelectAvatar
}
/>
<
AvatarSelect
onSelect=
{
onSelectAvatar
}
/>
...
...
projects/app/src/pageComponents/account/team/GroupManage/GroupManageMember.tsx
View file @
4871a698
...
@@ -26,7 +26,7 @@ import { DEFAULT_TEAM_AVATAR } from '@fastgpt/global/common/system/constants';
...
@@ -26,7 +26,7 @@ import { DEFAULT_TEAM_AVATAR } from '@fastgpt/global/common/system/constants';
import
SearchInput
from
'@fastgpt/web/components/common/Input/SearchInput'
;
import
SearchInput
from
'@fastgpt/web/components/common/Input/SearchInput'
;
import
{
import
{
GroupMemberItemType
,
GroupMemberItemType
,
MemberGroupListType
MemberGroupList
Item
Type
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
useMount
}
from
'ahooks'
;
import
{
useMount
}
from
'ahooks'
;
...
@@ -43,24 +43,19 @@ export type GroupFormType = {
...
@@ -43,24 +43,19 @@ export type GroupFormType = {
function
GroupEditModal
({
function
GroupEditModal
({
onClose
,
onClose
,
editGroupId
,
editGroupId
,
group
s
,
group
,
refetchGroup
s
onSucces
s
}:
{
}:
{
onClose
:
()
=>
void
;
onClose
:
()
=>
void
;
editGroupId
?:
string
;
editGroupId
?:
string
;
group
s
:
MemberGroupListType
;
group
:
MemberGroupListItemType
<
true
>
;
refetchGroup
s
:
()
=>
void
;
onSucces
s
:
()
=>
void
;
})
{
})
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
userInfo
}
=
useUserStore
();
const
{
userInfo
}
=
useUserStore
();
const
{
toast
}
=
useToast
();
const
{
toast
}
=
useToast
();
const
group
=
useMemo
(()
=>
{
return
groups
.
find
((
item
)
=>
item
.
_id
===
editGroupId
);
},
[
editGroupId
,
groups
]);
const
allMembers
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
.
members
);
const
allMembers
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
.
members
);
const
refetchMembers
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
.
refetchMembers
);
const
MemberScrollData
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
.
MemberScrollData
);
const
MemberScrollData
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
.
MemberScrollData
);
const
[
hoveredMemberId
,
setHoveredMemberId
]
=
useState
<
string
>
();
const
[
hoveredMemberId
,
setHoveredMemberId
]
=
useState
<
string
>
();
...
@@ -94,7 +89,7 @@ function GroupEditModal({
...
@@ -94,7 +89,7 @@ function GroupEditModal({
});
});
},
},
{
{
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
refetchGroups
(),
refetchMember
s
()])
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
onSucces
s
()])
}
}
);
);
...
...
projects/app/src/pageComponents/account/team/GroupManage/GroupTransferOwnerModal.tsx
View file @
4871a698
import
{
putGroupChangeOwner
,
putUpdateGroup
}
from
'@/web/support/user/team/group/api'
;
import
{
putGroupChangeOwner
}
from
'@/web/support/user/team/group/api'
;
import
{
import
{
Box
,
Box
,
Flex
,
Flex
,
...
@@ -15,26 +15,24 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
...
@@ -15,26 +15,24 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
React
,
{
use
Memo
,
use
State
}
from
'react'
;
import
React
,
{
useState
}
from
'react'
;
import
{
TeamContext
}
from
'../context'
;
import
{
TeamContext
}
from
'../context'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
MemberGroupListType
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
MemberGroupList
Item
Type
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
GetSearchUserGroupOrg
}
from
'@/web/support/user/api'
;
import
{
GetSearchUserGroupOrg
}
from
'@/web/support/user/api'
;
import
{
Omit
}
from
'@fastgpt/web/components/common/DndDrag'
;
import
{
Omit
}
from
'@fastgpt/web/components/common/DndDrag'
;
export
type
ChangeOwnerModalProps
=
{
groupId
:
string
;
groups
:
MemberGroupListType
;
refetchGroups
:
()
=>
void
;
};
export
function
ChangeOwnerModal
({
export
function
ChangeOwnerModal
({
onClose
,
group
,
groupId
,
onSuccess
,
groups
,
onClose
refetchGroups
}:
{
}:
ChangeOwnerModalProps
&
{
onClose
:
()
=>
void
})
{
group
:
MemberGroupListItemType
<
true
>
;
onSuccess
:
()
=>
void
;
onClose
:
()
=>
void
;
})
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
[
inputValue
,
setInputValue
]
=
React
.
useState
(
''
);
const
[
inputValue
,
setInputValue
]
=
React
.
useState
(
''
);
const
{
data
:
searchedData
}
=
useRequest2
(
const
{
data
:
searchedData
}
=
useRequest2
(
async
()
=>
{
async
()
=>
{
...
@@ -50,14 +48,8 @@ export function ChangeOwnerModal({
...
@@ -50,14 +48,8 @@ export function ChangeOwnerModal({
);
);
const
{
members
:
allMembers
}
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
);
const
{
members
:
allMembers
}
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
);
const
group
=
useMemo
(()
=>
{
return
groups
.
find
((
item
)
=>
item
.
_id
===
groupId
);
},
[
groupId
,
groups
]);
const
memberList
=
searchedData
?
searchedData
.
members
:
allMembers
;
const
memberList
=
searchedData
?
searchedData
.
members
:
allMembers
;
const
[
keepAdmin
,
setKeepAdmin
]
=
useState
(
true
);
const
{
const
{
isOpen
:
isOpenMemberListMenu
,
isOpen
:
isOpenMemberListMenu
,
onClose
:
onCloseMemberListMenu
,
onClose
:
onCloseMemberListMenu
,
...
@@ -69,10 +61,12 @@ export function ChangeOwnerModal({
...
@@ -69,10 +61,12 @@ export function ChangeOwnerModal({
'permission'
|
'teamId'
'permission'
|
'teamId'
>
|
null
>
(
null
);
>
|
null
>
(
null
);
const
{
runAsync
,
loading
}
=
useRequest2
(
const
[
keepAdmin
,
setKeepAdmin
]
=
useState
(
true
);
(
tmbId
:
string
)
=>
putGroupChangeOwner
(
groupId
,
tmbId
),
const
{
runAsync
:
onTransfer
,
loading
}
=
useRequest2
(
(
tmbId
:
string
)
=>
putGroupChangeOwner
(
group
.
_id
,
tmbId
),
{
{
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
refetchGroup
s
()]),
onSuccess
:
()
=>
Promise
.
all
([
onClose
(),
onSucces
s
()]),
successToast
:
t
(
'common:permission.change_owner_success'
),
successToast
:
t
(
'common:permission.change_owner_success'
),
errorToast
:
t
(
'common:permission.change_owner_failed'
)
errorToast
:
t
(
'common:permission.change_owner_failed'
)
}
}
...
@@ -82,7 +76,7 @@ export function ChangeOwnerModal({
...
@@ -82,7 +76,7 @@ export function ChangeOwnerModal({
if
(
!
selectedMember
)
{
if
(
!
selectedMember
)
{
return
;
return
;
}
}
await
runAsync
(
selectedMember
.
tmbId
);
await
onTransfer
(
selectedMember
.
tmbId
);
};
};
return
(
return
(
...
@@ -92,7 +86,6 @@ export function ChangeOwnerModal({
...
@@ -92,7 +86,6 @@ export function ChangeOwnerModal({
iconColor=
"primary.600"
iconColor=
"primary.600"
onClose=
{
onClose
}
onClose=
{
onClose
}
title=
{
t
(
'common:permission.change_owner'
)
}
title=
{
t
(
'common:permission.change_owner'
)
}
isLoading=
{
loading
}
>
>
<
ModalBody
>
<
ModalBody
>
<
HStack
>
<
HStack
>
...
@@ -181,7 +174,9 @@ export function ChangeOwnerModal({
...
@@ -181,7 +174,9 @@ export function ChangeOwnerModal({
<
Button
onClick=
{
onClose
}
variant=
{
'whiteBase'
}
>
<
Button
onClick=
{
onClose
}
variant=
{
'whiteBase'
}
>
{
t
(
'common:common.Cancel'
)
}
{
t
(
'common:common.Cancel'
)
}
</
Button
>
</
Button
>
<
Button
onClick=
{
onConfirm
}
>
{
t
(
'common:common.Confirm'
)
}
</
Button
>
<
Button
isLoading=
{
loading
}
isDisabled=
{
!
selectedMember
}
onClick=
{
onConfirm
}
>
{
t
(
'common:common.Confirm'
)
}
</
Button
>
</
HStack
>
</
HStack
>
</
ModalFooter
>
</
ModalFooter
>
</
MyModal
>
</
MyModal
>
...
...
projects/app/src/pageComponents/account/team/GroupManage/index.tsx
View file @
4871a698
...
@@ -3,7 +3,6 @@ import {
...
@@ -3,7 +3,6 @@ import {
Box
,
Box
,
Button
,
Button
,
Flex
,
Flex
,
HStack
,
Table
,
Table
,
TableContainer
,
TableContainer
,
Tbody
,
Tbody
,
...
@@ -16,20 +15,18 @@ import {
...
@@ -16,20 +15,18 @@ import {
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useConfirm
}
from
'@fastgpt/web/hooks/useConfirm'
;
import
{
useConfirm
}
from
'@fastgpt/web/hooks/useConfirm'
;
import
MyBox
from
'@fastgpt/web/components/common/MyBox'
;
import
MyBox
from
'@fastgpt/web/components/common/MyBox'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
TeamContext
}
from
'../context'
;
import
MyMenu
,
{
MenuItemType
}
from
'@fastgpt/web/components/common/MyMenu'
;
import
MyMenu
,
{
MenuItemType
}
from
'@fastgpt/web/components/common/MyMenu'
;
import
MyIcon
from
'@fastgpt/web/components/common/Icon'
;
import
MyIcon
from
'@fastgpt/web/components/common/Icon'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
deleteGroup
,
getGroupList
,
getGroupMembers
}
from
'@/web/support/user/team/group/api'
;
import
{
deleteGroup
,
getGroupList
}
from
'@/web/support/user/team/group/api'
;
import
{
DefaultGroupName
}
from
'@fastgpt/global/support/user/team/group/constant'
;
import
{
DefaultGroupName
}
from
'@fastgpt/global/support/user/team/group/constant'
;
import
MemberTag
from
'../../../../components/support/user/team/Info/MemberTag'
;
import
MemberTag
from
'../../../../components/support/user/team/Info/MemberTag'
;
import
MyTooltip
from
'@fastgpt/web/components/common/MyTooltip'
;
import
MyTooltip
from
'@fastgpt/web/components/common/MyTooltip'
;
import
dynamic
from
'next/dynamic'
;
import
dynamic
from
'next/dynamic'
;
import
{
useState
}
from
'react'
;
import
{
useState
}
from
'react'
;
import
IconButton
from
'../OrgManage/IconButton'
;
import
IconButton
from
'../OrgManage/IconButton'
;
import
{
MemberGroupType
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
MemberGroup
ListItem
Type
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
const
ChangeOwnerModal
=
dynamic
(()
=>
import
(
'./GroupTransferOwnerModal'
));
const
ChangeOwnerModal
=
dynamic
(()
=>
import
(
'./GroupTransferOwnerModal'
));
const
GroupInfoModal
=
dynamic
(()
=>
import
(
'./GroupInfoModal'
));
const
GroupInfoModal
=
dynamic
(()
=>
import
(
'./GroupInfoModal'
));
...
@@ -39,26 +36,23 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -39,26 +36,23 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
userInfo
}
=
useUserStore
();
const
{
userInfo
}
=
useUserStore
();
const
{
members
,
teamSize
}
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
);
const
{
const
{
data
:
groups
=
[],
data
:
groups
=
[],
loading
:
isLoadingGroups
,
loading
:
isLoadingGroups
,
refresh
:
refetchGroups
refresh
:
refetchGroups
}
=
useRequest2
(
getGroupList
,
{
}
=
useRequest2
(
()
=>
getGroupList
<
true
>
({
withMembers
:
true
})
,
{
manual
:
false
,
manual
:
false
,
refreshDeps
:
[
userInfo
?.
team
?.
teamId
]
refreshDeps
:
[
userInfo
?.
team
?.
teamId
]
});
});
const
[
editGroup
,
setEditGroup
]
=
useState
<
MemberGroup
Type
>
();
const
[
editGroup
,
setEditGroup
]
=
useState
<
MemberGroup
ListItemType
<
true
>
>
();
const
{
const
{
isOpen
:
isOpenGroupInfo
,
isOpen
:
isOpenGroupInfo
,
onOpen
:
onOpenGroupInfo
,
onOpen
:
onOpenGroupInfo
,
onClose
:
onCloseGroupInfo
onClose
:
onCloseGroupInfo
}
=
useDisclosure
();
}
=
useDisclosure
();
const
onEditGroupInfo
=
(
e
:
MemberGroupListItemType
<
true
>
)
=>
{
const
onEditGroupInfo
=
(
e
:
MemberGroupType
)
=>
{
setEditGroup
(
e
);
setEditGroup
(
e
);
onOpenGroupInfo
();
onOpenGroupInfo
();
};
};
...
@@ -67,7 +61,6 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -67,7 +61,6 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
type
:
'delete'
,
type
:
'delete'
,
content
:
t
(
'account_team:confirm_delete_group'
)
content
:
t
(
'account_team:confirm_delete_group'
)
});
});
const
{
runAsync
:
delDeleteGroup
}
=
useRequest2
(
deleteGroup
,
{
const
{
runAsync
:
delDeleteGroup
}
=
useRequest2
(
deleteGroup
,
{
onSuccess
:
()
=>
{
onSuccess
:
()
=>
{
refetchGroups
();
refetchGroups
();
...
@@ -79,21 +72,17 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -79,21 +72,17 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
onOpen
:
onOpenManageGroupMember
,
onOpen
:
onOpenManageGroupMember
,
onClose
:
onCloseManageGroupMember
onClose
:
onCloseManageGroupMember
}
=
useDisclosure
();
}
=
useDisclosure
();
const
onManageMember
=
(
e
:
MemberGroup
Type
)
=>
{
const
onManageMember
=
(
e
:
MemberGroup
ListItemType
<
true
>
)
=>
{
setEditGroup
(
e
);
setEditGroup
(
e
);
onOpenManageGroupMember
();
onOpenManageGroupMember
();
};
};
const
hasGroupManagePer
=
(
group
:
(
typeof
groups
)[
0
])
=>
userInfo
?.
team
.
permission
.
hasManagePer
;
const
isGroupOwner
=
(
group
:
(
typeof
groups
)[
0
])
=>
userInfo
?.
team
.
permission
.
hasManagePer
;
const
{
const
{
isOpen
:
isOpenChangeOwner
,
isOpen
:
isOpenChangeOwner
,
onOpen
:
onOpenChangeOwner
,
onOpen
:
onOpenChangeOwner
,
onClose
:
onCloseChangeOwner
onClose
:
onCloseChangeOwner
}
=
useDisclosure
();
}
=
useDisclosure
();
const
onChangeOwner
=
(
e
:
MemberGroup
Type
)
=>
{
const
onChangeOwner
=
(
e
:
MemberGroup
ListItemType
<
true
>
)
=>
{
setEditGroup
(
e
);
setEditGroup
(
e
);
onOpenChangeOwner
();
onOpenChangeOwner
();
};
};
...
@@ -135,57 +124,37 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -135,57 +124,37 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
{
groups
?.
map
((
group
)
=>
(
{
groups
?.
map
((
group
)
=>
(
<
Tr
key=
{
group
.
_id
}
overflow=
{
'unset'
}
>
<
Tr
key=
{
group
.
_id
}
overflow=
{
'unset'
}
>
<
Td
>
<
Td
>
<
HStack
>
<
MemberTag
name=
{
group
.
name
===
DefaultGroupName
?
userInfo
?.
team
.
teamName
??
''
:
group
.
name
}
avatar=
{
group
.
avatar
}
/>
<
Box
>
(
{
group
.
name
===
DefaultGroupName
?
teamSize
:
group
.
count
}
)
</
Box
>
</
HStack
>
</
Td
>
<
Td
>
<
MemberTag
<
MemberTag
name=
{
name=
{
group
.
name
===
DefaultGroupName
group
.
name
===
DefaultGroupName
?
userInfo
?.
team
.
teamName
??
''
:
group
.
name
?
members
.
find
((
item
)
=>
item
.
role
===
'owner'
)?.
memberName
??
''
:
group
.
owner
.
name
}
avatar=
{
group
.
name
===
DefaultGroupName
?
members
.
find
((
item
)
=>
item
.
role
===
'owner'
)?.
avatar
??
''
:
group
.
owner
.
avatar
}
}
avatar=
{
group
.
avatar
}
/>
/>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
{
group
.
name
===
DefaultGroupName
?
(
<
MemberTag
name=
{
group
.
owner
?.
name
}
avatar=
{
group
.
owner
?.
avatar
}
/>
<
AvatarGroup
avatars=
{
members
.
map
((
v
)
=>
v
.
avatar
)
}
total=
{
teamSize
}
/>
</
Td
>
)
:
hasGroupManagePer
(
group
)
?
(
<
Td
>
<
MyTooltip
label=
{
t
(
'account_team:manage_member'
)
}
>
<
MyTooltip
<
Box
cursor=
"pointer"
onClick=
{
()
=>
onManageMember
(
group
)
}
>
label=
{
group
.
permission
?.
hasManagePer
?
t
(
'account_team:manage_member'
)
:
''
}
<
AvatarGroup
>
avatars=
{
group
.
members
.
map
(
<
Box
(
v
)
=>
members
.
find
((
m
)
=>
m
.
tmbId
===
v
.
tmbId
)?.
avatar
??
''
{
...
(
group
.
permission
?
.
hasManagePer
)
}
?
{
total=
{
group
.
count
}
cursor
:
'
pointer
',
/>
onClick
:
()
=
>
onManageMember(group)
</
Box
>
}
</
MyTooltip
>
:
{}
)}
)
:
(
>
<
AvatarGroup
<
AvatarGroup
avatars=
{
group
.
members
.
map
(
avatars=
{
group
?.
members
.
map
((
v
)
=>
v
.
avatar
)
}
(
v
)
=>
members
.
find
((
m
)
=>
m
.
tmbId
===
v
.
tmbId
)?.
avatar
??
''
total=
{
group
.
count
}
)
}
/>
total=
{
group
.
count
}
</
Box
>
/>
</
MyTooltip
>
)
}
</
Td
>
</
Td
>
<
Td
>
<
Td
>
{
hasGroupManagePer
(
group
)
&&
group
.
name
!==
DefaultGroupName
&&
(
{
group
.
permission
?.
hasManagePer
&&
(
<
MyMenu
<
MyMenu
Button=
{
<
IconButton
name=
{
'more'
}
/>
}
Button=
{
<
IconButton
name=
{
'more'
}
/>
}
menuList=
{
[
menuList=
{
[
...
@@ -205,7 +174,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -205,7 +174,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
onManageMember
(
group
);
onManageMember
(
group
);
}
}
},
},
...(
isGroupOwner
(
group
)
...(
group
.
permission
?.
isOwner
?
[
?
[
{
{
label
:
t
(
'account_team:transfer_ownership'
),
label
:
t
(
'account_team:transfer_ownership'
),
...
@@ -239,34 +208,33 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -239,34 +208,33 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
</
MyBox
>
</
MyBox
>
<
ConfirmDeleteGroupModal
/>
<
ConfirmDeleteGroupModal
/>
{
isOpenChangeOwner
&&
editGroup
&&
(
<
ChangeOwnerModal
groupId=
{
editGroup
.
_id
}
onClose=
{
onCloseChangeOwner
}
groups=
{
groups
}
refetchGroups=
{
refetchGroups
}
/>
)
}
{
isOpenGroupInfo
&&
(
{
isOpenGroupInfo
&&
(
<
GroupInfoModal
<
GroupInfoModal
groups=
{
groups
}
editGroup=
{
editGroup
}
refetchGroup
s=
{
refetchGroups
}
onSucces
s=
{
refetchGroups
}
onClose=
{
()
=>
{
onClose=
{
()
=>
{
onCloseGroupInfo
();
onCloseGroupInfo
();
setEditGroup
(
undefined
);
setEditGroup
(
undefined
);
}
}
}
}
editGroupId=
{
editGroup
?.
_id
}
/>
/>
)
}
)
}
{
isOpenChangeOwner
&&
editGroup
&&
(
<
ChangeOwnerModal
group=
{
editGroup
}
onClose=
{
onCloseChangeOwner
}
onSuccess=
{
refetchGroups
}
/>
)
}
{
isOpenManageGroupMember
&&
editGroup
&&
(
{
isOpenManageGroupMember
&&
editGroup
&&
(
<
GroupManageMember
<
GroupManageMember
groups=
{
groups
}
group=
{
editGroup
}
refetchGroups=
{
refetchGroups
}
onClose=
{
()
=>
{
onClose=
{
()
=>
{
onCloseManageGroupMember
();
onCloseManageGroupMember
();
setEditGroup
(
undefined
);
setEditGroup
(
undefined
);
}
}
}
}
editGroupId=
{
editGroup
.
_id
}
onSuccess=
{
refetchGroups
}
/>
/>
)
}
)
}
</>
</>
...
...
projects/app/src/pageComponents/account/team/MemberTable.tsx
View file @
4871a698
...
@@ -20,8 +20,9 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
...
@@ -20,8 +20,9 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import
{
useEditTextarea
}
from
'@fastgpt/web/hooks/useEditTextarea'
;
import
{
useEditTextarea
}
from
'@fastgpt/web/hooks/useEditTextarea'
;
import
{
import
{
delRemoveMember
,
delRemoveMember
,
postRestoreMember
,
getTeamMembers
,
putUpdateMemberNameByManager
putUpdateMemberNameByManager
,
postRestoreMember
}
from
'@/web/support/user/team/api'
;
}
from
'@/web/support/user/team/api'
;
import
Tag
from
'@fastgpt/web/components/common/Tag'
;
import
Tag
from
'@fastgpt/web/components/common/Tag'
;
import
Icon
from
'@fastgpt/web/components/common/Icon'
;
import
Icon
from
'@fastgpt/web/components/common/Icon'
;
...
@@ -33,7 +34,6 @@ import dynamic from 'next/dynamic';
...
@@ -33,7 +34,6 @@ import dynamic from 'next/dynamic';
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
delLeaveTeam
}
from
'@/web/support/user/team/api'
;
import
{
delLeaveTeam
}
from
'@/web/support/user/team/api'
;
import
{
GetSearchUserGroupOrg
,
postSyncMembers
}
from
'@/web/support/user/api'
;
import
{
GetSearchUserGroupOrg
,
postSyncMembers
}
from
'@/web/support/user/api'
;
import
MyLoading
from
'@fastgpt/web/components/common/MyLoading'
;
import
{
import
{
TeamMemberRoleEnum
,
TeamMemberRoleEnum
,
TeamMemberStatusEnum
TeamMemberStatusEnum
...
@@ -41,10 +41,12 @@ import {
...
@@ -41,10 +41,12 @@ import {
import
format
from
'date-fns/format'
;
import
format
from
'date-fns/format'
;
import
OrgTags
from
'@/components/support/user/team/OrgTags'
;
import
OrgTags
from
'@/components/support/user/team/OrgTags'
;
import
SearchInput
from
'@fastgpt/web/components/common/Input/SearchInput'
;
import
SearchInput
from
'@fastgpt/web/components/common/Input/SearchInput'
;
import
{
useState
}
from
'react'
;
import
{
use
Callback
,
use
State
}
from
'react'
;
import
{
downloadFetch
}
from
'@/web/common/system/utils'
;
import
{
downloadFetch
}
from
'@/web/common/system/utils'
;
import
{
TeamMemberItemType
}
from
'@fastgpt/global/support/user/team/type'
;
import
{
TeamMemberItemType
}
from
'@fastgpt/global/support/user/team/type'
;
import
{
useToast
}
from
'@fastgpt/web/hooks/useToast'
;
import
{
useToast
}
from
'@fastgpt/web/hooks/useToast'
;
import
MyBox
from
'@fastgpt/web/components/common/MyBox'
;
import
{
useScrollPagination
}
from
'@fastgpt/web/hooks/useScrollPagination'
;
const
InviteModal
=
dynamic
(()
=>
import
(
'./Invite/InviteModal'
));
const
InviteModal
=
dynamic
(()
=>
import
(
'./Invite/InviteModal'
));
const
TeamTagModal
=
dynamic
(()
=>
import
(
'@/components/support/user/team/TeamTagModal'
));
const
TeamTagModal
=
dynamic
(()
=>
import
(
'@/components/support/user/team/TeamTagModal'
));
...
@@ -55,32 +57,31 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -55,32 +57,31 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
const
{
userInfo
}
=
useUserStore
();
const
{
userInfo
}
=
useUserStore
();
const
{
feConfigs
}
=
useSystemStore
();
const
{
feConfigs
}
=
useSystemStore
();
const
isSyncMember
=
feConfigs
?.
register_method
?.
includes
(
'sync'
);
const
{
myTeams
,
refetchTeams
,
members
,
refetchMembers
,
onSwitchTeam
,
MemberScrollData
}
=
const
{
myTeams
,
onSwitchTeam
}
=
useContextSelector
(
TeamContext
,
(
v
)
=>
v
);
useContextSelector
(
TeamContext
,
(
v
)
=>
v
);
const
{
const
{
isOpen
:
isOpenTeamTagsAsync
,
isOpen
:
isOpenTeamTagsAsync
,
onOpen
:
onOpenTeamTagsAsync
,
onOpen
:
onOpenTeamTagsAsync
,
onClose
:
onCloseTeamTagsAsync
onClose
:
onCloseTeamTagsAsync
}
=
useDisclosure
();
}
=
useDisclosure
();
const
{
isOpen
:
isOpenInvite
,
onOpen
:
onOpenInvite
,
onClose
:
onCloseInvite
}
=
useDisclosure
();
const
{
ConfirmModal
:
ConfirmRemoveMemberModal
,
openConfirm
:
openRemoveMember
}
=
useConfirm
({
type
:
'delete'
});
const
{
ConfirmModal
:
ConfirmRestoreMemberModal
,
openConfirm
:
openRestoreMember
}
=
useConfirm
({
// member action
type
:
'common'
,
const
{
title
:
t
(
'account_team:restore_tip_title'
),
data
:
members
=
[],
iconSrc
:
'common/confirm/restoreTip'
,
isLoading
:
loadingMembers
,
iconColor
:
'primary.500'
refreshList
:
refetchMemberList
,
ScrollData
:
MemberScrollData
}
=
useScrollPagination
(
getTeamMembers
,
{
pageSize
:
20
,
params
:
{
withLeaved
:
true
}
});
});
const
[
searchText
,
setSearchText
]
=
useState
<
string
>
(
''
);
const
[
searchText
,
setSearchText
]
=
useState
<
string
>
(
''
);
const
isSyncMember
=
feConfigs
.
register_method
?.
includes
(
'sync'
);
const
{
data
:
searchMembersData
,
run
:
refreshSearchMembers
}
=
useRequest2
(
const
{
data
:
searchMembersData
}
=
useRequest2
(
async
()
=>
{
async
()
=>
{
if
(
!
searchText
)
return
Promise
.
resolve
();
if
(
!
searchText
)
return
Promise
.
resolve
();
return
GetSearchUserGroupOrg
(
searchText
,
{
members
:
true
,
orgs
:
false
,
groups
:
false
});
return
GetSearchUserGroupOrg
(
searchText
,
{
members
:
true
,
orgs
:
false
,
groups
:
false
});
...
@@ -88,47 +89,54 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -88,47 +89,54 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
{
{
manual
:
false
,
manual
:
false
,
throttleWait
:
500
,
throttleWait
:
500
,
debounceWait
:
200
,
refreshDeps
:
[
searchText
]
refreshDeps
:
[
searchText
]
}
}
);
);
const
{
runAsync
:
onLeaveTeam
}
=
useRequest2
(
const
onRefreshMembers
=
useCallback
(()
=>
{
async
()
=>
{
refetchMemberList
();
const
defaultTeam
=
myTeams
[
0
];
refreshSearchMembers
();
// change to personal team
},
[
refetchMemberList
,
refreshSearchMembers
]);
onSwitchTeam
(
defaultTeam
.
teamId
);
return
delLeaveTeam
();
const
{
isOpen
:
isOpenInvite
,
onOpen
:
onOpenInvite
,
onClose
:
onCloseInvite
}
=
useDisclosure
();
},
{
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
,
{
const
{
runAsync
:
onSyncMember
,
loading
:
isSyncing
}
=
useRequest2
(
postSyncMembers
,
{
onSuccess
()
{
onSuccess
:
onRefreshMembers
,
refetchMembers
();
},
successToast
:
t
(
'account_team:sync_member_success'
),
successToast
:
t
(
'account_team:sync_member_success'
),
errorToast
:
t
(
'account_team:sync_member_failed'
)
errorToast
:
t
(
'account_team:sync_member_failed'
)
});
});
const
{
runAsync
:
onRestore
,
loading
:
isUpdateInvite
}
=
useRequest2
(
postRestoreMember
,
{
const
{
ConfirmModal
:
ConfirmLeaveTeamModal
,
openConfirm
:
openLeaveConfirm
}
=
useConfirm
({
content
:
t
(
'account_team:confirm_leave_team'
)
});
const
{
runAsync
:
onLeaveTeam
}
=
useRequest2
(
delLeaveTeam
,
{
onSuccess
()
{
onSuccess
()
{
refetchMembers
();
const
defaultTeam
=
myTeams
[
0
];
onSwitchTeam
(
defaultTeam
.
teamId
);
},
},
successToast
:
t
(
'common:user.team.invite.Accepted'
),
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'
)
errorToast
:
t
(
'common:user.team.invite.Reject'
)
});
});
const
isLoading
=
isUpdateInvite
||
isSyncing
;
const
isLoading
=
loadingMembers
||
isSyncing
;
const
{
EditModal
:
EditMemberNameModal
,
onOpenModal
:
openEditMemberName
}
=
useEditTextarea
({
const
{
EditModal
:
EditMemberNameModal
,
onOpenModal
:
openEditMemberName
}
=
useEditTextarea
({
title
:
t
(
'account_team:edit_member'
),
title
:
t
(
'account_team:edit_member'
),
...
@@ -141,7 +149,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -141,7 +149,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
defaultVal
:
memberName
,
defaultVal
:
memberName
,
onSuccess
:
(
newName
:
string
)
=>
{
onSuccess
:
(
newName
:
string
)
=>
{
return
putUpdateMemberNameByManager
(
tmbId
,
newName
).
then
(()
=>
{
return
putUpdateMemberNameByManager
(
tmbId
,
newName
).
then
(()
=>
{
refetc
hMembers
();
onRefres
hMembers
();
});
});
},
},
onError
:
(
err
)
=>
{
onError
:
(
err
)
=>
{
...
@@ -155,7 +163,6 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -155,7 +163,6 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
return
(
return
(
<>
<>
{
isLoading
&&
<
MyLoading
/>
}
<
Flex
justify=
{
'space-between'
}
align=
{
'center'
}
pb=
{
'1rem'
}
>
<
Flex
justify=
{
'space-between'
}
align=
{
'center'
}
pb=
{
'1rem'
}
>
{
Tabs
}
{
Tabs
}
<
HStack
alignItems=
{
'center'
}
>
<
HStack
alignItems=
{
'center'
}
>
...
@@ -237,7 +244,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -237,7 +244,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
</
HStack
>
</
HStack
>
</
Flex
>
</
Flex
>
<
Box
flex=
{
'1 0 0'
}
overflow=
{
'auto'
}
>
<
MyBox
isLoading=
{
isLoading
}
flex=
{
'1 0 0'
}
overflow=
{
'auto'
}
>
<
MemberScrollData
>
<
MemberScrollData
>
<
TableContainer
overflow=
{
'unset'
}
fontSize=
{
'sm'
}
>
<
TableContainer
overflow=
{
'unset'
}
fontSize=
{
'sm'
}
>
<
Table
overflow=
{
'unset'
}
>
<
Table
overflow=
{
'unset'
}
>
...
@@ -321,27 +328,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -321,27 +328,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
}
}
}
}
onClick=
{
()
=>
{
onClick=
{
()
=>
{
openRemoveMember
(
openRemoveMember
(
()
=>
delRemoveMember
(
member
.
tmbId
).
then
(
refetchMembers
),
()
=>
onRemoveMember
(
member
.
tmbId
),
undefined
,
t
(
'account_team:remove_tip'
,
{
username
:
member
.
memberName
})
)();
}
}
/>
<
Icon
name=
{
'common/trash'
}
cursor=
{
'pointer'
}
w=
"1rem"
p=
"1"
borderRadius=
"sm"
_hover=
{
{
color
:
'red.600'
,
bgColor
:
'myGray.100'
}
}
onClick=
{
()
=>
{
openRemoveMember
(
()
=>
delRemoveMember
(
member
.
tmbId
).
then
(
refetchMembers
),
undefined
,
undefined
,
t
(
'account_team:remove_tip'
,
{
t
(
'account_team:remove_tip'
,
{
username
:
member
.
memberName
username
:
member
.
memberName
...
@@ -385,7 +372,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
...
@@ -385,7 +372,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
<
EditMemberNameModal
/>
<
EditMemberNameModal
/>
</
TableContainer
>
</
TableContainer
>
</
MemberScrollData
>
</
MemberScrollData
>
</
Box
>
</
My
Box
>
<
ConfirmLeaveTeamModal
/>
<
ConfirmLeaveTeamModal
/>
{
isOpenInvite
&&
userInfo
?.
team
?.
teamId
&&
<
InviteModal
onClose=
{
onCloseInvite
}
/>
}
{
isOpenInvite
&&
userInfo
?.
team
?.
teamId
&&
<
InviteModal
onClose=
{
onCloseInvite
}
/>
}
...
...
projects/app/src/pageComponents/account/team/OrgManage/index.tsx
View file @
4871a698
...
@@ -14,7 +14,7 @@ import {
...
@@ -14,7 +14,7 @@ import {
Tr
,
Tr
,
VStack
VStack
}
from
'@chakra-ui/react'
;
}
from
'@chakra-ui/react'
;
import
type
{
OrgListItemType
,
OrgType
}
from
'@fastgpt/global/support/user/team/org/type'
;
import
type
{
OrgListItemType
}
from
'@fastgpt/global/support/user/team/org/type'
;
import
Avatar
from
'@fastgpt/web/components/common/Avatar'
;
import
Avatar
from
'@fastgpt/web/components/common/Avatar'
;
import
MyIcon
from
'@fastgpt/web/components/common/Icon'
;
import
MyIcon
from
'@fastgpt/web/components/common/Icon'
;
import
type
{
IconNameType
}
from
'@fastgpt/web/components/common/Icon/type'
;
import
type
{
IconNameType
}
from
'@fastgpt/web/components/common/Icon/type'
;
...
@@ -32,12 +32,9 @@ import { defaultOrgForm, type OrgFormType } from './OrgInfoModal';
...
@@ -32,12 +32,9 @@ import { defaultOrgForm, type OrgFormType } from './OrgInfoModal';
import
dynamic
from
'next/dynamic'
;
import
dynamic
from
'next/dynamic'
;
import
MyBox
from
'@fastgpt/web/components/common/MyBox'
;
import
MyBox
from
'@fastgpt/web/components/common/MyBox'
;
import
Path
from
'@/components/common/folder/Path'
;
import
Path
from
'@/components/common/folder/Path'
;
import
{
ParentIdType
,
ParentTreePathItemType
}
from
'@fastgpt/global/common/parentFolder/type'
;
import
{
getOrgChildrenPath
}
from
'@fastgpt/global/support/user/team/org/constant'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
delRemoveMember
}
from
'@/web/support/user/team/api'
;
import
{
delRemoveMember
}
from
'@/web/support/user/team/api'
;
import
SearchInput
from
'@fastgpt/web/components/common/Input/SearchInput'
;
import
SearchInput
from
'@fastgpt/web/components/common/Input/SearchInput'
;
import
{
useScrollPagination
}
from
'@fastgpt/web/hooks/useScrollPagination'
;
import
useOrg
from
'@/web/support/user/team/org/hooks/useOrg'
;
import
useOrg
from
'@/web/support/user/team/org/hooks/useOrg'
;
const
OrgInfoModal
=
dynamic
(()
=>
import
(
'./OrgInfoModal'
));
const
OrgInfoModal
=
dynamic
(()
=>
import
(
'./OrgInfoModal'
));
...
...
projects/app/src/pageComponents/account/team/context.tsx
View file @
4871a698
...
@@ -13,10 +13,8 @@ import { useUserStore } from '@/web/support/user/useUserStore';
...
@@ -13,10 +13,8 @@ import { useUserStore } from '@/web/support/user/useUserStore';
import
type
{
TeamTmbItemType
,
TeamMemberItemType
}
from
'@fastgpt/global/support/user/team/type'
;
import
type
{
TeamTmbItemType
,
TeamMemberItemType
}
from
'@fastgpt/global/support/user/team/type'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
getGroupList
}
from
'@/web/support/user/team/group/api'
;
import
{
MemberGroupListType
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
{
useScrollPagination
}
from
'@fastgpt/web/hooks/useScrollPagination'
;
import
{
useScrollPagination
}
from
'@fastgpt/web/hooks/useScrollPagination'
;
import
{
OrgType
}
from
'@fastgpt/global/support/user/team/org/type
'
;
import
{
useRouter
}
from
'next/router
'
;
const
EditInfoModal
=
dynamic
(()
=>
import
(
'./EditInfoModal'
));
const
EditInfoModal
=
dynamic
(()
=>
import
(
'./EditInfoModal'
));
...
@@ -55,6 +53,8 @@ export const TeamContext = createContext<TeamModalContextType>({
...
@@ -55,6 +53,8 @@ export const TeamContext = createContext<TeamModalContextType>({
export
const
TeamModalContextProvider
=
({
children
}:
{
children
:
ReactNode
})
=>
{
export
const
TeamModalContextProvider
=
({
children
}:
{
children
:
ReactNode
})
=>
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
router
=
useRouter
();
const
[
editTeamData
,
setEditTeamData
]
=
useState
<
EditTeamFormDataType
>
();
const
[
editTeamData
,
setEditTeamData
]
=
useState
<
EditTeamFormDataType
>
();
const
{
userInfo
,
initUserInfo
}
=
useUserStore
();
const
{
userInfo
,
initUserInfo
}
=
useUserStore
();
...
@@ -96,10 +96,12 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
...
@@ -96,10 +96,12 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
const
{
runAsync
:
onSwitchTeam
,
loading
:
isSwitchingTeam
}
=
useRequest2
(
const
{
runAsync
:
onSwitchTeam
,
loading
:
isSwitchingTeam
}
=
useRequest2
(
async
(
teamId
:
string
)
=>
{
async
(
teamId
:
string
)
=>
{
await
putSwitchTeam
(
teamId
);
await
putSwitchTeam
(
teamId
);
refetchMembers
();
return
initUserInfo
();
return
initUserInfo
();
},
},
{
{
onSuccess
:
()
=>
{
router
.
reload
();
},
errorToast
:
t
(
'common:user.team.Switch Team Failed'
)
errorToast
:
t
(
'common:user.team.Switch Team Failed'
)
}
}
);
);
...
...
projects/app/src/web/support/user/team/group/api.ts
View file @
4871a698
import
{
DELETE
,
GET
,
POST
,
PUT
}
from
'@/web/common/api/request'
;
import
{
DELETE
,
GET
,
POST
,
PUT
}
from
'@/web/common/api/request'
;
import
{
GetGroupListBody
}
from
'@fastgpt/global/support/permission/memberGroup/api'
;
import
type
{
import
type
{
GroupMemberItemType
,
GroupMemberItemType
,
MemberGroupListType
MemberGroupList
Item
Type
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
}
from
'@fastgpt/global/support/permission/memberGroup/type'
;
import
type
{
import
type
{
postCreateGroupData
,
postCreateGroupData
,
putUpdateGroupData
putUpdateGroupData
}
from
'@fastgpt/global/support/user/team/group/api'
;
}
from
'@fastgpt/global/support/user/team/group/api'
;
export
const
getGroupList
=
()
=>
GET
<
MemberGroupListType
>
(
'/proApi/support/user/team/group/list'
);
export
const
getGroupList
=
<
T
extends
boolean
>
(
data
:
GetGroupListBody
)
=>
POST
<
MemberGroupListItemType
<
T
>
[]
>
(
'/proApi/support/user/team/group/list'
,
data
).
then
((
res
)
=>
{
console
.
log
(
res
);
return
res
;
});
export
const
postCreateGroup
=
(
data
:
postCreateGroupData
)
=>
export
const
postCreateGroup
=
(
data
:
postCreateGroupData
)
=>
POST
(
'/proApi/support/user/team/group/create'
,
data
);
POST
(
'/proApi/support/user/team/group/create'
,
data
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment