diff --git a/web/src/components/session/LoginLog.js b/web/src/components/session/LoginLog.js
new file mode 100644
index 0000000..021bf3d
--- /dev/null
+++ b/web/src/components/session/LoginLog.js
@@ -0,0 +1,399 @@
+import React, {Component} from 'react';
+
+import {
+ Button,
+ Col,
+ Divider,
+ Input,
+ Layout,
+ Modal,
+ notification,
+ PageHeader,
+ Row,
+ Select,
+ Space,
+ Table,
+ Tooltip,
+ Typography
+} from "antd";
+import qs from "qs";
+import request from "../../common/request";
+import {formatDate, isEmpty, itemRender} from "../../utils/utils";
+import {message} from "antd/es";
+import {DeleteOutlined, ExclamationCircleOutlined, SyncOutlined, UndoOutlined} from "@ant-design/icons";
+import Logout from "../user/Logout";
+
+const confirm = Modal.confirm;
+const {Content} = Layout;
+const {Search} = Input;
+const {Title, Text} = Typography;
+const routes = [
+ {
+ path: '',
+ breadcrumbName: '首页',
+ },
+ {
+ path: 'loginLog',
+ breadcrumbName: '登录日志',
+ }
+];
+
+class LoginLog extends Component {
+
+ inputRefOfClientIp = React.createRef();
+
+ state = {
+ items: [],
+ total: 0,
+ queryParams: {
+ pageIndex: 1,
+ pageSize: 10,
+ userId: undefined,
+ },
+ loading: false,
+ selectedRowKeys: [],
+ delBtnLoading: false,
+ users: [],
+ };
+
+ componentDidMount() {
+ this.loadTableData();
+ this.handleSearchByNickname('');
+ }
+
+ async loadTableData(queryParams) {
+ queryParams = queryParams || this.state.queryParams;
+
+ this.setState({
+ queryParams: queryParams,
+ loading: true
+ });
+
+ // queryParams
+ let paramsStr = qs.stringify(queryParams);
+
+ let data = {
+ items: [],
+ total: 0
+ };
+
+ try {
+ let result = await request.get('/login-logs/paging?' + paramsStr);
+ if (result.code === 1) {
+ data = result.data;
+ } else {
+ message.error(result.message);
+ }
+ } catch (e) {
+
+ } finally {
+ const items = data.items.map(item => {
+ return {'key': item['id'], ...item}
+ })
+ this.setState({
+ items: items,
+ total: data.total,
+ queryParams: queryParams,
+ loading: false
+ });
+ }
+ }
+
+ handleChangPage = (pageIndex, pageSize) => {
+ let queryParams = this.state.queryParams;
+ queryParams.pageIndex = pageIndex;
+ queryParams.pageSize = pageSize;
+
+ this.setState({
+ queryParams: queryParams
+ });
+
+ this.loadTableData(queryParams)
+ };
+
+ handleSearchByClientIp = clientIp => {
+ let query = {
+ ...this.state.queryParams,
+ 'pageIndex': 1,
+ 'pageSize': this.state.queryParams.pageSize,
+ 'clientIp': clientIp,
+ }
+ this.loadTableData(query);
+ }
+
+ handleChangeByProtocol = protocol => {
+ let query = {
+ ...this.state.queryParams,
+ 'pageIndex': 1,
+ 'pageSize': this.state.queryParams.pageSize,
+ 'protocol': protocol,
+ }
+ this.loadTableData(query);
+ }
+
+ handleSearchByNickname = async nickname => {
+ const result = await request.get(`/users/paging?pageIndex=1&pageSize=1000&nickname=${nickname}`);
+ if (result.code !== 1) {
+ message.error(result.message, 10);
+ return;
+ }
+
+ this.setState({
+ users: result.data.items
+ })
+ }
+
+ handleChangeByUserId = userId => {
+ let query = {
+ ...this.state.queryParams,
+ 'pageIndex': 1,
+ 'pageSize': this.state.queryParams.pageSize,
+ 'userId': userId,
+ }
+ this.loadTableData(query);
+ }
+
+ batchDelete = async () => {
+ this.setState({
+ delBtnLoading: true
+ })
+ try {
+ let result = await request.delete('/login-logs/' + this.state.selectedRowKeys.join(','));
+ if (result.code === 1) {
+ message.success('操作成功', 3);
+ this.setState({
+ selectedRowKeys: []
+ })
+ await this.loadTableData(this.state.queryParams);
+ } else {
+ message.error('删除失败 :( ' + result.message, 10);
+ }
+ } finally {
+ this.setState({
+ delBtnLoading: false
+ })
+ }
+ }
+
+ render() {
+
+ const columns = [{
+ title: '序号',
+ dataIndex: 'id',
+ key: 'id',
+ render: (id, record, index) => {
+ return index + 1;
+ }
+ }, {
+ title: '用户昵称',
+ dataIndex: 'userName',
+ key: 'userName'
+ }, {
+ title: '来源IP',
+ dataIndex: 'clientIp',
+ key: 'clientIp'
+ }, {
+ title: '浏览器',
+ dataIndex: 'clientUserAgent',
+ key: 'clientUserAgent',
+ render: (text, record) => {
+ if (isEmpty(text)) {
+ return '未知';
+ }
+ return (
+
+ {text.split(' ')[0]}
+
+ )
+ }
+ }, {
+ title: '登录时间',
+ dataIndex: 'loginTime',
+ key: 'loginTime',
+ render: (text, record) => {
+
+ return formatDate(text, 'yyyy-MM-dd hh:mm:ss');
+ }
+ }, {
+ title: '注销时间',
+ dataIndex: 'logoutTime',
+ key: 'logoutTime',
+ render: (text, record) => {
+ if (isEmpty(text) || text === '0001-01-01 00:00:00') {
+ return '';
+ }
+ return text;
+ }
+ },
+ {
+ title: '操作',
+ key: 'action',
+ render: (text, record) => {
+ return (
+
+
+
+ )
+ },
+ }
+ ];
+
+ const selectedRowKeys = this.state.selectedRowKeys;
+ const rowSelection = {
+ selectedRowKeys: this.state.selectedRowKeys,
+ onChange: (selectedRowKeys, selectedRows) => {
+ this.setState({selectedRowKeys});
+ },
+ };
+ const hasSelected = selectedRowKeys.length > 0;
+
+ const userOptions = this.state.users.map(d => {d.nickname});
+
+ return (
+ <>
+
+ ]}
+ subTitle="只有登录成功的才会保存日志"
+ >
+
+
+
+
+
+
+ 登录日志列表
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `总计 ${total} 条`
+ }}
+ loading={this.state.loading}
+ />
+
+ >
+ );
+ }
+}
+
+export default LoginLog;
diff --git a/web/src/components/session/OfflineSession.js b/web/src/components/session/OfflineSession.js
index 9b88168..35b6912 100644
--- a/web/src/components/session/OfflineSession.js
+++ b/web/src/components/session/OfflineSession.js
@@ -474,20 +474,24 @@ class OfflineSession extends Component {
loading={this.state.loading}
/>
-
+
+ : undefined
+ }
- width={window.innerWidth * 0.8}
- footer={null}
- destroyOnClose
- maskClosable={false}
- >
-
-
>
);
diff --git a/web/src/components/session/Playback.js b/web/src/components/session/Playback.js
index bb82e42..fc7899b 100644
--- a/web/src/components/session/Playback.js
+++ b/web/src/components/session/Playback.js
@@ -142,7 +142,9 @@ class Playback extends Component {
this.setState({
recording: recording
- })
+ }, () => {
+ this.handlePlayPause();
+ });
}
handlePlayPause = () => {
@@ -150,7 +152,6 @@ class Playback extends Component {
if (recording) {
if (this.state.percent === this.state.max) {
// 重播
- console.log('重新播放')
this.setState({
percent: 0
}, () => {