perf: update name space

This commit is contained in:
ibuler
2024-12-04 18:34:10 +08:00
parent 4b309d950c
commit 2e472dad93
34 changed files with 447 additions and 350 deletions

View File

@@ -1,6 +1,7 @@
<template>
<Dialog
:visible="iVisible"
height="300"
title="Processing"
width="300"
>
@@ -39,10 +40,9 @@ export default {
</script>
<style lang="scss" scoped>
.spinner {
width: 50px;
height: 50px;
width: 100px;
height: 100px;
border: 5px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top-color: #3498db;

View File

@@ -22,7 +22,6 @@
<i class="fa fa-check color-primary" />
</span>
<span v-else>
{{ iValue }}
<svg-icon icon-class="ignore" />
</span>
</el-tooltip>
@@ -95,7 +94,7 @@ export default {
if (cmd === 'add_account') {
this.row.present = true
}
this.row.status = { 'value': '0' }
this.row.status = { 'value': '1' }
}).finally(() => {
setTimeout(() => {
this.processing = false

View File

@@ -113,7 +113,7 @@ export default [
// },
// {
// path: ':id',
// component: () => import('@/views/accounts/AccountTemplate/AccountTemplateDetail/index.vue'),
// component: () => import('@/views/accounts/AccountTemplate/AccountTemplateDetail/Application.vue'),
// name: 'AccountTemplateDetail',
// meta: { title: i18n.t('AccountTemplate') },
// hidden: true

View File

@@ -20,8 +20,7 @@ export default [
component: () => import('@/views/sessions/SessionList/index.vue'),
name: 'AccountSessionList',
meta: {
title: i18n.t('账号会话'),
menuTitle: i18n.t('账号会话'),
title: i18n.t('AccountSessions'),
permissions: []
}
}
@@ -46,8 +45,7 @@ export default [
component: () => import('@/views/accounts/AccountActivity/AccountActivityList.vue'),
name: 'AccountActivityList',
meta: {
title: i18n.t('活动记录'),
menuTitle: i18n.t('活动记录'),
title: i18n.t('AccountActivity'),
permissions: ['audits.view_operatelog']
}
}

View File

@@ -102,7 +102,7 @@ export default [
component: () => import('@/views/accounts/AccountChangeSecret/index.vue'),
name: 'AccountChangeSecretList',
meta: {
menuTitle: i18n.t('ChangeCredentials'),
menuTitle: i18n.t('ChangeSecret'),
title: i18n.t('AccountChangeSecret'),
permissions: ['accounts.view_changesecretautomation']
}

View File

@@ -3,7 +3,7 @@ import i18n from '@/i18n/i18n'
import empty from '@/layout/empty'
import automations from './automations'
import services from './service'
import integrations from './integrations'
import security from './security'
import activity from './activity'
@@ -13,7 +13,7 @@ export default {
component: Layout,
redirect: '/pam/dashboard',
meta: {
title: '特权账号',
title: i18n.t('PAM'),
icon: 'pam',
type: 'view',
showNavSwitcher: true,
@@ -36,7 +36,7 @@ export default {
name: 'PamAccounts',
component: () => import('@/views/pam/Account/index.vue'),
meta: {
title: i18n.t('特权账号'),
title: i18n.t('Accounts'),
icon: 'accounts',
permissions: []
}
@@ -57,22 +57,22 @@ export default {
name: 'AccountSecurity',
component: empty,
meta: {
title: i18n.t('安全中心'),
title: i18n.t('Security'),
icon: 'accounts',
permissions: []
},
children: security
},
{
path: '/pam/services',
name: 'AccountService',
path: '/pam/integrations',
name: 'Integrations',
component: empty,
meta: {
title: i18n.t('Service'),
title: i18n.t('Integration'),
icon: 'accounts',
permissions: []
},
children: services
children: integrations
},
{
path: '/pam/activity',

View File

@@ -0,0 +1,60 @@
import empty from '@/layout/empty.vue'
import i18n from '@/i18n/i18n'
export default [
{
path: 'services',
name: 'Services',
component: empty,
redirect: {
name: 'IntegrationApplicationList'
},
meta: {
app: 'accounts',
name: 'Service',
icon: 'service',
resource: 'integrationapplicaion'
},
children: [
{
path: '',
component: () => import('@/views/pam/Integration/Application.vue'),
name: 'IntegrationApplicationList',
meta: {
title: i18n.t('Applications'),
permissions: ['accounts.view_integrationapplication']
}
},
{
path: 'create',
component: () => import('@/views/pam/Integration/ApplicationCreateUpdate.vue'),
name: 'IntegrationApplicationCreate',
hidden: true,
meta: {
title: i18n.t('IntegrationApplicationCreate'),
permissions: ['accounts.add_integrationapplication']
}
},
{
path: ':id/update',
component: () => import('@/views/pam/Integration/ApplicationCreateUpdate.vue'),
name: 'IntegrationApplicationUpdate',
hidden: true,
meta: {
title: i18n.t('IntegrationApplicationUpdate'),
permissions: ['accounts.change_integrationapplication']
}
},
{
path: ':id',
component: () => import('@/views/pam/Integration/ApplicationDetail/index.vue'),
name: 'ApplicationDetail',
hidden: true,
meta: {
title: i18n.t('ApplicationDetail'),
permissions: ['accounts.view_integrationapplication']
}
}
]
}
]

View File

@@ -15,16 +15,15 @@ export default [
children: [
{
path: '',
component: () => import('@/views/pam/AccountCheck/index.vue'),
component: () => import('@/views/pam/RiskDetect/index.vue'),
name: 'AccountCheckList',
meta: {
title: i18n.t('账号检查'),
menuTitle: i18n.t('账号检查')
title: i18n.t('RiskDetection')
}
},
{
path: 'create',
component: () => import('@/views/pam/AccountCheck/AccountCheckCreateUpdate.vue'),
component: () => import('@/views/pam/RiskDetect/AccountCheckCreateUpdate.vue'),
name: 'AccountCheckCreateUpdate',
hidden: true,
meta: {

View File

@@ -1,61 +0,0 @@
import empty from '@/layout/empty.vue'
import i18n from '@/i18n/i18n'
export default [
{
path: 'services',
name: 'ServiceIntegration',
component: empty,
redirect: {
name: 'ServiceIntegrationList'
},
meta: {
app: 'accounts',
name: 'ServiceIntegration',
icon: 'service',
resource: 'serviceintegration'
},
children: [
{
path: '',
component: () => import('@/views/pam/ServiceIntegration/index.vue'),
name: 'ServiceIntegrationList',
meta: {
title: i18n.t('ServiceIntegration'),
menuTitle: i18n.t('ServiceIntegration'),
permissions: ['accounts.view_serviceintegration']
}
},
{
path: 'create',
component: () => import('@/views/pam/ServiceIntegration/ServiceIntegrationCreateUpdate.vue'),
name: 'ServiceIntegrationCreate',
hidden: true,
meta: {
title: i18n.t('ServiceIntegrationCreate'),
permissions: ['accounts.add_serviceintegration']
}
},
{
path: ':id/update',
component: () => import('@/views/pam/ServiceIntegration/ServiceIntegrationCreateUpdate.vue'),
name: 'ServiceIntegrationUpdate',
hidden: true,
meta: {
title: i18n.t('ServiceIntegrationUpdate'),
permissions: ['accounts.change_serviceintegration']
}
},
{
path: ':id',
component: () => import('@/views/pam/ServiceIntegration/ServiceIntegrationDetail/index.vue'),
name: 'ServiceIntegrationDetail',
hidden: true,
meta: {
title: i18n.t('ServiceIntegrationDetail'),
permissions: ['accounts.view_serviceintegration']
}
}
]
}
]

View File

@@ -1,175 +0,0 @@
<template>
<span>
<span v-if="iValue === '0'" class="risk-handler">
<el-dropdown trigger="click" @command="handleRisk">
<el-button class="confirm action" size="mini">
<i class="fa fa-check" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item of iActions" :key="item.name" :command="item.name">
{{ item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-tooltip :content="$tc('Ignore')" :open-delay="400">
<el-button class="ignore action" size="mini">
<svg-icon icon-class="ignore" />
</el-button>
</el-tooltip>
</span>
<el-tooltip v-else :content="iLabel" :open-delay="400" class="platform-status">
<span v-if="iValue === '1'">
<i class="fa fa-check color-primary" />
</span>
<span v-else>
<svg-icon icon-class="ignore" />
</span>
</el-tooltip>
<ReviewDraw :row="row" :visible.sync="reviewDrawer" />
</span>
</template>
<script>
import BaseFormatter from '@/components/Table/TableFormatters/base.vue'
import ReviewDraw from '@/views/pam/AccountCheck/RiskHandlerFormatter/ReviewDraw.vue'
export default {
name: 'RiskSummaryFormatter',
components: { ReviewDraw },
extends: BaseFormatter,
props: {
formatterArgsDefault: {
type: Object,
default: () => ({})
}
},
data() {
return {
formatterArgs: Object.assign(this.formatterArgsDefault, this.col.formatterArgs),
reviewDrawer: false
}
},
computed: {
iActions() {
return this.getActions()
},
iValue() {
if (this.cellValueIsLabelChoice()) {
return this.cellValue.value
} else {
return this.cellValue
}
},
iLabel() {
if (this.cellValueIsLabelChoice()) {
return this.cellValue.label
} else {
return this.cellValue
}
},
iConfirmIcon() {
const icon = this.formatterArgs.confirmIcon
if (typeof icon === 'function') {
return icon({ row: this.row, cellValue: this.cellValue })
} else {
return icon
}
}
},
methods: {
handleRisk(cmd) {
const data = {
username: this.row.username,
asset: this.row.asset.id,
risk: this.row.risk.value,
action: cmd
}
switch (cmd) {
case 'review':
this.reviewDrawer = true
break
default:
this.$axios.post(`/api/v1/accounts/account-risks/handle/`, data).then(() => {
this.row.status = 'confirmed'
})
}
},
getActions() {
const actions = [
{
name: 'disable_remote',
label: this.$t('Disable remote'),
has: ['long_time_no_login', 'new_found']
},
{
name: 'delete_remote',
label: this.$t('Delete Account'),
has: ['long_time_no_login', 'new_found']
},
{
name: 'delete_both',
label: this.$t('Delete Both'),
has: ['long_time_no_login']
},
{
name: 'add_account',
label: this.$t('Add to Account'),
has: ['new_found']
},
{
name: 'change_password',
label: this.$t('Change Password'),
has: ['long_time_password', 'weak_password', 'password_expired']
},
// {
// name: 'addPrivilegedAccount',
// label: this.$t('Add Privileged Account'),
// has: ['no_admin_account']
// },
// {
// name: 'modifyPassword',
// label: this.$t('Modify Password'),
// has: ['password_error']
// },
{
name: 'review',
label: this.$t('Review'),
has: ['group_changed', 'sudo_changed', 'authorized_key_changed', 'account_deleted', 'others']
}
]
return actions.filter(action => {
return action.has.includes(this.row.risk.value) || action.name === 'review'
})
}
}
}
</script>
<style lang='scss' scoped>
.action.el-button--mini {
cursor: pointer;
padding: 1px 4px;
&.confirm {
::v-deep i {
color: var(--color-primary);
}
}
&.remove {
::v-deep i {
color: var(--color-danger);
}
}
&.ignore {
::v-deep svg.svg-icon {
}
}
}
.draw-body {
padding: 20px;
font-size: 13px;
}
</style>

View File

@@ -0,0 +1,49 @@
<template>
<TabPage
:active-menu.sync="activeMenu"
:submenu="tab.submenu"
/>
</template>
<script>
import { TabPage } from '@/layout/components'
export default {
name: 'IntegrationApplicationList',
components: {
TabPage
},
data() {
return {
loading: true,
activeMenu: 'service',
tab: {
submenu: [
{
name: 'application',
title: this.$t('Applications'),
hidden: !this.$hasPerm('accounts.view_integrationapplication'),
component: () => import('@/views/pam/Integration/ApplicationList.vue')
},
{
name: 'records',
title: this.$t('Records'),
hidden: !this.$hasPerm('audits.view_serviceaccesslog'),
component: () => import('@/views/pam/Integration/components/CallRecords.vue')
},
{
name: 'docs',
title: this.$t('Documentation'),
hidden: !this.$hasPerm('accounts.view_integrationapplication'),
component: () => import('@/views/pam/Integration/SDKList.vue')
}
]
}
}
},
watch: {},
async mounted() {
},
methods: {}
}
</script>

View File

@@ -8,7 +8,7 @@ import { UploadField } from '@/components'
import { JSONManyToManySelect } from '@/components/Form/FormFields'
export default {
name: 'ServiceIntegrationCreateUpdate',
name: 'IntegrationApplicationCreateUpdate',
components: {
GenericCreateUpdatePage
},
@@ -16,9 +16,9 @@ export default {
const vm = this
return {
logo_file: null,
url: '/api/v1/accounts/service-integrations/',
url: '/api/v1/accounts/integration-applications/',
fields: [
[this.$t('Basic'), ['name', 'logo_image']],
[this.$t('Basic'), ['name', 'logo']],
[this.$t('AccountPolicy'), ['accounts', 'ip_group']],
[this.$t('Other'), ['is_active', 'comment']]
],
@@ -50,7 +50,7 @@ export default {
]
}
},
logo_image: {
logo: {
component: UploadField,
el: {
width: '10%',
@@ -66,11 +66,11 @@ export default {
},
hasSaveContinue: false,
createSuccessNextRoute: {
name: 'ServiceIntegrationDetail'
name: 'ApplicationDetail'
},
performSubmit(values) {
const formData = new FormData()
delete values['logo_image']
delete values['logo']
if (!Array.isArray(values.ip_group)) {
values.ip_group = values.ip_group ? values.ip_group.split(',') : []
@@ -87,7 +87,7 @@ export default {
formData.append(key, value)
}
if (vm.logo_file) {
formData.append('logo_image', vm.logo_file)
formData.append('logo', vm.logo_file)
}
return this.$axios[this.method](this.iUrl, formData)
}

View File

@@ -18,7 +18,7 @@ import AutoDetailCard from '@/components/Cards/DetailCard/auto'
import SecretDialog from '@/components/Dialog/Secret.vue'
export default {
name: 'ServiceIntegrationInfo',
name: 'IntegrationApplicationInfo',
components: {
SecretDialog,
AutoDetailCard,
@@ -42,12 +42,12 @@ export default {
attrs: {
type: 'primary',
label: this.$t('Generate'),
disabled: !this.$hasPerm('accounts.change_serviceintegration') || !this.object.is_active
disabled: !this.$hasPerm('accounts.change_integrationapplication') || !this.object.is_active
},
callbacks: {
click: function() {
this.$axios.get(
`/api/v1/accounts/service-integrations/${this.object.id}/secret/`,
`/api/v1/accounts/integration-applications/${this.object.id}/secret/`,
).then(res => {
this.$refs.secretDialog.show(res)
})
@@ -55,7 +55,7 @@ export default {
}
}
],
url: `/api/v1/accounts/service-integrations/${this.object.id}`,
url: `/api/v1/accounts/integration-applications/${this.object.id}`,
detailFields: [
'id', 'name', 'date_created', 'date_updated', 'comment', 'is_active'
]

View File

@@ -8,27 +8,27 @@
<script>
import { GenericDetailPage } from '@/layout/components'
import ServiceIntegrationInfo from './ServiceIntegrationInfo.vue'
import IntegrationApplicationInfo from './ServiceInfo.vue'
import ServiceCallRecords from '../components/CallRecords.vue'
export default {
components: {
GenericDetailPage,
ServiceCallRecords,
ServiceIntegrationInfo
IntegrationApplicationInfo
},
data() {
return {
object: {},
config: {
titlePrefix: this.$t('ServiceIntegrationDetail'),
activeMenu: 'ServiceIntegrationInfo',
url: '/api/v1/accounts/service-integrations',
titlePrefix: this.$t('ApplicationDetail'),
activeMenu: 'IntegrationApplicationInfo',
url: '/api/v1/accounts/integration-applications',
submenu: [
{
title: this.$t('Basic'),
name: 'ServiceIntegrationInfo',
hidden: () => !this.$hasPerm('accounts.view_serviceintegration')
name: 'IntegrationApplicationInfo',
hidden: () => !this.$hasPerm('accounts.view_integrationapplication')
},
{
name: 'ServiceCallRecords',

View File

@@ -16,8 +16,8 @@ export default {
data() {
return {
tableConfig: {
url: '/api/v1/accounts/service-integrations/',
permissions: { app: 'accounts', resource: 'serviceintegration' }
url: '/api/v1/accounts/integration-applications/',
permissions: { app: 'accounts', resource: 'integrationapplication' }
},
headerActions: {
hasImport: false,
@@ -30,7 +30,7 @@ export default {
},
subComponentProps: {
getImage: (obj) => {
return obj.logo_image
return obj.logo
},
getInfos: (obj) => {
return [
@@ -41,7 +41,7 @@ export default {
]
},
handleUpdate: (obj) => {
this.$router.push({ name: 'ServiceIntegrationUpdate', params: { id: obj.id }})
this.$router.push({ name: 'IntegrationApplicationUpdate', params: { id: obj.id }})
}
}
}

View File

@@ -93,7 +93,7 @@ export default {
})
},
getSdkInfo() {
const url = `/api/v1/accounts/service-integrations/sdks/?language=${this.currentLanguage}`
const url = `/api/v1/accounts/integration-applications/sdks/?language=${this.currentLanguage}`
this.$axios.get(url).then(res => {
this.readme = res.readme
this.$nextTick(() => {

View File

@@ -1,28 +1,31 @@
<template>
<el-drawer
v-if="iVisible"
:title="$t('Details')"
:visible.sync="iVisible"
append-to-body
destroy-on-close
direction="rtl"
style="z-index: 999"
title="审查"
@open="handleOpen"
>
<div class="drawer-body">
<el-timeline :reverse="true">
<el-timeline-item
v-for="detail in row.details"
:key="detail.datetime"
:icon="getDetailIcon(detail)"
:timestamp="formatTimestamp(detail.datetime)"
:type="getDetailType(detail)"
placement="top"
>
<span v-html="handleDetail(row, detail)" />
</el-timeline-item>
</el-timeline>
</div>
<div class="drawer-footer">
<div v-if="showButtons" class="drawer-footer">
<span class="buttons">
<el-button size="small" type="primary" @click="handleConfirm">确认</el-button>
<el-button size="small">忽略</el-button>
<el-button size="small" type="primary" @click="handleConfirm">{{ $t("Confirm") }}</el-button>
<el-button size="small">{{ $t('Ignore') }}</el-button>
</span>
</div>
</el-drawer>
@@ -30,6 +33,7 @@
<script>
import { toSafeLocalDateStr } from '@/utils/time'
import { riskActions } from './const'
export default {
name: 'ReviewDraw',
@@ -41,10 +45,16 @@ export default {
visible: {
type: Boolean,
default: false
},
showButtons: {
type: Boolean,
default: true
}
},
data() {
return {}
return {
riskActions
}
},
computed: {
iVisible: {
@@ -54,21 +64,59 @@ export default {
set(val) {
this.$emit('update:visible', val)
}
},
actionMap() {
return riskActions.reduce((acc, cur) => {
acc[cur.name] = cur
return acc
}, {})
}
},
mounted() {
},
methods: {
handleOpen() {
},
formatTimestamp(datetime) {
return toSafeLocalDateStr(datetime)
},
handleConfirm() {
},
getDetailIcon(detail) {
if (detail.status === '1') {
return 'el-icon-check'
} else if (detail.status === '0') {
return 'el-icon-close'
}
},
getDetailType(detail) {
if (detail.type !== 'process') {
return ''
}
if (detail.status === '1') {
return 'primary'
} else {
return 'danger'
}
},
handleDetail(row, detail) {
if (!detail.type || ['init', 'refind'].includes(detail.type)) {
return this.handleInit(row, detail)
} else if (detail.type === 'process') {
return this.handleProcess(row, detail)
}
},
handleProcess(row, detail) {
const { action, processor } = detail
const actionLabel = this.actionMap[action]?.label || action
return `${processor} ${actionLabel}`
},
handleInit(row, detail) {
switch (row.risk.value) {
case 'ghost':
return '发现时间: ' + this.formatTimestamp(detail.datetime)
case 'zombie':
return '上次登录时间: ' + this.formatTimestamp(detail.date)
case 'new_found':
return this.$tc('New found')
case 'long_time_no_login':
return this.$tc('Last login time') + ': ' + this.formatTimestamp(detail.date)
case 'group_changed':
case 'sudoers_changed':
case 'authorized_key_changed':
@@ -78,9 +126,9 @@ ${detail.diff}
</pre>
`
case 'long_time_password':
return '上次改密时间: ' + this.formatTimestamp(detail.date)
return this.$t('Last change time') + ': ' + this.formatTimestamp(detail.date)
case 'account_deleted':
return '账号被删除'
return this.$t('Account deleted')
default:
return '其它'
}

View File

@@ -0,0 +1,49 @@
import i18n from '@/i18n/i18n'
export const riskActions = [
{
name: 'disable_remote',
label: i18n.t('Disable remote'),
has: ['long_time_no_login', 'new_found']
},
{
name: 'delete_remote',
label: i18n.t('Delete Account'),
has: ['long_time_no_login', 'new_found']
},
{
name: 'delete_both',
label: i18n.t('Delete Both'),
has: ['long_time_no_login']
},
{
name: 'add_account',
label: i18n.t('Add to Account'),
has: ['new_found'],
disabled: async function() {
const url = `/api/v1/accounts/accounts/?username=${this.row.username}&asset=${this.row.asset.id}`
const data = await this.$axios.get(url)
return data.length > 0
}
},
{
name: 'change_password',
label: i18n.t('Change Password'),
has: ['long_time_password', 'weak_password', 'password_expired']
},
// {
// name: 'addPrivilegedAccount',
// label: i18n.t('Add Privileged Account'),
// has: ['no_admin_account']
// },
// {
// name: 'modifyPassword',
// label: i18n.t('Modify Password'),
// has: ['password_error']
// },
{
name: 'review',
label: i18n.t('Review'),
has: ['group_changed', 'sudo_changed', 'authorized_key_changed', 'account_deleted', 'others']
}
]

View File

@@ -0,0 +1,180 @@
<template>
<span>
<span v-if="iValue === '0'" class="risk-handler">
<el-dropdown trigger="click" @command="handleRisk" @visible-change="handleVisibleChange">
<el-button class="confirm action" size="mini">
<i class="fa fa-check" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item of actions"
:key="item.name"
:command="item.name"
:disabled="item.disabled"
>
{{ item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-tooltip :content="$tc('Ignore')" :open-delay="400">
<el-button class="ignore action" size="mini" @click="handleRisk('ignore')">
<svg-icon icon-class="ignore" />
</el-button>
</el-tooltip>
</span>
<el-tooltip v-else :content="$t('Detail')" :open-delay="400" class="platform-status">
<el-button size="mini" type="text" @click="showDetail">
<i v-if="iValue === '1'" class="fa fa-check color-primary" />
<svg-icon v-else icon-class="ignore" />
{{ iLabel }}
</el-button>
</el-tooltip>
<ReviewDraw :row="row" :show-buttons="reviewButtons" :visible.sync="reviewDrawer" />
<ProcessingDialog :visible="processing" />
</span>
</template>
<script>
import BaseFormatter from '@/components/Table/TableFormatters/base.vue'
import ReviewDraw from '@/views/pam/RiskDetect/RiskHandlerFormatter/ReviewDraw.vue'
import ProcessingDialog from '@/components/Dialog/ProcessingDialog.vue'
import { riskActions } from './const'
export default {
name: 'RiskSummaryFormatter',
components: { ProcessingDialog, ReviewDraw },
extends: BaseFormatter,
props: {
formatterArgsDefault: {
type: Object,
default: () => ({})
}
},
data() {
return {
reviewDrawer: false,
reviewButtons: true,
processing: false,
actions: [],
formatterArgs: Object.assign(this.formatterArgsDefault, this.col.formatterArgs)
}
},
computed: {
iActions() {
return this.getActions()
},
iValue() {
if (this.cellValueIsLabelChoice()) {
return this.cellValue.value
} else {
return this.cellValue
}
},
iLabel() {
if (this.cellValueIsLabelChoice()) {
return this.cellValue.label
} else {
return this.cellValue
}
}
},
methods: {
showDetail() {
this.reviewButtons = false
this.reviewDrawer = true
},
handleReview() {
this.reviewButtons = true
this.reviewDrawer = true
},
async handleCommon(cmd) {
const data = {
username: this.row.username,
asset: this.row.asset.id,
risk: this.row.risk.value,
action: cmd
}
this.processing = true
this.$axios.post(`/api/v1/accounts/account-risks/handle/`, data).then(() => {
if (cmd !== 'ignore') {
this.row.status = { value: '1', label: this.$t('Confirmed') }
} else {
this.row.status = { value: '2', label: this.$t('Ignored') }
}
}).finally(() => {
setTimeout(() => {
this.processing = false
this.$axios.get(`/api/v1/accounts/account-risks/${this.row.id}/`).then((res) => {
Object.assign(this.row, res)
})
}, 500)
})
},
handleRisk(cmd) {
if (cmd === 'review') {
this.handleReview()
} else {
this.handleCommon(cmd)
}
},
async checkDisabled(action) {
let disabled = action.disabled === undefined ? false : action.disabled
if (typeof disabled === 'function') {
disabled = await action.disabled.call(this)
}
return disabled
},
async handleVisibleChange(visible) {
if (!visible) {
return
}
if (this.actions.length === 0) {
this.actions = await this.getActions()
}
return this.actions.length > 0
},
checkHas(action) {
return action.has.includes(this.row.risk.value) || action.name === 'review'
},
async getActions() {
let actions = _.cloneDeep(riskActions)
actions = actions.filter((action) => {
return this.checkHas(action)
})
for (const action of actions) {
action.disabled = await this.checkDisabled(action)
}
return actions
}
}
}
</script>
<style lang='scss' scoped>
.action.el-button--mini {
cursor: pointer;
padding: 1px 4px;
&.confirm {
::v-deep i {
color: var(--color-primary);
}
}
&.remove {
::v-deep i {
color: var(--color-danger);
}
}
&.ignore {
::v-deep svg.svg-icon {
}
}
}
.draw-body {
padding: 20px;
font-size: 13px;
}
</style>

View File

@@ -16,28 +16,28 @@ export default {
activeMenu: 'AccountRisks',
submenu: [
{
title: this.$t('检查结果'),
title: this.$t('DetectResults'),
name: 'AccountRisks',
hidden: !this.$hasPerm('accounts.view_accountrisk'),
component: () => import('@/views/pam/AccountCheck/AccountRiskList.vue')
component: () => import('@/views/pam/RiskDetect/AccountRiskList.vue')
},
{
title: this.$t('检查任务'),
title: this.$t('DetectTasks'),
name: 'AccountCheckTask',
hidden: !this.$hasPerm('accounts.view_accountcheckautomation'),
component: () => import('./AccountCheckTaskList.vue')
},
{
title: this.$t('执行历史'),
title: this.$t('Executions'),
name: 'AccountCheckExecution',
hidden: !this.$hasPerm('accounts.view_accountcheckautomation'),
component: () => import('./AccountCheckExecutionList.vue')
},
{
title: this.$t('检查引擎'),
title: this.$t('DetectEngines'),
name: 'AccountCheckEngine',
hidden: !this.$hasPerm('accounts.view_accountcheckautomation'),
component: () => import('@/views/pam/AccountCheck/AccountCheckEngine.vue')
component: () => import('@/views/pam/RiskDetect/AccountCheckEngine.vue')
}
]
}

View File

@@ -1,49 +0,0 @@
<template>
<TabPage
:active-menu.sync="activeMenu"
:submenu="tab.submenu"
/>
</template>
<script>
import { TabPage } from '@/layout/components'
export default {
name: 'ServiceIntegrationList',
components: {
TabPage
},
data() {
return {
loading: true,
activeMenu: 'service',
tab: {
submenu: [
{
name: 'service',
title: this.$t('RelevantApp'),
hidden: !this.$hasPerm('accounts.view_serviceintegration'),
component: () => import('@/views/pam/ServiceIntegration/ServiceIntegrationList.vue')
},
{
name: 'call-records',
title: this.$t('CallRecords'),
hidden: !this.$hasPerm('audits.view_serviceaccesslog'),
component: () => import('@/views/pam/ServiceIntegration/components/CallRecords.vue')
},
{
name: 'sdk-doc',
title: this.$t('SDK'),
hidden: !this.$hasPerm('accounts.view_serviceintegration'),
component: () => import('@/views/pam/ServiceIntegration/SDKList.vue')
}
]
}
}
},
watch: {},
async mounted() {
},
methods: {}
}
</script>