mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 08:25:07 +00:00
feat: openapi page
This commit is contained in:
16
src/api/openapi.ts
Normal file
16
src/api/openapi.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { GET, POST, DELETE } from './request';
|
||||
import { UserOpenApiKey } from '@/types/openapi';
|
||||
/**
|
||||
* crete a api key
|
||||
*/
|
||||
export const createAApiKey = () => POST('/openapi/postKey');
|
||||
|
||||
/**
|
||||
* get api keys
|
||||
*/
|
||||
export const getApiKeys = () => GET<UserOpenApiKey[]>('/openapi/getKeys');
|
||||
|
||||
/**
|
||||
* delete api by id
|
||||
*/
|
||||
export const delApiById = (id: string) => DELETE(`/openapi/delKet?id=${id}`);
|
1
src/components/Icon/icons/board.svg
Normal file
1
src/components/Icon/icons/board.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680878351566" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1173" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M896 771.413333h-768c-51.2 0-93.866667-42.666667-93.866667-93.866666V209.92c0-51.2 42.666667-93.866667 93.866667-93.866667h768c51.2 0 93.866667 42.666667 93.866667 93.866667v465.92c0 52.906667-42.666667 95.573333-93.866667 95.573333zM128 167.253333C104.106667 167.253333 85.333333 186.026667 85.333333 209.92v465.92c0 23.893333 18.773333 42.666667 42.666667 42.666667h768c23.893333 0 42.666667-18.773333 42.666667-42.666667V209.92c0-23.893333-18.773333-42.666667-42.666667-42.666667h-768z" p-id="1174"></path><path d="M512 907.946667c-13.653333 0-25.6-11.946667-25.6-25.6v-136.533334c0-13.653333 11.946667-25.6 25.6-25.6s25.6 11.946667 25.6 25.6v136.533334c0 13.653333-11.946667 25.6-25.6 25.6z" p-id="1175"></path><path d="M680.96 907.946667H343.04c-13.653333 0-25.6-11.946667-25.6-25.6s11.946667-25.6 25.6-25.6h337.92c13.653333 0 25.6 11.946667 25.6 25.6s-11.946667 25.6-25.6 25.6zM776.533333 648.533333h-529.066666c-13.653333 0-25.6-11.946667-25.6-25.6s11.946667-25.6 25.6-25.6h530.773333c13.653333 0 25.6 11.946667 25.6 25.6s-11.946667 25.6-27.306667 25.6z" p-id="1176"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
19
src/components/Icon/icons/chatting.svg
Normal file
19
src/components/Icon/icons/chatting.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="204px" height="204px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||
<circle cx="84" cy="50" r="10" fill="#e15b64">
|
||||
<animate attributeName="r" repeatCount="indefinite" dur="0.5681818181818182s" calcMode="spline" keyTimes="0;1" values="15;0" keySplines="0 0.5 0.5 1" begin="0s"></animate>
|
||||
<animate attributeName="fill" repeatCount="indefinite" dur="2.272727272727273s" calcMode="discrete" keyTimes="0;0.25;0.5;0.75;1" values="#e15b64;#abbd81;#f8b26a;#f47e60;#e15b64" begin="0s"></animate>
|
||||
</circle><circle cx="16" cy="50" r="10" fill="#e15b64">
|
||||
<animate attributeName="r" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;15;15;15" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="0s"></animate>
|
||||
<animate attributeName="cx" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="0s"></animate>
|
||||
</circle><circle cx="50" cy="50" r="10" fill="#f47e60">
|
||||
<animate attributeName="r" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;15;15;15" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.5681818181818182s"></animate>
|
||||
<animate attributeName="cx" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.5681818181818182s"></animate>
|
||||
</circle><circle cx="84" cy="50" r="10" fill="#f8b26a">
|
||||
<animate attributeName="r" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;15;15;15" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-1.1363636363636365s"></animate>
|
||||
<animate attributeName="cx" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-1.1363636363636365s"></animate>
|
||||
</circle><circle cx="16" cy="50" r="10" fill="#abbd81">
|
||||
<animate attributeName="r" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;15;15;15" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-1.7045454545454546s"></animate>
|
||||
<animate attributeName="cx" repeatCount="indefinite" dur="2.272727272727273s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-1.7045454545454546s"></animate>
|
||||
</circle>
|
||||
<!-- [ldio] generated by https://loading.io/ --></svg>
|
After Width: | Height: | Size: 2.9 KiB |
1
src/components/Icon/icons/develop.svg
Normal file
1
src/components/Icon/icons/develop.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680878410563" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2745" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M256 512l81.6 108.8a32 32 0 0 1-51.2 38.4l-96-128a31.968 31.968 0 0 1 0-38.4l96-128a32 32 0 0 1 51.2 38.4L256 512zM670.4 620.8a32 32 0 0 0 51.2 38.4l96-128a31.968 31.968 0 0 0 0-38.4l-96-128a32 32 0 0 0-51.2 38.4L752 512l-81.6 108.8zM503.232 646.944a32 32 0 1 1-62.464-13.888l64-288a32 32 0 1 1 62.464 13.888l-64 288z" p-id="2746"></path><path d="M160 144a32 32 0 0 0-32 32V864a32 32 0 0 0 32 32h688a32 32 0 0 0 32-32V176a32 32 0 0 0-32-32H160z m0-64h688a96 96 0 0 1 96 96V864a96 96 0 0 1-96 96H160a96 96 0 0 1-96-96V176a96 96 0 0 1 96-96z" p-id="2747"></path></svg>
|
After Width: | Height: | Size: 897 B |
1
src/components/Icon/icons/user.svg
Normal file
1
src/components/Icon/icons/user.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680878383832" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1637" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M511.333 63.333c-247.424 0-448 200.576-448 448s200.576 448 448 448 448-200.576 448-448-200.576-448-448-448z m0 832c-51.868 0-102.15-10.144-149.451-30.15-36.011-15.231-69.123-35.67-98.812-60.897 12.177-31.985 42.226-63.875 84.223-88.903C396.189 686.243 456.222 669.53 512 669.53c55.631 0 115.416 16.658 164.026 45.703 41.762 24.953 71.689 56.812 83.863 88.804-29.764 25.342-62.976 45.865-99.106 61.146-47.299 20.006-97.582 30.15-149.45 30.15z m296.268-139.658c-20.493-35.937-54.353-68.855-98.747-95.381C649.75 624.979 579.839 605.53 512 605.53c-67.964 0-138.094 19.488-197.471 54.875-44.644 26.606-78.656 59.594-99.195 95.586-23.835-28.755-43.234-60.652-57.85-95.208-20.006-47.3-30.15-97.583-30.15-149.451s10.144-102.15 30.15-149.451c19.337-45.719 47.034-86.792 82.321-122.078 35.286-35.287 76.359-62.983 122.078-82.321 47.3-20.006 97.583-30.15 149.451-30.15 51.868 0 102.15 10.144 149.451 30.15 45.719 19.337 86.792 47.034 122.078 82.321 35.287 35.286 62.983 76.359 82.321 122.078 20.006 47.3 30.15 97.583 30.15 149.451s-10.144 102.15-30.15 149.451c-14.563 34.429-33.869 66.22-57.583 94.892z" p-id="1638"></path><path d="M512 220.223c-88.224 0-160 71.776-160 160s71.776 160 160 160c88.225 0 160-71.775 160-160s-71.775-160-160-160z m0 256c-52.935 0-96-43.065-96-96s43.065-96 96-96 96 43.065 96 96-43.065 96-96 96z" p-id="1639"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '@chakra-ui/react';
|
||||
import { Icon } from '@chakra-ui/react';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const map = {
|
||||
model: require('./icons/model.svg').default,
|
||||
@@ -10,7 +9,11 @@ const map = {
|
||||
menu: require('./icons/menu.svg').default,
|
||||
pay: require('./icons/pay.svg').default,
|
||||
copy: require('./icons/copy.svg').default,
|
||||
chatSend: require('./icons/chatSend.svg').default
|
||||
chatSend: require('./icons/chatSend.svg').default,
|
||||
board: require('./icons/board.svg').default,
|
||||
develop: require('./icons/develop.svg').default,
|
||||
user: require('./icons/user.svg').default,
|
||||
chatting: require('./icons/chatting.svg').default
|
||||
};
|
||||
|
||||
export type IconName = keyof typeof map;
|
||||
|
@@ -16,27 +16,27 @@ const unShowLayoutRoute: { [key: string]: boolean } = {
|
||||
const navbarList = [
|
||||
{
|
||||
label: '介绍',
|
||||
icon: 'icon-gongzuotai-01',
|
||||
icon: 'board',
|
||||
link: '/',
|
||||
activeLink: ['/']
|
||||
},
|
||||
{
|
||||
label: '模型',
|
||||
icon: 'icon-moxing',
|
||||
icon: 'model',
|
||||
link: '/model/list',
|
||||
activeLink: ['/model/list', '/model/detail']
|
||||
},
|
||||
// {
|
||||
// label: '数据',
|
||||
// icon: 'icon-datafull',
|
||||
// link: '/data/list',
|
||||
// activeLink: ['/data/list', '/data/detail']
|
||||
// },
|
||||
{
|
||||
label: '账号',
|
||||
icon: 'icon-yonghu-yuan',
|
||||
icon: 'user',
|
||||
link: '/number/setting',
|
||||
activeLink: ['/number/setting']
|
||||
},
|
||||
{
|
||||
label: '开发',
|
||||
icon: 'develop',
|
||||
link: '/openapi',
|
||||
activeLink: ['/openapi']
|
||||
}
|
||||
];
|
||||
|
||||
|
@@ -2,8 +2,7 @@ import React from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import Icon from '../Iconfont';
|
||||
|
||||
import MyIcon from '../Icon';
|
||||
export enum NavbarTypeEnum {
|
||||
normal = 'normal',
|
||||
small = 'small'
|
||||
@@ -66,20 +65,16 @@ const Navbar = ({
|
||||
backgroundColor: 'transparent'
|
||||
})}
|
||||
>
|
||||
<Icon
|
||||
name={item.icon}
|
||||
width={24}
|
||||
height={24}
|
||||
color={item.activeLink.includes(router.pathname) ? '#2B6CB0' : '#4A5568'}
|
||||
<MyIcon
|
||||
name={item.icon as any}
|
||||
width={'24px'}
|
||||
height={'24px'}
|
||||
fill={item.activeLink.includes(router.pathname) ? '#2B6CB0' : '#4A5568'}
|
||||
/>
|
||||
<Box mt={1}>{item.label}</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Box>
|
||||
{/* 通知 icon */}
|
||||
{/* <Flex className={styles.informIcon} mb={5} justifyContent={'center'}>
|
||||
<Icon name={'icon-tongzhi'} width={28} height={28} color={'#718096'}></Icon>
|
||||
</Flex> */}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import Icon from '../Iconfont';
|
||||
import MyIcon from '../Icon';
|
||||
import {
|
||||
Flex,
|
||||
Drawer,
|
||||
@@ -39,9 +39,8 @@ const NavbarPhone = ({
|
||||
px={7}
|
||||
>
|
||||
<Box onClick={onOpen}>
|
||||
<Icon name="icon-caidan" width={20} height={20}></Icon>
|
||||
<MyIcon name="menu" width={'20px'} height={'20px'} color={'blackAlpha.600'}></MyIcon>
|
||||
</Box>
|
||||
{/* <Icon name="icon-tongzhi" width={20} height={20}></Icon> */}
|
||||
</Flex>
|
||||
<Drawer isOpen={isOpen} placement="left" size={'xs'} onClose={onClose}>
|
||||
<DrawerOverlay />
|
||||
@@ -74,11 +73,11 @@ const NavbarPhone = ({
|
||||
backgroundColor: 'transparent'
|
||||
})}
|
||||
>
|
||||
<Icon
|
||||
name={item.icon}
|
||||
width={24}
|
||||
height={24}
|
||||
color={item.activeLink.includes(router.pathname) ? '#2B6CB0' : '#4A5568'}
|
||||
<MyIcon
|
||||
name={item.icon as any}
|
||||
width={'24px'}
|
||||
height={'24px'}
|
||||
fill={item.activeLink.includes(router.pathname) ? '#2B6CB0' : '#4A5568'}
|
||||
/>
|
||||
<Box ml={5}>{item.label}</Box>
|
||||
</Flex>
|
||||
|
@@ -51,7 +51,6 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<Script src="/js/iconfont.js" strategy="afterInteractive"></Script>
|
||||
<Script src="/js/qrcode.min.js" strategy="afterInteractive"></Script>
|
||||
<Script src="/js/pdf.js" strategy="afterInteractive"></Script>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
|
33
src/pages/api/openapi/delKet.ts
Normal file
33
src/pages/api/openapi/delKet.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase, OpenApi } from '@/service/mongo';
|
||||
import { authToken } from '@/service/utils/tools';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { id } = req.query as { id: string };
|
||||
const { authorization } = req.headers;
|
||||
|
||||
if (!authorization) {
|
||||
throw new Error('缺少登录凭证');
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
const userId = await authToken(authorization);
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
await OpenApi.findOneAndRemove({ _id: id, userId });
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
40
src/pages/api/openapi/getKeys.ts
Normal file
40
src/pages/api/openapi/getKeys.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase, OpenApi } from '@/service/mongo';
|
||||
import { authToken } from '@/service/utils/tools';
|
||||
import { UserOpenApiKey } from '@/types/openapi';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { authorization } = req.headers;
|
||||
|
||||
if (!authorization) {
|
||||
throw new Error('缺少登录凭证');
|
||||
}
|
||||
|
||||
const userId = await authToken(authorization);
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
const findResponse = await OpenApi.find({ userId });
|
||||
|
||||
// jus save four data
|
||||
const apiKeys = findResponse.map<UserOpenApiKey>((item) => {
|
||||
const key = item.apiKey;
|
||||
return {
|
||||
id: item._id,
|
||||
apiKey: `${key.substring(0, 2)}******${key.substring(key.length - 2)}`
|
||||
};
|
||||
});
|
||||
|
||||
jsonRes(res, {
|
||||
data: apiKeys
|
||||
});
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
43
src/pages/api/openapi/postKey.ts
Normal file
43
src/pages/api/openapi/postKey.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase, OpenApi } from '@/service/mongo';
|
||||
import { authToken } from '@/service/utils/tools';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890-', 20);
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { authorization } = req.headers;
|
||||
|
||||
if (!authorization) {
|
||||
throw new Error('缺少登录凭证');
|
||||
}
|
||||
|
||||
const userId = await authToken(authorization);
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
const count = await OpenApi.find({ userId }).countDocuments();
|
||||
|
||||
if (count >= 5) {
|
||||
throw new Error('最多 5 组API Key');
|
||||
}
|
||||
|
||||
const apiKey = `${userId}-${nanoid()}`;
|
||||
|
||||
await OpenApi.create({
|
||||
userId,
|
||||
apiKey
|
||||
});
|
||||
|
||||
jsonRes(res, {
|
||||
data: apiKey
|
||||
});
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
@@ -519,11 +519,11 @@ const Chat = ({ chatId }: { chatId: string }) => {
|
||||
onClick={sendPrompt}
|
||||
>
|
||||
{isChatting ? (
|
||||
<Image
|
||||
<Icon
|
||||
style={{ transform: 'translateY(4px)' }}
|
||||
src={'/icon/chatting.svg'}
|
||||
fill
|
||||
alt={''}
|
||||
h={'30px'}
|
||||
w={'30px'}
|
||||
name={'chatting'}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
|
12
src/pages/openapi/index.tsx
Normal file
12
src/pages/openapi/index.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Card, Box, Flex, Button, Input } from '@chakra-ui/react';
|
||||
|
||||
const OpenApi = () => {
|
||||
return (
|
||||
<Card px={6} py={4}>
|
||||
ss
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default OpenApi;
|
@@ -7,6 +7,10 @@ const OpenApiSchema = new Schema({
|
||||
ref: 'user',
|
||||
required: true
|
||||
},
|
||||
apiKey: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
|
@@ -42,3 +42,4 @@ export * from './models/pay';
|
||||
export * from './models/data';
|
||||
export * from './models/dataItem';
|
||||
export * from './models/splitData';
|
||||
export * from './models/openapi';
|
||||
|
1
src/types/mongoSchema.d.ts
vendored
1
src/types/mongoSchema.d.ts
vendored
@@ -154,4 +154,5 @@ export interface OpenApiSchema {
|
||||
userId: string;
|
||||
createTime: Date;
|
||||
lastUsedTime: Date;
|
||||
apiKey: String;
|
||||
}
|
||||
|
4
src/types/openapi.d.ts
vendored
Normal file
4
src/types/openapi.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface UserOpenApiKey {
|
||||
id: string;
|
||||
apiKey: string;
|
||||
}
|
Reference in New Issue
Block a user