fix: pagination bug (#3577)
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
|
import { SourceMemberType } from '@fastgpt/global/support/user/type';
|
||||||
import { MongoTeam } from './team/teamSchema';
|
import { MongoTeam } from './team/teamSchema';
|
||||||
|
import { MongoTeamMember } from './team/teamMemberSchema';
|
||||||
|
import { ClientSession } from '../../common/mongo';
|
||||||
|
|
||||||
/* export dataset limit */
|
/* export dataset limit */
|
||||||
export const updateExportDatasetLimit = async (teamId: string) => {
|
export const updateExportDatasetLimit = async (teamId: string) => {
|
||||||
@@ -67,3 +70,43 @@ export const checkWebSyncLimit = async ({
|
|||||||
return Promise.reject(`每个团队,每 ${limitMinutes} 分钟仅使用一次同步功能。`);
|
return Promise.reject(`每个团队,每 ${limitMinutes} 分钟仅使用一次同步功能。`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will add a property named sourceMember to the list passed in.
|
||||||
|
* @param list The list to add the sourceMember property to. [TmbId] property is required.
|
||||||
|
* @error If member is not found, this item will be skipped.
|
||||||
|
* @returns The list with the sourceMember property added.
|
||||||
|
*/
|
||||||
|
export async function addSourceMember<T extends { tmbId: string }>({
|
||||||
|
list,
|
||||||
|
teamId,
|
||||||
|
session
|
||||||
|
}: {
|
||||||
|
list: T[];
|
||||||
|
teamId?: string;
|
||||||
|
session?: ClientSession;
|
||||||
|
}): Promise<Array<T & { sourceMember: SourceMemberType }>> {
|
||||||
|
if (!list.length) return [];
|
||||||
|
|
||||||
|
const tmbList = await MongoTeamMember.find(
|
||||||
|
{
|
||||||
|
_id: { $in: list.map((item) => String(item.tmbId)) },
|
||||||
|
...(teamId && { teamId })
|
||||||
|
},
|
||||||
|
'tmbId name avatar status',
|
||||||
|
{
|
||||||
|
session
|
||||||
|
}
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
return list
|
||||||
|
.map((item) => {
|
||||||
|
const tmb = tmbList.find((tmb) => String(tmb._id) === String(item.tmbId));
|
||||||
|
if (!tmb) return;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
...(tmb && { sourceMember: { name: tmb.name, avatar: tmb.avatar, status: tmb.status } })
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean) as Array<T & { sourceMember: SourceMemberType }>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ function GroupEditModal({ onClose, editGroupId }: { onClose: () => void; editGro
|
|||||||
members: allMembers,
|
members: allMembers,
|
||||||
refetchGroups,
|
refetchGroups,
|
||||||
groups,
|
groups,
|
||||||
refetchMembers
|
refetchMembers,
|
||||||
|
MemberScrollData
|
||||||
} = useContextSelector(TeamContext, (v) => v);
|
} = useContextSelector(TeamContext, (v) => v);
|
||||||
|
|
||||||
const group = useMemo(() => {
|
const group = useMemo(() => {
|
||||||
@@ -156,31 +157,33 @@ function GroupEditModal({ onClose, editGroupId }: { onClose: () => void; editGro
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Flex flexDirection="column" mt={3} flexGrow="1" overflow={'auto'} maxH={'400px'}>
|
<Flex flexDirection="column" mt={3} flexGrow="1" overflow={'auto'} maxH={'400px'}>
|
||||||
{filtered.map((member) => {
|
<MemberScrollData>
|
||||||
return (
|
{filtered.map((member) => {
|
||||||
<HStack
|
return (
|
||||||
py="2"
|
<HStack
|
||||||
px={3}
|
py="2"
|
||||||
borderRadius={'md'}
|
px={3}
|
||||||
alignItems="center"
|
borderRadius={'md'}
|
||||||
key={member.tmbId}
|
alignItems="center"
|
||||||
cursor={'pointer'}
|
key={member.tmbId}
|
||||||
_hover={{
|
cursor={'pointer'}
|
||||||
bg: 'myGray.50',
|
_hover={{
|
||||||
...(!isSelected(member.tmbId) ? { svg: { color: 'myGray.50' } } : {})
|
bg: 'myGray.50',
|
||||||
}}
|
...(!isSelected(member.tmbId) ? { svg: { color: 'myGray.50' } } : {})
|
||||||
_notLast={{ mb: 2 }}
|
}}
|
||||||
onClick={() => handleToggleSelect(member.tmbId)}
|
_notLast={{ mb: 2 }}
|
||||||
>
|
onClick={() => handleToggleSelect(member.tmbId)}
|
||||||
<Checkbox
|
>
|
||||||
isChecked={!!isSelected(member.tmbId)}
|
<Checkbox
|
||||||
icon={<MyIcon name={'common/check'} w={'12px'} />}
|
isChecked={!!isSelected(member.tmbId)}
|
||||||
/>
|
icon={<MyIcon name={'common/check'} w={'12px'} />}
|
||||||
<Avatar src={member.avatar} w="1.5rem" borderRadius={'50%'} />
|
/>
|
||||||
<Box>{member.memberName}</Box>
|
<Avatar src={member.avatar} w="1.5rem" borderRadius={'50%'} />
|
||||||
</HStack>
|
<Box>{member.memberName}</Box>
|
||||||
);
|
</HStack>
|
||||||
})}
|
);
|
||||||
|
})}
|
||||||
|
</MemberScrollData>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex borderLeft="1px" borderColor="myGray.200" flexDirection="column" p="4" h={'100%'}>
|
<Flex borderLeft="1px" borderColor="myGray.200" flexDirection="column" p="4" h={'100%'}>
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import { useMemo, useState } from 'react';
|
|||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { TeamContext } from '../context';
|
import { TeamContext } from '../context';
|
||||||
import { OrgType } from '@fastgpt/global/support/user/team/org/type';
|
import { OrgType } from '@fastgpt/global/support/user/team/org/type';
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
|
|
||||||
export type GroupFormType = {
|
export type GroupFormType = {
|
||||||
members: {
|
members: {
|
||||||
@@ -51,7 +50,7 @@ function OrgMemberManageModal({
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const allMembers = useContextSelector(TeamContext, (v) => v.members);
|
const { members: allMembers, MemberScrollData } = useContextSelector(TeamContext, (v) => v);
|
||||||
|
|
||||||
const [selectedMembers, setSelectedMembers] = useState<string[]>(
|
const [selectedMembers, setSelectedMembers] = useState<string[]>(
|
||||||
currentOrg.members.map((item) => item.tmbId)
|
currentOrg.members.map((item) => item.tmbId)
|
||||||
@@ -124,32 +123,34 @@ function OrgMemberManageModal({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Flex flexDirection="column" mt={3} flexGrow="1" overflow={'auto'} maxH={'400px'}>
|
<Flex flexDirection="column" mt={3} flexGrow="1" overflow={'auto'} maxH={'400px'}>
|
||||||
{filterMembers.map((member) => {
|
<MemberScrollData>
|
||||||
return (
|
{filterMembers.map((member) => {
|
||||||
<HStack
|
return (
|
||||||
py="2"
|
<HStack
|
||||||
px={3}
|
py="2"
|
||||||
borderRadius={'md'}
|
px={3}
|
||||||
alignItems="center"
|
borderRadius={'md'}
|
||||||
key={member.tmbId}
|
alignItems="center"
|
||||||
cursor={'pointer'}
|
key={member.tmbId}
|
||||||
_hover={{
|
cursor={'pointer'}
|
||||||
bg: 'myGray.50',
|
_hover={{
|
||||||
...(!isSelected(member.tmbId) ? { svg: { color: 'myGray.50' } } : {})
|
bg: 'myGray.50',
|
||||||
}}
|
...(!isSelected(member.tmbId) ? { svg: { color: 'myGray.50' } } : {})
|
||||||
_notLast={{ mb: 2 }}
|
}}
|
||||||
onClick={() => handleToggleSelect(member.tmbId)}
|
_notLast={{ mb: 2 }}
|
||||||
>
|
onClick={() => handleToggleSelect(member.tmbId)}
|
||||||
<Checkbox
|
>
|
||||||
isChecked={!!isSelected(member.tmbId)}
|
<Checkbox
|
||||||
icon={<CheckboxIcon name={'common/check'} />}
|
isChecked={!!isSelected(member.tmbId)}
|
||||||
pointerEvents="none"
|
icon={<CheckboxIcon name={'common/check'} />}
|
||||||
/>
|
pointerEvents="none"
|
||||||
<Avatar src={member.avatar} w="1.5rem" borderRadius={'50%'} />
|
/>
|
||||||
<Box>{member.memberName}</Box>
|
<Avatar src={member.avatar} w="1.5rem" borderRadius={'50%'} />
|
||||||
</HStack>
|
<Box>{member.memberName}</Box>
|
||||||
);
|
</HStack>
|
||||||
})}
|
);
|
||||||
|
})}
|
||||||
|
</MemberScrollData>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex borderLeft="1px" borderColor="myGray.200" flexDirection="column" p="4" h={'100%'}>
|
<Flex borderLeft="1px" borderColor="myGray.200" flexDirection="column" p="4" h={'100%'}>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { NextAPI } from '@/service/middleware/entry';
|
|||||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { readFromSecondary } from '@fastgpt/service/common/mongo/utils';
|
import { readFromSecondary } from '@fastgpt/service/common/mongo/utils';
|
||||||
import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
|
import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
|
||||||
import { TeamMemberCollectionName } from '@fastgpt/global/support/user/team/constant';
|
|
||||||
import { PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
import { PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||||
|
import { addSourceMember } from '@fastgpt/service/support/user/utils';
|
||||||
|
|
||||||
async function handler(
|
async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
@@ -82,14 +82,6 @@ async function handler(
|
|||||||
as: 'chatitems'
|
as: 'chatitems'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
$lookup: {
|
|
||||||
from: TeamMemberCollectionName,
|
|
||||||
localField: 'tmbId',
|
|
||||||
foreignField: '_id',
|
|
||||||
as: 'member'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
$addFields: {
|
$addFields: {
|
||||||
userGoodFeedbackCount: {
|
userGoodFeedbackCount: {
|
||||||
@@ -143,12 +135,7 @@ async function handler(
|
|||||||
customFeedbacksCount: 1,
|
customFeedbacksCount: 1,
|
||||||
markCount: 1,
|
markCount: 1,
|
||||||
outLinkUid: 1,
|
outLinkUid: 1,
|
||||||
tmbId: 1,
|
tmbId: 1
|
||||||
sourceMember: {
|
|
||||||
name: '$member.name',
|
|
||||||
avatar: '$member.avatar',
|
|
||||||
status: '$member.status'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -159,8 +146,15 @@ async function handler(
|
|||||||
MongoChat.countDocuments(where, { ...readFromSecondary })
|
MongoChat.countDocuments(where, { ...readFromSecondary })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const listWithSourceMember = await addSourceMember({
|
||||||
|
list: list,
|
||||||
|
teamId
|
||||||
|
});
|
||||||
|
|
||||||
|
const listWithoutTmbId = list.filter((item) => !item.tmbId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
list,
|
list: listWithSourceMember.concat(listWithoutTmbId),
|
||||||
total
|
total
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { replaceRegChars } from '@fastgpt/global/common/string/tools';
|
|||||||
import { concatPer } from '@fastgpt/service/support/permission/controller';
|
import { concatPer } from '@fastgpt/service/support/permission/controller';
|
||||||
import { getGroupsByTmbId } from '@fastgpt/service/support/permission/memberGroup/controllers';
|
import { getGroupsByTmbId } from '@fastgpt/service/support/permission/memberGroup/controllers';
|
||||||
import { getOrgIdSetWithParentByTmbId } from '@fastgpt/service/support/permission/org/controllers';
|
import { getOrgIdSetWithParentByTmbId } from '@fastgpt/service/support/permission/org/controllers';
|
||||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
import { addSourceMember } from '@fastgpt/service/support/user/utils';
|
||||||
|
|
||||||
export type ListAppBody = {
|
export type ListAppBody = {
|
||||||
parentId?: ParentIdType;
|
parentId?: ParentIdType;
|
||||||
@@ -202,32 +202,9 @@ async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemTy
|
|||||||
})
|
})
|
||||||
.filter((app) => app.permission.hasReadPer);
|
.filter((app) => app.permission.hasReadPer);
|
||||||
|
|
||||||
// get member info
|
return addSourceMember({
|
||||||
const memberInfo = await MongoTeamMember.find(
|
list: formatApps,
|
||||||
{ _id: { $in: formatApps.map((app) => app.tmbId) } },
|
teamId
|
||||||
'_id name avatar status'
|
|
||||||
).lean();
|
|
||||||
|
|
||||||
return formatApps.map((app) => {
|
|
||||||
const member = memberInfo.find((item) => String(item._id) === String(app.tmbId))!;
|
|
||||||
return {
|
|
||||||
_id: app._id,
|
|
||||||
tmbId: app.tmbId,
|
|
||||||
avatar: app.avatar,
|
|
||||||
type: app.type,
|
|
||||||
name: app.name,
|
|
||||||
intro: app.intro,
|
|
||||||
updateTime: app.updateTime,
|
|
||||||
permission: app.permission,
|
|
||||||
pluginData: app.pluginData,
|
|
||||||
inheritPermission: app.inheritPermission ?? true,
|
|
||||||
private: app.privateApp,
|
|
||||||
sourceMember: {
|
|
||||||
name: member.name,
|
|
||||||
avatar: member.avatar,
|
|
||||||
status: member.status
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
|||||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { VersionListItemType } from '@fastgpt/global/core/app/version';
|
import { VersionListItemType } from '@fastgpt/global/core/app/version';
|
||||||
import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
|
import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
|
||||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
import { addSourceMember } from '@fastgpt/service/support/user/utils';
|
||||||
|
|
||||||
export type versionListBody = PaginationProps<{
|
export type versionListBody = PaginationProps<{
|
||||||
appId: string;
|
appId: string;
|
||||||
@@ -36,43 +36,21 @@ async function handler(
|
|||||||
.limit(pageSize)
|
.limit(pageSize)
|
||||||
.lean();
|
.lean();
|
||||||
|
|
||||||
const memberList = await MongoTeamMember.find(
|
return (
|
||||||
{
|
await addSourceMember({
|
||||||
_id: { $in: versions.map((item) => item.tmbId) }
|
list: versions
|
||||||
},
|
})
|
||||||
'_id name avatar status'
|
).map((item) => ({
|
||||||
).lean();
|
...item,
|
||||||
|
isPublish: !!item.isPublish
|
||||||
return versions.map((item) => {
|
}));
|
||||||
const member = memberList.find((member) => String(member._id) === String(item.tmbId));
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
sourceMember: {
|
|
||||||
name: member?.name || '',
|
|
||||||
avatar: member?.avatar || '',
|
|
||||||
status: member?.status || ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
})(),
|
})(),
|
||||||
MongoAppVersion.countDocuments({ appId })
|
MongoAppVersion.countDocuments({ appId })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const versionList = result.map((item) => {
|
|
||||||
return {
|
|
||||||
_id: item._id,
|
|
||||||
appId: item.appId,
|
|
||||||
versionName: item.versionName,
|
|
||||||
time: item.time,
|
|
||||||
isPublish: item.isPublish,
|
|
||||||
tmbId: item.tmbId,
|
|
||||||
sourceMember: item.sourceMember
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total,
|
total,
|
||||||
list: versionList
|
list: result
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { DatasetListItemType } from '@fastgpt/global/core/dataset/type.d';
|
|
||||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||||
@@ -18,8 +17,7 @@ import { replaceRegChars } from '@fastgpt/global/common/string/tools';
|
|||||||
import { getGroupsByTmbId } from '@fastgpt/service/support/permission/memberGroup/controllers';
|
import { getGroupsByTmbId } from '@fastgpt/service/support/permission/memberGroup/controllers';
|
||||||
import { concatPer } from '@fastgpt/service/support/permission/controller';
|
import { concatPer } from '@fastgpt/service/support/permission/controller';
|
||||||
import { getOrgIdSetWithParentByTmbId } from '@fastgpt/service/support/permission/org/controllers';
|
import { getOrgIdSetWithParentByTmbId } from '@fastgpt/service/support/permission/org/controllers';
|
||||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
import { addSourceMember } from '@fastgpt/service/support/user/utils';
|
||||||
import { getVectorModel } from '@fastgpt/service/core/ai/model';
|
|
||||||
|
|
||||||
export type GetDatasetListBody = {
|
export type GetDatasetListBody = {
|
||||||
parentId: ParentIdType;
|
parentId: ParentIdType;
|
||||||
@@ -175,30 +173,9 @@ async function handler(req: ApiRequestProps<GetDatasetListBody>) {
|
|||||||
})
|
})
|
||||||
.filter((app) => app.permission.hasReadPer);
|
.filter((app) => app.permission.hasReadPer);
|
||||||
|
|
||||||
const tmbIds = formatDatasets.map((item) => String(item.tmbId));
|
return addSourceMember({
|
||||||
const memberInfo = await MongoTeamMember.find({ _id: { $in: tmbIds } }, '_id name avatar').lean();
|
list: formatDatasets,
|
||||||
|
teamId
|
||||||
return formatDatasets.map((item) => {
|
|
||||||
const member =
|
|
||||||
memberInfo.find((member) => String(member._id) === String(item.tmbId)) ?? memberInfo[0];
|
|
||||||
|
|
||||||
return {
|
|
||||||
_id: item._id,
|
|
||||||
avatar: item.avatar,
|
|
||||||
name: item.name,
|
|
||||||
intro: item.intro,
|
|
||||||
type: item.type,
|
|
||||||
permission: item.permission,
|
|
||||||
vectorModel: getVectorModel(item.vectorModel),
|
|
||||||
inheritPermission: item.inheritPermission,
|
|
||||||
tmbId: item.tmbId,
|
|
||||||
updateTime: item.updateTime,
|
|
||||||
private: item.privateDataset,
|
|
||||||
sourceMember: {
|
|
||||||
name: member!.name,
|
|
||||||
avatar: member!.avatar
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user