mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
4.8.10 test (#2539)
* fix: i18n * fix: null value * fix: workflow refresh variables * perf: copy data * doc * perf: run app code * perf: variable store * update doc * perf: pay ui * fix: log header ui * fix: log header ui
This commit is contained in:
@@ -53,19 +53,27 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4810' \
|
||||
4. 新增 - 工作流撤销和重做
|
||||
5. 新增 - 工作流本次编辑记录,取代自动保存
|
||||
6. 新增 - 工作流版本支持重命名
|
||||
7. 商业版新增 - 飞书机器人接入
|
||||
8. 商业版新增 - 公众号接入接入
|
||||
9. 商业版新增 - 自助开票申请
|
||||
10. 商业版新增 - SSO 定制
|
||||
11. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
|
||||
12. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。
|
||||
13. 优化 - 最新 React Markdown 组件,支持 Base64 图片。
|
||||
14. 优化 - 知识库列表 UI。
|
||||
15. 优化 - 支持无网络配置情况下运行。
|
||||
16. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。
|
||||
17. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
|
||||
18. 修复 - 选择 Milvus 部署时,无法导出知识库。
|
||||
19. 修复 - 创建 APP 副本,无法复制系统配置。
|
||||
20. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
|
||||
21. 修复 - 内容提取的数据类型与输出数据类型未一致。
|
||||
22. 修复 - 工作流运行时间统计错误。
|
||||
7. 新增 - 应用调用迁移成单独节点,同时可以传递全局变量和用户的文件。
|
||||
8. 商业版新增 - 飞书机器人接入
|
||||
9. 商业版新增 - 公众号接入接入
|
||||
10. 商业版新增 - 自助开票申请
|
||||
11. 商业版新增 - SSO 定制
|
||||
12. 优化 - SSE 响应优化。
|
||||
13. 优化 - 无 SSL 证书情况下,优化复制。
|
||||
14. 优化 - 单选框打开后自动滚动到选中的位置。
|
||||
15. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
|
||||
16. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。
|
||||
17. 优化 - 最新 React Markdown 组件,支持 Base64 图片。
|
||||
18. 优化 - 知识库列表 UI。
|
||||
19. 优化 - 支持无网络配置情况下运行。
|
||||
20. 优化 - 部分全局变量,增加数据类型约束。
|
||||
21. 修复 - 全局变量 key 可能重复。
|
||||
22. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。
|
||||
23. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
|
||||
24. 修复 - 选择 Milvus 部署时,无法导出知识库。
|
||||
25. 修复 - 创建 APP 副本,无法复制系统配置。
|
||||
26. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
|
||||
27. 修复 - 内容提取的数据类型与输出数据类型未一致。
|
||||
28. 修复 - 工作流运行时间统计错误。
|
||||
29. 修复 - stream 模式下,工具调用有可能出现 undefined
|
||||
30. 修复 - 全局变量在 API 中无法持久化。
|
||||
|
@@ -45,8 +45,7 @@ const systemNodes: FlowNodeTemplateType[] = [
|
||||
LafModule,
|
||||
IfElseNode,
|
||||
VariableUpdateNode,
|
||||
CodeNode,
|
||||
RunAppModule
|
||||
CodeNode
|
||||
];
|
||||
/* app flow module templates */
|
||||
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
|
||||
@@ -72,5 +71,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
|
||||
),
|
||||
EmptyNode,
|
||||
RunPluginModule,
|
||||
RunAppPluginModule
|
||||
RunAppPluginModule,
|
||||
RunAppModule
|
||||
];
|
||||
|
@@ -72,15 +72,3 @@ export const standardSubLevelMap = {
|
||||
weight: 5
|
||||
}
|
||||
};
|
||||
|
||||
export enum PackageChangeStatusEnum {
|
||||
buy = 'buy',
|
||||
renewal = 'renewal',
|
||||
upgrade = 'upgrade'
|
||||
}
|
||||
|
||||
export const packagePayTextMap = {
|
||||
[PackageChangeStatusEnum.buy]: i18nT('common:pay.package_tip.buy'),
|
||||
[PackageChangeStatusEnum.renewal]: i18nT('common:pay.package_tip.renewal'),
|
||||
[PackageChangeStatusEnum.upgrade]: i18nT('common:pay.package_tip.upgrade')
|
||||
};
|
||||
|
@@ -5,7 +5,6 @@ import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/c
|
||||
import { delFileByFileIdList, getGFSCollection } from '../../common/file/gridfs/controller';
|
||||
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||
import { MongoChat } from './chatSchema';
|
||||
import { ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d';
|
||||
|
||||
export async function getChatItems({
|
||||
appId,
|
||||
@@ -37,24 +36,6 @@ export async function getChatItems({
|
||||
return { histories };
|
||||
}
|
||||
|
||||
export async function getChat({
|
||||
appId,
|
||||
chatId,
|
||||
field
|
||||
}: {
|
||||
appId: string;
|
||||
chatId?: string;
|
||||
field: string;
|
||||
}): Promise<{ chat: ChatType | null }> {
|
||||
if (!chatId) {
|
||||
return { chat: null };
|
||||
}
|
||||
|
||||
const chat = await MongoChat.findOne({ appId, chatId }, field).lean();
|
||||
|
||||
return { chat };
|
||||
}
|
||||
|
||||
/* Temporary adaptation for old conversation records */
|
||||
export const adaptStringValue = (value: any): ChatItemValueItemType[] => {
|
||||
if (typeof value === 'string') {
|
||||
|
@@ -357,7 +357,7 @@ async function streamResponse({
|
||||
const responseChoice = part.choices?.[0]?.delta;
|
||||
// console.log(responseChoice, '---===');
|
||||
|
||||
if (responseChoice.content) {
|
||||
if (responseChoice?.content) {
|
||||
const content = responseChoice?.content || '';
|
||||
textAnswer += content;
|
||||
|
||||
|
@@ -44,7 +44,7 @@ const MyMenu = ({
|
||||
iconSize = '1rem',
|
||||
Button,
|
||||
menuList,
|
||||
iconRadius = 'sm',
|
||||
iconRadius,
|
||||
placement = 'bottom-start'
|
||||
}: Props) => {
|
||||
const typeMapStyle: Record<MenuItemType, MenuItemProps> = {
|
||||
|
@@ -126,6 +126,7 @@
|
||||
"Confirm to leave the page": "Confirm to leave the page?",
|
||||
"Copy": "Copy",
|
||||
"Copy Successful": "Copy Successful",
|
||||
"Copy_failed": "Copy failed, please copy manually",
|
||||
"Create Failed": "Create Failed",
|
||||
"Create New": "Create New",
|
||||
"Create Success": "Create Success",
|
||||
@@ -1430,7 +1431,7 @@
|
||||
"Quote Content Tip": "You can customize the structure of the quote content to better adapt to different scenarios. You can use some variables for template configuration:\n{{q}} - search content, {{a}} - expected content, {{source}} - source, {{sourceId}} - source file name, {{index}} - the nth quote, they are all optional, here are the default values:\n{{default}}",
|
||||
"Quote Prompt Tip": "You can use {{quote}} to insert the quote content template, and use {{question}} to insert the question. Here are the default values:\n{{default}}"
|
||||
},
|
||||
"textarea_variable_picker_tip": "Input / to select variables",
|
||||
"textarea_variable_picker_tip": "Input '/' to select variables",
|
||||
"tool_field": "Tool field parameter configuration",
|
||||
"undefined_var": "An undefined variable is referenced. Is it automatically added?",
|
||||
"unit": {
|
||||
|
@@ -128,6 +128,7 @@
|
||||
"Confirm to leave the page": "确认离开该页面?",
|
||||
"Copy": "复制",
|
||||
"Copy Successful": "复制成功",
|
||||
"Copy_failed": "复制失败,请手动复制",
|
||||
"Create Failed": "创建异常",
|
||||
"Create New": "新建",
|
||||
"Create Success": "创建成功",
|
||||
@@ -637,7 +638,8 @@
|
||||
"success": "开始同步"
|
||||
}
|
||||
},
|
||||
"training": {}
|
||||
"training": {
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Auxiliary Data": "辅助数据",
|
||||
@@ -1429,7 +1431,7 @@
|
||||
"Quote Content Tip": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置:\n{{q}} - 检索内容,{{a}} - 预期内容,{{source}} - 来源,{{sourceId}} - 来源文件名,{{index}} - 第 n 个引用,他们都是可选的,下面是默认值:\n{{default}}",
|
||||
"Quote Prompt Tip": "可以用 {{quote}} 来插入引用内容模板,使用 {{question}} 来插入问题。下面是默认值:\n{{default}}"
|
||||
},
|
||||
"textarea_variable_picker_tip": "输入 / 可选择变量",
|
||||
"textarea_variable_picker_tip": "输入\"/\"可选择变量",
|
||||
"tool_field": "工具字段参数配置",
|
||||
"undefined_var": "引用了未定义的变量,是否自动添加?",
|
||||
"unit": {
|
||||
|
@@ -58,6 +58,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
const [baseUrl, setBaseUrl] = useState('https://fastgpt.in/api');
|
||||
const [editData, setEditData] = useState<EditProps>();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
type: 'delete',
|
||||
content: t('workflow:delete_api')
|
||||
@@ -271,6 +272,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
wordBreak={'break-all'}
|
||||
cursor={'pointer'}
|
||||
borderRadius={'md'}
|
||||
userSelect={'all'}
|
||||
onClick={() => copyData(apiKey)}
|
||||
>
|
||||
<Box flex={1}>{apiKey}</Box>
|
||||
|
@@ -75,7 +75,7 @@ const QRCodePayModal = ({
|
||||
<MyModal isOpen title={t('common:user.Pay')} iconSrc="/imgs/modal/pay.svg">
|
||||
<ModalBody textAlign={'center'} py={6} whiteSpace={'pre'}>
|
||||
{tip && (
|
||||
<Box textAlign={'left'} whiteSpace={'normal'} mb={3}>
|
||||
<Box fontSize={'sm'} whiteSpace={'normal'} mb={3}>
|
||||
{tip}
|
||||
</Box>
|
||||
)}
|
||||
|
@@ -43,7 +43,7 @@ const StandardPlanContentList = ({
|
||||
}, [subPlans?.standard, level, mode]);
|
||||
|
||||
return planContent ? (
|
||||
<Grid gap={4} fontSize={'sm'}>
|
||||
<Grid gap={4} fontSize={'sm'} fontWeight={500}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'price/right'} w={'16px'} mr={3} />
|
||||
<Box color={'myGray.600'}>
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import ApiKeyTable from '@/components/support/apikey/Table';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
|
@@ -16,7 +16,6 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { getTeamPlans } from '@/web/support/user/team/api';
|
||||
@@ -25,7 +24,6 @@ import {
|
||||
standardSubLevelMap,
|
||||
SubTypeEnum
|
||||
} from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
|
||||
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
@@ -71,7 +69,7 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
|
||||
isCentered
|
||||
>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<ModalBody px={'3.25rem'} py={'2rem'}>
|
||||
<ModalBody px={[4, 8]} py={[2, 6]}>
|
||||
<TableContainer mt={2} position={'relative'} minH={'300px'}>
|
||||
<Table>
|
||||
<Thead>
|
||||
@@ -100,7 +98,6 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
|
||||
? subPlans?.standard?.[currentSubLevel]
|
||||
: undefined;
|
||||
const datasetSize = standardPlan?.maxDatasetSize || currentExtraDatasetSize;
|
||||
const now = new Date();
|
||||
|
||||
return (
|
||||
<Tr key={_id} fontWeight={500} fontSize={'mini'} color={'myGray.900'}>
|
||||
|
@@ -20,7 +20,7 @@ import {
|
||||
textAdaptGptResponse
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { GPTMessages2Chats, chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getChat, getChatItems } from '@fastgpt/service/core/chat/controller';
|
||||
import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
||||
import { saveChat } from '@fastgpt/service/core/chat/saveChat';
|
||||
import { responseWrite } from '@fastgpt/service/common/response';
|
||||
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
||||
@@ -216,11 +216,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
}
|
||||
return latestHumanChat;
|
||||
})();
|
||||
const { text, files } = chatValue2RuntimePrompt(userQuestion.value);
|
||||
|
||||
// Get and concat history;
|
||||
const limit = getMaxHistoryLimitFromNodes(app.modules);
|
||||
const [{ histories }, { nodes, edges, chatConfig }, { chat }] = await Promise.all([
|
||||
const [{ histories }, { nodes, edges, chatConfig }, chatDetail] = await Promise.all([
|
||||
getChatItems({
|
||||
appId: app._id,
|
||||
chatId,
|
||||
@@ -228,32 +227,27 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
field: `dataId obj value nodeOutputs`
|
||||
}),
|
||||
getAppLatestVersion(app._id, app),
|
||||
getChat({
|
||||
appId: app._id,
|
||||
chatId,
|
||||
field: 'source variableList variables'
|
||||
})
|
||||
MongoChat.findOne({ appId: app._id, chatId }, 'source variableList variables')
|
||||
]);
|
||||
// get chat histories
|
||||
|
||||
// Get chat histories
|
||||
const newHistories = concatHistories(histories, chatMessages);
|
||||
|
||||
// get global variables
|
||||
if (chat && chat.variables) {
|
||||
// Get store variables(Api variable precedence)
|
||||
if (chatDetail?.variables) {
|
||||
variables = {
|
||||
...chat.variables,
|
||||
...chatDetail.variables,
|
||||
...variables
|
||||
};
|
||||
}
|
||||
|
||||
// Get runtimeNodes
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, newHistories));
|
||||
|
||||
if (isPlugin) {
|
||||
// Rewrite plugin run params variables
|
||||
variables = removePluginInputVariables(variables, runtimeNodes);
|
||||
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
|
||||
}
|
||||
|
||||
runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes);
|
||||
|
||||
const workflowResponseWrite = getWorkflowResponseWrite({
|
||||
|
@@ -1,10 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Flex, Box, useTheme } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { HUMAN_ICON } from '@fastgpt/global/common/system/constants';
|
||||
import { getInitChatInfo } from '@/web/core/chat/api';
|
||||
import MyTag from '@fastgpt/web/components/common/Tag/index';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
@@ -17,6 +15,8 @@ import CloseIcon from '@fastgpt/web/components/common/Icon/close';
|
||||
import ChatBox from '@/components/core/chat/ChatContainer/ChatBox';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { PcHeader } from '@/pages/chat/components/ChatHeader';
|
||||
|
||||
const PluginRunBox = dynamic(() => import('@/components/core/chat/ChatContainer/PluginRunBox'));
|
||||
|
||||
const DetailLogsModal = ({
|
||||
@@ -124,26 +124,7 @@ const DetailLogsModal = ({
|
||||
>
|
||||
{isPc ? (
|
||||
<>
|
||||
<Box mr={3} color={'myGray.1000'}>
|
||||
{title}
|
||||
</Box>
|
||||
{chatRecords.length > 0 && (
|
||||
<>
|
||||
<MyTag colorSchema="blue">
|
||||
<MyIcon name={'history'} w={'14px'} />
|
||||
<Box ml={1}>
|
||||
{t('common:core.chat.History Amount', { amount: chatRecords.length })}
|
||||
</Box>
|
||||
</MyTag>
|
||||
{!!chatModels && (
|
||||
<MyTag ml={2} colorSchema={'green'}>
|
||||
<MyIcon name={'core/chat/chatModelTag'} w={'14px'} />
|
||||
<Box ml={1}>{chatModels.join(',')}</Box>
|
||||
</MyTag>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<PcHeader title={title || ''} history={chatRecords} chatModels={chatModels} />
|
||||
<Box flex={1} />
|
||||
</>
|
||||
) : (
|
||||
|
@@ -408,7 +408,6 @@ const RenderList = React.memo(function RenderList({
|
||||
templates.forEach((item) => {
|
||||
const index = copy.findIndex((template) => template.type === item.templateType);
|
||||
if (index === -1) return;
|
||||
if (item.flowNodeType === FlowNodeTypeEnum.runApp) return;
|
||||
copy[index].list.push(item);
|
||||
});
|
||||
return copy.filter((item) => item.list.length > 0);
|
||||
|
@@ -52,7 +52,7 @@ const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
label: item.label
|
||||
};
|
||||
});
|
||||
}, [nodeList, t]);
|
||||
}, [nodeList, appDetail.chatConfig, t]);
|
||||
|
||||
return (
|
||||
<NodeCard
|
||||
|
@@ -248,7 +248,7 @@ const MobileHeader = ({
|
||||
);
|
||||
};
|
||||
|
||||
const PcHeader = ({
|
||||
export const PcHeader = ({
|
||||
title,
|
||||
chatModels,
|
||||
history
|
||||
@@ -260,7 +260,7 @@ const PcHeader = ({
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<Box mr={3} maxW={'160px'} className="textEllipsis" color={'myGray.1000'}>
|
||||
<Box mr={3} maxW={'200px'} className="textEllipsis" color={'myGray.1000'}>
|
||||
{title}
|
||||
</Box>
|
||||
<MyTag>
|
||||
|
@@ -2,12 +2,7 @@ import React, { useMemo, useState } from 'react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { Box, Button, Flex, Grid, HStack } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
StandardSubLevelEnum,
|
||||
SubModeEnum,
|
||||
PackageChangeStatusEnum,
|
||||
packagePayTextMap
|
||||
} from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
@@ -16,8 +11,12 @@ import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRC
|
||||
import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
|
||||
import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
|
||||
export enum PackageChangeStatusEnum {
|
||||
buy = 'buy',
|
||||
renewal = 'renewal',
|
||||
upgrade = 'upgrade'
|
||||
}
|
||||
|
||||
const Standard = ({
|
||||
standardPlan: myStandardPlan,
|
||||
@@ -27,8 +26,13 @@ const Standard = ({
|
||||
refetchTeamSubPlan: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
const packagePayTextMap = {
|
||||
[PackageChangeStatusEnum.buy]: t('common:pay.package_tip.buy'),
|
||||
[PackageChangeStatusEnum.renewal]: t('common:pay.package_tip.renewal'),
|
||||
[PackageChangeStatusEnum.upgrade]: t('common:pay.package_tip.upgrade')
|
||||
};
|
||||
|
||||
const [packageChange, setPackageChange] = useState<PackageChangeStatusEnum>();
|
||||
const { subPlans, feConfigs } = useSystemStore();
|
||||
const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
|
||||
@@ -177,7 +181,8 @@ const Standard = ({
|
||||
boxShadow={'0'}
|
||||
cursor={'default'}
|
||||
w={'100%'}
|
||||
variant={isCurrentPlan ? 'whiteBase' : 'solid'}
|
||||
isDisabled
|
||||
variant={'whiteBase'}
|
||||
>
|
||||
{t('common:free')}
|
||||
</Button>
|
||||
@@ -265,7 +270,7 @@ const Standard = ({
|
||||
</Grid>
|
||||
|
||||
{!!qrPayData && packageChange && (
|
||||
<QRCodePayModal tip={t(packagePayTextMap[packageChange])} {...qrPayData} />
|
||||
<QRCodePayModal tip={packagePayTextMap[packageChange]} {...qrPayData} />
|
||||
)}
|
||||
</Flex>
|
||||
<HStack mt={8} color={'blue.700'} ml={8}>
|
||||
|
@@ -2,6 +2,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useCallback } from 'react';
|
||||
import { hasHttps } from '@fastgpt/web/common/system/utils';
|
||||
import { isProduction } from '@fastgpt/service/common/system/constants';
|
||||
|
||||
/**
|
||||
* copy text data
|
||||
@@ -17,20 +18,31 @@ export const useCopyData = () => {
|
||||
duration = 1000
|
||||
) => {
|
||||
try {
|
||||
if (hasHttps() && navigator.clipboard) {
|
||||
if (hasHttps() && !isProduction && navigator.clipboard) {
|
||||
await navigator.clipboard.writeText(data);
|
||||
} else {
|
||||
throw new Error('');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// console.log(error);
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = data;
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.opacity = '0';
|
||||
document.body.appendChild(textarea);
|
||||
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body?.removeChild(textarea);
|
||||
const res = document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
|
||||
if (!res) {
|
||||
return toast({
|
||||
title: t('common:common.Copy_failed'),
|
||||
status: 'error',
|
||||
duration
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (title) {
|
||||
|
Reference in New Issue
Block a user