feat: support sub route config (#3071)

* feat: support sub route config

* dockerfile

* fix upload

* delete unused code
This commit is contained in:
heheer 2024-11-07 13:53:23 +08:00 committed by GitHub
parent dc95ab1dc1
commit 3b82ed0aa1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 100 additions and 168 deletions

View File

@ -16,7 +16,7 @@ export const bucketNameMap = {
}
};
export const ReadFileBaseUrl = `${process.env.FE_DOMAIN || ''}/api/common/file/read`;
export const ReadFileBaseUrl = `${process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL}/api/common/file/read`;
export const documentFileType = '.txt, .docx, .csv, .xlsx, .pdf, .md, .html, .pptx';
export const imageFileType =

View File

@ -14,7 +14,6 @@ import type {
ChatCompletionToolMessageParam
} from '../../core/ai/type.d';
import { ChatCompletionRequestMessageRoleEnum } from '../../core/ai/constants';
const GPT2Chat = {
[ChatCompletionRequestMessageRoleEnum.System]: ChatRoleEnum.System,
[ChatCompletionRequestMessageRoleEnum.User]: ChatRoleEnum.Human,
@ -61,14 +60,14 @@ export const chats2GPTMessages = ({
return {
type: 'image_url',
image_url: {
url: item.file?.url || ''
url: item.file.url
}
};
} else if (item.file?.type === ChatFileTypeEnum.file) {
return {
type: 'file_url',
name: item.file?.name || '',
url: item.file?.url || ''
url: item.file.url
};
}
}

View File

@ -9,3 +9,12 @@ export const getUserFingerprint = async () => {
export const hasHttps = () => {
return window.location.protocol === 'https:';
};
export const getWebReqUrl = (url: string = '') => {
if (!url) return '/';
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
if (!baseUrl) return url;
if (!url.startsWith('/') || url.startsWith(baseUrl)) return url;
return `${baseUrl}${url}`;
};

View File

@ -1,9 +1,10 @@
import React from 'react';
import { Box, Flex, Image } from '@chakra-ui/react';
import { Box } from '@chakra-ui/react';
import type { ImageProps } from '@chakra-ui/react';
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
import MyIcon from '../Icon';
import { iconPaths } from '../Icon/constants';
import MyImage from '../Image/MyImage';
const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
// @ts-ignore
@ -14,7 +15,7 @@ const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
<MyIcon name={src as any} w={w} borderRadius={props.borderRadius} />
</Box>
) : (
<Image
<MyImage
fallbackSrc={LOGO_ICON}
fallbackStrategy={'onError'}
objectFit={'contain'}

View File

@ -0,0 +1,7 @@
import React from 'react';
import { Image, ImageProps } from '@chakra-ui/react';
import { getWebReqUrl } from '../../../common/system/utils';
const MyImage = (props: ImageProps) => {
return <Image {...props} src={getWebReqUrl(props.src)} alt={props.alt || ''} />;
};
export default React.memo(MyImage);

View File

@ -1,9 +1,10 @@
import React from 'react';
import { PhotoProvider, PhotoView } from 'react-photo-view';
import 'react-photo-view/dist/react-photo-view.css';
import { Box, Image, ImageProps } from '@chakra-ui/react';
import { ImageProps } from '@chakra-ui/react';
import { useSystem } from '../../../hooks/useSystem';
import Loading from '../MyLoading';
import MyImage from './MyImage';
const MyPhotoView = ({ ...props }: ImageProps) => {
const { isPc } = useSystem();
@ -15,7 +16,7 @@ const MyPhotoView = ({ ...props }: ImageProps) => {
loadingElement={<Loading fixed={false} />}
>
<PhotoView src={props.src}>
<Image cursor={'pointer'} {...props} />
<MyImage cursor={'pointer'} {...props} />
</PhotoView>
</PhotoProvider>
);

View File

@ -1,7 +1,7 @@
import React from 'react';
import MyIcon from '../Icon';
import { Flex, Image, Box, CloseButton, FlexProps } from '@chakra-ui/react';
import { Flex, Box, CloseButton, FlexProps } from '@chakra-ui/react';
import { useLoading } from '../../../hooks/useLoading';
import Avatar from '../Avatar';
type Props = FlexProps & {
onClose: () => void;
@ -50,15 +50,7 @@ const CustomRightDrawer = ({
py={'10px'}
px={5}
>
{iconSrc && (
<>
{iconSrc.startsWith('/') ? (
<Image mr={3} objectFit={'contain'} alt="" src={iconSrc} w={'20px'} />
) : (
<MyIcon mr={3} name={iconSrc as any} w={'20px'} />
)}
</>
)}
{iconSrc && <Avatar mr={3} w={'20px'} src={iconSrc} />}
<Box flex={'1'} fontSize={'md'}>
{title}
</Box>

View File

@ -13,6 +13,7 @@ import {
Box
} from '@chakra-ui/react';
import { useLoading } from '../../../hooks/useLoading';
import Avatar from '../Avatar';
type Props = DrawerContentProps & {
onClose: () => void;
@ -52,15 +53,7 @@ const MyRightDrawer = ({
py={'10px'}
px={5}
>
{iconSrc && (
<>
{iconSrc.startsWith('/') ? (
<Image mr={3} objectFit={'contain'} alt="" src={iconSrc} w={'20px'} />
) : (
<MyIcon mr={3} name={iconSrc as any} w={'20px'} />
)}
</>
)}
{iconSrc && <Avatar mr={3} w={'20px'} src={iconSrc} />}
<Box flex={'1'} fontSize={'md'}>
{title}
</Box>

View File

@ -2,9 +2,10 @@ import React, { useCallback, useRef, useState } from 'react';
import Editor, { Monaco, loader } from '@monaco-editor/react';
import { Box, BoxProps } from '@chakra-ui/react';
import MyIcon from '../../Icon';
import { getWebReqUrl } from '../../../../common/system/utils';
loader.config({
paths: { vs: '/js/monaco-editor.0.45.0/vs' }
paths: { vs: getWebReqUrl('/js/monaco-editor.0.45.0/vs') }
});
type EditorVariablePickerType = {

View File

@ -4,9 +4,10 @@ import { Box, BoxProps } from '@chakra-ui/react';
import MyIcon from '../../Icon';
import { useToast } from '../../../../hooks/useToast';
import { useTranslation } from 'next-i18next';
import { getWebReqUrl } from '../../../../common/system/utils';
loader.config({
paths: { vs: '/js/monaco-editor.0.45.0/vs' }
paths: { vs: getWebReqUrl('/js/monaco-editor.0.45.0/vs') }
});
type EditorVariablePickerType = {

View File

@ -1,97 +0,0 @@
import { Box, Button, Image } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
export default function ComfirmVar({
newVariables,
onCancel,
onConfirm
}: {
newVariables: string[];
onCancel: () => void;
onConfirm: () => void;
}) {
const { t } = useTranslation();
return (
<>
<Box
background={'rgba(35, 56, 118, 0.2)'}
rounded={'sm'}
position={'absolute'}
top={0}
left={0}
right={0}
bottom={0}
/>
<Box
position={'absolute'}
top={'50%'}
left={'50%'}
transform={'translate(-50%, -50%)'}
w={'70%'}
h={'70%'}
bg={'white'}
rounded={'lg'}
boxShadow={'0 2px 4px rgba(0, 0, 0, 0.1)'}
display={'flex'}
flexDirection={'column'}
justifyContent={'space-between'}
pb={4}
>
<Box display={'flex'} mt={4} mr={4}>
<Box
w={'36px'}
h={'36px'}
minW={'36px'}
boxShadow={'0 4px 8px rgba(0, 0, 0, 0.1)'}
display={'flex'}
alignItems={'center'}
justifyContent={'center'}
rounded={'md'}
border={'1px solid rgba(0, 0, 0, 0.1)'}
mx={4}
>
<Image alt={''} src={'/imgs/workflow/variable.png'} objectFit={'contain'} w={'20px'} />
</Box>
<Box>{t('common:undefined_var')}</Box>
</Box>
<Box
ml={16}
mt={4}
fontSize={'sm'}
color={'rgb(28,100,242)'}
display={'flex'}
whiteSpace={'wrap'}
>
{newVariables.map((item, index) => (
<Box
key={index}
display={'flex'}
alignItems={'center'}
justifyContent={'center'}
bg={'rgb(237,242,250)'}
px={1}
h={6}
rounded={'md'}
mr={2}
>
<span>
<span style={{ opacity: '60%' }}>{`{{`}</span>
<span>{item}</span>
<span style={{ opacity: '60%' }}>{`}}`}</span>
</span>
</Box>
))}
</Box>
<Box>
<Box display={'flex'} justifyContent={'flex-end'} mt={4} mr={4}>
<Button size={'sm'} variant={'ghost'} onClick={onCancel}>
{t('common:common.Cancel')}
</Button>
<Button size={'sm'} variant={'primary'} ml={4} onClick={onConfirm}>
{t('common:common.Confirm')}
</Button>
</Box>
</Box>
</Box>
</>
);
}

View File

@ -1119,7 +1119,6 @@
"tag_list": "Tag List",
"team_tag": "Team Tag",
"textarea_variable_picker_tip": "Enter \"/\" to select a variable",
"undefined_var": "Referenced an undefined variable, add it automatically?",
"unit.character": "Character",
"unit.minute": "Minute",
"unusable_variable": "No Usable Variables",

View File

@ -1125,7 +1125,6 @@
"tag_list": "标签列表",
"team_tag": "团队标签",
"textarea_variable_picker_tip": "输入\"/\"可选择变量",
"undefined_var": "引用了未定义的变量,是否自动添加?",
"unit.character": "字符",
"unit.minute": "分钟",
"unusable_variable": "无可用变量",

View File

@ -35,6 +35,8 @@ SANDBOX_URL=http://localhost:3001
PRO_URL=
# 页面的地址,用于自动补全相对路径资源的 domain
FE_DOMAIN=http://localhost:3000
# 二级路由
# NEXT_PUBLIC_BASE_URL=/fastai
# 日志等级: debug, info, warn, error
LOG_LEVEL=debug

View File

@ -26,6 +26,7 @@ FROM node:20.14.0-alpine AS builder
WORKDIR /app
ARG proxy
ARG base_url
# copy common node_modules and one project node_modules
COPY package.json pnpm-workspace.yaml .npmrc tsconfig.json ./
@ -39,6 +40,7 @@ RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
ENV NODE_OPTIONS="--max-old-space-size=4096"
ENV NEXT_PUBLIC_BASE_URL=$base_url
RUN pnpm --filter=app build
# --------- runner -----------
@ -46,6 +48,7 @@ FROM node:20.14.0-alpine AS runner
WORKDIR /app
ARG proxy
ARG base_url
# create user and use it
RUN addgroup --system --gid 1001 nodejs
@ -81,6 +84,7 @@ RUN chown -R nextjs:nodejs /app/data
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV NEXT_PUBLIC_BASE_URL=$base_url
EXPOSE 3000

View File

@ -6,6 +6,7 @@ const isDev = process.env.NODE_ENV === 'development';
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: process.env.NEXT_PUBLIC_BASE_URL,
i18n,
output: 'standalone',
reactStrictMode: isDev ? false : true,

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Image, Skeleton, ImageProps } from '@chakra-ui/react';
import { Skeleton, ImageProps } from '@chakra-ui/react';
import CustomImage from '@fastgpt/web/components/common/Image/MyImage';
export const MyImage = (props: ImageProps) => {
const [isLoading, setIsLoading] = useState(true);
@ -13,7 +14,7 @@ export const MyImage = (props: ImageProps) => {
justifyContent={'center'}
my={1}
>
<Image
<CustomImage
display={'inline-block'}
borderRadius={'md'}
alt={''}

View File

@ -13,6 +13,7 @@ import MySelect from '@fastgpt/web/components/common/MySelect';
import { defaultTTSConfig } from '@fastgpt/global/core/app/constants';
import ChatFunctionTip from './Tip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
const TTSSelect = ({
value = defaultTTSConfig,
@ -133,7 +134,7 @@ const TTSSelect = ({
<Flex mt={10} justifyContent={'end'}>
{audioPlaying ? (
<Flex>
<Image src="/icon/speaking.gif" w={'24px'} alt={''} />
<MyImage src="/icon/speaking.gif" w={'24px'} alt={''} />
<Button
ml={2}
variant={'grayBase'}

View File

@ -1,5 +1,5 @@
import { useI18n } from '@/web/context/I18n';
import { Box, Flex, Image } from '@chakra-ui/react';
import { Box, Flex } from '@chakra-ui/react';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useTranslation } from 'next-i18next';
import React, { useRef } from 'react';
@ -77,7 +77,7 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => {
label={
<Box pt={2}>
<Flex alignItems={'flex-start'}>
<Image src={data.icon} w={'36px'} alt={''} />
<MyImage src={data.icon} w={'36px'} alt={''} />
<Box ml={3}>
<Box fontWeight="bold">{data.title}</Box>
<Box fontSize={'xs'} color={'myGray.500'}>
@ -85,7 +85,7 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => {
</Box>
</Box>
</Flex>
<Image src={data.imgUrl} w={'100%'} minH={['auto', '250px']} mt={2} alt={''} />
<MyImage src={data.imgUrl} w={'100%'} minH={['auto', '250px']} mt={2} alt={''} />
</Box>
}
/>

View File

@ -1,5 +1,5 @@
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { Flex, FlexProps, Image, css, useTheme } from '@chakra-ui/react';
import { Flex, FlexProps, css, useTheme } from '@chakra-ui/react';
import { ChatSiteItemType } from '@fastgpt/global/core/chat/type';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import React, { useMemo } from 'react';
@ -9,6 +9,7 @@ import { formatChatValue2InputType } from '../utils';
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { ChatBoxContext } from '../Provider';
import { useContextSelector } from 'use-context-selector';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
export type ChatControllerProps = {
isLastChild: boolean;
@ -124,7 +125,7 @@ const ChatController = ({
onClick={cancelAudio}
/>
</MyTooltip>
<Image
<MyImage
src="/icon/speaking.gif"
w={'23px'}
alt={''}

View File

@ -6,6 +6,7 @@ import { useTranslation } from 'next-i18next';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import QuoteItem from '@/components/core/dataset/QuoteItem';
import RawSourceBox from '@/components/core/dataset/RawSourceBox';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
const QuoteModal = ({
rawSearch = [],
@ -42,13 +43,13 @@ const QuoteModal = ({
h={['90vh', '80vh']}
isCentered
minW={['90vw', '600px']}
iconSrc={!!metadata ? undefined : '/imgs/modal/quote.svg'}
iconSrc={!!metadata ? undefined : getWebReqUrl('/imgs/modal/quote.svg')}
title={
<Box>
{metadata ? (
<RawSourceBox {...metadata} canView={showDetail} />
) : (
<>{t('core.chat.Quote Amount', { amount: rawSearch.length })}</>
<>{t('common:core.chat.Quote Amount', { amount: rawSearch.length })}</>
)}
<Box fontSize={'xs'} color={'myGray.500'} fontWeight={'normal'}>
{t('common:core.chat.quote.Quote Tip')}

View File

@ -6,6 +6,7 @@ import MyBox from '@fastgpt/web/components/common/MyBox';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
const RenderFilePreview = ({
fileList,
@ -70,7 +71,7 @@ const RenderFilePreview = ({
/>
)}
{isImage && (
<Image
<MyImage
alt={'img'}
src={item.icon}
w={'full'}

View File

@ -1,5 +1,6 @@
import { getCaptchaPic } from '@/web/support/user/api';
import { Button, Input, Image, ModalBody, ModalFooter, Skeleton } from '@chakra-ui/react';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useTranslation } from 'next-i18next';
@ -42,7 +43,7 @@ const SendCodeAuthModal = ({
justifyContent={'center'}
my={1}
>
<Image
<MyImage
borderRadius={'md'}
w={'100%'}
h={'200px'}

View File

@ -13,6 +13,7 @@ import '@/web/styles/reset.scss';
import NextHead from '@/components/common/NextHead';
import { ReactElement, useEffect } from 'react';
import { NextPage } from 'next';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
type NextPageWithLayout = NextPage & {
setLayout?: (page: ReactElement) => JSX.Element;
@ -49,7 +50,7 @@ function App({ Component, pageProps }: AppPropsWithLayout) {
process.env.SYSTEM_DESCRIPTION ||
`${title}${t('app:intro')}`
}
icon={feConfigs?.favicon || process.env.SYSTEM_FAVICON}
icon={getWebReqUrl(feConfigs?.favicon || process.env.SYSTEM_FAVICON)}
/>
{scripts?.map((item, i) => <Script key={i} strategy="lazyOnload" {...item}></Script>)}

View File

@ -9,7 +9,6 @@ import {
Link,
Progress,
Grid,
Image,
BoxProps
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
@ -45,6 +44,7 @@ import StandardPlanContentList from '@/components/support/wallet/StandardPlanCon
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
const StandDetailModal = dynamic(() => import('./standardDetailModal'));
const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu'));
@ -653,7 +653,7 @@ const Other = ({ onOpenContact }: { onOpenContact: () => void }) => {
onClick={onOpenLaf}
fontSize={'sm'}
>
<Image src="/imgs/workflow/laf.png" w={'18px'} alt="laf" />
<MyImage src="/imgs/workflow/laf.png" w={'18px'} alt="laf" />
<Box ml={2} flex={1}>
{'laf' + t('common:navbar.Account')}
</Box>

View File

@ -13,6 +13,7 @@ import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next';
import Script from 'next/script';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
const Promotion = dynamic(() => import('./components/Promotion'));
const UsageTable = dynamic(() => import('./components/UsageTable'));
@ -128,7 +129,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
return (
<>
<Script src="/js/qrcode.min.js" strategy="lazyOnload"></Script>
<Script src={getWebReqUrl('/js/qrcode.min.js')} strategy="lazyOnload"></Script>
<PageContainer>
<Flex flexDirection={['column', 'row']} h={'100%'} pt={[4, 0]}>
{isPc ? (

View File

@ -2,7 +2,7 @@ import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
import React, { useCallback, useState } from 'react';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next';
import { Box, Flex, FlexProps, Grid, Image, ModalBody, Switch, useTheme } from '@chakra-ui/react';
import { Box, Flex, FlexProps, Grid, ModalBody, Switch, useTheme } from '@chakra-ui/react';
import MyRadio from '@/components/common/MyRadio';
import { useForm } from 'react-hook-form';
import MyIcon from '@fastgpt/web/components/common/Icon';
@ -10,6 +10,7 @@ import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { fileToBase64 } from '@/web/common/file/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
enum UsingWayEnum {
link = 'link',
@ -29,15 +30,15 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
const VariableTypeList = [
{
title: <Image src={'/imgs/outlink/link.svg'} alt={''} />,
title: <MyImage src={'/imgs/outlink/link.svg'} alt={''} />,
value: UsingWayEnum.link
},
{
title: <Image src={'/imgs/outlink/iframe.svg'} alt={''} />,
title: <MyImage src={'/imgs/outlink/iframe.svg'} alt={''} />,
value: UsingWayEnum.iframe
},
{
title: <Image src={'/imgs/outlink/script.svg'} alt={''} />,
title: <MyImage src={'/imgs/outlink/script.svg'} alt={''} />,
value: UsingWayEnum.script
}
];
@ -162,7 +163,7 @@ console.log("Chat box loaded")
</Flex>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('common:core.app.outLink.Script Open Icon')}</Box>
<Image
<MyImage
src={getValues('scriptOpenIcon')}
alt={''}
w={'20px'}
@ -173,7 +174,7 @@ console.log("Chat box loaded")
</Flex>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('common:core.app.outLink.Script Close Icon')}</Box>
<Image
<MyImage
src={getValues('scriptCloseIcon')}
alt={''}
w={'20px'}

View File

@ -3,6 +3,7 @@ import { Box, Image, Flex, ModalBody } from '@chakra-ui/react';
import MyModal from '@fastgpt/web/components/common/MyModal';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
export type ShowShareLinkModalProps = {
shareLink: string;
@ -40,7 +41,7 @@ function ShowShareLinkModal({ shareLink, onClose, img }: ShowShareLinkModalProps
</Box>
</Box>
<Box mt="4" borderRadius="0.5rem" border="1px" borderStyle="solid" borderColor="myGray.200">
<Image src={img} borderRadius="0.5rem" alt="" />
<MyImage src={img} borderRadius="0.5rem" alt="" />
</Box>
</ModalBody>
</MyModal>

View File

@ -1,5 +1,5 @@
import React, { useCallback, useMemo } from 'react';
import { Box, Button, Card, Flex, FlexProps, Image } from '@chakra-ui/react';
import { Box, Button, Card, Flex, FlexProps } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import Avatar from '@fastgpt/web/components/common/Avatar';
import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
@ -15,7 +15,7 @@ import { ConnectionSourceHandle, ConnectionTargetHandle } from './Handle/Connect
import { useDebug } from '../../hooks/useDebug';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import { getPreviewPluginNode } from '@/web/core/app/api/plugin';
import { storeNode2FlowNode, getLatestNodeTemplate } from '@/web/core/workflow/utils';
import { storeNode2FlowNode } from '@/web/core/workflow/utils';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../../context';
@ -28,6 +28,7 @@ import { WholeResponseContent } from '@/components/core/chat/components/WholeRes
import { getDocPath } from '@/web/common/system/doc';
import { WorkflowActionContext } from '../../../context/workflowInitContext';
import { WorkflowEventContext } from '../../../context/workflowEventContext';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
type Props = FlowNodeItemType & {
children?: React.ReactNode | React.ReactNode[] | string;
@ -244,7 +245,7 @@ const NodeCard = (props: Props) => {
{!!nodeTemplate?.diagram && !hasNewVersion && (
<MyTooltip
label={
<Image
<MyImage
src={nodeTemplate?.diagram}
w={'100%'}
minH={['auto', '200px']}

View File

@ -1,7 +1,7 @@
import React, { Dispatch } from 'react';
import { LoginPageTypeEnum } from '@/web/support/user/login/constants';
import type { ResLogin } from '@/global/support/api/userRes';
import { Box, Center, Image } from '@chakra-ui/react';
import { Box, Center } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { getWXLoginQR, getWXLoginResult } from '@/web/support/user/api';
import { getErrText } from '@fastgpt/global/common/error/utils';
@ -9,6 +9,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
import FormLayout from './components/FormLayout';
import { useTranslation } from 'next-i18next';
import Loading from '@fastgpt/web/components/common/MyLoading';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
interface Props {
loginSuccess: (e: ResLogin) => void;
@ -44,7 +45,7 @@ const WechatForm = ({ setPageType, loginSuccess }: Props) => {
</Box>
<Box p={5} display={'flex'} w={'full'} justifyContent={'center'}>
{wechatInfo?.codeUrl ? (
<Image w="200px" src={wechatInfo?.codeUrl} alt="qrcode"></Image>
<MyImage w="200px" src={wechatInfo?.codeUrl} alt="qrcode"></MyImage>
) : (
<Center w={200} h={200} position={'relative'}>
<Loading fixed={false} />

View File

@ -1,6 +1,6 @@
import { LoginPageTypeEnum } from '@/web/support/user/login/constants';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { AbsoluteCenter, Box, Button, Flex, Image } from '@chakra-ui/react';
import { AbsoluteCenter, Box, Button, Flex } from '@chakra-ui/react';
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
import { OAuthEnum } from '@fastgpt/global/support/user/constant';
import MyIcon from '@fastgpt/web/components/common/Icon';
@ -10,6 +10,7 @@ import { Dispatch, useRef } from 'react';
import { useTranslation } from 'next-i18next';
import I18nLngSelector from '@/components/Select/I18nLngSelector';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 8);
interface Props {
@ -86,7 +87,7 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
alignItems={'center'}
justifyContent={'center'}
>
<Image src={LOGO_ICON} w={['22.5px', '36px']} alt={'icon'} />
<MyImage src={LOGO_ICON} w={['22.5px', '36px']} alt={'icon'} />
</Flex>
<Box ml={[3, 5]} fontSize={['lg', 'xl']} fontWeight={'bold'} color={'myGray.900'}>
{feConfigs?.systemTitle}
@ -137,7 +138,7 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
w={'100%'}
h={'40px'}
borderRadius={'sm'}
leftIcon={<Image alt="" src={feConfigs.sso.icon as any} w="20px" />}
leftIcon={<MyImage alt="" src={feConfigs.sso.icon as any} w="20px" />}
onClick={() => {
feConfigs.sso?.url && router.replace(feConfigs.sso?.url, '_self');
}}

View File

@ -28,6 +28,7 @@ import I18nLngSelector from '@/components/Select/I18nLngSelector';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { GET } from '@/web/common/api/request';
import { getDocPath } from '@/web/common/system/doc';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
const RegisterForm = dynamic(() => import('./components/RegisterForm'));
const ForgetPasswordForm = dynamic(() => import('./components/ForgetPasswordForm'));
@ -136,7 +137,7 @@ const Login = ({ ChineseRedirectUrl }: { ChineseRedirectUrl: string }) => {
<Flex
alignItems={'center'}
justifyContent={'center'}
bg={`url('/icon/login-bg.svg') no-repeat`}
bg={`url(${getWebReqUrl('/icon/login-bg.svg')}) no-repeat`}
backgroundSize={'cover'}
userSelect={'none'}
h={'100%'}

View File

@ -11,6 +11,7 @@ import {
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { useSystemStore } from '../system/useSystemStore';
import { formatTime2YMDHMW } from '@fastgpt/global/common/string/time';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
type StreamFetchProps = {
url?: string;
@ -136,7 +137,7 @@ export const streamFetch = ({
};
// send request
await fetchEventSource(url, {
await fetchEventSource(getWebReqUrl(url), {
...requestData,
async onopen(res) {
clearTimeout(timeoutId);

View File

@ -8,6 +8,7 @@ import { clearToken } from '@/web/support/user/auth';
import { TOKEN_ERROR_CODE } from '@fastgpt/global/common/error/errorCode';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { useSystemStore } from '../system/useSystemStore';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
interface ConfigType {
headers?: { [key: string]: string };
@ -114,7 +115,7 @@ function responseError(err: any) {
!(window.location.pathname === '/chat/share' || window.location.pathname === '/chat/team')
) {
window.location.replace(
`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`
getWebReqUrl(`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`)
);
}
@ -160,7 +161,7 @@ function request(
return instance
.request({
baseURL: '/api',
baseURL: getWebReqUrl('/api'),
url,
method,
data: ['POST', 'PUT'].includes(method) ? data : null,

View File

@ -1,7 +1,8 @@
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
import { useQuery } from '@tanstack/react-query';
export const getMd = async (url: string) => {
const response = await fetch(`/docs/${url}`);
const response = await fetch(getWebReqUrl(`/docs/${url}`));
const textContent = await response.text();
return textContent;
};

View File

@ -1,3 +1,4 @@
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
import { useSystemStore } from './useSystemStore';
export const getDocPath = (path: string) => {
const feConfigs = useSystemStore.getState().feConfigs;
@ -5,5 +6,6 @@ export const getDocPath = (path: string) => {
if (!feConfigs?.docUrl) return '';
if (!path.startsWith('/')) return path;
if (feConfigs.docUrl.endsWith('/')) return feConfigs.docUrl.slice(0, -1);
return feConfigs.docUrl + path;
return getWebReqUrl(feConfigs.docUrl + path);
};

View File

@ -8,6 +8,7 @@ import { TTSTypeEnum } from '@/web/core/app/constants';
import { useTranslation } from 'next-i18next';
import type { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat.d';
import { useMount } from 'ahooks';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
const contentType = 'audio/mpeg';
const splitMarker = 'SPLIT_MARKER';
@ -45,7 +46,7 @@ export const useAudioPlay = (props?: OutLinkChatAuthProps & { ttsConfig?: AppTTS
setAudioLoading(true);
audioController.current = new AbortController();
const response = await fetch('/api/core/chat/item/getSpeech', {
const response = await fetch(getWebReqUrl('/api/core/chat/item/getSpeech'), {
method: 'POST',
headers: {
'Content-Type': 'application/json'