新增:登陆日志,操作日志

This commit is contained in:
jmal 2021-02-08 18:07:41 +08:00
parent f6b4eefaec
commit 6eb0fab315
7 changed files with 347 additions and 10 deletions

13
src/api/log.js Normal file
View File

@ -0,0 +1,13 @@
import request from '@/utils/request'
const qs = require('qs')
export default {
logList(params) {
return request({
url: '/log/list',
method: 'get',
params
})
},
}

View File

@ -50,7 +50,7 @@
</div>
<div v-if="item.formatData">
<div v-if="item.tag">
<el-tag size="mini" v-for="tagname in item.formatData(scope.row[item.prop])" :key="tagname">{{tagname}}</el-tag>
<el-tag size="mini" v-for="tag in item.formatData(scope.row[item.prop])" :type="tag.type" :key="tag.name">{{tag.name}}</el-tag>
</div>
<div v-else-if="item.icon">
<svg-icon :icon-class="item.formatData(scope.row[item.prop])"></svg-icon>

View File

@ -140,13 +140,13 @@ export default {
{prop: 'roles', minWidth: 120, label: '角色', tag: true,
formatData: (roles)=> {
if(roles){
let tagNames = this.roleList.map(role => {
let tags = this.roleList.map(role => {
if (roles.includes(role.id)) {
return role.name
return {name : role.name}
}
})
tagNames = tagNames.filter(tagName => tagName !== undefined)
return tagNames
tags = tags.filter(tag => tag !== undefined)
return tags
}
}
},

View File

@ -0,0 +1,161 @@
<template>
<div class="container">
<el-card class="box-card table-search-header">
<div slot="header">
<div class="box-card-header">
<el-form size="medium" class="search-form" ref="queryForm" label-width="77px" :model="queryCondition" @submit.native.prevent>
<el-row :gutter="10">
<el-col :sm="12" :md="8">
<el-form-item label="账号:">
<el-input clearable placeholder="请输入" v-model="queryCondition.username" />
</el-form-item>
</el-col>
<el-col :sm="12" :md="9">
<el-form-item label="时间:" prop="logTime">
<el-date-picker
v-model="pickerValue"
size="medium"
type="datetimerange"
:picker-options="pickerOptions"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
align="right">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :sm="12" :md="7">
<div class="el-form-actions">
<el-button class="card-btn-icon" size="medium" icon="el-icon-search" type="primary" @click="getLogList()">查询</el-button>
</div>
</el-col>
</el-row>
</el-form>
</div>
</div>
<table-list
:less-client-height="280"
:tableData="dataList"
:loading="loading"
:hasSelection="false"
:tableHeader="tableHeader"
:pagination="pagination"
@pageChange="pageChange"
@sortChange="sortChange"
></table-list>
</el-card>
</div>
</template>
<script>
import logApi from '@/api/log'
import TableList from "@/components/table/TableList";
export default {
name: 'LogList',
components: {
TableList
},
props: {
type: {
type: String,
default: ''
},
tableHeader: {
type: Array,
default: []
}
},
data() {
return {
dataList: [],
loading: false,
// 分页信息
pagination: {
pageIndex: 1,
pageSize: 12,
pageTotal: 0
},
// 查询条件
queryCondition: {
username: undefined,
type: this.type,
startTime: undefined,
endTime: undefined
},
pickerValue: [],
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
}]
},
}
},
mounted() {
this.getLogList()
},
methods: {
//表格组件返回排序对象
sortChange(data) {
let column = data.backData;
this.queryCondition.sortProp = column.prop
this.queryCondition.sortOrder = column.order
this.getLogList()
},
//分页导航
pageChange(data) {
this.pagination = data.backData;
this.getLogList()
},
getLogList(){
if (this.pickerValue.length > 0){
this.queryCondition.startTime = this.pickerValue[0].getTime()
this.queryCondition.endTime = this.pickerValue[1].getTime()
}
this.loading = true
logApi.logList({
page: this.pagination.pageIndex,
pageSize: this.pagination.pageSize,
...this.queryCondition
}).then(res => {
this.dataList = res.data
this.pagination.pageTotal = res.count
this.loading = false
})
},
}
}
</script>
<style lang="scss" scoped>
@import "src/styles/setting";
.box-card {
max-width: 1440px;
}
/deep/.el-range-editor--medium {
width: 100%;
}
</style>

View File

@ -0,0 +1,41 @@
<template>
<div>
<log-list type="LOGIN" :table-header="tableHeader"></log-list>
</div>
</template>
<script>
import LogList from "@/views/setting/sys/logList";
export default {
components: {
LogList
},
data() {
return {
tableHeader: [
{prop: 'username',label: '账号', sortable: 'custom'},
{prop: 'showName',label: '用户名', sortable: 'custom'},
{prop: 'ip',label: 'IP地址', sortable: 'custom'},
{prop: 'deviceModel',label: '设备型号', sortable: 'custom'},
{prop: 'operatingSystem',label: '操作系统', sortable: 'custom'},
{prop: 'browser',label: '浏览器', sortable: 'custom'},
{prop: 'status', minWidth: 80, label: '状态', tag: true,
formatData: (status)=> {
if(status === 0) {
return [{name: '登陆成功', type: 'success'}]
} else {
return [{name: '登陆失败', type: 'danger'}]
}
}
},
{prop: 'remarks',label: '备注', sortable: 'custom'},
{prop: 'createTime',label: '创建时间', minWidth: 110, sortable: 'custom'},
],
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,122 @@
<template>
<div>
<el-dialog class="dialog-form" width="600px" title="详情" :visible.sync="dialogVisible">
<el-form size="medium" ref="managerForm" label-width="90px" :model="detailsData">
<el-row :gutter="10">
<el-col :sm="12">
<el-form-item label="操作人:">
<div>{{detailsData.showName}}({{detailsData.username}})</div>
</el-form-item>
<el-form-item label="操作模块:">
<div>{{detailsData.operationModule}}</div>
</el-form-item>
<el-form-item label="操作时间:">
<div>{{detailsData.createTime}}</div>
</el-form-item>
<el-form-item label="请求方式:">
<div>{{detailsData.method}}</div>
</el-form-item>
</el-col>
<el-col :sm="12">
<el-form-item label="IP地址:">
<div>{{detailsData.ip}}</div>
</el-form-item>
<el-form-item label="操作功能:">
<div>{{detailsData.operationFun}}</div>
</el-form-item>
<el-form-item label="请求耗时:">
<div>{{detailsData.time}}ms</div>
</el-form-item>
<el-form-item label="请求状态:">
<el-tag size="mini" :type="detailsData.status === 0 ? 'success': 'danger'">{{detailsData.status === 0 ? '正常':'异常'}}</el-tag>
</el-form-item>
</el-col>
</el-row>
<el-divider></el-divider>
<el-row>
<el-col>
<el-form-item label="请求地址:">
<div>{{detailsData.url}}</div>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="请求参数:">
<div>{{detailsData.params}}</div>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="备注:">
<div>{{detailsData.remarks}}</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="dialogVisible = false">关闭</el-button>
</div>
</el-dialog>
<log-list type="OPERATION" :table-header="tableHeader"></log-list>
</div>
</template>
<script>
import LogList from "@/views/setting/sys/logList";
export default {
components: {
LogList
},
data() {
return {
tableHeader: [
{prop: 'username',label: '账号', minWidth: 105, sortable: 'custom'},
{prop: 'showName',label: '用户名', minWidth: 105, sortable: 'custom'},
{prop: 'ip',label: 'IP地址', minWidth: 105, sortable: 'custom'},
{prop: 'operationModule',label: '操作模块', minWidth: 105, sortable: 'custom'},
{prop: 'operationFun',label: '操作功能', minWidth: 105, sortable: 'custom'},
{prop: 'url',label: '请求地址', minWidth: 105, sortable: 'custom'},
{prop: 'method',label: '方式', minWidth: 75, sortable: 'custom'},
{prop: 'status', minWidth: 75, label: '状态', tag: true, sortable: 'custom',
formatData: (status)=> {
if(status === 0) {
return [{name: '正常', type: 'success'}]
} else {
return [{name: '异常', type: 'danger'}]
}
}
},
{prop: 'time', label: '耗时', minWidth: 75, sortable: 'custom',
formatData: (time)=> {
return time + 'ms'
}
},
{prop: 'createTime',label: '创建时间', minWidth: 110, sortable: 'custom'},
{label: '操作', minWidth: 75, active: [
{name: '详情', icon: 'el-icon-view', handle: (row) => this.details(row)},
],
},
],
dialogVisible: false,
detailsData: {},
}
},
methods: {
details(row) {
this.detailsData = row
this.dialogVisible = true
}
}
}
</script>
<style lang="scss" scoped>
@import "src/styles/setting";
/deep/ .box-card {
max-width: 1440px;
}
/deep/ .el-form-item {
margin-bottom: 0px;
}
/deep/.el-divider--horizontal {
margin: 10px 0;
}
</style>

View File

@ -184,15 +184,15 @@ export default {
formatData: (menuType)=> {
switch (menuType) {
case 0:
return ['首页菜单']
return [{name: '首页菜单'}]
case 1:
return ['按钮']
return [{name: '按钮'}]
case 2:
return ['设置菜单']
return [{name: '设置菜单'}]
case 3:
return ['顶部菜单']
return [{name: '顶部菜单'}]
case 4:
return ['右上角菜单']
return [{name: '右上角菜单'}]
}
}
},