diff --git a/frontend/src/components/layout/index.tsx b/frontend/src/components/layout/index.tsx index e0533852d0..e3486d5d5e 100644 --- a/frontend/src/components/layout/index.tsx +++ b/frontend/src/components/layout/index.tsx @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, Suspense } from 'react'; import type { MenuProps } from 'antd'; import { Layout, Menu } from 'antd'; import { MenuFoldOutlined } from '@ant-design/icons'; @@ -155,19 +155,21 @@ const AppLayout: React.FC = () => { - - {flattenRouteList.map((route) => ( - - ))} - - - - + loading}> + + {flattenRouteList.map((route) => ( + + ))} + + + + + diff --git a/frontend/src/locale/i18n.ts b/frontend/src/locale/i18n.ts index c8bb2f0047..59dd83f004 100644 --- a/frontend/src/locale/i18n.ts +++ b/frontend/src/locale/i18n.ts @@ -7,28 +7,17 @@ import i18n from 'i18next'; import { initReactI18next } from "react-i18next"; import en from './en_US.json'; import zh from './zh_CN.json'; -import coreEn from '@fit-elsa/elsa-core/locales/en.json'; -import coreZh from '@fit-elsa/elsa-core/locales/zh.json'; -import reactEn from '@fit-elsa/elsa-react/locales/en.json'; -import reactZh from '@fit-elsa/elsa-react/locales/zh.json'; - -const mergeTranslations = (...translationObjects) => { - // 从右向左合并(右侧优先级更高) - return translationObjects - .filter(obj => obj) // 过滤掉假值(undefined/null - .reduce((merged, current) => ({ ...merged, ...current }), {}); -}; const resources = { en: { - translation: mergeTranslations(coreEn, reactEn, en) // 优先级顺序: en > reactEn > coreEn + translation: en }, zh: { - translation: mergeTranslations(coreZh, reactZh, zh) // 优先级顺序: zh > reactZh > coreZh + translation: zh } }; -const getCookie = (cname) => { +const getCookie = (cname: string) => { const name = `${cname}=`; const ca = document.cookie.split(';'); for (let i = 0; i < ca.length; i++) { @@ -49,6 +38,4 @@ i18n.use(initReactI18next).init({ returnNull: false }); - - -export default i18n; +export default i18n; \ No newline at end of file diff --git a/frontend/src/pages/aippIndex/index.tsx b/frontend/src/pages/aippIndex/index.tsx index 5c1aa0bb53..1e183d8fe7 100644 --- a/frontend/src/pages/aippIndex/index.tsx +++ b/frontend/src/pages/aippIndex/index.tsx @@ -4,12 +4,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState, lazy, Suspense } from 'react'; import { Spin } from 'antd'; import { useParams } from 'react-router-dom'; import AddFlow from '../addFlow'; import ConfigForm from '../configForm'; -import CommonChat from '../chatPreview/chatComminPage'; +const CommonChat = lazy(() => import('../chatPreview/chatComminPage')); import ChoreographyHead from '../components/header'; import { getAppInfo, updateFormInfo } from '@/shared/http/aipp'; import { debounce, getCurrentTime, getUiD, setSpaClassName, getAppConfig } from '@/shared/utils/common'; @@ -215,12 +215,14 @@ const AippIndex = () => { onChangeShowConfig={handleChangeShowConfig} /> )} - + loading}> + + diff --git a/frontend/src/pages/chatPreview/components/chat-details.tsx b/frontend/src/pages/chatPreview/components/chat-details.tsx index 3c1a8ddbfb..ab298ea7e4 100644 --- a/frontend/src/pages/chatPreview/components/chat-details.tsx +++ b/frontend/src/pages/chatPreview/components/chat-details.tsx @@ -11,7 +11,6 @@ import { CreateAppIcon } from '@/assets/icon'; import { useAppDispatch, useAppSelector } from '@/store/hook'; import { findConfigValue } from '@/shared/utils/common'; import { convertImgPath } from '@/common/util'; -import EditModal from '@/pages/components/edit-modal'; import knowledgeBase from '@/assets/images/knowledge/knowledge-base.png'; import robot2 from '@/assets/images/ai/demo.png'; import '../styles/chat-details.scss'; @@ -103,7 +102,6 @@ const ChatDetail = ({ showMask = false }) => { )) : } - )}; }; diff --git a/frontend/src/router/route.ts b/frontend/src/router/route.ts index 11e7481825..9a9dcfd988 100644 --- a/frontend/src/router/route.ts +++ b/frontend/src/router/route.ts @@ -5,22 +5,23 @@ *--------------------------------------------------------------------------------------------*/ import type { MenuProps } from 'antd'; -import { ReactElement } from 'react'; +import { ReactElement, lazy } from 'react'; import { Icons } from '../components/icons/index'; -import IntelligentForm from '../pages/intelligent-form'; -import Plugin from '../pages/plugin'; -import ChatHome from '../pages/chatEngineHome/index'; -import ChatRunning from '../pages/chatRunning/index'; -import AppDetail from '../pages/appDetail'; -import AippIndex from '../pages/aippIndex'; -import AddFlow from '../pages/addFlow'; -import FlowDetail from '../pages/detailFlow'; -import Apps from '../pages/apps'; -import AppDev from '../pages/appDev/index'; -import PlugeDetail from '../pages/plugin/detail/plugin-list'; -import PlugeFlowDetail from '../pages/plugin/detail/plugin-flow-detail'; -import ViewReport from '../pages/appDetail/evaluate/task/viewReport'; -import HttpTool from '../pages/httpTool'; +const IntelligentForm = lazy(()=> import('../pages/intelligent-form')); +const Plugin = lazy(()=> import('../pages/plugin')); +const ChatHome = lazy(()=> import('../pages/chatEngineHome/index')); +const ChatRunning = lazy(()=> import('../pages/chatRunning/index')); +const AppDetail = lazy(()=> import('../pages/appDetail')); +const AippIndex = lazy(() => import('../pages/aippIndex')); +const AddFlow = lazy(()=> import('../pages/addFlow')); +const FlowDetail = lazy(()=> import('../pages/detailFlow')); +const Apps = lazy(()=> import('../pages/apps')); +const AppDev = lazy(()=> import('../pages/appDev/index')); +const PlugeDetail = lazy(()=> import('../pages/plugin/detail/plugin-list')); +const PlugeFlowDetail = lazy(()=> import('../pages/plugin/detail/plugin-flow-detail')); +const ViewReport = lazy(()=> import('../pages/appDetail/evaluate/task/viewReport')); +const HttpTool = lazy(()=> import('../pages/httpTool')); + import i18n from '../locale/i18n'; export type MenuItem = Required['items'][number] & { diff --git a/frontend/src/shared/utils/common.ts b/frontend/src/shared/utils/common.ts index 6772759193..812a751ee6 100644 --- a/frontend/src/shared/utils/common.ts +++ b/frontend/src/shared/utils/common.ts @@ -2,7 +2,6 @@ import { useLocation } from 'react-router-dom'; import { useCallback, useMemo, useState } from 'react'; import { pick, find, filter } from 'lodash'; import { Message } from '@/shared/utils/message'; -import { createGraphOperator } from '@fit-elsa/elsa-react'; import { storage } from '../storage'; import i18n from '@/locale/i18n'; import { getAppCategories } from "@/shared/http/aipp"; @@ -450,3 +449,126 @@ export const getAppConfig = (appInfo) => { export const generateUniqueName = () => { return 'guest-' + nanoid(16); } + +// ==================== GraphOperator ==================== + +// 数据类型常量 +const DATA_TYPES = { + STRING: 'String', + INTEGER: 'Integer', + BOOLEAN: 'Boolean', + NUMBER: 'Number', + OBJECT: 'Object', + ARRAY: 'Array', +}; + +// 来源类型常量 +const FROM_TYPE = { + EXPAND: 'Expand', + INPUT: 'Input', + REFERENCE: 'Reference', +}; + +/** + * 将配置数据转换为结构体 + * @param config 配置数据 + * @return {{}|*} 结构体 + */ +const configToStruct = (config: any) => { + if (config.type === DATA_TYPES.ARRAY) { + return config.value.map(v => configToStruct(v)); + } else if (config.type === DATA_TYPES.OBJECT) { + const obj = {}; + config.value.forEach((item: any) => { + obj[item.name] = configToStruct(item); + }); + return obj; + } else { + return Object.prototype.hasOwnProperty.call(config, 'value') ? config.value : config; + } +}; + +/** + * 创建画布操纵器 + * @param graphString 画布字符串 + * @return {{}} 画布操纵器对象 + */ +export const createGraphOperator = (graphString: string) => { + const graph = JSON.parse(graphString); + const shapes = graph.pages[0].shapes; + + const getInputParams = (shape: any) => { + if (shape.type === 'startNodeStart') { + return shape.flowMeta.inputParams; + } else if (shape.type === 'endNodeEnd') { + return shape.flowMeta.callback.converter.entity.inputParams; + } else { + return shape.flowMeta.jober.converter.entity.inputParams; + } + }; + + const getConfigByKeys = (keys: string[]) => { + if (!Array.isArray(keys)) { + throw new Error('Expected keys to be an array'); + } + + if (keys.length === 0) { + return null; + } + + const tmpKeys = [...keys]; + const shapeId = tmpKeys.shift(); + const shape = getShapeById(shapeId); + const inputParams = getInputParams(shape); + if (!inputParams) { + throw new Error('Expected inputParams exists'); + } + let config = {type: DATA_TYPES.OBJECT, value: inputParams}; + while (tmpKeys.length > 0 && config && config.value) { + const key = tmpKeys.shift(); + config = config.value.find(v => v.name === key); + } + return config; + }; + + const getShapeById = (shapeId: string) => { + return shapes.find((shape) => shape.id === shapeId); + }; + + return { + /** + * 获取配置信息 + * @param keys 键值数组 + * @return {{}|*|null} 配置信息 + */ + getConfig: (keys: string[]) => { + const config = getConfigByKeys(keys); + return config ? configToStruct(config) : null; + }, + + /** + * 获取画布中开始节点的入参信息 + * @return {array} 开始节点入参信息 + */ + getStartNodeInputParams: (): any[] => { + return shapes.filter(shape => shape.type === 'startNodeStart').map(startNode => startNode.flowMeta.inputParams); + }, + + /** + * 根据节点类型获取对应节点id列表 + * @param type 节点类型 + * @returns {array} 对应节点id列表 + */ + getShapeIdsByType: (type: string): string[] => { + return shapes.filter((shape) => shape.type === type).map((shape) => shape.id); + }, + + /** + * 获取画布数据 + * @return {string} 画布数据 + */ + getGraph: (): string => { + return JSON.stringify(graph); + } + }; +};