feat: usage filter & export & dashbord (#3538)
* feat: usage filter & export & dashbord * adjust ui * fix tmb scroll * fix code & selecte all * merge
This commit is contained in:
parent
e009be51e7
commit
0c05add8b2
17
packages/global/support/wallet/usage/api.d.ts
vendored
17
packages/global/support/wallet/usage/api.d.ts
vendored
@ -6,6 +6,23 @@ export type CreateTrainingUsageProps = {
|
|||||||
datasetId: string;
|
datasetId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GetTotalPointsProps = {
|
||||||
|
dateStart: Date;
|
||||||
|
dateEnd: Date;
|
||||||
|
teamMemberIds: string[];
|
||||||
|
sources: UsageSourceEnum[];
|
||||||
|
unit: 'day' | 'week' | 'month';
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetUsageProps = {
|
||||||
|
dateStart: Date;
|
||||||
|
dateEnd: Date;
|
||||||
|
sources?: UsageSourceEnum[];
|
||||||
|
teamMemberIds?: string[];
|
||||||
|
projectName?: string;
|
||||||
|
isSelectAllTmb?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type ConcatUsageProps = UsageListItemCountType & {
|
export type ConcatUsageProps = UsageListItemCountType & {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
|
|||||||
@ -18,30 +18,30 @@ export const UsageSourceMap = {
|
|||||||
label: i18nT('common:core.chat.logs.online')
|
label: i18nT('common:core.chat.logs.online')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.api]: {
|
[UsageSourceEnum.api]: {
|
||||||
label: 'Api'
|
label: 'API'
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.shareLink]: {
|
[UsageSourceEnum.shareLink]: {
|
||||||
label: i18nT('common:core.chat.logs.free_login')
|
label: i18nT('common:core.chat.logs.free_login')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.training]: {
|
[UsageSourceEnum.training]: {
|
||||||
label: 'dataset.Training Name'
|
label: i18nT('common:dataset.Training Name')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.cronJob]: {
|
[UsageSourceEnum.cronJob]: {
|
||||||
label: i18nT('common:cron_job_run_app')
|
label: i18nT('common:cron_job_run_app')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.feishu]: {
|
[UsageSourceEnum.feishu]: {
|
||||||
label: i18nT('user:usage.feishu')
|
label: i18nT('account_usage:feishu')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.official_account]: {
|
[UsageSourceEnum.official_account]: {
|
||||||
label: i18nT('user:usage.official_account')
|
label: i18nT('account_usage:official_account')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.share]: {
|
[UsageSourceEnum.share]: {
|
||||||
label: i18nT('user:usage.share')
|
label: i18nT('account_usage:share')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.wecom]: {
|
[UsageSourceEnum.wecom]: {
|
||||||
label: i18nT('user:usage.wecom')
|
label: i18nT('account_usage:wecom')
|
||||||
},
|
},
|
||||||
[UsageSourceEnum.dingtalk]: {
|
[UsageSourceEnum.dingtalk]: {
|
||||||
label: i18nT('user:usage.dingtalk')
|
label: i18nT('account_usage:dingtalk')
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SourceMemberType } from '../../../support/user/type';
|
||||||
import { CreateUsageProps } from './api';
|
import { CreateUsageProps } from './api';
|
||||||
import { UsageSourceEnum } from './constants';
|
import { UsageSourceEnum } from './constants';
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ export type UsageListItemCountType = {
|
|||||||
// deprecated
|
// deprecated
|
||||||
tokens?: number;
|
tokens?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UsageListItemType = UsageListItemCountType & {
|
export type UsageListItemType = UsageListItemCountType & {
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
amount: number;
|
amount: number;
|
||||||
@ -28,4 +30,5 @@ export type UsageItemType = {
|
|||||||
source: UsageSchemaType['source'];
|
source: UsageSchemaType['source'];
|
||||||
totalPoints: number;
|
totalPoints: number;
|
||||||
list: UsageSchemaType['list'];
|
list: UsageSchemaType['list'];
|
||||||
|
sourceMember: SourceMemberType;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo, useRef } from 'react';
|
import React, { useState, useMemo, useRef, useEffect } from 'react';
|
||||||
import { Box, Card, Flex, useTheme, useOutsideClick, Button } from '@chakra-ui/react';
|
import { Box, Card, Flex, useTheme, useOutsideClick, Button } from '@chakra-ui/react';
|
||||||
import { addDays, format } from 'date-fns';
|
import { addDays, format } from 'date-fns';
|
||||||
import { type DateRange, DayPicker } from 'react-day-picker';
|
import { type DateRange, DayPicker } from 'react-day-picker';
|
||||||
@ -14,12 +14,14 @@ const DateRangePicker = ({
|
|||||||
defaultDate = {
|
defaultDate = {
|
||||||
from: addDays(new Date(), -30),
|
from: addDays(new Date(), -30),
|
||||||
to: new Date()
|
to: new Date()
|
||||||
}
|
},
|
||||||
|
dateRange
|
||||||
}: {
|
}: {
|
||||||
onChange?: (date: DateRange) => void;
|
onChange?: (date: DateRange) => void;
|
||||||
onSuccess?: (date: DateRange) => void;
|
onSuccess?: (date: DateRange) => void;
|
||||||
position?: 'bottom' | 'top';
|
position?: 'bottom' | 'top';
|
||||||
defaultDate?: DateRange;
|
defaultDate?: DateRange;
|
||||||
|
dateRange?: DateRange;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -27,6 +29,12 @@ const DateRangePicker = ({
|
|||||||
const [range, setRange] = useState<DateRange | undefined>(defaultDate);
|
const [range, setRange] = useState<DateRange | undefined>(defaultDate);
|
||||||
const [showSelected, setShowSelected] = useState(false);
|
const [showSelected, setShowSelected] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (dateRange) {
|
||||||
|
setRange(dateRange);
|
||||||
|
}
|
||||||
|
}, [dateRange]);
|
||||||
|
|
||||||
const formatSelected = useMemo(() => {
|
const formatSelected = useMemo(() => {
|
||||||
if (range?.from && range.to) {
|
if (range?.from && range.to) {
|
||||||
return `${format(range.from, 'y-MM-dd')} ~ ${format(range.to, 'y-MM-dd')}`;
|
return `${format(range.from, 'y-MM-dd')} ~ ${format(range.to, 'y-MM-dd')}`;
|
||||||
@ -49,7 +57,7 @@ const DateRangePicker = ({
|
|||||||
py={1}
|
py={1}
|
||||||
borderRadius={'sm'}
|
borderRadius={'sm'}
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
bg={'myGray.100'}
|
bg={'myGray.50'}
|
||||||
fontSize={'sm'}
|
fontSize={'sm'}
|
||||||
onClick={() => setShowSelected(true)}
|
onClick={() => setShowSelected(true)}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
|
||||||
ButtonProps,
|
ButtonProps,
|
||||||
|
Checkbox,
|
||||||
Flex,
|
Flex,
|
||||||
Menu,
|
Menu,
|
||||||
MenuButton,
|
MenuButton,
|
||||||
@ -10,11 +10,12 @@ import {
|
|||||||
MenuList,
|
MenuList,
|
||||||
useDisclosure
|
useDisclosure
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import React, { useRef } from 'react';
|
import React, { useMemo, useRef } from 'react';
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import MyTag from '../Tag/index';
|
import MyTag from '../Tag/index';
|
||||||
import MyIcon from '../Icon';
|
import MyIcon from '../Icon';
|
||||||
import MyAvatar from '../Avatar';
|
import MyAvatar from '../Avatar';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useScrollPagination } from '../../../hooks/useScrollPagination';
|
||||||
|
|
||||||
export type SelectProps<T = any> = {
|
export type SelectProps<T = any> = {
|
||||||
value: T[];
|
value: T[];
|
||||||
@ -25,22 +26,31 @@ export type SelectProps<T = any> = {
|
|||||||
value: T;
|
value: T;
|
||||||
}[];
|
}[];
|
||||||
maxH?: number;
|
maxH?: number;
|
||||||
|
itemWrap?: boolean;
|
||||||
onSelect: (val: T[]) => void;
|
onSelect: (val: T[]) => void;
|
||||||
closeable?: boolean;
|
closeable?: boolean;
|
||||||
|
showCheckedIcon?: boolean;
|
||||||
|
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||||
|
isSelectAll?: boolean;
|
||||||
|
setIsSelectAll?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
} & Omit<ButtonProps, 'onSelect'>;
|
} & Omit<ButtonProps, 'onSelect'>;
|
||||||
|
|
||||||
const MultipleSelect = <T = any,>({
|
const MultipleSelect = <T = any,>({
|
||||||
value = [],
|
value = [],
|
||||||
placeholder,
|
placeholder,
|
||||||
list = [],
|
list = [],
|
||||||
width = '100%',
|
|
||||||
maxH = 400,
|
maxH = 400,
|
||||||
onSelect,
|
onSelect,
|
||||||
closeable = false,
|
closeable = false,
|
||||||
|
showCheckedIcon = true,
|
||||||
|
itemWrap = true,
|
||||||
|
ScrollData,
|
||||||
|
isSelectAll,
|
||||||
|
setIsSelectAll,
|
||||||
...props
|
...props
|
||||||
}: SelectProps<T>) => {
|
}: SelectProps<T>) => {
|
||||||
const { t } = useTranslation();
|
|
||||||
const ref = useRef<HTMLButtonElement>(null);
|
const ref = useRef<HTMLButtonElement>(null);
|
||||||
|
const { t } = useTranslation();
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const menuItemStyles: MenuItemProps = {
|
const menuItemStyles: MenuItemProps = {
|
||||||
borderRadius: 'sm',
|
borderRadius: 'sm',
|
||||||
@ -63,6 +73,71 @@ const MultipleSelect = <T = any,>({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSelectAll = () => {
|
||||||
|
if (!setIsSelectAll) {
|
||||||
|
onSelect(value.length === list.length ? [] : list.map((item) => item.value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelectAll) {
|
||||||
|
onSelect([]);
|
||||||
|
}
|
||||||
|
setIsSelectAll((state) => !state);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ListRender = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{list.map((item, i) => (
|
||||||
|
<MenuItem
|
||||||
|
key={i}
|
||||||
|
{...menuItemStyles}
|
||||||
|
{...((isSelectAll && !value.includes(item.value)) ||
|
||||||
|
(!isSelectAll && value.includes(item.value))
|
||||||
|
? {
|
||||||
|
color: 'primary.600'
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
color: 'myGray.900'
|
||||||
|
})}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
onclickItem(item.value);
|
||||||
|
}}
|
||||||
|
whiteSpace={'pre-wrap'}
|
||||||
|
fontSize={'sm'}
|
||||||
|
gap={2}
|
||||||
|
>
|
||||||
|
{!showCheckedIcon && (
|
||||||
|
<Checkbox
|
||||||
|
isChecked={
|
||||||
|
(isSelectAll && !value.includes(item.value)) ||
|
||||||
|
(!isSelectAll && value.includes(item.value))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.icon && <MyAvatar src={item.icon} w={'1rem'} borderRadius={'0'} />}
|
||||||
|
<Box flex={'1 0 0'}>{item.label}</Box>
|
||||||
|
{showCheckedIcon && (
|
||||||
|
<Box w={'0.8rem'} lineHeight={1}>
|
||||||
|
{(isSelectAll && !value.includes(item.value)) ||
|
||||||
|
(!isSelectAll && value.includes(item.value) && (
|
||||||
|
<MyIcon name={'price/right'} w={'1rem'} />
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, [value, list, isSelectAll]);
|
||||||
|
|
||||||
|
const isAllSelected = useMemo(
|
||||||
|
() => (isSelectAll && value.length === 0) || (!isSelectAll && value.length === list.length),
|
||||||
|
[isSelectAll, value, list]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Menu
|
<Menu
|
||||||
@ -75,12 +150,10 @@ const MultipleSelect = <T = any,>({
|
|||||||
closeOnSelect={false}
|
closeOnSelect={false}
|
||||||
>
|
>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
as={Box}
|
as={Flex}
|
||||||
|
alignItems={'center'}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
width={width}
|
|
||||||
minH={'40px'}
|
|
||||||
px={3}
|
px={3}
|
||||||
py={2}
|
|
||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
border={'base'}
|
border={'base'}
|
||||||
userSelect={'none'}
|
userSelect={'none'}
|
||||||
@ -88,6 +161,9 @@ const MultipleSelect = <T = any,>({
|
|||||||
_active={{
|
_active={{
|
||||||
transform: 'none'
|
transform: 'none'
|
||||||
}}
|
}}
|
||||||
|
_hover={{
|
||||||
|
borderColor: 'primary.300'
|
||||||
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
{...(isOpen
|
{...(isOpen
|
||||||
? {
|
? {
|
||||||
@ -102,82 +178,94 @@ const MultipleSelect = <T = any,>({
|
|||||||
{placeholder}
|
{placeholder}
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Flex alignItems={'center'} gap={2} flexWrap={'wrap'}>
|
<Flex alignItems={'center'} gap={2}>
|
||||||
{value.map((item, i) => {
|
<Flex
|
||||||
const listItem = list.find((i) => i.value === item);
|
alignItems={'center'}
|
||||||
if (!listItem) return null;
|
gap={2}
|
||||||
|
flexWrap={itemWrap ? 'wrap' : 'nowrap'}
|
||||||
return (
|
overflow={'hidden'}
|
||||||
<MyTag className="tag-icon" key={i} colorSchema="blue" type={'borderFill'}>
|
flex={1}
|
||||||
{listItem.label}
|
>
|
||||||
{closeable && (
|
{isAllSelected ? (
|
||||||
<MyIcon
|
<Box fontSize={'mini'} color={'myGray.900'}>
|
||||||
name={'common/closeLight'}
|
{t('common:common.All')}
|
||||||
ml={1}
|
</Box>
|
||||||
w="0.8rem"
|
) : (
|
||||||
cursor={'pointer'}
|
(isSelectAll
|
||||||
_hover={{
|
? list.filter((item) => !value.includes(item.value))
|
||||||
color: 'red.500'
|
: list.filter((item) => value.includes(item.value))
|
||||||
}}
|
).map((item, i) => (
|
||||||
onClick={(e) => {
|
<MyTag
|
||||||
console.log(111);
|
className="tag-icon"
|
||||||
e.stopPropagation();
|
key={i}
|
||||||
onclickItem(item);
|
bg={'primary.100'}
|
||||||
}}
|
color={'primary.700'}
|
||||||
/>
|
type={'fill'}
|
||||||
)}
|
borderRadius={'full'}
|
||||||
</MyTag>
|
px={2}
|
||||||
);
|
py={0.5}
|
||||||
})}
|
flexShrink={0}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
{closeable && (
|
||||||
|
<MyIcon
|
||||||
|
name={'common/closeLight'}
|
||||||
|
ml={1}
|
||||||
|
w="0.8rem"
|
||||||
|
cursor={'pointer'}
|
||||||
|
_hover={{
|
||||||
|
color: 'red.500'
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onclickItem(item.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</MyTag>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
<MyIcon name={'core/chat/chevronDown'} color={'myGray.600'} w={4} h={4} />
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
|
|
||||||
<MenuList
|
<MenuList
|
||||||
className={props.className}
|
className={props.className}
|
||||||
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'}
|
|
||||||
px={'6px'}
|
px={'6px'}
|
||||||
py={'6px'}
|
py={'6px'}
|
||||||
border={'1px solid #fff'}
|
border={'1px solid #fff'}
|
||||||
boxShadow={
|
boxShadow={
|
||||||
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
'0px 4px 10px 0px rgba(19, 51, 107, 0.10), 0px 0px 1px 0px rgba(19, 51, 107, 0.10);'
|
||||||
}
|
}
|
||||||
zIndex={99}
|
zIndex={99}
|
||||||
maxH={'40vh'}
|
maxH={'40vh'}
|
||||||
overflowY={'auto'}
|
overflowY={'auto'}
|
||||||
>
|
>
|
||||||
{list.map((item, i) => (
|
<MenuItem
|
||||||
<MenuItem
|
{...menuItemStyles}
|
||||||
key={i}
|
color={isAllSelected ? 'primary.600' : 'myGray.900'}
|
||||||
{...menuItemStyles}
|
onClick={(e) => {
|
||||||
{...(value.includes(item.value)
|
e.stopPropagation();
|
||||||
? {
|
e.preventDefault();
|
||||||
color: 'primary.600'
|
onSelectAll();
|
||||||
}
|
}}
|
||||||
: {
|
whiteSpace={'pre-wrap'}
|
||||||
color: 'myGray.900'
|
fontSize={'sm'}
|
||||||
})}
|
gap={2}
|
||||||
onClick={() => onclickItem(item.value)}
|
mb={1}
|
||||||
whiteSpace={'pre-wrap'}
|
>
|
||||||
fontSize={'sm'}
|
{!showCheckedIcon && <Checkbox isChecked={isAllSelected} />}
|
||||||
gap={2}
|
<Box flex={'1 0 0'}>{t('common:common.All')}</Box>
|
||||||
>
|
{showCheckedIcon && (
|
||||||
{item.icon && <MyAvatar src={item.icon} w={'1rem'} borderRadius={'0'} />}
|
|
||||||
<Box flex={'1 0 0'}>{item.label}</Box>
|
|
||||||
<Box w={'0.8rem'} lineHeight={1}>
|
<Box w={'0.8rem'} lineHeight={1}>
|
||||||
{value.includes(item.value) && <MyIcon name={'price/right'} w={'1rem'} />}
|
{isAllSelected && <MyIcon name={'price/right'} w={'1rem'} />}
|
||||||
</Box>
|
</Box>
|
||||||
</MenuItem>
|
)}
|
||||||
))}
|
</MenuItem>
|
||||||
|
|
||||||
|
{ScrollData ? <ScrollData>{ListRender}</ScrollData> : ListRender}
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -66,7 +66,7 @@ const MyTag = ({ children, colorSchema = 'blue', type = 'fill', showDot, ...prop
|
|||||||
}, [colorSchema]);
|
}, [colorSchema]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Flex
|
||||||
display={'inline-flex'}
|
display={'inline-flex'}
|
||||||
px={2.5}
|
px={2.5}
|
||||||
lineHeight={1}
|
lineHeight={1}
|
||||||
@ -83,7 +83,7 @@ const MyTag = ({ children, colorSchema = 'blue', type = 'fill', showDot, ...prop
|
|||||||
>
|
>
|
||||||
{showDot && <Box w={1.5} h={1.5} borderRadius={'md'} bg={theme.color} mr={1.5}></Box>}
|
{showDot && <Box w={1.5} h={1.5} borderRadius={'md'} bg={theme.color} mr={1.5}></Box>}
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,14 @@
|
|||||||
"all": "all",
|
"all": "all",
|
||||||
"app_name": "Application name",
|
"app_name": "Application name",
|
||||||
"billing_module": "Deduction module",
|
"billing_module": "Deduction module",
|
||||||
|
"confirm_export": "A total of {{total}} pieces of data were filtered out. Are you sure to export?",
|
||||||
|
"current_filter_conditions": "Current filter conditions",
|
||||||
|
"dashboard": "Dashboard",
|
||||||
"details": "Details",
|
"details": "Details",
|
||||||
|
"dingtalk": "DingTalk",
|
||||||
"duration_seconds": "Duration (seconds)",
|
"duration_seconds": "Duration (seconds)",
|
||||||
|
"export_confirm": "Export confirmation",
|
||||||
|
"feishu": "Feishu",
|
||||||
"generation_time": "Generation time",
|
"generation_time": "Generation time",
|
||||||
"input_token_length": "input tokens",
|
"input_token_length": "input tokens",
|
||||||
"member": "member",
|
"member": "member",
|
||||||
@ -12,14 +18,21 @@
|
|||||||
"module_name": "module name",
|
"module_name": "module name",
|
||||||
"month": "moon",
|
"month": "moon",
|
||||||
"no_usage_records": "No usage record yet",
|
"no_usage_records": "No usage record yet",
|
||||||
|
"official_account": "Official Account",
|
||||||
"order_number": "Order number",
|
"order_number": "Order number",
|
||||||
"output_token_length": "output tokens",
|
"output_token_length": "output tokens",
|
||||||
|
"points": "Points",
|
||||||
"project_name": "Project name",
|
"project_name": "Project name",
|
||||||
|
"select_member_and_source_first": "Please select members and types first",
|
||||||
|
"share": "Share Link",
|
||||||
"source": "source",
|
"source": "source",
|
||||||
|
"start_export": "Export started",
|
||||||
"text_length": "text length",
|
"text_length": "text length",
|
||||||
"token_length": "token length",
|
"token_length": "token length",
|
||||||
"total_points": "AI points consumption",
|
"total_points": "AI points consumption",
|
||||||
"total_points_consumed": "AI points consumption",
|
"total_points_consumed": "AI points consumption",
|
||||||
"usage_detail": "Usage details",
|
"total_usage": "Total Usage",
|
||||||
"user_type": "type"
|
"usage_detail": "Details",
|
||||||
|
"user_type": "type",
|
||||||
|
"wecom": "WeCom"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,10 +112,5 @@
|
|||||||
"team.org.org": "Organization",
|
"team.org.org": "Organization",
|
||||||
"team.manage_collaborators": "Manage Collaborators",
|
"team.manage_collaborators": "Manage Collaborators",
|
||||||
"team.no_collaborators": "No Collaborators",
|
"team.no_collaborators": "No Collaborators",
|
||||||
"team.write_role_member": "",
|
"team.write_role_member": ""
|
||||||
"usage.feishu": "Feishu",
|
|
||||||
"usage.dingtalk": "DingTalk",
|
|
||||||
"usage.official_account": "Official Account",
|
|
||||||
"usage.share": "Share Link",
|
|
||||||
"usage.wecom": "WeCom"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,18 @@
|
|||||||
"all": "所有",
|
"all": "所有",
|
||||||
"app_name": "应用名",
|
"app_name": "应用名",
|
||||||
"billing_module": "扣费模块",
|
"billing_module": "扣费模块",
|
||||||
|
"confirm_export": "共筛选出 {{total}} 条数据,是否确认导出?",
|
||||||
|
"current_filter_conditions": "当前筛选条件:",
|
||||||
|
"dashboard": "仪表盘",
|
||||||
"details": "详情",
|
"details": "详情",
|
||||||
|
"dingtalk": "钉钉",
|
||||||
"duration_seconds": "时长(秒)",
|
"duration_seconds": "时长(秒)",
|
||||||
|
"every_day": "每天",
|
||||||
|
"every_month": "每月",
|
||||||
|
"every_week": "每周",
|
||||||
|
"export_confirm": "导出确认",
|
||||||
|
"export_success": "导出成功",
|
||||||
|
"feishu": "飞书",
|
||||||
"generation_time": "生成时间",
|
"generation_time": "生成时间",
|
||||||
"input_token_length": "输入 tokens",
|
"input_token_length": "输入 tokens",
|
||||||
"member": "成员",
|
"member": "成员",
|
||||||
@ -12,14 +22,21 @@
|
|||||||
"module_name": "模块名",
|
"module_name": "模块名",
|
||||||
"month": "月",
|
"month": "月",
|
||||||
"no_usage_records": "暂无使用记录",
|
"no_usage_records": "暂无使用记录",
|
||||||
|
"official_account": "公众号",
|
||||||
"order_number": "订单号",
|
"order_number": "订单号",
|
||||||
"output_token_length": "输出 tokens",
|
"output_token_length": "输出 tokens",
|
||||||
|
"points": "积分",
|
||||||
"project_name": "项目名",
|
"project_name": "项目名",
|
||||||
|
"select_member_and_source_first": "请先选中成员和类型",
|
||||||
|
"share": "分享链接",
|
||||||
"source": "来源",
|
"source": "来源",
|
||||||
|
"start_export": "已开始导出",
|
||||||
"text_length": "文本长度",
|
"text_length": "文本长度",
|
||||||
"token_length": "token 长度",
|
"token_length": "token 长度",
|
||||||
"total_points": "AI 积分消耗",
|
"total_points": "AI 积分消耗",
|
||||||
"total_points_consumed": "AI 积分消耗",
|
"total_points_consumed": "AI 积分消耗",
|
||||||
|
"total_usage": "总消耗",
|
||||||
"usage_detail": "使用详情",
|
"usage_detail": "使用详情",
|
||||||
"user_type": "类型"
|
"user_type": "类型",
|
||||||
|
"wecom": "企业微信"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,10 +112,5 @@
|
|||||||
"team.org.org": "部门",
|
"team.org.org": "部门",
|
||||||
"team.manage_collaborators": "管理协作者",
|
"team.manage_collaborators": "管理协作者",
|
||||||
"team.no_collaborators": "暂无协作者",
|
"team.no_collaborators": "暂无协作者",
|
||||||
"team.write_role_member": "可写权限",
|
"team.write_role_member": "可写权限"
|
||||||
"usage.feishu": "飞书",
|
|
||||||
"usage.dingtalk": "钉钉",
|
|
||||||
"usage.official_account": "公众号",
|
|
||||||
"usage.share": "分享链接",
|
|
||||||
"usage.wecom": "企业微信"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,14 @@
|
|||||||
"all": "所有",
|
"all": "所有",
|
||||||
"app_name": "應用程式名",
|
"app_name": "應用程式名",
|
||||||
"billing_module": "扣費模組",
|
"billing_module": "扣費模組",
|
||||||
|
"confirm_export": "共篩選出 {{total}} 條數據,是否確認導出?",
|
||||||
|
"current_filter_conditions": "當前篩選條件:",
|
||||||
|
"dashboard": "儀表板",
|
||||||
"details": "詳情",
|
"details": "詳情",
|
||||||
|
"dingtalk": "釘釘",
|
||||||
"duration_seconds": "時長(秒)",
|
"duration_seconds": "時長(秒)",
|
||||||
|
"export_confirm": "導出確認",
|
||||||
|
"feishu": "飛書",
|
||||||
"generation_time": "生成時間",
|
"generation_time": "生成時間",
|
||||||
"input_token_length": "輸入 tokens",
|
"input_token_length": "輸入 tokens",
|
||||||
"member": "成員",
|
"member": "成員",
|
||||||
@ -12,14 +18,21 @@
|
|||||||
"module_name": "模組名",
|
"module_name": "模組名",
|
||||||
"month": "月",
|
"month": "月",
|
||||||
"no_usage_records": "暫無使用紀錄",
|
"no_usage_records": "暫無使用紀錄",
|
||||||
|
"official_account": "公眾號",
|
||||||
"order_number": "訂單編號",
|
"order_number": "訂單編號",
|
||||||
"output_token_length": "輸出 tokens",
|
"output_token_length": "輸出 tokens",
|
||||||
|
"points": "積分",
|
||||||
"project_name": "專案名",
|
"project_name": "專案名",
|
||||||
|
"select_member_and_source_first": "請先選取成員和類型",
|
||||||
|
"share": "分享連結",
|
||||||
"source": "來源",
|
"source": "來源",
|
||||||
|
"start_export": "已開始匯出",
|
||||||
"text_length": "文字長度",
|
"text_length": "文字長度",
|
||||||
"token_length": "token 長度",
|
"token_length": "token 長度",
|
||||||
"total_points": "AI 積分消耗",
|
"total_points": "AI 積分消耗",
|
||||||
"total_points_consumed": "AI 積分消耗",
|
"total_points_consumed": "AI 積分消耗",
|
||||||
|
"total_usage": "總消耗",
|
||||||
"usage_detail": "使用詳情",
|
"usage_detail": "使用詳情",
|
||||||
"user_type": "類型"
|
"user_type": "類型",
|
||||||
|
"wecom": "企業微信"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,10 +112,5 @@
|
|||||||
"team.org.org": "組織",
|
"team.org.org": "組織",
|
||||||
"team.manage_collaborators": "管理協作者",
|
"team.manage_collaborators": "管理協作者",
|
||||||
"team.no_collaborators": "目前沒有協作者",
|
"team.no_collaborators": "目前沒有協作者",
|
||||||
"team.write_role_member": "可寫入權限",
|
"team.write_role_member": "可寫入權限"
|
||||||
"usage.feishu": "飛書",
|
|
||||||
"usage.dingtalk": "釘釘",
|
|
||||||
"usage.official_account": "公眾號",
|
|
||||||
"usage.share": "分享連結",
|
|
||||||
"usage.wecom": "企業微信"
|
|
||||||
}
|
}
|
||||||
|
|||||||
199
pnpm-lock.yaml
generated
199
pnpm-lock.yaml
generated
@ -22,7 +22,7 @@ importers:
|
|||||||
version: 13.3.0
|
version: 13.3.0
|
||||||
next-i18next:
|
next-i18next:
|
||||||
specifier: 15.3.0
|
specifier: 15.3.0
|
||||||
version: 15.3.0(i18next@23.11.5)(next@14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
version: 15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||||
prettier:
|
prettier:
|
||||||
specifier: 3.2.4
|
specifier: 3.2.4
|
||||||
version: 3.2.4
|
version: 3.2.4
|
||||||
@ -67,7 +67,7 @@ importers:
|
|||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
next:
|
next:
|
||||||
specifier: 14.2.5
|
specifier: 14.2.5
|
||||||
version: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||||
openai:
|
openai:
|
||||||
specifier: 4.61.0
|
specifier: 4.61.0
|
||||||
version: 4.61.0(encoding@0.1.13)
|
version: 4.61.0(encoding@0.1.13)
|
||||||
@ -210,7 +210,7 @@ importers:
|
|||||||
version: 1.4.5-lts.1
|
version: 1.4.5-lts.1
|
||||||
next:
|
next:
|
||||||
specifier: 14.2.5
|
specifier: 14.2.5
|
||||||
version: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||||
nextjs-cors:
|
nextjs-cors:
|
||||||
specifier: ^2.2.0
|
specifier: ^2.2.0
|
||||||
version: 2.2.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))
|
version: 2.2.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))
|
||||||
@ -295,7 +295,7 @@ importers:
|
|||||||
version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||||
'@chakra-ui/next-js':
|
'@chakra-ui/next-js':
|
||||||
specifier: 2.1.5
|
specifier: 2.1.5
|
||||||
version: 2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)
|
version: 2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)
|
||||||
'@chakra-ui/react':
|
'@chakra-ui/react':
|
||||||
specifier: 2.8.1
|
specifier: 2.8.1
|
||||||
version: 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@ -358,7 +358,7 @@ importers:
|
|||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
next-i18next:
|
next-i18next:
|
||||||
specifier: 15.3.0
|
specifier: 15.3.0
|
||||||
version: 15.3.0(i18next@23.11.5)(next@14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
version: 15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||||
papaparse:
|
papaparse:
|
||||||
specifier: ^5.4.1
|
specifier: ^5.4.1
|
||||||
version: 5.4.1
|
version: 5.4.1
|
||||||
@ -558,6 +558,9 @@ importers:
|
|||||||
reactflow:
|
reactflow:
|
||||||
specifier: ^11.7.4
|
specifier: ^11.7.4
|
||||||
version: 11.11.4(@types/react@18.3.1)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 11.11.4(@types/react@18.3.1)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
recharts:
|
||||||
|
specifier: ^2.15.0
|
||||||
|
version: 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
rehype-external-links:
|
rehype-external-links:
|
||||||
specifier: ^3.0.0
|
specifier: ^3.0.0
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
@ -3198,8 +3201,8 @@ packages:
|
|||||||
'@tanstack/react-query@4.36.1':
|
'@tanstack/react-query@4.36.1':
|
||||||
resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==}
|
resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
react: 18.3.1
|
||||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
react-dom: 18.3.1
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
react-dom:
|
react-dom:
|
||||||
@ -4330,6 +4333,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
clsx@2.1.1:
|
||||||
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
co@4.6.0:
|
co@4.6.0:
|
||||||
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
||||||
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
||||||
@ -4760,6 +4767,9 @@ packages:
|
|||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
decimal.js-light@2.5.1:
|
||||||
|
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
|
||||||
|
|
||||||
decode-named-character-reference@1.0.2:
|
decode-named-character-reference@1.0.2:
|
||||||
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
|
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
|
||||||
|
|
||||||
@ -4902,6 +4912,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
dom-helpers@5.2.1:
|
||||||
|
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||||
|
|
||||||
dom-serializer@1.4.1:
|
dom-serializer@1.4.1:
|
||||||
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
|
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
|
||||||
|
|
||||||
@ -5215,6 +5228,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
eventemitter3@4.0.7:
|
||||||
|
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||||
|
|
||||||
eventemitter3@5.0.1:
|
eventemitter3@5.0.1:
|
||||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||||
|
|
||||||
@ -5272,6 +5288,10 @@ packages:
|
|||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
fast-equals@5.2.0:
|
||||||
|
resolution: {integrity: sha512-3VpaQYf+CDFdRQfgsb+3vY7XaKjM35WCMoQTTE8h4S/eUkHzyJFOOA/gATYgoLejy4FBrEQD/sXe5Auk4cW/AQ==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
fast-fifo@1.3.2:
|
fast-fifo@1.3.2:
|
||||||
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
|
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
|
||||||
|
|
||||||
@ -7828,6 +7848,12 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
react-smooth@4.0.4:
|
||||||
|
resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
react-style-singleton@2.2.1:
|
react-style-singleton@2.2.1:
|
||||||
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -7849,6 +7875,12 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
|
||||||
|
react-transition-group@4.4.5:
|
||||||
|
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.6.0'
|
||||||
|
react-dom: '>=16.6.0'
|
||||||
|
|
||||||
react@18.3.1:
|
react@18.3.1:
|
||||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -7878,6 +7910,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
||||||
engines: {node: '>= 12.13.0'}
|
engines: {node: '>= 12.13.0'}
|
||||||
|
|
||||||
|
recharts-scale@0.4.5:
|
||||||
|
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
|
||||||
|
|
||||||
|
recharts@2.15.0:
|
||||||
|
resolution: {integrity: sha512-cIvMxDfpAmqAmVgc4yb7pgm/O1tmmkl/CjrvXuW+62/+7jj/iF9Ykm+hb/UJt42TREHMyd3gb+pkgoa2MxgDIw==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
redux@4.2.1:
|
redux@4.2.1:
|
||||||
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
||||||
|
|
||||||
@ -8978,6 +9020,9 @@ packages:
|
|||||||
vfile@6.0.2:
|
vfile@6.0.2:
|
||||||
resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==}
|
resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==}
|
||||||
|
|
||||||
|
victory-vendor@36.9.2:
|
||||||
|
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
|
||||||
|
|
||||||
vite-node@1.6.0:
|
vite-node@1.6.0:
|
||||||
resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==}
|
resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
@ -10492,6 +10537,14 @@ snapshots:
|
|||||||
next: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
next: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
|
||||||
|
'@chakra-ui/next-js@2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@chakra-ui/react': 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@emotion/cache': 11.11.0
|
||||||
|
'@emotion/react': 11.11.1(@types/react@18.3.1)(react@18.3.1)
|
||||||
|
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
'@chakra-ui/number-input@2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
'@chakra-ui/number-input@2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@chakra-ui/counter': 2.1.0(react@18.3.1)
|
'@chakra-ui/counter': 2.1.0(react@18.3.1)
|
||||||
@ -13231,7 +13284,7 @@ snapshots:
|
|||||||
|
|
||||||
axios@1.7.7:
|
axios@1.7.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.9(debug@4.3.7)
|
follow-redirects: 1.15.9
|
||||||
form-data: 4.0.1
|
form-data: 4.0.1
|
||||||
proxy-from-env: 1.1.0
|
proxy-from-env: 1.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -13637,6 +13690,8 @@ snapshots:
|
|||||||
|
|
||||||
clone@1.0.4: {}
|
clone@1.0.4: {}
|
||||||
|
|
||||||
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
co@4.6.0: {}
|
co@4.6.0: {}
|
||||||
|
|
||||||
collapse-white-space@1.0.6: {}
|
collapse-white-space@1.0.6: {}
|
||||||
@ -14078,6 +14133,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
|
decimal.js-light@2.5.1: {}
|
||||||
|
|
||||||
decode-named-character-reference@1.0.2:
|
decode-named-character-reference@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
character-entities: 2.0.2
|
character-entities: 2.0.2
|
||||||
@ -14234,6 +14291,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
|
dom-helpers@5.2.1:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.25.7
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
dom-serializer@1.4.1:
|
dom-serializer@1.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
@ -14731,6 +14793,8 @@ snapshots:
|
|||||||
|
|
||||||
event-target-shim@5.0.1: {}
|
event-target-shim@5.0.1: {}
|
||||||
|
|
||||||
|
eventemitter3@4.0.7: {}
|
||||||
|
|
||||||
eventemitter3@5.0.1: {}
|
eventemitter3@5.0.1: {}
|
||||||
|
|
||||||
events@3.3.0: {}
|
events@3.3.0: {}
|
||||||
@ -14837,6 +14901,8 @@ snapshots:
|
|||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fast-equals@5.2.0: {}
|
||||||
|
|
||||||
fast-fifo@1.3.2: {}
|
fast-fifo@1.3.2: {}
|
||||||
|
|
||||||
fast-glob@3.3.2:
|
fast-glob@3.3.2:
|
||||||
@ -15012,6 +15078,8 @@ snapshots:
|
|||||||
|
|
||||||
follow-redirects@1.15.6: {}
|
follow-redirects@1.15.6: {}
|
||||||
|
|
||||||
|
follow-redirects@1.15.9: {}
|
||||||
|
|
||||||
follow-redirects@1.15.9(debug@4.3.4):
|
follow-redirects@1.15.9(debug@4.3.4):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
@ -17359,6 +17427,18 @@ snapshots:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
react-i18next: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
react-i18next: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
|
next-i18next@15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.8
|
||||||
|
'@types/hoist-non-react-statics': 3.3.5
|
||||||
|
core-js: 3.37.1
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
i18next: 23.11.5
|
||||||
|
i18next-fs-backend: 2.3.1
|
||||||
|
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||||
|
react: 18.3.1
|
||||||
|
react-i18next: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
next@14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8):
|
next@14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/env': 14.2.5
|
'@next/env': 14.2.5
|
||||||
@ -17385,10 +17465,36 @@ snapshots:
|
|||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
|
|
||||||
|
next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8):
|
||||||
|
dependencies:
|
||||||
|
'@next/env': 14.2.5
|
||||||
|
'@swc/helpers': 0.5.5
|
||||||
|
busboy: 1.6.0
|
||||||
|
caniuse-lite: 1.0.30001669
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
postcss: 8.4.31
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
styled-jsx: 5.1.1(react@18.3.1)
|
||||||
|
optionalDependencies:
|
||||||
|
'@next/swc-darwin-arm64': 14.2.5
|
||||||
|
'@next/swc-darwin-x64': 14.2.5
|
||||||
|
'@next/swc-linux-arm64-gnu': 14.2.5
|
||||||
|
'@next/swc-linux-arm64-musl': 14.2.5
|
||||||
|
'@next/swc-linux-x64-gnu': 14.2.5
|
||||||
|
'@next/swc-linux-x64-musl': 14.2.5
|
||||||
|
'@next/swc-win32-arm64-msvc': 14.2.5
|
||||||
|
'@next/swc-win32-ia32-msvc': 14.2.5
|
||||||
|
'@next/swc-win32-x64-msvc': 14.2.5
|
||||||
|
sass: 1.77.8
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@babel/core'
|
||||||
|
- babel-plugin-macros
|
||||||
|
|
||||||
nextjs-cors@2.2.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)):
|
nextjs-cors@2.2.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)):
|
||||||
dependencies:
|
dependencies:
|
||||||
cors: 2.8.5
|
cors: 2.8.5
|
||||||
next: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||||
|
|
||||||
nextjs-node-loader@1.1.5(webpack@5.92.1):
|
nextjs-node-loader@1.1.5(webpack@5.92.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -18097,6 +18203,14 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 18.3.1
|
'@types/react': 18.3.1
|
||||||
|
|
||||||
|
react-smooth@4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
fast-equals: 5.2.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
react-style-singleton@2.2.1(@types/react@18.3.1)(react@18.3.1):
|
react-style-singleton@2.2.1(@types/react@18.3.1)(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
get-nonce: 1.0.1
|
get-nonce: 1.0.1
|
||||||
@ -18124,6 +18238,15 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/react'
|
- '@types/react'
|
||||||
|
|
||||||
|
react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.25.7
|
||||||
|
dom-helpers: 5.2.1
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
react@18.3.1:
|
react@18.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
@ -18172,6 +18295,23 @@ snapshots:
|
|||||||
|
|
||||||
real-require@0.2.0: {}
|
real-require@0.2.0: {}
|
||||||
|
|
||||||
|
recharts-scale@0.4.5:
|
||||||
|
dependencies:
|
||||||
|
decimal.js-light: 2.5.1
|
||||||
|
|
||||||
|
recharts@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
clsx: 2.1.1
|
||||||
|
eventemitter3: 4.0.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-is: 18.3.1
|
||||||
|
react-smooth: 4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
recharts-scale: 0.4.5
|
||||||
|
tiny-invariant: 1.3.3
|
||||||
|
victory-vendor: 36.9.2
|
||||||
|
|
||||||
redux@4.2.1:
|
redux@4.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.24.8
|
'@babel/runtime': 7.24.8
|
||||||
@ -18791,6 +18931,11 @@ snapshots:
|
|||||||
'@babel/core': 7.24.9
|
'@babel/core': 7.24.9
|
||||||
babel-plugin-macros: 3.1.0
|
babel-plugin-macros: 3.1.0
|
||||||
|
|
||||||
|
styled-jsx@5.1.1(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
client-only: 0.0.1
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
stylis@4.2.0: {}
|
stylis@4.2.0: {}
|
||||||
|
|
||||||
stylis@4.3.2: {}
|
stylis@4.3.2: {}
|
||||||
@ -18992,6 +19137,25 @@ snapshots:
|
|||||||
|
|
||||||
ts-dedent@2.2.0: {}
|
ts-dedent@2.2.0: {}
|
||||||
|
|
||||||
|
ts-jest@29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.3)))(typescript@5.5.3):
|
||||||
|
dependencies:
|
||||||
|
bs-logger: 0.2.6
|
||||||
|
ejs: 3.1.10
|
||||||
|
fast-json-stable-stringify: 2.1.0
|
||||||
|
jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.3))
|
||||||
|
jest-util: 29.7.0
|
||||||
|
json5: 2.2.3
|
||||||
|
lodash.memoize: 4.1.2
|
||||||
|
make-error: 1.3.6
|
||||||
|
semver: 7.6.3
|
||||||
|
typescript: 5.5.3
|
||||||
|
yargs-parser: 21.1.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@babel/core': 7.24.9
|
||||||
|
'@jest/transform': 29.7.0
|
||||||
|
'@jest/types': 29.6.3
|
||||||
|
babel-jest: 29.7.0(@babel/core@7.24.9)
|
||||||
|
|
||||||
ts-jest@29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.3)))(typescript@5.5.3):
|
ts-jest@29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.3)))(typescript@5.5.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
bs-logger: 0.2.6
|
bs-logger: 0.2.6
|
||||||
@ -19377,6 +19541,23 @@ snapshots:
|
|||||||
unist-util-stringify-position: 4.0.0
|
unist-util-stringify-position: 4.0.0
|
||||||
vfile-message: 4.0.2
|
vfile-message: 4.0.2
|
||||||
|
|
||||||
|
victory-vendor@36.9.2:
|
||||||
|
dependencies:
|
||||||
|
'@types/d3-array': 3.2.1
|
||||||
|
'@types/d3-ease': 3.0.2
|
||||||
|
'@types/d3-interpolate': 3.0.4
|
||||||
|
'@types/d3-scale': 4.0.8
|
||||||
|
'@types/d3-shape': 3.1.6
|
||||||
|
'@types/d3-time': 3.0.3
|
||||||
|
'@types/d3-timer': 3.0.2
|
||||||
|
d3-array: 3.2.4
|
||||||
|
d3-ease: 3.0.1
|
||||||
|
d3-interpolate: 3.0.1
|
||||||
|
d3-scale: 4.0.2
|
||||||
|
d3-shape: 3.2.0
|
||||||
|
d3-time: 3.1.0
|
||||||
|
d3-timer: 3.0.1
|
||||||
|
|
||||||
vite-node@1.6.0(@types/node@22.7.8)(sass@1.77.8)(terser@5.31.3):
|
vite-node@1.6.0(@types/node@22.7.8)(sass@1.77.8)(terser@5.31.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
|
|||||||
@ -21,8 +21,8 @@
|
|||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@fastgpt/plugins": "workspace:*",
|
"@fastgpt/plugins": "workspace:*",
|
||||||
"@fastgpt/service": "workspace:*",
|
"@fastgpt/service": "workspace:*",
|
||||||
"@fastgpt/web": "workspace:*",
|
|
||||||
"@fastgpt/templates": "workspace:*",
|
"@fastgpt/templates": "workspace:*",
|
||||||
|
"@fastgpt/web": "workspace:*",
|
||||||
"@fortaine/fetch-event-source": "^3.0.6",
|
"@fortaine/fetch-event-source": "^3.0.6",
|
||||||
"@node-rs/jieba": "1.10.0",
|
"@node-rs/jieba": "1.10.0",
|
||||||
"@tanstack/react-query": "^4.24.10",
|
"@tanstack/react-query": "^4.24.10",
|
||||||
@ -60,6 +60,7 @@
|
|||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"react-textarea-autosize": "^8.5.4",
|
"react-textarea-autosize": "^8.5.4",
|
||||||
"reactflow": "^11.7.4",
|
"reactflow": "^11.7.4",
|
||||||
|
"recharts": "^2.15.0",
|
||||||
"rehype-external-links": "^3.0.0",
|
"rehype-external-links": "^3.0.0",
|
||||||
"rehype-katex": "^7.0.0",
|
"rehype-katex": "^7.0.0",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import MySelect from '@fastgpt/web/components/common/MySelect';
|
|||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||||
import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
||||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||||
|
|
||||||
const BillTable = () => {
|
const BillTable = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@ -177,6 +178,7 @@ export default BillTable;
|
|||||||
|
|
||||||
function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: () => void }) {
|
function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: () => void }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MyModal
|
<MyModal
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
import { downloadFetch } from '@/web/common/system/utils';
|
||||||
|
import { Button, Flex, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||||
|
import { formatTime2YMD } from '@fastgpt/global/common/string/time';
|
||||||
|
import { UsageSourceEnum, UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||||
|
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
|
export type ExportModalParams = {
|
||||||
|
dateStart: Date;
|
||||||
|
dateEnd: Date;
|
||||||
|
sources: UsageSourceEnum[];
|
||||||
|
teamMemberIds: string[];
|
||||||
|
teamMemberNames: string[];
|
||||||
|
isSelectAllTmb: boolean;
|
||||||
|
projectName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExportModal = ({
|
||||||
|
onClose,
|
||||||
|
params,
|
||||||
|
memberTotal,
|
||||||
|
total
|
||||||
|
}: {
|
||||||
|
onClose: () => void;
|
||||||
|
params: ExportModalParams;
|
||||||
|
memberTotal: number;
|
||||||
|
total: number;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
teamMemberIds,
|
||||||
|
teamMemberNames,
|
||||||
|
isSelectAllTmb,
|
||||||
|
sources,
|
||||||
|
dateStart,
|
||||||
|
dateEnd,
|
||||||
|
projectName
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const { runAsync: exportUsage, loading } = useRequest2(
|
||||||
|
async () => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
searchParams.set('dateStart', dateStart.toISOString());
|
||||||
|
searchParams.set('dateEnd', dateEnd.toISOString());
|
||||||
|
sources.forEach((source) => searchParams.append('sources', source.toString()));
|
||||||
|
teamMemberIds.forEach((tmbId) => searchParams.append('teamMemberIds', tmbId));
|
||||||
|
searchParams.set('isSelectAllTmb', isSelectAllTmb.toString());
|
||||||
|
searchParams.set('projectName', projectName);
|
||||||
|
|
||||||
|
await downloadFetch({
|
||||||
|
url: `/api/proApi/support/wallet/usage/exportUsage?${searchParams}`,
|
||||||
|
filename: `usage.csv`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
successToast: t('account_usage:start_export')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyModal title={t('account_usage:export_confirm')} iconSrc="export" iconColor={'primary.600'}>
|
||||||
|
<ModalBody>
|
||||||
|
<Flex mb={4}>{t('account_usage:current_filter_conditions')}</Flex>
|
||||||
|
<Flex>
|
||||||
|
{`${t('common:user.Time')}: ${formatTime2YMD(dateStart)} ~ ${formatTime2YMD(dateEnd)}`}
|
||||||
|
</Flex>
|
||||||
|
<Flex>{`${t('common:user.team.Member')}(${memberTotal}): ${teamMemberNames.join(', ')}`}</Flex>
|
||||||
|
<Flex>
|
||||||
|
{`${t('common:user.type')}: ${sources.map((item) => t(UsageSourceMap[item].label as any)).join(', ')}`}
|
||||||
|
</Flex>
|
||||||
|
<Flex>{`${t('common:user.Application Name')}: ${projectName}`}</Flex>
|
||||||
|
<Flex mt={4}>{t('account_usage:confirm_export', { total })}</Flex>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter gap={2}>
|
||||||
|
<Button variant={'whiteBase'} onClick={onClose}>
|
||||||
|
{t('common:common.Cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={exportUsage} isLoading={loading}>
|
||||||
|
{t('common:Export')}
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</MyModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExportModal;
|
||||||
164
projects/app/src/pages/account/usage/components/UsageForm.tsx
Normal file
164
projects/app/src/pages/account/usage/components/UsageForm.tsx
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import { getTotalPoints } from '@/web/support/wallet/usage/api';
|
||||||
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
|
import { formatNumber } from '@fastgpt/global/common/math/tools';
|
||||||
|
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
|
import { DateRangeType } from '@fastgpt/web/components/common/DateRangePicker';
|
||||||
|
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||||
|
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||||
|
import { addDays } from 'date-fns';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import React, { useEffect, useMemo } from 'react';
|
||||||
|
import {
|
||||||
|
ResponsiveContainer,
|
||||||
|
LineChart,
|
||||||
|
Line,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
CartesianGrid,
|
||||||
|
Tooltip,
|
||||||
|
TooltipProps
|
||||||
|
} from 'recharts';
|
||||||
|
import { NameType, ValueType } from 'recharts/types/component/DefaultTooltipContent';
|
||||||
|
import { UnitType } from '../index';
|
||||||
|
|
||||||
|
export type usageFormType = {
|
||||||
|
date: string;
|
||||||
|
totalPoints: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomTooltip = ({ active, payload }: TooltipProps<ValueType, NameType>) => {
|
||||||
|
const data = payload?.[0]?.payload as usageFormType;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
if (active && data) {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
bg={'white'}
|
||||||
|
p={3}
|
||||||
|
borderRadius={'md'}
|
||||||
|
border={'0.5px solid'}
|
||||||
|
borderColor={'myGray.200'}
|
||||||
|
boxShadow={
|
||||||
|
'0px 24px 48px -12px rgba(19, 51, 107, 0.20), 0px 0px 1px 0px rgba(19, 51, 107, 0.20)'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box fontSize={'mini'} color={'myGray.600'} mb={3}>
|
||||||
|
{data.date}
|
||||||
|
</Box>
|
||||||
|
<Box fontSize={'14px'} color={'myGray.900'} fontWeight={'medium'}>
|
||||||
|
{`${formatNumber(data.totalPoints)} ${t('account_usage:points')}`}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const UsageForm = ({
|
||||||
|
dateRange,
|
||||||
|
selectTmbIds,
|
||||||
|
usageSources,
|
||||||
|
unit,
|
||||||
|
Tabs,
|
||||||
|
Selectors
|
||||||
|
}: {
|
||||||
|
dateRange: DateRangeType;
|
||||||
|
selectTmbIds: string[];
|
||||||
|
usageSources: UsageSourceEnum[];
|
||||||
|
unit: UnitType;
|
||||||
|
Tabs: React.ReactNode;
|
||||||
|
Selectors: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
run: getTotalPointsData,
|
||||||
|
data: totalPoints,
|
||||||
|
loading: totalPointsLoading
|
||||||
|
} = useRequest2(
|
||||||
|
() =>
|
||||||
|
getTotalPoints({
|
||||||
|
dateStart: dateRange.from || new Date(),
|
||||||
|
dateEnd: addDays(dateRange.to || new Date(), 1),
|
||||||
|
teamMemberIds: selectTmbIds,
|
||||||
|
sources: usageSources,
|
||||||
|
unit
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
manual: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const totalUsage = useMemo(() => {
|
||||||
|
return totalPoints?.reduce((acc, curr) => acc + curr.totalPoints, 0);
|
||||||
|
}, [totalPoints]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectTmbIds.length === 0 || usageSources.length === 0) return;
|
||||||
|
getTotalPointsData();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [usageSources, selectTmbIds.length, dateRange, unit]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box>{Tabs}</Box>
|
||||||
|
<Box>{Selectors}</Box>
|
||||||
|
<MyBox isLoading={totalPointsLoading}>
|
||||||
|
<Flex fontSize={'20px'} fontWeight={'medium'} my={6}>
|
||||||
|
<Box color={'black'}>{`${t('account_usage:total_usage')}:`}</Box>
|
||||||
|
<Box color={'primary.600'} ml={2}>
|
||||||
|
{`${formatNumber(totalUsage || 0)} ${t('account_usage:points')}`}
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
<Flex mb={4} fontSize={'mini'} color={'myGray.500'} fontWeight={'medium'}>
|
||||||
|
{t('account_usage:points')}
|
||||||
|
</Flex>
|
||||||
|
<ResponsiveContainer width="100%" height={424}>
|
||||||
|
<LineChart data={totalPoints} margin={{ top: 10, right: 30, left: -12, bottom: 0 }}>
|
||||||
|
<XAxis
|
||||||
|
dataKey="date"
|
||||||
|
padding={{ left: 40, right: 40 }}
|
||||||
|
tickMargin={10}
|
||||||
|
tickSize={0}
|
||||||
|
tick={{ fontSize: '12px', color: '#667085', fontWeight: '500' }}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
axisLine={false}
|
||||||
|
tickSize={0}
|
||||||
|
tickMargin={12}
|
||||||
|
tick={{ fontSize: '12px', color: '#667085', fontWeight: '500' }}
|
||||||
|
/>
|
||||||
|
<CartesianGrid
|
||||||
|
strokeDasharray="3 3"
|
||||||
|
verticalCoordinatesGenerator={(props) => {
|
||||||
|
const { width } = props;
|
||||||
|
if (width < 500) {
|
||||||
|
return [width * 0.2, width * 0.4, width * 0.6, width * 0.8];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
width * 0.125,
|
||||||
|
width * 0.25,
|
||||||
|
width * 0.375,
|
||||||
|
width * 0.5,
|
||||||
|
width * 0.625,
|
||||||
|
width * 0.75,
|
||||||
|
width * 0.875
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip content={<CustomTooltip />} />
|
||||||
|
<Line
|
||||||
|
type="monotone"
|
||||||
|
dataKey="totalPoints"
|
||||||
|
stroke="#5E8FFF"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
dot={false}
|
||||||
|
/>
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</MyBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(UsageForm);
|
||||||
188
projects/app/src/pages/account/usage/components/UsageTable.tsx
Normal file
188
projects/app/src/pages/account/usage/components/UsageTable.tsx
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
Table,
|
||||||
|
TableContainer,
|
||||||
|
Tbody,
|
||||||
|
Td,
|
||||||
|
Th,
|
||||||
|
Thead,
|
||||||
|
Tr
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { formatNumber } from '@fastgpt/global/common/math/tools';
|
||||||
|
import { UsageSourceEnum, UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
|
import { UsageItemType } from '@fastgpt/global/support/wallet/usage/type';
|
||||||
|
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||||
|
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||||
|
import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
||||||
|
import { getUserUsages } from '@/web/support/wallet/usage/api';
|
||||||
|
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||||
|
import { DateRangeType } from '@fastgpt/web/components/common/DateRangePicker';
|
||||||
|
import { addDays } from 'date-fns';
|
||||||
|
import { ExportModalParams } from './ExportModal';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
import { TeamMemberItemType } from '@fastgpt/global/support/user/team/type';
|
||||||
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
|
|
||||||
|
const UsageDetail = dynamic(() => import('./UsageDetail'));
|
||||||
|
const ExportModal = dynamic(() => import('./ExportModal'));
|
||||||
|
|
||||||
|
const UsageTableList = ({
|
||||||
|
dateRange,
|
||||||
|
selectTmbIds,
|
||||||
|
usageSources,
|
||||||
|
projectName,
|
||||||
|
members,
|
||||||
|
memberTotal,
|
||||||
|
isSelectAllTmb,
|
||||||
|
Tabs,
|
||||||
|
Selectors
|
||||||
|
}: {
|
||||||
|
dateRange: DateRangeType;
|
||||||
|
selectTmbIds: string[];
|
||||||
|
usageSources: UsageSourceEnum[];
|
||||||
|
projectName: string;
|
||||||
|
members: TeamMemberItemType[];
|
||||||
|
memberTotal: number;
|
||||||
|
isSelectAllTmb: boolean;
|
||||||
|
Tabs: React.ReactNode;
|
||||||
|
Selectors: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { isPc } = useSystem();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: usages,
|
||||||
|
isLoading,
|
||||||
|
Pagination,
|
||||||
|
getData,
|
||||||
|
total
|
||||||
|
} = usePagination(getUserUsages, {
|
||||||
|
pageSize: isPc ? 20 : 10,
|
||||||
|
params: {
|
||||||
|
dateStart: dateRange.from || new Date(),
|
||||||
|
dateEnd: addDays(dateRange.to || new Date(), 1),
|
||||||
|
sources: usageSources,
|
||||||
|
teamMemberIds: selectTmbIds,
|
||||||
|
isSelectAllTmb,
|
||||||
|
projectName
|
||||||
|
},
|
||||||
|
defaultRequest: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const [usageDetail, setUsageDetail] = useState<UsageItemType>();
|
||||||
|
const [currentParams, setCurrentParams] = useState<ExportModalParams | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if ((!isSelectAllTmb && selectTmbIds.length === 0) || usageSources.length === 0) return;
|
||||||
|
getData(1);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [usageSources, selectTmbIds.length, projectName, dateRange, isSelectAllTmb]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box>{Tabs}</Box>
|
||||||
|
<Flex flexDir={['column', 'row']} w={'100%'} alignItems={['flex-end', 'center']}>
|
||||||
|
<Box>{Selectors}</Box>
|
||||||
|
<Box flex={'1'} />
|
||||||
|
<Button
|
||||||
|
size={'md'}
|
||||||
|
onClick={() => {
|
||||||
|
if ((selectTmbIds.length === 0 && !isSelectAllTmb) || usageSources.length === 0) {
|
||||||
|
return toast({
|
||||||
|
status: 'warning',
|
||||||
|
title: t('account_usage:select_member_and_source_first')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentParams({
|
||||||
|
dateStart: dateRange.from || new Date(),
|
||||||
|
dateEnd: addDays(dateRange.to || new Date(), 1),
|
||||||
|
sources: usageSources,
|
||||||
|
teamMemberIds: selectTmbIds,
|
||||||
|
teamMemberNames: members
|
||||||
|
.filter((item) =>
|
||||||
|
isSelectAllTmb
|
||||||
|
? !selectTmbIds.includes(item.tmbId)
|
||||||
|
: selectTmbIds.includes(item.tmbId)
|
||||||
|
)
|
||||||
|
.map((item) => item.memberName),
|
||||||
|
isSelectAllTmb,
|
||||||
|
projectName
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('common:Export')}
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
<MyBox position={'relative'} overflowY={'auto'} mt={3} flex={1} isLoading={isLoading}>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<Thead>
|
||||||
|
<Tr>
|
||||||
|
<Th>{t('common:user.Time')}</Th>
|
||||||
|
<Th>{t('account_usage:member')}</Th>
|
||||||
|
<Th>{t('account_usage:user_type')}</Th>
|
||||||
|
<Th>{t('account_usage:project_name')}</Th>
|
||||||
|
<Th>{t('account_usage:total_points')}</Th>
|
||||||
|
<Th></Th>
|
||||||
|
</Tr>
|
||||||
|
</Thead>
|
||||||
|
<Tbody fontSize={'sm'}>
|
||||||
|
{usages.map((item) => (
|
||||||
|
<Tr key={item.id}>
|
||||||
|
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
||||||
|
<Td>
|
||||||
|
<Flex alignItems={'center'} color={'myGray.500'}>
|
||||||
|
<Avatar src={item.sourceMember.avatar} w={'20px'} mr={1} rounded={'full'} />
|
||||||
|
{item.sourceMember.name}
|
||||||
|
</Flex>
|
||||||
|
</Td>
|
||||||
|
<Td>{t(UsageSourceMap[item.source]?.label as any) || '-'}</Td>
|
||||||
|
<Td>{t(item.appName as any) || '-'}</Td>
|
||||||
|
<Td>{formatNumber(item.totalPoints) || 0}</Td>
|
||||||
|
<Td>
|
||||||
|
<Button
|
||||||
|
size={'sm'}
|
||||||
|
variant={'whitePrimary'}
|
||||||
|
onClick={() => setUsageDetail(item)}
|
||||||
|
>
|
||||||
|
{t('account_usage:details')}
|
||||||
|
</Button>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</Tbody>
|
||||||
|
</Table>
|
||||||
|
{!isLoading && usages.length === 0 && (
|
||||||
|
<EmptyTip text={t('account_usage:no_usage_records')}></EmptyTip>
|
||||||
|
)}
|
||||||
|
</TableContainer>
|
||||||
|
</MyBox>
|
||||||
|
<Flex mt={3} justifyContent={'center'}>
|
||||||
|
<Pagination />
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{!!usageDetail && (
|
||||||
|
<UsageDetail usage={usageDetail} onClose={() => setUsageDetail(undefined)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!!currentParams && (
|
||||||
|
<ExportModal
|
||||||
|
onClose={() => setCurrentParams(null)}
|
||||||
|
params={currentParams}
|
||||||
|
memberTotal={isSelectAllTmb ? memberTotal - selectTmbIds.length : selectTmbIds.length}
|
||||||
|
total={total}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UsageTableList;
|
||||||
@ -1,76 +1,66 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import {
|
import { Flex, Box } from '@chakra-ui/react';
|
||||||
Table,
|
|
||||||
Thead,
|
|
||||||
Tbody,
|
|
||||||
Tr,
|
|
||||||
Th,
|
|
||||||
Td,
|
|
||||||
TableContainer,
|
|
||||||
Flex,
|
|
||||||
Box,
|
|
||||||
Button
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { UsageSourceEnum, UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
|
import { UsageSourceEnum, UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
import { getUserUsages } from '@/web/support/wallet/usage/api';
|
|
||||||
import type { UsageItemType } from '@fastgpt/global/support/wallet/usage/type';
|
|
||||||
import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
|
||||||
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import DateRangePicker, {
|
import DateRangePicker, {
|
||||||
type DateRangeType
|
type DateRangeType
|
||||||
} from '@fastgpt/web/components/common/DateRangePicker';
|
} from '@fastgpt/web/components/common/DateRangePicker';
|
||||||
import { addDays } from 'date-fns';
|
import { addDays, startOfMonth, startOfWeek } from 'date-fns';
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
|
||||||
import { formatNumber } from '@fastgpt/global/common/math/tools';
|
|
||||||
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
|
||||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
|
||||||
import AccountContainer from '../components/AccountContainer';
|
import AccountContainer from '../components/AccountContainer';
|
||||||
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
|
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
|
||||||
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
|
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
|
||||||
import { getTeamMembers } from '@/web/support/user/team/api';
|
import { getTeamMembers } from '@/web/support/user/team/api';
|
||||||
|
import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs';
|
||||||
|
import MultipleSelect from '@fastgpt/web/components/common/MySelect/MultipleSelect';
|
||||||
|
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||||
|
import UsageForm from './components/UsageForm';
|
||||||
|
import UsageTableList from './components/UsageTable';
|
||||||
|
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
const UsageDetail = dynamic(() => import('./UsageDetail'));
|
export enum UsageTabEnum {
|
||||||
|
detail = 'detail',
|
||||||
|
dashboard = 'dashboard'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UnitType = 'day' | 'week' | 'month';
|
||||||
|
|
||||||
const UsageTable = () => {
|
const UsageTable = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Loading } = useLoading();
|
const { userInfo } = useUserStore();
|
||||||
|
const router = useRouter();
|
||||||
|
const { usageTab = UsageTabEnum.detail } = router.query as { usageTab: `${UsageTabEnum}` };
|
||||||
|
const { data: members, ScrollData, total: memberTotal } = useScrollPagination(getTeamMembers, {});
|
||||||
const [dateRange, setDateRange] = useState<DateRangeType>({
|
const [dateRange, setDateRange] = useState<DateRangeType>({
|
||||||
from: addDays(new Date(), -7),
|
from: addDays(new Date(), -7),
|
||||||
to: new Date()
|
to: new Date()
|
||||||
});
|
});
|
||||||
const [usageSource, setUsageSource] = useState<UsageSourceEnum | ''>('');
|
const [selectTmbIds, setSelectTmbIds] = useState<string[]>([]);
|
||||||
const { isPc } = useSystem();
|
const [usageSources, setUsageSources] = useState<UsageSourceEnum[]>(
|
||||||
const { userInfo } = useUserStore();
|
Object.values(UsageSourceEnum)
|
||||||
const [usageDetail, setUsageDetail] = useState<UsageItemType>();
|
);
|
||||||
|
const [isSelectAllTmb, setIsSelectAllTmb] = useState<boolean>(true);
|
||||||
|
const [unit, setUnit] = useState<UnitType>('day');
|
||||||
|
const [projectName, setProjectName] = useState<string>('');
|
||||||
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
|
||||||
const sourceList = useMemo(
|
const sourceList = useMemo(
|
||||||
() =>
|
() =>
|
||||||
[
|
Object.entries(UsageSourceMap).map(([key, value]) => ({
|
||||||
{ label: t('account_usage:all'), value: '' },
|
label: t(value.label as any),
|
||||||
...Object.entries(UsageSourceMap).map(([key, value]) => ({
|
value: key
|
||||||
label: t(value.label as any),
|
})),
|
||||||
value: key
|
|
||||||
}))
|
|
||||||
] as {
|
|
||||||
label: never;
|
|
||||||
value: UsageSourceEnum | '';
|
|
||||||
}[],
|
|
||||||
[t]
|
[t]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [selectTmbId, setSelectTmbId] = useState(userInfo?.team?.tmbId);
|
|
||||||
const { data: members, ScrollData } = useScrollPagination(getTeamMembers, {});
|
|
||||||
const tmbList = useMemo(
|
const tmbList = useMemo(
|
||||||
() =>
|
() =>
|
||||||
members.map((item) => ({
|
members.map((item) => ({
|
||||||
label: (
|
label: (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'} color={'myGray.500'}>
|
||||||
<Avatar src={item.avatar} w={'16px'} mr={1} />
|
<Avatar src={item.avatar} w={'20px'} mr={1} rounded={'full'} />
|
||||||
{item.memberName}
|
{item.memberName}
|
||||||
</Flex>
|
</Flex>
|
||||||
),
|
),
|
||||||
@ -79,122 +69,198 @@ const UsageTable = () => {
|
|||||||
[members]
|
[members]
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const Tabs = useMemo(
|
||||||
data: usages,
|
() => (
|
||||||
isLoading,
|
<FillRowTabs
|
||||||
Pagination,
|
list={[
|
||||||
getData
|
{ label: t('account_usage:usage_detail'), value: 'detail' },
|
||||||
} = usePagination(getUserUsages, {
|
{ label: t('account_usage:dashboard'), value: 'dashboard' }
|
||||||
pageSize: isPc ? 20 : 10,
|
]}
|
||||||
params: {
|
px={'1rem'}
|
||||||
dateStart: dateRange.from || new Date(),
|
value={usageTab}
|
||||||
dateEnd: addDays(dateRange.to || new Date(), 1),
|
onChange={(e) => {
|
||||||
source: usageSource as UsageSourceEnum,
|
router.replace({
|
||||||
teamMemberId: selectTmbId ?? ''
|
query: {
|
||||||
},
|
...router.query,
|
||||||
defaultRequest: false
|
usageTab: e
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[router, t, usageTab]
|
||||||
|
);
|
||||||
|
|
||||||
|
const Selectors = useMemo(
|
||||||
|
() => (
|
||||||
|
<Flex mt={4}>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box fontSize={'mini'} fontWeight={'medium'} color={'myGray.900'} mr={4}>
|
||||||
|
{t('common:user.Time')}
|
||||||
|
</Box>
|
||||||
|
<DateRangePicker
|
||||||
|
defaultDate={dateRange}
|
||||||
|
dateRange={dateRange}
|
||||||
|
position="bottom"
|
||||||
|
onChange={setDateRange}
|
||||||
|
/>
|
||||||
|
{usageTab === UsageTabEnum.dashboard && (
|
||||||
|
<MySelect
|
||||||
|
bg={'myGray.50'}
|
||||||
|
minH={'32px'}
|
||||||
|
height={'32px'}
|
||||||
|
fontSize={'mini'}
|
||||||
|
ml={1}
|
||||||
|
list={[
|
||||||
|
{ label: t('account_usage:every_day'), value: 'day' },
|
||||||
|
{ label: t('account_usage:every_week'), value: 'week' },
|
||||||
|
{ label: t('account_usage:every_month'), value: 'month' }
|
||||||
|
]}
|
||||||
|
value={unit}
|
||||||
|
onchange={(val) => {
|
||||||
|
if (!dateRange.from) return dateRange;
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case 'week':
|
||||||
|
setDateRange({
|
||||||
|
from: startOfWeek(dateRange.from, { weekStartsOn: 1 }),
|
||||||
|
to: dateRange.to
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'month':
|
||||||
|
setDateRange({
|
||||||
|
from: startOfMonth(dateRange.from),
|
||||||
|
to: dateRange.to
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUnit(val as 'day' | 'week' | 'month');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
{tmbList.length > 1 && userInfo?.team?.permission.hasManagePer && (
|
||||||
|
<Flex alignItems={'center'} ml={6}>
|
||||||
|
<Box fontSize={'mini'} fontWeight={'medium'} color={'myGray.900'} mr={4}>
|
||||||
|
{t('account_usage:member')}
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<MultipleSelect<string>
|
||||||
|
list={tmbList}
|
||||||
|
value={selectTmbIds}
|
||||||
|
onSelect={(val) => {
|
||||||
|
setSelectTmbIds(val as string[]);
|
||||||
|
}}
|
||||||
|
itemWrap={false}
|
||||||
|
height={'32px'}
|
||||||
|
bg={'myGray.50'}
|
||||||
|
w={'160px'}
|
||||||
|
showCheckedIcon={false}
|
||||||
|
ScrollData={ScrollData}
|
||||||
|
isSelectAll={isSelectAllTmb}
|
||||||
|
setIsSelectAll={setIsSelectAllTmb}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
<Flex alignItems={'center'} ml={6}>
|
||||||
|
<Box fontSize={'mini'} fontWeight={'medium'} color={'myGray.900'} mr={4}>
|
||||||
|
{t('common:user.type')}
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<MultipleSelect<string>
|
||||||
|
list={sourceList}
|
||||||
|
value={usageSources}
|
||||||
|
onSelect={(val) => setUsageSources(val as UsageSourceEnum[])}
|
||||||
|
itemWrap={false}
|
||||||
|
height={'32px'}
|
||||||
|
bg={'myGray.50'}
|
||||||
|
w={'160px'}
|
||||||
|
showCheckedIcon={false}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
{usageTab === UsageTabEnum.detail && (
|
||||||
|
<Flex alignItems={'center'} ml={6}>
|
||||||
|
<Box
|
||||||
|
fontSize={'mini'}
|
||||||
|
fontWeight={'medium'}
|
||||||
|
color={'myGray.900'}
|
||||||
|
mr={4}
|
||||||
|
whiteSpace={'nowrap'}
|
||||||
|
>
|
||||||
|
{t('common:user.Application Name')}
|
||||||
|
</Box>
|
||||||
|
<SearchInput
|
||||||
|
placeholder={t('common:user.Application Name')}
|
||||||
|
w={'160px'}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
dateRange,
|
||||||
|
selectTmbIds,
|
||||||
|
sourceList,
|
||||||
|
t,
|
||||||
|
tmbList,
|
||||||
|
unit,
|
||||||
|
usageSources,
|
||||||
|
usageTab,
|
||||||
|
inputValue,
|
||||||
|
isSelectAllTmb
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getData(1);
|
const timer = setTimeout(() => {
|
||||||
}, [usageSource, selectTmbId]);
|
setProjectName(inputValue);
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [inputValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AccountContainer>
|
<AccountContainer>
|
||||||
<Flex flexDirection={'column'} py={[0, 5]} h={'100%'} position={'relative'}>
|
<Box
|
||||||
<Flex
|
px={[3, 8]}
|
||||||
flexDir={['column', 'row']}
|
pt={[0, 8]}
|
||||||
gap={2}
|
pb={[0, 4]}
|
||||||
w={'100%'}
|
h={'full'}
|
||||||
px={[3, 8]}
|
overflow={'hidden'}
|
||||||
alignItems={['flex-end', 'center']}
|
display={'flex'}
|
||||||
>
|
flexDirection={'column'}
|
||||||
{tmbList.length > 1 && userInfo?.team?.permission.hasManagePer && (
|
>
|
||||||
<Flex alignItems={'center'}>
|
{usageTab === UsageTabEnum.detail && (
|
||||||
<Box mr={2} flexShrink={0}>
|
<UsageTableList
|
||||||
{t('account_usage:member')}
|
dateRange={dateRange}
|
||||||
</Box>
|
selectTmbIds={selectTmbIds}
|
||||||
<MySelect
|
usageSources={usageSources}
|
||||||
size={'sm'}
|
projectName={projectName}
|
||||||
minW={'100px'}
|
members={members}
|
||||||
ScrollData={ScrollData}
|
memberTotal={memberTotal}
|
||||||
list={tmbList}
|
isSelectAllTmb={isSelectAllTmb}
|
||||||
value={selectTmbId}
|
Tabs={Tabs}
|
||||||
onchange={setSelectTmbId}
|
Selectors={Selectors}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
<Box flex={'1'} />
|
|
||||||
<Flex alignItems={'center'} gap={3}>
|
|
||||||
<DateRangePicker
|
|
||||||
defaultDate={dateRange}
|
|
||||||
position="bottom"
|
|
||||||
onChange={setDateRange}
|
|
||||||
onSuccess={() => getData(1)}
|
|
||||||
/>
|
|
||||||
<Pagination />
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
<TableContainer
|
|
||||||
mt={2}
|
|
||||||
px={[3, 8]}
|
|
||||||
position={'relative'}
|
|
||||||
flex={'1 0 0'}
|
|
||||||
h={0}
|
|
||||||
overflowY={'auto'}
|
|
||||||
>
|
|
||||||
<Table>
|
|
||||||
<Thead>
|
|
||||||
<Tr>
|
|
||||||
{/* <Th>{t('account_usage:user.team.Member Name')}</Th> */}
|
|
||||||
<Th>{t('account_usage:user_type')}</Th>
|
|
||||||
<Th>
|
|
||||||
<MySelect<UsageSourceEnum | ''>
|
|
||||||
list={sourceList}
|
|
||||||
value={usageSource}
|
|
||||||
size={'sm'}
|
|
||||||
onchange={(e) => {
|
|
||||||
setUsageSource(e);
|
|
||||||
}}
|
|
||||||
w={'130px'}
|
|
||||||
></MySelect>
|
|
||||||
</Th>
|
|
||||||
<Th>{t('account_usage:project_name')}</Th>
|
|
||||||
<Th>{t('account_usage:total_points')}</Th>
|
|
||||||
<Th></Th>
|
|
||||||
</Tr>
|
|
||||||
</Thead>
|
|
||||||
<Tbody fontSize={'sm'}>
|
|
||||||
{usages.map((item) => (
|
|
||||||
<Tr key={item.id}>
|
|
||||||
{/* <Td>{item.memberName}</Td> */}
|
|
||||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
|
||||||
<Td>{t(UsageSourceMap[item.source]?.label as any) || '-'}</Td>
|
|
||||||
<Td>{t(item.appName as any) || '-'}</Td>
|
|
||||||
<Td>{formatNumber(item.totalPoints) || 0}</Td>
|
|
||||||
<Td>
|
|
||||||
<Button
|
|
||||||
size={'sm'}
|
|
||||||
variant={'whitePrimary'}
|
|
||||||
onClick={() => setUsageDetail(item)}
|
|
||||||
>
|
|
||||||
{t('account_usage:details')}
|
|
||||||
</Button>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
))}
|
|
||||||
</Tbody>
|
|
||||||
</Table>
|
|
||||||
{!isLoading && usages.length === 0 && (
|
|
||||||
<EmptyTip text={t('account_usage:no_usage_records')}></EmptyTip>
|
|
||||||
)}
|
|
||||||
</TableContainer>
|
|
||||||
|
|
||||||
<Loading loading={isLoading} fixed={false} />
|
|
||||||
{!!usageDetail && (
|
|
||||||
<UsageDetail usage={usageDetail} onClose={() => setUsageDetail(undefined)} />
|
|
||||||
)}
|
)}
|
||||||
</Flex>
|
{usageTab === UsageTabEnum.dashboard && (
|
||||||
|
<UsageForm
|
||||||
|
dateRange={dateRange}
|
||||||
|
selectTmbIds={selectTmbIds}
|
||||||
|
usageSources={usageSources}
|
||||||
|
unit={unit}
|
||||||
|
Tabs={Tabs}
|
||||||
|
Selectors={Selectors}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</AccountContainer>
|
</AccountContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -359,6 +359,8 @@ const InputTypeConfig = ({
|
|||||||
<MultipleSelect<WorkflowIOValueTypeEnum>
|
<MultipleSelect<WorkflowIOValueTypeEnum>
|
||||||
list={valueTypeSelectList}
|
list={valueTypeSelectList}
|
||||||
bg={'myGray.50'}
|
bg={'myGray.50'}
|
||||||
|
minH={'40px'}
|
||||||
|
py={2}
|
||||||
value={selectValueTypeList || []}
|
value={selectValueTypeList || []}
|
||||||
onSelect={(e) => {
|
onSelect={(e) => {
|
||||||
setValue('customInputConfig.selectValueTypeList', e);
|
setValue('customInputConfig.selectValueTypeList', e);
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
import { POST } from '@/web/common/api/request';
|
import { POST } from '@/web/common/api/request';
|
||||||
import { CreateTrainingUsageProps } from '@fastgpt/global/support/wallet/usage/api.d';
|
import {
|
||||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
CreateTrainingUsageProps,
|
||||||
|
GetTotalPointsProps,
|
||||||
|
GetUsageProps
|
||||||
|
} from '@fastgpt/global/support/wallet/usage/api.d';
|
||||||
import type { UsageItemType } from '@fastgpt/global/support/wallet/usage/type';
|
import type { UsageItemType } from '@fastgpt/global/support/wallet/usage/type';
|
||||||
import { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
import { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||||
|
|
||||||
export const getUserUsages = (
|
export const getUserUsages = (data: PaginationProps<GetUsageProps>) =>
|
||||||
data: PaginationProps<{
|
POST<PaginationResponse<UsageItemType>>(`/proApi/support/wallet/usage/getUsage`, data);
|
||||||
dateStart: Date;
|
|
||||||
dateEnd: Date;
|
export const getTotalPoints = (data: GetTotalPointsProps) =>
|
||||||
source?: UsageSourceEnum;
|
POST<{ totalPoints: number; date: string }[]>(
|
||||||
teamMemberId: string;
|
`/proApi/support/wallet/usage/getTotalPoints`,
|
||||||
}>
|
data
|
||||||
) => POST<PaginationResponse<UsageItemType>>(`/proApi/support/wallet/usage/getUsage`, data);
|
);
|
||||||
|
|
||||||
export const postCreateTrainingUsage = (data: CreateTrainingUsageProps) =>
|
export const postCreateTrainingUsage = (data: CreateTrainingUsageProps) =>
|
||||||
POST<string>(`/support/wallet/usage/createTrainingUsage`, data);
|
POST<string>(`/support/wallet/usage/createTrainingUsage`, data);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user