Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
f764d81c
authored
Jul 28, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: iframe embed
parent
5d0c8fa4
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
152 additions
and
134 deletions
+152
-134
client/public/js/iframe.js
+57
-62
client/src/api/chat.ts
+8
-9
client/src/constants/user.ts
+4
-2
client/src/pages/api/openapi/v1/chat/completions.ts
+7
-4
client/src/pages/app/detail/components/OutLink.tsx
+50
-38
client/src/pages/app/list/index.tsx
+1
-1
client/src/pages/chat/components/ToolMenu.tsx
+7
-4
client/src/service/utils/auth.ts
+14
-11
client/src/types/mongoSchema.d.ts
+2
-1
client/src/utils/tools.ts
+2
-2
No files found.
client/public/js/iframe.js
View file @
f764d81c
async
function
embedChatbot
()
{
async
function
embedChatbot
()
{
const
t
=
window
.
difyChatbotConfig
;
const
chatBtnId
=
'fastgpt-chatbot-button'
;
if
(
t
&&
t
.
token
)
{
const
chatWindowId
=
'fastgpt-chatbot-window'
;
var
e
=
!!
t
.
isDev
;
const
script
=
document
.
getElementById
(
'fastgpt-iframe'
);
const
o
=
t
.
baseUrl
||
`https://
${
e
?
'dev.'
:
''
}
udify.app`
,
const
botSrc
=
script
?.
getAttribute
(
'data-src'
);
n
=
`<svg
const
primaryColor
=
script
?.
getAttribute
(
'data-color'
)
||
'#4e83fd'
;
id="openIcon"
width="24"
if
(
!
botSrc
)
{
height="24"
console
.
error
(
`Can't find appid`
);
viewBox="0 0 24 24"
return
;
fill="none"
}
xmlns="http://www.w3.org/2000/svg"
if
(
document
.
getElementById
(
chatBtnId
))
{
>
return
;
<path
}
fill-rule="evenodd"
clip-rule="evenodd"
const
MessageIcon
=
`<?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="1690532785664" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4132" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M512 32C247.04 32 32 224 32 464A410.24 410.24 0 0 0 172.48 768L160 965.12a25.28 25.28 0 0 0 39.04 22.4l168-112A528.64 528.64 0 0 0 512 896c264.96 0 480-192 480-432S776.96 32 512 32z m244.8 416l-361.6 301.76a12.48 12.48 0 0 1-19.84-12.48l59.2-233.92h-160a12.48 12.48 0 0 1-7.36-23.36l361.6-301.76a12.48 12.48 0 0 1 19.84 12.48l-59.2 233.92h160a12.48 12.48 0 0 1 8 22.08z" fill=
${
primaryColor
}
p-id="4133"></path></svg>`
;
d="M7.7586 2L16.2412 2C17.0462 1.99999 17.7105 1.99998 18.2517 2.04419C18.8138 2.09012 19.3305 2.18868 19.8159 2.43598C20.5685 2.81947 21.1804 3.43139 21.5639 4.18404C21.8112 4.66937 21.9098 5.18608 21.9557 5.74818C21.9999 6.28937 21.9999 6.95373 21.9999 7.7587L22 14.1376C22.0004 14.933 22.0007 15.5236 21.8636 16.0353C21.4937 17.4156 20.4155 18.4938 19.0352 18.8637C18.7277 18.9461 18.3917 18.9789 17.9999 18.9918L17.9999 20.371C18 20.6062 18 20.846 17.9822 21.0425C17.9651 21.2305 17.9199 21.5852 17.6722 21.8955C17.3872 22.2525 16.9551 22.4602 16.4983 22.4597C16.1013 22.4593 15.7961 22.273 15.6386 22.1689C15.474 22.06 15.2868 21.9102 15.1031 21.7632L12.69 19.8327C12.1714 19.4178 12.0174 19.3007 11.8575 19.219C11.697 19.137 11.5262 19.0771 11.3496 19.0408C11.1737 19.0047 10.9803 19 10.3162 19H7.75858C6.95362 19 6.28927 19 5.74808 18.9558C5.18598 18.9099 4.66928 18.8113 4.18394 18.564C3.43129 18.1805 2.81937 17.5686 2.43588 16.816C2.18859 16.3306 2.09002 15.8139 2.0441 15.2518C1.99988 14.7106 1.99989 14.0463 1.9999 13.2413V7.75868C1.99989 6.95372 1.99988 6.28936 2.0441 5.74818C2.09002 5.18608 2.18859 4.66937 2.43588 4.18404C2.81937 3.43139 3.43129 2.81947 4.18394 2.43598C4.66928 2.18868 5.18598 2.09012 5.74808 2.04419C6.28927 1.99998 6.95364 1.99999 7.7586 2ZM10.5073 7.5C10.5073 6.67157 9.83575 6 9.00732 6C8.1789 6 7.50732 6.67157 7.50732 7.5C7.50732 8.32843 8.1789 9 9.00732 9C9.83575 9 10.5073 8.32843 10.5073 7.5ZM16.6073 11.7001C16.1669 11.3697 15.5426 11.4577 15.2105 11.8959C15.1488 11.9746 15.081 12.0486 15.0119 12.1207C14.8646 12.2744 14.6432 12.4829 14.3566 12.6913C13.7796 13.111 12.9818 13.5001 12.0073 13.5001C11.0328 13.5001 10.235 13.111 9.65799 12.6913C9.37138 12.4829 9.15004 12.2744 9.00274 12.1207C8.93366 12.0486 8.86581 11.9745 8.80418 11.8959C8.472 11.4577 7.84775 11.3697 7.40732 11.7001C6.96549 12.0314 6.87595 12.6582 7.20732 13.1001C7.20479 13.0968 7.21072 13.1043 7.22094 13.1171C7.24532 13.1478 7.29407 13.2091 7.31068 13.2289C7.36932 13.2987 7.45232 13.3934 7.55877 13.5045C7.77084 13.7258 8.08075 14.0172 8.48165 14.3088C9.27958 14.8891 10.4818 15.5001 12.0073 15.5001C13.5328 15.5001 14.735 14.8891 15.533 14.3088C15.9339 14.0172 16.2438 13.7258 16.4559 13.5045C16.5623 13.3934 16.6453 13.2987 16.704 13.2289C16.7333 13.1939 16.7567 13.165 16.7739 13.1432C17.1193 12.6969 17.0729 12.0493 16.6073 11.7001ZM15.0073 6C15.8358 6 16.5073 6.67157 16.5073 7.5C16.5073 8.32843 15.8358 9 15.0073 9C14.1789 9 13.5073 8.32843 13.5073 7.5C13.5073 6.67157 14.1789 6 15.0073 6Z"
fill="white"
const
CloseIcon
=
`<?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="1690535441526" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6367" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024zM305.956571 370.395429L447.488 512 305.956571 653.604571a45.568 45.568 0 1 0 64.438858 64.438858L512 576.512l141.604571 141.531429a45.568 45.568 0 0 0 64.438858-64.438858L576.512 512l141.531429-141.604571a45.568 45.568 0 1 0-64.438858-64.438858L512 447.488 370.395429 305.956571a45.568 45.568 0 0 0-64.438858 64.438858z" fill=
${
primaryColor
}
p-id="6368"></path></svg>`
;
/>
</svg>`
,
const
ChatBtn
=
document
.
createElement
(
'div'
);
i
=
`<svg
ChatBtn
.
id
=
chatBtnId
;
id="closeIcon"
ChatBtn
.
style
.
cssText
=
width="24"
'position: fixed; bottom: 1rem; right: 1rem; width: 40px; height: 40px; cursor: pointer; z-index: 2147483647; '
;
height="24"
viewBox="0 0 24 24"
const
ChatBtnDiv
=
document
.
createElement
(
'div'
);
fill="none"
ChatBtnDiv
.
style
.
cssText
=
xmlns="http://www.w3.org/2000/svg"
'transition: all 0.2s ease-in-out 0s; left: unset; transform: scale(1); :hover {transform: scale(1.1);} display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 9999;'
;
>
ChatBtnDiv
.
innerHTML
=
MessageIcon
;
<path
d="M18 18L6 6M6 18L18 6"
ChatBtn
.
appendChild
(
ChatBtnDiv
);
stroke="white"
stroke-width="2"
const
iframe
=
document
.
createElement
(
'iframe'
);
stroke-linecap="round"
iframe
.
allow
=
'fullscreen;microphone'
;
stroke-linejoin="round"
iframe
.
title
=
'FastGpt Chat Window'
;
/>
iframe
.
id
=
chatWindowId
;
</svg>`
;
iframe
.
src
=
botSrc
;
if
(
!
document
.
getElementById
(
'dify-chatbot-bubble-button'
))
{
e
=
document
.
createElement
(
'div'
);
iframe
.
style
.
cssText
=
(
e
.
id
=
'dify-chatbot-bubble-button'
),
'visibility: hidden; border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 4rem; right: 1rem; width: 24rem; height: 40rem; max-width: 90vw; max-height: 85vh; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;'
;
(
e
.
style
.
cssText
=
'position: fixed; bottom: 1rem; right: 1rem; width: 50px; height: 50px; border-radius: 25px; background-color: #155EEF; box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 8px 0px; cursor: pointer; z-index: 2147483647; transition: all 0.2s ease-in-out 0s; left: unset; transform: scale(1); :hover {transform: scale(1.1);}'
);
document
.
body
.
appendChild
(
iframe
);
const
d
=
document
.
createElement
(
'div'
);
(
d
.
style
.
cssText
=
iframe
.
onload
=
()
=>
{
'display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;'
),
document
.
body
.
appendChild
(
ChatBtn
);
(
d
.
innerHTML
=
n
),
};
e
.
appendChild
(
d
),
document
.
body
.
appendChild
(
e
),
ChatBtn
.
addEventListener
(
'click'
,
function
()
{
e
.
addEventListener
(
'click'
,
function
()
{
const
chatWindow
=
document
.
getElementById
(
chatWindowId
);
var
e
=
document
.
getElementById
(
'dify-chatbot-bubble-window'
);
e
if
(
!
chatWindow
)
return
;
?
'none'
===
e
.
style
.
display
const
visibilityVal
=
chatWindow
.
style
.
visibility
;
?
((
e
.
style
.
display
=
'block'
),
(
d
.
innerHTML
=
i
))
if
(
visibilityVal
===
'hidden'
)
{
:
((
e
.
style
.
display
=
'none'
),
(
d
.
innerHTML
=
n
))
chatWindow
.
style
.
visibility
=
'unset'
;
:
(((
e
=
document
.
createElement
(
'iframe'
)).
allow
=
'fullscreen;microphone'
),
ChatBtnDiv
.
innerHTML
=
CloseIcon
;
(
e
.
title
=
'dify chatbot bubble window'
),
}
else
{
(
e
.
id
=
'dify-chatbot-bubble-window'
),
chatWindow
.
style
.
visibility
=
'hidden'
;
(
e
.
src
=
o
+
'/chatbot/'
+
t
.
token
),
ChatBtnDiv
.
innerHTML
=
MessageIcon
;
(
e
.
style
.
cssText
=
'border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 5rem; right: 1rem; width: 24rem; height: 40rem; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;'
),
document
.
body
.
appendChild
(
e
),
(
d
.
innerHTML
=
i
));
});
}
}
}
else
console
.
error
(
'difyChatbotConfig is empty or token is not provided'
);
});
}
}
document
.
body
.
onload
=
embedChatbot
;
document
.
body
.
onload
=
embedChatbot
;
client/src/api/chat.ts
View file @
f764d81c
...
@@ -2,9 +2,8 @@ import { GET, POST, DELETE, PUT } from './request';
...
@@ -2,9 +2,8 @@ import { GET, POST, DELETE, PUT } from './request';
import
type
{
ChatHistoryItemType
}
from
'@/types/chat'
;
import
type
{
ChatHistoryItemType
}
from
'@/types/chat'
;
import
type
{
InitChatResponse
,
InitShareChatResponse
}
from
'./response/chat'
;
import
type
{
InitChatResponse
,
InitShareChatResponse
}
from
'./response/chat'
;
import
{
RequestPaging
}
from
'../types/index'
;
import
{
RequestPaging
}
from
'../types/index'
;
import
type
{
ShareChat
Schema
}
from
'@/types/mongoSchema'
;
import
type
{
OutLink
Schema
}
from
'@/types/mongoSchema'
;
import
type
{
ShareChatEditType
}
from
'@/types/app'
;
import
type
{
ShareChatEditType
}
from
'@/types/app'
;
import
type
{
QuoteItemType
}
from
'@/types/chat'
;
import
type
{
Props
as
UpdateHistoryProps
}
from
'@/pages/api/chat/history/updateChatHistory'
;
import
type
{
Props
as
UpdateHistoryProps
}
from
'@/pages/api/chat/history/updateChatHistory'
;
/**
/**
...
@@ -51,6 +50,12 @@ export const putChatHistory = (data: UpdateHistoryProps) =>
...
@@ -51,6 +50,12 @@ export const putChatHistory = (data: UpdateHistoryProps) =>
PUT
(
'/chat/history/updateChatHistory'
,
data
);
PUT
(
'/chat/history/updateChatHistory'
,
data
);
/**
/**
* 初始化分享聊天
*/
export
const
initShareChatInfo
=
(
data
:
{
shareId
:
string
})
=>
GET
<
InitShareChatResponse
>
(
`/chat/shareChat/init`
,
data
);
/**
* create a shareChat
* create a shareChat
*/
*/
export
const
createShareChat
=
(
export
const
createShareChat
=
(
...
@@ -63,15 +68,9 @@ export const createShareChat = (
...
@@ -63,15 +68,9 @@ export const createShareChat = (
* get shareChat
* get shareChat
*/
*/
export
const
getShareChatList
=
(
appId
:
string
)
=>
export
const
getShareChatList
=
(
appId
:
string
)
=>
GET
<
ShareChat
Schema
[]
>
(
`/chat/shareChat/list`
,
{
appId
});
GET
<
OutLink
Schema
[]
>
(
`/chat/shareChat/list`
,
{
appId
});
/**
/**
* delete a shareChat
* delete a shareChat
*/
*/
export
const
delShareChatById
=
(
id
:
string
)
=>
DELETE
(
`/chat/shareChat/delete?id=
${
id
}
`
);
export
const
delShareChatById
=
(
id
:
string
)
=>
DELETE
(
`/chat/shareChat/delete?id=
${
id
}
`
);
/**
* 初始化分享聊天
*/
export
const
initShareChatInfo
=
(
data
:
{
shareId
:
string
})
=>
GET
<
InitShareChatResponse
>
(
`/chat/shareChat/init`
,
data
);
client/src/constants/user.ts
View file @
f764d81c
export
enum
BillSourceEnum
{
export
enum
BillSourceEnum
{
fastgpt
=
'fastgpt'
,
fastgpt
=
'fastgpt'
,
api
=
'api'
api
=
'api'
,
shareLink
=
'shareLink'
}
}
export
enum
PageTypeEnum
{
export
enum
PageTypeEnum
{
login
=
'login'
,
login
=
'login'
,
...
@@ -10,7 +11,8 @@ export enum PageTypeEnum {
...
@@ -10,7 +11,8 @@ export enum PageTypeEnum {
export
const
BillSourceMap
:
Record
<
`
${
BillSourceEnum
}
`
,
string
>
=
{
export
const
BillSourceMap
:
Record
<
`
${
BillSourceEnum
}
`
,
string
>
=
{
[
BillSourceEnum
.
fastgpt
]:
'FastGpt 平台'
,
[
BillSourceEnum
.
fastgpt
]:
'FastGpt 平台'
,
[
BillSourceEnum
.
api
]:
'Api'
[
BillSourceEnum
.
api
]:
'Api'
,
[
BillSourceEnum
.
shareLink
]:
'免登录链接'
};
};
export
enum
PromotionEnum
{
export
enum
PromotionEnum
{
...
...
client/src/pages/api/openapi/v1/chat/completions.ts
View file @
f764d81c
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
authUser
,
authApp
,
authShareChat
}
from
'@/service/utils/auth'
;
import
{
authUser
,
authApp
,
authShareChat
,
AuthUserTypeEnum
}
from
'@/service/utils/auth'
;
import
{
sseErrRes
,
jsonRes
}
from
'@/service/response'
;
import
{
sseErrRes
,
jsonRes
}
from
'@/service/response'
;
import
{
withNextCors
}
from
'@/service/utils/tools'
;
import
{
withNextCors
}
from
'@/service/utils/tools'
;
import
{
ChatRoleEnum
,
ChatSourceEnum
,
sseResponseEventEnum
}
from
'@/constants/chat'
;
import
{
ChatRoleEnum
,
ChatSourceEnum
,
sseResponseEventEnum
}
from
'@/constants/chat'
;
...
@@ -25,7 +25,6 @@ import { pushTaskBill } from '@/service/events/pushBill';
...
@@ -25,7 +25,6 @@ import { pushTaskBill } from '@/service/events/pushBill';
import
{
BillSourceEnum
}
from
'@/constants/user'
;
import
{
BillSourceEnum
}
from
'@/constants/user'
;
import
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
import
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
import
{
UserModelSchema
}
from
'@/types/mongoSchema'
;
import
{
UserModelSchema
}
from
'@/types/mongoSchema'
;
import
{
getAIChatApi
}
from
'@/service/ai/openai'
;
export
type
MessageItemType
=
ChatCompletionRequestMessage
&
{
_id
?:
string
};
export
type
MessageItemType
=
ChatCompletionRequestMessage
&
{
_id
?:
string
};
type
FastGptWebChatProps
=
{
type
FastGptWebChatProps
=
{
...
@@ -84,7 +83,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
...
@@ -84,7 +83,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
if
(
!
user
)
{
if
(
!
user
)
{
throw
new
Error
(
'Account is error'
);
throw
new
Error
(
'Account is error'
);
}
}
if
(
authType
!==
'token'
)
{
if
(
authType
===
AuthUserTypeEnum
.
apikey
||
shareId
)
{
user
.
openaiAccount
=
undefined
;
user
.
openaiAccount
=
undefined
;
}
}
...
@@ -208,7 +207,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
...
@@ -208,7 +207,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
appName
:
app
.
name
,
appName
:
app
.
name
,
appId
,
appId
,
userId
,
userId
,
source
:
authType
===
'apikey'
?
BillSourceEnum
.
api
:
BillSourceEnum
.
fastgpt
,
source
:
(()
=>
{
if
(
authType
===
'apikey'
)
return
BillSourceEnum
.
api
;
if
(
shareId
)
return
BillSourceEnum
.
shareLink
;
return
BillSourceEnum
.
fastgpt
;
})(),
response
:
responseData
,
response
:
responseData
,
shareId
shareId
});
});
...
...
client/src/pages/app/detail/components/OutLink.tsx
View file @
f764d81c
...
@@ -19,11 +19,10 @@ import {
...
@@ -19,11 +19,10 @@ import {
}
from
'@chakra-ui/react'
;
}
from
'@chakra-ui/react'
;
import
{
QuestionOutlineIcon
}
from
'@chakra-ui/icons'
;
import
{
QuestionOutlineIcon
}
from
'@chakra-ui/icons'
;
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
useLoading
}
from
'@/hooks/useLoading'
;
import
{
useLoading
}
from
'@/hooks/useLoading'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
getShareChatList
,
delShareChatById
,
createShareChat
}
from
'@/api/chat'
;
import
{
getShareChatList
,
delShareChatById
,
createShareChat
}
from
'@/api/chat'
;
import
{
formatTimeToChatTime
,
useCopyData
,
getErrText
}
from
'@/utils/tools'
;
import
{
formatTimeToChatTime
,
useCopyData
}
from
'@/utils/tools'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
defaultShareChat
}
from
'@/constants/model'
;
import
{
defaultShareChat
}
from
'@/constants/model'
;
import
type
{
ShareChatEditType
}
from
'@/types/app'
;
import
type
{
ShareChatEditType
}
from
'@/types/app'
;
...
@@ -67,8 +66,8 @@ const Share = ({ appId }: { appId: string }) => {
...
@@ -67,8 +66,8 @@ const Share = ({ appId }: { appId: string }) => {
onSuccess
(
id
)
{
onSuccess
(
id
)
{
onCloseCreateShareChat
();
onCloseCreateShareChat
();
refetchShareChatList
();
refetchShareChatList
();
const
url
=
`
对话地址为:
${
location
.
origin
}
/chat/share?shareId=
${
id
}
`
;
const
url
=
`
${
location
.
origin
}
/chat/share?shareId=
${
id
}
`
;
copyData
(
url
,
'
已复制分享地址
'
);
copyData
(
url
,
'
创建成功。已复制分享地址,可直接分享使用
'
);
resetShareChat
(
defaultShareChat
);
resetShareChat
(
defaultShareChat
);
}
}
});
});
...
@@ -116,40 +115,53 @@ const Share = ({ appId }: { appId: string }) => {
...
@@ -116,40 +115,53 @@ const Share = ({ appId }: { appId: string }) => {
<
Td
>
{
item
.
name
}
</
Td
>
<
Td
>
{
item
.
name
}
</
Td
>
<
Td
>
{
formatPrice
(
item
.
total
)
}
元
</
Td
>
<
Td
>
{
formatPrice
(
item
.
total
)
}
元
</
Td
>
<
Td
>
{
item
.
lastTime
?
formatTimeToChatTime
(
item
.
lastTime
)
:
'未使用'
}
</
Td
>
<
Td
>
{
item
.
lastTime
?
formatTimeToChatTime
(
item
.
lastTime
)
:
'未使用'
}
</
Td
>
<
Td
>
<
Td
display=
{
'flex'
}
alignItems=
{
'center'
}
>
<
Flex
>
<
MyTooltip
label=
{
'嵌入网页'
}
>
<
MyTooltip
label=
{
'复制分享链接'
}
>
<
MyIcon
<
MyIcon
mr=
{
4
}
mr=
{
3
}
name=
"apiLight"
name=
"copy"
w=
{
'14px'
}
w=
{
'14px'
}
cursor=
{
'pointer'
}
cursor=
{
'pointer'
}
_hover=
{
{
color
:
'myBlue.600'
}
}
_hover=
{
{
color
:
'myBlue.600'
}
}
onClick=
{
()
=>
{
onClick=
{
()
=>
{
const
url
=
`${location.origin}/chat/share?shareId=${item.shareId}`
;
const
url
=
`${location.origin}/chat/share?shareId=${item.shareId}`
;
const
src
=
`${location.origin}/js/iframe.js`
;
copyData
(
url
,
'已复制分享链接'
);
const
script
=
`<script src="${src}" id="fastgpt-iframe" data-src="${url}" data-color="#4e83fd"></script>`
;
}
}
copyData
(
script
,
'已复制嵌入 Script,可在应用 HTML 底部嵌入'
,
3000
);
/>
}
}
</
MyTooltip
>
/>
<
MyTooltip
label=
{
'删除链接'
}
>
</
MyTooltip
>
<
MyIcon
<
MyTooltip
label=
{
'复制分享链接'
}
>
name=
"delete"
<
MyIcon
w=
{
'14px'
}
mr=
{
4
}
cursor=
{
'pointer'
}
name=
"copy"
_hover=
{
{
color
:
'red'
}
}
w=
{
'14px'
}
onClick=
{
async
()
=>
{
cursor=
{
'pointer'
}
setIsLoading
(
true
);
_hover=
{
{
color
:
'myBlue.600'
}
}
try
{
onClick=
{
()
=>
{
await
delShareChatById
(
item
.
_id
);
const
url
=
`${location.origin}/chat/share?shareId=${item.shareId}`
;
refetchShareChatList
();
copyData
(
url
,
'已复制分享链接,可直接分享使用'
);
}
catch
(
error
)
{
}
}
console
.
log
(
error
);
/>
}
</
MyTooltip
>
setIsLoading
(
false
);
<
MyTooltip
label=
{
'删除链接'
}
>
}
}
<
MyIcon
/>
name=
"delete"
</
MyTooltip
>
w=
{
'14px'
}
</
Flex
>
cursor=
{
'pointer'
}
_hover=
{
{
color
:
'red'
}
}
onClick=
{
async
()
=>
{
setIsLoading
(
true
);
try
{
await
delShareChatById
(
item
.
_id
);
refetchShareChatList
();
}
catch
(
error
)
{
console
.
log
(
error
);
}
setIsLoading
(
false
);
}
}
/>
</
MyTooltip
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
))
}
))
}
...
...
client/src/pages/app/list/index.tsx
View file @
f764d81c
import
React
,
{
useCallback
}
from
'react'
;
import
React
,
{
useCallback
,
useEffect
}
from
'react'
;
import
{
import
{
Box
,
Box
,
Grid
,
Grid
,
...
...
client/src/pages/chat/components/ToolMenu.tsx
View file @
f764d81c
...
@@ -8,7 +8,7 @@ import { useRouter } from 'next/router';
...
@@ -8,7 +8,7 @@ import { useRouter } from 'next/router';
const
ToolMenu
=
({
history
}:
{
history
:
ChatItemType
[]
})
=>
{
const
ToolMenu
=
({
history
}:
{
history
:
ChatItemType
[]
})
=>
{
const
{
onExportChat
}
=
useChatBox
();
const
{
onExportChat
}
=
useChatBox
();
const
router
=
useRouter
();
const
router
=
useRouter
();
const
{
appId
}
=
router
.
query
;
const
{
appId
,
shareId
}
=
router
.
query
;
const
menuList
=
useMemo
(
const
menuList
=
useMemo
(
()
=>
[
()
=>
[
...
@@ -18,7 +18,8 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
...
@@ -18,7 +18,8 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
onClick
:
()
=>
{
onClick
:
()
=>
{
router
.
replace
({
router
.
replace
({
query
:
{
query
:
{
appId
appId
,
shareId
}
}
});
});
}
}
...
@@ -35,7 +36,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
...
@@ -35,7 +36,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
},
},
{
icon
:
'pdf'
,
label
:
'PDF导出'
,
onClick
:
()
=>
onExportChat
({
type
:
'pdf'
,
history
})
}
{
icon
:
'pdf'
,
label
:
'PDF导出'
,
onClick
:
()
=>
onExportChat
({
type
:
'pdf'
,
history
})
}
],
],
[
appId
,
history
,
onExportChat
,
router
]
[
appId
,
history
,
onExportChat
,
router
,
shareId
]
);
);
return
history
.
length
>
0
?
(
return
history
.
length
>
0
?
(
...
@@ -59,7 +60,9 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
...
@@ -59,7 +60,9 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
))
}
))
}
</
MenuList
>
</
MenuList
>
</
Menu
>
</
Menu
>
)
:
null
;
)
:
(
<
Box
w=
{
'28px'
}
h=
{
'28px'
}
/>
);
};
};
export
default
ToolMenu
;
export
default
ToolMenu
;
client/src/service/utils/auth.ts
View file @
f764d81c
...
@@ -2,11 +2,14 @@ import type { NextApiRequest } from 'next';
...
@@ -2,11 +2,14 @@ import type { NextApiRequest } from 'next';
import
jwt
from
'jsonwebtoken'
;
import
jwt
from
'jsonwebtoken'
;
import
Cookie
from
'cookie'
;
import
Cookie
from
'cookie'
;
import
{
App
,
OpenApi
,
User
,
OutLink
,
KB
}
from
'../mongo'
;
import
{
App
,
OpenApi
,
User
,
OutLink
,
KB
}
from
'../mongo'
;
import
type
{
AppSchema
,
UserModelSchema
}
from
'@/types/mongoSchema'
;
import
type
{
AppSchema
}
from
'@/types/mongoSchema'
;
import
{
formatPrice
}
from
'@/utils/user'
;
import
{
ERROR_ENUM
}
from
'../errorCode'
;
import
{
ERROR_ENUM
}
from
'../errorCode'
;
export
type
AuthType
=
'token'
|
'root'
|
'apikey'
;
export
enum
AuthUserTypeEnum
{
token
=
'token'
,
root
=
'root'
,
apikey
=
'apikey'
}
export
const
parseCookie
=
(
cookie
?:
string
):
Promise
<
string
>
=>
{
export
const
parseCookie
=
(
cookie
?:
string
):
Promise
<
string
>
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
...
@@ -124,28 +127,28 @@ export const authUser = async ({
...
@@ -124,28 +127,28 @@ export const authUser = async ({
let
uid
=
''
;
let
uid
=
''
;
let
appId
=
''
;
let
appId
=
''
;
let
authType
:
AuthType
=
'token'
;
let
authType
:
`
${
AuthUserTypeEnum
}
`
=
AuthUserTypeEnum
.
token
;
if
(
authToken
)
{
if
(
authToken
)
{
uid
=
await
parseCookie
(
cookie
);
uid
=
await
parseCookie
(
cookie
);
authType
=
'token'
;
authType
=
AuthUserTypeEnum
.
token
;
}
else
if
(
authRoot
)
{
}
else
if
(
authRoot
)
{
uid
=
await
parseRootKey
(
rootkey
,
userid
);
uid
=
await
parseRootKey
(
rootkey
,
userid
);
authType
=
'root'
;
authType
=
AuthUserTypeEnum
.
root
;
}
else
if
(
cookie
)
{
}
else
if
(
cookie
)
{
uid
=
await
parseCookie
(
cookie
);
uid
=
await
parseCookie
(
cookie
);
authType
=
'token'
;
authType
=
AuthUserTypeEnum
.
token
;
}
else
if
(
apikey
)
{
}
else
if
(
apikey
)
{
uid
=
await
parseOpenApiKey
(
apikey
);
uid
=
await
parseOpenApiKey
(
apikey
);
authType
=
'apikey'
;
authType
=
AuthUserTypeEnum
.
apikey
;
}
else
if
(
authorization
)
{
}
else
if
(
authorization
)
{
const
authResponse
=
await
parseAuthorization
(
authorization
);
const
authResponse
=
await
parseAuthorization
(
authorization
);
uid
=
authResponse
.
uid
;
uid
=
authResponse
.
uid
;
appId
=
authResponse
.
appId
;
appId
=
authResponse
.
appId
;
authType
=
'apikey'
;
authType
=
AuthUserTypeEnum
.
apikey
;
}
else
if
(
rootkey
)
{
}
else
if
(
rootkey
)
{
uid
=
await
parseRootKey
(
rootkey
,
userid
);
uid
=
await
parseRootKey
(
rootkey
,
userid
);
authType
=
'root'
;
authType
=
AuthUserTypeEnum
.
root
;
}
else
{
}
else
{
return
Promise
.
reject
(
ERROR_ENUM
.
unAuthorization
);
return
Promise
.
reject
(
ERROR_ENUM
.
unAuthorization
);
}
}
...
@@ -229,6 +232,6 @@ export const authShareChat = async ({ shareId }: { shareId: string }) => {
...
@@ -229,6 +232,6 @@ export const authShareChat = async ({ shareId }: { shareId: string }) => {
user
,
user
,
userId
:
String
(
shareChat
.
userId
),
userId
:
String
(
shareChat
.
userId
),
appId
:
String
(
shareChat
.
appId
),
appId
:
String
(
shareChat
.
appId
),
authType
:
'token'
as
AuthType
authType
:
AuthUserTypeEnum
.
token
};
};
};
};
client/src/types/mongoSchema.d.ts
View file @
f764d81c
...
@@ -4,7 +4,7 @@ import type { DataType } from './data';
...
@@ -4,7 +4,7 @@ import type { DataType } from './data';
import
{
BillSourceEnum
,
InformTypeEnum
}
from
'@/constants/user'
;
import
{
BillSourceEnum
,
InformTypeEnum
}
from
'@/constants/user'
;
import
{
TrainingModeEnum
}
from
'@/constants/plugin'
;
import
{
TrainingModeEnum
}
from
'@/constants/plugin'
;
import
type
{
AppModuleItemType
}
from
'./app'
;
import
type
{
AppModuleItemType
}
from
'./app'
;
import
{
ChatSourceEnum
}
from
'@/constants/chat'
;
import
{
ChatSourceEnum
,
OutLinkTypeEnum
}
from
'@/constants/chat'
;
export
interface
UserModelSchema
{
export
interface
UserModelSchema
{
_id
:
string
;
_id
:
string
;
...
@@ -144,6 +144,7 @@ export interface OutLinkSchema {
...
@@ -144,6 +144,7 @@ export interface OutLinkSchema {
name
:
string
;
name
:
string
;
total
:
number
;
total
:
number
;
lastTime
:
Date
;
lastTime
:
Date
;
type
:
`
${
OutLinkTypeEnum
}
`
;
}
}
export
interface
kbSchema
{
export
interface
kbSchema
{
...
...
client/src/utils/tools.ts
View file @
f764d81c
...
@@ -9,7 +9,7 @@ export const useCopyData = () => {
...
@@ -9,7 +9,7 @@ export const useCopyData = () => {
const
{
toast
}
=
useToast
();
const
{
toast
}
=
useToast
();
return
{
return
{
copyData
:
async
(
data
:
string
,
title
:
string
=
'复制成功'
)
=>
{
copyData
:
async
(
data
:
string
,
title
:
string
=
'复制成功'
,
duration
=
1000
)
=>
{
try
{
try
{
if
(
navigator
.
clipboard
)
{
if
(
navigator
.
clipboard
)
{
await
navigator
.
clipboard
.
writeText
(
data
);
await
navigator
.
clipboard
.
writeText
(
data
);
...
@@ -28,7 +28,7 @@ export const useCopyData = () => {
...
@@ -28,7 +28,7 @@ export const useCopyData = () => {
toast
({
toast
({
title
,
title
,
status
:
'success'
,
status
:
'success'
,
duration
:
1000
duration
});
});
}
}
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment