From dfc706e16d1c18d07e686eaa70dd454464595259 Mon Sep 17 00:00:00 2001 From: whyour Date: Fri, 23 Sep 2022 20:09:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=AE=A1=E7=90=86=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=88=A0=E9=99=A4=E6=97=A5=E5=BF=97=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/api/log.ts | 33 ++++++++++++- src/layouts/defaultProps.tsx | 12 ++--- src/pages/log/index.tsx | 93 ++++++++++++++++++++++++++++++++++-- src/pages/script/index.tsx | 12 +---- src/utils/config.ts | 6 +-- src/utils/index.ts | 7 ++- 6 files changed, 136 insertions(+), 27 deletions(-) diff --git a/back/api/log.ts b/back/api/log.ts index 33d7e2ec..5a82c031 100644 --- a/back/api/log.ts +++ b/back/api/log.ts @@ -3,8 +3,9 @@ import { Container } from 'typedi'; import { Logger } from 'winston'; import * as fs from 'fs'; import config from '../config'; -import { getFileContentByName, readDirs } from '../config/util'; +import { emptyDir, getFileContentByName, readDirs } from '../config/util'; import { join } from 'path'; +import { celebrate, Joi } from 'celebrate'; const route = Router(); const blacklist = ['.tmp']; @@ -45,4 +46,34 @@ export default (app: Router) => { } }, ); + + route.delete( + '/', + celebrate({ + body: Joi.object({ + filename: Joi.string().required(), + path: Joi.string().allow(''), + type: Joi.string().optional() + }), + }), + async (req: Request, res: Response, next: NextFunction) => { + try { + let { filename, path, type } = req.body as { + filename: string; + path: string; + type: string; + }; + const filePath = join(config.logPath, path, filename); + if (type === 'directory') { + emptyDir(filePath); + } else { + fs.unlinkSync(filePath); + } + res.send({ code: 200 }); + } catch (e) { + return next(e); + } + }, + ); + }; diff --git a/src/layouts/defaultProps.tsx b/src/layouts/defaultProps.tsx index 5856dc31..cc879c34 100644 --- a/src/layouts/defaultProps.tsx +++ b/src/layouts/defaultProps.tsx @@ -68,18 +68,18 @@ export default { icon: , component: '@/pages/dependence/index', }, + { + path: '/log', + name: '日志管理', + icon: , + component: '@/pages/log/index', + }, { path: '/diff', name: '对比工具', icon: , component: '@/pages/diff/index', }, - { - path: '/log', - name: '任务日志', - icon: , - component: '@/pages/log/index', - }, { path: '/setting', name: '系统设置', diff --git a/src/pages/log/index.tsx b/src/pages/log/index.tsx index 9155a293..7f6589a9 100644 --- a/src/pages/log/index.tsx +++ b/src/pages/log/index.tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, Key, useRef } from 'react'; -import { TreeSelect, Tree, Input, Empty } from 'antd'; +import { TreeSelect, Tree, Input, Empty, Button, message, Modal, Tooltip, Typography } from 'antd'; import config from '@/utils/config'; import { PageContainer } from '@ant-design/pro-layout'; import Editor from '@monaco-editor/react'; @@ -9,6 +9,11 @@ import { Controlled as CodeMirror } from 'react-codemirror2'; import SplitPane from 'react-split-pane'; import { useOutletContext } from '@umijs/max'; import { SharedContext } from '@/layouts'; +import { DeleteOutlined } from '@ant-design/icons'; +import { depthFirstSearch } from '@/utils'; +import { debounce } from 'lodash'; + +const { Text } = Typography; function getFilterData(keyword: string, data: any) { const expandedKeys: string[] = []; @@ -49,6 +54,8 @@ const Log = () => { const [height, setHeight] = useState(); const treeDom = useRef(); const [expandedKeys, setExpandedKeys] = useState([]); + const [currentNode, setCurrentNode] = useState(); + const [searchValue, setSearchValue] = useState(''); const getLogs = () => { setLoading(true); @@ -77,9 +84,16 @@ const Log = () => { if (node.key === select || !value) { return; } - setValue('加载中...'); + setCurrentNode(node); setSelect(value); setTitle(node.key); + + if (node.type === 'directory') { + setValue('请选择日志文件'); + return; + } + + setValue('加载中...'); getLog(node); }; @@ -90,16 +104,75 @@ const Log = () => { const onSearch = useCallback( (e) => { const keyword = e.target.value; + debounceSearch(keyword); + }, + [data, setFilterData], + ); + + const debounceSearch = useCallback( + debounce((keyword) => { + setSearchValue(keyword); const { tree, expandedKeys } = getFilterData( keyword.toLocaleLowerCase(), data, ); setFilterData(tree); setExpandedKeys(expandedKeys); - }, + }, 300), [data, setFilterData], ); + const deleteFile = () => { + Modal.confirm({ + title: `确认删除`, + content: ( + <> + 确认删除 + + {select} + + 文件{currentNode.type === 'directory' ? '夹下所以日志':''},删除后不可恢复 + + ), + onOk() { + request + .delete(`${config.apiPrefix}logs`, { + data: { + filename: currentNode.title, + path: currentNode.parent || '', + type: currentNode.type + }, + }) + .then(({ code }) => { + if (code === 200) { + message.success(`删除成功`); + let newData = [...data]; + if (currentNode.parent) { + newData = depthFirstSearch(newData, (c) => c.key === currentNode.key); + } else { + const index = newData.findIndex( + (x) => x.key === currentNode.key, + ); + if (index !== -1) { + newData.splice(index, 1); + } + } + setData(newData); + } + }); + }, + onCancel() { + console.log('Cancel'); + }, + }); + }; + + useEffect(() => { + const word = searchValue || ''; + const { tree } = getFilterData(word.toLocaleLowerCase(), data); + setFilterData(tree); + }, [data]); + useEffect(() => { getLogs(); if (treeDom && treeDom.current) { @@ -113,7 +186,7 @@ const Log = () => { title={title} loading={loading} extra={ - isPhone && [ + isPhone ? [ { showSearch onSelect={onSelect} />, + ] : [ + +