mirror of
https://github.com/jumpserver/lina.git
synced 2025-08-13 20:35:58 +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"
|
placement="bottom"
|
||||||
>
|
>
|
||||||
{{ activity.content }}
|
{{ 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-item>
|
||||||
</el-timeline>
|
</el-timeline>
|
||||||
<div v-if="activities.length < 1">
|
|
||||||
{{ this.$t('common.NoContent') }}
|
|
||||||
</div>
|
|
||||||
</IBox>
|
</IBox>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -24,9 +24,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import IBox from '@/components/IBox'
|
import IBox from '@/components/IBox'
|
||||||
|
import { openTaskPage } from '@/utils/jms'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AccountActivity',
|
name: 'ResourceActivity',
|
||||||
components: {
|
components: {
|
||||||
IBox
|
IBox
|
||||||
},
|
},
|
||||||
@ -59,6 +60,9 @@ export default {
|
|||||||
this.activities.push(res[i])
|
this.activities.push(res[i])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
onClick(taskUrl) {
|
||||||
|
openTaskPage('', 'celery', taskUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,6 +434,7 @@
|
|||||||
"About": "About",
|
"About": "About",
|
||||||
"PermissionCompany": "Permission company",
|
"PermissionCompany": "Permission company",
|
||||||
"ApproverNumbers": "Approver numbers",
|
"ApproverNumbers": "Approver numbers",
|
||||||
|
"ConvenientOperate": "Convenient operate",
|
||||||
"Overview": "Overview",
|
"Overview": "Overview",
|
||||||
"Now": "Now",
|
"Now": "Now",
|
||||||
"EnterToContinue": "Press Enter to continue",
|
"EnterToContinue": "Press Enter to continue",
|
||||||
|
@ -434,6 +434,7 @@
|
|||||||
"About": "について",
|
"About": "について",
|
||||||
"PermissionCompany": "授权公司",
|
"PermissionCompany": "授权公司",
|
||||||
"ApproverNumbers": "承認者数",
|
"ApproverNumbers": "承認者数",
|
||||||
|
"ConvenientOperate": "便利な操作",
|
||||||
"Overview": "概要",
|
"Overview": "概要",
|
||||||
"Now": "今",
|
"Now": "今",
|
||||||
"EnterToContinue": "Enter キーを押して続行します了",
|
"EnterToContinue": "Enter キーを押して続行します了",
|
||||||
|
@ -431,6 +431,7 @@
|
|||||||
"PermissionCompany": "授权公司",
|
"PermissionCompany": "授权公司",
|
||||||
"Filename": "文件名",
|
"Filename": "文件名",
|
||||||
"ApproverNumbers": "审批人数量",
|
"ApproverNumbers": "审批人数量",
|
||||||
|
"ConvenientOperate": "便捷操作",
|
||||||
"Overview": "概览",
|
"Overview": "概览",
|
||||||
"Now": "现在",
|
"Now": "现在",
|
||||||
"EnterToContinue": "按回车继续输入",
|
"EnterToContinue": "按回车继续输入",
|
||||||
|
@ -172,7 +172,7 @@ export default {
|
|||||||
const activity = {
|
const activity = {
|
||||||
title: this.$t('common.Activity'),
|
title: this.$t('common.Activity'),
|
||||||
name: 'ResourceActivity',
|
name: 'ResourceActivity',
|
||||||
hidden: () => !this.$hasPerm('audits.view_operatelog')
|
hidden: () => !this.$hasPerm('audits.view_activitylog')
|
||||||
}
|
}
|
||||||
return [...this.submenu, activity]
|
return [...this.submenu, activity]
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import i18n from '@/i18n/i18n'
|
import i18n from '@/i18n/i18n'
|
||||||
|
import empty from '@/layout/empty'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: 'login-log',
|
path: 'login-logs',
|
||||||
name: 'LoginLog',
|
name: 'LoginLog',
|
||||||
component: () => import('@/views/audits/LoginLogList'),
|
component: () => import('@/views/audits/LoginLogList'),
|
||||||
meta: {
|
meta: {
|
||||||
@ -11,14 +12,35 @@ export default [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'operate-log',
|
path: 'operate-logs',
|
||||||
name: 'OperateLog',
|
name: '',
|
||||||
component: () => import('@/views/audits/OperateLogList'),
|
component: empty,
|
||||||
|
meta: {
|
||||||
|
title: i18n.t('route.OperateLog'),
|
||||||
|
permissions: ['audits.view_operatelog']
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: 'OperateLogList',
|
||||||
|
component: () => import('@/views/audits/OperateLog/OperateLogList'),
|
||||||
meta: {
|
meta: {
|
||||||
title: i18n.t('route.OperateLog'),
|
title: i18n.t('route.OperateLog'),
|
||||||
permissions: ['audits.view_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',
|
path: 'password-change-log',
|
||||||
name: 'PasswordChangeLog',
|
name: 'PasswordChangeLog',
|
@ -2,7 +2,7 @@ import Layout from '@/layout'
|
|||||||
import i18n from '@/i18n/i18n'
|
import i18n from '@/i18n/i18n'
|
||||||
|
|
||||||
import SessionRoutes from './sessions'
|
import SessionRoutes from './sessions'
|
||||||
import LogRoutes from './logs'
|
import LogRoutes from './audits'
|
||||||
import empty from '@/layout/empty'
|
import empty from '@/layout/empty'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ export default {
|
|||||||
children: SessionRoutes
|
children: SessionRoutes
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/audit/logs',
|
path: '/audit/audits',
|
||||||
component: empty,
|
component: empty,
|
||||||
redirect: '',
|
redirect: '',
|
||||||
name: 'Audits',
|
name: 'Audits',
|
||||||
|
@ -2,9 +2,12 @@ import store from '@/store'
|
|||||||
import { constantRoutes } from '@/router'
|
import { constantRoutes } from '@/router'
|
||||||
import { openWindow } from './common'
|
import { openWindow } from './common'
|
||||||
|
|
||||||
export function openTaskPage(taskId, taskType) {
|
export function openTaskPage(taskId, taskType, taskUrl) {
|
||||||
taskType = taskType || 'celery'
|
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) {
|
export function checkPermission(permsRequired, permsAll) {
|
||||||
|
@ -64,6 +64,9 @@ export default {
|
|||||||
datePicker: {
|
datePicker: {
|
||||||
dateStart: dateFrom,
|
dateStart: dateFrom,
|
||||||
dateEnd: dateTo
|
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"
|
:header-actions="headerActions"
|
||||||
:table-config="tableConfig"
|
:table-config="tableConfig"
|
||||||
/>
|
/>
|
||||||
<Dialog
|
|
||||||
v-if="logDetailVisible"
|
<OperateLogDetailDialog
|
||||||
:title="this.$tc('route.OperateLog')"
|
ref="DetailDialog"
|
||||||
:visible.sync="logDetailVisible"
|
/>
|
||||||
:show-cancel="false"
|
|
||||||
:show-confirm="false"
|
|
||||||
>
|
|
||||||
<OperateLogDetail :row="rowObj" />
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import GenericListPage from '@/layout/components/GenericListPage'
|
import GenericListPage from '@/layout/components/GenericListPage'
|
||||||
import { Dialog } from '@/components'
|
|
||||||
import { getDaysAgo, getDaysFuture } from '@/utils/common'
|
import { getDaysAgo, getDaysFuture } from '@/utils/common'
|
||||||
import OperateLogDetail from './components/OperateLogDetail'
|
import OperateLogDetailDialog from './OperateLogDetail/DetailDialog'
|
||||||
import { ActionsFormatter } from '@/components/TableFormatters'
|
import { ActionsFormatter } from '@/components/TableFormatters'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
GenericListPage,
|
GenericListPage,
|
||||||
OperateLogDetail,
|
OperateLogDetailDialog
|
||||||
Dialog
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const vm = this
|
const vm = this
|
||||||
@ -36,6 +29,7 @@ export default {
|
|||||||
const dateFrom = getDaysAgo(7, now).toISOString()
|
const dateFrom = getDaysAgo(7, now).toISOString()
|
||||||
const dateTo = getDaysFuture(1, now).toISOString()
|
const dateTo = getDaysFuture(1, now).toISOString()
|
||||||
return {
|
return {
|
||||||
|
url: '/api/v1/audits/operate-logs/',
|
||||||
rowObj: {
|
rowObj: {
|
||||||
diff: ''
|
diff: ''
|
||||||
},
|
},
|
||||||
@ -80,14 +74,8 @@ export default {
|
|||||||
type: 'primary',
|
type: 'primary',
|
||||||
callback: ({ row }) => {
|
callback: ({ row }) => {
|
||||||
vm.loading = true
|
vm.loading = true
|
||||||
vm.$axios.get(
|
this.$refs.DetailDialog.show(row.id)
|
||||||
`/api/v1/audits/operate-logs/${row.id}/?type=action_detail`,
|
|
||||||
).then(res => {
|
|
||||||
vm.rowObj.diff = res.diff
|
|
||||||
vm.logDetailVisible = true
|
|
||||||
}).finally(() => {
|
|
||||||
vm.loading = false
|
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'),
|
this.$t('common.Logging'),
|
||||||
[
|
[
|
||||||
'LOGIN_LOG_KEEP_DAYS', 'TASK_LOG_KEEP_DAYS', 'OPERATE_LOG_KEEP_DAYS',
|
'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'
|
name: 'TaskHistory'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
hasRightSide: false
|
hasRightSide: false,
|
||||||
|
hasActivity: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user