mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-07-16 16:20:10 +08:00
feat: plugin system
This commit is contained in:
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"Antd",
|
||||
"apinto",
|
||||
"Apipark",
|
||||
"logsettings",
|
||||
"resourcesettings"
|
||||
]
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
# 部署
|
||||
|
||||
## 代码同步
|
||||
packages目录下,部分子项目为企业版独有,不要同步到开源版:
|
||||
packages/businessEntry, packages/openApi, packages/systemRunning, README.pro.md
|
||||
|
||||
## 安装依赖
|
||||
建议使用pnpm
|
||||
`npm install -g pnpm`
|
||||
使用pnpm安装依赖
|
||||
`pnpm install`
|
||||
|
||||
## 编译
|
||||
### 开源版本
|
||||
`pnpm run build`
|
||||
### 企业版本
|
||||
`pnpm run build:pro`
|
||||
@@ -9,11 +9,9 @@
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"build": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=core --stream --verbose ",
|
||||
"build:pro": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=business-entry --stream --verbose ",
|
||||
"serve": "lerna run preview --parallel",
|
||||
"serve:remotes": "lerna run serve --scope=remote --parallel",
|
||||
"dev": "lerna run dev --scope=core --stream",
|
||||
"dev:pro": "lerna run dev --scope=business-entry --stream",
|
||||
"stop": "kill-port --port 5000",
|
||||
"scan": "i18next-scanner --config i18next-scanner.config.js"
|
||||
},
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
// .env.pro
|
||||
VITE_APP_MODE=pro
|
||||
VITE_APP_TITLE=My Production App
|
||||
VITE_API_BASE_URL=https://api.production.example.com
|
||||
@@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs','public','code-snippet','ace-editor'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
public/tinymce
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# `businessEntry`
|
||||
|
||||
> TODO: description
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
const businessEntry = require('businessEntry');
|
||||
|
||||
// TODO: DEMONSTRATE API
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const businessEntry = require('..');
|
||||
const assert = require('assert').strict;
|
||||
|
||||
assert.strictEqual(businessEntry(), 'Hello from businessEntry');
|
||||
console.info('businessEntry tests passed');
|
||||
@@ -1,15 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/frontend/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>2APIPark</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script src="/frontend/iconpark_eolink.js"></script>
|
||||
<script src="/frontend/iconpark_apinto.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "business-entry",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": " vite --port 5000 --strictPort",
|
||||
"build": "vite build ",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview --port 5000 --strictPort",
|
||||
"serve": "vite preview --port 5000 --strictPort"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
},
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,158 +0,0 @@
|
||||
import '@core/App.css'
|
||||
import { ConfigProvider } from 'antd';
|
||||
import RenderRoutes from '@businessEntry/components/aoplatform/RenderRoutes';
|
||||
import {BreadcrumbProvider} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import useInitializeMonaco from "@common/hooks/useInitializeMonaco";
|
||||
import ThemeSwitcher from '@common/components/aoplatform/ThemeSwitcher'
|
||||
|
||||
const antdComponentThemeToken = {
|
||||
token: {
|
||||
// Seed Token,影响范围大
|
||||
colorPrimary: '#3D46F2',
|
||||
colorLink:'#3D46F2',
|
||||
colorBorder:'#ededed',
|
||||
colorText:'#333',
|
||||
borderRadius: 4,
|
||||
// 派生变量,影响范围小
|
||||
colorBgContainer: '#fff',
|
||||
colorPrimaryBg:'#EBEEF2',
|
||||
colorTextQuaternary:'#BBB',
|
||||
colorTextTertiary:'#999'
|
||||
},
|
||||
components:{
|
||||
// 派生变量,影响范围小
|
||||
Input:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Select:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Checkbox:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Cascader:{
|
||||
activeShadow:'none',
|
||||
optionSelectedBg:'#EBEEF2',
|
||||
optionHoverBg:'#EBEEF2'
|
||||
},
|
||||
Layout: {
|
||||
bodyBg: '#17163E',
|
||||
headerBg: 'transparent',
|
||||
headerColor: '#333',
|
||||
headerPadding: '10 20px',
|
||||
lightSiderBg: 'transparent',
|
||||
siderBg: 'transparent',
|
||||
},
|
||||
Breadcrumb:{
|
||||
itemColor:'#666',
|
||||
linkColor:'#666',
|
||||
lastItemColor:'#333',
|
||||
},
|
||||
Table:{
|
||||
headerBorderRadius:0,
|
||||
headerSplitColor:'#ededed',
|
||||
borderColor:'#ededed',
|
||||
cellPaddingBlockMD:'10px',
|
||||
cellPaddingInlineMD:'12px',
|
||||
cellPaddingBlockSM:'8px',
|
||||
cellPaddingInlineSM:'12px',
|
||||
headerFilterHoverBg:'#EBEEF2',
|
||||
headerSortActiveBg:'#F7F8FA',
|
||||
headerSortHoverBg:'#F7F8FA',
|
||||
fixedHeaderSortActiveBg:'#F7F8FA',
|
||||
headerBg:'#F7F8FA',
|
||||
rowHoverBg:'#EBEEF2'
|
||||
|
||||
},
|
||||
Segmented:{
|
||||
itemColor:'#333',
|
||||
itemSelectedColor:'#333',
|
||||
trackBg:'#f7f8fa',
|
||||
trackPadding:0,
|
||||
// itemHoverColor:'#EBEEF2',
|
||||
itemActiveBg:'#EBEEF2',
|
||||
itemHoverBg:'#EBEEF2',
|
||||
itemSelectedBg:'#EBEEF2',
|
||||
},
|
||||
Tree:{
|
||||
// titleHeight:30,
|
||||
// fontSize:12,
|
||||
directoryNodeSelectedBg:'#EBEEF2',
|
||||
directoryNodeSelectedColor:'#333',
|
||||
nodeSelectedBg:'#EBEEF2',
|
||||
nodeHoverBg:'#EBEEF2'
|
||||
},
|
||||
Collapse:{
|
||||
headerBg:'#f7f8fa',
|
||||
headerPadding:"12px",
|
||||
contentPadding:"0 10px 12px 10px"
|
||||
},
|
||||
Button:{
|
||||
// paddingInline:8,
|
||||
dangerShadow:'none',
|
||||
defaultShadow:'none',
|
||||
primaryShadow:'none'
|
||||
},
|
||||
Tabs:{
|
||||
cardBg:'#EBEEF2',
|
||||
cardHeight:42,
|
||||
horizontalItemGutter:8,
|
||||
horizontalItemPaddingSM:'12px 8px 8px 8px',
|
||||
horizontalItemPadding:'12px 8px 8px 8px',
|
||||
},
|
||||
Menu:{
|
||||
// itemBg:'#F7F8FA',
|
||||
// subMenuItemBg:'#F7F8FA',
|
||||
// itemMarginBlock:0,
|
||||
// activeBarBorderWidth:0,
|
||||
// itemSelectedColor:'#333',
|
||||
// itemSelectedBg:'#EBEEF2',
|
||||
// itemHoverBg:'#EBEEF2'
|
||||
// itemHeight:'72px',
|
||||
// darkItemBg:'transparent',
|
||||
// itemBg:'transparent',
|
||||
// itemSelectedBg:'transparent',
|
||||
// darkItemSelectedBg:'transparent',
|
||||
// subMenuItemBg:'transparent',
|
||||
// itemActiveBg:'transparent',
|
||||
// darkSubMenuItemBg:'transparent',
|
||||
// activeBarHeight:'2px',
|
||||
// activeBarBorderWidth:2
|
||||
},
|
||||
List:{
|
||||
itemPadding:'8px 0'
|
||||
},
|
||||
Form:{
|
||||
itemMarginBottom:10,
|
||||
|
||||
},
|
||||
Alert:{
|
||||
defaultPadding:'12px 16px'
|
||||
},
|
||||
Tag:{
|
||||
defaultBg:"#f7f8fa"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
useInitializeMonaco()
|
||||
|
||||
return (
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={zhCN}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}>
|
||||
<ThemeSwitcher />
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -1,568 +0,0 @@
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import BasicLayout from '@common/components/aoplatform/BasicLayout';
|
||||
import {createElement, ReactElement,ReactNode,Suspense, useEffect, useState} from 'react';
|
||||
import {App, Skeleton} from "antd";
|
||||
import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx";
|
||||
import {FC} from 'react';import React from 'react';
|
||||
import usePluginLoader from '@common/hooks/pluginLoader.ts';
|
||||
|
||||
export type RouteConfig = {
|
||||
path:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
}
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
}
|
||||
|
||||
// const PUBLIC_ROUTES:RouteConfig[] = [
|
||||
// {
|
||||
// path:'/',
|
||||
// component:<Login/>,
|
||||
// key: 'root',
|
||||
// },
|
||||
// {
|
||||
// path:'/login',
|
||||
// component:<Login/>,
|
||||
// key: 'login'
|
||||
// },
|
||||
// {
|
||||
// path:'/',
|
||||
// component:<ProtectedRoute/>,
|
||||
// key: 'layout',
|
||||
// children:[
|
||||
// {
|
||||
// path:'guide/*',
|
||||
// component:<Guide />,
|
||||
// key:'guide'
|
||||
// },
|
||||
// {
|
||||
// path:'team',
|
||||
// component:<Outlet/>,
|
||||
// key: 'team',
|
||||
// provider: TeamProvider,
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'teamList',
|
||||
// component: <Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key: 'teamList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamList.tsx'))
|
||||
// },
|
||||
// {
|
||||
// path:'inside/:teamId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsidePage.tsx')),
|
||||
// key: 'teamInside',
|
||||
// children:[
|
||||
// {
|
||||
// path:'member',
|
||||
// key: 'teamMember',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsideMember.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key: 'teamSetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamConfig.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'service',
|
||||
// component:<SystemOutlet />,
|
||||
// key: 'restService',
|
||||
// provider: SystemProvider,
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key:'restServiceList',
|
||||
// component:<Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key: 'restServiceList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'list/:teamId',
|
||||
// key: 'restServiceList3',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:':teamId',
|
||||
// component:<Outlet/>,
|
||||
// key: 'restServiceInside',
|
||||
// children:[
|
||||
// {
|
||||
// path:'inside/:serviceId',
|
||||
// key: 'restServiceInside2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsidePage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'api',
|
||||
// key: 'restServiceInsideApi',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideApiDocument.tsx')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/create',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/:routeId',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
// path:'route',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
// },
|
||||
// {
|
||||
// path:'upstream',
|
||||
// key: 'restServiceInsideUpstream',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/upstream/SystemInsideUpstreamContent.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'document',
|
||||
// key: 'restServiceInsideDocument',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideDocument.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'subscriber',
|
||||
// key: 'restServiceInsideSubscriber',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideSubscriber.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'approval',
|
||||
// key: 'restServiceInsideApproval',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApproval.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'restServiceInsideApprovalList',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: 'restServiceInsideApprovalList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'topology',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemTopology.tsx')),
|
||||
// key: 'systemTopology',
|
||||
// children:[
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'publish',
|
||||
// key: 'systemPublish',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublish.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'systemPublishList',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: 'systemPublishList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key: 'systemConfig',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
// children:[
|
||||
// ]
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'aiInside/:serviceId',
|
||||
// component:<AiServiceOutlet />,
|
||||
// provider: AiServiceProvider,
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsidePage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'api',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideApiDocument')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/create',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/:routeId',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
// path:'route',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterList')),
|
||||
// },
|
||||
// {
|
||||
// path:'document',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideDocument.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'subscriber',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideSubscriber.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'approval',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApproval')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'publish',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublish')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'datasourcing',
|
||||
// key: 'dataSourcing',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideDashboardSetting.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'cluster',
|
||||
// key: 'cluster',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCluster.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'aisetting',
|
||||
// key: 'aiSetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiSetting/AiSettingList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'cert',
|
||||
// key: 'cert',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCert.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'serviceHub',
|
||||
// component:<Outlet />,
|
||||
// key:'serviceHub',
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'serviceHubList',
|
||||
// component: <Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'serviceHubList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'detail/:serviceId',
|
||||
// key:'serviceHubDetail',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubDetail.tsx')),
|
||||
// }]
|
||||
// },
|
||||
// {
|
||||
// path:'commonsetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/common/CommonPage.tsx')),
|
||||
// key:uuidv4(),
|
||||
// },
|
||||
// {
|
||||
// path:'consumer',
|
||||
// component:<Outlet />,
|
||||
// provider:TenantManagementProvider,
|
||||
// key:'tenantManagement',
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key:'tenantManagementList',
|
||||
// component:<Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:':teamId/inside/:appId',
|
||||
// key:'tenantManagementInside',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsidePage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'service',
|
||||
// key:'tenantManagementInsideService',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideService.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'authorization',
|
||||
// key:'tenantManagementInsideAuthorization',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideAuth.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key:'tenantManagementSetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementAppSetting.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'serviceHubManagementList',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'list/:teamId',
|
||||
// key:'serviceHubManagementList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'member',
|
||||
// key:'member',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberPage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key:'memberList',
|
||||
// component:<Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'memberList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'list/:memberGroupId',
|
||||
// key:'memberList3',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'role',
|
||||
// key:'role',
|
||||
// component:<Outlet />,
|
||||
// children:[
|
||||
// {
|
||||
// path: '',
|
||||
// key: 'roleList',
|
||||
// component: <Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'roleList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleList.tsx')),
|
||||
// },{
|
||||
// path:':roleType/config/:roleId',
|
||||
// key:'roleConfig',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
// },{
|
||||
// path:':roleType/config',
|
||||
// key:'roleConfig2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'analytics',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/Dashboard.tsx')),
|
||||
// key:'analytics',
|
||||
// children:[
|
||||
// {
|
||||
// path:'total',
|
||||
// key:'analytics2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardTotal.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'template/:moduleId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
// key:'intelligentPlugin'
|
||||
// },
|
||||
// {
|
||||
// path:'logsettings/*',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/logsettings/LogSettings.tsx')),
|
||||
// key: 'logSettings',
|
||||
// children:[{
|
||||
// path:'template/:moduleId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
// key:'logSettings2'
|
||||
// }]
|
||||
|
||||
// },
|
||||
// APP_MODE ==='pro' && {
|
||||
// path:'resourcesettings/*',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/resourcesettings/ResourceSettings.tsx')),
|
||||
// key: 'resourceSettings',
|
||||
// children:[{
|
||||
// path:'template/:moduleId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
// key:'resourceSettings2'
|
||||
// }]
|
||||
|
||||
// },
|
||||
// {
|
||||
// path:'userProfile/*',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')),
|
||||
// key:'userProfile',
|
||||
// children:[{
|
||||
// path:'changepsw',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')),
|
||||
// key:'changePsw'
|
||||
// }]
|
||||
// },
|
||||
// APP_MODE === 'pro' &&{
|
||||
// path:'openapi',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@openApi/pages/OpenApiList.tsx')),
|
||||
// key:'openApi',
|
||||
// },
|
||||
// {
|
||||
// path:'systemrunning',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@systemRunning/pages/SystemRunning.tsx')),
|
||||
// key:'systemRunning'
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
|
||||
const RenderRoutes = ()=> {
|
||||
const { loadPlugins } = usePluginLoader()
|
||||
const [routeConfig , setRouteConfig] = useState<RouteConfig[]>([])
|
||||
useEffect(()=>{
|
||||
loadPlugins().then((res)=>{
|
||||
console.log('newRouteConfig',res)
|
||||
setRouteConfig(res as RouteConfig[])
|
||||
})
|
||||
},[])
|
||||
|
||||
return (
|
||||
<App className="h-full" message={{ maxCount: 1 }}>
|
||||
<Router>
|
||||
<Routes>
|
||||
{generateRoutes(routeConfig)}
|
||||
</Routes>
|
||||
</Router>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
const generateRoutes = (routerConfig: RouteConfig[]) => {
|
||||
return routerConfig?.map((route: RouteConfig) => {
|
||||
let routeElement;
|
||||
if (route.lazy) {
|
||||
const LazyComponent = route.lazy as React.ExoticComponent<unknown>;
|
||||
|
||||
routeElement = (
|
||||
<Suspense fallback={ <div className=''><Skeleton className='m-btnbase w-calc-100vw-minus-padding-r' active /></div>}>
|
||||
{route.provider ? (
|
||||
createElement(route.provider, {}, <LazyComponent />)
|
||||
) : (
|
||||
<LazyComponent />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
} else {
|
||||
routeElement = route.provider ? (
|
||||
createElement(route.provider, {}, route.component)
|
||||
) : (
|
||||
route.component
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Route
|
||||
key={route.key}
|
||||
path={route.path}
|
||||
element={routeElement}
|
||||
>
|
||||
{route.children && generateRoutes(route.children as RouteConfig[])}
|
||||
</Route>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 保护的路由组件
|
||||
export function ProtectedRoute() {
|
||||
const {state} = useGlobalContext()
|
||||
return state.isAuthenticated? <BasicLayout project="core" /> : <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
export default RenderRoutes
|
||||
@@ -1,31 +0,0 @@
|
||||
import { ReactElement,ReactNode,FC } from 'react';
|
||||
|
||||
export type RouteConfig = {
|
||||
path:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
}
|
||||
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
routeId:string
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import {StrictMode} from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import '@core/index.css'
|
||||
import {GlobalProvider} from "@common/contexts/GlobalStateContext.tsx";
|
||||
|
||||
async function initializeApp() {
|
||||
try {
|
||||
// 初始化行为
|
||||
// await fetchInitialConfig(); // 示例:获取初始配置
|
||||
|
||||
// 异步操作完成后,渲染React应用
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<GlobalProvider>
|
||||
<App />
|
||||
</GlobalProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Initialization failed:', error);
|
||||
// 处理初始化失败的情况,比如渲染一个错误界面
|
||||
}
|
||||
}
|
||||
|
||||
// 执行初始化
|
||||
initializeApp();
|
||||
@@ -1,209 +0,0 @@
|
||||
import { RouteConfig } from '@businessEntry/components/aoplatform/RenderRoutes';
|
||||
import { routerMap } from '@businessEntry/consts/const';
|
||||
import { isFunction } from 'lodash-es'
|
||||
// @ts-expect-error module cannot find
|
||||
import { __federation_method_setRemote,__federation_method_getRemote,__federation_method_unwrapDefault } from 'virtual:__federation__';
|
||||
|
||||
interface RemoteModuleConfig{
|
||||
type:string
|
||||
remoteEntry:string
|
||||
exposedModule:string
|
||||
remoteName:string
|
||||
}
|
||||
|
||||
export async function loadRemoteModule(remoteModuleConfig:RemoteModuleConfig){
|
||||
__federation_method_setRemote(remoteModuleConfig.remoteName, {
|
||||
url: () => Promise.resolve(remoteModuleConfig.remoteEntry),
|
||||
format: 'esm',
|
||||
from: 'vite',
|
||||
});
|
||||
|
||||
return await __federation_method_getRemote(
|
||||
remoteModuleConfig.remoteName,
|
||||
`./${remoteModuleConfig.exposedModule}`
|
||||
)
|
||||
}
|
||||
|
||||
export function generateRemoteModuleTemplate(
|
||||
pluginName: string,
|
||||
exposedModule: string,
|
||||
pluginPath: string
|
||||
):RemoteModuleConfig {
|
||||
return {
|
||||
type: 'module',
|
||||
remoteEntry: pluginPath,
|
||||
exposedModule: `./${exposedModule}`,
|
||||
remoteName: pluginName
|
||||
}
|
||||
}
|
||||
|
||||
/** 校验子应用导出的 生命周期 对象是否正确 */
|
||||
export function validateExportLifecycle(exports: unknown) {
|
||||
const { bootstrap, mount, unmount } = exports ?? {}
|
||||
return isFunction(bootstrap) && isFunction(mount) && isFunction(unmount)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const DEFAULT_LOCAL_PLUGIN_PATH = '/plugin-frontend/'
|
||||
interface PluginRouterConfig {
|
||||
path:string;
|
||||
type:string;
|
||||
expose?:string
|
||||
}
|
||||
interface PluginConfig {
|
||||
name: string;
|
||||
router: Array<PluginRouterConfig>;
|
||||
path?: string;
|
||||
driver:string
|
||||
}
|
||||
|
||||
export interface CoreObj {
|
||||
routerConfig: RouteConfig[];
|
||||
setExecuteList: (param:unknown[])=>void;
|
||||
pluginLoader: PluginLoaderService;
|
||||
pluginLifecycleGuard: PluginLifecycleGuard;
|
||||
pluginProvider: PluginProviderService;
|
||||
builtInPluginLoader: (name: string) => any;
|
||||
}
|
||||
|
||||
const defaultBuiltInPlugin:Array<{path:string, pathMatch?:'full' | 'prefix', componentName?:string, type?:string}> = [
|
||||
{ path: '/', pathMatch: 'full', componentName: 'login' },
|
||||
{ path: '/login', componentName: 'login' },
|
||||
{ path: '/', componentName: 'basicLayout' },
|
||||
// { path: '**', componentName: 'redirectPage' }
|
||||
|
||||
]
|
||||
|
||||
|
||||
export const ApiparkPluginDriver:{[key:string]:{[key:string]:(coreObj?:CoreObj, pluginConfig?:PluginConfig)=>(CoreObj|undefined)}} = {
|
||||
builtIn: {
|
||||
// apinto主项目驱动,在core中自动调,不根据插件配置表
|
||||
default: (coreObj?:CoreObj) => {
|
||||
if(!coreObj) return coreObj
|
||||
const url = new URL(window.location.href)
|
||||
const navHidden = url.searchParams.get('nav_hidden') || sessionStorage.getItem('nav_hidden')
|
||||
if (navHidden === 'true') sessionStorage.setItem('nav_hidden', navHidden)
|
||||
const routes = defaultBuiltInPlugin.filter(plugin =>navHidden === 'true' && plugin.componentName === 'basicLayout' ? routerMap.get('navHidden')!.component : routerMap.get(plugin.componentName || plugin.path) ).map(plugin => (
|
||||
{
|
||||
path: plugin.path,
|
||||
component: navHidden === 'true' && plugin.componentName === 'basicLayout' ? routerMap.get('navHidden')!.component : routerMap.get(plugin.componentName || plugin.path)?.component,
|
||||
children: [],
|
||||
key:plugin.componentName,
|
||||
data: {
|
||||
type: plugin.type || plugin.componentName || plugin.path
|
||||
},
|
||||
pathMatch: plugin.pathMatch || 'prefix'
|
||||
})
|
||||
)
|
||||
console.log(routes)
|
||||
coreObj.routerConfig.push(...routes)
|
||||
return coreObj
|
||||
},
|
||||
component: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
const routerToChanged:RouteConfig[] = pluginRouter.type === 'root' ? coreObj.routerConfig : coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
routerMap.get(pluginConfig.name) && routerToChanged.unshift({...routerMap.get(pluginConfig.name)!, key:pluginConfig.name, path:pluginRouter.path})
|
||||
}
|
||||
return coreObj
|
||||
},
|
||||
module: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
const routerToChanged:RouteConfig[] = pluginRouter.type === 'root' ? coreObj.routerConfig : coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
routerMap.get(pluginRouter.name) && routerToChanged.unshift({...routerMap.get(pluginRouter.name)!, key:pluginRouter.name, path:pluginRouter.path})
|
||||
}
|
||||
return coreObj
|
||||
},
|
||||
httpApi: () => {
|
||||
return undefined
|
||||
}
|
||||
},
|
||||
remote: {
|
||||
normal: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
const routerToChanged:RouteConfig[] = coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
const remoteRouter:RouteConfig[] = routerToChanged.find((item:RouteConfig) => item?.data?.['type'] === 'remotePlugin') as RouteConfig[]
|
||||
if (!remoteRouter) {
|
||||
routerMap.get('remote') && routerToChanged.unshift({
|
||||
...routerMap.get('remote')!, key:'remote', path:'remote',type:'remotePlugin',children:[{
|
||||
path:':moduleName',
|
||||
component: routerMap.get('remote')!.component}
|
||||
]
|
||||
})
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
intelligent: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
normal: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
if(['logsettings','resourcesettings'].indexOf(pluginConfig.name) !== -1){
|
||||
const routerToChanged:RouteConfig[] = coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
const remoteRouter:RouteConfig[] = routerToChanged.find((item:RouteConfig) => item?.data?.['key'] === pluginConfig.name) as RouteConfig[]
|
||||
if(!remoteRouter){
|
||||
routerMap.get(pluginConfig.name) && routerToChanged.unshift({...routerMap.get(pluginConfig.name)!, key:pluginConfig.name, path:pluginConfig.path})
|
||||
}
|
||||
return
|
||||
}
|
||||
const remoteRouter = coreObj.routerConfig.find((item:RouteConfig) => item?.data?.['type'] === 'intelligentPlugin')
|
||||
if (!remoteRouter) {
|
||||
// coreObj.pluginProvider.setRouterConfig(false, {
|
||||
// path: 'template',
|
||||
// loadChildren: coreObj.builtInPluginLoader('intelligent'),
|
||||
// data: {
|
||||
// type: 'intelligentPlugin'
|
||||
// }
|
||||
// }, coreObj.routerConfig)
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
local: {
|
||||
router: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
if (pluginRouter.type === 'sub') {
|
||||
continue
|
||||
}
|
||||
updateRouterConfigWithPlugin(coreObj, pluginRouter, pluginConfig)
|
||||
}
|
||||
return coreObj
|
||||
},
|
||||
preload: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
coreObj.setExecuteList(prev=>[...prev,{ ...pluginConfig, expose: 'Bootstrap', bootstrap: 'BootstrapModule.bootstrap' }])
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
updateRouterConfigWithPlugin(coreObj, pluginRouter, pluginConfig)
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
// extender: (coreObj?:CoreObj, pluginConfig?:PluginConfig) => {}
|
||||
}
|
||||
}
|
||||
function updateRouterConfigWithPlugin (coreObj: CoreObj, pluginRouter: PluginRouterConfig, pluginConfig: PluginConfig) {
|
||||
if (!pluginRouter.expose) {
|
||||
throw new Error('pluginRouter.expose is required')
|
||||
} else {
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
const routerToChanged:RouteConfig[] = pluginRouter.type === 'root' ? coreObj.routerConfig : coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
routerMap.get(pluginConfig.name) && routerToChanged.unshift({...routerMap.get(pluginConfig.name)!, key:pluginConfig.name, path:pluginRouter.path})
|
||||
}
|
||||
|
||||
// coreObj.pluginProvider.setRouterConfig(pluginRouter.type === 'root', {
|
||||
// path: pluginRouter.path,
|
||||
// loadChildren: () => coreObj.pluginLoader.loadModule(
|
||||
// pluginRouter.path,
|
||||
// pluginConfig.name,
|
||||
// pluginRouter.expose!,
|
||||
// pluginConfig.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${pluginConfig.name}/ApiparkPluginDriver.js`
|
||||
// ),
|
||||
// canActivate: [coreObj.pluginLifecycleGuard],
|
||||
// canActivateChild: [coreObj.pluginLifecycleGuard],
|
||||
// canDeactivate: [coreObj.pluginLifecycleGuard],
|
||||
// canLoad: [coreObj.pluginLifecycleGuard]
|
||||
// }, coreObj.routerConfig)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
// start-vite.js// start-vite.js
|
||||
import { exec } from 'child_process';
|
||||
|
||||
const viteProcess = exec('pnpm run build');
|
||||
|
||||
viteProcess.stdout.on('data', (data) => {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
viteProcess.stderr.on('data', (data) => {
|
||||
console.error(data.toString());
|
||||
});
|
||||
|
||||
viteProcess.on('close', (code) => {
|
||||
console.log(`Vite process exited with code ${code}`);
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@core/*": ["../core/src/*"],
|
||||
"@common/*": ["../common/src/*"],
|
||||
"@market/*": ["../market/src/*"],
|
||||
"@dashboard/*": ["../dashboard/src/*"],
|
||||
"@openApi/*": ["../openApi/src/*"],
|
||||
"@systemRunning/*": ["../systemRunning/src/*"],
|
||||
"@businessEntry/*": ["./src/*"],
|
||||
},
|
||||
},
|
||||
"include": ["src", "public/iconpark_eolink.js", "public/iconpark_apinto.js", "../common/src/component/aoplatform/EditableTableWithModal.tsx", "../common/src/components/aoplatform/TreeWithMore.tsx", "../common/src/components/aoplatform/DatePicker.tsx", "../common/src/components/aoplatform/TimeRangeSelector.tsx", "../common/src/components/aoplatform/TimePicker.tsx", "../common/src/components/aoplatform/MemberTransfer.tsx", "../common/src/components/aoplatform/Navigation.tsx", "../common/src/components/aoplatform/PageList.tsx", "../common/src/components/aoplatform/ErrorBoundary.tsx", "../common/src/components/aoplatform/ScrollableSection.tsx", "../common/src/utils/postcat.tsx", "../common/src/utils/curl.ts", "../common/src/components/aoplatform/ResetPsw.tsx", "../common/src/components/aoplatform/SubscribeApprovalModalContent.tsx", "src/components/aoplatform/RenderRoutes.tsx", "../common/src/components/aoplatform/PublishApprovalModalContent.tsx", "../common/src/components/aoplatform/InsidePage.tsx", "../common/src/const/type.ts", "../common/src/components/aoplatform/intelligent-plugin", "../common/src/const/domain", "../common/src/hooks/pluginLoader.ts"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import { defineConfig, Plugin } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import path from 'path'
|
||||
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
import federation from "@originjs/vite-plugin-federation";
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: './node_modules/.vite',
|
||||
build:{
|
||||
outDir:'../../dist',
|
||||
sourcemap: false,
|
||||
chunkSizeWarningLimit: 50000,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
chunkFileNames: 'assets/eo-[name]-[hash].js',
|
||||
},
|
||||
},
|
||||
},
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
tailwindcss(path.resolve(__dirname, '../common/tailwind.config.js')),
|
||||
autoprefixer,
|
||||
],
|
||||
},
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
modules:{
|
||||
localsConvention:"camelCase",
|
||||
generateScopedName:"[local]_[hash:base64:2]"
|
||||
}
|
||||
},
|
||||
plugins: [react(),
|
||||
dynamicImportVars({
|
||||
include:["src"],
|
||||
exclude:[],
|
||||
warnOnError:false
|
||||
}),
|
||||
federation({
|
||||
name:"container",
|
||||
remotes:{
|
||||
remoteApp: 'http://localhost:5001/assets/remoteEntry.js' // 远程项目的URL
|
||||
},
|
||||
shared:[
|
||||
"react",
|
||||
"react-dom",
|
||||
]
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
{ find: /^~/, replacement: '' },
|
||||
{ find: '@common', replacement: path.resolve(__dirname, '../common/src') },
|
||||
{ find: '@market', replacement: path.resolve(__dirname, '../market/src') },
|
||||
{ find: '@core', replacement: path.resolve(__dirname, '../core/src') },
|
||||
{ find: '@dashboard', replacement: path.resolve(__dirname, '../dashboard/src') },
|
||||
{ find: '@openApi', replacement: path.resolve(__dirname, '../openApi/src') },
|
||||
{ find: '@systemRunning', replacement: path.resolve(__dirname, '../systemRunning/src') },
|
||||
{ find: '@businessEntry', replacement: path.resolve(__dirname, './src') },
|
||||
]
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api/v1': {
|
||||
// target: 'http://uat.apikit.com:11204/mockApi/aoplatform/',
|
||||
target: 'http://172.18.166.219:8288/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/api2/v1': {
|
||||
// target: 'http://uat.apikit.com:11204/mockApi/aoplatform/',
|
||||
target: 'http://172.18.166.219:8288/',
|
||||
changeOrigin: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
logLevel:'info'
|
||||
})
|
||||
@@ -19,6 +19,7 @@ import { Icon } from '@iconify/react';
|
||||
import { $t } from '@common/locales';
|
||||
import { ProConfigProvider, ProLayout } from '@ant-design/pro-components';
|
||||
import LanguageSetting from './LanguageSetting';
|
||||
import { usePluginSlotHub } from '@common/contexts/PluginSlotHubContext';
|
||||
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
export type MenuItem = Required<MenuProps>['items'][number];
|
||||
@@ -43,6 +44,7 @@ const themeToken = {
|
||||
const [pathname, setPathname] = useState(currentUrl);
|
||||
const mainPage = project === 'core' ?'/service/list':'/serviceHub/list'
|
||||
const [menuItems, setMenuItems] = useState<MenuProps['items']>();
|
||||
const pluginSlotHub = usePluginSlotHub()
|
||||
|
||||
useEffect(()=>{
|
||||
const newMenu = transformMenuData(menuList)
|
||||
@@ -145,6 +147,16 @@ const themeToken = {
|
||||
].filter(Boolean), [userInfo]);
|
||||
|
||||
|
||||
const actionRender =useMemo( ()=>{
|
||||
return [
|
||||
<LanguageSetting />,
|
||||
<Button className=" text-[#ffffffb3] hover:text-[#fff] border-none" type="default" ghost onClick={()=>{window.open('https://docs.apipark.com','_blank')}}>
|
||||
<span className='flex items-center gap-[8px]'> <Icon icon="ic:baseline-help" width="14" height="14"/>{$t('文档')}</span>
|
||||
</Button> ,
|
||||
...((pluginSlotHub.getSlot('basicLayoutAfterBtns') as unknown[] )||[] )
|
||||
]
|
||||
},[pluginSlotHub.getSlot('basicLayoutAfterBtns') ])
|
||||
|
||||
|
||||
return(
|
||||
<div
|
||||
@@ -195,12 +207,7 @@ const themeToken = {
|
||||
actionsRender={(props) => {
|
||||
if (props.isMobile) return [];
|
||||
if (typeof window === 'undefined') return [];
|
||||
return [
|
||||
<LanguageSetting />,
|
||||
<Button className=" text-[#ffffffb3] hover:text-[#fff] border-none" type="default" ghost onClick={()=>{window.open('https://docs.apipark.com','_blank')}}>
|
||||
<span className='flex items-center gap-[8px]'> <Icon icon="ic:baseline-help" width="14" height="14"/>{$t('文档')}</span>
|
||||
</Button>
|
||||
];
|
||||
return actionRender;
|
||||
}}
|
||||
headerTitleRender={() => (
|
||||
<div className="w-[192px] flex items-center">
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Result, Skeleton } from 'antd';
|
||||
|
||||
const NotFound: React.FC = () => {
|
||||
const [showPage, setShowPage] = useState<boolean>(false)
|
||||
|
||||
useEffect(()=>{
|
||||
setTimeout(()=>setShowPage(true), 1000)
|
||||
},[])
|
||||
|
||||
return (
|
||||
<div className={`h-full w-full flex flex-1 align-middle ${showPage ? 'items-center' : ''}`}>
|
||||
{ showPage ? <Result
|
||||
className='w-full'
|
||||
status="404"
|
||||
title="404"
|
||||
subTitle="Sorry, the page you visited does not exist."
|
||||
/> : <Skeleton active /> }
|
||||
</div>
|
||||
)}
|
||||
|
||||
export default NotFound;
|
||||
@@ -0,0 +1,80 @@
|
||||
import { set } from 'lodash-es';
|
||||
import { ExoticComponent, JSXElementConstructor, ReactElement, useEffect, useState } from 'react';
|
||||
import { useBlocker, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { JSX } from 'react/jsx-runtime';
|
||||
|
||||
const withRouteGuard = (WrappedComponent: ExoticComponent<any> | JSXElementConstructor<any>, {
|
||||
canActivate,
|
||||
canLoad ,
|
||||
canDeactivate,
|
||||
deactivated,
|
||||
pathPrefix
|
||||
}: { pathPrefix?:string, canActivate?: () => Promise<boolean>; canLoad?: () => Promise<boolean>; canDeactivate?: () => Promise<boolean>; deactivated?: () => Promise<void>; } = {}) => {
|
||||
return function RouteGuard(props: JSX.IntrinsicAttributes) {
|
||||
const [isActivated, setIsActivated] = useState<boolean>(false);
|
||||
const location = useLocation();
|
||||
|
||||
// check canActivate
|
||||
const startLifecycle = async ()=>{
|
||||
if(canActivate){
|
||||
const activateRes = await canActivate();
|
||||
setIsActivated(activateRes);
|
||||
}else{
|
||||
setIsActivated(true);
|
||||
}
|
||||
}
|
||||
|
||||
// check canDeactivate
|
||||
const handleBeforeUnload =async (event: { preventDefault: () => void; returnValue: string; }) => {
|
||||
const deactivateRes = canDeactivate? await canDeactivate():true;
|
||||
if (!deactivateRes) {
|
||||
event.preventDefault();
|
||||
event.returnValue = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 激活组件时的检查
|
||||
useEffect(() => {
|
||||
startLifecycle();
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
deactivated?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
const blocker = useBlocker((tx) => {
|
||||
const currentPath = location.pathname;
|
||||
const targetPath = tx.nextLocation.pathname;
|
||||
|
||||
if (pathPrefix && currentPath.startsWith(pathPrefix) && !targetPath.startsWith(pathPrefix) && canDeactivate) {
|
||||
canDeactivate().then((res) => {
|
||||
if(res){
|
||||
return false;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const checkCanLoad = async()=>{
|
||||
const loadRes = await canLoad!();
|
||||
!loadRes && setIsActivated(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (isActivated && canLoad) {
|
||||
checkCanLoad()
|
||||
}
|
||||
}, [isActivated]);
|
||||
|
||||
return isActivated ? <WrappedComponent {...props}/> : null;
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouteGuard;
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
UPDATE_DATASETS_EVENT_EMITTER,
|
||||
UPDATE_HISTORY_EVENT_EMITTER,
|
||||
} from './constants'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
export type PromptEditorProps = {
|
||||
instanceId?: string
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import { $splitNodeContainingQuery } from '../../utils'
|
||||
import { useOptions } from './hooks'
|
||||
import type { PickerBlockMenuOption } from './menu'
|
||||
// import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
type ComponentPickerProps = {
|
||||
triggerString: string
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { DELETE_CONTEXT_BLOCK_COMMAND } from './index'
|
||||
// PortalToFollowElemContent,
|
||||
// PortalToFollowElemTrigger,
|
||||
// } from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
import { $t } from '@common/locales'
|
||||
|
||||
type ContextBlockComponentProps = {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { DELETE_HISTORY_BLOCK_COMMAND } from './index'
|
||||
// PortalToFollowElemContent,
|
||||
// PortalToFollowElemTrigger,
|
||||
// } from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
import { $t } from '@common/locales'
|
||||
|
||||
type HistoryBlockComponentProps = {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
||||
import { textToEditorState } from '../utils'
|
||||
import { CustomTextNode } from './custom-text/node'
|
||||
import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'
|
||||
export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import { ProtectedRoute } from '@core/components/aoplatform/RenderRoutes'
|
||||
import { AiServiceProvider } from '@core/contexts/AiServiceContext'
|
||||
import { SystemProvider } from '@core/contexts/SystemContext'
|
||||
import { TeamProvider } from '@core/contexts/TeamContext'
|
||||
import { TenantManagementProvider } from '@market/contexts/TenantManagementContext'
|
||||
import { lazy } from 'react'
|
||||
import { Outlet, Navigate } from 'react-router-dom'
|
||||
|
||||
export type BasicResponse<T> = {
|
||||
code:number
|
||||
data:T
|
||||
@@ -72,4 +80,4 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
export const DATA_SHOW_TYPE_OPTIONS = [
|
||||
{label:'列表', value:'list'},
|
||||
{label:'块', value:'block'},
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { FC, ReactElement, ReactNode } from "react"
|
||||
import { PERMISSION_DEFINITION } from "./permissions"
|
||||
import { MatchPositionEnum, MatchTypeEnum } from "@core/const/system/const"
|
||||
import usePluginLoader from "@common/hooks/pluginLoader"
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext"
|
||||
|
||||
export type UserInfoType = {
|
||||
username: string
|
||||
@@ -8,7 +11,6 @@ export type UserInfoType = {
|
||||
phone: string
|
||||
avatar: string
|
||||
type:string
|
||||
|
||||
}
|
||||
|
||||
export type UserProfileProps = {
|
||||
@@ -100,4 +102,87 @@ export type SimpleMemberItem = {
|
||||
email:string
|
||||
department:string
|
||||
avatar:string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export type RouteConfig = {
|
||||
path:string
|
||||
pathPrefix?:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
data?:Record<string, string>
|
||||
lifecycle?:{
|
||||
canActivate?:()=>Promise<boolean>
|
||||
canLoad?:()=>Promise<boolean>
|
||||
canDeactivate?:()=>Promise<boolean>
|
||||
deactivated?:()=>Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
routeId:string
|
||||
}
|
||||
|
||||
|
||||
export type PluginRouterConfig = {
|
||||
name:string
|
||||
path:string;
|
||||
type:string;
|
||||
expose?:string
|
||||
}
|
||||
|
||||
export type CoreObj = {
|
||||
routerConfig: RouteConfig[];
|
||||
setExecuteList: (param:unknown[])=>void;
|
||||
pluginLoader: {
|
||||
loadModule: (path: string, name: string, expose: string, pluginPath: string) => Promise<any>;
|
||||
};
|
||||
pluginProvider: ReturnType<typeof useGlobalContext>
|
||||
// pluginLifecycleGuard: PluginLifecycleGuard;
|
||||
builtInPluginLoader: (name: string) => any;
|
||||
}
|
||||
|
||||
export type PluginConfigType = {
|
||||
name: string;
|
||||
router: Array<PluginRouterConfig>;
|
||||
path?: string;
|
||||
driver:string
|
||||
}
|
||||
|
||||
|
||||
export type ApiparkPluginDriverType = {
|
||||
[key:string]:{[key:string]:(coreObj?:CoreObj, pluginConfig?:PluginConfigType)=>(CoreObj|undefined)}
|
||||
}
|
||||
|
||||
|
||||
export type RouterMapConfig = {
|
||||
type: 'component' | 'module',
|
||||
component: ReactElement,
|
||||
provider?: FC,
|
||||
lazy?: FC
|
||||
key?: string
|
||||
children?: RouteConfig[]
|
||||
data?:Record<string, string>
|
||||
pathMatch?:string
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createContext, Dispatch, FC, ReactNode, useContext, useReducer, useState} from "react";
|
||||
import {createContext, Dispatch, FC, ReactNode, useContext, useEffect, useReducer, useState} from "react";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { App } from "antd";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const";
|
||||
@@ -6,6 +6,13 @@ import { checkAccess } from "@common/utils/permission";
|
||||
import { PERMISSION_DEFINITION } from "@common/const/permissions";
|
||||
import { $t } from "@common/locales";
|
||||
import { MenuItem } from "@common/utils/navigation";
|
||||
import { usePluginEventHub } from "./PluginEventHubContext";
|
||||
import { ErrorBoundary } from "@ant-design/pro-components";
|
||||
import NotFound from "@common/components/aoplatform/NotFound";
|
||||
import { RouteConfig } from "@common/const/type";
|
||||
import { ProtectedRoute } from "@core/components/aoplatform/RenderRoutes";
|
||||
import Login from "@core/pages/Login";
|
||||
import { useLocaleContext } from "./LocaleContext";
|
||||
|
||||
interface GlobalState {
|
||||
isAuthenticated: boolean;
|
||||
@@ -31,59 +38,6 @@ export type GlobalAction =
|
||||
| { type: 'UPDATE_MAIN_PAGE'; mainPage: string }
|
||||
| { type: 'UPDATE_LANGUAGE'; language: string }
|
||||
|
||||
class EventEmitter {
|
||||
// 用来存放注册的事件与回调
|
||||
_events:any
|
||||
constructor () {
|
||||
this._events = {}
|
||||
}
|
||||
|
||||
on (eventName:string, callback:Function) {
|
||||
// 由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列
|
||||
const callbacks = this._events[eventName] || []
|
||||
callbacks.push(callback)
|
||||
this._events[eventName] = callbacks
|
||||
}
|
||||
|
||||
// 此处需要处理,emit时需要按顺序执行监听的函数,每个函数都会返回是否中止的参数,如果中止则不执行后续的函数
|
||||
// emit传入eventName 和 event, 返回 event
|
||||
emit (eventName:string, event:any) {
|
||||
return new Promise((resolve) => {
|
||||
const callbacks = this._events[eventName] || []
|
||||
for (const cb of callbacks) {
|
||||
const cbRes = cb(event.data)
|
||||
if (cbRes.continue === false) {
|
||||
resolve(cbRes)
|
||||
break
|
||||
} else {
|
||||
event = cbRes
|
||||
}
|
||||
}
|
||||
resolve(event.data)
|
||||
})
|
||||
}
|
||||
|
||||
// 取消订阅
|
||||
off (eventName:string, callback:Function) {
|
||||
const callbacks = this._events[eventName] || []
|
||||
const newCallbacks = callbacks.filter((fn:any) => fn !== callback && fn.initialCallback !== callback /* 用于once的取消订阅 */)
|
||||
this._events[eventName] = newCallbacks
|
||||
}
|
||||
|
||||
// 单次订阅,后台插件可以自行决定取消对事件的订阅
|
||||
once (eventName:string, callback:Function) {
|
||||
// 由于需要在回调函数执行后,取消订阅当前事件,所以需要对传入的回调函数做一层包装,然后绑定包装后的函数
|
||||
const one = (...args:any) => {
|
||||
callback(...args)
|
||||
this.off(eventName, one)
|
||||
}
|
||||
|
||||
// 由于:我们订阅事件的时候,修改了原回调函数的引用,所以,用户触发 off 的时候不能找到对应的回调函数
|
||||
// 所以,我们需要在当前函数与用户传入的回调函数做一个绑定,我们通过自定义属性来实现
|
||||
one.initialCallback = callback
|
||||
this.on(eventName, one)
|
||||
}
|
||||
}
|
||||
|
||||
const mockData = [
|
||||
{
|
||||
@@ -119,7 +73,14 @@ class EventEmitter {
|
||||
"path": "/team",
|
||||
"icon": "ic:baseline-people-alt",
|
||||
"access": "all"
|
||||
}
|
||||
},
|
||||
// {
|
||||
// "name": "路由组件",
|
||||
// "key": "router",
|
||||
// "path": "/router1",
|
||||
// "icon": "ic:baseline-people-alt",
|
||||
// "access": "all"
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -251,16 +212,13 @@ export const GlobalContext = createContext<{
|
||||
checkPermission:(access:keyof typeof PERMISSION_DEFINITION[0] | Array<keyof typeof PERMISSION_DEFINITION[0]>)=>boolean
|
||||
teamDataFlushed:boolean
|
||||
accessInit:boolean
|
||||
// 插件系统
|
||||
pluginEventHub:EventEmitter
|
||||
pluginSlotHubService:{
|
||||
addSlot:(name:string, content:unknown)=>void
|
||||
addSlotArr:(name:string, content:unknown[])=>void
|
||||
removeSlot:(name:string)=>void
|
||||
getSlot:(name:string)=>unknown
|
||||
}
|
||||
aiConfigFlushed:boolean
|
||||
setAiConfigFlushed:(flush:boolean)=>void
|
||||
routeConfig: RouteConfig[];
|
||||
setRouterConfig: (isRoot: boolean, config: RouteConfig) => void;
|
||||
addRouteConfig: (parentRoute: RouteConfig, config: RouteConfig) => void;
|
||||
fetchData: ReturnType<typeof useFetch>['fetchData'];
|
||||
$t: typeof $t;
|
||||
} | undefined>(undefined);
|
||||
|
||||
const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState => {
|
||||
@@ -311,10 +269,18 @@ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState =>
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const DefaultRouteConfig = [
|
||||
{ path: '/', pathMatch: 'full', component: <Login /> ,key:'root',},
|
||||
{ path: '/login', component: <Login /> ,key:'login'},
|
||||
{ path: '/', pathMatch:'prefix',component:<ProtectedRoute /> ,key:'basciLayout',children:[
|
||||
{ path: '*', component: <ErrorBoundary><NotFound/></ErrorBoundary>, key: 'errorBoundary' }
|
||||
]}
|
||||
]
|
||||
// Create a context provider component
|
||||
export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const {fetchData} = useFetch()
|
||||
const { message } = App.useApp()
|
||||
const { setLocale } = useLocaleContext();
|
||||
const [state, dispatch] = useReducer(globalReducer, {
|
||||
isAuthenticated: true, //mock用
|
||||
userData: null,
|
||||
@@ -330,10 +296,43 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const [accessInit, setAccessInit] = useState<boolean>(false)
|
||||
const [aiConfigFlushed, setAiConfigFlushed] = useState<boolean>(false)
|
||||
let getGlobalAccessPromise: Promise<BasicResponse<{ access:string[] }>> | null = null
|
||||
const [pluginEventHub] = useState<EventEmitter>(new EventEmitter())
|
||||
const [pluginSlotHub] = useState<Map<string,unknown>>(new Map())
|
||||
const [menuList, setMenuList] = useState<MenuItem[]>(mockData);
|
||||
const [routeConfig, setRouteConfigState] = useState<RouteConfig[]>(DefaultRouteConfig)
|
||||
|
||||
useEffect(() => {
|
||||
setLocale(state.language);
|
||||
}, [state.language, setLocale]);
|
||||
|
||||
const { fetchData } = useFetch();
|
||||
|
||||
const setRouterConfig = (isRoot: boolean, config: RouteConfig) => {
|
||||
setRouteConfigState(prevConfig => {
|
||||
if (isRoot) {
|
||||
return [config,...prevConfig];
|
||||
} else {
|
||||
const rootRoute = prevConfig.find(route => route.path === '/' && route?.pathMatch === 'prefix') ;
|
||||
if (rootRoute ) {
|
||||
rootRoute.children = rootRoute.children ? [config, ...rootRoute.children] : [config];
|
||||
}
|
||||
return [...prevConfig];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const addRouteConfig = (parentRoute: RouteConfig, config: RouteConfig) => {
|
||||
const addConfigToParent = (routes: RouteConfig[]): RouteConfig[] => {
|
||||
return routes.map(route => {
|
||||
if (route.key === parentRoute.key) {
|
||||
route.children = route.children ? [...route.children, config] : [config];
|
||||
} else if (route.children) {
|
||||
route.children = addConfigToParent(route.children);
|
||||
}
|
||||
return route;
|
||||
});
|
||||
};
|
||||
|
||||
setRouteConfigState(prevConfig => addConfigToParent(prevConfig));
|
||||
};
|
||||
|
||||
const getGlobalAccessData = ()=>{
|
||||
if(getGlobalAccessPromise){
|
||||
@@ -404,23 +403,26 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
return revs
|
||||
}
|
||||
|
||||
const pluginSlotHubService = {
|
||||
addSlot:(name:string, content:any) => {pluginSlotHub.set(name, content)},
|
||||
addSlotArr : (name:string, content:any[]) => {pluginSlotHub.get(name) ? pluginSlotHub.set(name, (pluginSlotHub.get(name) as Array<unknown>).push(content)) : pluginSlotHub.set(name, content)},
|
||||
removeSlot:(name:string) => {pluginSlotHub.delete(name)},
|
||||
getSlot:(name:string) => {pluginSlotHub.get(name)}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={
|
||||
{ state, dispatch,accessData,pluginAccessDictionary,
|
||||
{ state, dispatch,
|
||||
accessData,
|
||||
pluginAccessDictionary,
|
||||
getGlobalAccessData,
|
||||
getPluginAccessDictionary,
|
||||
getTeamAccessData,teamDataFlushed,getMenuList,menuList,
|
||||
cleanTeamAccessData,
|
||||
resetAccess ,checkPermission,accessInit,
|
||||
aiConfigFlushed, setAiConfigFlushed,pluginEventHub,pluginSlotHubService}}>
|
||||
resetAccess ,checkPermission,
|
||||
accessInit,
|
||||
aiConfigFlushed,
|
||||
setAiConfigFlushed,
|
||||
routeConfig,
|
||||
setRouterConfig,
|
||||
addRouteConfig,
|
||||
fetchData,
|
||||
$t:$t,}}>
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useMemo } from 'react';
|
||||
import { ConfigProviderProps } from 'antd';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
import zhTW from 'antd/locale/zh_TW';
|
||||
import jaJP from 'antd/locale/ja_JP';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/zh-tw';
|
||||
import 'dayjs/locale/ja';
|
||||
|
||||
type Locale = ConfigProviderProps['locale'];
|
||||
|
||||
const languageMap: Record<string, Locale> = {
|
||||
'zh-CN': zhCN,
|
||||
'en-US': enUS,
|
||||
'zh-TW': zhTW,
|
||||
'ja-JP': jaJP,
|
||||
};
|
||||
|
||||
const LocaleContext = createContext<{
|
||||
locale: Locale;
|
||||
setLocale: (locale: string) => void;
|
||||
}>({
|
||||
locale: zhCN,
|
||||
setLocale: () => {},
|
||||
});
|
||||
|
||||
export const LocaleProvider: React.FC = ({ children }) => {
|
||||
const [locale, setLocaleState] = useState<Locale>(zhCN);
|
||||
|
||||
const setLocale = (language: string) => {
|
||||
dayjs.locale(language);
|
||||
setLocaleState(languageMap[language]);
|
||||
};
|
||||
|
||||
return (
|
||||
<LocaleContext.Provider value={{ locale, setLocale }}>
|
||||
{children}
|
||||
</LocaleContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useLocaleContext = () => useContext(LocaleContext);
|
||||
@@ -0,0 +1,76 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
|
||||
|
||||
class EventEmitter {
|
||||
// 用来存放注册的事件与回调
|
||||
_events:any
|
||||
constructor () {
|
||||
this._events = {}
|
||||
}
|
||||
|
||||
on (eventName:string, callback:Function) {
|
||||
// 由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列
|
||||
const callbacks = this._events[eventName] || []
|
||||
callbacks.push(callback)
|
||||
this._events[eventName] = callbacks
|
||||
}
|
||||
|
||||
// 此处需要处理,emit时需要按顺序执行监听的函数,每个函数都会返回是否中止的参数,如果中止则不执行后续的函数
|
||||
// emit传入eventName 和 event, 返回 event
|
||||
emit (eventName:string, event:any) {
|
||||
return new Promise((resolve) => {
|
||||
const callbacks = this._events[eventName] || []
|
||||
for (const cb of callbacks) {
|
||||
const cbRes = cb(event.data)
|
||||
if (cbRes.continue === false) {
|
||||
resolve(cbRes)
|
||||
break
|
||||
} else {
|
||||
event = cbRes
|
||||
}
|
||||
}
|
||||
resolve(event.data)
|
||||
})
|
||||
}
|
||||
|
||||
// 取消订阅
|
||||
off (eventName:string, callback:Function) {
|
||||
const callbacks = this._events[eventName] || []
|
||||
const newCallbacks = callbacks.filter((fn:any) => fn !== callback && fn.initialCallback !== callback /* 用于once的取消订阅 */)
|
||||
this._events[eventName] = newCallbacks
|
||||
}
|
||||
|
||||
// 单次订阅,后台插件可以自行决定取消对事件的订阅
|
||||
once (eventName:string, callback:Function) {
|
||||
// 由于需要在回调函数执行后,取消订阅当前事件,所以需要对传入的回调函数做一层包装,然后绑定包装后的函数
|
||||
const one = (...args:any) => {
|
||||
callback(...args)
|
||||
this.off(eventName, one)
|
||||
}
|
||||
|
||||
// 由于:我们订阅事件的时候,修改了原回调函数的引用,所以,用户触发 off 的时候不能找到对应的回调函数
|
||||
// 所以,我们需要在当前函数与用户传入的回调函数做一个绑定,我们通过自定义属性来实现
|
||||
one.initialCallback = callback
|
||||
this.on(eventName, one)
|
||||
}
|
||||
}
|
||||
|
||||
export const PluginEventHubContext = createContext<EventEmitter | undefined>(undefined);
|
||||
|
||||
export const PluginEventHubProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [pluginEventHub] = useState<EventEmitter>(new EventEmitter());
|
||||
|
||||
return (
|
||||
<PluginEventHubContext.Provider value={pluginEventHub}>
|
||||
{children}
|
||||
</PluginEventHubContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePluginEventHub = () => {
|
||||
const context = useContext(PluginEventHubContext);
|
||||
if (!context) {
|
||||
throw new Error('usePluginEventHub must be used within a PluginEventHubProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
|
||||
export const PluginSlotHubContext = createContext<{
|
||||
addSlot: (name: string, content: unknown) => void;
|
||||
addSlotArr: (name: string, content: unknown[]) => void;
|
||||
removeSlot: (name: string) => void;
|
||||
getSlot: (name: string) => unknown;
|
||||
} | undefined>(undefined);
|
||||
|
||||
export const PluginSlotHubProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [pluginSlotHub] = useState<Map<string, unknown>>(new Map());
|
||||
|
||||
const pluginSlotHubService = {
|
||||
addSlot: (name: string, content: any) => {
|
||||
pluginSlotHub.set(name, pluginSlotHub.get(name) ? [...(pluginSlotHub.get(name) as Array<unknown>), content] : [content] ); },
|
||||
addSlotArr: (name: string, content: any[]) => { pluginSlotHub.get(name) ? pluginSlotHub.set(name, (pluginSlotHub.get(name) as Array<unknown>).push(content)) : pluginSlotHub.set(name, content); },
|
||||
removeSlot: (name: string) => { pluginSlotHub.delete(name); },
|
||||
getSlot: (name: string) => {
|
||||
|
||||
return pluginSlotHub.get(name) ; }
|
||||
};
|
||||
|
||||
return (
|
||||
<PluginSlotHubContext.Provider value={pluginSlotHubService}>
|
||||
{children}
|
||||
</PluginSlotHubContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePluginSlotHub = () => {
|
||||
const context = useContext(PluginSlotHubContext);
|
||||
if (!context) {
|
||||
throw new Error('usePluginSlotHub must be used within a PluginSlotHubProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,4 +1,6 @@
|
||||
import { STATUS_CODE } from "@common/const/const";
|
||||
import { BasicResponse, STATUS_CODE } from "@common/const/const";
|
||||
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
||||
import EventEmitter from "events";
|
||||
|
||||
const urlWhiteList = [/api.example.com\/users/, /api.example2.com\/products/]; // 正则白名单
|
||||
|
||||
@@ -137,7 +139,10 @@ type EoRequest = RequestInit & {eoParams?:{[k:string]:unknown},eoTransformKeys?:
|
||||
|
||||
type EoHeaders = Headers | {[k:string]:string}
|
||||
|
||||
export function useFetch(){
|
||||
export function useFetch() {
|
||||
// plugin cannot use usePluginEventHub directly, so we need to pass it as a parameter
|
||||
const pluginEventHub = usePluginEventHub()
|
||||
|
||||
function fetchData<T>(url:string, options: EoRequest ) {
|
||||
// 合并传入的headers与默认headers
|
||||
const headers = { ...(options.body ? {}:DEFAULT_HEADERS), ...options.headers };
|
||||
@@ -184,9 +189,11 @@ export function useFetch(){
|
||||
// 如果响应体为JSON且指定了转换键,则转换响应数据
|
||||
if ( isJsonHttp(response.headers)) {
|
||||
const data = await response.json();
|
||||
return shouldTransformKeys ? keysToCamel(data,options.eoTransformKeys as string[]) as T:data
|
||||
const newData = await pluginEventHub.emit('httpResponse', {data,continue:true}) as Response;
|
||||
return shouldTransformKeys ? keysToCamel(newData,options.eoTransformKeys as string[]) as T:data
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { App } from "antd";
|
||||
import { ApiparkPluginDriver as apipark, CoreObj, generateRemoteModuleTemplate, loadRemoteModule, validateExportLifecycle } from "@businessEntry/utils/plugin";
|
||||
import { DEFAULT_LOCAL_PLUGIN_PATH, generateRemoteModuleTemplate, loadRemoteModule, validateExportLifecycle } from "@common/utils/plugin.tsx";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { RouteConfig } from "@businessEntry/components/aoplatform/RenderRoutes";
|
||||
import { routerMap } from "@businessEntry/consts/const";
|
||||
import { PluginConfigType, RouteConfig } from "@common/const/type.ts";
|
||||
import { ApiparkPluginDriverType ,RouterMapConfig} from "@common/const/type";
|
||||
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
||||
import { usePluginSlotHub } from "@common/contexts/PluginSlotHubContext";
|
||||
import { App } from "antd";
|
||||
|
||||
const mockData = {
|
||||
buildAt:'2024-09-13T03:51:25Z',
|
||||
@@ -182,7 +184,7 @@ const mockData = {
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// {
|
||||
// "driver": "apipark.remote.normal",
|
||||
// "name": "remote",
|
||||
@@ -230,12 +232,12 @@ const mockData = {
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.local.router",
|
||||
// "name": "monitor",
|
||||
// "driver": "apipark.local.preload",
|
||||
// "name": "remote",
|
||||
// "router": [
|
||||
// {
|
||||
// "expose": "AppModule",
|
||||
// "path": "monitor",
|
||||
// "expose": "App",
|
||||
// "path": "router1/*",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
@@ -256,17 +258,34 @@ const mockData = {
|
||||
version:'6438d5aa'
|
||||
}
|
||||
|
||||
const usePluginLoader = () => {
|
||||
export type ExecutePluginType = PluginConfigType & {
|
||||
expose:string,
|
||||
bootstrap:string
|
||||
}
|
||||
|
||||
const usePluginLoader = (apipark:ApiparkPluginDriverType,routerMap:Map<string, RouterMapConfig>) => {
|
||||
const [modules, setModules] = useState(new Map());
|
||||
const [executeList, setExecuteList] = useState([]);
|
||||
const [executeList, setExecuteList] = useState<ExecutePluginType[]>([]);
|
||||
const [baseHref, setBaseHref] = useState('');
|
||||
const [redirectUrl, setRedirectUrl] = useState('');
|
||||
const [pendingTasks, setPendingTasks] = useState(0);
|
||||
const {fetchData} = useFetch();
|
||||
const pluginProvider = useGlobalContext();
|
||||
const {state, dispatch,getMenuList,pluginEventHub,pluginSlotHubService:pluginSlotHub} = pluginProvider
|
||||
const { finalRouterConfig, setFinalRouterConfig} = useState<RouteConfig[]>([])
|
||||
const {message:messageService, modal:modalService} = App.useApp();
|
||||
|
||||
const pluginEventHub = usePluginEventHub();
|
||||
const pluginSlotHub = usePluginSlotHub();
|
||||
const { getMenuList,dispatch} = pluginProvider
|
||||
const { modal,message } = App.useApp()
|
||||
const [startLoadExecutePlugin, setStartLoadExecutePlugin] = useState<boolean>(false)
|
||||
const messageService = message;
|
||||
const modalService = modal;
|
||||
let startInstallPlugin = false
|
||||
|
||||
useEffect(()=>{
|
||||
if (startLoadExecutePlugin && pendingTasks === 0 && executeList.length > 0) {
|
||||
loadExecutedPlugin();
|
||||
}
|
||||
},[pendingTasks, executeList])
|
||||
|
||||
|
||||
const getModule = (routerPrefix:string, specific = false) => {
|
||||
if (routerPrefix.startsWith('/')) {
|
||||
routerPrefix = routerPrefix.substring(1);
|
||||
@@ -289,26 +308,34 @@ const usePluginLoader = () => {
|
||||
const loadModule = async (routerPrefix: string, pluginName: any, exposedModule: string , pluginPath: any) => {
|
||||
if (!modules.get(routerPrefix)) {
|
||||
try {
|
||||
const Module = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, exposedModule, pluginPath));
|
||||
setModules(prevModules => new Map(prevModules).set(routerPrefix, Module));
|
||||
const loadedModule = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, exposedModule, pluginPath));
|
||||
const Module = loadedModule.default ?? loadedModule
|
||||
let ModuleBootstrap;
|
||||
try {
|
||||
ModuleBootstrap = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, 'Bootstrap', pluginPath));
|
||||
} catch (error) {
|
||||
console.warn('Bootstrap module not found:', error);
|
||||
}
|
||||
setModules(prevModules => new Map(prevModules).set(routerPrefix,Module[exposedModule] ));
|
||||
if (!validateExportLifecycle(Module)) {
|
||||
console.error('需要导出插件生命周期函数');
|
||||
return;
|
||||
}
|
||||
await Module.bootstrap?.({
|
||||
pluginProvider,
|
||||
pluginEventHub: pluginEventHub,
|
||||
pluginEventHub,
|
||||
pluginSlotHub
|
||||
});
|
||||
return Module[exposedModule];
|
||||
return Module;
|
||||
} catch (error) {
|
||||
console.error('导入插件失败:', error);
|
||||
}
|
||||
}
|
||||
return getModule(routerPrefix, true)[exposedModule];
|
||||
return getModule(routerPrefix, true);
|
||||
};
|
||||
|
||||
const loadExecutedPlugin = async () => {
|
||||
setStartLoadExecutePlugin(true)
|
||||
for (const plugin of executeList) {
|
||||
try {
|
||||
const Module = await loadRemoteModule(generateRemoteModuleTemplate(plugin.name, plugin?.expose || 'Bootstrap', plugin.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${plugin.name}/apipark.js`));
|
||||
@@ -321,10 +348,8 @@ const usePluginLoader = () => {
|
||||
pluginSlotHub,
|
||||
pluginProvider,
|
||||
platformProvider:null,
|
||||
closeModal,
|
||||
messageService,
|
||||
modalService,
|
||||
apiService:fetchData
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -333,24 +358,22 @@ const usePluginLoader = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO 暂未找到关闭弹窗的全局方法
|
||||
const closeModal = () => {
|
||||
};
|
||||
|
||||
const loadPlugins = () => {
|
||||
return new Promise((resolve) => {
|
||||
const routerConfig: RouteConfig[] = [];
|
||||
apipark['builtIn'].default({ routerConfig } as CoreObj);
|
||||
installPlugin(routerConfig).then(async (res)=>{
|
||||
if(startInstallPlugin) {
|
||||
return resolve(true)
|
||||
}
|
||||
startInstallPlugin = true
|
||||
installPlugin().then(async (res)=>{
|
||||
// reset route after loading executed plugins
|
||||
// TODO 需要测试次式executeList是否已经更新,如果没有更新的话要修改executeList 更新的写法
|
||||
await loadExecutedPlugin();
|
||||
resolve(res)
|
||||
return resolve(res)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const installPlugin = (routerConfig: any[]) => {
|
||||
const installPlugin = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// fetchData('system/plugins',{method:'GET'}).then((resp) => {
|
||||
// if (resp.code === 0){
|
||||
@@ -374,12 +397,18 @@ const usePluginLoader = () => {
|
||||
continue;
|
||||
}
|
||||
const driver = driverName.split('.').reduce((driverMethod: { [x: string]: any; }, driverName: string | number) => driverMethod[driverName], driverMethod);
|
||||
driver({ routerConfig, setExecuteList, pluginLoader, pluginProvider, pluginLifecycleGuard, builtInPluginLoader }, plugin);
|
||||
if(driverName.split('.')[2] === 'preload'){
|
||||
setPendingTasks(prev => prev + 1);
|
||||
}
|
||||
;(driver as Function )?.({ setExecuteList:(callback:ExecutePluginType[]) => {
|
||||
setExecuteList(callback);
|
||||
setPendingTasks(prev => prev - 1);
|
||||
}, pluginLoader, pluginProvider, pluginLifecycleGuard, builtInPluginLoader }, plugin);
|
||||
} catch (err) {
|
||||
console.warn('安装插件出错:', err);
|
||||
}
|
||||
}
|
||||
resolve(routerConfig);
|
||||
resolve(true);
|
||||
// } else {
|
||||
// messageService.error(resp.msg || '获取插件配置列表失败,请重试!');
|
||||
// reject(new Error(resp.msg || '获取插件配置列表失败'));
|
||||
@@ -391,7 +420,7 @@ const usePluginLoader = () => {
|
||||
|
||||
const loadBuiltInModule = (pluginName: any) => {
|
||||
try {
|
||||
const { module } = routerMap.get(pluginName);
|
||||
const { module } = routerMap.get(pluginName)!;
|
||||
return module;
|
||||
} catch (err) {
|
||||
console.warn(`安装内置插件[${pluginName}]出错:`, err);
|
||||
@@ -402,7 +431,6 @@ const usePluginLoader = () => {
|
||||
loadPlugins,
|
||||
loadModule,
|
||||
loadExecutedPlugin,
|
||||
closeModal,
|
||||
setBaseHref,
|
||||
getModule
|
||||
};
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import { CoreObj, PluginConfigType, PluginRouterConfig, RouteConfig, RouterMapConfig } from '@common/const/type';
|
||||
import { isFunction } from 'lodash-es'
|
||||
// @ts-expect-error module cannot find
|
||||
import { __federation_method_setRemote,__federation_method_getRemote,__federation_method_unwrapDefault } from 'virtual:__federation__';
|
||||
import { ApiparkPluginDriverType } from '@common/const/type';
|
||||
import React from 'react';
|
||||
|
||||
interface RemoteModuleConfig{
|
||||
type:string
|
||||
remoteEntry:string
|
||||
exposedModule:string
|
||||
remoteName:string
|
||||
}
|
||||
|
||||
export async function loadRemoteModule(remoteModuleConfig:RemoteModuleConfig){
|
||||
__federation_method_setRemote(remoteModuleConfig.remoteName, {
|
||||
url: () => Promise.resolve(remoteModuleConfig.remoteEntry),
|
||||
format: 'esm',
|
||||
from: 'vite',
|
||||
});
|
||||
return await __federation_method_getRemote(
|
||||
remoteModuleConfig.remoteName,
|
||||
`./${remoteModuleConfig.exposedModule}`
|
||||
)
|
||||
}
|
||||
|
||||
export function generateRemoteModuleTemplate(
|
||||
pluginName: string,
|
||||
exposedModule: string,
|
||||
pluginPath: string
|
||||
):RemoteModuleConfig {
|
||||
return {
|
||||
type: 'module',
|
||||
remoteEntry: pluginPath,
|
||||
exposedModule,
|
||||
remoteName: pluginName
|
||||
}
|
||||
}
|
||||
|
||||
/** check the lifecycle method of plugin */
|
||||
export function validateExportLifecycle(exports: unknown) {
|
||||
const { bootstrap, mount, unmount } = exports ?? {}
|
||||
return isFunction(bootstrap) && isFunction(mount) && isFunction(unmount)
|
||||
}
|
||||
|
||||
export const DEFAULT_LOCAL_PLUGIN_PATH = '/plugin-frontend/'
|
||||
|
||||
export const ApiparkPluginDriver = (routerMap: Map<string, RouterMapConfig>): ApiparkPluginDriverType => { return {
|
||||
builtIn: {
|
||||
component: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
routerMap.get(pluginConfig.name) && coreObj.pluginProvider.setRouterConfig(pluginRouter.type === 'root' , {
|
||||
...routerMap.get(pluginConfig.name)!,
|
||||
key:pluginConfig.name,
|
||||
path:pluginRouter.path})
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
remote: {
|
||||
normal: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
const routerToChanged:RouteConfig[] = coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
const remoteRouter:RouteConfig[] = routerToChanged.find((item:RouteConfig) => item?.data?.['type'] === 'remotePlugin') as RouteConfig[]
|
||||
if (!remoteRouter) {
|
||||
routerMap.get('remote') && coreObj.pluginProvider.setRouterConfig(false,{
|
||||
...routerMap.get('remote')!, key:'remote', path:'remote',type:'remotePlugin',children:[{
|
||||
path:':moduleName',
|
||||
component: routerMap.get('remote')!.component}
|
||||
]
|
||||
})
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
intelligent: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
normal: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
if(['logsettings','resourcesettings'].indexOf(pluginConfig.name) !== -1){
|
||||
const routerToChanged:RouteConfig[] = coreObj.routerConfig.find((router: RouteConfig) => router.path === '/' && router?.pathMatch !== 'full')!.children as RouteConfig[]
|
||||
const remoteRouter:RouteConfig[] = routerToChanged.find((item:RouteConfig) => item?.data?.['key'] === pluginConfig.name) as RouteConfig[]
|
||||
if(!remoteRouter){
|
||||
routerMap.get(pluginConfig.name) && routerToChanged.unshift({...routerMap.get(pluginConfig.name)!, key:pluginConfig.name, path:pluginConfig.path})
|
||||
}
|
||||
return
|
||||
}
|
||||
const remoteRouter = coreObj.routerConfig.find((item:RouteConfig) => item?.data?.['type'] === 'intelligentPlugin')
|
||||
if (!remoteRouter) {
|
||||
// coreObj.pluginProvider.setRouterConfig(false, {
|
||||
// path: 'template',
|
||||
// loadChildren: coreObj.builtInPluginLoader('intelligent'),
|
||||
// data: {
|
||||
// type: 'intelligentPlugin'
|
||||
// }
|
||||
// }, coreObj.routerConfig)
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
},
|
||||
local: {
|
||||
router: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
if (pluginRouter.type === 'sub') {
|
||||
continue
|
||||
}
|
||||
updateRouterConfigWithPlugin(coreObj, pluginRouter, pluginConfig)
|
||||
}
|
||||
return coreObj
|
||||
},
|
||||
preload: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {
|
||||
if(!coreObj || !pluginConfig) return coreObj
|
||||
coreObj.setExecuteList(prev=>[...prev,{ ...pluginConfig, expose: 'Bootstrap', bootstrap: 'BootstrapModule.bootstrap' }])
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
updateRouterConfigWithPlugin(coreObj, pluginRouter, pluginConfig)
|
||||
}
|
||||
return coreObj
|
||||
}
|
||||
// extender: (coreObj?:CoreObj, pluginConfig?:PluginConfigType) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
async function updateRouterConfigWithPlugin (coreObj: CoreObj, pluginRouter: PluginRouterConfig, pluginConfig: PluginConfigType) {
|
||||
if (!pluginRouter.expose) {
|
||||
throw new Error('pluginRouter.expose is required')
|
||||
} else {
|
||||
for (const pluginRouter of pluginConfig.router) {
|
||||
const loadedModule = await coreObj.pluginLoader.loadModule(
|
||||
pluginRouter.path,
|
||||
pluginConfig.name,
|
||||
pluginRouter.expose!,
|
||||
pluginConfig.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${pluginConfig.name}/apipark.js`
|
||||
)
|
||||
const loadedModulePage = loadedModule[pluginRouter.expose!]
|
||||
const LazyComponent = React.lazy(() => Promise.resolve({ default: loadedModulePage?.default || loadedModulePage }));
|
||||
|
||||
const newRouter: RouteConfig = {
|
||||
path: pluginRouter.path,
|
||||
key: pluginConfig.name,
|
||||
lazy: () => Promise.resolve({ default: (props: any) => <LazyComponent {...props} /> }),
|
||||
pathPrefix: pluginRouter.path.endsWith('/*') ? pluginRouter.path.slice(0, -2) : pluginRouter.path,
|
||||
lifecycle:{
|
||||
canActivate: loadedModule?.beforeMount,
|
||||
canLoad: loadedModule?.mount,
|
||||
canDeactivate: loadedModule?.beforeUnmount,
|
||||
deactivated: loadedModule?.unmount
|
||||
}
|
||||
};
|
||||
coreObj.pluginProvider.setRouterConfig(pluginRouter.type === 'root' , newRouter)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,16 @@
|
||||
|
||||
import './App.css'
|
||||
import { ConfigProvider, ConfigProviderProps, Radio, RadioChangeEvent } from 'antd';
|
||||
import { ConfigProvider, App as AppAntd } from 'antd';
|
||||
import RenderRoutes from '@core/components/aoplatform/RenderRoutes';
|
||||
import {BreadcrumbProvider} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
import zhTW from 'antd/locale/zh_TW';
|
||||
import jaJP from 'antd/locale/ja_JP';
|
||||
import useInitializeMonaco from "@common/hooks/useInitializeMonaco";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/zh-tw';
|
||||
import 'dayjs/locale/ja';
|
||||
import dayjs from 'dayjs';
|
||||
import { useGlobalContext } from '@common/contexts/GlobalStateContext';
|
||||
import { useMemo } from 'react';
|
||||
import { GlobalProvider } from '@common/contexts/GlobalStateContext';
|
||||
import { $t } from '@common/locales';
|
||||
|
||||
type Locale = ConfigProviderProps['locale'];
|
||||
|
||||
const languageMap: Record<string, Locale> = {
|
||||
'zh-CN':zhCN,
|
||||
'en-US':enUS,
|
||||
'zh-TW':zhTW,
|
||||
'ja-JP':jaJP
|
||||
}
|
||||
import { PluginEventHubProvider } from '@common/contexts/PluginEventHubContext';
|
||||
import { PluginSlotHubProvider } from '@common/contexts/PluginSlotHubContext';
|
||||
import { useLocaleContext } from '@common/contexts/LocaleContext';
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
|
||||
|
||||
const antdComponentThemeToken = {
|
||||
@@ -150,33 +136,35 @@ const antdComponentThemeToken = {
|
||||
|
||||
|
||||
function App() {
|
||||
const [locale, setLocal] = useState<Locale>();
|
||||
const { locale } = useLocaleContext();
|
||||
useInitializeMonaco()
|
||||
const { state} = useGlobalContext()
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dayjs.locale(state.language);
|
||||
setLocal(languageMap[state.language]);
|
||||
},[state.language])
|
||||
|
||||
const validateMessages = useMemo(()=>({
|
||||
required: $t('必填项'),
|
||||
email:$t('不是有效邮箱地址')}
|
||||
),[state.language])
|
||||
),[locale])
|
||||
|
||||
return (
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={locale}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}
|
||||
form={{validateMessages }}>
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={locale}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}
|
||||
form={{validateMessages }}>
|
||||
<AppAntd className="h-full" message={{ maxCount: 1 }}>
|
||||
<PluginEventHubProvider>
|
||||
<PluginSlotHubProvider>
|
||||
<GlobalProvider>
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</GlobalProvider>
|
||||
</PluginSlotHubProvider>
|
||||
</PluginEventHubProvider>
|
||||
</AppAntd>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,532 +1,90 @@
|
||||
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { Navigate, RouterProvider, createBrowserRouter, RouteObject } from 'react-router-dom';
|
||||
import BasicLayout from '@common/components/aoplatform/BasicLayout';
|
||||
import {createElement,Suspense, useEffect, useState} from 'react';
|
||||
import {App, Skeleton} from "antd";
|
||||
import {Skeleton, Spin} from "antd";
|
||||
import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx";
|
||||
import usePluginLoader from '@common/hooks/pluginLoader.ts';
|
||||
import { RouteConfig } from '@common/const/type.ts';
|
||||
|
||||
// // const PUBLIC_ROUTES:RouteConfig[] = [
|
||||
// {
|
||||
// path:'/',
|
||||
// component:<Login/>,
|
||||
// key: 'root',
|
||||
// },
|
||||
// {
|
||||
// path:'/login',
|
||||
// component:<Login/>,
|
||||
// key: 'login'
|
||||
// },
|
||||
// {
|
||||
// path:'/',
|
||||
// component:<ProtectedRoute/>,
|
||||
// key: 'layout',
|
||||
// children:[
|
||||
// {
|
||||
// path:'guide/*',
|
||||
// component:<Guide />,
|
||||
// key:'guide'
|
||||
// },
|
||||
// {
|
||||
// path:'team',
|
||||
// component:<Outlet/>,
|
||||
// key: 'team',
|
||||
// provider: TeamProvider,
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'teamList',
|
||||
// component: <Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key: 'teamList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamList.tsx'))
|
||||
// },
|
||||
// {
|
||||
// path:'inside/:teamId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsidePage.tsx')),
|
||||
// key: 'teamInside',
|
||||
// children:[
|
||||
// {
|
||||
// path:'member',
|
||||
// key: 'teamMember',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsideMember.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key: 'teamSetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamConfig.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'service',
|
||||
// key: uuidv4(),
|
||||
// component:<SystemOutlet />,
|
||||
// key: 'restService',
|
||||
// provider: SystemProvider,
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key:'restServiceList',
|
||||
// component:<Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key: 'restServiceList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'list/:teamId',
|
||||
// key: 'restServiceList3',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:':teamId',
|
||||
// component:<Outlet/>,
|
||||
// key: 'restServiceInside',
|
||||
// children:[
|
||||
// {
|
||||
// path:'inside/:serviceId',
|
||||
// key: 'restServiceInside2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsidePage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'api',
|
||||
// key: 'restServiceInsideApi',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideApiDocument.tsx')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/create',
|
||||
// key: 'restServiceInsideRouteCreate',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/:routeId',
|
||||
// key: 'restServiceInsideRouteEdit',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
// path:'route',
|
||||
// key: 'restServiceInsideRoute',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
// },
|
||||
// {
|
||||
// path:'upstream',
|
||||
// key: 'restServiceInsideUpstream',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/upstream/SystemInsideUpstreamContent.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'document',
|
||||
// key: 'restServiceInsideDocument',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideDocument.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'subscriber',
|
||||
// key: 'restServiceInsideSubscriber',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideSubscriber.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'approval',
|
||||
// key: 'restServiceInsideApproval',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApproval.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'restServiceInsideApprovalList',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: 'restServiceInsideApprovalList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'topology',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemTopology.tsx')),
|
||||
// key: 'systemTopology',
|
||||
// children:[
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'publish',
|
||||
// key: 'systemPublish',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublish.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'systemPublishList',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: 'systemPublishList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key: 'systemConfig',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'aiInside/:serviceId',
|
||||
// component:<AiServiceOutlet />,
|
||||
// provider: AiServiceProvider,
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsidePage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'api',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideApiDocument')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/create',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
|
||||
// path:'route/:routeId',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate')),
|
||||
// },
|
||||
// {
|
||||
// path:'route',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterList')),
|
||||
// },
|
||||
// {
|
||||
// path:'document',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideDocument.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'subscriber',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/AiServiceInsideSubscriber.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'approval',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApproval')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/approval/AiServiceInsideApprovalList')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'publish',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublish')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
// },
|
||||
// {
|
||||
// path:'*',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiService/publish/AiServiceInsidePublishList')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key: uuidv4(),
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
// children:[
|
||||
|
||||
// ]
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'datasourcing',
|
||||
// key: 'dataSourcing',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideDashboardSetting.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'cluster',
|
||||
// key: 'cluster',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCluster.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'aisetting',
|
||||
// key: 'aiSetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiSetting/AiSettingList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'cert',
|
||||
// key: 'cert',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCert.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'serviceHub',
|
||||
// component:<Outlet />,
|
||||
// key:'serviceHub',
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key: 'serviceHubList',
|
||||
// component: <Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'serviceHubList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'detail/:serviceId',
|
||||
// key:'serviceHubDetail',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubDetail.tsx')),
|
||||
// }]
|
||||
// },
|
||||
// {
|
||||
// path:'commonsetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/common/CommonPage.tsx')),
|
||||
// key:uuidv4(),
|
||||
// },
|
||||
// {
|
||||
// path:'consumer',
|
||||
// component:<Outlet />,
|
||||
// provider:TenantManagementProvider,
|
||||
// key:'tenantManagement',
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key:'tenantManagementList',
|
||||
// component:<Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:':teamId/inside/:appId',
|
||||
// key:'tenantManagementInside',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsidePage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'service',
|
||||
// key:'tenantManagementInsideService',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideService.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'authorization',
|
||||
// key:'tenantManagementInsideAuthorization',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideAuth.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'setting',
|
||||
// key:'tenantManagementSetting',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementAppSetting.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'serviceHubManagementList',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'list/:teamId',
|
||||
// key:'serviceHubManagementList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'member',
|
||||
// key:'member',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberPage.tsx')),
|
||||
// children:[
|
||||
// {
|
||||
// path:'',
|
||||
// key:'memberList',
|
||||
// component:<Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'memberList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
// },
|
||||
// {
|
||||
// path:'list/:memberGroupId',
|
||||
// key:'memberList3',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'role',
|
||||
// key:'role',
|
||||
// component:<Outlet />,
|
||||
// children:[
|
||||
// {
|
||||
// path: '',
|
||||
// key: 'roleList',
|
||||
// component: <Navigate to="list" />
|
||||
// },
|
||||
// {
|
||||
// path:'list',
|
||||
// key:'roleList2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleList.tsx')),
|
||||
// },{
|
||||
// path:':roleType/config/:roleId',
|
||||
// key:'roleConfig',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
// },{
|
||||
// path:':roleType/config',
|
||||
// key:'roleConfig2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'analytics',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/Dashboard.tsx')),
|
||||
// key:'analytics',
|
||||
// children:[
|
||||
// {
|
||||
// path:'total',
|
||||
// key:'analytics2',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardTotal.tsx')),
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path:'template/:moduleId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
// key:'intelligentPlugin'
|
||||
// },
|
||||
// {
|
||||
// path:'logsettings/*',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/logsettings/LogSettings.tsx')),
|
||||
// key: 'logSettings',
|
||||
// children:[{
|
||||
// path:'template/:moduleId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
// key:'logSettings2'
|
||||
// }]
|
||||
|
||||
// },
|
||||
// APP_MODE ==='pro' && {
|
||||
// path:'resourcesettings/*',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/resourcesettings/ResourceSettings.tsx')),
|
||||
// key: 'resourceSettings',
|
||||
// children:[{
|
||||
// path:'template/:moduleId',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
// key:'resourceSettings2'
|
||||
// }]
|
||||
|
||||
// },
|
||||
// {
|
||||
// path:'userProfile/*',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')),
|
||||
// key:'userProfile',
|
||||
// children:[{
|
||||
// path:'changepsw',
|
||||
// lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')),
|
||||
// key:'changePsw'
|
||||
// }]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// // ]
|
||||
import { ApiparkPluginDriver } from '@common/utils/plugin.tsx';
|
||||
import { routerMap } from '@core/const/const';
|
||||
import withRouteGuard from "@common/components/aoplatform/WithRouteGuard.tsx";
|
||||
import ErrorBoundary from "@common/components/aoplatform/ErrorBoundary";
|
||||
import React from 'react';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
|
||||
const RenderRoutes = ()=> {
|
||||
const { loadPlugins } = usePluginLoader()
|
||||
const [routeConfig , setRouteConfig] = useState<RouteConfig[]>([])
|
||||
const { loadPlugins,loadExecutedPlugin } = usePluginLoader(ApiparkPluginDriver(routerMap), routerMap)
|
||||
const { routeConfig } = useGlobalContext();
|
||||
const [router, setRouter] = useState<unknown>(null);
|
||||
|
||||
useEffect(()=>{
|
||||
loadPlugins().then((res)=>{
|
||||
console.log('newRouteConfig',res)
|
||||
setRouteConfig(res as RouteConfig[])
|
||||
loadPlugins().then(()=>{
|
||||
loadExecutedPlugin()
|
||||
})
|
||||
},[])
|
||||
|
||||
useEffect(() => {
|
||||
if (routeConfig && routeConfig.length > 0) {
|
||||
const routerInstance = createBrowserRouter(generateRoutes(routeConfig));
|
||||
setRouter(routerInstance);
|
||||
}
|
||||
}, [routeConfig]);
|
||||
|
||||
if (!router) {
|
||||
return <Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={true} className='w-full h-full flex items-center justify-center'></Spin>;
|
||||
}
|
||||
|
||||
return (
|
||||
<App className="h-full" message={{ maxCount: 1 }}>
|
||||
<Router>
|
||||
<Routes>
|
||||
{ generateRoutes(routeConfig)}
|
||||
</Routes>
|
||||
</Router>
|
||||
</App>
|
||||
)
|
||||
<RouterProvider router={router} />
|
||||
);
|
||||
}
|
||||
|
||||
const generateRoutes = (routerConfig: RouteConfig[]) => {
|
||||
const generateRoutes = (routerConfig: RouteConfig[]):RouteObject[] => {
|
||||
return routerConfig?.map((route: RouteConfig) => {
|
||||
let routeElement;
|
||||
if (route.lazy) {
|
||||
const LazyComponent = route.lazy as React.ExoticComponent<unknown>;
|
||||
|
||||
let LazyComponent;
|
||||
if (typeof route.lazy === 'function') {
|
||||
const result = route.lazy();
|
||||
if (result instanceof Promise) {
|
||||
LazyComponent = React.lazy(() => result.then(module => ({ default: module.default || module })));
|
||||
} else {
|
||||
LazyComponent = result;
|
||||
}
|
||||
} else {
|
||||
LazyComponent = route.lazy;
|
||||
}
|
||||
const GuardedComponent = withRouteGuard(LazyComponent, {pathPrefix:`/${route.pathPrefix ?? route.path}`, ...route.lifecycle});
|
||||
routeElement = (
|
||||
<Suspense fallback={ <div className=''><Skeleton className='m-btnbase w-calc-100vw-minus-padding-r' active /></div>}>
|
||||
{route.provider ? (
|
||||
createElement(route.provider, {}, <LazyComponent />)
|
||||
createElement(route.provider, {}, <GuardedComponent />)
|
||||
) : (
|
||||
<LazyComponent />
|
||||
<GuardedComponent />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
} else {
|
||||
routeElement = route.provider ? (
|
||||
createElement(route.provider, {}, route.component)
|
||||
createElement(route.provider, {}, route.component)
|
||||
) : (
|
||||
route.component
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Route
|
||||
key={route.key}
|
||||
path={route.path}
|
||||
element={routeElement}
|
||||
>
|
||||
{route.children && generateRoutes(route.children as RouteConfig[])}
|
||||
</Route>
|
||||
{
|
||||
path: route.path,
|
||||
element: <ErrorBoundary>{routeElement}</ErrorBoundary> ,
|
||||
children: route.children ? generateRoutes(route.children as RouteConfig[]) : undefined,}
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 保护的路由组件
|
||||
function ProtectedRoute() {
|
||||
export function ProtectedRoute() {
|
||||
const {state} = useGlobalContext()
|
||||
return state.isAuthenticated? <BasicLayout project="core" /> : <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,18 +1,19 @@
|
||||
import { RouterMapConfig } from '@common/const/type';
|
||||
import { ProtectedRoute } from '@core/components/aoplatform/RenderRoutes';
|
||||
import { AiServiceProvider } from '@core/contexts/AiServiceContext';
|
||||
import { SystemProvider } from '@core/contexts/SystemContext';
|
||||
import { TeamProvider } from '@core/contexts/TeamContext';
|
||||
import AiServiceOutlet from '@core/pages/aiService/AiServiceOutlet';
|
||||
import Guide from '@core/pages/guide/Guide';
|
||||
import Login from '@core/pages/Login';
|
||||
import SystemOutlet from '@core/pages/system/SystemOutlet';
|
||||
import { TenantManagementProvider } from '@market/contexts/TenantManagementContext';
|
||||
import { lazy } from 'react';
|
||||
import { Outlet, Navigate } from 'react-router-dom';
|
||||
import {ProtectedRoute} from '@businessEntry/components/aoplatform/RenderRoutes';
|
||||
import Guide from '@core/pages/guide/Guide';
|
||||
import { AiServiceProvider } from '@core/contexts/AiServiceContext';
|
||||
import AiServiceOutlet from '@core/pages/aiService/AiServiceOutlet';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
// 内置插件与对应组件/模块
|
||||
export const routerMap:Map<string, unknown> = new Map([
|
||||
export const routerMap:Map<string, RouterMapConfig> = new Map([
|
||||
['basicLayout', { type: 'component', component: <ProtectedRoute />}],
|
||||
['navHidden', { type: 'component', component: <ProtectedRoute /> }],
|
||||
['login', { type: 'component', component: <Login /> }],
|
||||
@@ -104,7 +105,7 @@ import React from 'react';
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterCreate')),
|
||||
},
|
||||
{
|
||||
path:'router',
|
||||
path:'route',
|
||||
key: 'restServiceInsideRoute',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
},
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
import {FC, createContext, useContext, useState, ReactNode } from 'react';
|
||||
import { PartitionConfigFieldType } from '../const/partitions/types.ts';
|
||||
|
||||
interface PartitionContextProps {
|
||||
partitionInfo:PartitionConfigFieldType|undefined
|
||||
setPartitionInfo:React.Dispatch<React.SetStateAction<PartitionConfigFieldType|undefined>>;
|
||||
}
|
||||
|
||||
const PartitionContext = createContext<PartitionContextProps | undefined>(undefined);
|
||||
|
||||
export const usePartitionContext = () => {
|
||||
const context = useContext(PartitionContext);
|
||||
if (!context) {
|
||||
throw new Error('useArray must be used within a ArrayProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const PartitionProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [partitionInfo, setPartitionInfo] = useState<PartitionConfigFieldType>()
|
||||
return <PartitionContext.Provider value={{ partitionInfo, setPartitionInfo }}>{children}</PartitionContext.Provider>;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
import { createContext, useContext, useState, ReactNode, FC } from 'react';
|
||||
import { MyServiceFieldType } from '../const/system/type.ts';
|
||||
|
||||
interface SystemMyServiceContextProps {
|
||||
serviceInfo:MyServiceFieldType|undefined
|
||||
setServiceInfo:React.Dispatch<React.SetStateAction<MyServiceFieldType|undefined>>;
|
||||
}
|
||||
|
||||
const SystemMyServiceContext = createContext<SystemMyServiceContextProps | undefined>(undefined);
|
||||
|
||||
export const useSystemMyServiceContext = () => {
|
||||
const context = useContext(SystemMyServiceContext);
|
||||
if (!context) {
|
||||
throw new Error('useArray must be used within a ArrayProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const SystemMyServiceProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [serviceInfo, setServiceInfo] = useState<MyServiceFieldType>()
|
||||
return <SystemMyServiceContext.Provider value={{ serviceInfo, setServiceInfo }}>{children}</SystemMyServiceContext.Provider>;
|
||||
};
|
||||
@@ -3,8 +3,6 @@ import {StrictMode} from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
import {GlobalProvider} from "@common/contexts/GlobalStateContext.tsx";
|
||||
|
||||
async function initializeApp() {
|
||||
try {
|
||||
// 初始化行为
|
||||
@@ -13,9 +11,7 @@ async function initializeApp() {
|
||||
// 异步操作完成后,渲染React消费者
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<GlobalProvider>
|
||||
<App />
|
||||
</GlobalProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
@@ -206,7 +206,7 @@ const Login:FC = ()=> {
|
||||
|
||||
<section className="flex flex-col items-center mt-[46px] text-SECOND_TEXT">
|
||||
<p className="leading-[28px]">
|
||||
{$t('Version (0)-(1)',[state.version,state.updateDate])}, {$t(state.powered)}
|
||||
{$t('Version (0)-(1)',[state?.version,state?.updateDate])}, {$t(state?.powered || '-')}
|
||||
</p>
|
||||
<LanguageSetting mode="light"/>
|
||||
</section>
|
||||
|
||||
@@ -42,7 +42,6 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
|
||||
|
||||
const getApiDefine = ()=>{
|
||||
console.log('@@@@@@@')
|
||||
setApiPrefix('')
|
||||
setPrefixForce(false)
|
||||
fetchData<BasicResponse<{ prefix:string, force:boolean }>>('service/router/define',{method:'GET',eoParams:{service:serviceId,team:teamId}}).then(response=>{
|
||||
|
||||
@@ -79,7 +79,7 @@ const SystemInsideUpstreamContent= forwardRef<SystemInsideUpstreamContentHandle>
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
setTimeout(()=>{
|
||||
form.setFieldsValue({...DEFAULT_FORM_VALUE,...data.upstream})
|
||||
setFormShowHost(data.upstream.passHost === 'rewrite')
|
||||
setFormShowHost(data.upstream?.passHost === 'rewrite')
|
||||
},0)
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
|
||||
@@ -31,7 +31,6 @@ const TeamList:FC = ()=>{
|
||||
const [curTeam, setCurTeam] = useState<TeamConfigFieldType>({} as TeamConfigFieldType)
|
||||
const [modalVisible, setModalVisible] = useState<boolean>(false)
|
||||
const [modalType, setModalType] = useState<'add'|'edit'>('add')
|
||||
|
||||
const getTeamList = ()=>{
|
||||
if(!accessInit){
|
||||
getGlobalAccessData()?.then?.(()=>{getTeamList()})
|
||||
|
||||
@@ -5,6 +5,7 @@ import path from 'path'
|
||||
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
import federation from "@originjs/vite-plugin-federation";
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: './node_modules/.vite',
|
||||
@@ -42,6 +43,17 @@ export default defineConfig({
|
||||
exclude:[],
|
||||
warnOnError:false
|
||||
}),
|
||||
federation({
|
||||
name:"container",
|
||||
remotes:{
|
||||
remoteApp: 'http://localhost:5001/assets/remoteEntry.js' // 远程项目的URL
|
||||
},
|
||||
shared:[
|
||||
"react",
|
||||
"react-dom",
|
||||
]
|
||||
})
|
||||
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
|
||||
@@ -78,7 +78,6 @@ export const ManagementAuthorityConfig = forwardRef<ManagementAuthorityConfigHan
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
//console.log(data)
|
||||
if(type === 'edit' && data){
|
||||
form.setFieldsValue({...data,expireTime:data.expireTime === 0 ? '' : dayjs(data.expireTime * 1000)})
|
||||
forceUpdate({})
|
||||
|
||||
@@ -110,7 +110,7 @@ export default function ServiceHubManagement() {
|
||||
}))
|
||||
);
|
||||
if (!teamId && data.teams?.[0]?.id) {
|
||||
navigateTo(data.teams[0].id);
|
||||
navigateTo(`/consumer/list/${data.teams[0].id}`);
|
||||
}
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error));
|
||||
|
||||
Reference in New Issue
Block a user