Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9192b3995f | |||
| 7b54e12950 | |||
| 8857fc4f33 | |||
| 6bed4f7672 | |||
| ea32fb1cd6 |
@@ -113,9 +113,13 @@ func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string
|
||||
if input.AiModel.Type != "local" {
|
||||
provider = input.AiModel.Provider
|
||||
}
|
||||
modelName := input.AiModel.Name
|
||||
if modelName == "" {
|
||||
modelName = input.AiModel.Id
|
||||
}
|
||||
proxy.Plugins["ai_formatter"] = api.PluginSetting{
|
||||
Config: plugin_model.ConfigType{
|
||||
"model": input.AiModel.Name,
|
||||
"model": modelName,
|
||||
"provider": provider,
|
||||
"config": input.AiModel.Config,
|
||||
},
|
||||
|
||||
@@ -21,13 +21,14 @@ import (
|
||||
var _ IMcpController = (*imlMcpController)(nil)
|
||||
|
||||
type imlMcpController struct {
|
||||
settingModule system.ISettingModule `autowired:""`
|
||||
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
|
||||
appModule service.IAppModule `autowired:""`
|
||||
mcpModule mcp.IMcpModule `autowired:""`
|
||||
sessionKeys sync.Map
|
||||
server map[string]http.Handler
|
||||
openServer http.Handler
|
||||
settingModule system.ISettingModule `autowired:""`
|
||||
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
|
||||
appModule service.IAppModule `autowired:""`
|
||||
mcpModule mcp.IMcpModule `autowired:""`
|
||||
sessionKeys sync.Map
|
||||
sseServers map[string]http.Handler
|
||||
openSseServer http.Handler
|
||||
openStreamableServer http.Handler
|
||||
}
|
||||
|
||||
func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
|
||||
@@ -42,12 +43,12 @@ func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
|
||||
paths := strings.Split(req.URL.Path, "/")
|
||||
req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1])
|
||||
locale := utils.I18n(ctx)
|
||||
if v, ok := i.server[locale]; ok {
|
||||
if v, ok := i.sseServers[locale]; ok {
|
||||
v.ServeHTTP(ctx.Writer, req)
|
||||
return
|
||||
}
|
||||
|
||||
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
|
||||
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
|
||||
@@ -68,7 +69,7 @@ func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/sse", mcp_server.GlobalBasePath)
|
||||
i.handleSSE(ctx, i.openServer, SessionInfo{
|
||||
i.handleSSE(ctx, i.openSseServer, SessionInfo{
|
||||
Apikey: apikey,
|
||||
App: appId,
|
||||
})
|
||||
@@ -81,8 +82,29 @@ func (i *imlMcpController) AppHandleMessage(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/message", mcp_server.GlobalBasePath)
|
||||
ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
|
||||
i.handleMessage(ctx, i.openServer)
|
||||
//ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
|
||||
i.handleMessage(ctx, i.openSseServer)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) AppHandleStreamHTTP(ctx *gin.Context) {
|
||||
apikey := ctx.Request.Header.Get("Authorization")
|
||||
apikey = strings.TrimPrefix(apikey, "Bearer ")
|
||||
if apikey == "" {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
|
||||
return
|
||||
}
|
||||
appId := ctx.Request.Header.Get("X-Application-Id")
|
||||
if appId == "" {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid app id", "success": "fail"})
|
||||
return
|
||||
}
|
||||
cfg := i.settingModule.Get(ctx)
|
||||
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
|
||||
|
||||
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
|
||||
req = req.WithContext(utils.SetLabel(req.Context(), "app", appId))
|
||||
req.URL.Path = mcp_server.OpenGlobalMCPPath
|
||||
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string, error) {
|
||||
@@ -94,36 +116,44 @@ func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string,
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get app info error: %v", err)
|
||||
}
|
||||
return fmt.Sprintf(mcpDefaultConfig, appInfo.Name, fmt.Sprintf("%s/openapi/v1/mcp/app/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), appId)), nil
|
||||
}
|
||||
|
||||
var mcpDefaultConfig = `{
|
||||
"mcpServers": {
|
||||
"%s": {
|
||||
"url": "%s"
|
||||
}
|
||||
}
|
||||
return mcp_server.NewMCPConfig(
|
||||
mcp_server.TransportTypeStreamableHTTP,
|
||||
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenAppMCPPath),
|
||||
map[string]string{
|
||||
"Authorization": "Bearer {your_api_key}",
|
||||
"X-Application-Id": appId,
|
||||
},
|
||||
nil,
|
||||
).ToString(appInfo.Name), nil
|
||||
}
|
||||
`
|
||||
|
||||
func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) {
|
||||
cfg := i.settingModule.Get(ctx)
|
||||
if cfg.SitePrefix == "" {
|
||||
return "", fmt.Errorf("site prefix is empty")
|
||||
}
|
||||
return fmt.Sprintf(mcpDefaultConfig, "APIPark-MCP-Server", fmt.Sprintf("%s/openapi/v1/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.GlobalBasePath)), nil
|
||||
return mcp_server.NewMCPConfig(
|
||||
mcp_server.TransportTypeStreamableHTTP,
|
||||
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenGlobalMCPPath),
|
||||
map[string]string{
|
||||
"Authorization": "Bearer {your_api_key}",
|
||||
},
|
||||
nil,
|
||||
).ToString("APIPark-MCP-Server"), nil
|
||||
}
|
||||
|
||||
func (i *imlMcpController) OnComplete() {
|
||||
i.server = make(map[string]http.Handler)
|
||||
i.sseServers = make(map[string]http.Handler)
|
||||
for language, tools := range mcpToolsByLanguage {
|
||||
s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging())
|
||||
s.AddTool(tools[ToolServiceList], i.mcpModule.Services)
|
||||
s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs)
|
||||
s.AddTool(tools[ToolInvokeAPI], i.mcpModule.Invoke)
|
||||
i.server[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
|
||||
i.sseServers[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
|
||||
if language == languageEnUs {
|
||||
i.openServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
|
||||
i.openSseServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
|
||||
i.openStreamableServer = server.NewStreamableHTTPServer(s, server.WithEndpointPath(mcp_server.OpenGlobalMCPPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,16 +162,16 @@ func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
|
||||
cfg := i.settingModule.Get(ctx)
|
||||
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
|
||||
locale := utils.I18n(ctx)
|
||||
if v, ok := i.server[locale]; ok {
|
||||
if v, ok := i.sseServers[locale]; ok {
|
||||
v.ServeHTTP(ctx.Writer, req)
|
||||
return
|
||||
}
|
||||
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
|
||||
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) {
|
||||
apikey := ctx.Request.URL.Query().Get("apikey")
|
||||
i.handleSSE(ctx, i.openServer, SessionInfo{
|
||||
i.handleSSE(ctx, i.openSseServer, SessionInfo{
|
||||
Apikey: apikey,
|
||||
})
|
||||
}
|
||||
@@ -167,7 +197,16 @@ func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, sIn
|
||||
}
|
||||
|
||||
func (i *imlMcpController) GlobalHandleMessage(ctx *gin.Context) {
|
||||
i.handleMessage(ctx, i.openServer)
|
||||
i.handleMessage(ctx, i.openSseServer)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) GlobalHandleStreamHTTP(ctx *gin.Context) {
|
||||
apikey := ctx.Request.Header.Get("Authorization")
|
||||
apikey = strings.TrimPrefix(apikey, "Bearer ")
|
||||
cfg := i.settingModule.Get(ctx)
|
||||
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
|
||||
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
|
||||
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
|
||||
@@ -204,12 +243,13 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) {
|
||||
apikey := ctx.Request.URL.Query().Get("apikey")
|
||||
serviceId := ctx.Param("serviceId")
|
||||
apikey := ctx.Request.Header.Get("Authorization")
|
||||
serviceId := ctx.Request.Header.Get("X-Service-Id")
|
||||
if serviceId == "" {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
|
||||
return
|
||||
}
|
||||
apikey = strings.TrimPrefix(apikey, "Bearer ")
|
||||
ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})
|
||||
|
||||
@@ -13,11 +13,13 @@ type IMcpController interface {
|
||||
GlobalMCPHandle(ctx *gin.Context)
|
||||
GlobalHandleSSE(ctx *gin.Context)
|
||||
GlobalHandleMessage(ctx *gin.Context)
|
||||
GlobalHandleStreamHTTP(ctx *gin.Context)
|
||||
GlobalMCPConfig(ctx *gin.Context) (string, error)
|
||||
|
||||
AppMCPHandle(ctx *gin.Context)
|
||||
AppHandleSSE(ctx *gin.Context)
|
||||
AppHandleMessage(ctx *gin.Context)
|
||||
AppHandleStreamHTTP(ctx *gin.Context)
|
||||
AppMCPConfig(ctx *gin.Context, appId string) (string, error)
|
||||
|
||||
ServiceHandleSSE(ctx *gin.Context)
|
||||
|
||||
@@ -520,16 +520,21 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
|
||||
modelId := ""
|
||||
modelCfg := ""
|
||||
modelType := "online"
|
||||
if input.Model != nil {
|
||||
modelId = *input.Model
|
||||
}
|
||||
if *input.Provider == ai_provider_local.ProviderLocal {
|
||||
modelType = "local"
|
||||
list, err := i.aiLocalModel.SimpleList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if modelId == "" {
|
||||
list, err := i.aiLocalModel.SimpleList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return nil, fmt.Errorf("no local model")
|
||||
}
|
||||
modelId = list[0].Id
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return nil, fmt.Errorf("no local model")
|
||||
}
|
||||
modelId = list[0].Id
|
||||
modelCfg = ai_provider_local.LocalConfig
|
||||
} else {
|
||||
pv, err := i.providerModule.Provider(ctx, *input.Provider)
|
||||
@@ -540,14 +545,15 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
|
||||
if !has {
|
||||
return nil, fmt.Errorf("provider not found")
|
||||
}
|
||||
m, has := p.GetModel(pv.DefaultLLM)
|
||||
if modelId == "" {
|
||||
modelId = pv.DefaultLLM
|
||||
}
|
||||
m, has := p.GetModel(modelId)
|
||||
if !has {
|
||||
return nil, fmt.Errorf("model %s not found", pv.DefaultLLM)
|
||||
}
|
||||
//modelId = m.ID()
|
||||
modelId = m.Name()
|
||||
modelCfg = m.DefaultConfig()
|
||||
|
||||
}
|
||||
|
||||
var info *service_dto.Service
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"plugins": ["react", "@typescript-eslint", "prettier", "unused-imports"],
|
||||
"rules": {
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"prettier/prettier": "off",
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
|
||||
@@ -6,7 +6,7 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
.next/
|
||||
|
||||
node_modules
|
||||
dist
|
||||
market_dist
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const srcDir = path.join(__dirname, 'src');
|
||||
|
||||
const filesToDelete = [
|
||||
'package.json',
|
||||
'tsconfig.json',
|
||||
'tsconfig.node.json',
|
||||
'vite.config.ts',
|
||||
'postcss.config.js',
|
||||
'tailwind.config.js',
|
||||
'.eslintrc.cjs',
|
||||
'index.html',
|
||||
'start-vite.js'
|
||||
];
|
||||
|
||||
function walkDirAndClean(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
|
||||
fs.readdirSync(dir).forEach(f => {
|
||||
let dirPath = path.join(dir, f);
|
||||
try {
|
||||
let stat = fs.statSync(dirPath);
|
||||
if (stat.isDirectory() && f !== 'node_modules') {
|
||||
// If it's a top-level module directory like src/core, src/common
|
||||
if (dir === srcDir) {
|
||||
filesToDelete.forEach(file => {
|
||||
const fileToDelete = path.join(dirPath, file);
|
||||
if (fs.existsSync(fileToDelete)) {
|
||||
fs.unlinkSync(fileToDelete);
|
||||
console.log(`Deleted: ${fileToDelete}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
});
|
||||
}
|
||||
|
||||
walkDirAndClean(srcDir);
|
||||
console.log('Cleanup completed!');
|
||||
@@ -1,50 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const srcDir = path.join(__dirname, 'src');
|
||||
|
||||
function walkDir(dir, callback) {
|
||||
if (dir.includes('node_modules')) return;
|
||||
fs.readdirSync(dir).forEach(f => {
|
||||
let dirPath = path.join(dir, f);
|
||||
try {
|
||||
let isDirectory = fs.statSync(dirPath).isDirectory();
|
||||
isDirectory ? walkDir(dirPath, callback) : callback(path.join(dir, f));
|
||||
} catch(e) {}
|
||||
});
|
||||
}
|
||||
|
||||
const filesToRename = [];
|
||||
const filesToUpdate = [];
|
||||
|
||||
walkDir(srcDir, (filePath) => {
|
||||
if (filePath.endsWith('.module.css')) {
|
||||
filesToRename.push(filePath);
|
||||
} else if (filePath.endsWith('.tsx') || filePath.endsWith('.ts')) {
|
||||
filesToUpdate.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
filesToRename.forEach(oldPath => {
|
||||
const newPath = oldPath.replace(/\.module\.css$/, '.css');
|
||||
|
||||
// Read and remove :global wrappers entirely
|
||||
let content = fs.readFileSync(oldPath, 'utf8');
|
||||
content = content.replace(/:global\(([^)]+)\)/g, '$1'); // replace :global(.foo) with .foo
|
||||
content = content.replace(/:global\s+/g, ''); // replace :global .foo with .foo
|
||||
|
||||
fs.writeFileSync(oldPath, content);
|
||||
fs.renameSync(oldPath, newPath);
|
||||
console.log(`Renamed and cleaned: ${path.basename(oldPath)} -> ${path.basename(newPath)}`);
|
||||
});
|
||||
|
||||
filesToUpdate.forEach(filePath => {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
if (content.includes('.module.css')) {
|
||||
content = content.replace(/\.module\.css/g, '.css');
|
||||
fs.writeFileSync(filePath, content);
|
||||
console.log(`Updated imports in: ${path.basename(filePath)}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Done!');
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "independent"
|
||||
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const rootDir = __dirname;
|
||||
const packagesDir = path.join(rootDir, 'packages');
|
||||
const srcDir = path.join(rootDir, 'src');
|
||||
const appDir = path.join(srcDir, 'app');
|
||||
|
||||
console.log('🚀 开始拆除 Lerna 并迁移至 Next.js...');
|
||||
|
||||
// 1. 创建基础目录
|
||||
if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir);
|
||||
if (!fs.existsSync(appDir)) fs.mkdirSync(appDir);
|
||||
|
||||
// 2. 读取并合并 package.json
|
||||
const rootPkgPath = path.join(rootDir, 'package.json');
|
||||
const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf8'));
|
||||
|
||||
const mergedDeps = { ...rootPkg.dependencies };
|
||||
const mergedDevDeps = { ...rootPkg.devDependencies };
|
||||
|
||||
if (fs.existsSync(packagesDir)) {
|
||||
const packages = fs.readdirSync(packagesDir);
|
||||
for (const pkg of packages) {
|
||||
const pkgPath = path.join(packagesDir, pkg);
|
||||
if (fs.statSync(pkgPath).isDirectory()) {
|
||||
// 合并依赖
|
||||
const childPkgPath = path.join(pkgPath, 'package.json');
|
||||
if (fs.existsSync(childPkgPath)) {
|
||||
const childPkg = JSON.parse(fs.readFileSync(childPkgPath, 'utf8'));
|
||||
Object.assign(mergedDeps, childPkg.dependencies || {});
|
||||
Object.assign(mergedDevDeps, childPkg.devDependencies || {});
|
||||
}
|
||||
// 移动目录到 src 下
|
||||
const destPath = path.join(srcDir, pkg);
|
||||
if (!fs.existsSync(destPath)) {
|
||||
fs.renameSync(pkgPath, destPath);
|
||||
console.log(`📦 已迁移模块: packages/${pkg} -> src/${pkg}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 删除空的 packages 文件夹
|
||||
try { fs.rmdirSync(packagesDir); } catch (e) { console.error('Failed to remove packages dir, skipping', e) }
|
||||
}
|
||||
|
||||
// 3. 清理并更新根 package.json
|
||||
delete rootPkg.workspaces; // 移除 lerna workspaces
|
||||
rootPkg.scripts = {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
};
|
||||
|
||||
// 移除 Vite 和 Lerna 相关依赖
|
||||
const removeDeps = ['lerna', 'vite', '@originjs/vite-plugin-federation', '@vitejs/plugin-react', 'vite-tsconfig-paths'];
|
||||
removeDeps.forEach(dep => {
|
||||
delete mergedDeps[dep];
|
||||
delete mergedDevDeps[dep];
|
||||
});
|
||||
|
||||
// 添加 Next.js 和 React 最新核心依赖 (与 xroute-ui 对齐)
|
||||
mergedDeps['next'] = "15.4.5";
|
||||
mergedDeps['react'] = "19.1.0";
|
||||
mergedDeps['react-dom'] = "19.1.0";
|
||||
mergedDevDeps['@types/react'] = "^19";
|
||||
mergedDevDeps['@types/react-dom'] = "^19";
|
||||
|
||||
rootPkg.dependencies = mergedDeps;
|
||||
rootPkg.devDependencies = mergedDevDeps;
|
||||
|
||||
fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2));
|
||||
console.log('✅ package.json 依赖已合并并重写');
|
||||
|
||||
// 4. 生成 tsconfig.json (配置路径别名)
|
||||
const tsconfigPath = path.join(rootDir, 'tsconfig.json');
|
||||
const tsconfig = {
|
||||
compilerOptions: {
|
||||
target: "es5",
|
||||
lib: ["dom", "dom.iterable", "esnext"],
|
||||
allowJs: true,
|
||||
skipLibCheck: true,
|
||||
strict: false,
|
||||
noEmit: true,
|
||||
esModuleInterop: true,
|
||||
module: "esnext",
|
||||
moduleResolution: "bundler",
|
||||
resolveJsonModule: true,
|
||||
isolatedModules: true,
|
||||
jsx: "preserve",
|
||||
incremental: true,
|
||||
plugins: [{ name: "next" }],
|
||||
baseUrl: ".",
|
||||
paths: {
|
||||
"@/*": ["src/*"],
|
||||
// 欺骗原有代码,使其能找到拍平后的新路径
|
||||
"@apipark/common/*": ["src/common/src/*"],
|
||||
"@apipark/core/*": ["src/core/src/*"],
|
||||
"@apipark/dashboard/*": ["src/dashboard/src/*"],
|
||||
"@apipark/market/*": ["src/market/src/*"],
|
||||
"@apipark/openApi/*": ["src/openApi/src/*"],
|
||||
"@apipark/systemRunning/*": ["src/systemRunning/src/*"]
|
||||
}
|
||||
},
|
||||
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
exclude: ["node_modules"]
|
||||
};
|
||||
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
||||
console.log('✅ tsconfig.json 别名映射已配置');
|
||||
|
||||
// 5. 创建 Next.js App Router 挂载点
|
||||
const layoutCode = `export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}`;
|
||||
fs.writeFileSync(path.join(appDir, 'layout.tsx'), layoutCode);
|
||||
|
||||
const slugDir = path.join(appDir, '[[...slug]]');
|
||||
if (!fs.existsSync(slugDir)) fs.mkdirSync(slugDir, { recursive: true });
|
||||
|
||||
const pageCode = `"use client";
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
// 动态导入原有的 Vite SPA 根组件,禁用 SSR 避免 window 报错
|
||||
const ApiParkApp = dynamic(() => import('@/core/src/App'), {
|
||||
ssr: false,
|
||||
loading: () => <div style={{ padding: 50 }}>Loading APIPark...</div>
|
||||
});
|
||||
|
||||
export default function Page() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
if (!mounted) return null;
|
||||
return <ApiParkApp />;
|
||||
}`;
|
||||
fs.writeFileSync(path.join(slugDir, 'page.tsx'), pageCode);
|
||||
|
||||
console.log('✅ Next.js 路由挂载点创建完毕!');
|
||||
console.log('🎉 迁移完成!请执行 pnpm install 重新安装依赖。');
|
||||
@@ -1,4 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
@@ -1,42 +0,0 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
images: {
|
||||
disableStaticImages: true,
|
||||
},
|
||||
experimental: {
|
||||
optimizePackageImports: ["@heroui/react"],
|
||||
},
|
||||
transpilePackages: ['@heroui/react', '@heroui/theme', '@ant-design', 'antd', 'rc-util', 'rc-pagination', 'rc-picker', 'rc-tree', 'rc-table'],
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/api/v1/:path*',
|
||||
destination: 'http://172.18.166.219:8288/api/v1/:path*', // Proxy to backend
|
||||
},
|
||||
{
|
||||
source: '/api2/v1/:path*',
|
||||
destination: 'http://172.18.166.219:8288/api2/v1/:path*', // Proxy to backend 2
|
||||
}
|
||||
];
|
||||
},
|
||||
webpack: (config) => {
|
||||
config.module.rules.push({
|
||||
test: /\.(svg|png|jpe?g|gif|webp)$/i,
|
||||
type: 'asset/resource',
|
||||
generator: {
|
||||
filename: 'static/media/[name].[hash][ext]'
|
||||
}
|
||||
});
|
||||
|
||||
// 解决一些 Node.js polyfill 在浏览器端缺失的问题
|
||||
config.resolve.fallback = {
|
||||
...config.resolve.fallback,
|
||||
fs: false,
|
||||
path: false,
|
||||
os: false,
|
||||
};
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
@@ -2,12 +2,20 @@
|
||||
"name": "frontend",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"dev": "next dev -p 5000",
|
||||
"build": "next build",
|
||||
"start": "next start -p 5000",
|
||||
"lint": "next lint"
|
||||
"test": "jest",
|
||||
"build": "set NODE_OPTIONS=--max-old-space-size=8192 && lerna run build --scope=core --stream --verbose ",
|
||||
"serve": "lerna run preview --parallel",
|
||||
"serve:remotes": "lerna run serve --scope=remote --parallel",
|
||||
"dev": "lerna run dev --scope=core --stream",
|
||||
"stop": "kill-port --port 5000",
|
||||
"scan": "i18next-scanner --config i18next-scanner.config.js",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix && prettier --write ."
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@@ -15,88 +23,51 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@ant-design/pro-components": "2.7.19",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@floating-ui/react": "^0.26.24",
|
||||
"@formkit/auto-animate": "^0.8.1",
|
||||
"@heroui/react": "^3.0.3",
|
||||
"@heroui/styles": "^3.0.3",
|
||||
"@heroui/theme": "^2.4.20",
|
||||
"@lexical/code": "^0.17.1",
|
||||
"@lexical/react": "^0.17.1",
|
||||
"@lexical/selection": "^0.17.1",
|
||||
"@lexical/text": "^0.17.1",
|
||||
"@lexical/utils": "^0.17.1",
|
||||
"@modelcontextprotocol/sdk": "^1.9.0",
|
||||
"@mui/icons-material": "^5.15.6",
|
||||
"@mui/lab": "5.0.0-alpha.150",
|
||||
"@mui/material": "5.14.14",
|
||||
"@mui/x-data-grid-pro": "6.18.1",
|
||||
"@originjs/vite-plugin-federation": "^1.3.3",
|
||||
"@rollup/plugin-dynamic-import-vars": "^2.1.2",
|
||||
"@tinymce/tinymce-react": "^4.3.2",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"@xyflow/react": "^12.3.6",
|
||||
"ahooks": "^3.8.1",
|
||||
"allotment": "^1.20.0",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"crc": "^4.3.2",
|
||||
"dayjs": "^1.11.10",
|
||||
"dompurify": "^3.1.6",
|
||||
"echarts": "^5.5.0",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"framer-motion": "^10.16.4",
|
||||
"fs-extra": "^11.2.0",
|
||||
"highlight.js": "^11.9.0",
|
||||
"i18next": "^23.12.2",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"js-base64": "^3.7.5",
|
||||
"lexical": "^0.17.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"next": "15.4.5",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-nesting": "^12.1.5",
|
||||
"rc-picker": "^4.1.1",
|
||||
"react": "19.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-hook-form": "^7.49.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^15.0.1",
|
||||
"react-joyride": "^2.8.2",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-router-dom": "6.20.0",
|
||||
"react-virtuoso": "^4.7.11",
|
||||
"swagger-ui-react": "^5.17.14",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"tinymce": "^6.8.1",
|
||||
"use-context-selector": "^2.0.0",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"uuid": "^9.0.1",
|
||||
"zod": "^3.23.8"
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"react-json-view": "^1.21.3",
|
||||
"zod": "^3.23.8",
|
||||
"@modelcontextprotocol/sdk": "^1.9.0",
|
||||
"echarts-for-react": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/cssinjs": "^1.18.2",
|
||||
"@antv/g6": "^4.8.24",
|
||||
"@formily/antd-v5": "^1.2.1",
|
||||
"@formily/core": "^2.2.13",
|
||||
"@formily/react": "^2.2.13",
|
||||
"@formily/reactive": "^2.2.13",
|
||||
"@iconify/react": "^5.0.2",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@tailwindcss/postcss": "^4.2.1",
|
||||
"lightningcss": "^1.32.0",
|
||||
"@testing-library/jest-dom": "^6.4.5",
|
||||
"@testing-library/react": "^15.0.7",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.10.5",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/react": "^18.2.37",
|
||||
"@types/react-dom": "^18.2.15",
|
||||
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
||||
"@typescript-eslint/parser": "^6.10.0",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"antd": "^5.19.4",
|
||||
"babel-jest": "^29.7.0",
|
||||
"eslint": "^8.53.0",
|
||||
@@ -106,22 +77,22 @@
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.4",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"exceljs": "^4.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18next-scanner": "^4.5.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"jsdom": "^24.0.0",
|
||||
"lerna": "^8.1.3",
|
||||
"less": "^4.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "^0.45.0",
|
||||
"postcss-nested": "^6.0.1",
|
||||
"prettier": "^3.1.1",
|
||||
"react-test-renderer": "^18.3.1",
|
||||
"ts-jest": "^29.1.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.0.0",
|
||||
"vite-jest": "^0.1.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "common",
|
||||
"version": "1.0.0",
|
||||
"description": "Common library for AO Platform",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"test": "node ./__tests__/common.test.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "^0.26.24",
|
||||
"@formkit/auto-animate": "^0.8.1",
|
||||
"@lexical/code": "^0.17.1",
|
||||
"@lexical/react": "^0.17.1",
|
||||
"@lexical/selection": "^0.17.1",
|
||||
"@lexical/text": "^0.17.1",
|
||||
"@lexical/utils": "^0.17.1",
|
||||
"@mui/icons-material": "^5.15.6",
|
||||
"@mui/lab": "5.0.0-alpha.150",
|
||||
"@mui/material": "5.14.14",
|
||||
"@mui/x-data-grid-pro": "6.18.1",
|
||||
"ahooks": "^3.8.1",
|
||||
"allotment": "^1.20.0",
|
||||
"echarts": "^5.5.0",
|
||||
"lexical": "^0.17.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"rc-picker": "^4.1.1",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-hook-form": "^7.49.3",
|
||||
"use-context-selector": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formily/antd-v5": "^1.2.1",
|
||||
"@formily/core": "^2.2.13",
|
||||
"@formily/react": "^2.2.13",
|
||||
"@formily/reactive": "^2.2.13",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"exceljs": "^4.4.0",
|
||||
"monaco-editor": "^0.45.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
},
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
@@ -15,7 +15,7 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
||||
import LanguageSetting from './LanguageSetting'
|
||||
|
||||
const APP_MODE = process.env.NEXT_PUBLIC_APP_MODE || 'production'
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE
|
||||
export type MenuItem = Required<MenuProps>['items'][number]
|
||||
|
||||
const themeToken = {
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
.eo_page_list .ant-pro-card .ant-pro-card-body{
|
||||
:global .eo_page_list .ant-pro-card .ant-pro-card-body{
|
||||
padding:0 !important;
|
||||
}
|
||||
|
||||
.eo_page_list .ant-pro-table-list-toolbar-container{
|
||||
:global .eo_page_list .ant-pro-table-list-toolbar-container{
|
||||
|
||||
.ant-pro-table-list-toolbar-right{
|
||||
justify-content: flex-start;
|
||||
@@ -14,7 +14,7 @@
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.eo_page_list .ant-table-wrapper {
|
||||
:global .eo_page_list .ant-table-wrapper {
|
||||
.ant-table-pagination.ant-pagination {
|
||||
margin: 1px 10px 0 !important;
|
||||
padding: 10px 0;
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
useState
|
||||
} from 'react'
|
||||
import { useGlobalContext } from '../../contexts/GlobalStateContext'
|
||||
import './PageList.css'
|
||||
import './PageList.module.css'
|
||||
|
||||
export type PageProColumns<T = any, ValueType = 'text'> = ProColumns<T, ValueType> & { btnNums?: number }
|
||||
|
||||