import { useState, useEffect, useCallback, Key, useRef } from 'react'; 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'; import { request } from '@/utils/http'; import styles from './index.module.less'; 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/debounce'; import uniq from 'lodash/uniq'; import useFilterTreeData from '@/hooks/useFilterTreeData'; const { Text } = Typography; const Log = () => { const { headerStyle, isPhone, theme } = useOutletContext(); const [value, setValue] = useState('请选择日志文件'); const [select, setSelect] = useState(''); const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [height, setHeight] = useState(); const treeDom = useRef(); const [expandedKeys, setExpandedKeys] = useState([]); const [currentNode, setCurrentNode] = useState(); const [searchValue, setSearchValue] = useState(''); const getLogs = () => { setLoading(true); request .get(`${config.apiPrefix}logs`) .then(({ code, data }) => { if (code === 200) { setData(data); } }) .finally(() => setLoading(false)); }; const getLog = (node: any) => { request .get(`${config.apiPrefix}logs/${node.title}?path=${node.parent || ''}`) .then(({ code, data }) => { if (code === 200) { setValue(data); } }); }; const onSelect = (value: any, node: any) => { setCurrentNode(node); setSelect(value); if (node.key === select || !value) { return; } if (node.type === 'directory') { setValue('请选择日志文件'); return; } setValue('加载中...'); getLog(node); }; const onTreeSelect = useCallback((keys: Key[], e: any) => { onSelect(keys[0], e.node); }, []); const onSearch = useCallback( (e) => { const keyword = e.target.value; debounceSearch(keyword); }, [data], ); const debounceSearch = useCallback( debounce((keyword) => { setSearchValue(keyword); }, 300), [data], ); const { treeData: filterData, keys: searchExpandedKeys } = useFilterTreeData( data, searchValue, { treeNodeFilterProp: 'title' }, ); useEffect(() => { setExpandedKeys(uniq([...expandedKeys, ...searchExpandedKeys])); }, [searchExpandedKeys]); 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); initState(); } }); }, onCancel() { console.log('Cancel'); }, }); }; const initState = () => { setSelect(''); setCurrentNode(null); setValue('请选择脚本文件'); }; const onExpand = (expKeys: any) => { setExpandedKeys(expKeys); }; useEffect(() => { getLogs(); }, []); useEffect(() => { if (treeDom.current) { setHeight(treeDom.current.clientHeight); } }, [treeDom.current, data]); return ( , ] : [