mirror of
https://github.com/whyour/qinglong.git
synced 2026-07-17 01:14:50 +08:00
增加登录日志
This commit is contained in:
Vendored
+1
-1
@@ -280,7 +280,7 @@ const Env = ({ headerStyle, isPhone, theme }: any) => {
|
||||
<>
|
||||
确认删除变量{' '}
|
||||
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
||||
{record.value}
|
||||
{record.name}: {record.value}
|
||||
</Text>{' '}
|
||||
吗
|
||||
</>
|
||||
|
||||
@@ -15,7 +15,6 @@ import { request } from '@/utils/http';
|
||||
import styles from './index.module.less';
|
||||
import EditModal from './editModal';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { useCtx, useTheme } from '@/utils/hooks';
|
||||
import SplitPane from 'react-split-pane';
|
||||
|
||||
const { Text } = Typography;
|
||||
@@ -82,9 +81,29 @@ const Script = ({ headerStyle, isPhone, theme }: any) => {
|
||||
getDetail(node);
|
||||
};
|
||||
|
||||
const onTreeSelect = useCallback((keys: Key[], e: any) => {
|
||||
onSelect(keys[0], e.node);
|
||||
}, []);
|
||||
const onTreeSelect = useCallback(
|
||||
(keys: Key[], e: any) => {
|
||||
const content = editorRef.current
|
||||
? editorRef.current.getValue().replace(/\r\n/g, '\n')
|
||||
: value;
|
||||
if (content !== value) {
|
||||
Modal.confirm({
|
||||
title: `确认离开`,
|
||||
content: <>当前修改未保存,确定离开吗</>,
|
||||
onOk() {
|
||||
onSelect(keys[0], e.node);
|
||||
setIsEditing(false);
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
} else {
|
||||
onSelect(keys[0], e.node);
|
||||
}
|
||||
},
|
||||
[value],
|
||||
);
|
||||
|
||||
const onSearch = useCallback(
|
||||
(e) => {
|
||||
@@ -132,6 +151,7 @@ const Script = ({ headerStyle, isPhone, theme }: any) => {
|
||||
.then((_data: any) => {
|
||||
if (_data.code === 200) {
|
||||
message.success(`保存成功`);
|
||||
setValue(content);
|
||||
setIsEditing(false);
|
||||
} else {
|
||||
message.error(_data);
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
ReloadOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import SecuritySettings from './security';
|
||||
import LoginLog from './loginLog';
|
||||
|
||||
const { Text } = Typography;
|
||||
const optionsWithDisabled = [
|
||||
@@ -37,7 +38,7 @@ const optionsWithDisabled = [
|
||||
{ label: '跟随系统', value: 'auto' },
|
||||
];
|
||||
|
||||
const Setting = ({ headerStyle, isPhone, user }: any) => {
|
||||
const Setting = ({ headerStyle, isPhone, user, reloadUser }: any) => {
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
@@ -110,6 +111,7 @@ const Setting = ({ headerStyle, isPhone, user }: any) => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [editedApp, setEditedApp] = useState();
|
||||
const [tabActiveKey, setTabActiveKey] = useState('security');
|
||||
const [loginLogData, setLoginLogData] = useState<any[]>([]);
|
||||
|
||||
const themeChange = (e: any) => {
|
||||
setTheme(e.target.value);
|
||||
@@ -219,10 +221,23 @@ const Setting = ({ headerStyle, isPhone, user }: any) => {
|
||||
setDataSource(result);
|
||||
};
|
||||
|
||||
const getLoginLog = () => {
|
||||
request
|
||||
.get(`${config.apiPrefix}user/login-log`)
|
||||
.then((data: any) => {
|
||||
setLoginLogData(data.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const tabChange = (activeKey: string) => {
|
||||
setTabActiveKey(activeKey);
|
||||
if (activeKey === 'app') {
|
||||
getApps();
|
||||
} else if (activeKey === 'login') {
|
||||
getLoginLog();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -261,7 +276,7 @@ const Setting = ({ headerStyle, isPhone, user }: any) => {
|
||||
onChange={tabChange}
|
||||
>
|
||||
<Tabs.TabPane tab="安全设置" key="security">
|
||||
<SecuritySettings user={user} />
|
||||
<SecuritySettings user={user} userChange={reloadUser} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="应用设置" key="app">
|
||||
<Table
|
||||
@@ -274,6 +289,9 @@ const Setting = ({ headerStyle, isPhone, user }: any) => {
|
||||
loading={loading}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="登陆日志" key="login">
|
||||
<LoginLog data={loginLogData} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="其他设置" key="theme">
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="主题设置" name="theme" initialValue={theme}>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Typography, Table, Tag, Button, Spin, message } from 'antd';
|
||||
import { request } from '@/utils/http';
|
||||
import config from '@/utils/config';
|
||||
|
||||
const { Text, Link } = Typography;
|
||||
|
||||
enum LoginStatus {
|
||||
'成功',
|
||||
'失败',
|
||||
}
|
||||
|
||||
enum LoginStatusColor {
|
||||
'success',
|
||||
'error',
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
align: 'center' as const,
|
||||
width: 50,
|
||||
render: (text: string, record: any, index: number) => {
|
||||
return <span style={{ cursor: 'text' }}>{index + 1} </span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
dataIndex: 'timestamp',
|
||||
key: 'timestamp',
|
||||
align: 'center' as const,
|
||||
render: (text: string, record: any) => {
|
||||
return <span>{new Date(record.timestamp).toLocaleString()}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '地址',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
align: 'center' as const,
|
||||
},
|
||||
{
|
||||
title: 'IP',
|
||||
dataIndex: 'ip',
|
||||
key: 'ip',
|
||||
align: 'center' as const,
|
||||
},
|
||||
{
|
||||
title: '登陆状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
align: 'center' as const,
|
||||
render: (text: string, record: any) => {
|
||||
return (
|
||||
<Tag color={LoginStatusColor[record.status]} style={{ marginRight: 0 }}>
|
||||
{LoginStatus[record.status]}
|
||||
</Tag>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const LoginLog = ({ data }: any) => {
|
||||
return (
|
||||
<>
|
||||
<Table
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
dataSource={data}
|
||||
rowKey="_id"
|
||||
size="middle"
|
||||
scroll={{ x: 768 }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginLog;
|
||||
@@ -7,7 +7,7 @@ import QRCode from 'qrcode.react';
|
||||
|
||||
const { Title, Link } = Typography;
|
||||
|
||||
const SecuritySettings = ({ user }: any) => {
|
||||
const SecuritySettings = ({ user, userChange }: any) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [twoFactorActived, setTwoFactorActived] = useState<boolean>();
|
||||
const [twoFactoring, setTwoFactoring] = useState(false);
|
||||
@@ -46,6 +46,7 @@ const SecuritySettings = ({ user }: any) => {
|
||||
.then((data: any) => {
|
||||
if (data.data) {
|
||||
setTwoFactorActived(false);
|
||||
userChange();
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
@@ -61,6 +62,7 @@ const SecuritySettings = ({ user }: any) => {
|
||||
message.success('激活成功');
|
||||
setTwoFactoring(false);
|
||||
setTwoFactorActived(true);
|
||||
userChange();
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
|
||||
Reference in New Issue
Block a user