Add local plugin import functionality

Implemented backend API and frontend UI for importing local plugin zip files. The backend now supports file uploads via a new /Plugin/Import endpoint using multer, and the frontend provides a button to upload and import plugins directly from the dashboard.

Prompt to register plugin manager if not loaded

Renames plugin_develop.ts to plugin-develop.ts for consistency. Updates the plugin import handler to prompt the user to register the plugin manager if it is not loaded, improving user experience and error handling.
This commit is contained in:
手瓜一十雪
2026-01-30 11:55:53 +08:00
parent 6a9437cb3b
commit bb69ae6c62
4 changed files with 134 additions and 2 deletions

View File

@@ -1,4 +1,8 @@
import { Router } from 'express';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import os from 'os';
import {
GetPluginListHandler,
SetPluginStatusHandler,
@@ -7,7 +11,8 @@ import {
SetPluginConfigHandler,
RegisterPluginManagerHandler,
PluginConfigSSEHandler,
PluginConfigChangeHandler
PluginConfigChangeHandler,
ImportLocalPluginHandler
} from '@/napcat-webui-backend/src/api/Plugin';
import {
GetPluginStoreListHandler,
@@ -16,6 +21,39 @@ import {
InstallPluginFromStoreSSEHandler
} from '@/napcat-webui-backend/src/api/PluginStore';
// 配置 multer 用于文件上传
const uploadDir = path.join(os.tmpdir(), 'napcat-plugin-uploads');
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
const storage = multer.diskStorage({
destination: (_req, _file, cb) => {
cb(null, uploadDir);
},
filename: (_req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, uniqueSuffix + '-' + file.originalname);
}
});
const upload = multer({
storage,
limits: {
fileSize: 50 * 1024 * 1024, // 50MB 限制
},
fileFilter: (_req, file, cb) => {
// 只允许 .zip 文件
if (file.mimetype === 'application/zip' ||
file.mimetype === 'application/x-zip-compressed' ||
file.originalname.endsWith('.zip')) {
cb(null, true);
} else {
cb(new Error('Only .zip files are allowed'));
}
}
});
const router: Router = Router();
router.get('/List', GetPluginListHandler);
@@ -26,6 +64,7 @@ router.post('/Config', SetPluginConfigHandler);
router.get('/Config/SSE', PluginConfigSSEHandler);
router.post('/Config/Change', PluginConfigChangeHandler);
router.post('/RegisterManager', RegisterPluginManagerHandler);
router.post('/Import', upload.single('plugin'), ImportLocalPluginHandler);
// 插件商店相关路由
router.get('/Store/List', GetPluginStoreListHandler);