From f65a72821b38c583fd15d4cab116ff7ea6dce20a Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Fri, 28 Jul 2023 09:38:50 +0800 Subject: [PATCH] perf: share link --- client/public/js/iframe.js | 66 +++++++++++++++++++ .../components/Icon/icons/outlink/iframe.svg | 1 + .../icons/outlink/iframe.svg:Zone.Identifier | 0 .../components/Icon/icons/outlink/share.svg | 1 + client/src/components/Icon/index.tsx | 4 +- client/src/components/Radio/index.tsx | 12 +++- client/src/constants/chat.ts | 5 ++ client/src/pages/api/app/del.ts | 4 +- client/src/pages/api/chat/shareChat/create.ts | 4 +- client/src/pages/api/chat/shareChat/delete.ts | 4 +- client/src/pages/api/chat/shareChat/init.ts | 4 +- client/src/pages/api/chat/shareChat/list.ts | 4 +- .../pages/api/openapi/v1/chat/completions.ts | 3 +- .../app/detail/components/BasicEdit/index.tsx | 4 +- .../components/{Share.tsx => OutLink.tsx} | 59 ++++++++++++++--- client/src/pages/app/detail/index.tsx | 8 +-- client/src/pages/chat/share.tsx | 4 +- client/src/service/events/pushBill.ts | 4 +- .../models/{shareChat.ts => outLink.ts} | 12 ++-- client/src/service/mongo.ts | 2 +- client/src/service/utils/auth.ts | 4 +- client/src/types/mongoSchema.d.ts | 2 +- 22 files changed, 171 insertions(+), 40 deletions(-) create mode 100644 client/public/js/iframe.js create mode 100644 client/src/components/Icon/icons/outlink/iframe.svg create mode 100644 client/src/components/Icon/icons/outlink/iframe.svg:Zone.Identifier create mode 100644 client/src/components/Icon/icons/outlink/share.svg rename client/src/pages/app/detail/components/{Share.tsx => OutLink.tsx} (80%) rename client/src/service/models/{shareChat.ts => outLink.ts} (57%) diff --git a/client/public/js/iframe.js b/client/public/js/iframe.js new file mode 100644 index 000000000..2490ba73d --- /dev/null +++ b/client/public/js/iframe.js @@ -0,0 +1,66 @@ +async function embedChatbot() { + const t = window.difyChatbotConfig; + if (t && t.token) { + var e = !!t.isDev; + const o = t.baseUrl || `https://${e ? 'dev.' : ''}udify.app`, + n = ` + + `, + i = ` + + `; + if (!document.getElementById('dify-chatbot-bubble-button')) { + e = document.createElement('div'); + (e.id = 'dify-chatbot-bubble-button'), + (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);}'); + const d = document.createElement('div'); + (d.style.cssText = + 'display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;'), + (d.innerHTML = n), + e.appendChild(d), + document.body.appendChild(e), + e.addEventListener('click', function () { + var e = document.getElementById('dify-chatbot-bubble-window'); + e + ? 'none' === e.style.display + ? ((e.style.display = 'block'), (d.innerHTML = i)) + : ((e.style.display = 'none'), (d.innerHTML = n)) + : (((e = document.createElement('iframe')).allow = 'fullscreen;microphone'), + (e.title = 'dify chatbot bubble window'), + (e.id = 'dify-chatbot-bubble-window'), + (e.src = o + '/chatbot/' + t.token), + (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; diff --git a/client/src/components/Icon/icons/outlink/iframe.svg b/client/src/components/Icon/icons/outlink/iframe.svg new file mode 100644 index 000000000..63fa649ba --- /dev/null +++ b/client/src/components/Icon/icons/outlink/iframe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/Icon/icons/outlink/iframe.svg:Zone.Identifier b/client/src/components/Icon/icons/outlink/iframe.svg:Zone.Identifier new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/components/Icon/icons/outlink/share.svg b/client/src/components/Icon/icons/outlink/share.svg new file mode 100644 index 000000000..04b18a985 --- /dev/null +++ b/client/src/components/Icon/icons/outlink/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/Icon/index.tsx b/client/src/components/Icon/index.tsx index 8efdd5edc..ed6a745e0 100644 --- a/client/src/components/Icon/index.tsx +++ b/client/src/components/Icon/index.tsx @@ -70,7 +70,9 @@ const map = { loginoutLight: require('./icons/light/loginout.svg').default, chatModelTag: require('./icons/light/chatModelTag.svg').default, language_en: require('./icons/language/en.svg').default, - language_zh: require('./icons/language/zh.svg').default + language_zh: require('./icons/language/zh.svg').default, + outlink_share: require('./icons/outlink/share.svg').default, + outlink_iframe: require('./icons/outlink/iframe.svg').default }; export type IconName = keyof typeof map; diff --git a/client/src/components/Radio/index.tsx b/client/src/components/Radio/index.tsx index a3c056885..c022634a3 100644 --- a/client/src/components/Radio/index.tsx +++ b/client/src/components/Radio/index.tsx @@ -6,12 +6,20 @@ import MyIcon from '@/components/Icon'; // @ts-ignore interface Props extends GridProps { list: { icon?: string; title: string; desc?: string; value: string | number }[]; + iconSize?: string; align?: 'top' | 'center'; value: string | number; onChange: (e: string | number) => void; } -const MyRadio = ({ list, value, align = 'center', onChange, ...props }: Props) => { +const MyRadio = ({ + list, + value, + align = 'center', + iconSize = '18px', + onChange, + ...props +}: Props) => { const theme = useTheme(); return ( @@ -60,7 +68,7 @@ const MyRadio = ({ list, value, align = 'center', onChange, ...props }: Props) = }} onClick={() => onChange(item.value)} > - {!!item.icon && } + {!!item.icon && } {item.title} {!!item.desc && ( diff --git a/client/src/constants/chat.ts b/client/src/constants/chat.ts index 7f3be2207..819bbac0f 100644 --- a/client/src/constants/chat.ts +++ b/client/src/constants/chat.ts @@ -57,5 +57,10 @@ export enum ChatModuleEnum { 'CQ' = 'Classify Question' } +export enum OutLinkTypeEnum { + 'share' = 'share', + 'iframe' = 'iframe' +} + export const HUMAN_ICON = `https://fastgpt.run/icon/human.png`; export const LOGO_ICON = `https://fastgpt.run/icon/logo.png`; diff --git a/client/src/pages/api/app/del.ts b/client/src/pages/api/app/del.ts index 16778c9ec..819f07fbf 100644 --- a/client/src/pages/api/app/del.ts +++ b/client/src/pages/api/app/del.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { Chat, App, connectToDatabase, Collection, ShareChat } from '@/service/mongo'; +import { Chat, App, connectToDatabase, Collection, OutLink } from '@/service/mongo'; import { authUser } from '@/service/utils/auth'; import { authApp } from '@/service/utils/auth'; @@ -35,7 +35,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< }); // 删除分享链接 - await ShareChat.deleteMany({ + await OutLink.deleteMany({ appId }); diff --git a/client/src/pages/api/chat/shareChat/create.ts b/client/src/pages/api/chat/shareChat/create.ts index 5a9c17302..4c8eb5f10 100644 --- a/client/src/pages/api/chat/shareChat/create.ts +++ b/client/src/pages/api/chat/shareChat/create.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { connectToDatabase, ShareChat } from '@/service/mongo'; +import { connectToDatabase, OutLink } from '@/service/mongo'; import { authApp, authUser } from '@/service/utils/auth'; import type { ShareChatEditType } from '@/types/app'; import { customAlphabet } from 'nanoid'; @@ -23,7 +23,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }); const shareId = nanoid(); - await ShareChat.create({ + await OutLink.create({ shareId, userId, appId, diff --git a/client/src/pages/api/chat/shareChat/delete.ts b/client/src/pages/api/chat/shareChat/delete.ts index 5ca33cbed..081795850 100644 --- a/client/src/pages/api/chat/shareChat/delete.ts +++ b/client/src/pages/api/chat/shareChat/delete.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { connectToDatabase, ShareChat } from '@/service/mongo'; +import { connectToDatabase, OutLink } from '@/service/mongo'; import { authUser } from '@/service/utils/auth'; /* delete a shareChat by shareChatId */ @@ -14,7 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const { userId } = await authUser({ req, authToken: true }); - await ShareChat.findOneAndRemove({ + await OutLink.findOneAndRemove({ _id: id, userId }); diff --git a/client/src/pages/api/chat/shareChat/init.ts b/client/src/pages/api/chat/shareChat/init.ts index 9bdbb0b35..d4867fc3e 100644 --- a/client/src/pages/api/chat/shareChat/init.ts +++ b/client/src/pages/api/chat/shareChat/init.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { connectToDatabase, ShareChat, User } from '@/service/mongo'; +import { connectToDatabase, OutLink, User } from '@/service/mongo'; import type { InitShareChatResponse } from '@/api/response/chat'; import { authApp } from '@/service/utils/auth'; import { HUMAN_ICON } from '@/constants/chat'; @@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await connectToDatabase(); // get shareChat - const shareChat = await ShareChat.findOne({ shareId }); + const shareChat = await OutLink.findOne({ shareId }); if (!shareChat) { return jsonRes(res, { diff --git a/client/src/pages/api/chat/shareChat/list.ts b/client/src/pages/api/chat/shareChat/list.ts index ba44729da..b080ea8b4 100644 --- a/client/src/pages/api/chat/shareChat/list.ts +++ b/client/src/pages/api/chat/shareChat/list.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { connectToDatabase, ShareChat } from '@/service/mongo'; +import { connectToDatabase, OutLink } from '@/service/mongo'; import { authUser } from '@/service/utils/auth'; import { hashPassword } from '@/service/utils/tools'; @@ -15,7 +15,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const { userId } = await authUser({ req, authToken: true }); - const data = await ShareChat.find({ + const data = await OutLink.find({ appId, userId }).sort({ diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts index 93b26e56f..1fc7d7a46 100644 --- a/client/src/pages/api/openapi/v1/chat/completions.ts +++ b/client/src/pages/api/openapi/v1/chat/completions.ts @@ -198,7 +198,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex appId, userId, source: authType === 'apikey' ? BillSourceEnum.api : BillSourceEnum.fastgpt, - response: responseData + response: responseData, + shareId }); } catch (err: any) { if (stream) { diff --git a/client/src/pages/app/detail/components/BasicEdit/index.tsx b/client/src/pages/app/detail/components/BasicEdit/index.tsx index 435d51182..30f688b8f 100644 --- a/client/src/pages/app/detail/components/BasicEdit/index.tsx +++ b/client/src/pages/app/detail/components/BasicEdit/index.tsx @@ -261,12 +261,12 @@ const Settings = ({ appId }: { appId: string }) => { router.replace({ query: { appId, - currentTab: 'share' + currentTab: 'outLink' } }); }} > - 分享 + 外接 @@ -118,7 +118,7 @@ const Share = ({ appId }: { appId: string }) => { {item.lastTime ? formatTimeToChatTime(item.lastTime) : '未使用'} - + { _hover={{ color: 'myBlue.600' }} onClick={() => { const url = `${location.origin}/chat/share?shareId=${item.shareId}`; - copyData(url, '已复制分享地址'); + copyData(url, '已复制分享链接'); }} /> @@ -205,4 +205,47 @@ const Share = ({ appId }: { appId: string }) => { ); }; -export default Share; +enum LinkTypeEnum { + share = 'share', + iframe = 'iframe' +} + +const OutLink = ({ appId }: { appId: string }) => { + const theme = useTheme(); + + const [linkType, setLinkType] = useState<`${LinkTypeEnum}`>(LinkTypeEnum.share); + + return ( + + + 外部使用途径 + + + setLinkType(e as `${LinkTypeEnum}`)} + /> + + + {linkType === LinkTypeEnum.share && } + + ); +}; + +export default OutLink; diff --git a/client/src/pages/app/detail/index.tsx b/client/src/pages/app/detail/index.tsx index 27eb7c8b0..27efbe464 100644 --- a/client/src/pages/app/detail/index.tsx +++ b/client/src/pages/app/detail/index.tsx @@ -20,7 +20,7 @@ const AdEdit = dynamic(() => import('./components/AdEdit'), { ssr: false, loading: () => }); -const Share = dynamic(() => import('./components/Share'), { +const OutLink = dynamic(() => import('./components/OutLink'), { ssr: false }); const API = dynamic(() => import('./components/API'), { @@ -30,7 +30,7 @@ const API = dynamic(() => import('./components/API'), { enum TabEnum { 'basicEdit' = 'basicEdit', 'adEdit' = 'adEdit', - 'share' = 'share', + 'outLink' = 'outLink', 'API' = 'API' } @@ -57,7 +57,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => { () => [ { label: '简易配置', id: TabEnum.basicEdit, icon: 'overviewLight' }, { label: '高级编排', id: TabEnum.adEdit, icon: 'settingLight' }, - { label: '链接分享', id: TabEnum.share, icon: 'shareLight' }, + { label: '外部使用', id: TabEnum.outLink, icon: 'shareLight' }, { label: 'API访问', id: TabEnum.API, icon: 'apiLight' }, { label: '立即对话', id: 'startChat', icon: 'chat' } ], @@ -178,7 +178,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => { /> )} {currentTab === TabEnum.API && } - {currentTab === TabEnum.share && } + {currentTab === TabEnum.outLink && } diff --git a/client/src/pages/chat/share.tsx b/client/src/pages/chat/share.tsx index 5130fe437..fd681dfda 100644 --- a/client/src/pages/chat/share.tsx +++ b/client/src/pages/chat/share.tsx @@ -20,7 +20,7 @@ import ChatHeader from './components/ChatHeader'; import ChatHistorySlider from './components/ChatHistorySlider'; import { serviceSideProps } from '@/utils/i18n'; -const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) => { +const OutLink = ({ shareId, chatId }: { shareId: string; chatId: string }) => { const router = useRouter(); const { toast } = useToast(); const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure(); @@ -250,4 +250,4 @@ export async function getServerSideProps(context: any) { }; } -export default ShareChat; +export default OutLink; diff --git a/client/src/service/events/pushBill.ts b/client/src/service/events/pushBill.ts index dc1d4f622..709298ccb 100644 --- a/client/src/service/events/pushBill.ts +++ b/client/src/service/events/pushBill.ts @@ -1,4 +1,4 @@ -import { connectToDatabase, Bill, User, ShareChat } from '../mongo'; +import { connectToDatabase, Bill, User, OutLink } from '../mongo'; import { BillSourceEnum } from '@/constants/user'; import { getModel } from '../utils/data'; import { ChatHistoryItemResType } from '@/types/chat'; @@ -59,7 +59,7 @@ export const updateShareChatBill = async ({ total: number; }) => { try { - await ShareChat.findOneAndUpdate( + await OutLink.findOneAndUpdate( { shareId }, { $inc: { total }, diff --git a/client/src/service/models/shareChat.ts b/client/src/service/models/outLink.ts similarity index 57% rename from client/src/service/models/shareChat.ts rename to client/src/service/models/outLink.ts index a9adc3ef0..ba46ac7d4 100644 --- a/client/src/service/models/shareChat.ts +++ b/client/src/service/models/outLink.ts @@ -1,7 +1,8 @@ import { Schema, model, models, Model } from 'mongoose'; -import { ShareChatSchema as ShareChatSchemaType } from '@/types/mongoSchema'; +import { OutLinkSchema as SchmaType } from '@/types/mongoSchema'; +import { OutLinkTypeEnum } from '@/constants/chat'; -const ShareChatSchema = new Schema({ +const OutLinkSchema = new Schema({ shareId: { type: String, required: true @@ -16,6 +17,10 @@ const ShareChatSchema = new Schema({ ref: 'model', required: true }, + type: { + type: String, + default: OutLinkTypeEnum.share + }, name: { type: String, required: true @@ -29,5 +34,4 @@ const ShareChatSchema = new Schema({ } }); -export const ShareChat: Model = - models['shareChat'] || model('shareChat', ShareChatSchema); +export const OutLink: Model = models['outlinks'] || model('outlinks', OutLinkSchema); diff --git a/client/src/service/mongo.ts b/client/src/service/mongo.ts index 723dd1e1b..26c18caf8 100644 --- a/client/src/service/mongo.ts +++ b/client/src/service/mongo.ts @@ -120,7 +120,7 @@ export * from './models/trainingData'; export * from './models/openapi'; export * from './models/promotionRecord'; export * from './models/collection'; -export * from './models/shareChat'; +export * from './models/outLink'; export * from './models/kb'; export * from './models/inform'; export * from './models/image'; diff --git a/client/src/service/utils/auth.ts b/client/src/service/utils/auth.ts index fb920bc39..73123d1e0 100644 --- a/client/src/service/utils/auth.ts +++ b/client/src/service/utils/auth.ts @@ -1,7 +1,7 @@ import type { NextApiRequest } from 'next'; import jwt from 'jsonwebtoken'; import Cookie from 'cookie'; -import { App, OpenApi, User, ShareChat, KB } from '../mongo'; +import { App, OpenApi, User, OutLink, KB } from '../mongo'; import type { AppSchema } from '@/types/mongoSchema'; import { formatPrice } from '@/utils/user'; import { ERROR_ENUM } from '../errorCode'; @@ -216,7 +216,7 @@ export const authKb = async ({ kbId, userId }: { kbId: string; userId: string }) export const authShareChat = async ({ shareId }: { shareId: string }) => { // get shareChat - const shareChat = await ShareChat.findOne({ shareId }); + const shareChat = await OutLink.findOne({ shareId }); if (!shareChat) { return Promise.reject('分享链接已失效'); diff --git a/client/src/types/mongoSchema.d.ts b/client/src/types/mongoSchema.d.ts index f35c987ae..45cda9630 100644 --- a/client/src/types/mongoSchema.d.ts +++ b/client/src/types/mongoSchema.d.ts @@ -135,7 +135,7 @@ export interface PromotionRecordSchema { amount: number; } -export interface ShareChatSchema { +export interface OutLinkSchema { _id: string; shareId: string; userId: string;