mirror of
				https://github.com/whyour/qinglong.git
				synced 2025-10-31 08:56:06 +08:00 
			
		
		
		
	系统日志增加时间筛选和清空
This commit is contained in:
		
							parent
							
								
									f6021c8157
								
							
						
					
					
						commit
						f4cb3eacf8
					
				|  | @ -340,12 +340,41 @@ export default (app: Router) => { | ||||||
|     }, |     }, | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   route.get('/log', async (req: Request, res: Response, next: NextFunction) => { |   route.get( | ||||||
|     try { |     '/log', | ||||||
|       const systemService = Container.get(SystemService); |     celebrate({ | ||||||
|       await systemService.getSystemLog(res); |       query: { | ||||||
|     } catch (e) { |         startTime: Joi.string().allow('').optional(), | ||||||
|       return next(e); |         endTime: Joi.string().allow('').optional(), | ||||||
|     } |         t: Joi.string().optional(), | ||||||
|   }); |       }, | ||||||
|  |     }), | ||||||
|  |     async (req: Request, res: Response, next: NextFunction) => { | ||||||
|  |       try { | ||||||
|  |         const systemService = Container.get(SystemService); | ||||||
|  |         await systemService.getSystemLog( | ||||||
|  |           res, | ||||||
|  |           req.query as { | ||||||
|  |             startTime?: string; | ||||||
|  |             endTime?: string; | ||||||
|  |           }, | ||||||
|  |         ); | ||||||
|  |       } catch (e) { | ||||||
|  |         return next(e); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   route.delete( | ||||||
|  |     '/log', | ||||||
|  |     async (req: Request, res: Response, next: NextFunction) => { | ||||||
|  |       try { | ||||||
|  |         const systemService = Container.get(SystemService); | ||||||
|  |         await systemService.deleteSystemLog(); | ||||||
|  |         res.send({ code: 200 }); | ||||||
|  |       } catch (e) { | ||||||
|  |         return next(e); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ import { | ||||||
|   parseVersion, |   parseVersion, | ||||||
|   promiseExec, |   promiseExec, | ||||||
|   readDirs, |   readDirs, | ||||||
|  |   rmPath, | ||||||
| } from '../config/util'; | } from '../config/util'; | ||||||
| import { | import { | ||||||
|   DependenceModel, |   DependenceModel, | ||||||
|  | @ -34,6 +35,7 @@ import NotificationService from './notify'; | ||||||
| import ScheduleService, { TaskCallbacks } from './schedule'; | import ScheduleService, { TaskCallbacks } from './schedule'; | ||||||
| import SockService from './sock'; | import SockService from './sock'; | ||||||
| import os from 'os'; | import os from 'os'; | ||||||
|  | import dayjs from 'dayjs'; | ||||||
| 
 | 
 | ||||||
| @Service() | @Service() | ||||||
| export default class SystemService { | export default class SystemService { | ||||||
|  | @ -409,9 +411,25 @@ export default class SystemService { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public async getSystemLog(res: Response) { |   public async getSystemLog( | ||||||
|  |     res: Response, | ||||||
|  |     query: { | ||||||
|  |       startTime?: string; | ||||||
|  |       endTime?: string; | ||||||
|  |     }, | ||||||
|  |   ) { | ||||||
|  |     const startTime = dayjs(query.startTime || undefined) | ||||||
|  |       .startOf('d') | ||||||
|  |       .valueOf(); | ||||||
|  |     const endTime = dayjs(query.endTime || undefined) | ||||||
|  |       .endOf('d') | ||||||
|  |       .valueOf(); | ||||||
|     const result = await readDirs(config.systemLogPath, config.systemLogPath); |     const result = await readDirs(config.systemLogPath, config.systemLogPath); | ||||||
|     const logs = result.reverse().filter((x) => x.title.endsWith('.log')); |     const logs = result | ||||||
|  |       .reverse() | ||||||
|  |       .filter((x) => x.title.endsWith('.log')) | ||||||
|  |       .filter((x) => x.mtime >= startTime && x.mtime <= endTime); | ||||||
|  | 
 | ||||||
|     res.set({ |     res.set({ | ||||||
|       'Content-Length': sum(logs.map((x) => x.size)), |       'Content-Length': sum(logs.map((x) => x.size)), | ||||||
|     }); |     }); | ||||||
|  | @ -433,4 +451,12 @@ export default class SystemService { | ||||||
|       } |       } | ||||||
|     })(res, logs); |     })(res, logs); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   public async deleteSystemLog() { | ||||||
|  |     const result = await readDirs(config.systemLogPath, config.systemLogPath); | ||||||
|  |     const logs = result.reverse().filter((x) => x.title.endsWith('.log')); | ||||||
|  |     for (const log of logs) { | ||||||
|  |       await rmPath(path.join(config.systemLogPath, log.title)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -154,6 +154,7 @@ export default class UserService { | ||||||
|             status: LoginStatus.success, |             status: LoginStatus.success, | ||||||
|           }, |           }, | ||||||
|         }); |         }); | ||||||
|  |         this.getLoginLog(); | ||||||
|         return { |         return { | ||||||
|           code: 200, |           code: 200, | ||||||
|           data: { token, lastip, lastaddr, lastlogon, retries, platform }, |           data: { token, lastip, lastaddr, lastlogon, retries, platform }, | ||||||
|  | @ -182,6 +183,7 @@ export default class UserService { | ||||||
|             status: LoginStatus.fail, |             status: LoginStatus.fail, | ||||||
|           }, |           }, | ||||||
|         }); |         }); | ||||||
|  |         this.getLoginLog(); | ||||||
|         if (retries > 2) { |         if (retries > 2) { | ||||||
|           const waitTime = Math.round(Math.pow(3, retries + 1)); |           const waitTime = Math.round(Math.pow(3, retries + 1)); | ||||||
|           return { |           return { | ||||||
|  | @ -215,8 +217,9 @@ export default class UserService { | ||||||
|         (a, b) => b.info!.timestamp! - a.info!.timestamp!, |         (a, b) => b.info!.timestamp! - a.info!.timestamp!, | ||||||
|       ); |       ); | ||||||
|       if (result.length > 100) { |       if (result.length > 100) { | ||||||
|  |         const ids = result.slice(0, result.length - 100).map((x) => x.id!); | ||||||
|         await SystemModel.destroy({ |         await SystemModel.destroy({ | ||||||
|           where: { id: result[result.length - 1].id }, |           where: { id: ids }, | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|       return result.map((x) => x.info); |       return result.map((x) => x.info); | ||||||
|  |  | ||||||
|  | @ -103,6 +103,7 @@ | ||||||
|     "ip2region": "2.3.0" |     "ip2region": "2.3.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|  |     "moment": "2.30.1", | ||||||
|     "@ant-design/icons": "^4.7.0", |     "@ant-design/icons": "^4.7.0", | ||||||
|     "@ant-design/pro-layout": "6.38.22", |     "@ant-design/pro-layout": "6.38.22", | ||||||
|     "@monaco-editor/react": "4.2.1", |     "@monaco-editor/react": "4.2.1", | ||||||
|  |  | ||||||
|  | @ -262,6 +262,9 @@ devDependencies: | ||||||
|   lint-staged: |   lint-staged: | ||||||
|     specifier: ^13.0.3 |     specifier: ^13.0.3 | ||||||
|     version: 13.2.2 |     version: 13.2.2 | ||||||
|  |   moment: | ||||||
|  |     specifier: 2.30.1 | ||||||
|  |     version: 2.30.1 | ||||||
|   monaco-editor: |   monaco-editor: | ||||||
|     specifier: 0.33.0 |     specifier: 0.33.0 | ||||||
|     version: 0.33.0 |     version: 0.33.0 | ||||||
|  | @ -855,7 +858,7 @@ packages: | ||||||
|       '@babel/runtime': 7.23.1 |       '@babel/runtime': 7.23.1 | ||||||
|       antd: 4.24.10(react-dom@18.2.0)(react@18.2.0) |       antd: 4.24.10(react-dom@18.2.0)(react@18.2.0) | ||||||
|       classnames: 2.3.2 |       classnames: 2.3.2 | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|       rc-util: 5.37.0(react-dom@18.2.0)(react@18.2.0) |       rc-util: 5.37.0(react-dom@18.2.0)(react@18.2.0) | ||||||
|       react: 18.2.0 |       react: 18.2.0 | ||||||
|       react-dom: 18.2.0(react@18.2.0) |       react-dom: 18.2.0(react@18.2.0) | ||||||
|  | @ -6263,7 +6266,7 @@ packages: | ||||||
|       fast-deep-equal: 3.1.3 |       fast-deep-equal: 3.1.3 | ||||||
|       intl: 1.2.5 |       intl: 1.2.5 | ||||||
|       lodash: 4.17.21 |       lodash: 4.17.21 | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|       qiankun: 2.10.8 |       qiankun: 2.10.8 | ||||||
|       react-intl: 3.12.1(react@18.2.0) |       react-intl: 3.12.1(react@18.2.0) | ||||||
|       react-redux: 8.0.7(@types/react-dom@18.2.4)(@types/react@18.2.8)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1) |       react-redux: 8.0.7(@types/react-dom@18.2.4)(@types/react@18.2.8)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1) | ||||||
|  | @ -6849,7 +6852,7 @@ packages: | ||||||
|       classnames: 2.3.2 |       classnames: 2.3.2 | ||||||
|       copy-to-clipboard: 3.3.3 |       copy-to-clipboard: 3.3.3 | ||||||
|       lodash: 4.17.21 |       lodash: 4.17.21 | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|       rc-cascader: 3.7.2(react-dom@18.2.0)(react@18.2.0) |       rc-cascader: 3.7.2(react-dom@18.2.0)(react@18.2.0) | ||||||
|       rc-checkbox: 3.0.1(react-dom@18.2.0)(react@18.2.0) |       rc-checkbox: 3.0.1(react-dom@18.2.0)(react@18.2.0) | ||||||
|       rc-collapse: 3.4.2(react-dom@18.2.0)(react@18.2.0) |       rc-collapse: 3.4.2(react-dom@18.2.0)(react@18.2.0) | ||||||
|  | @ -9394,7 +9397,7 @@ packages: | ||||||
|   /file-stream-rotator@0.6.1: |   /file-stream-rotator@0.6.1: | ||||||
|     resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==} |     resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|   /file-uri-to-path@2.0.0: |   /file-uri-to-path@2.0.0: | ||||||
|  | @ -11619,11 +11622,11 @@ packages: | ||||||
|   /moment-timezone@0.5.43: |   /moment-timezone@0.5.43: | ||||||
|     resolution: {integrity: sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==} |     resolution: {integrity: sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|   /moment@2.29.4: |   /moment@2.30.1: | ||||||
|     resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} |     resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} | ||||||
| 
 | 
 | ||||||
|   /monaco-editor@0.33.0: |   /monaco-editor@0.33.0: | ||||||
|     resolution: {integrity: sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==} |     resolution: {integrity: sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==} | ||||||
|  | @ -13757,7 +13760,7 @@ packages: | ||||||
|       classnames: 2.3.2 |       classnames: 2.3.2 | ||||||
|       date-fns: 2.30.0 |       date-fns: 2.30.0 | ||||||
|       dayjs: 1.11.8 |       dayjs: 1.11.8 | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|       rc-trigger: 5.3.4(react-dom@18.2.0)(react@18.2.0) |       rc-trigger: 5.3.4(react-dom@18.2.0)(react@18.2.0) | ||||||
|       rc-util: 5.37.0(react-dom@18.2.0)(react@18.2.0) |       rc-util: 5.37.0(react-dom@18.2.0)(react@18.2.0) | ||||||
|       react: 18.2.0 |       react: 18.2.0 | ||||||
|  | @ -15115,7 +15118,7 @@ packages: | ||||||
|       dottie: 2.0.3 |       dottie: 2.0.3 | ||||||
|       inflection: 1.13.4 |       inflection: 1.13.4 | ||||||
|       lodash: 4.17.21 |       lodash: 4.17.21 | ||||||
|       moment: 2.29.4 |       moment: 2.30.1 | ||||||
|       moment-timezone: 0.5.43 |       moment-timezone: 0.5.43 | ||||||
|       pg-connection-string: 2.6.0 |       pg-connection-string: 2.6.0 | ||||||
|       retry-as-promised: 7.0.4 |       retry-as-promised: 7.0.4 | ||||||
|  |  | ||||||
|  | @ -41,8 +41,8 @@ function run() { | ||||||
|         .replace(/"/g, '\\"') |         .replace(/"/g, '\\"') | ||||||
|         .replace(/\$/g, '\\$'); |         .replace(/\$/g, '\\$'); | ||||||
|       command = `${command} && eval '${escapeTaskBefore}'`; |       command = `${command} && eval '${escapeTaskBefore}'`; | ||||||
|  |       console.log('执行前置命令\n'); | ||||||
|     } |     } | ||||||
|     console.log('执行前置命令\n'); |  | ||||||
|     const res = execSync( |     const res = execSync( | ||||||
|       `${command} && echo -e '${splitStr}' && NODE_OPTIONS= node -p 'JSON.stringify(process.env)'"`, |       `${command} && echo -e '${splitStr}' && NODE_OPTIONS= node -p 'JSON.stringify(process.env)'"`, | ||||||
|       { |       { | ||||||
|  | @ -55,7 +55,9 @@ function run() { | ||||||
|       process.env[key] = newEnvObject[key]; |       process.env[key] = newEnvObject[key]; | ||||||
|     } |     } | ||||||
|     console.log(output); |     console.log(output); | ||||||
|     console.log('执行前置命令结束\n'); |     if (task_before) { | ||||||
|  |       console.log('执行前置命令结束\n'); | ||||||
|  |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     if (!error.message.includes('spawnSync /bin/sh E2BIG')) { |     if (!error.message.includes('spawnSync /bin/sh E2BIG')) { | ||||||
|       console.log(`run task before error: `, error); |       console.log(`run task before error: `, error); | ||||||
|  |  | ||||||
|  | @ -46,11 +46,11 @@ def run(): | ||||||
|         if task_before: |         if task_before: | ||||||
|             escape_task_before = task_before.replace('"', '\\"').replace("$", "\\$") |             escape_task_before = task_before.replace('"', '\\"').replace("$", "\\$") | ||||||
|             command += f" && eval '{escape_task_before}'" |             command += f" && eval '{escape_task_before}'" | ||||||
|  |             print("执行前置命令\n") | ||||||
| 
 | 
 | ||||||
|         python_command = "PYTHONPATH= python3 -c 'import os, json; print(json.dumps(dict(os.environ)))'" |         python_command = "PYTHONPATH= python3 -c 'import os, json; print(json.dumps(dict(os.environ)))'" | ||||||
|         command += f" && echo -e '{split_str}' && {python_command}\"" |         command += f" && echo -e '{split_str}' && {python_command}\"" | ||||||
| 
 | 
 | ||||||
|         print("执行前置命令\n") |  | ||||||
|         res = subprocess.check_output(command, shell=True, encoding="utf-8") |         res = subprocess.check_output(command, shell=True, encoding="utf-8") | ||||||
|         output, env_str = res.split(split_str) |         output, env_str = res.split(split_str) | ||||||
| 
 | 
 | ||||||
|  | @ -60,7 +60,8 @@ def run(): | ||||||
|             os.environ[key] = value |             os.environ[key] = value | ||||||
| 
 | 
 | ||||||
|         print(output) |         print(output) | ||||||
|         print("执行前置命令结束") |         if task_before: | ||||||
|  |             print("执行前置命令结束") | ||||||
| 
 | 
 | ||||||
|     except subprocess.CalledProcessError as error: |     except subprocess.CalledProcessError as error: | ||||||
|         print(f"run task before error: {error}") |         print(f"run task before error: {error}") | ||||||
|  |  | ||||||
|  | @ -462,3 +462,8 @@ body[data-dark='true'] { | ||||||
|     --antd-arrow-background-color: rgb(24, 26, 27); |     --antd-arrow-background-color: rgb(24, 26, 27); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .ant-tabs-content-holder { | ||||||
|  |   flex: 1; | ||||||
|  |   overflow-y: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -124,15 +124,14 @@ const Setting = () => { | ||||||
|   const [editedApp, setEditedApp] = useState<any>(); |   const [editedApp, setEditedApp] = useState<any>(); | ||||||
|   const [tabActiveKey, setTabActiveKey] = useState('security'); |   const [tabActiveKey, setTabActiveKey] = useState('security'); | ||||||
|   const [loginLogData, setLoginLogData] = useState<any[]>([]); |   const [loginLogData, setLoginLogData] = useState<any[]>([]); | ||||||
|   const [systemLogData, setSystemLogData] = useState<string>(''); |  | ||||||
|   const [notificationInfo, setNotificationInfo] = useState<any>(); |   const [notificationInfo, setNotificationInfo] = useState<any>(); | ||||||
|   const containergRef = useRef<HTMLDivElement>(null); |   const containergRef = useRef<HTMLDivElement>(null); | ||||||
|   const [height, setHeight] = useState<number>(0); |   const [height, setHeight] = useState<number>(0); | ||||||
| 
 | 
 | ||||||
|   useResizeObserver(containergRef, (entry) => { |   useResizeObserver(containergRef, (entry) => { | ||||||
|     const _height = entry.target.parentElement?.parentElement?.offsetHeight; |     const _height = entry.target.parentElement?.parentElement?.offsetHeight; | ||||||
|     if (_height && height !== _height - 66) { |     if (_height && height !== _height - 110) { | ||||||
|       setHeight(_height - 66); |       setHeight(_height - 110); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  | @ -253,19 +252,6 @@ const Setting = () => { | ||||||
|       }); |       }); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const getSystemLog = () => { |  | ||||||
|     request |  | ||||||
|       .get<Blob>(`${config.apiPrefix}system/log`, { |  | ||||||
|         responseType: 'blob', |  | ||||||
|       }) |  | ||||||
|       .then(async (res) => { |  | ||||||
|         setSystemLogData(await res.text()); |  | ||||||
|       }) |  | ||||||
|       .catch((error: any) => { |  | ||||||
|         console.log(error); |  | ||||||
|       }); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const tabChange = (activeKey: string) => { |   const tabChange = (activeKey: string) => { | ||||||
|     setTabActiveKey(activeKey); |     setTabActiveKey(activeKey); | ||||||
|     if (activeKey === 'app') { |     if (activeKey === 'app') { | ||||||
|  | @ -274,8 +260,6 @@ const Setting = () => { | ||||||
|       getLoginLog(); |       getLoginLog(); | ||||||
|     } else if (activeKey === 'notification') { |     } else if (activeKey === 'notification') { | ||||||
|       getNotification(); |       getNotification(); | ||||||
|     } else if (activeKey === 'syslog') { |  | ||||||
|       getSystemLog(); |  | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | @ -315,12 +299,14 @@ const Setting = () => { | ||||||
|           : [] |           : [] | ||||||
|       } |       } | ||||||
|     > |     > | ||||||
|       <div ref={containergRef}> |       <div ref={containergRef} style={{ height: '100%' }}> | ||||||
|         <Tabs |         <Tabs | ||||||
|  |           style={{ height: '100%' }} | ||||||
|           defaultActiveKey="security" |           defaultActiveKey="security" | ||||||
|           size="small" |           size="small" | ||||||
|           tabPosition="top" |           tabPosition="top" | ||||||
|           onChange={tabChange} |           onChange={tabChange} | ||||||
|  |           destroyInactiveTabPane | ||||||
|           items={[ |           items={[ | ||||||
|             ...(!isDemoEnv |             ...(!isDemoEnv | ||||||
|               ? [ |               ? [ | ||||||
|  | @ -356,9 +342,7 @@ const Setting = () => { | ||||||
|             { |             { | ||||||
|               key: 'syslog', |               key: 'syslog', | ||||||
|               label: intl.get('系统日志'), |               label: intl.get('系统日志'), | ||||||
|               children: ( |               children: <SystemLog height={height} theme={theme} />, | ||||||
|                 <SystemLog data={systemLogData} height={height} theme={theme} /> |  | ||||||
|               ), |  | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|               key: 'login', |               key: 'login', | ||||||
|  | @ -383,7 +367,7 @@ const Setting = () => { | ||||||
|               children: <About systemInfo={systemInfo} />, |               children: <About systemInfo={systemInfo} />, | ||||||
|             }, |             }, | ||||||
|           ]} |           ]} | ||||||
|         ></Tabs> |         /> | ||||||
|       </div> |       </div> | ||||||
|       <AppModal |       <AppModal | ||||||
|         visible={isModalVisible} |         visible={isModalVisible} | ||||||
|  |  | ||||||
|  | @ -1,13 +1,39 @@ | ||||||
| import React, { useRef } from 'react'; | import React, { useRef, useState } from 'react'; | ||||||
| import CodeMirror from '@uiw/react-codemirror'; | import CodeMirror from '@uiw/react-codemirror'; | ||||||
| import { Button } from 'antd'; | import { Button, DatePicker, Empty, message, Spin } from 'antd'; | ||||||
| import { | import { | ||||||
|   VerticalAlignBottomOutlined, |   VerticalAlignBottomOutlined, | ||||||
|   VerticalAlignTopOutlined, |   VerticalAlignTopOutlined, | ||||||
| } from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||||
|  | import { request } from '@/utils/http'; | ||||||
|  | import config from '@/utils/config'; | ||||||
|  | import { useRequest } from 'ahooks'; | ||||||
|  | import moment from 'moment'; | ||||||
| 
 | 
 | ||||||
| const SystemLog = ({ data, height, theme }: any) => { | const { RangePicker } = DatePicker; | ||||||
|  | 
 | ||||||
|  | const SystemLog = ({ height, theme }: any) => { | ||||||
|   const editorRef = useRef<any>(null); |   const editorRef = useRef<any>(null); | ||||||
|  |   const panelVisiableRef = useRef<[string, string] | false>(); | ||||||
|  |   const [range, setRange] = useState<string[]>(['', '']); | ||||||
|  |   const [systemLogData, setSystemLogData] = useState<string>(''); | ||||||
|  | 
 | ||||||
|  |   const { loading, refresh } = useRequest( | ||||||
|  |     () => { | ||||||
|  |       return request.get<Blob>( | ||||||
|  |         `${config.apiPrefix}system/log?startTime=${range[0]}&endTime=${range[1]}`, | ||||||
|  |         { | ||||||
|  |           responseType: 'blob', | ||||||
|  |         }, | ||||||
|  |       ); | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       refreshDeps: [range], | ||||||
|  |       async onSuccess(res) { | ||||||
|  |         setSystemLogData(await res.text()); | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ); | ||||||
| 
 | 
 | ||||||
|   const scrollTo = (position: 'start' | 'end') => { |   const scrollTo = (position: 'start' | 'end') => { | ||||||
|     editorRef.current.scrollDOM.scrollTo({ |     editorRef.current.scrollDOM.scrollTo({ | ||||||
|  | @ -15,42 +41,93 @@ const SystemLog = ({ data, height, theme }: any) => { | ||||||
|     }); |     }); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   const deleteLog = () => { | ||||||
|  |     request.delete(`${config.apiPrefix}system/log`).then((x) => { | ||||||
|  |       message.success('删除成功'); | ||||||
|  |       refresh(); | ||||||
|  |     }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div style={{ position: 'relative' }}> |     <div style={{ position: 'relative' }}> | ||||||
|       <CodeMirror |       <div> | ||||||
|         maxHeight={`${height}px`} |         <RangePicker | ||||||
|         value={data} |           style={{ marginBottom: 12, marginRight: 12 }} | ||||||
|         onCreateEditor={(view) => { |           disabledDate={(date) => | ||||||
|           editorRef.current = view; |             date > moment() || date < moment().subtract(7, 'days') | ||||||
|         }} |           } | ||||||
|         readOnly={true} |           defaultValue={[moment(), moment()]} | ||||||
|         theme={theme.includes('dark') ? 'dark' : 'light'} |           onOpenChange={(v) => { | ||||||
|       /> |             panelVisiableRef.current = v ? ['', ''] : false; | ||||||
|       <div |           }} | ||||||
|         style={{ |           onCalendarChange={(_, dates, { range }) => { | ||||||
|           position: 'absolute', |             if ( | ||||||
|           bottom: 20, |               !panelVisiableRef.current || | ||||||
|           right: 20, |               typeof panelVisiableRef.current === 'boolean' | ||||||
|           display: 'flex', |             ) { | ||||||
|           flexDirection: 'column', |               return; | ||||||
|           gap: 10, |             } | ||||||
|         }} |             if (range === 'start') { | ||||||
|       > |               panelVisiableRef.current[0] = dates[0]; | ||||||
|         <Button |             } | ||||||
|           size='small' |             if (range === 'end') { | ||||||
|           icon={<VerticalAlignTopOutlined />} |               panelVisiableRef.current[1] = dates[1]; | ||||||
|           onClick={() => { |             } | ||||||
|             scrollTo('start'); |             if (panelVisiableRef.current[0] && panelVisiableRef.current[1]) { | ||||||
|  |               setRange(dates); | ||||||
|  |             } | ||||||
|           }} |           }} | ||||||
|         /> |         /> | ||||||
|         <Button |         <Button | ||||||
|           size='small' |  | ||||||
|           icon={<VerticalAlignBottomOutlined />} |  | ||||||
|           onClick={() => { |           onClick={() => { | ||||||
|             scrollTo('end'); |             deleteLog(); | ||||||
|           }} |           }} | ||||||
|         /> |         > | ||||||
|  |           清空日志 | ||||||
|  |         </Button> | ||||||
|       </div> |       </div> | ||||||
|  |       {systemLogData ? ( | ||||||
|  |         <> | ||||||
|  |           <CodeMirror | ||||||
|  |             maxHeight={`${height}px`} | ||||||
|  |             value={systemLogData} | ||||||
|  |             onCreateEditor={(view) => { | ||||||
|  |               editorRef.current = view; | ||||||
|  |             }} | ||||||
|  |             readOnly={true} | ||||||
|  |             theme={theme.includes('dark') ? 'dark' : 'light'} | ||||||
|  |           /> | ||||||
|  |           <div | ||||||
|  |             style={{ | ||||||
|  |               position: 'absolute', | ||||||
|  |               bottom: 20, | ||||||
|  |               right: 20, | ||||||
|  |               display: 'flex', | ||||||
|  |               flexDirection: 'column', | ||||||
|  |               gap: 10, | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             <Button | ||||||
|  |               size="small" | ||||||
|  |               icon={<VerticalAlignTopOutlined />} | ||||||
|  |               onClick={() => { | ||||||
|  |                 scrollTo('start'); | ||||||
|  |               }} | ||||||
|  |             /> | ||||||
|  |             <Button | ||||||
|  |               size="small" | ||||||
|  |               icon={<VerticalAlignBottomOutlined />} | ||||||
|  |               onClick={() => { | ||||||
|  |                 scrollTo('end'); | ||||||
|  |               }} | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
|  |         </> | ||||||
|  |       ) : loading ? ( | ||||||
|  |         <Spin /> | ||||||
|  |       ) : ( | ||||||
|  |         <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> | ||||||
|  |       )} | ||||||
|     </div> |     </div> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 whyour
						whyour