/* eslint-disable no-lonely-if */ /* eslint-disable no-else-return */ /* eslint-disable no-unneeded-ternary */ import React, { useState, useEffect, useRef } from 'react'; import { DatePicker, Input, Table, Row, Col, Button, notification, message, Tooltip, Spin, Pagination, Select, Tag, Modal, Tabs, } from 'antd'; import { CalculatorFilled, SwapRightOutlined, SyncOutlined, InfoCircleOutlined, } from '@ant-design/icons'; import moment from 'moment'; import 'moment/dist/locale/zh-cn'; import locale from 'antd/es/date-picker/locale/zh_CN'; import styles from './index.less'; import { GetCallLogPages, GetWayNumberofcalls, GetAccessLog, GetRemoteOperationLog, } from '@/services/logCenter/api'; import { GetWayPages } from '@/services/homePage/api'; const { RangePicker } = DatePicker; const { Option } = Select; const { TabPane } = Tabs; const LogCenter = () => { const [loading, setLoading] = useState(false); // 源数据 const [loading1, setLoading1] = useState(false); // 源数据 const [loadingAccess, setLoadingAccess] = useState(false); // 源数据 const [loadingRemote, setLoadingRemote] = useState(false); // 源数据 const [requestUrl, setRequestUrl] = useState(''); // 接口名称筛选 const [label, setLabel] = useState(''); // 标签筛选 const [allTime, setAllTime] = useState([ moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss'), ]); const [showSearchStyle, setShowSearchStyle] = useState(false); // 是否显示模糊查询样式 const [total, setTotal] = useState(0); const [pageSize, setPageSize] = useState(20); const [currentPage, setCurrentPage] = useState(1); const [total1, setTotal1] = useState(0); const [pageSize1, setPageSize1] = useState(10); const [currentPage1, setCurrentPage1] = useState(1); const [loginCodeFilters, setLoginCodeFilters] = useState([]); const [loginStateCodeFilters, setLoginStateCodeFilters] = useState([]); const [content, setContent] = useState(); const [modalVisible, setModalVisible] = useState(false); const [tableData, setTableData] = useState([]); const [tableData1, setTableData1] = useState([]); const [tableDataAccess, setTableDataAccess] = useState([]); const [tableDataRemote, setTableDataRemote] = useState([]); const [selectState, setSelectState] = useState('失败'); const timeSorter = useRef('desc'); const filterSorter = useRef('requestDate'); const [activeKey, setActiveKey] = useState('1'); const [totalAccess, setTotalAccess] = useState(0); const [pageSizeAccess, setPageSizeAccess] = useState(20); const [currentPageAccess, setCurrentPageAccess] = useState(1); const [totalRemote, setTotalRemote] = useState(0); const [pageSizeRemote, setPageSizeRemote] = useState(20); const [currentPageRemote, setCurrentPageRemote] = useState(1); useEffect(() => { getTableList(); getApiCount(); }, []); const getTableList = (pageIndex, page, time, url, tag, success, flag) => { setLoading(true); let successState = ''; if (success) { if (success === '成功') { successState = 0; } else if (success === '警告') { successState = -1; } else if (success === '失败') { successState = -2; } else if (success === '全部') { successState = null; } } else { if (selectState === '全部') { successState = null; } else if (selectState === '成功') { successState = 0; } else if (selectState === '警告') { successState = -1; } else if (selectState === '失败') { successState = -2; } } let newUrl = url ? url : requestUrl; GetWayPages({ pageIndex: pageIndex ? pageIndex : currentPage, pageSize: page ? page : pageSize, dateFrom: time ? time[0].format('YYYY-MM-DD HH:mm:ss') : allTime[0].format('YYYY-MM-DD HH:mm:ss'), dateTo: time ? time[1].format('YYYY-MM-DD HH:mm:ss') : allTime[1].format('YYYY-MM-DD HH:mm:ss'), info: flag ? '' : newUrl, methodType: 0, sortFieldsAndDirection: `${filterSorter.current} ${timeSorter.current}`, state: successState, }).then(res => { setLoading(false); if (res.code === 0) { setTableData(res.data.listData.list); setTotal(res.data.listData.totalCount); setLoginCodeFilters([{ text: '成功', value: 1 }, { text: '失败', value: 0 }]); let arr2 = res.data.listData.list.map(item => item.result); arr2 = arr2.filter((value, index) => arr2.indexOf(value) === index); setLoginStateCodeFilters(arr2.map(item => ({ text: item, value: item }))); } else { setTableData([]); notification.error({ message: '提示', duration: 3, description: res.msg, }); } }); }; const getApiCount = (pageIndex, page, time, url, flag) => { setLoading1(true); let newUrl = url ? url : requestUrl; GetWayNumberofcalls({ pageIndex: pageIndex ? pageIndex : currentPage1, pageSize: page ? page : pageSize1, dateFrom: time ? time[0].format('YYYY-MM-DD HH:mm:ss') : allTime[0].format('YYYY-MM-DD HH:mm:ss'), dateTo: time ? time[1].format('YYYY-MM-DD HH:mm:ss') : allTime[1].format('YYYY-MM-DD HH:mm:ss'), info: flag ? '' : newUrl, }).then(resData => { setLoading1(false); if (resData.code === 0) { setTableData1(resData.data.listdata); setTotal1(resData.data.listcount); } else { setTableData1([]); notification.error({ message: '提示', duration: 3, description: resData.msg, }); } }); }; const getAccessLog = (pageIndex, page, time, word, flag) => { setLoadingAccess(true); let newUrl = word ? word : requestUrl; GetAccessLog({ keyword: flag ? '' : newUrl, dateFrom: time ? time[0].format('YYYY-MM-DD HH:mm:ss') : allTime[0].format('YYYY-MM-DD HH:mm:ss'), dateTo: time ? time[1].format('YYYY-MM-DD HH:mm:ss') : allTime[1].format('YYYY-MM-DD HH:mm:ss'), pageIndex: pageIndex ? pageIndex : currentPageAccess, pageSize: page ? page : pageSizeAccess, }).then(res => { setLoadingAccess(false); if (res.code === 0) { setTableDataAccess(res.data.data); setTotalAccess(res.data.count); } else { setTableDataAccess([]); notification.error({ message: '提示', duration: 3, description: res.msg, }); } }); }; const getRemoteOperationLog = (pageIndex, page, time, code) => { setLoadingRemote(true); GetRemoteOperationLog({ deviceCode: code ? code : requestUrl, dateFrom: time ? time[0].format('YYYY-MM-DD HH:mm:ss') : allTime[0].format('YYYY-MM-DD HH:mm:ss'), dateTo: time ? time[1].format('YYYY-MM-DD HH:mm:ss') : allTime[1].format('YYYY-MM-DD HH:mm:ss'), pageIndex: pageIndex ? pageIndex : currentPageRemote, pageSize: page ? page : pageSizeRemote, }).then(res => { setLoadingRemote(false); if (res.code === 0) { setTableDataRemote(res.data.list); setTotalRemote(res.data.totalCount); } else { setTableDataRemote([]); notification.error({ message: '提示', duration: 3, description: res.msg, }); } }); }; const columns = [ { title: '接口名称', dataIndex: 'path', key: 'path', width: 400, fixed: 'left', onCell: () => ({ style: { maxWidth: 300, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', }, }), render: record => ( <Tooltip placement="topLeft" title={record}> {searchStyle(record)} </Tooltip> ), }, { title: '调用时间', dataIndex: 'requestDate', key: 'requestDate', width: 140, align: 'center', sorter: true, }, { title: '调用结果', dataIndex: 'code', key: 'code', width: 100, align: 'center', render: record => { if (record === -2) { return <span style={{ color: 'red', fontWeight: 'bold' }}>失败</span>; } else if (record === 0) { return <span style={{ color: '#6ecd3d', fontWeight: 'bold' }}>成功</span>; } else if (record === -1) { return <span style={{ color: '#efd341', fontWeight: 'bold' }}>警告</span>; } }, }, { title: '耗时/ms', dataIndex: 'consumerTime', key: 'consumerTime', align: 'center', width: 80, sorter: true, }, { title: '请求方法', dataIndex: 'method', key: 'method', width: 80, align: 'center', render: record => { if (record === 'GET') { return ( <Tag color="orange" style={{ width: '44.44px' }}> GET </Tag> ); } return <Tag color="green">POST</Tag>; }, }, { title: '返回体大小/byte', dataIndex: 'responseSize', key: 'responseSize', width: 130, align: 'center', }, { title: '异常信息', dataIndex: 'errorMsg', key: 'errorMsg', align: 'center', width: 100, render: record => { if (record) { return ( <Button size="small" type="primary" onClick={() => { handleLog(record); }} style={{ backgroundColor: 'red' }} > 错误内容 </Button> ); } }, }, ]; const columns1 = [ { title: '调用频次排名', width: 100, align: 'center', fixed: 'left', render: (text, record, index) => { let data = currentPage1 * pageSize1 + index + 1 - pageSize1; if (data === 1) { return ( <div className={styles.sort} type={data}> {data} </div> ); } else if (data === 2) { return ( <div className={styles.sort} type={data}> {data} </div> ); } else if (data === 3) { return ( <div className={styles.sort} type={data}> {data} </div> ); } else { return <span>{data}</span>; } }, }, { title: '接口名称', dataIndex: 'path', key: 'path', width: 300, fixed: 'left', onCell: () => ({ style: { maxWidth: 300, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', cursor: 'pointer', }, }), render: record => ( <Tooltip placement="topLeft" title={record}> {record} </Tooltip> ), }, { title: '调用次数', dataIndex: 'count', key: 'count', width: 70, align: 'center', }, ]; const columnsAccess = [ { title: '功能名称', dataIndex: '功能名称', key: '功能名称', width: 100, align: 'center', render: record => searchStyle(record), }, { title: '功能路径', dataIndex: '功能路径', key: '功能路径', width: 300, fixed: 'left', onCell: () => ({ style: { maxWidth: 300, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', }, }), render: record => ( <Tooltip placement="topLeft" title={record}> {searchStyle(record)} </Tooltip> ), }, { title: '访问时间', dataIndex: '访问时间', key: '访问时间', width: 140, align: 'center', }, { title: '功能路由', dataIndex: '功能路由', key: '功能路由', width: 200, align: 'center', render: record => searchStyle(record), }, { title: '虚拟目录', dataIndex: '虚拟目录', key: '虚拟目录', align: 'center', width: 80, }, { title: '访问人', dataIndex: '访问人', key: '访问人', width: 80, align: 'center', render: record => searchStyle(record), }, ]; const columnsRemote = [ { title: '操作人', dataIndex: 'opreationName', key: 'opreationName', width: 100, align: 'center', }, { title: '操作时间', dataIndex: 'opreationTime', key: 'opreationTime', width: 100, align: 'center', }, { title: '初始状态', dataIndex: 'initStatus', key: 'initStatus', width: 80, align: 'center', }, { title: '设备编码', dataIndex: 'deviceCode', key: 'deviceCode', width: 100, align: 'center', }, { title: '服务返回信息', dataIndex: 'backContent', key: 'backContent', align: 'center', width: 200, onCell: () => ({ style: { maxWidth: 200, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', }, }), render: record => ( <Tooltip placement="topLeft" title={record}> {record} </Tooltip> ), }, { title: '控制等待时间', dataIndex: 'controlWatiTime', key: 'controlWatiTime', width: 80, align: 'center', }, { title: '控制点位', dataIndex: 'controlPoint', key: 'controlPoint', width: 140, align: 'center', onCell: () => ({ style: { maxWidth: 140, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', }, }), render: record => ( <Tooltip placement="topLeft" title={record}> {record} </Tooltip> ), }, { title: '控制结果', dataIndex: 'controlResult', key: 'controlResult', width: 80, align: 'center', render: record => { if (record === '成功') { return <Tag color="green">{record}</Tag>; } return <Tag color="orange">{record}</Tag>; }, }, { title: '目标状态', dataIndex: 'targetStatus', key: 'targetStatus', align: 'center', width: 80, }, { title: '实际状态', dataIndex: 'realStatus', key: 'realStatus', width: 80, align: 'center', }, ]; const handleLog = text => { setModalVisible(true); setContent(text); }; // 模糊查询匹配的样式 const searchStyle = val => { let n; if (showSearchStyle) { n = val.replace(new RegExp(requestUrl, 'g'), `<span style='color:red'>${requestUrl}</span>`); } else { n = val; } return <div dangerouslySetInnerHTML={{ __html: n }} />; }; const searchStyle1 = val => { let n; if (showSearchStyle) { n = val.replace(new RegExp(label, 'g'), `<span style='color:red'>${label}</span>`); } else { n = val; } return <div dangerouslySetInnerHTML={{ __html: n }} />; }; const changeTime = time => { let time1 = time[0].format('YYYY-MM'); let time2 = time[1].format('YYYY-MM'); if (time1 !== time2 && activeKey === '1') { message.warning('不允许跨月查询'); } else { if (activeKey === '1') { setAllTime(time); setPageSize(20); setCurrentPage(1); getTableList(1, 20, time); setPageSize1(10); setCurrentPage1(1); getApiCount(1, 10, time); } else if (activeKey === '2') { setAllTime(time); setPageSizeAccess(20); setCurrentPageAccess(1); getAccessLog(1, 20, time); } else { setAllTime(time); setPageSizeRemote(20); setCurrentPageRemote(1); getRemoteOperationLog(1, 20, time); } } }; // 近1/6/12/24小时 const setTime = time => { setAllTime([ moment(new Date(new Date().getTime() - time * 60 * 60 * 1000), 'YYYY-MM-DD HH:mm:ss'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss'), ]); }; const handleReset = () => { setAllTime([moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')]); setRequestUrl(''); setLabel(''); setSelectState('失败'); setShowSearchStyle(false); if (activeKey === '1') { getTableList( 1, 20, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', '', '失败', 'rest', ); getApiCount( 1, 10, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', 'rest', ); } else if (activeKey === '2') { getAccessLog( 1, 20, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', 'rest', ); } else { getRemoteOperationLog( 1, 20, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', 'rest', ); } }; const paginationChange = (page, pageSizes) => { getTableList(page, pageSizes); setCurrentPage(page); setPageSize(pageSizes); }; const paginationChange1 = (page, pageSizes) => { getApiCount(page, pageSizes); setCurrentPage1(page); setPageSize1(pageSizes); }; const paginationChangeAccess = (page, pageSizes) => { getAccessLog(page, pageSizes); setCurrentPageAccess(page); setPageSizeAccess(pageSizes); }; const paginationChangeRemote = (page, pageSizes) => { getRemoteOperationLog(page, pageSizes); setCurrentPageRemote(page); setPageSizeRemote(pageSizes); }; const onChangeInput = (pagination, filters, sorter) => { timeSorter.current = sorter.order === 'ascend' ? 'asc' : 'desc'; filterSorter.current = sorter.field ? sorter.field : 'requestDate'; getTableList(); }; const changeSuccess = e => { setSelectState(e); getTableList('', '', '', '', '', e); }; const onChange = e => { setActiveKey(e); setAllTime([moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')]); setCurrentPage(1); setCurrentPage1(1); setCurrentPageAccess(1); setCurrentPageRemote(1); setRequestUrl(''); setLabel(''); setSelectState('失败'); setShowSearchStyle(false); if (e === '1') { getTableList( 1, 20, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', '', '失败', 'rest', ); getApiCount( 1, 10, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', 'rest', ); } else if (e === '2') { getAccessLog( 1, 20, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', ); } else { getRemoteOperationLog( 1, 20, [moment().startOf('month'), moment(new Date(), 'YYYY-MM-DD HH:mm:ss')], '', ); } }; return ( <div className={styles.centerLog}> <Tabs activeKey={activeKey} onChange={onChange} style={{ backgroundColor: 'white', paddingLeft: '20px' }} > <TabPane tab="接口调用" key="1"> <div className={styles.head}> <span style={{ lineHeight: 2, marginLeft: '7px' }}>时间:</span> <RangePicker locale={locale} showTime format="YYYY-MM-DD HH:mm:ss" onChange={changeTime} value={allTime} allowClear={false} /> <span style={{ marginLeft: '20px' }}>调用结果:</span> <Select style={{ width: '180px' }} value={selectState} onSelect={e => changeSuccess(e)}> <Option value="全部">全部</Option> <Option value="成功">成功</Option> <Option value="警告">警告</Option> <Option value="失败">失败</Option> </Select> <span style={{ marginLeft: '20px' }}>接口名称:</span> <Input style={{ width: '200px' }} placeholder="请输入接口名称" onChange={e => { setRequestUrl(e.target.value); }} value={requestUrl} allowClear /> <Button type="primary" style={{ marginLeft: '10px' }} onClick={() => { setPageSize(20); setCurrentPage(1); getTableList(1, 20); setCurrentPage1(1); getApiCount(1, 10); setShowSearchStyle(true); }} > 查询 </Button> <Button icon={<SyncOutlined className={styles.icon} />} onClick={handleReset} style={{ marginLeft: '25px', verticalAlign: 'middle', }} > 重置 </Button> </div> <div className={styles.content}> <div className={styles.left}> <div className={styles.table}> <Table size="small" bordered columns={columns} dataSource={tableData} scroll={{ y: 'calc(100% - 30px)' }} pagination={false} onChange={onChangeInput} loading={loading} /> </div> <div className={styles.footer}> <Pagination total={total} showTotal={(aa, range) => `第${range[0]}-${range[1]} 条/共 ${total} 条`} pageSizeOptions={[10, 20, 40, 100]} current={currentPage} onChange={paginationChange} size="small" pageSize={pageSize} showSizeChanger /> </div> </div> <div className={styles.right}> <div className={styles.table}> <Table size="large" bordered columns={columns1} dataSource={tableData1} scroll={{ y: 'calc(100% - 30px)' }} pagination={false} onChange={onChangeInput} loading={loading1} /> </div> <div className={styles.footer}> <Pagination total={total1} defaultPageSize={10} showTotal={(aa, range) => `第${range[0]}-${range[1]} 条/共 ${total1} 条`} current={currentPage1} onChange={paginationChange1} size="small" pageSize={pageSize1} showSizeChanger={false} /> </div> </div> </div> </TabPane> <TabPane tab="功能访问" key="2"> <div className={styles.head}> <span style={{ lineHeight: 2, marginLeft: '7px' }}>时间:</span> <RangePicker locale={locale} showTime format="YYYY-MM-DD HH:mm:ss" onChange={changeTime} value={allTime} allowClear={false} /> <Tooltip title="可查询功能路径 、功能路由、功能名称、访问人"> <InfoCircleOutlined style={{ color: '#1890ff', marginLeft: '20px', }} /> </Tooltip> <span style={{ marginLeft: '3px' }}>快速搜索:</span> <Input style={{ width: '200px' }} placeholder="请输入功能路径 、功能路由、功能名称、访问人" onChange={e => { setRequestUrl(e.target.value); }} value={requestUrl} allowClear /> <Button type="primary" style={{ marginLeft: '10px' }} onClick={() => { setPageSizeAccess(20); setCurrentPageAccess(1); getAccessLog(1, 20); setShowSearchStyle(true); }} > 查询 </Button> <Button icon={<SyncOutlined className={styles.icon} />} onClick={handleReset} style={{ marginLeft: '25px', verticalAlign: 'middle', }} > 重置 </Button> </div> <div className={styles.table}> <Table size="small" bordered columns={columnsAccess} dataSource={tableDataAccess} scroll={{ y: 'calc(100% - 30px)' }} pagination={false} onChange={onChangeInput} loading={loadingAccess} /> </div> <div className={styles.footer}> <Pagination total={totalAccess} showTotal={(aa, range) => `第${range[0]}-${range[1]} 条/共 ${totalAccess} 条`} pageSizeOptions={[10, 20, 40, 100]} current={currentPageAccess} onChange={paginationChangeAccess} size="small" pageSize={pageSizeAccess} showSizeChanger /> </div> </TabPane> <TabPane tab="设备控制" key="3"> <div className={styles.head}> <span style={{ lineHeight: 2, marginLeft: '7px' }}>时间:</span> <RangePicker locale={locale} showTime format="YYYY-MM-DD HH:mm:ss" onChange={changeTime} value={allTime} allowClear={false} /> <span style={{ marginLeft: '20px' }}>设备编码:</span> <Input style={{ width: '200px' }} placeholder="请输入设备编码" onChange={e => { setRequestUrl(e.target.value); }} value={requestUrl} allowClear /> <Button type="primary" style={{ marginLeft: '10px' }} onClick={() => { setPageSizeRemote(20); setCurrentPageRemote(1); getRemoteOperationLog(1, 20); setShowSearchStyle(true); }} > 查询 </Button> <Button icon={<SyncOutlined className={styles.icon} />} onClick={handleReset} style={{ marginLeft: '25px', verticalAlign: 'middle', }} > 重置 </Button> </div> <div className={styles.table}> <Table size="small" bordered columns={columnsRemote} dataSource={tableDataRemote} scroll={{ y: 'calc(100% - 30px)' }} pagination={false} onChange={onChangeInput} loading={loadingRemote} /> </div> <div className={styles.footer}> <Pagination total={totalRemote} showTotal={(aa, range) => `第${range[0]}-${range[1]} 条/共 ${totalRemote} 条`} pageSizeOptions={[10, 20, 40, 100]} current={currentPageRemote} onChange={paginationChangeRemote} size="small" pageSize={pageSizeRemote} showSizeChanger /> </div> </TabPane> </Tabs> <Modal title="详细信息" visible={modalVisible} keyboard={false} maskClosable centered onOk={() => setModalVisible(false)} onCancel={() => setModalVisible(false)} width="1000px" bodyStyle={{ minHeight: '100px', maxHeight: '600px', overflowY: 'scroll', }} style={{ top: '40px' }} footer={[ <Button type="primary" onClick={() => setModalVisible(false)} key="back"> 关闭窗口 </Button>, ]} > {content} </Modal> </div> ); }; export default LogCenter;