import React, { useEffect, useMemo, useState } from 'react'; import { Box, Button, Flex, ModalFooter, ModalBody, Table, Thead, Tbody, Tr, Th, Td, TableContainer, useTheme, Link, Input, IconButton } from '@chakra-ui/react'; import { getOpenApiKeys, createAOpenApiKey, delOpenApiById, putOpenApiKey } from '@/web/support/openapi/api'; import type { EditApiKeyProps } from '@/global/support/openapi/api.d'; import { useQuery, useMutation } from '@tanstack/react-query'; import { useLoading } from '@fastgpt/web/hooks/useLoading'; import dayjs from 'dayjs'; import { AddIcon } from '@chakra-ui/icons'; import { useCopyData } from '@/web/common/hooks/useCopyData'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useTranslation } from 'next-i18next'; import MyIcon from '@fastgpt/web/components/common/Icon'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useForm } from 'react-hook-form'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { getDocPath } from '@/web/common/system/doc'; import MyMenu from '@fastgpt/web/components/common/MyMenu'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useI18n } from '@/web/context/I18n'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import MyBox from '@fastgpt/web/components/common/MyBox'; type EditProps = EditApiKeyProps & { _id?: string }; const defaultEditData: EditProps = { name: '', limit: { maxUsagePoints: -1 } }; const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => { const { t } = useTranslation(); const { Loading } = useLoading(); const theme = useTheme(); const { copyData } = useCopyData(); const { feConfigs } = useSystemStore(); const [baseUrl, setBaseUrl] = useState('https://fastgpt.in/api'); const [editData, setEditData] = useState(); const [apiKey, setApiKey] = useState(''); const { ConfirmModal, openConfirm } = useConfirm({ type: 'delete', content: '确认删除该API密钥?删除后该密钥立即失效,对应的对话日志不会删除,请确认!' }); const { mutate: onclickRemove, isLoading: isDeleting } = useMutation({ mutationFn: async (id: string) => { return delOpenApiById(id); }, onSuccess() { refetch(); } }); const { data: apiKeys = [], isLoading: isGetting, refetch } = useQuery(['getOpenApiKeys', appId], () => getOpenApiKeys({ appId })); useEffect(() => { setBaseUrl(feConfigs?.customApiDomain || `${location.origin}/api`); }, []); return ( {t('common:support.openapi.Api manager')} {feConfigs?.docUrl && ( {t('common:common.Read document')} )} {tips} copyData(baseUrl, t('common:support.openapi.Copy success'))} > {t('common:support.openapi.Api baseurl')} {baseUrl} {feConfigs?.isPlus && ( <> )} {apiKeys.map(({ _id, name, usagePoints, limit, apiKey, createTime, lastUsedTime }) => ( {feConfigs?.isPlus && ( <> )} ))}
{t('common:Name')} Api Key {t('common:support.outlink.Usage points')}{t('common:common.Expired Time')}{t('common:common.Create Time')} {t('common:common.Last use time')}
{name} {apiKey} {Math.round(usagePoints)}/ {feConfigs?.isPlus && limit?.maxUsagePoints && limit?.maxUsagePoints > -1 ? `${limit?.maxUsagePoints}` : t('common:common.Unlimited')} {limit?.expiredTime ? dayjs(limit?.expiredTime).format('YYYY/MM/DD\nHH:mm') : '-'} {dayjs(createTime).format('YYYY/MM/DD\nHH:mm:ss')} {lastUsedTime ? dayjs(lastUsedTime).format('YYYY/MM/DD\nHH:mm:ss') : t('common:common.Un used')} } name={'more'} variant={'whitePrimary'} size={'sm'} aria-label={''} /> } menuList={[ { children: [ { label: t('common:common.Edit'), icon: 'edit', onClick: () => setEditData({ _id, name, limit, appId }) }, { label: t('common:common.Delete'), icon: 'delete', type: 'danger', onClick: () => openConfirm(() => onclickRemove(_id))() } ] } ]} />
{!!editData && ( setEditData(undefined)} onCreate={(id) => { setApiKey(id); refetch(); setEditData(undefined); }} onEdit={() => { refetch(); setEditData(undefined); }} /> )} {t('common:support.openapi.New api key')} {t('common:support.openapi.New api key tip')} } onClose={() => setApiKey('')} > copyData(apiKey)} > {apiKey}
); }; export default React.memo(ApiKeyTable); // edit link modal function EditKeyModal({ defaultData, onClose, onCreate, onEdit }: { defaultData: EditProps; onClose: () => void; onCreate: (id: string) => void; onEdit: () => void; }) { const { t } = useTranslation(); const { publishT } = useI18n(); const isEdit = useMemo(() => !!defaultData._id, [defaultData]); const { feConfigs } = useSystemStore(); const { register, setValue, handleSubmit: submitShareChat } = useForm({ defaultValues: defaultData }); const { mutate: onclickCreate, isLoading: creating } = useRequest({ mutationFn: async (e: EditProps) => createAOpenApiKey(e), errorToast: '创建链接异常', onSuccess: onCreate }); const { mutate: onclickUpdate, isLoading: updating } = useRequest({ mutationFn: (e: EditProps) => { //@ts-ignore return putOpenApiKey(e); }, errorToast: '更新链接异常', onSuccess: onEdit }); return ( {t('common:Name')} {feConfigs?.isPlus && ( <> {t('common:support.outlink.Max usage points')} {t('common:common.Expired Time')} { setValue('limit.expiredTime', new Date(e.target.value)); }} /> )} ); }