mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 12:20:34 +00:00
feat: 注册限流配置
feat: 页面加载动画 feat: md样式优化 feat: 移动端全屏覆盖
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
AXIOS_PROXY_HOST=127.0.0.1
|
||||
AXIOS_PROXY_PORT=33210
|
||||
MONGODB_UR=
|
||||
MONGODB_URI=
|
||||
MY_MAIL=
|
||||
MAILE_CODE=
|
||||
TOKEN_KEY=
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -35,4 +35,5 @@ yarn-error.log*
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
public/trainData/
|
||||
.vscode/
|
||||
.vscode/
|
||||
platform.json
|
@@ -55,5 +55,12 @@ USER nextjs
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
ENV MAX_USER ''
|
||||
ENV AXIOS_PROXY_HOST ''
|
||||
ENV AXIOS_PROXY_PORT ''
|
||||
ENV MONGODB_URI ''
|
||||
ENV MY_MAIL ''
|
||||
ENV MAILE_CODE ''
|
||||
ENV TOKEN_KEY ''
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
@@ -6,7 +6,7 @@
|
||||
```
|
||||
AXIOS_PROXY_HOST=axios代理地址,目前 openai 接口都需要走代理,本机的话就填 127.0.0.1
|
||||
AXIOS_PROXY_PORT=代理端口
|
||||
MONGODB_UR=mongo数据库地址
|
||||
MONGODB_URI=mongo数据库地址
|
||||
MY_MAIL=发送验证码邮箱
|
||||
MAILE_CODE=邮箱秘钥
|
||||
TOKEN_KEY=随便填一个,用于生成和校验token
|
||||
@@ -27,7 +27,7 @@ docker pull imageName
|
||||
docker stop doc-gpt || true
|
||||
docker rm doc-gpt || true
|
||||
# 运行时才把参数写入
|
||||
docker run -d --network=host --name doc-gpt -e AXIOS_PROXY_HOST= -e AXIOS_PROXY_PORT= -e MAILE_CODE= -e TOKEN_KEY= -e MONGODB_UR= imageName
|
||||
docker run -d --network=host --name doc-gpt -e AXIOS_PROXY_HOST= -e AXIOS_PROXY_PORT= -e MAILE_CODE= -e TOKEN_KEY= -e MONGODB_URI= imageName
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"@next/font": "13.1.6",
|
||||
"@reduxjs/toolkit": "^1.9.3",
|
||||
"@tanstack/react-query": "^4.24.10",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"axios": "^1.3.3",
|
||||
"crypto": "^1.0.1",
|
||||
"dayjs": "^1.11.7",
|
||||
@@ -32,6 +33,7 @@
|
||||
"mongoose": "^6.10.0",
|
||||
"next": "13.1.6",
|
||||
"nodemailer": "^6.9.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"openai": "^3.2.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
@@ -13,6 +13,7 @@ specifiers:
|
||||
'@types/jsonwebtoken': ^9.0.1
|
||||
'@types/node': 18.14.0
|
||||
'@types/nodemailer': ^6.4.7
|
||||
'@types/nprogress': ^0.2.0
|
||||
'@types/react': 18.0.28
|
||||
'@types/react-dom': 18.0.11
|
||||
'@types/react-syntax-highlighter': ^15.5.6
|
||||
@@ -33,6 +34,7 @@ specifiers:
|
||||
mongoose: ^6.10.0
|
||||
next: 13.1.6
|
||||
nodemailer: ^6.9.1
|
||||
nprogress: ^0.2.0
|
||||
openai: ^3.2.1
|
||||
prettier: ^2.8.4
|
||||
react: 18.2.0
|
||||
@@ -57,6 +59,7 @@ dependencies:
|
||||
'@next/font': registry.npmmirror.com/@next/font/13.1.6
|
||||
'@reduxjs/toolkit': registry.npmmirror.com/@reduxjs/toolkit/1.9.3_react@18.2.0
|
||||
'@tanstack/react-query': registry.npmmirror.com/@tanstack/react-query/4.24.10_biqbaboplfbrettd7655fr4n2y
|
||||
'@types/nprogress': registry.npmmirror.com/@types/nprogress/0.2.0
|
||||
axios: registry.npmmirror.com/axios/1.3.3
|
||||
crypto: registry.npmmirror.com/crypto/1.0.1
|
||||
dayjs: registry.npmmirror.com/dayjs/1.11.7
|
||||
@@ -70,6 +73,7 @@ dependencies:
|
||||
mongoose: registry.npmmirror.com/mongoose/6.10.0
|
||||
next: registry.npmmirror.com/next/13.1.6_wiv434v7erz4aedd5whhdwmpv4
|
||||
nodemailer: registry.npmmirror.com/nodemailer/6.9.1
|
||||
nprogress: registry.npmmirror.com/nprogress/0.2.0
|
||||
openai: registry.npmmirror.com/openai/3.2.1
|
||||
react: registry.npmmirror.com/react/18.2.0
|
||||
react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0
|
||||
@@ -1097,6 +1101,15 @@ packages:
|
||||
regenerator-runtime: registry.npmmirror.com/regenerator-runtime/0.13.11
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/@babel/runtime/7.21.0:
|
||||
resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/runtime/-/runtime-7.21.0.tgz}
|
||||
name: '@babel/runtime'
|
||||
version: 7.21.0
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
regenerator-runtime: registry.npmmirror.com/regenerator-runtime/0.13.11
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/@babel/types/7.21.0:
|
||||
resolution: {integrity: sha512-uR7NWq2VNFnDi7EYqiRz2Jv/VQIu38tu64Zy8TX2nQFQ6etJ9V/Rr2msW8BS132mum2rL645qpDrLtAJtVpuow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/types/-/types-7.21.0.tgz}
|
||||
name: '@babel/types'
|
||||
@@ -2433,7 +2446,7 @@ packages:
|
||||
version: 11.10.6
|
||||
dependencies:
|
||||
'@babel/helper-module-imports': registry.npmmirror.com/@babel/helper-module-imports/7.18.6
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.20.13
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.21.0
|
||||
'@emotion/hash': registry.npmmirror.com/@emotion/hash/0.9.0
|
||||
'@emotion/memoize': registry.npmmirror.com/@emotion/memoize/0.8.0
|
||||
'@emotion/serialize': registry.npmmirror.com/@emotion/serialize/1.1.1
|
||||
@@ -3048,6 +3061,12 @@ packages:
|
||||
'@types/node': registry.npmmirror.com/@types/node/18.14.0
|
||||
dev: true
|
||||
|
||||
registry.npmmirror.com/@types/nprogress/0.2.0:
|
||||
resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/nprogress/-/nprogress-0.2.0.tgz}
|
||||
name: '@types/nprogress'
|
||||
version: 0.2.0
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/@types/parse-json/4.0.0:
|
||||
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.0.tgz}
|
||||
name: '@types/parse-json'
|
||||
@@ -3469,7 +3488,7 @@ packages:
|
||||
version: 3.1.0
|
||||
engines: {node: '>=10', npm: '>=6'}
|
||||
dependencies:
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.20.13
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.21.0
|
||||
cosmiconfig: registry.npmmirror.com/cosmiconfig/7.1.0
|
||||
resolve: registry.npmmirror.com/resolve/1.22.1
|
||||
dev: false
|
||||
@@ -4329,7 +4348,7 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
|
||||
dependencies:
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.20.13
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.21.0
|
||||
aria-query: registry.npmmirror.com/aria-query/5.1.3
|
||||
array-includes: registry.npmmirror.com/array-includes/3.1.6
|
||||
array.prototype.flatmap: registry.npmmirror.com/array.prototype.flatmap/1.3.1
|
||||
@@ -6481,6 +6500,12 @@ packages:
|
||||
path-key: registry.npmmirror.com/path-key/4.0.0
|
||||
dev: true
|
||||
|
||||
registry.npmmirror.com/nprogress/0.2.0:
|
||||
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz}
|
||||
name: nprogress
|
||||
version: 0.2.0
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/object-assign/4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz}
|
||||
name: object-assign
|
||||
@@ -6889,7 +6914,7 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.20.13
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.21.0
|
||||
react: registry.npmmirror.com/react/18.2.0
|
||||
dev: false
|
||||
|
||||
@@ -6924,7 +6949,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.20.13
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.21.0
|
||||
'@types/react': registry.npmmirror.com/@types/react/18.0.28
|
||||
focus-lock: registry.npmmirror.com/focus-lock/0.11.6
|
||||
prop-types: registry.npmmirror.com/prop-types/15.8.1
|
||||
@@ -7110,7 +7135,7 @@ packages:
|
||||
name: redux
|
||||
version: 4.2.1
|
||||
dependencies:
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.20.13
|
||||
'@babel/runtime': registry.npmmirror.com/@babel/runtime/7.21.0
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/refractor/3.6.0:
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 33 KiB |
Binary file not shown.
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 117 KiB |
@@ -7,6 +7,7 @@ import { useGlobalStore } from '@/store/global';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
const unAuthPage: { [key: string]: boolean } = {
|
||||
'/': true,
|
||||
'/login': true,
|
||||
'/chat': true
|
||||
};
|
||||
@@ -48,7 +49,7 @@ const Auth = ({ children }: { children: JSX.Element }) => {
|
||||
}
|
||||
);
|
||||
|
||||
return userInfo || unAuthPage[router.pathname] === true ? <>{children}</> : null;
|
||||
return userInfo || unAuthPage[router.pathname] === true ? children : null;
|
||||
};
|
||||
|
||||
export default Auth;
|
||||
|
@@ -51,10 +51,10 @@ const Layout = ({ children }: { children: JSX.Element }) => {
|
||||
return (
|
||||
<>
|
||||
{!unShowLayoutRoute[router.pathname] ? (
|
||||
<Box minHeight={'100vh'} backgroundColor={'gray.100'}>
|
||||
<Box data-test="ss" h={'100%'} backgroundColor={'gray.100'} overflow={'auto'}>
|
||||
{isPc ? (
|
||||
<>
|
||||
<Box h={'100vh'} position={'fixed'} left={0} top={0} w={'80px'}>
|
||||
<Box h={'100%'} position={'fixed'} left={0} top={0} w={'80px'}>
|
||||
<Navbar navbarList={navbarList} />
|
||||
</Box>
|
||||
<Box ml={'80px'} p={7}>
|
||||
|
@@ -3,7 +3,6 @@ import { Box, Flex } from '@chakra-ui/react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import Icon from '../Icon';
|
||||
import styles from './style.module.scss';
|
||||
|
||||
export enum NavbarTypeEnum {
|
||||
normal = 'normal',
|
||||
|
@@ -1,47 +1,5 @@
|
||||
import React from 'react';
|
||||
export const codeLight: { [key: string]: React.CSSProperties } = {
|
||||
'code[class*=language-]': {
|
||||
color: '#d4d4d4',
|
||||
fontSize: '13px',
|
||||
textShadow: 'none',
|
||||
fontFamily: 'Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace',
|
||||
direction: 'ltr',
|
||||
textAlign: 'left',
|
||||
whiteSpace: 'pre',
|
||||
wordSpacing: 'normal',
|
||||
wordBreak: 'normal',
|
||||
lineHeight: '1.5',
|
||||
MozTabSize: '4',
|
||||
OTabSize: '4',
|
||||
tabSize: '4',
|
||||
WebkitHyphens: 'none',
|
||||
MozHyphens: 'none',
|
||||
msHyphens: 'none',
|
||||
hyphens: 'none'
|
||||
},
|
||||
'pre[class*=language-]': {
|
||||
color: '#d4d4d4',
|
||||
fontSize: '13px',
|
||||
textShadow: 'none',
|
||||
fontFamily: 'Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace',
|
||||
direction: 'ltr',
|
||||
textAlign: 'left',
|
||||
whiteSpace: 'pre',
|
||||
wordSpacing: 'normal',
|
||||
wordBreak: 'normal',
|
||||
lineHeight: '1.5',
|
||||
MozTabSize: '4',
|
||||
OTabSize: '4',
|
||||
tabSize: '4',
|
||||
WebkitHyphens: 'none',
|
||||
MozHyphens: 'none',
|
||||
msHyphens: 'none',
|
||||
hyphens: 'none',
|
||||
padding: '1em',
|
||||
margin: '.5em 0',
|
||||
overflow: 'auto',
|
||||
background: '#1e1e1e'
|
||||
},
|
||||
'code[class*=language-] ::selection': {
|
||||
textShadow: 'none',
|
||||
background: '#264f78'
|
||||
|
@@ -27,96 +27,343 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown > *:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
.markdown > *:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.markdown a.absent {
|
||||
color: #cc0000;
|
||||
}
|
||||
.markdown a.anchor {
|
||||
bottom: 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
left: 0;
|
||||
margin-left: -30px;
|
||||
padding-left: 30px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
.markdown h1,
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
cursor: text;
|
||||
font-weight: bold;
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
.markdown h1 .mini-icon-link,
|
||||
.markdown h2 .mini-icon-link,
|
||||
.markdown h3 .mini-icon-link,
|
||||
.markdown h4 .mini-icon-link,
|
||||
.markdown h5 .mini-icon-link,
|
||||
.markdown h6 .mini-icon-link {
|
||||
color: #000000;
|
||||
display: none;
|
||||
}
|
||||
.markdown h1:hover a.anchor,
|
||||
.markdown h2:hover a.anchor,
|
||||
.markdown h3:hover a.anchor,
|
||||
.markdown h4:hover a.anchor,
|
||||
.markdown h5:hover a.anchor,
|
||||
.markdown h6:hover a.anchor {
|
||||
line-height: 1;
|
||||
margin-left: -22px;
|
||||
padding-left: 0;
|
||||
text-decoration: none;
|
||||
top: 15%;
|
||||
}
|
||||
.markdown h1:hover a.anchor .mini-icon-link,
|
||||
.markdown h2:hover a.anchor .mini-icon-link,
|
||||
.markdown h3:hover a.anchor .mini-icon-link,
|
||||
.markdown h4:hover a.anchor .mini-icon-link,
|
||||
.markdown h5:hover a.anchor .mini-icon-link,
|
||||
.markdown h6:hover a.anchor .mini-icon-link {
|
||||
display: inline-block;
|
||||
}
|
||||
.markdown h1 tt,
|
||||
.markdown h1 code,
|
||||
.markdown h2 tt,
|
||||
.markdown h2 code,
|
||||
.markdown h3 tt,
|
||||
.markdown h3 code,
|
||||
.markdown h4 tt,
|
||||
.markdown h4 code,
|
||||
.markdown h5 tt,
|
||||
.markdown h5 code,
|
||||
.markdown h6 tt,
|
||||
.markdown h6 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
.markdown h1 {
|
||||
color: #000000;
|
||||
font-size: 28px;
|
||||
}
|
||||
.markdown h2 {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
color: #000000;
|
||||
font-size: 24px;
|
||||
}
|
||||
.markdown h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.markdown h4 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.markdown h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
.markdown h6 {
|
||||
color: #777777;
|
||||
font-size: 14px;
|
||||
}
|
||||
.markdown p,
|
||||
.markdown blockquote,
|
||||
.markdown ul,
|
||||
.markdown ol,
|
||||
.markdown dl,
|
||||
.markdown table {
|
||||
margin: 15px 0;
|
||||
}
|
||||
.markdown hr {
|
||||
background: url('https://a248.e.akamai.net/assets.github.com/assets/primer/markdown/dirty-shade-350cca8f57223ebd53603021b2e670f4f319f1b7.png')
|
||||
repeat-x scroll 0 0 transparent;
|
||||
border: 0 none;
|
||||
color: #cccccc;
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
.markdown > h2:first-child,
|
||||
.markdown > h1:first-child,
|
||||
.markdown > h1:first-child + h2,
|
||||
.markdown > h3:first-child,
|
||||
.markdown > h4:first-child,
|
||||
.markdown > h5:first-child,
|
||||
.markdown > h6:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.markdown a:first-child h1,
|
||||
.markdown a:first-child h2,
|
||||
.markdown a:first-child h3,
|
||||
.markdown a:first-child h4,
|
||||
.markdown a:first-child h5,
|
||||
.markdown a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.markdown h1 + p,
|
||||
.markdown h2 + p,
|
||||
.markdown h3 + p,
|
||||
.markdown h4 + p,
|
||||
.markdown h5 + p,
|
||||
.markdown h6 + p {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown li p.first {
|
||||
display: inline-block;
|
||||
}
|
||||
.markdown ul,
|
||||
.markdown ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
.markdown ul.no-list,
|
||||
.markdown ol.no-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
.markdown ul li > *:first-child,
|
||||
.markdown ol li > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown ul ul,
|
||||
.markdown ul ol,
|
||||
.markdown ol ol,
|
||||
.markdown ol ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown dl {
|
||||
padding: 0;
|
||||
}
|
||||
.markdown dl dt {
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
margin: 15px 0 5px;
|
||||
padding: 0;
|
||||
}
|
||||
.markdown dl dt:first-child {
|
||||
padding: 0;
|
||||
}
|
||||
.markdown dl dt > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown dl dt > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown dl dd {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.markdown dl dd > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown dl dd > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown blockquote {
|
||||
border-left: 4px solid #dddddd;
|
||||
color: #777777;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.markdown blockquote > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown blockquote > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
.markdown table th,
|
||||
.markdown table td {
|
||||
border: 1px solid #cccccc;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
.markdown table tr {
|
||||
background-color: #ffffff;
|
||||
border-top: 1px solid #cccccc;
|
||||
}
|
||||
.markdown table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
.markdown img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.markdown span.frame {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
.markdown span.frame > span {
|
||||
border: 1px solid #dddddd;
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 13px 0 0;
|
||||
overflow: hidden;
|
||||
padding: 7px;
|
||||
width: auto;
|
||||
}
|
||||
.markdown span.frame span img {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
.markdown span.frame span span {
|
||||
clear: both;
|
||||
color: #333333;
|
||||
display: block;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
.markdown span.align-center {
|
||||
clear: both;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
.markdown span.align-center > span {
|
||||
display: block;
|
||||
margin: 13px auto 0;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
.markdown span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.markdown span.align-right {
|
||||
clear: both;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
.markdown span.align-right > span {
|
||||
display: block;
|
||||
margin: 13px 0 0;
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
}
|
||||
.markdown span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
}
|
||||
.markdown span.float-left {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.markdown span.float-left span {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
.markdown span.float-right {
|
||||
display: block;
|
||||
float: right;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.markdown span.float-right > span {
|
||||
display: block;
|
||||
margin: 13px auto 0;
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
}
|
||||
.markdown code,
|
||||
.markdown tt {
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
margin: 0 2px;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.markdown pre > code {
|
||||
background: none repeat scroll 0 0 transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
}
|
||||
.markdown .highlight pre,
|
||||
.markdown pre {
|
||||
background-color: #f8f8f8;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.markdown pre code,
|
||||
.markdown pre tt {
|
||||
background-color: transparent;
|
||||
border: medium none;
|
||||
}
|
||||
.markdown {
|
||||
/* 标题样式 */
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.83rem;
|
||||
}
|
||||
|
||||
/* 列表样式 */
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 1.5rem;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
ul {
|
||||
list-style: inside;
|
||||
}
|
||||
ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
/* 链接样式 */
|
||||
a {
|
||||
color: #0077cc;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid #0077cc;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #005580;
|
||||
border-bottom-color: #005580;
|
||||
}
|
||||
|
||||
/* 图片样式 */
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
/* 强调样式 */
|
||||
em,
|
||||
i {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
strong,
|
||||
b {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 代码样式 */
|
||||
code {
|
||||
border-radius: 3px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
letter-spacing: 0.5px;
|
||||
text-align: justify;
|
||||
pre {
|
||||
padding: 10px 15px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
background-color: #222 !important;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
border: none;
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.7;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo, memo } from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import styles from './index.module.scss';
|
||||
@@ -24,10 +24,16 @@ const Markdown = ({ source, isChatting }: { source: string; isChatting: boolean
|
||||
code({ node, inline, className, children, ...props }) {
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const code = String(children).replace(/\n$/, '');
|
||||
|
||||
return (
|
||||
return !inline ? (
|
||||
<Box my={3} borderRadius={'md'} overflow={'hidden'}>
|
||||
<Flex py={2} px={5} backgroundColor={'#323641'} color={'#fff'} fontSize={'sm'}>
|
||||
<Flex
|
||||
py={2}
|
||||
px={5}
|
||||
backgroundColor={'#323641'}
|
||||
color={'#fff'}
|
||||
fontSize={'sm'}
|
||||
userSelect={'none'}
|
||||
>
|
||||
<Box flex={1}>{match?.[1]}</Box>
|
||||
<Flex cursor={'pointer'} onClick={() => copyData(code)} alignItems={'center'}>
|
||||
<Icon name={'icon-fuzhi'} width={15} height={15} color={'#fff'}></Icon>
|
||||
@@ -36,13 +42,17 @@ const Markdown = ({ source, isChatting }: { source: string; isChatting: boolean
|
||||
</Flex>
|
||||
<SyntaxHighlighter
|
||||
style={codeLight as any}
|
||||
showLineNumbers
|
||||
language={match?.[1]}
|
||||
language={match?.[1] || 'bash'}
|
||||
PreTag="pre"
|
||||
{...props}
|
||||
>
|
||||
{code}
|
||||
</SyntaxHighlighter>
|
||||
</Box>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
}}
|
||||
|
@@ -58,7 +58,11 @@ export const theme = extendTheme({
|
||||
global: {
|
||||
'html, body': {
|
||||
color: 'blackAlpha.800',
|
||||
fontSize: '14px'
|
||||
fontSize: '14px',
|
||||
fontFamily:
|
||||
'Söhne,ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,Helvetica Neue,Arial,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji',
|
||||
height: '100%',
|
||||
overflowY: 'auto'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -1,11 +1,20 @@
|
||||
import type { AppProps, NextWebVitalsMetric } from 'next/app';
|
||||
import Script from 'next/script';
|
||||
import Head from 'next/head';
|
||||
import { ChakraProvider } from '@chakra-ui/react';
|
||||
import Layout from '@/components/Layout';
|
||||
import { theme } from '@/constants/theme';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import NProgress from 'nprogress'; //nprogress module
|
||||
import Router from 'next/router';
|
||||
import 'nprogress/nprogress.css';
|
||||
import '../styles/reset.scss';
|
||||
|
||||
//Binding events.
|
||||
Router.events.on('routeChangeStart', () => NProgress.start());
|
||||
Router.events.on('routeChangeComplete', () => NProgress.done());
|
||||
Router.events.on('routeChangeError', () => NProgress.done());
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
// Create a client
|
||||
const queryClient = new QueryClient({
|
||||
@@ -28,7 +37,6 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<script src="/iconfont.js" async></script>
|
||||
</Head>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ChakraProvider theme={theme}>
|
||||
@@ -37,6 +45,7 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
</Layout>
|
||||
</ChakraProvider>
|
||||
</QueryClientProvider>
|
||||
<Script src="/iconfont.js"></Script>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@@ -2,13 +2,13 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { AuthCode } from '@/service/models/authCode';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { connectToDatabase, User } from '@/service/mongo';
|
||||
import { sendCode } from '@/service/utils/sendEmail';
|
||||
import { EmailTypeEnum } from '@/constants/common';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { email, type } = req.query;
|
||||
const { email, type } = req.query as { email: string; type: `${EmailTypeEnum}` };
|
||||
|
||||
if (!email || !type) {
|
||||
throw new Error('缺少参数');
|
||||
@@ -16,6 +16,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
// 注册人数限流
|
||||
if (type === EmailTypeEnum.register) {
|
||||
const maxCount = process.env.MAX_USER ? +process.env.MAX_USER : Infinity;
|
||||
const userCount = await User.count();
|
||||
|
||||
if (userCount >= maxCount) {
|
||||
throw new Error('当前注册用户已满,请等待名额~');
|
||||
}
|
||||
}
|
||||
|
||||
let code = '';
|
||||
for (let i = 0; i < 6; i++) {
|
||||
code += Math.floor(Math.random() * 10);
|
||||
|
@@ -18,10 +18,12 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import { OpenAiModelEnum } from '@/constants/model';
|
||||
|
||||
const textareaMinH = '22px';
|
||||
|
||||
const Chat = () => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const { media } = useScreen();
|
||||
const { isPc, media } = useScreen();
|
||||
const { chatId, windowId } = router.query as { chatId: string; windowId?: string };
|
||||
const ChatBox = useRef<HTMLDivElement>(null);
|
||||
const TextareaDom = useRef<HTMLTextAreaElement>(null);
|
||||
@@ -32,7 +34,7 @@ const Chat = () => {
|
||||
|
||||
const isChatting = useMemo(() => chatList[chatList.length - 1]?.status === 'loading', [chatList]);
|
||||
const lastWordHuman = useMemo(() => chatList[chatList.length - 1]?.obj === 'Human', [chatList]);
|
||||
const { Loading } = useLoading();
|
||||
const { Loading, setIsLoading } = useLoading({ defaultLoading: true });
|
||||
|
||||
// 滚动到底部
|
||||
const scrollToBottom = useCallback(() => {
|
||||
@@ -47,28 +49,36 @@ const Chat = () => {
|
||||
}, []);
|
||||
|
||||
// 初始化聊天框
|
||||
useQuery([chatId, windowId], () => (chatId ? getInitChatSiteInfo(chatId, windowId) : null), {
|
||||
cacheTime: 5 * 60 * 1000,
|
||||
onSuccess(res) {
|
||||
if (!res) return;
|
||||
router.replace(`/chat?chatId=${chatId}&windowId=${res.windowId}`);
|
||||
const { isInitialLoading } = useQuery(
|
||||
[chatId, windowId],
|
||||
() => (chatId ? getInitChatSiteInfo(chatId, windowId) : null),
|
||||
{
|
||||
cacheTime: 5 * 60 * 1000,
|
||||
onSuccess(res) {
|
||||
if (!res) return;
|
||||
router.replace(`/chat?chatId=${chatId}&windowId=${res.windowId}`);
|
||||
|
||||
setChatSiteData(res.chatSite);
|
||||
setChatList(
|
||||
res.history.map((item) => ({
|
||||
...item,
|
||||
status: 'finish'
|
||||
}))
|
||||
);
|
||||
scrollToBottom();
|
||||
},
|
||||
onError() {
|
||||
toast({
|
||||
title: '初始化异常',
|
||||
status: 'error'
|
||||
});
|
||||
setChatSiteData(res.chatSite);
|
||||
setChatList(
|
||||
res.history.map((item) => ({
|
||||
...item,
|
||||
status: 'finish'
|
||||
}))
|
||||
);
|
||||
scrollToBottom();
|
||||
setIsLoading(false);
|
||||
},
|
||||
onError() {
|
||||
toast({
|
||||
title: '初始化异常,请刷新',
|
||||
status: 'error',
|
||||
isClosable: true,
|
||||
duration: 5000
|
||||
});
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
// gpt3 方法
|
||||
const gpt3ChatPrompt = useCallback(
|
||||
@@ -179,8 +189,9 @@ const Chat = () => {
|
||||
setTimeout(() => {
|
||||
scrollToBottom();
|
||||
|
||||
/* 回到最小高度 */
|
||||
if (TextareaDom.current) {
|
||||
TextareaDom.current.style.height = 22 + 'px';
|
||||
TextareaDom.current.style.height = textareaMinH;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
@@ -242,7 +253,7 @@ const Chat = () => {
|
||||
}, [chatList, windowId]);
|
||||
|
||||
return (
|
||||
<Flex h={'100vh'} flexDirection={'column'} overflowY={'hidden'}>
|
||||
<Flex height={'100%'} flexDirection={'column'}>
|
||||
{/* 头部 */}
|
||||
<Flex
|
||||
px={4}
|
||||
@@ -258,7 +269,6 @@ const Chat = () => {
|
||||
<Icon name={'icon-zhongzhi'} width={20} height={20} color={'#718096'}></Icon>
|
||||
</Box>
|
||||
{/* 滚动到底部按键 */}
|
||||
{/* 滚动到底部 */}
|
||||
{ChatBox.current && ChatBox.current.scrollHeight > 2 * ChatBox.current.clientHeight && (
|
||||
<Box ml={10} cursor={'pointer'} onClick={scrollToBottom}>
|
||||
<Icon
|
||||
@@ -302,8 +312,9 @@ const Chat = () => {
|
||||
<Box
|
||||
m={media('20px auto', '0 auto')}
|
||||
w={media('100vw', '100%')}
|
||||
maxW={'800px'}
|
||||
maxW={media('800px', 'auto')}
|
||||
boxShadow={'0 -14px 30px rgba(255,255,255,0.6)'}
|
||||
borderTop={media('none', '1px solid rgba(0,0,0,0.1)')}
|
||||
>
|
||||
{lastWordHuman ? (
|
||||
<Box textAlign={'center'}>
|
||||
@@ -349,12 +360,12 @@ const Chat = () => {
|
||||
onChange={(e) => {
|
||||
const textarea = e.target;
|
||||
setInputVal(textarea.value);
|
||||
|
||||
textarea.style.height = textarea.value.split('\n').length * 22 + 'px';
|
||||
textarea.style.height = textareaMinH;
|
||||
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
// 触发快捷发送
|
||||
if (e.keyCode === 13 && !e.shiftKey) {
|
||||
if (isPc && e.keyCode === 13 && !e.shiftKey) {
|
||||
sendPrompt();
|
||||
e.preventDefault();
|
||||
}
|
||||
@@ -382,7 +393,7 @@ const Chat = () => {
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<Loading loading={!chatSiteData} />
|
||||
<Loading />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@@ -1,19 +1,12 @@
|
||||
import React, { useState, Dispatch, useCallback } from 'react';
|
||||
import {
|
||||
FormControl,
|
||||
Box,
|
||||
Input,
|
||||
Button,
|
||||
FormErrorMessage,
|
||||
useToast,
|
||||
Flex
|
||||
} from '@chakra-ui/react';
|
||||
import { FormControl, Box, Input, Button, FormErrorMessage, Flex } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { PageTypeEnum } from '../../../constants/user';
|
||||
import { postFindPassword } from '@/api/user';
|
||||
import { useSendCode } from '@/hooks/useSendCode';
|
||||
import type { ResLogin } from '@/api/response/user';
|
||||
import { useScreen } from '@/hooks/useScreen';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
|
||||
interface Props {
|
||||
setPageType: Dispatch<`${PageTypeEnum}`>;
|
||||
@@ -28,7 +21,7 @@ interface RegisterType {
|
||||
}
|
||||
|
||||
const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const toast = useToast();
|
||||
const { toast } = useToast();
|
||||
const { mediaLgMd } = useScreen();
|
||||
const {
|
||||
register,
|
||||
@@ -57,6 +50,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
async ({ email, code, password }: RegisterType) => {
|
||||
setRequesting(true);
|
||||
try {
|
||||
toast({
|
||||
title: `密码已找回`,
|
||||
status: 'success'
|
||||
});
|
||||
loginSuccess(
|
||||
await postFindPassword({
|
||||
email,
|
||||
@@ -64,11 +61,6 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
password
|
||||
})
|
||||
);
|
||||
toast({
|
||||
title: `密码已找回`,
|
||||
status: 'success',
|
||||
position: 'top'
|
||||
});
|
||||
} catch (error) {
|
||||
typeof error === 'string' &&
|
||||
toast({
|
||||
|
@@ -32,16 +32,16 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
async ({ email, password }: LoginFormType) => {
|
||||
setRequesting(true);
|
||||
try {
|
||||
toast({
|
||||
title: '登录成功',
|
||||
status: 'success'
|
||||
});
|
||||
loginSuccess(
|
||||
await postLogin({
|
||||
email,
|
||||
password
|
||||
})
|
||||
);
|
||||
toast({
|
||||
title: '登录成功',
|
||||
status: 'success'
|
||||
});
|
||||
} catch (error) {
|
||||
typeof error === 'string' &&
|
||||
toast({
|
||||
|
@@ -1,19 +1,12 @@
|
||||
import React, { useState, Dispatch, useCallback } from 'react';
|
||||
import {
|
||||
FormControl,
|
||||
Box,
|
||||
Input,
|
||||
Button,
|
||||
FormErrorMessage,
|
||||
useToast,
|
||||
Flex
|
||||
} from '@chakra-ui/react';
|
||||
import { FormControl, Box, Input, Button, FormErrorMessage, Flex } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { PageTypeEnum } from '@/constants/user';
|
||||
import { postRegister } from '@/api/user';
|
||||
import { useSendCode } from '@/hooks/useSendCode';
|
||||
import type { ResLogin } from '@/api/response/user';
|
||||
import { useScreen } from '@/hooks/useScreen';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
|
||||
interface Props {
|
||||
loginSuccess: (e: ResLogin) => void;
|
||||
@@ -28,7 +21,7 @@ interface RegisterType {
|
||||
}
|
||||
|
||||
const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const toast = useToast();
|
||||
const { toast } = useToast();
|
||||
const { mediaLgMd } = useScreen();
|
||||
const {
|
||||
register,
|
||||
@@ -57,6 +50,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
async ({ email, password, code }: RegisterType) => {
|
||||
setRequesting(true);
|
||||
try {
|
||||
toast({
|
||||
title: `注册成功`,
|
||||
status: 'success'
|
||||
});
|
||||
loginSuccess(
|
||||
await postRegister({
|
||||
email,
|
||||
@@ -64,17 +61,13 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
password
|
||||
})
|
||||
);
|
||||
toast({
|
||||
title: `注册成功`,
|
||||
status: 'success',
|
||||
position: 'top'
|
||||
});
|
||||
} catch (error) {
|
||||
typeof error === 'string' &&
|
||||
toast({
|
||||
title: error,
|
||||
status: 'error',
|
||||
position: 'top'
|
||||
duration: 4000,
|
||||
isClosable: true
|
||||
});
|
||||
}
|
||||
setRequesting(false);
|
||||
|
@@ -1,7 +1,5 @@
|
||||
.loginPage {
|
||||
background: url('/icon/login-bg.svg') no-repeat;
|
||||
background-size: cover;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
user-select: none;
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ const Login = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={styles.loginPage} p={isPc ? '10vh 10vw' : 0}>
|
||||
<Box className={styles.loginPage} h={'100%'} p={isPc ? '10vh 10vw' : 0}>
|
||||
<Flex
|
||||
maxW={'1240px'}
|
||||
m={'auto'}
|
||||
|
@@ -8,29 +8,23 @@ import { useRouter } from 'next/router';
|
||||
import ModelTable from './components/ModelTable';
|
||||
import ModelPhoneList from './components/ModelPhoneList';
|
||||
import { useScreen } from '@/hooks/useScreen';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
|
||||
const ModelList = () => {
|
||||
const { isPc } = useScreen();
|
||||
const router = useRouter();
|
||||
const [models, setModels] = useState<ModelType[]>([]);
|
||||
const [openCreateModel, setOpenCreateModel] = useState(false);
|
||||
const { setLoading } = useGlobalStore();
|
||||
const { Loading, setIsLoading } = useLoading();
|
||||
|
||||
/* 加载模型 */
|
||||
const loadModels = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await getMyModels();
|
||||
const { isLoading } = useQuery(['loadModels'], () => getMyModels(), {
|
||||
onSuccess(res) {
|
||||
if (!res) return;
|
||||
setModels(res);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setLoading(false);
|
||||
}, [setLoading]);
|
||||
useEffect(() => {
|
||||
loadModels();
|
||||
}, [loadModels]);
|
||||
});
|
||||
|
||||
/* 创建成功回调 */
|
||||
const createModelSuccess = useCallback((data: ModelType) => {
|
||||
@@ -40,7 +34,7 @@ const ModelList = () => {
|
||||
/* 点前往聊天预览页 */
|
||||
const handlePreviewChat = useCallback(
|
||||
async (modelId: string) => {
|
||||
setLoading(true);
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const chatId = await getChatSiteId(modelId);
|
||||
|
||||
@@ -50,9 +44,9 @@ const ModelList = () => {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setLoading(false);
|
||||
setIsLoading(false);
|
||||
},
|
||||
[router, setLoading]
|
||||
[router, setIsLoading]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -83,6 +77,7 @@ const ModelList = () => {
|
||||
setCreateModelOpen={setOpenCreateModel}
|
||||
onSuccess={createModelSuccess}
|
||||
/>
|
||||
<Loading loading={isLoading} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -8,7 +8,7 @@ export async function connectToDatabase() {
|
||||
return cachedClient;
|
||||
}
|
||||
|
||||
cachedClient = await mongoose.connect(process.env.MONGODB_UR as string, {
|
||||
cachedClient = await mongoose.connect(process.env.MONGODB_URI as string, {
|
||||
dbName: 'doc_gpt'
|
||||
});
|
||||
|
||||
|
@@ -45,14 +45,6 @@ pre,
|
||||
samp {
|
||||
font-family: couriernew, courier, monospace;
|
||||
}
|
||||
small {
|
||||
font-size: 12px;
|
||||
}
|
||||
ul,
|
||||
ol {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -82,6 +74,9 @@ table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
#__next {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar,
|
||||
::-webkit-scrollbar {
|
||||
|
@@ -8,19 +8,25 @@ export const useCopyData = () => {
|
||||
const { toast } = useToast();
|
||||
return {
|
||||
copyData: (data: string, title: string = '复制成功') => {
|
||||
const clipboardObj = navigator.clipboard;
|
||||
clipboardObj
|
||||
.writeText(data)
|
||||
.then(() => {
|
||||
toast({
|
||||
title,
|
||||
status: 'success',
|
||||
duration: 1000
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
try {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = data;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
toast({
|
||||
title,
|
||||
status: 'success',
|
||||
duration: 1000
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast({
|
||||
title: '复制失败',
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
Reference in New Issue
Block a user