mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 18:48:55 +00:00
fix colection create api (#766)
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { type DateRange, DayPicker } from 'react-day-picker';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import 'react-day-picker/dist/style.css';
|
||||
import zhCN from 'date-fns/locale/zh-CN';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const DateRangePicker = ({
|
||||
onChange,
|
||||
@@ -20,6 +21,7 @@ const DateRangePicker = ({
|
||||
position?: 'bottom' | 'top';
|
||||
defaultDate?: DateRange;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const OutRangeRef = useRef(null);
|
||||
const [range, setRange] = useState<DateRange | undefined>(defaultDate);
|
||||
@@ -99,7 +101,7 @@ const DateRangePicker = ({
|
||||
mr={2}
|
||||
onClick={() => setShowSelected(false)}
|
||||
>
|
||||
取消
|
||||
{t('common.Close')}
|
||||
</Button>
|
||||
<Button
|
||||
size={'sm'}
|
||||
@@ -108,7 +110,7 @@ const DateRangePicker = ({
|
||||
setShowSelected(false);
|
||||
}}
|
||||
>
|
||||
确认
|
||||
{t('common.Confirm')}
|
||||
</Button>
|
||||
</Flex>
|
||||
}
|
||||
|
@@ -1,6 +1,15 @@
|
||||
import React, { useRef, forwardRef, useMemo } from 'react';
|
||||
import { Menu, MenuList, MenuItem, Button, useDisclosure, MenuButton } from '@chakra-ui/react';
|
||||
import type { ButtonProps } from '@chakra-ui/react';
|
||||
import {
|
||||
Menu,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Button,
|
||||
useDisclosure,
|
||||
MenuButton,
|
||||
Box,
|
||||
css
|
||||
} from '@chakra-ui/react';
|
||||
import type { ButtonProps, MenuItemProps } from '@chakra-ui/react';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
|
||||
export type SelectProps = ButtonProps & {
|
||||
@@ -19,88 +28,102 @@ const MySelect = (
|
||||
selectRef: any
|
||||
) => {
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
const menuItemStyles = {
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myWhite.600'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 2
|
||||
}
|
||||
};
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
autoSelect={false}
|
||||
isOpen={isOpen}
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
strategy={'fixed'}
|
||||
matchWidth
|
||||
<Box
|
||||
css={css({
|
||||
'& div': {
|
||||
width: 'auto !important'
|
||||
}
|
||||
})}
|
||||
>
|
||||
<MenuButton
|
||||
as={Button}
|
||||
ref={ref}
|
||||
width={width}
|
||||
px={3}
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
variant={'whitePrimary'}
|
||||
textAlign={'left'}
|
||||
_active={{
|
||||
transform: 'none'
|
||||
}}
|
||||
{...(isOpen
|
||||
? {
|
||||
boxShadow: '0px 0px 4px #A8DBFF',
|
||||
borderColor: 'primary.500'
|
||||
}
|
||||
: {})}
|
||||
{...props}
|
||||
<Menu
|
||||
autoSelect={false}
|
||||
isOpen={isOpen}
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
strategy={'fixed'}
|
||||
matchWidth
|
||||
>
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</MenuButton>
|
||||
|
||||
<MenuList
|
||||
minW={(() => {
|
||||
const w = ref.current?.clientWidth;
|
||||
if (w) {
|
||||
return `${w}px !important`;
|
||||
}
|
||||
return Array.isArray(width)
|
||||
? width.map((item) => `${item} !important`)
|
||||
: `${width} !important`;
|
||||
})()}
|
||||
p={'6px'}
|
||||
border={'1px solid #fff'}
|
||||
boxShadow={'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'}
|
||||
zIndex={99}
|
||||
maxH={'40vh'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{list.map((item) => (
|
||||
<MenuItem
|
||||
key={item.value}
|
||||
{...menuItemStyles}
|
||||
{...(value === item.value
|
||||
? {
|
||||
color: 'primary.500',
|
||||
bg: 'myWhite.300'
|
||||
}
|
||||
: {})}
|
||||
onClick={() => {
|
||||
if (onchange && value !== item.value) {
|
||||
onchange(item.value);
|
||||
<MenuButton
|
||||
as={Button}
|
||||
ref={ref}
|
||||
width={width}
|
||||
px={3}
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
variant={'whitePrimary'}
|
||||
textAlign={'left'}
|
||||
_active={{
|
||||
transform: 'none'
|
||||
}}
|
||||
{...(isOpen
|
||||
? {
|
||||
boxShadow: '0px 0px 4px #A8DBFF',
|
||||
borderColor: 'primary.500'
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
>
|
||||
{item.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
: {})}
|
||||
{...props}
|
||||
>
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</MenuButton>
|
||||
|
||||
<MenuList
|
||||
minW={(() => {
|
||||
const w = ref.current?.clientWidth;
|
||||
if (w) {
|
||||
return `${w}px !important`;
|
||||
}
|
||||
return Array.isArray(width)
|
||||
? width.map((item) => `${item} !important`)
|
||||
: `${width} !important`;
|
||||
})()}
|
||||
w={'auto'}
|
||||
p={'6px'}
|
||||
border={'1px solid #fff'}
|
||||
boxShadow={
|
||||
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
||||
}
|
||||
zIndex={99}
|
||||
maxH={'40vh'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{list.map((item) => (
|
||||
<MenuItem
|
||||
key={item.value}
|
||||
{...menuItemStyles}
|
||||
{...(value === item.value
|
||||
? {
|
||||
color: 'primary.500',
|
||||
bg: 'myWhite.300'
|
||||
}
|
||||
: {})}
|
||||
onClick={() => {
|
||||
if (onchange && value !== item.value) {
|
||||
onchange(item.value);
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
>
|
||||
{item.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
@@ -15,18 +14,30 @@ import {
|
||||
Button
|
||||
} from '@chakra-ui/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getTeamDatasetValidSub, postExpandTeamDatasetSub } from '@/web/support/wallet/sub/api';
|
||||
import {
|
||||
getTeamDatasetValidSub,
|
||||
posCheckTeamDatasetSizeSub,
|
||||
postUpdateTeamDatasetSizeSub,
|
||||
putTeamDatasetSubStatus
|
||||
} 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';
|
||||
import {
|
||||
SubStatusEnum,
|
||||
SubTypeEnum,
|
||||
subSelectMap
|
||||
} from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { SubDatasetSizePreviewCheckResponse } from '@fastgpt/global/support/wallet/sub/api.d';
|
||||
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
|
||||
const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
|
||||
const datasetStoreFreeSize = feConfigs?.subscription?.datasetStoreFreeSize || 0;
|
||||
@@ -36,29 +47,93 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const { ConfirmModal, openConfirm } = useConfirm({});
|
||||
const { userInfo } = useUserStore();
|
||||
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}`);
|
||||
setIsRenew(res?.sub?.status === SubStatusEnum.active ? 'true' : 'false');
|
||||
setDatasetSize((res?.sub?.nextExtraDatasetSize || 0) / 1000);
|
||||
}
|
||||
});
|
||||
|
||||
const { mutate, isLoading } = useRequest({
|
||||
mutationFn: () => postExpandTeamDatasetSub({ size: datasetSize, renew: isRenew === 'true' }),
|
||||
onSuccess(res) {
|
||||
if (isExpand) {
|
||||
const { mutate: onClickUpdateSub, isLoading: isPaying } = useRequest({
|
||||
mutationFn: () => postUpdateTeamDatasetSizeSub({ size: datasetSize }),
|
||||
onSuccess() {
|
||||
setTimeout(() => {
|
||||
router.reload();
|
||||
}, 100);
|
||||
},
|
||||
successToast: t('common.Update success'),
|
||||
errorToast: t('common.error.Update error')
|
||||
});
|
||||
|
||||
const { mutate: onClickPreviewCheck, isLoading: isFetchingPreviewCheck } = useRequest({
|
||||
mutationFn: () =>
|
||||
posCheckTeamDatasetSizeSub({
|
||||
size: datasetSize
|
||||
}),
|
||||
onSuccess(res: SubDatasetSizePreviewCheckResponse) {
|
||||
if (!res.payForNewSub) {
|
||||
onClickUpdateSub('');
|
||||
return;
|
||||
} else {
|
||||
onClose();
|
||||
openConfirm(
|
||||
() => {
|
||||
if (!res.balanceEnough) return;
|
||||
onClickUpdateSub('');
|
||||
},
|
||||
undefined,
|
||||
<Box>
|
||||
<Flex>
|
||||
<Box flex={'0 0 100px'}>当前额外容量:</Box>
|
||||
<Box>{datasetSub?.sub?.currentExtraDatasetSize || 0}条</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box flex={'0 0 100px'}>新的额外容量:</Box>
|
||||
<Box>{res.newSubSize}条</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box flex={'0 0 100px'}>新套餐价格:</Box>
|
||||
<Box>{formatStorePrice2Read(res.newPrice)}元</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box flex={'0 0 100px'}>本次需支付:</Box>
|
||||
<Box>{formatStorePrice2Read(res.payPrice)}元</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box flex={'0 0 100px'}>有效时长:</Box>
|
||||
<Box>30天</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box flex={'0 0 100px'}>账号余额:</Box>
|
||||
<Box>{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}元</Box>
|
||||
</Flex>
|
||||
{!res.balanceEnough && (
|
||||
<Box mt={1} color={'red.600'}>
|
||||
账号余额不足,请先充值余额再购买额外容量。
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)();
|
||||
}
|
||||
},
|
||||
successToast: isExpand ? t('support.wallet.Pay success') : t('common.Update success'),
|
||||
errorToast: isExpand ? t('support.wallet.Pay error') : t('common.error.Update error')
|
||||
errorToast: t('common.error.Update error')
|
||||
});
|
||||
const { mutate: onUpdateStatus } = useRequest({
|
||||
mutationFn: (e: 'true' | 'false') => {
|
||||
setIsRenew(e);
|
||||
return putTeamDatasetSubStatus({
|
||||
status: subSelectMap[e],
|
||||
type: SubTypeEnum.extraDatasetSize
|
||||
});
|
||||
},
|
||||
successToast: t('common.Update success'),
|
||||
errorToast: t('common.error.Update error')
|
||||
});
|
||||
|
||||
const isLoading = isPaying || isFetchingPreviewCheck;
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
@@ -83,21 +158,35 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
|
||||
/>
|
||||
</>
|
||||
<Flex mt={4}>
|
||||
<Box w={'100px'}>{t('support.wallet.subscription.Current dataset store')}: </Box>
|
||||
<Box flex={'0 0 120px'}>{t('support.wallet.subscription.Current dataset store')}: </Box>
|
||||
<Box ml={2} fontWeight={'bold'} flex={1}>
|
||||
{datasetSub?.sub?.datasetStoreAmount || 0}
|
||||
{datasetSub?.sub?.currentExtraDatasetSize || 0}
|
||||
{t('core.dataset.data.unit')}
|
||||
</Box>
|
||||
</Flex>
|
||||
{datasetSub?.sub?.expiredTime && (
|
||||
{datasetSub?.sub?.nextExtraDatasetSize !== undefined && (
|
||||
<Flex mt={4}>
|
||||
<Box flex={'0 0 120px'}>{t('support.wallet.subscription.Next sub dataset size')}: </Box>
|
||||
<Box ml={2} fontWeight={'bold'} flex={1}>
|
||||
{datasetSub?.sub?.nextExtraDatasetSize || 0}
|
||||
{t('core.dataset.data.unit')}
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{!!datasetSub?.sub?.startTime && (
|
||||
<Flex mt={3}>
|
||||
<Box w={'100px'}>到期时间: </Box>
|
||||
<Box flex={'0 0 120px'}>订阅开始时间: </Box>
|
||||
<Box ml={2}>{formatTime2YMDHM(datasetSub?.sub?.startTime)}</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{!!datasetSub?.sub?.expiredTime && (
|
||||
<Flex mt={3}>
|
||||
<Box flex={'0 0 120px'}>订阅到期时间: </Box>
|
||||
<Box ml={2}>{formatTime2YMDHM(datasetSub?.sub?.expiredTime)}</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<Flex mt={3} alignItems={'center'}>
|
||||
<Box w={'100px'}>是否续订: </Box>
|
||||
<Box flex={'0 0 120px'}>是否自动续费: </Box>
|
||||
<MySelect
|
||||
ml={2}
|
||||
value={isRenew}
|
||||
@@ -107,15 +196,16 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
|
||||
{ label: '自动续费', value: 'true' },
|
||||
{ label: '不自动续费', value: 'false' }
|
||||
]}
|
||||
onchange={setIsRenew}
|
||||
onchange={onUpdateStatus}
|
||||
/>
|
||||
</Flex>
|
||||
<Box mt={4}>
|
||||
<Box>{t('support.wallet.subscription.Expand size')}</Box>
|
||||
<Box>{t('support.wallet.subscription.Update extra dataset size')}</Box>
|
||||
<Flex alignItems={'center'} mt={1}>
|
||||
<NumberInput
|
||||
flex={1}
|
||||
min={0}
|
||||
max={1000}
|
||||
step={1}
|
||||
value={datasetSize}
|
||||
position={'relative'}
|
||||
@@ -123,7 +213,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
|
||||
setDatasetSize(Number(e));
|
||||
}}
|
||||
>
|
||||
<NumberInputField value={datasetSize} step={1} min={0} />
|
||||
<NumberInputField value={datasetSize} step={1} min={0} max={1000} />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
@@ -134,33 +224,14 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
|
||||
</Box>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button mr={3} variant={'whiteBase'} onClick={onClose}>
|
||||
<Button 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>
|
||||
{datasetSize * 1000 !== datasetSub?.sub?.nextExtraDatasetSize && (
|
||||
<Button ml={3} isLoading={isLoading} onClick={onClickPreviewCheck}>
|
||||
{t('common.Confirm')}
|
||||
</Button>
|
||||
)}
|
||||
</ModalFooter>
|
||||
|
||||
<ConfirmModal />
|
||||
|
Reference in New Issue
Block a user