4.6.7 first pr (#726)

This commit is contained in:
Archer
2024-01-10 23:35:04 +08:00
committed by GitHub
parent 414b693303
commit 006ad17c6a
186 changed files with 2996 additions and 1838 deletions

View File

@@ -40,8 +40,8 @@ const FeedbackModal = ({
onSuccess() {
onSuccess(ref.current?.value || t('core.chat.feedback.No Content'));
},
successToast: t('chat.Feedback Success'),
errorToast: t('chat.Feedback Failed')
successToast: t('core.chat.Feedback Success'),
errorToast: t('core.chat.Feedback Failed')
});
return (
@@ -49,17 +49,17 @@ const FeedbackModal = ({
isOpen={true}
onClose={onClose}
iconSrc="/imgs/modal/badAnswer.svg"
title={t('chat.Feedback Modal')}
title={t('core.chat.Feedback Modal')}
>
<ModalBody>
<Textarea ref={ref} rows={10} placeholder={t('chat.Feedback Modal Tip')} />
<Textarea ref={ref} rows={10} placeholder={t('core.chat.Feedback Modal Tip')} />
</ModalBody>
<ModalFooter>
<Button variant={'whiteBase'} mr={2} onClick={onClose}>
{t('Cancel')}
</Button>
<Button isLoading={isLoading} onClick={mutate}>
{t('chat.Feedback Submit')}
{t('core.chat.Feedback Submit')}
</Button>
</ModalFooter>
</MyModal>

View File

@@ -8,10 +8,11 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRouter } from 'next/router';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { useToast } from '@/web/common/hooks/useToast';
import { customAlphabet } from 'nanoid';
import { IMG_BLOCK_KEY } from '@fastgpt/global/core/chat/constants';
import { addDays } from 'date-fns';
import { useRequest } from '@/web/common/hooks/useRequest';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
enum FileTypeEnum {
@@ -45,7 +46,6 @@ const MessageInput = ({
resetInputVal: (val: string) => void;
}) => {
const { shareId } = useRouter().query as { shareId?: string };
const { toast } = useToast();
const {
isSpeaking,
isTransCription,
@@ -68,17 +68,18 @@ const MessageInput = ({
maxCount: 10
});
const uploadFile = useCallback(
async (file: FileItemType) => {
const { mutate: uploadFile } = useRequest({
mutationFn: async (file: FileItemType) => {
if (file.type === FileTypeEnum.image) {
try {
const src = await compressImgFileAndUpload({
type: MongoImageTypeEnum.chatImage,
file: file.rawFile,
maxW: 4329,
maxH: 4329,
maxSize: 1024 * 1024 * 5,
// 30 day expired.
expiredTime: addDays(new Date(), 30),
expiredTime: addDays(new Date(), 7),
shareId
});
setFileList((state) =>
@@ -94,16 +95,13 @@ const MessageInput = ({
} catch (error) {
setFileList((state) => state.filter((item) => item.id !== file.id));
console.log(error);
toast({
status: 'error',
title: t('common.Upload File Failed')
});
return Promise.reject(error);
}
}
},
[shareId, t, toast]
);
errorToast: t('common.Upload File Failed')
});
const onSelectFile = useCallback(
async (files: File[]) => {
if (!files || files.length === 0) {
@@ -219,7 +217,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
visibility={isSpeaking && isTransCription ? 'visible' : 'hidden'}
>
<Spinner size={'sm'} mr={4} />
{t('chat.Converting to text')}
{t('core.chat.Converting to text')}
</Flex>
{/* file preview */}

View File

@@ -5,7 +5,7 @@ import MyModal from '../MyModal';
import { useTranslation } from 'next-i18next';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import QuoteItem from '../core/dataset/QuoteItem';
import { RawSourceText } from '@/pages/dataset/detail/components/InputDataModal';
import RawSourceBox from '../core/dataset/RawSourceBox';
const QuoteModal = ({
rawSearch = [],
@@ -46,7 +46,7 @@ const QuoteModal = ({
title={
<Box>
{metadata ? (
<RawSourceText {...metadata} canView={false} />
<RawSourceBox {...metadata} canView={false} />
) : (
<>{t('core.chat.Quote Amount', { amount: rawSearch.length })}</>
)}

View File

@@ -19,7 +19,7 @@ const ReadFeedbackModal = ({
isOpen={true}
onClose={onClose}
iconSrc="/imgs/modal/readFeedback.svg"
title={t('chat.Feedback Modal')}
title={t('core.chat.Feedback Modal')}
>
<ModalBody>{content}</ModalBody>
<ModalFooter>

View File

@@ -92,7 +92,7 @@ const ResponseTags = ({
<>
{sourceList.length > 0 && (
<>
<ChatBoxDivider icon="core/chat/quoteFill" text={t('chat.Quote')} />
<ChatBoxDivider icon="core/chat/quoteFill" text={t('core.chat.Quote')} />
<Flex alignItems={'center'} flexWrap={'wrap'} gap={2}>
{sourceList.map((item) => (
<MyTooltip key={item.collectionId} label={t('core.chat.quote.Read Quote')}>

View File

@@ -46,7 +46,7 @@ const SelectMarkCollection = ({
paths={paths}
onClose={onClose}
setParentId={setParentId}
tips={t('chat.Select Mark Kb Desc')}
tips={t('core.chat.Select Mark Kb Desc')}
>
<ModalBody flex={'1 0 0'} overflowY={'auto'}>
<Grid
@@ -164,19 +164,23 @@ const SelectMarkCollection = ({
<InputDataModal
onClose={onClose}
collectionId={adminMarkData.collectionId}
dataId={adminMarkData.dataId}
defaultValue={{
id: adminMarkData.dataId,
q: adminMarkData.q,
a: adminMarkData.a,
indexes: [getDefaultIndex({ dataId: `${Date.now()}` })]
a: adminMarkData.a
}}
onSuccess={(data) => {
if (!data.q || !adminMarkData.datasetId || !adminMarkData.collectionId || !data.id) {
if (
!data.q ||
!adminMarkData.datasetId ||
!adminMarkData.collectionId ||
!data.dataId
) {
return onClose();
}
onSuccess({
dataId: data.id,
dataId: data.dataId,
datasetId: adminMarkData.datasetId,
collectionId: adminMarkData.collectionId,
q: data.q,

View File

@@ -910,14 +910,15 @@ const ChatBox = (
)}
{/* admin mark content */}
{showMarkIcon && item.adminFeedback && (
<Box>
<Box fontSize={'sm'}>
<ChatBoxDivider
icon="core/app/markLight"
text={t('chat.Admin Mark Content')}
text={t('core.chat.Admin Mark Content')}
/>
<Box whiteSpace={'pre'}>{`${item.adminFeedback.q || ''}${
item.adminFeedback.a ? `\n${item.adminFeedback.a}` : ''
}`}</Box>
<Box whiteSpace={'pre'}>
<Box color={'black'}>{item.adminFeedback.q}</Box>
<Box color={'myGray.600'}>{item.adminFeedback.a}</Box>
</Box>
</Box>
)}
</Card>
@@ -996,6 +997,7 @@ const ChatBox = (
setAdminMarkData={(e) => setAdminMarkData({ ...e, chatItemId: adminMarkData.chatItemId })}
onClose={() => setAdminMarkData(undefined)}
onSuccess={(adminFeedback) => {
console.log(adminMarkData);
if (!appId || !chatId || !adminMarkData.chatItemId) return;
updateChatAdminFeedback({
appId,
@@ -1003,6 +1005,7 @@ const ChatBox = (
chatItemId: adminMarkData.chatItemId,
...adminFeedback
});
// update dom
setChatHistory((state) =>
state.map((chatItem) =>
@@ -1234,7 +1237,7 @@ function ChatController({
{!!onDelete && (
<>
{onRetry && (
<MyTooltip label={t('chat.retry')}>
<MyTooltip label={t('core.chat.retry')}>
<MyIcon
{...controlIconStyle}
name={'common/retryLight'}
@@ -1301,7 +1304,7 @@ function ChatController({
</MyTooltip>
))}
{!!onMark && (
<MyTooltip label={t('chat.Mark')}>
<MyTooltip label={t('core.chat.Mark')}>
<MyIcon
{...controlIconStyle}
name={'core/app/markLight'}

View File

@@ -30,7 +30,7 @@ const Navbar = ({ unread }: { unread: number }) => {
{
label: t('navbar.Chat'),
icon: 'core/chat/chatLight',
activeIcon: 'chatcore/dataset/chatFillFill',
activeIcon: 'core/chat/chatFill',
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
activeLink: ['/chat']
},
@@ -77,6 +77,12 @@ const Navbar = ({ unread }: { unread: number }) => {
h: '58px',
borderRadius: 'md'
};
const hoverStyle: LinkProps = {
_hover: {
bg: 'myGray.05',
color: 'primary.600'
}
};
return (
<Flex
@@ -146,10 +152,11 @@ const Navbar = ({ unread }: { unread: number }) => {
<Link
as={NextLink}
{...itemStyles}
{...hoverStyle}
prefetch
href={`/account?currentTab=inform`}
mb={0}
color={'#9096a5'}
color={'myGray.500'}
>
<Badge count={unread}>
<MyIcon name={'inform'} width={'22px'} height={'22px'} />
@@ -161,10 +168,11 @@ const Navbar = ({ unread }: { unread: number }) => {
<MyTooltip label={t('common.system.Use Helper')} placement={'right-end'}>
<Link
{...itemStyles}
{...hoverStyle}
href={feConfigs?.chatbotUrl || getDocPath('/docs/intro')}
target="_blank"
mb={0}
color={'#9096a5'}
color={'myGray.500'}
>
<MyIcon name={'common/courseLight'} width={'26px'} height={'26px'} />
</Link>
@@ -177,8 +185,9 @@ const Navbar = ({ unread }: { unread: number }) => {
href="https://github.com/labring/FastGPT"
target={'_blank'}
{...itemStyles}
{...hoverStyle}
mt={0}
color={'#9096a5'}
color={'myGray.500'}
>
<MyIcon name={'common/gitLight'} width={'22px'} height={'22px'} />
</Link>

View File

@@ -24,7 +24,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
return questionGuides.length > 0 ? (
<Box mt={2}>
<ChatBoxDivider icon="core/chat/QGFill" text={t('chat.Question Guide Tips')} />
<ChatBoxDivider icon="core/chat/QGFill" text={t('core.chat.Question Guide Tips')} />
<Flex alignItems={'center'} flexWrap={'wrap'} gap={2}>
{questionGuides.map((text) => (
<Flex

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { WheelEventHandler, useState } from 'react';
import {
Box,
Image,
@@ -14,6 +14,17 @@ const MdImage = ({ src }: { src?: string }) => {
const [isLoading, setIsLoading] = useState(true);
const [succeed, setSucceed] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const [scale, setScale] = useState(1);
const handleWheel: WheelEventHandler<HTMLImageElement> = (e) => {
setScale((prevScale) => {
const newScale = prevScale + e.deltaY * 0.5 * -0.01;
if (newScale < 0.5) return 0.5;
if (newScale > 10) return 10;
return newScale;
});
};
return (
<Skeleton
minH="100px"
@@ -48,6 +59,7 @@ const MdImage = ({ src }: { src?: string }) => {
<ModalOverlay />
<ModalContent boxShadow={'none'} maxW={'auto'} w="auto" bg={'transparent'}>
<Image
transform={`scale(${scale})`}
borderRadius={'md'}
src={src}
alt={''}
@@ -57,6 +69,7 @@ const MdImage = ({ src }: { src?: string }) => {
fallbackSrc={'/imgs/errImg.png'}
fallbackStrategy={'onError'}
objectFit={'contain'}
onWheel={handleWheel}
/>
</ModalContent>
<ModalCloseButton bg={'myWhite.500'} zIndex={999999} />

View File

@@ -343,7 +343,6 @@
margin: 10px 0;
}
.markdown {
text-align: justify;
tab-size: 4;
word-spacing: normal;
width: 100%;

View File

@@ -112,6 +112,17 @@ function A({ children, ...props }: any) {
}
const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => {
const components = useMemo<any>(
() => ({
img: Image,
pre: 'div',
p: (pProps: any) => <p {...pProps} dir="auto" />,
code: Code,
a: A
}),
[]
);
const formatSource = source
.replace(/\\n/g, '\n&nbsp;')
.replace(/(http[s]?:\/\/[^\s。]+)([。,])/g, '$1 $2')
@@ -124,13 +135,7 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
`}
remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
rehypePlugins={[RehypeKatex]}
components={{
img: Image,
pre: 'div',
p: (pProps) => <p {...pProps} dir="auto" />,
code: Code,
a: A
}}
components={components}
linkTarget={'_blank'}
>
{formatSource}

View File

@@ -4,18 +4,19 @@ import MySelect, { type SelectProps } from './index';
import { useTranslation } from 'next-i18next';
import dynamic from 'next/dynamic';
import { useDisclosure } from '@chakra-ui/react';
import { feConfigs } from '@/web/common/system/staticData';
const PriceBox = dynamic(() => import('@/components/support/wallet/Price'));
const SelectAiModel = ({ list, ...props }: SelectProps) => {
const { t } = useTranslation();
const expandList = useMemo(
() =>
list.concat({
label: t('support.user.Price'),
value: 'price'
}),
[list, t]
);
const expandList = useMemo(() => {
return feConfigs.show_pay
? list.concat({
label: t('support.user.Price'),
value: 'price'
})
: list;
}, [list, t]);
const {
isOpen: isOpenPriceBox,

View File

@@ -0,0 +1,30 @@
import { Box, Flex, FlexProps } from '@chakra-ui/react';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import React from 'react';
import { DatasetTypeMap } from '@fastgpt/global/core/dataset/constant';
const DatasetTypeTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps) => {
const { t } = useTranslation();
const item = DatasetTypeMap[type];
return (
<Flex
bg={'myGray.100'}
borderWidth={'1px'}
borderColor={'myGray.200'}
px={4}
py={'6px'}
borderRadius={'md'}
fontSize={'xs'}
{...props}
>
<MyIcon name={item.icon as any} w={'16px'} mr={2} color={'myGray.400'} />
<Box>{t(item.label)}</Box>
</Flex>
);
};
export default DatasetTypeTag;

View File

@@ -1,9 +1,6 @@
import React, { useMemo, useState } from 'react';
import { Box, Flex, Link, Progress } from '@chakra-ui/react';
import {
type InputDataType,
RawSourceText
} from '@/pages/dataset/detail/components/InputDataModal';
import RawSourceBox from '@/components/core/dataset/RawSourceBox';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type.d';
import NextLink from 'next/link';
import MyIcon from '@fastgpt/web/components/common/Icon';
@@ -11,9 +8,6 @@ import { useTranslation } from 'next-i18next';
import MyTooltip from '@/components/MyTooltip';
import dynamic from 'next/dynamic';
import MyBox from '@/components/common/MyBox';
import { getDatasetDataItemById } from '@/web/core/dataset/api';
import { useRequest } from '@/web/common/hooks/useRequest';
import { DatasetDataItemType } from '@fastgpt/global/core/dataset/type';
import { SearchScoreTypeEnum, SearchScoreTypeMap } from '@fastgpt/global/core/dataset/constant';
const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal'));
@@ -58,17 +52,7 @@ const QuoteItem = ({
linkToDataset?: boolean;
}) => {
const { t } = useTranslation();
const [editInputData, setEditInputData] = useState<InputDataType & { collectionId: string }>();
const { mutate: onclickEdit, isLoading } = useRequest({
mutationFn: async (id: string) => {
return getDatasetDataItemById(id);
},
onSuccess(data: DatasetDataItemType) {
setEditInputData(data);
},
errorToast: t('core.dataset.data.get data error')
});
const [editInputData, setEditInputData] = useState<{ dataId: string; collectionId: string }>();
const score = useMemo(() => {
if (!Array.isArray(quoteItem.score)) {
@@ -114,7 +98,6 @@ const QuoteItem = ({
return (
<>
<MyBox
isLoading={isLoading}
position={'relative'}
overflow={'hidden'}
fontSize={'sm'}
@@ -124,7 +107,7 @@ const QuoteItem = ({
display={'flex'}
flexDirection={'column'}
>
<Flex alignItems={'center'} mb={3}>
<Flex alignItems={'center'} mb={3} flexWrap={'wrap'} gap={3}>
{score?.primaryScore && (
<>
{canViewSource ? (
@@ -132,7 +115,6 @@ const QuoteItem = ({
<Flex
px={'12px'}
py={'5px'}
mr={4}
borderRadius={'md'}
color={'primary.700'}
bg={'primary.50'}
@@ -177,13 +159,13 @@ const QuoteItem = ({
{canViewSource &&
score.secondaryScore.map((item, i) => (
<MyTooltip key={item.type} label={t(SearchScoreTypeMap[item.type]?.desc)}>
<Box fontSize={'xs'} mr={3}>
<Box fontSize={'xs'}>
<Flex alignItems={'flex-start'} lineHeight={1.2} mb={1}>
<Box
px={'5px'}
borderWidth={'1px'}
borderRadius={'sm'}
mr={1}
mr={'2px'}
{...(scoreTheme[i] && scoreTheme[i])}
>
<Box transform={'scale(0.9)'}>#{item.index + 1}</Box>
@@ -223,7 +205,7 @@ const QuoteItem = ({
{quoteItem.q.length + (quoteItem.a?.length || 0)}
</Flex>
</MyTooltip>
<RawSourceText
<RawSourceBox
fontWeight={'bold'}
color={'black'}
sourceName={quoteItem.sourceName}
@@ -249,7 +231,12 @@ const QuoteItem = ({
_hover={{
color: 'primary.600'
}}
onClick={() => onclickEdit(quoteItem.id)}
onClick={() =>
setEditInputData({
dataId: quoteItem.id,
collectionId: quoteItem.collectionId
})
}
/>
</Box>
</MyTooltip>
@@ -271,7 +258,7 @@ const QuoteItem = ({
)}
</MyBox>
{editInputData && editInputData.id && (
{editInputData && (
<InputDataModal
onClose={() => setEditInputData(undefined)}
onSuccess={() => {
@@ -280,7 +267,7 @@ const QuoteItem = ({
onDelete={() => {
console.log('删除引用成功');
}}
defaultValue={editInputData}
dataId={editInputData.dataId}
collectionId={editInputData.collectionId}
/>
)}

View File

@@ -0,0 +1,68 @@
import React, { useMemo } from 'react';
import { Box, BoxProps, Image } from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import MyTooltip from '@/components/MyTooltip';
import { useTranslation } from 'next-i18next';
import { getFileAndOpen } from '@/web/core/dataset/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
type Props = BoxProps & {
sourceName?: string;
sourceId?: string;
canView?: boolean;
};
const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: Props) => {
const { t } = useTranslation();
const { toast } = useToast();
const { setLoading } = useSystemStore();
const canPreview = useMemo(() => !!sourceId && canView, [canView, sourceId]);
const icon = useMemo(() => getSourceNameIcon({ sourceId, sourceName }), [sourceId, sourceName]);
return (
<MyTooltip
label={canPreview ? t('file.Click to view file') || '' : ''}
shouldWrapChildren={false}
>
<Box
color={'myGray.600'}
display={'inline-flex'}
whiteSpace={'nowrap'}
{...(canPreview
? {
cursor: 'pointer',
textDecoration: 'underline',
onClick: async () => {
setLoading(true);
try {
await getFileAndOpen(sourceId as string);
} catch (error) {
toast({
title: t(getErrText(error, 'error.fileNotFound')),
status: 'error'
});
}
setLoading(false);
}
}
: {})}
{...props}
>
<Image src={icon} alt="" w={['14px', '16px']} mr={2} />
<Box
maxW={['200px', '300px']}
className={props.className ?? 'textEllipsis'}
wordBreak={'break-all'}
>
{sourceName || t('common.UnKnow Source')}
</Box>
</Box>
</MyTooltip>
);
};
export default RawSourceBox;

View File

@@ -38,7 +38,7 @@ const DatasetSelectContainer = ({
parentId: path.parentId,
parentName: path.parentName
}))}
FirstPathDom={t('chat.Select Mark Kb')}
FirstPathDom={t('core.chat.Select Mark Kb')}
onClick={(e) => {
setParentId(e);
}}

View File

@@ -12,6 +12,7 @@ import MyTooltip from '@/components/MyTooltip';
import Avatar from '@/components/Avatar';
import { postCreateTeam, putUpdateTeam } from '@/web/support/user/team/api';
import { CreateTeamProps } from '@fastgpt/global/support/user/team/controller.d';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
export type FormDataType = CreateTeamProps & {
id?: string;
@@ -50,6 +51,7 @@ function EditModal({
if (!file) return;
try {
const src = await compressImgFileAndUpload({
type: MongoImageTypeEnum.teamAvatar,
file,
maxW: 300,
maxH: 300

View File

@@ -17,14 +17,6 @@ import Markdown from '@/components/Markdown';
const Price = ({ onClose }: { onClose: () => void }) => {
const list = [
{
title: '知识库存储',
describe: '',
md: `
| 计费项 | 价格(¥) |
| --- | --- |
| 知识库索引数量 | 0/1000条/天 |`
},
{
title: '对话模型',
describe: '',

View File

@@ -0,0 +1,171 @@
import React, { useState } from 'react';
import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next';
import {
Box,
Flex,
ModalBody,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
ModalFooter,
Button
} from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { getTeamDatasetValidSub, postExpandTeamDatasetSub } from '@/web/support/wallet/sub/api';
import Markdown from '@/components/Markdown';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { getMonthRemainingDays } from '@fastgpt/global/common/math/date';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useRouter } from 'next/router';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@/web/common/hooks/useToast';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import MySelect from '@/components/Select';
const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
const datasetStoreFreeSize = feConfigs?.subscription?.datasetStoreFreeSize || 0;
const datasetStorePrice = feConfigs?.subscription?.datasetStorePrice || 0;
const { t } = useTranslation();
const { toast } = useToast();
const router = useRouter();
const { ConfirmModal, openConfirm } = useConfirm({});
const [datasetSize, setDatasetSize] = useState(0);
const [isRenew, setIsRenew] = useState('false');
const isExpand = datasetSize > 0;
const { data: datasetSub } = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub, {
onSuccess(res) {
setIsRenew(`${res?.sub?.renew}`);
}
});
const { mutate, isLoading } = useRequest({
mutationFn: () => postExpandTeamDatasetSub({ size: datasetSize, renew: isRenew === 'true' }),
onSuccess(res) {
if (isExpand) {
router.reload();
} else {
onClose();
}
},
successToast: isExpand ? t('support.wallet.Pay success') : t('common.Update success'),
errorToast: isExpand ? t('support.wallet.Pay error') : t('common.error.Update error')
});
return (
<MyModal
isOpen
iconSrc="/imgs/module/db.png"
title={t('support.wallet.subscription.Dataset store')}
>
<ModalBody>
<>
<Flex alignItems={'center'}>
{t('support.user.Price')}
<MyTooltip label={t('support.wallet.subscription.Dataset store price tip')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Flex>
<Markdown
source={`
| 免费知识库 | ${datasetStoreFreeSize}条 |
| --- | --- |
| 额外知识库 | ${datasetStorePrice}元/1000条/月 |
`}
/>
</>
<Flex mt={4}>
<Box w={'100px'}>{t('support.wallet.subscription.Current dataset store')}: </Box>
<Box ml={2} fontWeight={'bold'} flex={1}>
{datasetSub?.sub?.datasetStoreAmount || 0}
{t('core.dataset.data.unit')}
</Box>
</Flex>
{datasetSub?.sub?.expiredTime && (
<Flex mt={3}>
<Box w={'100px'}>: </Box>
<Box ml={2}>{formatTime2YMDHM(datasetSub?.sub?.expiredTime)}</Box>
</Flex>
)}
<Flex mt={3} alignItems={'center'}>
<Box w={'100px'}>: </Box>
<MySelect
ml={2}
value={isRenew}
size={'sm'}
w={'150px'}
list={[
{ label: '自动续费', value: 'true' },
{ label: '不自动续费', value: 'false' }
]}
onchange={setIsRenew}
/>
</Flex>
<Box mt={4}>
<Box>{t('support.wallet.subscription.Expand size')}</Box>
<Flex alignItems={'center'} mt={1}>
<NumberInput
flex={1}
min={0}
step={1}
value={datasetSize}
position={'relative'}
onChange={(e) => {
setDatasetSize(Number(e));
}}
>
<NumberInputField value={datasetSize} step={1} min={0} />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<Box ml={2}>000{t('core.dataset.data.unit')}</Box>
</Flex>
</Box>
</ModalBody>
<ModalFooter>
<Button mr={3} variant={'whiteBase'} onClick={onClose}>
{t('common.Close')}
</Button>
<Button
isLoading={isLoading}
onClick={() => {
if (isExpand) {
const currentMonthPrice = (
datasetSize *
datasetStorePrice *
(getMonthRemainingDays() / 30)
).toFixed(2);
const totalSize = (datasetSub?.sub?.datasetStoreAmount || 0) / 1000 + datasetSize;
openConfirm(
mutate,
undefined,
`本次扩容预估扣除 ${currentMonthPrice} 元。次月起,每月 1 号将会扣除 ${
totalSize * datasetStorePrice
} 元(共${totalSize * 1000}条)。请确保账号余额充足。`
)();
} else {
mutate('');
}
}}
>
{t('common.Confirm')}
</Button>
</ModalFooter>
<ConfirmModal />
</MyModal>
);
};
export default SubDatasetModal;