mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 12:20:34 +00:00
Test shorurl (#4686)
* Short-chain burying (#4678) * TrackRegisterParams * 新增工作流导入功能,支持从URL获取工作流JSON数据并创建应用。实现了URL验证、CORS处理、剪贴板读取等功能,确保用户能够顺利导入工作流数据。 * 更新工作流导入功能,将导入逻辑从utils模块迁移至workflow模块,并修正相关导入路径。此更改有助于代码结构的清晰和模块化。 * 优化工作流导入组件,重构导入逻辑,增加从URL获取工作流数据的功能,并实现JSON配置导入窗口。修复了状态管理和错误处理,提升用户体验。 * 更新工作流导入功能,增加对UTM参数的支持,优化从URL获取工作流数据的逻辑,并重构相关API接口。修复了状态管理和错误处理,提升了用户体验。 * 更新创建应用的API接口,将UTM参数的字段名称从`shorUrlId`和`projectCode`修改为`shorUrlPlatform`和`shorUrlProjectCode`,以提高代码的可读性和一致性。 * impoter json * Optimize the logic * delete some console * fix * perf: sem code --------- Co-authored-by: dreamer6680 <1468683855@qq.com>
This commit is contained in:
14
packages/global/support/marketing/type.d.ts
vendored
Normal file
14
packages/global/support/marketing/type.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
export type ShortUrlParams = {
|
||||
shortUrlSource?: string; // Article, video
|
||||
shortUrlMedium?: string; // bilibili, youtube
|
||||
shortUrlContent?: string; // project id
|
||||
};
|
||||
|
||||
export type TrackRegisterParams = {
|
||||
inviterId?: string;
|
||||
bd_vid?: string;
|
||||
fastgpt_sem?: {
|
||||
keyword?: string;
|
||||
} & ShortUrlParams;
|
||||
sourceDomain?: string;
|
||||
};
|
10
packages/global/support/user/login/api.d.ts
vendored
10
packages/global/support/user/login/api.d.ts
vendored
@@ -1,16 +1,10 @@
|
||||
import { TrackRegisterParams } from '../../marketing/type';
|
||||
|
||||
export type GetWXLoginQRResponse = {
|
||||
code: string;
|
||||
codeUrl: string;
|
||||
};
|
||||
|
||||
export type TrackRegisterParams = {
|
||||
inviterId?: string;
|
||||
bd_vid?: string;
|
||||
fastgpt_sem?: {
|
||||
keyword: string;
|
||||
};
|
||||
sourceDomain?: string;
|
||||
};
|
||||
export type AccountRegisterBody = {
|
||||
username: string;
|
||||
code: string;
|
||||
|
@@ -6,6 +6,7 @@ import { OAuthEnum } from '@fastgpt/global/support/user/constant';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { getAppLatestVersion } from '../../../core/app/version/controller';
|
||||
import { ShortUrlParams } from '@fastgpt/global/support/marketing/type';
|
||||
|
||||
const createTrack = ({ event, data }: { event: TrackEnum; data: Record<string, any> }) => {
|
||||
if (!global.feConfigs?.isPlus) return;
|
||||
@@ -31,7 +32,13 @@ export const pushTrack = {
|
||||
data
|
||||
});
|
||||
},
|
||||
createApp: (data: PushTrackCommonType & { type: AppTypeEnum }) => {
|
||||
createApp: (
|
||||
data: PushTrackCommonType &
|
||||
ShortUrlParams & {
|
||||
type: AppTypeEnum;
|
||||
appId: string;
|
||||
}
|
||||
) => {
|
||||
return createTrack({
|
||||
event: TrackEnum.createApp,
|
||||
data
|
||||
|
@@ -182,9 +182,14 @@
|
||||
"type.Http plugin": "HTTP Plugin",
|
||||
"type.Import from json": "Import JSON",
|
||||
"type.Import from json tip": "Create applications directly through JSON configuration files",
|
||||
"type.Import from json_error": "Failed to get workflow data, please check the URL or manually paste the JSON data",
|
||||
"type.Import from json_loading": "Workflow data is being retrieved, please wait...",
|
||||
"type.Plugin": "Plugin",
|
||||
"type.Simple bot": "Simple App",
|
||||
"type.Workflow bot": "Workflow",
|
||||
"type.error.URLempty": "The URL cannot be empty",
|
||||
"type.error.Workflow data is empty": "No workflow data was obtained",
|
||||
"type.error.workflowresponseempty": "Response content is empty",
|
||||
"type_not_recognized": "App type not recognized",
|
||||
"upload_file_max_amount": "Maximum File Quantity",
|
||||
"upload_file_max_amount_tip": "Maximum number of files uploaded in a single round of conversation",
|
||||
|
@@ -189,11 +189,16 @@
|
||||
"type.Http plugin": "HTTP 插件",
|
||||
"type.Import from json": "导入 JSON 配置",
|
||||
"type.Import from json tip": "通过 JSON 配置文件,直接创建应用",
|
||||
"type.Import from json_error": "获取工作流数据失败,请检查URL或手动粘贴JSON数据",
|
||||
"type.Import from json_loading": "正在获取工作流数据,请稍候...",
|
||||
"type.MCP tools": "MCP 工具集",
|
||||
"type.MCP_tools_url": "MCP 地址",
|
||||
"type.Plugin": "插件",
|
||||
"type.Simple bot": "简易应用",
|
||||
"type.Workflow bot": "工作流",
|
||||
"type.error.URLempty": "URL不能为空",
|
||||
"type.error.Workflow data is empty": "没有获取到工作流数据",
|
||||
"type.error.workflowresponseempty": "响应内容为空",
|
||||
"type_not_recognized": "未识别到应用类型",
|
||||
"upload_file_max_amount": "最大文件数量",
|
||||
"upload_file_max_amount_tip": "单轮对话中最大上传文件数量",
|
||||
|
@@ -182,9 +182,14 @@
|
||||
"type.Http plugin": "HTTP 外掛",
|
||||
"type.Import from json": "匯入 JSON 設定",
|
||||
"type.Import from json tip": "透過 JSON 設定文件,直接建立應用",
|
||||
"type.Import from json_error": "獲取工作流數據失敗,請檢查URL或手動粘貼JSON數據",
|
||||
"type.Import from json_loading": "正在獲取工作流數據,請稍候...",
|
||||
"type.Plugin": "外掛",
|
||||
"type.Simple bot": "簡易應用程式",
|
||||
"type.Workflow bot": "工作流程",
|
||||
"type.error.URLempty": "URL不能為空",
|
||||
"type.error.Workflow data is empty": "沒有獲取到工作流數據",
|
||||
"type.error.workflowresponseempty": "響應內容為空",
|
||||
"type_not_recognized": "未識別到應用程式類型",
|
||||
"upload_file_max_amount": "最大檔案數量",
|
||||
"upload_file_max_amount_tip": "單輪對話中最大上傳檔案數量",
|
||||
|
@@ -16,6 +16,14 @@ import { postCreateApp } from '@/web/core/app/api';
|
||||
import { useRouter } from 'next/router';
|
||||
import { form2AppWorkflow } from '@/web/core/app/utils';
|
||||
import ImportAppConfigEditor from '@/pageComponents/app/ImportAppConfigEditor';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { getFetchWorkflow } from '@/web/core/app/api/app';
|
||||
import {
|
||||
getUtmParams,
|
||||
getUtmWorkflow,
|
||||
removeUtmParams,
|
||||
removeUtmWorkflow
|
||||
} from '@/web/support/marketing/utils';
|
||||
|
||||
type FormType = {
|
||||
avatar: string;
|
||||
@@ -37,6 +45,24 @@ const JsonImportModal = ({ onClose }: { onClose: () => void }) => {
|
||||
});
|
||||
const workflowStr = watch('workflowStr');
|
||||
|
||||
const { loading: isFetching } = useRequest2(
|
||||
async () => {
|
||||
const url = getUtmWorkflow();
|
||||
if (!url) return;
|
||||
|
||||
const workflowData = await getFetchWorkflow({ url });
|
||||
|
||||
setValue('workflowStr', JSON.stringify(workflowData, null, 2));
|
||||
|
||||
const utmParams = getUtmParams();
|
||||
if (utmParams.shortUrlContent) setValue('name', utmParams.shortUrlContent);
|
||||
|
||||
removeUtmWorkflow();
|
||||
removeUtmParams();
|
||||
},
|
||||
{ manual: false }
|
||||
);
|
||||
|
||||
const avatar = watch('avatar');
|
||||
const {
|
||||
File,
|
||||
@@ -97,7 +123,8 @@ const JsonImportModal = ({ onClose }: { onClose: () => void }) => {
|
||||
type: appType,
|
||||
modules: workflow.nodes,
|
||||
edges: workflow.edges,
|
||||
chatConfig: workflow.chatConfig
|
||||
chatConfig: workflow.chatConfig,
|
||||
utmParams: getUtmParams()
|
||||
});
|
||||
},
|
||||
{
|
||||
@@ -116,7 +143,7 @@ const JsonImportModal = ({ onClose }: { onClose: () => void }) => {
|
||||
<MyModal
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
isLoading={isCreating}
|
||||
isLoading={isCreating || isFetching}
|
||||
title={t('app:type.Import from json')}
|
||||
iconSrc="common/importLight"
|
||||
iconColor={'primary.600'}
|
||||
|
@@ -13,7 +13,8 @@ import { checkIsWecomTerminal } from '@fastgpt/global/support/user/login/constan
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { GET, POST } from '@/web/common/api/request';
|
||||
import { POST } from '@/web/common/api/request';
|
||||
import { getBdVId } from '@/web/support/marketing/utils';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@@ -107,7 +108,7 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
|
||||
];
|
||||
|
||||
const show_oauth = useMemo(
|
||||
() => !sessionStorage.getItem('bd_vid') && !!(feConfigs?.sso?.url || oAuthList.length > 0),
|
||||
() => !getBdVId() && !!(feConfigs?.sso?.url || oAuthList.length > 0),
|
||||
[feConfigs?.sso?.url, oAuthList.length]
|
||||
);
|
||||
|
||||
|
@@ -12,6 +12,13 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import {
|
||||
getBdVId,
|
||||
getFastGPTSem,
|
||||
getInviterId,
|
||||
getSourceDomain,
|
||||
removeFastGPTSem
|
||||
} from '@/web/support/marketing/utils';
|
||||
|
||||
interface Props {
|
||||
loginSuccess: (e: ResLogin) => void;
|
||||
@@ -50,20 +57,13 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
username,
|
||||
code,
|
||||
password,
|
||||
inviterId: localStorage.getItem('inviterId') || undefined,
|
||||
bd_vid: sessionStorage.getItem('bd_vid') || undefined,
|
||||
fastgpt_sem: (() => {
|
||||
try {
|
||||
return sessionStorage.getItem('fastgpt_sem')
|
||||
? JSON.parse(sessionStorage.getItem('fastgpt_sem')!)
|
||||
: undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
})(),
|
||||
sourceDomain: sessionStorage.getItem('sourceDomain') || undefined
|
||||
inviterId: getInviterId(),
|
||||
bd_vid: getBdVId(),
|
||||
fastgpt_sem: getFastGPTSem(),
|
||||
sourceDomain: getSourceDomain()
|
||||
})
|
||||
);
|
||||
removeFastGPTSem();
|
||||
|
||||
toast({
|
||||
status: 'success',
|
||||
|
@@ -5,6 +5,7 @@ import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils'
|
||||
import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import type { AppSchema } from '@fastgpt/global/core/app/type';
|
||||
import { defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { ShortUrlParams } from '@fastgpt/global/support/marketing/type';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
|
||||
@@ -27,10 +28,11 @@ export type CreateAppBody = {
|
||||
modules: AppSchema['modules'];
|
||||
edges?: AppSchema['edges'];
|
||||
chatConfig?: AppSchema['chatConfig'];
|
||||
utmParams?: ShortUrlParams;
|
||||
};
|
||||
|
||||
async function handler(req: ApiRequestProps<CreateAppBody>) {
|
||||
const { parentId, name, avatar, type, modules, edges, chatConfig } = req.body;
|
||||
const { parentId, name, avatar, type, modules, edges, chatConfig, utmParams } = req.body;
|
||||
|
||||
if (!name || !type || !Array.isArray(modules)) {
|
||||
return Promise.reject(CommonErrEnum.inheritPermissionError);
|
||||
@@ -66,7 +68,9 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
|
||||
type,
|
||||
uid: userId,
|
||||
teamId,
|
||||
tmbId
|
||||
tmbId,
|
||||
appId,
|
||||
...utmParams
|
||||
});
|
||||
|
||||
return appId;
|
||||
|
51
projects/app/src/pages/api/core/app/fetchWorkflow.ts
Normal file
51
projects/app/src/pages/api/core/app/fetchWorkflow.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
|
||||
import axios from 'axios';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
|
||||
export type FetchWorkflowBody = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type FetchWorkflowQuery = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type FetchWorkflowResponseType = ApiResponseType<{
|
||||
data: JSON;
|
||||
}>;
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<FetchWorkflowBody, FetchWorkflowQuery>,
|
||||
res: FetchWorkflowResponseType
|
||||
) {
|
||||
await authCert({ req, authToken: true });
|
||||
|
||||
const url = req.body?.url || req.query?.url;
|
||||
|
||||
if (!url) {
|
||||
return Promise.reject('app:type.error.URLempty');
|
||||
}
|
||||
|
||||
const response = await axios.get(url, {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; FastGPT/1.0)'
|
||||
},
|
||||
timeout: 30000,
|
||||
validateStatus: (status) => status < 500
|
||||
});
|
||||
|
||||
const contentType = response.headers['content-type'] || '';
|
||||
|
||||
if (!response.data || response.data.length === 0) {
|
||||
return Promise.reject('app:type.error.workflowresponseempty');
|
||||
}
|
||||
|
||||
JSON.parse(JSON.stringify(response.data));
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { useMemo, useState, useEffect } from 'react';
|
||||
import { Box, Flex, Button, useDisclosure, Input, InputGroup } from '@chakra-ui/react';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { serviceSideProps } from '@/web/common/i18n/utils';
|
||||
@@ -33,6 +33,8 @@ import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import DashboardContainer from '@/pageComponents/dashboard/Container';
|
||||
import List from '@/pageComponents/dashboard/apps/List';
|
||||
import MCPToolsEditModal from '@/pageComponents/dashboard/apps/MCPToolsEditModal';
|
||||
import { getUtmWorkflow } from '@/web/support/marketing/utils';
|
||||
import { useMount } from 'ahooks';
|
||||
|
||||
const CreateModal = dynamic(() => import('@/pageComponents/dashboard/apps/CreateModal'));
|
||||
const EditFolderModal = dynamic(
|
||||
@@ -71,12 +73,20 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
|
||||
onOpen: onOpenCreateMCPTools,
|
||||
onClose: onCloseCreateMCPTools
|
||||
} = useDisclosure();
|
||||
|
||||
const [editFolder, setEditFolder] = useState<EditFolderFormType>();
|
||||
|
||||
const {
|
||||
isOpen: isOpenJsonImportModal,
|
||||
onOpen: onOpenJsonImportModal,
|
||||
onClose: onCloseJsonImportModal
|
||||
} = useDisclosure();
|
||||
const [editFolder, setEditFolder] = useState<EditFolderFormType>();
|
||||
//if there is a workflow url in the session storage, open the json import modal and import the workflow
|
||||
useMount(() => {
|
||||
if (getUtmWorkflow()) {
|
||||
onOpenJsonImportModal();
|
||||
}
|
||||
});
|
||||
|
||||
const { runAsync: onCreateFolder } = useRequest2(postCreateAppFolder, {
|
||||
onSuccess() {
|
||||
|
@@ -30,6 +30,7 @@ import { getDocPath } from '@/web/common/system/doc';
|
||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
||||
import LoginForm from '@/pageComponents/login/LoginForm/LoginForm';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { getBdVId } from '@/web/support/marketing/utils';
|
||||
|
||||
const RegisterForm = dynamic(() => import('@/pageComponents/login/RegisterForm'));
|
||||
const ForgetPasswordForm = dynamic(() => import('@/pageComponents/login/ForgetPasswordForm'));
|
||||
@@ -64,7 +65,7 @@ const Login = ({ ChineseRedirectUrl }: { ChineseRedirectUrl: string }) => {
|
||||
setUserInfo(res.user);
|
||||
|
||||
const decodeLastRoute = decodeURIComponent(lastRoute);
|
||||
// 检查是否是当前的 route
|
||||
|
||||
const navigateTo =
|
||||
decodeLastRoute && !decodeLastRoute.includes('/login')
|
||||
? decodeLastRoute
|
||||
@@ -90,7 +91,7 @@ const Login = ({ ChineseRedirectUrl }: { ChineseRedirectUrl: string }) => {
|
||||
|
||||
/* default login type */
|
||||
useEffect(() => {
|
||||
const bd_vid = sessionStorage.getItem('bd_vid');
|
||||
const bd_vid = getBdVId();
|
||||
if (bd_vid) {
|
||||
setPageType(LoginPageTypeEnum.passwordLogin);
|
||||
return;
|
||||
|
@@ -11,6 +11,13 @@ import { serviceSideProps } from '@/web/common/i18n/utils';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { OAuthEnum } from '@fastgpt/global/support/user/constant';
|
||||
import {
|
||||
getBdVId,
|
||||
getFastGPTSem,
|
||||
getInviterId,
|
||||
getSourceDomain,
|
||||
removeFastGPTSem
|
||||
} from '@/web/support/marketing/utils';
|
||||
|
||||
let isOauthLogging = false;
|
||||
|
||||
@@ -40,18 +47,10 @@ const provider = () => {
|
||||
type: loginStore?.provider || OAuthEnum.sso,
|
||||
props,
|
||||
callbackUrl: `${location.origin}/login/provider`,
|
||||
inviterId: localStorage.getItem('inviterId') || undefined,
|
||||
bd_vid: sessionStorage.getItem('bd_vid') || undefined,
|
||||
fastgpt_sem: (() => {
|
||||
try {
|
||||
return sessionStorage.getItem('fastgpt_sem')
|
||||
? JSON.parse(sessionStorage.getItem('fastgpt_sem')!)
|
||||
: undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
})(),
|
||||
sourceDomain: sessionStorage.getItem('sourceDomain') || undefined
|
||||
inviterId: getInviterId(),
|
||||
bd_vid: getBdVId(),
|
||||
fastgpt_sem: getFastGPTSem(),
|
||||
sourceDomain: getSourceDomain()
|
||||
});
|
||||
|
||||
if (!res) {
|
||||
@@ -63,6 +62,8 @@ const provider = () => {
|
||||
router.replace('/login');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
removeFastGPTSem();
|
||||
loginSuccess(res);
|
||||
} catch (error) {
|
||||
toast({
|
||||
|
@@ -7,14 +7,28 @@ import { useMemoizedFn, useMount } from 'ahooks';
|
||||
import { TrackEventName } from '../common/system/constants';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useUserStore } from '../support/user/useUserStore';
|
||||
import {
|
||||
setBdVId,
|
||||
setFastGPTSem,
|
||||
setInviterId,
|
||||
setSourceDomain,
|
||||
setUtmParams,
|
||||
setUtmWorkflow
|
||||
} from '../support/marketing/utils';
|
||||
import { ShortUrlParams } from '@fastgpt/global/support/marketing/type';
|
||||
|
||||
export const useInitApp = () => {
|
||||
const router = useRouter();
|
||||
const { hiId, bd_vid, k, sourceDomain } = router.query as {
|
||||
const { hiId, bd_vid, k, sourceDomain, utm_source, utm_medium, utm_content, utm_workflow } =
|
||||
router.query as {
|
||||
hiId?: string;
|
||||
bd_vid?: string;
|
||||
k?: string;
|
||||
sourceDomain?: string;
|
||||
utm_source?: string;
|
||||
utm_medium?: string;
|
||||
utm_content?: string;
|
||||
utm_workflow?: string;
|
||||
};
|
||||
const { loadGitStar, setInitd, feConfigs } = useSystemStore();
|
||||
const { userInfo } = useUserStore();
|
||||
@@ -69,20 +83,21 @@ export const useInitApp = () => {
|
||||
pollingInterval: 300000 // 5 minutes refresh
|
||||
});
|
||||
|
||||
// Marketing data track
|
||||
useEffect(() => {
|
||||
hiId && localStorage.setItem('inviterId', hiId);
|
||||
bd_vid && sessionStorage.setItem('bd_vid', bd_vid);
|
||||
k && sessionStorage.setItem('fastgpt_sem', JSON.stringify({ keyword: k }));
|
||||
setInviterId(hiId);
|
||||
setBdVId(bd_vid);
|
||||
setUtmWorkflow(utm_workflow);
|
||||
setSourceDomain(sourceDomain);
|
||||
|
||||
const formatSourceDomain = (() => {
|
||||
if (sourceDomain) return sourceDomain;
|
||||
return document.referrer;
|
||||
})();
|
||||
|
||||
if (formatSourceDomain && !sessionStorage.getItem('sourceDomain')) {
|
||||
sessionStorage.setItem('sourceDomain', formatSourceDomain);
|
||||
}
|
||||
}, [bd_vid, hiId, k, sourceDomain]);
|
||||
const utmParams: ShortUrlParams = {
|
||||
...(utm_source && { shortUrlSource: utm_source }),
|
||||
...(utm_medium && { shortUrlMedium: utm_medium }),
|
||||
...(utm_content && { shortUrlContent: utm_content })
|
||||
};
|
||||
setUtmParams(utmParams);
|
||||
setFastGPTSem({ keyword: k, ...utmParams });
|
||||
}, [bd_vid, hiId, k, utm_workflow, sourceDomain, utm_source, utm_medium, utm_content]);
|
||||
|
||||
return {
|
||||
feConfigs,
|
||||
|
@@ -10,6 +10,10 @@ import type {
|
||||
} from '@/pages/api/core/app/transitionWorkflow';
|
||||
import type { copyAppQuery, copyAppResponse } from '@/pages/api/core/app/copy';
|
||||
|
||||
import type {
|
||||
FetchWorkflowQuery,
|
||||
FetchWorkflowResponseType
|
||||
} from '@/pages/api/core/app/fetchWorkflow';
|
||||
/* folder */
|
||||
export const postCreateAppFolder = (data: CreateAppFolderBody) =>
|
||||
POST('/core/app/folder/create', data);
|
||||
@@ -25,3 +29,6 @@ export const postTransition2Workflow = (data: transitionWorkflowBody) =>
|
||||
POST<transitionWorkflowResponse>('/core/app/transitionWorkflow', data);
|
||||
|
||||
export const postCopyApp = (data: copyAppQuery) => POST<copyAppResponse>('/core/app/copy', data);
|
||||
|
||||
export const getFetchWorkflow = (data: FetchWorkflowQuery) =>
|
||||
GET<FetchWorkflowResponseType>('/core/app/fetchWorkflow', data);
|
||||
|
77
projects/app/src/web/support/marketing/utils.ts
Normal file
77
projects/app/src/web/support/marketing/utils.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { ShortUrlParams, TrackRegisterParams } from '@fastgpt/global/support/marketing/type';
|
||||
|
||||
export const getInviterId = () => {
|
||||
return localStorage.getItem('inviterId') || undefined;
|
||||
};
|
||||
export const setInviterId = (inviterId?: string) => {
|
||||
if (!inviterId) return;
|
||||
localStorage.setItem('inviterId', inviterId);
|
||||
};
|
||||
export const removeInviterId = () => {
|
||||
localStorage.removeItem('inviterId');
|
||||
};
|
||||
|
||||
export const getBdVId = () => {
|
||||
return sessionStorage.getItem('bd_vid') || undefined;
|
||||
};
|
||||
export const setBdVId = (bdVid?: string) => {
|
||||
if (!bdVid) return;
|
||||
sessionStorage.setItem('bd_vid', bdVid);
|
||||
};
|
||||
|
||||
export const getUtmWorkflow = () => {
|
||||
return sessionStorage.getItem('utm_workflow') || undefined;
|
||||
};
|
||||
export const setUtmWorkflow = (utmWorkflow?: string) => {
|
||||
if (!utmWorkflow) return;
|
||||
sessionStorage.setItem('utm_workflow', utmWorkflow);
|
||||
};
|
||||
export const removeUtmWorkflow = () => {
|
||||
sessionStorage.removeItem('utm_workflow');
|
||||
};
|
||||
|
||||
export const getUtmParams = () => {
|
||||
try {
|
||||
const params = JSON.parse(localStorage.getItem('utm_params') || '{}');
|
||||
return params as ShortUrlParams;
|
||||
} catch (error) {
|
||||
return {} as ShortUrlParams;
|
||||
}
|
||||
};
|
||||
export const setUtmParams = (utmParams?: ShortUrlParams) => {
|
||||
if (!utmParams || Object.keys(utmParams).length === 0) return;
|
||||
localStorage.setItem('utm_params', JSON.stringify(utmParams));
|
||||
};
|
||||
export const removeUtmParams = () => {
|
||||
localStorage.removeItem('utm_params');
|
||||
};
|
||||
|
||||
export const getFastGPTSem = () => {
|
||||
try {
|
||||
return localStorage.getItem('fastgpt_sem')
|
||||
? JSON.parse(localStorage.getItem('fastgpt_sem')!)
|
||||
: undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
export const setFastGPTSem = (fastgptSem?: TrackRegisterParams['fastgpt_sem']) => {
|
||||
if (!fastgptSem) return;
|
||||
localStorage.setItem('fastgpt_sem', JSON.stringify(fastgptSem));
|
||||
};
|
||||
export const removeFastGPTSem = () => {
|
||||
localStorage.removeItem('fastgpt_sem');
|
||||
};
|
||||
|
||||
export const getSourceDomain = () => {
|
||||
return sessionStorage.getItem('sourceDomain') || undefined;
|
||||
};
|
||||
export const setSourceDomain = (sourceDomain?: string) => {
|
||||
const formatSourceDomain = (() => {
|
||||
if (sourceDomain) return sourceDomain;
|
||||
return document.referrer;
|
||||
})();
|
||||
|
||||
if (!formatSourceDomain || getSourceDomain()) return;
|
||||
sessionStorage.setItem('sourceDomain', formatSourceDomain);
|
||||
};
|
Reference in New Issue
Block a user