mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36: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(
|
||||||
|
'/log',
|
||||||
|
celebrate({
|
||||||
|
query: {
|
||||||
|
startTime: Joi.string().allow('').optional(),
|
||||||
|
endTime: Joi.string().allow('').optional(),
|
||||||
|
t: Joi.string().optional(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const systemService = Container.get(SystemService);
|
const systemService = Container.get(SystemService);
|
||||||
await systemService.getSystemLog(res);
|
await systemService.getSystemLog(
|
||||||
|
res,
|
||||||
|
req.query as {
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
},
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return next(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);
|
||||||
|
if (task_before) {
|
||||||
console.log('执行前置命令结束\n');
|
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,6 +60,7 @@ def run():
|
||||||
os.environ[key] = value
|
os.environ[key] = value
|
||||||
|
|
||||||
print(output)
|
print(output)
|
||||||
|
if task_before:
|
||||||
print("执行前置命令结束")
|
print("执行前置命令结束")
|
||||||
|
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as 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,11 +41,56 @@ 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' }}>
|
||||||
|
<div>
|
||||||
|
<RangePicker
|
||||||
|
style={{ marginBottom: 12, marginRight: 12 }}
|
||||||
|
disabledDate={(date) =>
|
||||||
|
date > moment() || date < moment().subtract(7, 'days')
|
||||||
|
}
|
||||||
|
defaultValue={[moment(), moment()]}
|
||||||
|
onOpenChange={(v) => {
|
||||||
|
panelVisiableRef.current = v ? ['', ''] : false;
|
||||||
|
}}
|
||||||
|
onCalendarChange={(_, dates, { range }) => {
|
||||||
|
if (
|
||||||
|
!panelVisiableRef.current ||
|
||||||
|
typeof panelVisiableRef.current === 'boolean'
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (range === 'start') {
|
||||||
|
panelVisiableRef.current[0] = dates[0];
|
||||||
|
}
|
||||||
|
if (range === 'end') {
|
||||||
|
panelVisiableRef.current[1] = dates[1];
|
||||||
|
}
|
||||||
|
if (panelVisiableRef.current[0] && panelVisiableRef.current[1]) {
|
||||||
|
setRange(dates);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
deleteLog();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
清空日志
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{systemLogData ? (
|
||||||
|
<>
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
maxHeight={`${height}px`}
|
maxHeight={`${height}px`}
|
||||||
value={data}
|
value={systemLogData}
|
||||||
onCreateEditor={(view) => {
|
onCreateEditor={(view) => {
|
||||||
editorRef.current = view;
|
editorRef.current = view;
|
||||||
}}
|
}}
|
||||||
|
@ -37,20 +108,26 @@ const SystemLog = ({ data, height, theme }: any) => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
size='small'
|
size="small"
|
||||||
icon={<VerticalAlignTopOutlined />}
|
icon={<VerticalAlignTopOutlined />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
scrollTo('start');
|
scrollTo('start');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
size='small'
|
size="small"
|
||||||
icon={<VerticalAlignBottomOutlined />}
|
icon={<VerticalAlignBottomOutlined />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
scrollTo('end');
|
scrollTo('end');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
) : loading ? (
|
||||||
|
<Spin />
|
||||||
|
) : (
|
||||||
|
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user