mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 16:33:49 +00:00
perf: share link
This commit is contained in:
1
client/src/components/Icon/icons/outlink/iframe.svg
Normal file
1
client/src/components/Icon/icons/outlink/iframe.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="1690507072538" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2735" xmlns:xlink="http://www.w3.org/1999/xlink" width="74.625" height="64"><path d="M1095.111111 47.388444A66.389333 66.389333 0 0 1 1161.443556 113.777778v796.444444a66.389333 66.389333 0 0 1-66.332445 66.389334H99.555556A66.389333 66.389333 0 0 1 33.166222 910.222222V113.777778A66.389333 66.389333 0 0 1 99.555556 47.388444h995.555555z m-33.223111 199.111112H132.721778a33.166222 33.166222 0 0 0-33.166222 33.223111v597.333333a33.166222 33.166222 0 0 0 33.166222 33.166222h929.166222a33.166222 33.166222 0 0 0 33.223111-33.166222v-597.333333a33.223111 33.223111 0 0 0-33.223111-33.223111zM165.888 113.777778a33.166222 33.166222 0 1 0 0 66.389333 33.166222 33.166222 0 0 0 0-66.389333z m99.555556 0a33.166222 33.166222 0 1 0 0 66.389333 33.166222 33.166222 0 0 0 0-66.389333z m99.555555 0a33.166222 33.166222 0 1 0 0 66.389333 33.166222 33.166222 0 0 0 0-66.389333z" fill="#21D4ED" p-id="2736"></path><path d="M530.944 445.610667H995.555556c22.129778 0 33.166222 11.093333 33.166222 33.223111v331.832889c0 22.129778-11.036444 33.166222-33.166222 33.166222H530.944c-22.129778 0-33.166222-11.036444-33.166222-33.166222V478.833778c0-22.186667 11.036444-33.223111 33.166222-33.223111z" fill="#21D4ED" p-id="2737"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
client/src/components/Icon/icons/outlink/share.svg
Normal file
1
client/src/components/Icon/icons/outlink/share.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="1690507057466" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2581" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M816 416a174.816 174.816 0 0 1-133.6-62.624l-219.616 104.672a222.944 222.944 0 0 1-1.216 174.656l173.696 89.984A179.84 179.84 0 1 1 611.2 784l-185.056-96a224 224 0 1 1 2.912-284.8l221.44-105.6A175.552 175.552 0 1 1 816 416z" fill="#3399FF" p-id="2582"></path></svg>
|
After Width: | Height: | Size: 596 B |
@@ -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;
|
||||
|
@@ -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 (
|
||||
<Grid gridGap={[3, 5]} fontSize={['sm', 'md']} {...props}>
|
||||
@@ -60,7 +68,7 @@ const MyRadio = ({ list, value, align = 'center', onChange, ...props }: Props) =
|
||||
}}
|
||||
onClick={() => onChange(item.value)}
|
||||
>
|
||||
{!!item.icon && <MyIcon mr={'14px'} name={item.icon as any} w={'18px'} />}
|
||||
{!!item.icon && <MyIcon mr={'14px'} name={item.icon as any} w={iconSize} />}
|
||||
<Box>
|
||||
<Box>{item.title}</Box>
|
||||
{!!item.desc && (
|
||||
|
@@ -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`;
|
||||
|
@@ -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
|
||||
});
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
});
|
||||
|
@@ -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, {
|
||||
|
@@ -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({
|
||||
|
@@ -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) {
|
||||
|
@@ -261,12 +261,12 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
router.replace({
|
||||
query: {
|
||||
appId,
|
||||
currentTab: 'share'
|
||||
currentTab: 'outLink'
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
分享
|
||||
外接
|
||||
</Button>
|
||||
<Button
|
||||
size={['sm', 'md']}
|
||||
|
@@ -14,7 +14,8 @@ import {
|
||||
ModalFooter,
|
||||
ModalBody,
|
||||
FormControl,
|
||||
Input
|
||||
Input,
|
||||
useTheme
|
||||
} from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@/components/Icon';
|
||||
@@ -30,6 +31,7 @@ import { useRequest } from '@/hooks/useRequest';
|
||||
import { formatPrice } from '@/utils/user';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import MyRadio from '@/components/Radio';
|
||||
|
||||
const Share = ({ appId }: { appId: string }) => {
|
||||
const { Loading, setIsLoading } = useLoading();
|
||||
@@ -49,8 +51,6 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
defaultValues: defaultShareChat
|
||||
});
|
||||
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
data: shareChatList = [],
|
||||
@@ -77,7 +77,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
<Box position={'relative'} pt={[0, 5, 8]} px={[5, 8]} minH={'50vh'}>
|
||||
<Flex justifyContent={'space-between'}>
|
||||
<Box fontWeight={'bold'}>
|
||||
免登录聊天窗口
|
||||
免登录窗口
|
||||
<MyTooltip
|
||||
forceShow
|
||||
label="可以直接分享该模型给其他用户去进行对话,对方无需登录即可直接进行对话。注意,这个功能会消耗你账号的tokens。请保管好链接和密码。"
|
||||
@@ -97,7 +97,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
: {})}
|
||||
onClick={onOpenCreateShareChat}
|
||||
>
|
||||
创建新窗口
|
||||
创建新链接
|
||||
</Button>
|
||||
</Flex>
|
||||
<TableContainer mt={3}>
|
||||
@@ -118,7 +118,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
<Td>{item.lastTime ? formatTimeToChatTime(item.lastTime) : '未使用'}</Td>
|
||||
<Td>
|
||||
<Flex>
|
||||
<MyTooltip label={'复制分享地址'}>
|
||||
<MyTooltip label={'复制分享链接'}>
|
||||
<MyIcon
|
||||
mr={3}
|
||||
name="copy"
|
||||
@@ -127,7 +127,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
_hover={{ color: 'myBlue.600' }}
|
||||
onClick={() => {
|
||||
const url = `${location.origin}/chat/share?shareId=${item.shareId}`;
|
||||
copyData(url, '已复制分享地址');
|
||||
copyData(url, '已复制分享链接');
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
@@ -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 (
|
||||
<Box pt={[1, 5]}>
|
||||
<Box fontWeight={'bold'} fontSize={['md', 'xl']} mb={2} px={[4, 8]}>
|
||||
外部使用途径
|
||||
</Box>
|
||||
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
|
||||
<MyRadio
|
||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2, 350px)']}
|
||||
iconSize={'20px'}
|
||||
list={[
|
||||
{
|
||||
icon: 'outlink_share',
|
||||
title: '免登录窗口',
|
||||
desc: '分享链接给其他用户,无需登录即可直接进行使用',
|
||||
value: LinkTypeEnum.share
|
||||
}
|
||||
// {
|
||||
// icon: 'outlink_iframe',
|
||||
// title: '网页嵌入',
|
||||
// desc: '嵌入到已有网页中,右下角会生成对话按键',
|
||||
// value: LinkTypeEnum.iframe
|
||||
// }
|
||||
]}
|
||||
value={linkType}
|
||||
onChange={(e) => setLinkType(e as `${LinkTypeEnum}`)}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{linkType === LinkTypeEnum.share && <Share appId={appId} />}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default OutLink;
|
@@ -20,7 +20,7 @@ const AdEdit = dynamic(() => import('./components/AdEdit'), {
|
||||
ssr: false,
|
||||
loading: () => <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 && <API appId={appId} />}
|
||||
{currentTab === TabEnum.share && <Share appId={appId} />}
|
||||
{currentTab === TabEnum.outLink && <OutLink appId={appId} />}
|
||||
</Box>
|
||||
</Flex>
|
||||
</PageContainer>
|
||||
|
@@ -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;
|
||||
|
@@ -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 },
|
||||
|
@@ -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<ShareChatSchemaType> =
|
||||
models['shareChat'] || model('shareChat', ShareChatSchema);
|
||||
export const OutLink: Model<SchmaType> = models['outlinks'] || model('outlinks', OutLinkSchema);
|
@@ -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';
|
||||
|
@@ -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('分享链接已失效');
|
||||
|
2
client/src/types/mongoSchema.d.ts
vendored
2
client/src/types/mongoSchema.d.ts
vendored
@@ -135,7 +135,7 @@ export interface PromotionRecordSchema {
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export interface ShareChatSchema {
|
||||
export interface OutLinkSchema {
|
||||
_id: string;
|
||||
shareId: string;
|
||||
userId: string;
|
||||
|
Reference in New Issue
Block a user