275 lines
9.2 KiB
JavaScript
275 lines
9.2 KiB
JavaScript
import React, { Component } from 'react'
|
|
import {
|
|
Alert,
|
|
Button,
|
|
Card,
|
|
Descriptions,
|
|
Form,
|
|
Popconfirm,
|
|
Input,
|
|
message as Message,
|
|
Select,
|
|
DatePicker,
|
|
Tag,
|
|
} from 'antd'
|
|
import { Auth, Container, QueryTable } from 'components'
|
|
import { api } from 'common/api'
|
|
import { toCamelCase } from 'util/format'
|
|
import { isEqual } from 'lodash'
|
|
import getDictData from 'util/dic'
|
|
import moment from 'moment'
|
|
import ReactJson from 'react-json-view'
|
|
|
|
const { RangePicker } = DatePicker
|
|
|
|
const apiAction = {
|
|
page: api.sysOpLogPage,
|
|
delete: api.sysOpLogDelete,
|
|
}
|
|
|
|
const methodColor = {
|
|
POST: 'orange',
|
|
GET: 'green',
|
|
}
|
|
|
|
export default class index extends Component {
|
|
state = {
|
|
codes: {
|
|
opType: [],
|
|
},
|
|
}
|
|
// 表格实例
|
|
table = React.createRef()
|
|
// 表格字段
|
|
columns = [
|
|
{
|
|
title: '日志名称',
|
|
dataIndex: 'name',
|
|
width: 200,
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '请求地址',
|
|
dataIndex: 'url',
|
|
width: 300,
|
|
sorter: true,
|
|
render: (text, record) => (
|
|
<>
|
|
<Tag color={methodColor[record.reqMethod.toUpperCase()]}>
|
|
{record.reqMethod}
|
|
</Tag>{' '}
|
|
{text}
|
|
</>
|
|
),
|
|
},
|
|
{
|
|
title: '是否成功',
|
|
dataIndex: 'success',
|
|
width: 100,
|
|
render: text => (
|
|
<>
|
|
{text ? (
|
|
<span className="text-success">是</span>
|
|
) : (
|
|
<span className="text-error">否</span>
|
|
)}
|
|
</>
|
|
),
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: 'ip',
|
|
dataIndex: 'ip',
|
|
width: 120,
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '操作时间',
|
|
dataIndex: 'opTime',
|
|
width: 140,
|
|
sorter: true,
|
|
defaultSortOrder: 'descend',
|
|
},
|
|
{
|
|
title: '操作人',
|
|
width: 140,
|
|
dataIndex: 'account',
|
|
sorter: true,
|
|
},
|
|
]
|
|
|
|
/**
|
|
* 阻止外部组件引发的渲染,提升性能
|
|
* 可自行添加渲染条件
|
|
* [必要]
|
|
* @param {*} props
|
|
* @param {*} state
|
|
* @returns
|
|
*/
|
|
shouldComponentUpdate(props, state) {
|
|
return !isEqual(this.state, state)
|
|
}
|
|
|
|
/**
|
|
* 加载字典数据,之后开始加载表格数据
|
|
* 如果必须要加载字典数据,可直接对表格设置autoLoad=true
|
|
*/
|
|
componentDidMount() {}
|
|
|
|
/**
|
|
* 调用加载数据接口,可在调用前对query进行处理
|
|
* [异步,必要]
|
|
* @param {*} params
|
|
* @param {*} query
|
|
* @returns
|
|
*/
|
|
loadData = async (params, query) => {
|
|
if (query.dates && query.dates.length) {
|
|
query.searchBeginTime = moment(query.dates[0]).format('YYYY-MM-DD HH:mm:ss')
|
|
query.searchEndTime = moment(query.dates[1]).format('YYYY-MM-DD HH:mm:ss')
|
|
delete query.dates
|
|
}
|
|
const { data } = await apiAction.page({
|
|
...params,
|
|
...query,
|
|
})
|
|
return data
|
|
}
|
|
/**
|
|
* 绑定字典数据
|
|
* @param {*} code
|
|
* @param {*} name
|
|
* @returns
|
|
*/
|
|
bindCodeValue(code, name) {
|
|
name = toCamelCase(name)
|
|
const codes = this.state.codes[name]
|
|
if (codes) {
|
|
const c = codes.find(p => +p.code === code)
|
|
if (c) {
|
|
return c.value
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* 对表格上的操作进行统一处理
|
|
* [异步]
|
|
* @param {*} action
|
|
* @param {*} successMessage
|
|
*/
|
|
async onAction(action, successMessage) {
|
|
this.table.current.onLoading()
|
|
try {
|
|
await action
|
|
Message.success(successMessage)
|
|
this.table.current.onReloadData()
|
|
} catch {
|
|
this.table.current.onLoaded()
|
|
}
|
|
}
|
|
|
|
onOpLogClear() {
|
|
this.onAction(apiAction.delete(), '清空成功')
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<Container mode="fluid">
|
|
<br />
|
|
<Alert
|
|
closable
|
|
type="error"
|
|
message={
|
|
<>
|
|
<div>后端bug:任何操作的操作类型都是增加</div>
|
|
<div>没有记录请求参数.返回结果等信息</div>
|
|
</>
|
|
}
|
|
/>
|
|
<br />
|
|
<Card bordered={false}>
|
|
<QueryTable
|
|
ref={this.table}
|
|
loadData={this.loadData}
|
|
columns={this.columns}
|
|
query={
|
|
<Auth auth="sysOpLog:page">
|
|
<Form.Item label="日志名称" name="name">
|
|
<Input autoComplete="off" placeholder="请输入日志名称" />
|
|
</Form.Item>
|
|
<Form.Item label="是否成功" name="success">
|
|
<Select placeholder="请选择是否成功" style={{ width: '170px' }}>
|
|
<Select.Option key="true">是</Select.Option>
|
|
<Select.Option key="false">否</Select.Option>
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item label="操作时间" name="dates">
|
|
<RangePicker
|
|
showTime={{
|
|
hideDisabledOptions: true,
|
|
defaultValue: [
|
|
moment('00:00:00', 'HH:mm:ss'),
|
|
moment('23:59:59', 'HH:mm:ss'),
|
|
],
|
|
}}
|
|
format="YYYY-MM-DD HH:mm:ss"
|
|
></RangePicker>
|
|
</Form.Item>
|
|
</Auth>
|
|
}
|
|
operator={
|
|
<Auth auth="sysOpLog:delete">
|
|
<Popconfirm
|
|
placement="bottomLeft"
|
|
title="是否确认清空日志"
|
|
onConfirm={() => this.onOpLogClear()}
|
|
>
|
|
<Button>清空日志</Button>
|
|
</Popconfirm>
|
|
</Auth>
|
|
}
|
|
expandable={{
|
|
expandedRowRender: record => (
|
|
<Descriptions bordered size="small" labelStyle={{ width: '150px' }}>
|
|
<Descriptions.Item span="1" label="方法名称">
|
|
{record.methodName}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item span="2" label="地址">
|
|
{record.location}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="浏览器">
|
|
{record.browser}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item span="2" label="操作系统">
|
|
{record.os}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item span="3" label="类名称">
|
|
{record.className}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item span="3" label="返回结果">
|
|
<ReactJson
|
|
src={JSON.parse(record.result || '{}')}
|
|
collapsed
|
|
/>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item span="3" label="请求参数">
|
|
<ReactJson
|
|
src={JSON.parse(record.param || '{}')}
|
|
collapsed
|
|
/>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item span="3" label="具体消息">
|
|
{record.message}
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
),
|
|
}}
|
|
/>
|
|
</Card>
|
|
</Container>
|
|
)
|
|
}
|
|
}
|