diff --git a/back/api/script.ts b/back/api/script.ts index d6096c8f..18cb6daf 100644 --- a/back/api/script.ts +++ b/back/api/script.ts @@ -3,6 +3,7 @@ import { getFileContentByName, readDirs, getLastModifyFilePath, + readDir, } from '../config/util'; import { Router, Request, Response, NextFunction } from 'express'; import { Container } from 'typedi'; @@ -12,15 +13,37 @@ import * as fs from 'fs'; import { celebrate, Joi } from 'celebrate'; import path, { join } from 'path'; import ScriptService from '../services/script'; +import multer from 'multer'; const route = Router(); +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, config.scriptPath); + }, + filename: function (req, file, cb) { + console.log(req); + cb(null, file.originalname); + }, +}); +const upload = multer({ storage: storage }); + export default (app: Router) => { app.use('/scripts', route); route.get('/', async (req: Request, res: Response, next: NextFunction) => { const logger: Logger = Container.get('logger'); try { - const result = readDirs(config.scriptPath, config.scriptPath); + let result = []; + const blacklist = ['node_modules', '.git']; + if (req.query.path) { + const targetPath = path.join( + config.scriptPath, + req.query.path as string, + ); + result = readDir(targetPath, config.scriptPath, blacklist); + } else { + result = readDirs(config.scriptPath, config.scriptPath, blacklist); + } res.send({ code: 200, data: result, @@ -52,14 +75,7 @@ export default (app: Router) => { route.post( '/', - celebrate({ - body: Joi.object({ - filename: Joi.string().required(), - path: Joi.string().optional().allow(''), - content: Joi.string().allow(''), - originFilename: Joi.string().allow(''), - }), - }), + upload.single('file'), async (req: Request, res: Response, next: NextFunction) => { const logger: Logger = Container.get('logger'); try { @@ -69,6 +85,7 @@ export default (app: Router) => { content: string; originFilename: string; }; + if (!path) { path = config.scriptPath; } @@ -84,15 +101,18 @@ export default (app: Router) => { message: '文件路径禁止访问', }); } + + if (req.file) { + fs.renameSync(req.file.path, join(path, req.file.filename)); + return res.send({ code: 200 }); + } + if (!originFilename) { originFilename = filename; } const originFilePath = `${path}${originFilename.replace(/\//g, '')}`; const filePath = `${path}${filename.replace(/\//g, '')}`; if (fs.existsSync(originFilePath)) { - if (!fs.existsSync(config.bakPath)) { - fs.mkdirSync(config.bakPath); - } fs.copyFileSync( originFilePath, `${config.bakPath}${originFilename.replace(/\//g, '')}`, diff --git a/back/config/util.ts b/back/config/util.ts index f1db23ed..ef4d3798 100644 --- a/back/config/util.ts +++ b/back/config/util.ts @@ -277,31 +277,61 @@ export async function concurrentRun( return replyList; } -export function readDirs(dir: string, baseDir: string = '') { +export function readDirs( + dir: string, + baseDir: string = '', + blacklist: string[] = [], +) { const relativePath = path.relative(baseDir, dir); const files = fs.readdirSync(dir); - const result: any = files.map((file: string) => { - const subPath = path.join(dir, file); - const stats = fs.statSync(subPath); - const key = path.join(relativePath, file); - if (stats.isDirectory()) { + const result: any = files + .filter((x) => !blacklist.includes(x)) + .map((file: string) => { + const subPath = path.join(dir, file); + const stats = fs.statSync(subPath); + const key = path.join(relativePath, file); + if (stats.isDirectory()) { + return { + title: file, + value: file, + key, + type: 'directory', + disabled: true, + parent: relativePath, + children: readDirs(subPath, baseDir), + }; + } return { title: file, value: file, + type: 'file', key, - type: 'directory', - disabled: true, parent: relativePath, - children: readDirs(subPath, baseDir), }; - } - return { - title: file, - value: file, - type: 'file', - key, - parent: relativePath, - }; - }); + }); + return result; +} + +export function readDir( + dir: string, + baseDir: string = '', + blacklist: string[] = [], +) { + const relativePath = path.relative(baseDir, dir); + const files = fs.readdirSync(dir); + const result: any = files + .filter((x) => !blacklist.includes(x)) + .map((file: string) => { + const subPath = path.join(dir, file); + const stats = fs.statSync(subPath); + const key = path.join(relativePath, file); + return { + title: file, + value: file, + type: stats.isDirectory() ? 'directory' : 'file', + key, + parent: relativePath, + }; + }); return result; } diff --git a/back/loaders/initFile.ts b/back/loaders/initFile.ts index 464a0663..1c06692d 100644 --- a/back/loaders/initFile.ts +++ b/back/loaders/initFile.ts @@ -11,6 +11,7 @@ const configPath = path.join(dataPath, 'config/'); const scriptPath = path.join(dataPath, 'scripts/'); const logPath = path.join(dataPath, 'log/'); const uploadPath = path.join(dataPath, 'upload/'); +const bakPath = path.join(dataPath, 'bak/'); const samplePath = path.join(rootPath, 'sample/'); const confFile = path.join(configPath, 'config.sh'); const authConfigFile = path.join(configPath, 'auth.json'); @@ -27,6 +28,7 @@ export default async () => { const configDirExist = await fileExist(configPath); const uploadDirExist = await fileExist(uploadPath); const sshDirExist = await fileExist(sshPath); + const bakDirExist = await fileExist(bakPath); if (!configDirExist) { fs.mkdirSync(configPath); @@ -56,6 +58,10 @@ export default async () => { fs.mkdirSync(sshPath); } + if (!bakDirExist) { + fs.mkdirSync(bakPath); + } + dotenv.config({ path: confFile }); Logger.info('✌️ Init file down'); diff --git a/src/pages/script/editNameModal.tsx b/src/pages/script/editNameModal.tsx index 0e742402..58c8687e 100644 --- a/src/pages/script/editNameModal.tsx +++ b/src/pages/script/editNameModal.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useState } from 'react'; -import { Modal, message, Input, Form, Select } from 'antd'; +import { Modal, message, Input, Form, Select, Upload, Radio } from 'antd'; import { request } from '@/utils/http'; import config from '@/utils/config'; +import { UploadOutlined } from '@ant-design/icons'; const { Option } = Select; @@ -21,21 +22,30 @@ const EditScriptNameModal = ({ const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [dirs, setDirs] = useState([]); + const [file, setFile] = useState(); + const [type, setType] = useState<'blank' | 'upload'>('blank'); const handleOk = async (values: any) => { setLoading(true); values.path = values.path || ''; + const formData = new FormData(); + formData.append('file', file as any); + formData.append('filename', values.filename); + formData.append('path', values.path); + formData.append('content', ''); request .post(`${config.apiPrefix}scripts`, { - data: { filename: values.filename, path: values.path, content: '' }, + data: formData, }) .then(({ code, data }) => { if (code === 200) { message.success('保存文件成功'); + const key = values.path ? `${values.path}-` : ''; + const filename = file ? file.name : values.filename; handleCancel({ - filename: values.filename, + filename, path: values.path, - key: `${values.path}-${values.filename}`, + key: `${key}${filename}`, }); } else { message.error(data); @@ -45,6 +55,15 @@ const EditScriptNameModal = ({ .finally(() => setLoading(false)); }; + const beforeUpload = (file: File) => { + setFile(file); + return false; + }; + + const typeChange = (e) => { + setType(e.target.value); + }; + useEffect(() => { form.resetFields(); const originDirs = treeData.filter((x) => x.disabled); @@ -73,12 +92,25 @@ const EditScriptNameModal = ({ >
- + + 空文件 + 本地上传 + + {type === 'blank' && ( + + + + )} + {type === 'upload' && ( + + +

+ +

+

点击或者拖拽文件到此区域上传

+
+
+ )}
);