perf: workflow code (#2492)

* perf: workflow code

* perf: converpoints ui

* perf: account page ui
This commit is contained in:
Archer
2024-08-23 17:56:38 +08:00
committed by GitHub
parent eaaf6f5978
commit 3e57c7f559
11 changed files with 69 additions and 50 deletions

View File

@@ -28,17 +28,20 @@ STORE_LOG_LEVEL=warn
1. 新增 - 模板市场 1. 新增 - 模板市场
2. 新增 - 工作流节点拖动自动对齐吸附 2. 新增 - 工作流节点拖动自动对齐吸附
3. 新增 - 用户选择节点Debug 模式暂未支持) 3. 新增 - 用户选择节点Debug 模式暂未支持)
4. 商业版新增 - 飞书机器人接入 4. 新增 - 工作流撤销和重做
5. 商业版新增 - 公众号接入接入 5. 新增 - 工作流本次编辑记录,取代自动保存
6. 商业版新增 - 自助开票申请 6. 新增 - 工作流版本支持重命名
7. 商业版新增 - SSO 定制 7. 商业版新增 - 飞书机器人接入
8. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 8. 商业版新增 - 公众号接入接入
9. 优化 - 节点选择,避免切换 tab 时候path 加载报错。 9. 商业版新增 - 自助开票申请
10. 优化 - 最新 React Markdown 组件,支持 Base64 图片。 10. 商业版新增 - SSO 定制
11. 优化 - 知识库列表 UI 11. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态
12. 优化 - 支持无网络配置情况下运行 12. 优化 - 节点选择,避免切换 tab 时候path 加载报错
13. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记 13. 优化 - 最新 React Markdown 组件,支持 Base64 图片
14. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情 14. 优化 - 知识库列表 UI
15. 修复 - 选择 Milvus 部署时,无法导出知识库。 15. 优化 - 支持无网络配置情况下运行。
16. 修复 - 创建 APP 副本,无法复制系统配置 16. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记
17. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题 17. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情
18. 修复 - 选择 Milvus 部署时,无法导出知识库。
19. 修复 - 创建 APP 副本,无法复制系统配置。
20. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。

View File

@@ -1,4 +1,4 @@
import React from 'react'; import React, { useMemo } from 'react';
import { ModalBody, Box, Button, VStack, HStack, Link } from '@chakra-ui/react'; import { ModalBody, Box, Button, VStack, HStack, Link } from '@chakra-ui/react';
import MyModal from '@fastgpt/web/components/common/MyModal'; import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
@@ -6,22 +6,33 @@ import Icon from '@fastgpt/web/components/common/Icon';
import Tag from '@fastgpt/web/components/common/Tag'; import Tag from '@fastgpt/web/components/common/Tag';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { balanceConversion } from '@/web/support/wallet/bill/api'; import { balanceConversion } from '@/web/support/wallet/bill/api';
import Loading from '@fastgpt/web/components/common/MyLoading'; import { useUserStore } from '@/web/support/user/useUserStore';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
import { SUB_EXTRA_POINT_RATE } from '@fastgpt/global/support/wallet/bill/constants';
import { useRouter } from 'next/router';
const ConversionModal = ({ const ConversionModal = ({
onClose, onClose,
balance,
tokens,
onOpenContact onOpenContact
}: { }: {
onClose: () => void; onClose: () => void;
balance: string;
tokens: string;
onOpenContact: () => void; onOpenContact: () => void;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { userInfo } = useUserStore();
const router = useRouter();
const points = useMemo(() => {
if (!userInfo?.team?.balance) return 0;
const balance = formatStorePrice2Read(userInfo?.team?.balance);
return Math.ceil((balance / 15) * SUB_EXTRA_POINT_RATE);
}, []);
const { runAsync: onConvert, loading } = useRequest2(balanceConversion, { const { runAsync: onConvert, loading } = useRequest2(balanceConversion, {
onSuccess() {
router.reload();
},
successToast: t('user:bill.convert_success'), successToast: t('user:bill.convert_success'),
errorToast: t('user:bill.convert_error') errorToast: t('user:bill.convert_error')
}); });
@@ -35,7 +46,6 @@ const ConversionModal = ({
title={t('user:bill.use_balance')} title={t('user:bill.use_balance')}
> >
<ModalBody maxW={'450px'}> <ModalBody maxW={'450px'}>
{loading && <Loading />}
<VStack px="2.25" gap={2} pb="6"> <VStack px="2.25" gap={2} pb="6">
<HStack px="4" py="2" color="primary.600" bgColor="primary.50" borderRadius="md"> <HStack px="4" py="2" color="primary.600" bgColor="primary.50" borderRadius="md">
<Icon name="common/info" w="1rem" mr="1" /> <Icon name="common/info" w="1rem" mr="1" />
@@ -43,10 +53,10 @@ const ConversionModal = ({
</HStack> </HStack>
<VStack mt={6}> <VStack mt={6}>
<Box fontSize={'sm'} color="myGray.600" fontWeight="500"> <Box fontSize={'sm'} color="myGray.600" fontWeight="500">
{t('user:bill.price')}
</Box> </Box>
<Box fontSize={'xl'} fontWeight={'700'} color="myGray.900"> <Box fontSize={'xl'} fontWeight={'700'} color="myGray.900">
15/1000 {t('user:bill.tokens')} 15/1000 {t('user:bill.tokens')}/
</Box> </Box>
</VStack> </VStack>
<VStack mt={6}> <VStack mt={6}>
@@ -54,7 +64,7 @@ const ConversionModal = ({
{t('user:bill.balance')} {t('user:bill.balance')}
</Box> </Box>
<Box fontSize={'xl'} fontWeight={'700'} color="myGray.900"> <Box fontSize={'xl'} fontWeight={'700'} color="myGray.900">
{balance} {formatStorePrice2Read(userInfo?.team?.balance)?.toFixed(2)}
</Box> </Box>
</VStack> </VStack>
<VStack mt={6}> <VStack mt={6}>
@@ -62,9 +72,9 @@ const ConversionModal = ({
{t('user:bill.you_can_convert')} {t('user:bill.you_can_convert')}
</Box> </Box>
<Box fontSize={'xl'} fontWeight={'700'} color="myGray.900"> <Box fontSize={'xl'} fontWeight={'700'} color="myGray.900">
{tokens} {t('user:bill.tokens')} {points} {t('user:bill.tokens')}
</Box> </Box>
<Tag>{t('user:bill.token_expire_1year')}</Tag> <Tag fontSize={'lg'}>{t('user:bill.token_expire_1year')}</Tag>
</VStack> </VStack>
<VStack mt="6"> <VStack mt="6">
@@ -74,6 +84,7 @@ const ConversionModal = ({
fontSize={'sm'} fontSize={'sm'}
minW={'10rem'} minW={'10rem'}
onClick={onConvert} onClick={onConvert}
isLoading={loading}
> >
{t('user:bill.conversion')} {t('user:bill.conversion')}
</Button> </Button>

View File

@@ -305,22 +305,18 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
<Box flex={1}> <Box flex={1}>
<strong>{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}</strong> <strong>{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}</strong>
</Box> </Box>
{userInfo?.permission.hasManagePer && !!standardPlan && ( {/* TODO:暂时隐藏 */}
{/* {userInfo?.permission.hasManagePer && !!standardPlan && (
<Button variant={'primary'} size={'sm'} ml={5} onClick={onOpenConversionModal}> <Button variant={'primary'} size={'sm'} ml={5} onClick={onOpenConversionModal}>
{t('user:bill.conversion')} {t('user:bill.conversion')}
</Button> </Button>
)} )} */}
</Flex> </Flex>
</Box> </Box>
)} )}
</Box> </Box>
{isOpenConversionModal && ( {isOpenConversionModal && (
<ConversionModal <ConversionModal onClose={onCloseConversionModal} onOpenContact={onOpenContact} />
onClose={onCloseConversionModal}
balance={formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}
tokens={String((userInfo?.team?.balance ?? 0) / 15 / 10)}
onOpenContact={onOpenContact}
/>
)} )}
{isOpenUpdatePsw && <UpdatePswModal onClose={onCloseUpdatePsw} />} {isOpenUpdatePsw && <UpdatePswModal onClose={onCloseUpdatePsw} />}
{isOpenUpdateNotification && <UpdateNotification onClose={onCloseUpdateNotification} />} {isOpenUpdateNotification && <UpdateNotification onClose={onCloseUpdateNotification} />}

View File

@@ -21,6 +21,7 @@ import { subTypeMap, standardSubLevelMap } from '@fastgpt/global/support/wallet/
import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type'; import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time'; import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
const StandDetailModal = ({ onClose }: { onClose: () => void }) => { const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { Loading } = useLoading(); const { Loading } = useLoading();
@@ -33,6 +34,7 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
maxW={['90vw', '1200px']} maxW={['90vw', '1200px']}
iconSrc="modal/teamPlans" iconSrc="modal/teamPlans"
title={t('common:support.wallet.Standard Plan Detail')} title={t('common:support.wallet.Standard Plan Detail')}
isCentered
> >
<ModalCloseButton onClick={onClose} /> <ModalCloseButton onClick={onClose} />
<ModalBody> <ModalBody>

View File

@@ -8,7 +8,7 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import PageContainer from '@/components/PageContainer'; import PageContainer from '@/components/PageContainer';
import SideTabs from '@/components/SideTabs'; import SideTabs from '@/components/SideTabs';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import UserInfo from './components/Info'; import UserInfo from './components/Info/index';
import { serviceSideProps } from '@/web/common/utils/i18n'; import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import Script from 'next/script'; import Script from 'next/script';

View File

@@ -38,7 +38,8 @@ const WorkflowEdit = () => {
cloneDeep({ cloneDeep({
nodes: appDetail.modules || [], nodes: appDetail.modules || [],
edges: appDetail.edges || [] edges: appDetail.edges || []
}) }),
true
); );
} }
}); });

View File

@@ -61,6 +61,9 @@ const Header = () => {
} = useContextSelector(WorkflowContext, (v) => v); } = useContextSelector(WorkflowContext, (v) => v);
const isPublished = useMemo(() => { const isPublished = useMemo(() => {
/*
Find the last saved snapshot in the past and future snapshots
*/
const savedSnapshot = const savedSnapshot =
future.findLast((snapshot) => snapshot.isSaved) || past.find((snapshot) => snapshot.isSaved); future.findLast((snapshot) => snapshot.isSaved) || past.find((snapshot) => snapshot.isSaved);
@@ -97,6 +100,7 @@ const Header = () => {
//@ts-ignore //@ts-ignore
version: 'v2' version: 'v2'
}); });
// Mark the current snapshot as saved
setPast((prevPast) => setPast((prevPast) =>
prevPast.map((item, index) => prevPast.map((item, index) =>
index === prevPast.length - 1 index === prevPast.length - 1

View File

@@ -424,7 +424,7 @@ const WorkflowContextProvider = ({
const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => { const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => {
const { nodeId, type } = props; const { nodeId, type } = props;
setNodes((nodes) => { setNodes((nodes) => {
const newNodes = nodes.map((node) => { return nodes.map((node) => {
if (node.id !== nodeId) return node; if (node.id !== nodeId) return node;
const updateObj = cloneDeep(node.data); const updateObj = cloneDeep(node.data);
@@ -490,7 +490,6 @@ const WorkflowContextProvider = ({
data: updateObj data: updateObj
}; };
}); });
return newNodes;
}); });
}); });
const getNodeDynamicInputs = useCallback( const getNodeDynamicInputs = useCallback(
@@ -532,6 +531,13 @@ const WorkflowContextProvider = ({
const initData = useMemoizedFn( const initData = useMemoizedFn(
async (e: Parameters<WorkflowContextType['initData']>[0], isInit?: boolean) => { async (e: Parameters<WorkflowContextType['initData']>[0], isInit?: boolean) => {
/*
Refresh web page, load init
*/
if (isInit && past.length > 0) {
return resetSnapshot(past[0]);
}
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })) || []); setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })) || []);
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })) || []); setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })) || []);
@@ -544,12 +550,7 @@ const WorkflowContextProvider = ({
} }
// If it is the initial data, save the initial snapshot // If it is the initial data, save the initial snapshot
if (!isInit) return; if (isInit) {
// If it has been initialized, it will not be saved
if (past.length > 0) {
resetSnapshot(past[0]);
return;
}
saveSnapshot({ saveSnapshot({
pastNodes: e.nodes?.map((item) => storeNode2FlowNode({ item })) || [], pastNodes: e.nodes?.map((item) => storeNode2FlowNode({ item })) || [],
pastEdges: e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })) || [], pastEdges: e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })) || [],
@@ -558,6 +559,7 @@ const WorkflowContextProvider = ({
isSaved: true isSaved: true
}); });
} }
}
); );
/* ui flow to store data */ /* ui flow to store data */