import intl from 'react-intl-universal'; 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 CodeMirror from '@uiw/react-codemirror'; 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(intl.get('请选择日志文件')); const [select, setSelect] = useState(intl.get('请选择日志文件')); 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(intl.get('请选择日志文件')); return; } setValue(intl.get('加载中...')); 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: ( <> {intl.get('确认删除')} {select} {intl.get('文件')} {currentNode.type === 'directory' ? intl.get('夹下所以日志') : ''} {intl.get(',删除后不可恢复')} ), 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(intl.get('请选择脚本文件')); }; const onExpand = (expKeys: any) => { setExpandedKeys(expKeys); }; useEffect(() => { getLogs(); }, []); useEffect(() => { if (treeDom.current) { setHeight(treeDom.current.clientHeight); } }, [treeDom.current, data]); return ( {select} {currentNode?.type === 'file' && ( {(currentNode.size / 1024).toFixed(3)}KB )} } loading={loading} extra={ isPhone ? [ , ] : [