Merge pull request #2641 from jumpserver/pr@dev@perf_activities_log

perf: 优化Activity日志[操作日志、登录日志]显示
This commit is contained in:
老广
2023-02-15 20:44:06 +08:00
committed by GitHub
8 changed files with 278 additions and 62 deletions

View File

@@ -1,10 +1,10 @@
<template>
<Dialog
v-if="logDetailVisible"
v-if="detailVisible"
:show-confirm="false"
:show-cancel="false"
:title="this.$tc('route.OperateLog')"
:visible.sync="logDetailVisible"
:title="title"
:visible.sync="detailVisible"
>
<div>
<div v-if="isEmpty()" style="text-align: center">
@@ -12,24 +12,24 @@
</div>
<div v-else>
<el-table
:data="row.diff"
:data="diff"
height="500"
style="width: 100%"
>
<el-table-column
:label="this.$tc('audits.ChangeField')"
prop="field"
:prop="fieldName"
show-overflow-tooltip
width="100"
/>
<el-table-column
:label="this.$tc('audits.BeforeChange')"
prop="before"
:prop="leftKeyName"
show-overflow-tooltip
/>
<el-table-column
:label="this.$tc('audits.AfterChange')"
prop="after"
:prop="rightKeyName"
show-overflow-tooltip
/>
</el-table>
@@ -39,34 +39,45 @@
</template>
<script>
import { Dialog } from '@/components'
import Dialog from '@/components/Dialog/index'
export default {
name: 'DetailDialog',
name: 'DiffDetail',
components: {
Dialog
},
props: {},
props: {
title: {
type: String,
default: () => ''
},
fieldName: {
type: String,
default: () => 'field'
},
leftKeyName: {
type: String,
default: () => 'before'
},
rightKeyName: {
type: String,
default: () => 'after'
}
},
data() {
return {
row: {
diff: ''
},
logDetailVisible: false
diff: '',
detailVisible: false
}
},
methods: {
isEmpty() {
const content = this.row.diff
const content = this.diff
return !content || JSON.stringify(content) === '{}'
},
show(objId) {
this.$axios.get(
`/api/v1/audits/operate-logs/${objId}/?type=action_detail`,
).then(res => {
this.row.diff = res.diff
this.logDetailVisible = true
})
show(data) {
this.diff = data
this.detailVisible = true
}
}
}

View File

@@ -1,35 +1,40 @@
<template>
<el-row :gutter="20">
<el-col :md="12" :sm="24">
<IBox :title="title" class="block" v-bind="$attrs">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:size="activity.size"
:timestamp="activity.timestamp"
:type="activity.type"
placement="bottom"
>
{{ activity.content }}
<el-link v-if="activity.detail_url" type="primary" @click.native="onClick(activity.detail_url)">
{{ $tc('common.Detail') }}
</el-link>
</el-timeline-item>
</el-timeline>
</IBox>
</el-col>
</el-row>
<div>
<el-row :gutter="20">
<el-col :md="12" :sm="24">
<IBox :title="title" class="block" v-bind="$attrs">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:size="activity.size"
:timestamp="activity.timestamp"
:type="activity.type"
placement="bottom"
>
{{ activity.content }}
<el-link v-if="activity.detail_url" type="primary" @click.native="onClick(activity.r_type, activity.detail_url)">
{{ $tc('common.Detail') }}
</el-link>
</el-timeline-item>
</el-timeline>
</IBox>
</el-col>
</el-row>
<DiffDetail ref="DetailDialog" :title="this.$tc('route.OperateLog')" />
</div>
</template>
<script>
import IBox from '@/components/IBox'
import DiffDetail from '@/components/Dialog/DiffDetail'
import { openTaskPage } from '@/utils/jms'
export default {
name: 'ResourceActivity',
components: {
IBox
IBox,
DiffDetail
},
props: {
object: {
@@ -61,8 +66,16 @@ export default {
}
})
},
onClick(taskUrl) {
openTaskPage('', 'celery', taskUrl)
onClick(type, taskUrl) {
if (type === 'O') {
this.$axios.get(taskUrl).then(
res => {
this.$refs.DetailDialog.show(res.diff)
}
)
} else {
openTaskPage('', 'celery', taskUrl)
}
}
}
}

View File

@@ -5,11 +5,32 @@ export default [
{
path: 'login-logs',
name: 'LoginLog',
component: () => import('@/views/audits/LoginLogList'),
component: empty,
meta: {
title: i18n.t('route.LoginLog'),
permissions: ['audits.view_userloginlog']
}
},
children: [
{
path: '',
name: 'LoginLogList',
component: () => import('@/views/audits/LoginLog/LoginLogList'),
meta: {
title: i18n.t('route.LoginLog'),
permissions: ['audits.view_userloginlog']
}
},
{
path: ':id',
name: 'LoginLogDetail',
component: () => import('@/views/audits/LoginLog/LoginLogDetail/index'),
hidden: true,
meta: {
title: i18n.t('route.LoginLog'),
permissions: ['audits.view_userloginlog']
}
}
]
},
{
path: 'operate-logs',

View File

@@ -0,0 +1,39 @@
<template>
<div>
<el-row :gutter="20">
<el-col :md="14" :sm="24">
<AutoDetailCard :url="url" :fields="detailFields" :object="object" />
</el-col>
</el-row>
</div>
</template>
<script>
import AutoDetailCard from '@/components/DetailCard/auto'
export default {
name: 'Detail',
components: {
AutoDetailCard
},
props: {
object: {
type: Object,
default: () => {}
}
},
data() {
return {
url: `/api/v1/audits/login-logs/${this.object.id}`,
detailFields: [
'id', 'username', 'city', 'ip', 'backend_display', 'reason_display', 'status', 'type', 'user_agent', 'datetime'
]
}
},
computed: {
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,49 @@
<template>
<GenericDetailPage
:active-menu.sync="config.activeMenu"
:object.sync="LogDetail"
v-bind="config"
v-on="$listeners"
>
<keep-alive>
<component :is="config.activeMenu" :object="LogDetail" />
</keep-alive>
</GenericDetailPage>
</template>
<script>
import { GenericDetailPage, TabPage } from '@/layout/components'
import Detail from './Detail.vue'
export default {
components: {
GenericDetailPage,
TabPage,
Detail
},
data() {
return {
LogDetail: {},
config: {
activeMenu: 'Detail',
submenu: [
{
title: this.$t('common.BasicInfo'),
name: 'Detail'
}
],
actions: {
hasUpdate: () => false,
hasDelete: () => false
},
hasActivity: false,
getObjectName: (obj) => { return obj.id }
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,79 @@
<template>
<GenericListPage :header-actions="headerActions" :table-config="tableConfig" />
</template>
<script>
import GenericListPage from '@/layout/components/GenericListPage'
import { getDaysAgo, getDaysFuture } from '@/utils/common'
export default {
components: {
GenericListPage
},
data() {
const now = new Date()
const dateFrom = getDaysAgo(7, now).toISOString()
const dateTo = getDaysFuture(1, now).toISOString()
return {
tableConfig: {
permissions: {
app: 'audits',
resource: 'userloginlog'
},
columnsExclude: ['backend'],
columnsShow: {
min: ['username', 'type'],
default: [
'username', 'type', 'backend_display', 'ip', 'city',
'user_agent', 'mfa', 'reason_display', 'status', 'datetime'
]
},
url: '/api/v1/audits/login-logs/',
columnsMeta: {
user_agent: {
width: '150px'
},
actions: {
has: false
},
ip: {
width: '140px'
},
city: {
width: '90px'
},
mfa: {
width: '80px'
},
type: {
width: '110px'
},
datetime: {
width: '160px'
}
},
extraQuery: {
date_to: dateTo,
date_from: dateFrom
}
},
headerActions: {
hasLeftActions: false,
hasImport: false,
hasDatePicker: true,
datePicker: {
dateStart: dateFrom,
dateEnd: dateTo
},
searchConfig: {
getUrlQuery: true
}
}
}
}
}
</script>
<style>
</style>

View File

@@ -13,23 +13,21 @@
/>
</el-col>
</el-row>
<OperateLogDetailDialog
ref="DetailDialog"
/>
<DiffDetail ref="DetailDialog" :title="this.$tc('route.OperateLog')" />
</div>
</template>
<script>
import { QuickActions } from '@/components'
import AutoDetailCard from '@/components/DetailCard/auto'
import OperateLogDetailDialog from './DetailDialog'
import DiffDetail from '@/components/Dialog/DiffDetail'
export default {
name: 'Detail',
components: {
QuickActions,
AutoDetailCard,
OperateLogDetailDialog
DiffDetail
},
props: {
object: {
@@ -53,7 +51,11 @@ export default {
},
callbacks: {
click: function() {
this.$refs.DetailDialog.show(this.object.id)
this.$axios.get(
`api/v1/audits/operate-logs/${this.object.id}/?type=action_detail`
).then(res => {
this.$refs.DetailDialog.show(res.diff)
})
}.bind(this)
}
}

View File

@@ -5,23 +5,20 @@
:header-actions="headerActions"
:table-config="tableConfig"
/>
<OperateLogDetailDialog
ref="DetailDialog"
/>
<DiffDetail ref="DetailDialog" :title="this.$tc('route.OperateLog')" />
</div>
</template>
<script>
import GenericListPage from '@/layout/components/GenericListPage'
import { getDaysAgo, getDaysFuture } from '@/utils/common'
import OperateLogDetailDialog from './OperateLogDetail/DetailDialog'
import { ActionsFormatter } from '@/components/TableFormatters'
import DiffDetail from '@/components/Dialog/DiffDetail'
export default {
components: {
GenericListPage,
OperateLogDetailDialog
DiffDetail
},
data() {
const vm = this
@@ -74,8 +71,13 @@ export default {
type: 'primary',
callback: ({ row }) => {
vm.loading = true
this.$refs.DetailDialog.show(row.id)
vm.loading = false
this.$axios.get(
`api/v1/audits/operate-logs/${row.id}/?type=action_detail`
).then(res => {
this.$refs.DetailDialog.show(res.diff)
}).finally(() => {
vm.loading = false
})
}
}
]