mirror of
https://github.com/jumpserver/lina.git
synced 2025-08-01 15:11:16 +00:00
Merge pull request #2547 from jumpserver/pr@dev@perf_activity
perf: 增加Activity日志中此资源的任务执行及详情查看
This commit is contained in:
commit
bf55efeb56
@ -12,11 +12,11 @@
|
||||
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>
|
||||
<div v-if="activities.length < 1">
|
||||
{{ this.$t('common.NoContent') }}
|
||||
</div>
|
||||
</IBox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -24,9 +24,10 @@
|
||||
|
||||
<script>
|
||||
import IBox from '@/components/IBox'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
|
||||
export default {
|
||||
name: 'AccountActivity',
|
||||
name: 'ResourceActivity',
|
||||
components: {
|
||||
IBox
|
||||
},
|
||||
@ -59,6 +60,9 @@ export default {
|
||||
this.activities.push(res[i])
|
||||
}
|
||||
})
|
||||
},
|
||||
onClick(taskUrl) {
|
||||
openTaskPage('', 'celery', taskUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -434,6 +434,7 @@
|
||||
"About": "About",
|
||||
"PermissionCompany": "Permission company",
|
||||
"ApproverNumbers": "Approver numbers",
|
||||
"ConvenientOperate": "Convenient operate",
|
||||
"Overview": "Overview",
|
||||
"Now": "Now",
|
||||
"EnterToContinue": "Press Enter to continue",
|
||||
|
@ -434,6 +434,7 @@
|
||||
"About": "について",
|
||||
"PermissionCompany": "授权公司",
|
||||
"ApproverNumbers": "承認者数",
|
||||
"ConvenientOperate": "便利な操作",
|
||||
"Overview": "概要",
|
||||
"Now": "今",
|
||||
"EnterToContinue": "Enter キーを押して続行します了",
|
||||
|
@ -431,6 +431,7 @@
|
||||
"PermissionCompany": "授权公司",
|
||||
"Filename": "文件名",
|
||||
"ApproverNumbers": "审批人数量",
|
||||
"ConvenientOperate": "便捷操作",
|
||||
"Overview": "概览",
|
||||
"Now": "现在",
|
||||
"EnterToContinue": "按回车继续输入",
|
||||
|
@ -172,7 +172,7 @@ export default {
|
||||
const activity = {
|
||||
title: this.$t('common.Activity'),
|
||||
name: 'ResourceActivity',
|
||||
hidden: () => !this.$hasPerm('audits.view_operatelog')
|
||||
hidden: () => !this.$hasPerm('audits.view_activitylog')
|
||||
}
|
||||
return [...this.submenu, activity]
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import empty from '@/layout/empty'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: 'login-log',
|
||||
path: 'login-logs',
|
||||
name: 'LoginLog',
|
||||
component: () => import('@/views/audits/LoginLogList'),
|
||||
meta: {
|
||||
@ -11,13 +12,34 @@ export default [
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'operate-log',
|
||||
name: 'OperateLog',
|
||||
component: () => import('@/views/audits/OperateLogList'),
|
||||
path: 'operate-logs',
|
||||
name: '',
|
||||
component: empty,
|
||||
meta: {
|
||||
title: i18n.t('route.OperateLog'),
|
||||
permissions: ['audits.view_operatelog']
|
||||
}
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'OperateLogList',
|
||||
component: () => import('@/views/audits/OperateLog/OperateLogList'),
|
||||
meta: {
|
||||
title: i18n.t('route.OperateLog'),
|
||||
permissions: ['audits.view_operatelog']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
name: 'OperateLogDetail',
|
||||
component: () => import('@/views/audits/OperateLog/OperateLogDetail/index'),
|
||||
hidden: true,
|
||||
meta: {
|
||||
title: i18n.t('route.OperateLog'),
|
||||
permissions: ['audits.view_operatelog']
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'password-change-log',
|
@ -2,7 +2,7 @@ import Layout from '@/layout'
|
||||
import i18n from '@/i18n/i18n'
|
||||
|
||||
import SessionRoutes from './sessions'
|
||||
import LogRoutes from './logs'
|
||||
import LogRoutes from './audits'
|
||||
import empty from '@/layout/empty'
|
||||
import store from '@/store'
|
||||
|
||||
@ -44,7 +44,7 @@ export default {
|
||||
children: SessionRoutes
|
||||
},
|
||||
{
|
||||
path: '/audit/logs',
|
||||
path: '/audit/audits',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
name: 'Audits',
|
||||
|
@ -2,9 +2,12 @@ import store from '@/store'
|
||||
import { constantRoutes } from '@/router'
|
||||
import { openWindow } from './common'
|
||||
|
||||
export function openTaskPage(taskId, taskType) {
|
||||
export function openTaskPage(taskId, taskType, taskUrl) {
|
||||
taskType = taskType || 'celery'
|
||||
openWindow(`/#/ops/${taskType}/task/${taskId}/log/?type=${taskType}`)
|
||||
if (!taskUrl) {
|
||||
taskUrl = `/#/ops/${taskType}/task/${taskId}/log/?type=${taskType}`
|
||||
}
|
||||
openWindow(taskUrl)
|
||||
}
|
||||
|
||||
export function checkPermission(permsRequired, permsAll) {
|
||||
|
@ -64,6 +64,9 @@ export default {
|
||||
datePicker: {
|
||||
dateStart: dateFrom,
|
||||
dateEnd: dateTo
|
||||
},
|
||||
searchConfig: {
|
||||
getUrlQuery: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
src/views/audits/OperateLog/OperateLogDetail/Detail.vue
Normal file
69
src/views/audits/OperateLog/OperateLogDetail/Detail.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="14" :sm="24">
|
||||
<AutoDetailCard :url="url" :fields="detailFields" :object="object" />
|
||||
</el-col>
|
||||
<el-col :md="10" :sm="24">
|
||||
<QuickActions
|
||||
v-if="object.id"
|
||||
:actions="quickActions"
|
||||
:title="this.$tc('common.ConvenientOperate')"
|
||||
type="primary"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<OperateLogDetailDialog
|
||||
ref="DetailDialog"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { QuickActions } from '@/components'
|
||||
import AutoDetailCard from '@/components/DetailCard/auto'
|
||||
import OperateLogDetailDialog from './DetailDialog'
|
||||
|
||||
export default {
|
||||
name: 'Detail',
|
||||
components: {
|
||||
QuickActions,
|
||||
AutoDetailCard,
|
||||
OperateLogDetailDialog
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
url: `/api/v1/audits/operate-logs/${this.object.id}`,
|
||||
detailFields: [
|
||||
'id', 'user', 'remote_addr', 'resource',
|
||||
'resource_type_display', 'datetime'
|
||||
],
|
||||
quickActions: [
|
||||
{
|
||||
title: this.$t('audits.ChangeField'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$t('common.Detail')
|
||||
},
|
||||
callbacks: {
|
||||
click: function() {
|
||||
this.$refs.DetailDialog.show(this.object.id)
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-if="logDetailVisible"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:title="this.$tc('route.OperateLog')"
|
||||
:visible.sync="logDetailVisible"
|
||||
>
|
||||
<div>
|
||||
<div v-if="isEmpty()" style="text-align: center">
|
||||
{{ this.$tc('common.NoContent') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-table
|
||||
:data="row.diff"
|
||||
height="500"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
:label="this.$tc('audits.ChangeField')"
|
||||
prop="field"
|
||||
show-overflow-tooltip
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="this.$tc('audits.BeforeChange')"
|
||||
prop="before"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
:label="this.$tc('audits.AfterChange')"
|
||||
prop="after"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Dialog } from '@/components'
|
||||
|
||||
export default {
|
||||
name: 'DetailDialog',
|
||||
components: {
|
||||
Dialog
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
row: {
|
||||
diff: ''
|
||||
},
|
||||
logDetailVisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isEmpty() {
|
||||
const content = this.row.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
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.el-table::before {
|
||||
background-color: inherit;
|
||||
}
|
||||
</style>
|
49
src/views/audits/OperateLog/OperateLogDetail/index.vue
Normal file
49
src/views/audits/OperateLog/OperateLogDetail/index.vue
Normal 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>
|
@ -5,30 +5,23 @@
|
||||
:header-actions="headerActions"
|
||||
:table-config="tableConfig"
|
||||
/>
|
||||
<Dialog
|
||||
v-if="logDetailVisible"
|
||||
:title="this.$tc('route.OperateLog')"
|
||||
:visible.sync="logDetailVisible"
|
||||
:show-cancel="false"
|
||||
:show-confirm="false"
|
||||
>
|
||||
<OperateLogDetail :row="rowObj" />
|
||||
</Dialog>
|
||||
|
||||
<OperateLogDetailDialog
|
||||
ref="DetailDialog"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericListPage from '@/layout/components/GenericListPage'
|
||||
import { Dialog } from '@/components'
|
||||
import { getDaysAgo, getDaysFuture } from '@/utils/common'
|
||||
import OperateLogDetail from './components/OperateLogDetail'
|
||||
import OperateLogDetailDialog from './OperateLogDetail/DetailDialog'
|
||||
import { ActionsFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericListPage,
|
||||
OperateLogDetail,
|
||||
Dialog
|
||||
OperateLogDetailDialog
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
@ -36,6 +29,7 @@ export default {
|
||||
const dateFrom = getDaysAgo(7, now).toISOString()
|
||||
const dateTo = getDaysFuture(1, now).toISOString()
|
||||
return {
|
||||
url: '/api/v1/audits/operate-logs/',
|
||||
rowObj: {
|
||||
diff: ''
|
||||
},
|
||||
@ -80,14 +74,8 @@ export default {
|
||||
type: 'primary',
|
||||
callback: ({ row }) => {
|
||||
vm.loading = true
|
||||
vm.$axios.get(
|
||||
`/api/v1/audits/operate-logs/${row.id}/?type=action_detail`,
|
||||
).then(res => {
|
||||
vm.rowObj.diff = res.diff
|
||||
vm.logDetailVisible = true
|
||||
}).finally(() => {
|
||||
vm.loading = false
|
||||
})
|
||||
this.$refs.DetailDialog.show(row.id)
|
||||
vm.loading = false
|
||||
}
|
||||
}
|
||||
]
|
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="isEmpty()" style="text-align: center">
|
||||
{{ this.$tc('common.NoContent') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-table
|
||||
:data="row.diff"
|
||||
height="500"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
:label="this.$tc('audits.ChangeField')"
|
||||
prop="field"
|
||||
show-overflow-tooltip
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="this.$tc('audits.BeforeChange')"
|
||||
prop="before"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
:label="this.$tc('audits.AfterChange')"
|
||||
prop="after"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'OperateLogDetail',
|
||||
props: {
|
||||
row: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isEmpty() {
|
||||
const content = this.row.diff
|
||||
return !content || JSON.stringify(content) === '{}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.el-table::before {
|
||||
background-color: inherit;
|
||||
}
|
||||
</style>
|
@ -26,7 +26,7 @@ export default {
|
||||
this.$t('common.Logging'),
|
||||
[
|
||||
'LOGIN_LOG_KEEP_DAYS', 'TASK_LOG_KEEP_DAYS', 'OPERATE_LOG_KEEP_DAYS',
|
||||
'FTP_LOG_KEEP_DAYS', 'TERMINAL_SESSION_KEEP_DURATION'
|
||||
'FTP_LOG_KEEP_DAYS', 'TERMINAL_SESSION_KEEP_DURATION', 'ACTIVITY_LOG_KEEP_DAYS'
|
||||
]
|
||||
],
|
||||
[
|
||||
|
@ -36,7 +36,8 @@ export default {
|
||||
name: 'TaskHistory'
|
||||
}
|
||||
],
|
||||
hasRightSide: false
|
||||
hasRightSide: false,
|
||||
hasActivity: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user