mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
Inform (#4307)
* add manager change memberName and update inform UI * change icon and some inform ui * change for comment * fix for comment
This commit is contained in:
@@ -5,7 +5,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import { readInform } from '@/web/support/user/inform/api';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
|
||||
import Markdown from '@/components/Markdown';
|
||||
const ImportantInform = ({
|
||||
informs,
|
||||
refetch
|
||||
@@ -28,32 +28,61 @@ const ImportantInform = ({
|
||||
{informs.map((inform) => (
|
||||
<Flex
|
||||
key={inform._id}
|
||||
bg={'primary.015'}
|
||||
py={3}
|
||||
py={4}
|
||||
px={5}
|
||||
fontSize={'md'}
|
||||
borderRadius={'lg'}
|
||||
boxShadow={'4'}
|
||||
borderWidth={'1px'}
|
||||
backgroundColor={'white'}
|
||||
borderColor={'borderColor.base'}
|
||||
minW={['200px', '400px']}
|
||||
alignItems={'flex-start'}
|
||||
mb={3}
|
||||
backdropFilter={'blur(30px)'}
|
||||
>
|
||||
<MyIcon name={'support/user/informLight'} w={'16px'} mr={2} />
|
||||
<Box flex={'1 0 0'}>
|
||||
<Box fontWeight={'bold'}>{inform.title}</Box>
|
||||
<Box fontSize={'sm'}>{inform.content}</Box>
|
||||
</Box>
|
||||
<CloseIcon
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'primary.700'
|
||||
}}
|
||||
w={'12px'}
|
||||
onClick={() => onClickClose(inform._id)}
|
||||
<MyIcon
|
||||
name={'support/user/informLight'}
|
||||
w={5}
|
||||
h={5}
|
||||
mr={2}
|
||||
mt={'2px'}
|
||||
color="blue.600"
|
||||
/>
|
||||
<Box flex={'1 0 0'}>
|
||||
<Box
|
||||
fontWeight="bold"
|
||||
fontSize="16px"
|
||||
lineHeight="24px"
|
||||
letterSpacing="0.15px"
|
||||
fontFamily="'PingFang SC', sans-serif"
|
||||
color=" #24282C"
|
||||
>
|
||||
{inform.title}
|
||||
</Box>
|
||||
<Box
|
||||
pt={1}
|
||||
fontSize="14px"
|
||||
lineHeight="20px"
|
||||
letterSpacing="0.25px"
|
||||
fontFamily="'PingFang SC', sans-serif"
|
||||
fontWeight="400"
|
||||
color="#24282C"
|
||||
>
|
||||
<Markdown source={inform?.content} />
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
cursor={'pointer'}
|
||||
p={1}
|
||||
pt={0}
|
||||
borderRadius={'4px'}
|
||||
_hover={{
|
||||
backgroundColor: 'rgba(17, 24, 36, 0.05)'
|
||||
}}
|
||||
onClick={() => onClickClose(inform._id)}
|
||||
>
|
||||
<CloseIcon w={'12px'} />
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Box>
|
||||
|
@@ -0,0 +1,73 @@
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Markdown from '@/components/Markdown';
|
||||
import React from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
|
||||
import MyTag from '@fastgpt/web/components/common/Tag/index';
|
||||
import MyDivider from '@fastgpt/web/components/common/MyDivider';
|
||||
|
||||
const NotificationDetailsModal = ({ inform, onClose }: { inform: any; onClose: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const textStyles = {
|
||||
title: {
|
||||
color: 'grayModern.900',
|
||||
fontSize: '20px',
|
||||
fontWeight: 'medium',
|
||||
lineHeight: 6,
|
||||
letterSpacing: '0.15px'
|
||||
},
|
||||
time: {
|
||||
color: 'grayModern.500',
|
||||
fontSize: '12px',
|
||||
lineHeight: 5,
|
||||
letterSpacing: '0.25px'
|
||||
}
|
||||
};
|
||||
return (
|
||||
<MyModal
|
||||
isOpen={!!inform}
|
||||
iconSrc={'support/user/informLight'}
|
||||
title={t('account_inform:notification_detail')}
|
||||
onClose={onClose}
|
||||
iconColor="blue.600"
|
||||
maxW="680px"
|
||||
maxH="80vh"
|
||||
>
|
||||
<Flex flexDirection="column" p={8}>
|
||||
<Flex
|
||||
{...textStyles.time}
|
||||
fontFamily="PingFang SC"
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
alignSelf="stretch"
|
||||
>
|
||||
<Box {...textStyles.title} fontFamily="PingFang SC">
|
||||
{inform.title}
|
||||
</Box>
|
||||
<Box {...textStyles.time} ml={3} flex={1} fontFamily="PingFang SC">
|
||||
{t(formatTimeToChatTime(inform.time) as any).replace('#', ':')}
|
||||
</Box>
|
||||
<MyTag
|
||||
colorSchema={inform.teamId ? 'green' : 'blue'}
|
||||
mr={2}
|
||||
fontSize="xs"
|
||||
fontWeight="medium"
|
||||
showDot={false}
|
||||
type="fill"
|
||||
>
|
||||
{inform.teamId ? t('account_inform:team') : t('account_inform:system')}
|
||||
</MyTag>
|
||||
</Flex>
|
||||
<MyDivider my={4} />
|
||||
|
||||
<Box fontSize="sm" lineHeight={1.8}>
|
||||
<Markdown source={inform?.content} />
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(NotificationDetailsModal);
|
@@ -17,7 +17,12 @@ import {
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { delRemoveMember, postRestoreMember } from '@/web/support/user/team/api';
|
||||
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';
|
||||
@@ -40,6 +45,7 @@ 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'));
|
||||
@@ -128,6 +134,30 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
|
||||
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 && <MyLoading />}
|
||||
@@ -222,7 +252,9 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
{t('account_team:user_name')}
|
||||
</Th>
|
||||
<Th bgColor="myGray.100">{t('common:contact_way')}</Th>
|
||||
<Th bgColor="myGray.100">{t('account_team:org')}</Th>
|
||||
<Th bgColor="myGray.100" pl={9}>
|
||||
{t('account_team:org')}
|
||||
</Th>
|
||||
<Th bgColor="myGray.100">{t('account_team:join_update_time')}</Th>
|
||||
<Th borderRightRadius="6px" bgColor="myGray.100">
|
||||
{t('common:common.Action')}
|
||||
@@ -262,7 +294,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
})()}
|
||||
</Td>
|
||||
<Td maxW={'300px'}>
|
||||
<VStack gap={0}>
|
||||
<VStack gap={0} alignItems="flex-start">
|
||||
<Box>{format(new Date(member.createTime), 'yyyy-MM-dd HH:mm:ss')}</Box>
|
||||
<Box>
|
||||
{member.updateTime
|
||||
@@ -276,29 +308,45 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
member.role !== TeamMemberRoleEnum.owner &&
|
||||
member.tmbId !== userInfo?.team.tmbId &&
|
||||
(member.status === TeamMemberStatusEnum.active ? (
|
||||
<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(() =>
|
||||
Promise.all([refetchGroups(), refetchMembers()])
|
||||
),
|
||||
undefined,
|
||||
t('account_team:remove_tip', {
|
||||
username: member.memberName
|
||||
})
|
||||
)();
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<Icon
|
||||
name={'edit'}
|
||||
cursor={'pointer'}
|
||||
w="1rem"
|
||||
p="1"
|
||||
borderRadius="sm"
|
||||
_hover={{
|
||||
color: 'blue.600',
|
||||
bgColor: 'myGray.100'
|
||||
}}
|
||||
onClick={() =>
|
||||
handleEditMemberName(member.tmbId, 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(() =>
|
||||
Promise.all([refetchGroups(), refetchMembers()])
|
||||
),
|
||||
undefined,
|
||||
t('account_team:remove_tip', {
|
||||
username: member.memberName
|
||||
})
|
||||
)();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
member.status === TeamMemberStatusEnum.forbidden && (
|
||||
<Icon
|
||||
@@ -331,6 +379,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
</Table>
|
||||
<ConfirmRemoveMemberModal />
|
||||
<ConfirmRestoreMemberModal />
|
||||
<EditMemberNameModal />
|
||||
</TableContainer>
|
||||
</MemberScrollData>
|
||||
</Box>
|
||||
|
@@ -45,6 +45,7 @@ import TeamSelector from '@/pageComponents/account/TeamSelector';
|
||||
import { getWorkorderURL } from '@/web/common/workorder/api';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useMount } from 'ahooks';
|
||||
import MyDivider from '@fastgpt/web/components/common/MyDivider';
|
||||
|
||||
const StandDetailModal = dynamic(
|
||||
() => import('@/pageComponents/account/info/standardDetailModal'),
|
||||
@@ -76,7 +77,7 @@ const Info = () => {
|
||||
<Flex justifyContent={'center'} maxW={'1080px'}>
|
||||
<Box flex={'0 0 330px'}>
|
||||
<MyInfo onOpenContact={onOpenContact} />
|
||||
<Box mt={9}>
|
||||
<Box mt={6}>
|
||||
<Other onOpenContact={onOpenContact} />
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -162,8 +163,23 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
|
||||
const labelStyles: BoxProps = {
|
||||
flex: '0 0 80px',
|
||||
fontSize: 'sm',
|
||||
color: 'myGray.900'
|
||||
color: 'var(--light-general-on-surface-lowest, var(--Gray-Modern-500, #667085))',
|
||||
fontFamily: '"PingFang SC"',
|
||||
fontSize: '14px',
|
||||
fontStyle: 'normal',
|
||||
fontWeight: 400,
|
||||
lineHeight: '20px',
|
||||
letterSpacing: '0.25px'
|
||||
};
|
||||
|
||||
const titleStyles: BoxProps = {
|
||||
color: 'var(--light-general-on-surface, var(--Gray-Modern-900, #111824))',
|
||||
fontFamily: '"PingFang SC"',
|
||||
fontSize: '16px',
|
||||
fontStyle: 'normal',
|
||||
fontWeight: 500,
|
||||
lineHeight: '24px',
|
||||
letterSpacing: '0.15px'
|
||||
};
|
||||
|
||||
const isSyncMember = feConfigs.register_method?.includes('sync');
|
||||
@@ -171,27 +187,69 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
<Box>
|
||||
{/* user info */}
|
||||
{isPc && (
|
||||
<Flex alignItems={'center'} fontSize={'md'} h={'30px'}>
|
||||
<MyIcon mr={2} name={'support/user/userLight'} w={'1.25rem'} />
|
||||
{t('account_info:personal_information')}
|
||||
<Flex alignItems={'center'} h={'30px'} {...titleStyles}>
|
||||
<MyIcon mr={2} name={'core/dataset/fileCollection'} w={'1.25rem'} />
|
||||
{t('account_info:general_info')}
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<Box mt={[0, 6]} fontSize={'sm'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:user_account')} </Box>
|
||||
<Box flex={1}>{userInfo?.username}</Box>
|
||||
</Flex>
|
||||
{feConfigs?.isPlus && (
|
||||
<Flex mt={4} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:password')} </Box>
|
||||
<Box flex={1}>*****</Box>
|
||||
<Button size={'sm'} variant={'whitePrimary'} onClick={onOpenUpdatePsw}>
|
||||
{t('account_info:change')}
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
{feConfigs?.isPlus && (
|
||||
<Flex mt={4} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('common:contact_way')} </Box>
|
||||
<Box flex={1} {...(!userInfo?.contact ? { color: 'red.600' } : {})}>
|
||||
{userInfo?.contact ? userInfo?.contact : t('account_info:please_bind_contact')}
|
||||
</Box>
|
||||
|
||||
<Button size={'sm'} variant={'whitePrimary'} onClick={onOpenUpdateContact}>
|
||||
{t('account_info:change')}
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<MyDivider my={6} />
|
||||
|
||||
{isPc && (
|
||||
<Flex alignItems={'center'} h={'30px'} {...titleStyles} mt={6}>
|
||||
<MyIcon mr={2} name={'support/team/group'} w={'1.25rem'} />
|
||||
{t('account_info:team_info')}
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{feConfigs.isPlus && (
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:user_team_team_name')} </Box>
|
||||
<Flex flex={'1 0 0'} w={0} align={'center'}>
|
||||
<TeamSelector height={'28px'} w={'100%'} showManage />
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{isPc ? (
|
||||
<Flex alignItems={'center'} cursor={'pointer'}>
|
||||
<Box {...labelStyles}>{t('account_info:avatar')}: </Box>
|
||||
<Flex mt={4} alignItems={'center'} cursor={'pointer'}>
|
||||
<Box {...labelStyles}>{t('account_info:avatar')} </Box>
|
||||
|
||||
<MyTooltip label={t('account_info:select_avatar')}>
|
||||
<Box
|
||||
w={['44px', '56px']}
|
||||
h={['44px', '56px']}
|
||||
w={['22px', '32px']}
|
||||
h={['22px', '32px']}
|
||||
borderRadius={'50%'}
|
||||
border={theme.borders.base}
|
||||
overflow={'hidden'}
|
||||
p={'2px'}
|
||||
boxShadow={'0 0 5px rgba(0,0,0,0.1)'}
|
||||
mb={2}
|
||||
onClick={onOpenSelectFile}
|
||||
>
|
||||
<Avatar src={userInfo?.avatar} borderRadius={'50%'} w={'100%'} h={'100%'} />
|
||||
@@ -228,7 +286,7 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
)}
|
||||
{feConfigs?.isPlus && (
|
||||
<Flex mt={[0, 4]} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:member_name')}: </Box>
|
||||
<Box {...labelStyles}>{t('account_info:member_name')} </Box>
|
||||
<Input
|
||||
flex={'1 0 0'}
|
||||
disabled={isSyncMember}
|
||||
@@ -248,43 +306,10 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex alignItems={'center'} mt={6}>
|
||||
<Box {...labelStyles}>{t('account_info:user_account')}: </Box>
|
||||
<Box flex={1}>{userInfo?.username}</Box>
|
||||
</Flex>
|
||||
{feConfigs?.isPlus && (
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:password')}: </Box>
|
||||
<Box flex={1}>*****</Box>
|
||||
<Button size={'sm'} variant={'whitePrimary'} onClick={onOpenUpdatePsw}>
|
||||
{t('account_info:change')}
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
{feConfigs?.isPlus && (
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('common:contact_way')}: </Box>
|
||||
<Box flex={1} {...(!userInfo?.contact ? { color: 'red.600' } : {})}>
|
||||
{userInfo?.contact ? userInfo?.contact : t('account_info:please_bind_contact')}
|
||||
</Box>
|
||||
|
||||
<Button size={'sm'} variant={'whitePrimary'} onClick={onOpenUpdateContact}>
|
||||
{t('account_info:change')}
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
{feConfigs.isPlus && (
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:user_team_team_name')}: </Box>
|
||||
<Flex flex={'1 0 0'} w={0} align={'center'}>
|
||||
<TeamSelector height={'28px'} w={'100%'} showManage />
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{feConfigs?.isPlus && (userInfo?.team?.balance ?? 0) > 0 && (
|
||||
<Box mt={6} whiteSpace={'nowrap'}>
|
||||
<Box mt={4} whiteSpace={'nowrap'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box {...labelStyles}>{t('account_info:team_balance')}: </Box>
|
||||
<Box {...labelStyles}>{t('account_info:team_balance')} </Box>
|
||||
<Box flex={1}>
|
||||
<strong>{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}</strong>{' '}
|
||||
{t('account_info:yuan')}
|
||||
@@ -298,6 +323,8 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<MyDivider my={6} />
|
||||
</Box>
|
||||
{isOpenConversionModal && (
|
||||
<ConversionModal onClose={onCloseConversionModal} onOpenContact={onOpenContact} />
|
||||
@@ -418,7 +445,16 @@ const PlanUsage = () => {
|
||||
return standardPlan ? (
|
||||
<Box mt={[6, 0]}>
|
||||
<Flex fontSize={['md', 'lg']} h={'30px'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
color="var(--light-general-on-surface, var(--Gray-Modern-900, #111824))"
|
||||
fontFamily='"PingFang SC"'
|
||||
fontSize="16px"
|
||||
fontStyle="normal"
|
||||
fontWeight={500}
|
||||
lineHeight="24px"
|
||||
letterSpacing="0.15px"
|
||||
>
|
||||
<MyIcon mr={2} name={'support/account/plans'} w={'20px'} />
|
||||
{t('account_info:package_and_usage')}
|
||||
</Flex>
|
||||
@@ -601,7 +637,7 @@ const Other = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid gridGap={4} mt={3}>
|
||||
<Grid gridGap={4}>
|
||||
{feConfigs?.docUrl && (
|
||||
<Link
|
||||
href={getDocPath('/docs/intro')}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Box, Button, Flex, useTheme } from '@chakra-ui/react';
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Flex, useTheme } from '@chakra-ui/react';
|
||||
import { getInforms, readInform } from '@/web/support/user/inform/api';
|
||||
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
|
||||
import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
||||
@@ -8,11 +8,31 @@ import { useTranslation } from 'next-i18next';
|
||||
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||
import AccountContainer from '@/pageComponents/account/AccountContainer';
|
||||
import { serviceSideProps } from '@/web/common/i18n/utils';
|
||||
import MyTag from '@fastgpt/web/components/common/Tag/index';
|
||||
import Markdown from '@/components/Markdown';
|
||||
import NotificationDetailsModal from '@/pageComponents/account/NotificationDetailsModal';
|
||||
|
||||
const InformTable = () => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { Loading } = useLoading();
|
||||
const [selectedInform, setSelectedInform] = useState<any>(null);
|
||||
|
||||
const textStyles = {
|
||||
title: {
|
||||
color: '#111824',
|
||||
fontSize: 'md',
|
||||
fontWeight: 'bold',
|
||||
lineHeight: 6,
|
||||
letterSpacing: '0.15px'
|
||||
},
|
||||
time: {
|
||||
color: '#667085',
|
||||
fontSize: 'sm',
|
||||
lineHeight: 5,
|
||||
letterSpacing: '0.25px'
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
data: informs,
|
||||
@@ -28,63 +48,105 @@ const InformTable = () => {
|
||||
|
||||
return (
|
||||
<AccountContainer>
|
||||
<Flex flexDirection={'column'} py={[0, 5]} h={'100%'} position={'relative'}>
|
||||
<Box px={[3, 8]} position={'relative'} flex={'1 0 0'} h={0} overflowY={'auto'}>
|
||||
<Flex flexDirection="column" py={[0, 5]} h="100%" position="relative">
|
||||
<Box
|
||||
px={[3, 8]}
|
||||
position="relative"
|
||||
flex="1 0 0"
|
||||
h={0}
|
||||
overflowY="auto"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
{informs.map((item) => (
|
||||
<Box
|
||||
key={item._id}
|
||||
border={theme.borders.md}
|
||||
py={2}
|
||||
px={4}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
_notLast={{ mb: 3 }}
|
||||
py={5}
|
||||
px={6}
|
||||
maxH="168px"
|
||||
maxW="800px"
|
||||
minW="200px"
|
||||
width="100%"
|
||||
borderRadius="md"
|
||||
position="relative"
|
||||
_notLast={{ mb: 4 }}
|
||||
_hover={{
|
||||
border: '1px solid #94B5FF',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!item.read) {
|
||||
readInform(item._id).then(() => getData(pageNum));
|
||||
}
|
||||
setSelectedInform(item);
|
||||
}}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box fontWeight={'bold'}>{item.title}</Box>
|
||||
<Box ml={2} color={'myGray.500'} flex={'1 0 0'}>
|
||||
({t(formatTimeToChatTime(item.time) as any).replace('#', ':')})
|
||||
<Flex alignItems="center">
|
||||
<Box {...textStyles.title}>
|
||||
{item.teamId ? `【${item.teamName}】` : ''}
|
||||
{item.title}
|
||||
</Box>
|
||||
{!item.read && (
|
||||
<Button
|
||||
variant={'whitePrimary'}
|
||||
size={'xs'}
|
||||
onClick={async () => {
|
||||
if (!item.read) {
|
||||
await readInform(item._id);
|
||||
getData(pageNum);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('account_inform:read')}
|
||||
</Button>
|
||||
)}
|
||||
<Flex ml={3} flex={1} alignItems="center">
|
||||
<Box {...textStyles.time}>
|
||||
{t(formatTimeToChatTime(item.time) as any).replace('#', ':')}
|
||||
</Box>
|
||||
{!item.read && <Box w={2} h={2} borderRadius="full" bg="red.600" ml={3} />}
|
||||
</Flex>
|
||||
|
||||
<MyTag
|
||||
colorSchema={item.teamId ? 'green' : 'blue'}
|
||||
mr={2}
|
||||
fontSize="xs"
|
||||
fontWeight="medium"
|
||||
showDot={false}
|
||||
type="fill"
|
||||
>
|
||||
{item.teamId ? t('account_inform:team') : t('account_inform:system')}
|
||||
</MyTag>
|
||||
</Flex>
|
||||
<Box mt={2} fontSize={'sm'} color={'myGray.600'} whiteSpace={'pre-wrap'}>
|
||||
{item.content}
|
||||
|
||||
<Box
|
||||
mt={2}
|
||||
fontSize="sm"
|
||||
fontWeight={400}
|
||||
color="#485264"
|
||||
overflow="hidden"
|
||||
maxHeight={24}
|
||||
sx={{
|
||||
lineHeight: '16px',
|
||||
'& h1, & h2, & h3, & h4, & h5, & h6': {
|
||||
my: '0 !important',
|
||||
py: 0.5,
|
||||
display: 'block',
|
||||
lineHeight: 'normal'
|
||||
},
|
||||
'& p': {
|
||||
my: 0
|
||||
}
|
||||
}}
|
||||
noOfLines={6}
|
||||
>
|
||||
<Markdown source={item.content} />
|
||||
</Box>
|
||||
{!item.read && (
|
||||
<>
|
||||
<Box
|
||||
w={'5px'}
|
||||
h={'5px'}
|
||||
borderRadius={'10px'}
|
||||
bg={'red.600'}
|
||||
position={'absolute'}
|
||||
top={'8px'}
|
||||
left={'8px'}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{!isLoading && informs.length === 0 && (
|
||||
<EmptyTip text={t('account_inform:no_notifications')}></EmptyTip>
|
||||
<EmptyTip text={t('account_inform:no_notifications')} />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{selectedInform && (
|
||||
<NotificationDetailsModal
|
||||
inform={selectedInform}
|
||||
onClose={() => setSelectedInform(null)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{total > pageSize && (
|
||||
<Flex w={'100%'} mt={4} px={[3, 8]} justifyContent={'flex-end'}>
|
||||
<Flex w="100%" mt={4} px={[3, 8]} justifyContent="flex-end">
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import { GET, POST } from '@/web/common/api/request';
|
||||
import type { UserInformSchema } from '@fastgpt/global/support/user/inform/type';
|
||||
import type { UserInformType } from '@fastgpt/global/support/user/inform/type';
|
||||
import type { SystemMsgModalValueType } from '@fastgpt/service/support/user/inform/type';
|
||||
import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||
|
||||
export const getInforms = (data: PaginationProps) =>
|
||||
POST<PaginationResponse<UserInformSchema>>(`/proApi/support/user/inform/list`, data);
|
||||
POST<PaginationResponse<UserInformType>>(`/proApi/support/user/inform/list`, data);
|
||||
|
||||
export const getUnreadCount = () =>
|
||||
GET<{
|
||||
unReadCount: number;
|
||||
importantInforms: UserInformSchema[];
|
||||
importantInforms: UserInformType[];
|
||||
}>(`/proApi/support/user/inform/countUnread`);
|
||||
export const readInform = (id: string) => GET(`/proApi/support/user/inform/read`, { id });
|
||||
|
||||
|
@@ -40,6 +40,8 @@ export const getTeamMembers = (props: PaginationProps<{ withLeaved?: boolean }>)
|
||||
|
||||
// export const postInviteTeamMember = (data: InviteMemberProps) =>
|
||||
// POST<InviteMemberResponse>(`/proApi/support/user/team/member/invite`, data);
|
||||
export const putUpdateMemberNameByManager = (tmbId: string, name: string) =>
|
||||
PUT(`/proApi/support/user/team/member/updateNameByManager`, { tmbId, name });
|
||||
|
||||
export const putUpdateMemberName = (name: string) =>
|
||||
PUT(`/proApi/support/user/team/member/updateName`, { name });
|
||||
|
Reference in New Issue
Block a user