mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-19 09:43:32 +00:00
Merge pull request #826 from jumpserver/feat_account_manager
feat: 添加账号管理模块
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
<ListTable ref="ListTable" :table-config="iTableConfig" :header-actions="headerActions" />
|
||||
<Dialog v-if="showMFADialog" width="50" :title="this.$t('common.MFAConfirm')" :visible.sync="showMFADialog" :show-confirm="false" :show-cancel="false" :destroy-on-close="true">
|
||||
<div v-if="MFAConfirmed">
|
||||
<el-form label-position="right" label-width="80px" :model="MFAInfo">
|
||||
@@ -93,6 +93,10 @@ export default {
|
||||
hasClone: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
tableConfig: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -114,36 +118,31 @@ export default {
|
||||
password: '',
|
||||
private_key: ''
|
||||
},
|
||||
tableConfig: {
|
||||
defaultTableConfig: {
|
||||
url: this.url,
|
||||
columns: [
|
||||
{
|
||||
prop: 'hostname',
|
||||
columns: ['hostname', 'ip', 'username', 'version', 'date_created', 'actions'],
|
||||
columnsMeta: {
|
||||
'hostname': {
|
||||
label: this.$t('assets.Hostname'),
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'ip',
|
||||
'ip': {
|
||||
label: this.$t('assets.ip'),
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
prop: 'username',
|
||||
'username': {
|
||||
label: this.$t('assets.Username'),
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'version',
|
||||
'version': {
|
||||
label: this.$t('assets.Version'),
|
||||
width: '70px'
|
||||
},
|
||||
{
|
||||
prop: 'date_created',
|
||||
'date_created': {
|
||||
label: this.$t('assets.date_joined'),
|
||||
formatter: DateFormatter
|
||||
},
|
||||
{
|
||||
prop: 'id',
|
||||
'actions': {
|
||||
label: this.$t('common.Action'),
|
||||
align: 'center',
|
||||
width: 150,
|
||||
@@ -211,7 +210,7 @@ export default {
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
extraQuery: {
|
||||
latest: 1
|
||||
}
|
||||
@@ -256,16 +255,19 @@ export default {
|
||||
const ttl = this.publicSettings.SECURITY_MFA_VERIFY_TTL
|
||||
const now = new Date()
|
||||
return !(this.MFAVerifyAt && (now - this.MFAVerifyAt) < ttl * 1000)
|
||||
},
|
||||
iTableConfig() {
|
||||
return Object.assign(this.defaultTableConfig, this.tableConfig)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url(iNew) {
|
||||
this.$set(this.tableConfig, 'url', iNew)
|
||||
this.$set(this.iTableConfig, 'url', iNew)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.otherActions) {
|
||||
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
|
||||
const actionColumn = this.iTableConfig.columns[this.iTableConfig.columns.length - 1]
|
||||
for (const item of this.otherActions) {
|
||||
actionColumn.formatterArgs.extraActions.push(item)
|
||||
}
|
||||
|
@@ -522,6 +522,9 @@
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"Accounts": "账号管理",
|
||||
"AssetAccount": "资产账号",
|
||||
"ApplicationAccount": "应用账号",
|
||||
"Ticket":"工单",
|
||||
"CommandConfirm": "命令复核",
|
||||
"AdminUserCreate": "创建管理用户",
|
||||
|
@@ -520,6 +520,9 @@
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"Accounts": "Accounts",
|
||||
"AssetAccount": "Asset account",
|
||||
"ApplicationAccount": "Application account",
|
||||
"Ticket": "Tickets",
|
||||
"CommandConfirm": "Command confirm",
|
||||
"AdminUserCreate": "Admin user create",
|
||||
|
127
src/router/accounts.js
Normal file
127
src/router/accounts.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import empty from '@/layout/empty'
|
||||
export default [
|
||||
{
|
||||
path: 'asset-accounts',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('route.AssetAccount') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'AssetAccountList',
|
||||
component: () => import('@/views/accounts/AssetAccount/AssetAccountList'),
|
||||
meta: { title: i18n.t('route.AssetAccount') }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: () => import('@/views/accounts/AssetAccount/AssetAccountCreate'),
|
||||
name: 'AssetAccountCreate',
|
||||
meta: { title: i18n.t('common.Create'), activeMenu: '/accounts/asset-accounts/' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'application-accounts',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('route.AssetAccount') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'ApplicationAccountList',
|
||||
component: () => import('@/views/accounts/ApplicationAccount/ApplicationAccountList'),
|
||||
meta: { title: i18n.t('route.ApplicationAccount') }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'gathered-user',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserList') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/accounts/GatheredUser/index'),
|
||||
name: 'GatherUserListIndex',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUser'), activeMenu: '/accounts/gathered-user' }
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/accounts/GatheredUser/GatheredUserList'),
|
||||
name: 'GatherUserList',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserList'), activeMenu: '/accounts/gathered-user' }
|
||||
},
|
||||
{
|
||||
path: 'tasks',
|
||||
component: () => import('@/views/accounts/GatheredUser/TaskList'),
|
||||
name: 'GatherUserTaskList',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskList'), activeMenu: '/accounts/gathered-user' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tasks/:id',
|
||||
component: () => import('@/views/accounts/GatheredUser/TaskDetail/index'),
|
||||
name: 'GatherUserTaskDetail',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskDetail'), activeMenu: '/accounts/gathered-user' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tasks/create',
|
||||
component: () => import('@/views/accounts/GatheredUser/TaskCreateUpdate'),
|
||||
name: 'GatherUserTaskCreate',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskCreate'), activeMenu: '/accounts/gathered-user' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tasks/:id/update',
|
||||
component: () => import('@/views/accounts/GatheredUser/TaskCreateUpdate'),
|
||||
name: 'GatherUserTaskUpdate',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskUpdate'), action: 'update', activeMenu: '/accounts/gathered-user' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'change-auth-plan',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan/plan' },
|
||||
children: [
|
||||
{
|
||||
path: 'plan',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanList.vue'),
|
||||
name: 'ChangeAuthPlanList',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan/plan' }
|
||||
},
|
||||
{
|
||||
path: 'plan/create',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'ChangeAuthPlanCreate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlanCreate'), activeMenu: '/accounts/change-auth-plan/plan', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan/:id/update',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'ChangeAuthPlanUpdate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlanUpdate'), activeMenu: '/accounts/change-auth-plan/plan', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan/:id',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanDetail/index.vue'),
|
||||
name: 'ChangeAuthPlanDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/accounts/change-auth-plan/plan' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan-execution/:id',
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/index.vue'),
|
||||
name: 'ChangeAuthPlanExecutionDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ExecutionDetail'), activeMenu: '/accounts/change-auth-plan/plan' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -37,6 +37,7 @@ import TicketsRoutes from './tickets'
|
||||
import AuditsRoutes from './audits'
|
||||
import commonRoutes from './common'
|
||||
import aclRoutes from './acl'
|
||||
import AccountRoutes from './accounts'
|
||||
|
||||
/**
|
||||
* constantRoutes
|
||||
@@ -110,6 +111,18 @@ export const allRoleRoutes = [
|
||||
meta: { title: i18n.t('route.Applications'), icon: 'th' },
|
||||
children: ApplicationsRoute
|
||||
},
|
||||
{
|
||||
path: '/accounts',
|
||||
component: Layout,
|
||||
redirect: '/accounts/asset-accounts/',
|
||||
name: 'Accounts',
|
||||
meta: {
|
||||
licenseRequired: true,
|
||||
title: i18n.t('route.Accounts'),
|
||||
icon: 'address-book'
|
||||
},
|
||||
children: AccountRoutes
|
||||
},
|
||||
{
|
||||
path: '/perms/',
|
||||
component: Layout,
|
||||
|
@@ -88,11 +88,14 @@ export function toSafeLocalDateStr(d) {
|
||||
}
|
||||
|
||||
export function getApiPath(that) {
|
||||
const pagePath = that.$route.path
|
||||
const isOrgPath = pagePath.split('/').indexOf('orgs') !== -1
|
||||
if (isOrgPath) {
|
||||
return `/api/v1/orgs/orgs/${pagePath.split('/').pop()}/`
|
||||
let pagePath = that.$route.path
|
||||
const pagePathArray = pagePath.split('/')
|
||||
if (pagePathArray.indexOf('orgs') !== -1) {
|
||||
pagePathArray[pagePathArray.indexOf('xpack')] = 'orgs'
|
||||
} else if (pagePathArray.indexOf('gathered-user') !== -1 || pagePathArray.indexOf('change-auth-plan') !== -1) {
|
||||
pagePathArray[pagePathArray.indexOf('accounts')] = 'xpack'
|
||||
}
|
||||
pagePath = pagePathArray.join('/')
|
||||
return `/api/v1${pagePath}/`
|
||||
}
|
||||
|
||||
|
144
src/views/accounts/ApplicationAccount/ApplicationAccountList.vue
Normal file
144
src/views/accounts/ApplicationAccount/ApplicationAccountList.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<Page>
|
||||
<el-row>
|
||||
<el-col :span="14">
|
||||
<GenericListTable
|
||||
ref="LeftTable"
|
||||
class="application-table"
|
||||
:header-actions="leftTable.headerActions"
|
||||
:table-config="leftTable.tableConfig"
|
||||
@row-click="leftTable.tableConfig.rowClick"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<GenericListTable
|
||||
ref="RightTable"
|
||||
class="application-user-table"
|
||||
:header-actions="rightTable.headerActions"
|
||||
:table-config="rightTable.tableConfig"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Page from '@/layout/components/Page'
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import { DetailFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'AssetAccountList',
|
||||
components: {
|
||||
GenericListTable, Page
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
clickedRow: {},
|
||||
leftTable: {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/',
|
||||
columns: [
|
||||
'name', 'category_display', 'type_display', 'created_by', 'date_created', 'date_updated',
|
||||
'comment', 'org_name'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name'],
|
||||
default: ['name', 'category_display', 'type_display']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
getRoute({ row, col, cellValue }) {
|
||||
return {
|
||||
'db': 'DatabaseAppDetail', 'remote_app': 'RemoteAppDetail', 'cloud': 'KubernetesAppDetail'
|
||||
}[row.category]
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
if (row === vm.clickedRow) {
|
||||
return 'row-clicked'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
rowClick: function(row, column, event) {
|
||||
vm.rightTable.tableConfig.url = `/api/v1/applications/application-users/?application_id=${row.id}`
|
||||
vm.clickedRow = row
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: false,
|
||||
hasCreate: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
},
|
||||
rightTable: {
|
||||
tableConfig: {
|
||||
url: `/api/v1/applications/application-users/?application_id=`,
|
||||
columns: [
|
||||
'name', 'username', 'username_same_with_user', 'protocol', 'login_mode',
|
||||
'assets_amount', 'priority',
|
||||
'created_by', 'date_created', 'date_updated', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'username', 'actions'],
|
||||
default: ['name', 'username', 'date_created', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'SystemUserDetail'
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
hasUpdate: true, // can set function(row, value)
|
||||
hasDelete: false, // can set function(row, value)
|
||||
hasClone: false,
|
||||
onUpdate({ row, col }) {
|
||||
vm.$router.push({ name: 'SystemUserUpdate', params: { id: row.id }, query: { protocol: row.protocol }})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
return 'row-background-color'
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: false,
|
||||
hasImport: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.application-table ::v-deep .row-clicked, .application-user-table ::v-deep .row-background-color {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
</style>
|
184
src/views/accounts/AssetAccount/AssetAccountList.vue
Normal file
184
src/views/accounts/AssetAccount/AssetAccountList.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<Page>
|
||||
<el-row>
|
||||
<el-col v-show="iShowTree" :span="iShowTree?4:0">
|
||||
<AutoDataZTree
|
||||
ref="AUtoDataZTree"
|
||||
:setting="treeSetting"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="iShowTree?12:14">
|
||||
<div class="mini">
|
||||
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
|
||||
<i v-show="iShowTree" class="fa fa-angle-left fa-x" /><i v-show="!iShowTree" class="fa fa-angle-right fa-x" />
|
||||
</div>
|
||||
</div>
|
||||
<GenericListTable
|
||||
ref="LeftTable"
|
||||
class="asset-table"
|
||||
:header-actions="leftTable.headerActions"
|
||||
:table-config="leftTable.tableConfig"
|
||||
@row-click="leftTable.tableConfig.rowClick"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="iShowTree?8:10">
|
||||
<AssetUserTable
|
||||
ref="RightTable"
|
||||
class="asset-user-table"
|
||||
:url="rightTable.url"
|
||||
:has-left-actions="true"
|
||||
:table-config="rightTable.tableConfig"
|
||||
:has-clone="false"
|
||||
:has-import="false"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Page from '@/layout/components/Page'
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import AutoDataZTree from '@/components/AutoDataZTree/index'
|
||||
import { AssetUserTable } from '@/components'
|
||||
import { ChoicesFormatter, DetailFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'AssetAccountList',
|
||||
components: {
|
||||
AutoDataZTree, GenericListTable, Page, AssetUserTable
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
clickedRow: {},
|
||||
iShowTree: true,
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showRefresh: false,
|
||||
showAssets: false,
|
||||
url: '',
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/',
|
||||
callback: {
|
||||
onSelected: function(event, treeNode) {
|
||||
vm.leftTable.tableConfig.url = `/api/v1/assets/assets/?node_id=${treeNode.meta.node.id}`
|
||||
}
|
||||
}
|
||||
},
|
||||
leftTable: {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/',
|
||||
columns: [
|
||||
'hostname', 'ip', 'public_ip', 'admin_user_display',
|
||||
'protocols', 'platform', 'connectivity',
|
||||
'created_by', 'date_created', 'comment', 'org_name'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['hostname', 'ip', 'platform'],
|
||||
default: ['hostname', 'ip', 'connectivity', 'platform']
|
||||
},
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetDetail',
|
||||
routeQuery: {
|
||||
activeTab: 'Detail'
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
connectivity: {
|
||||
label: this.$t('assets.Reachable'),
|
||||
formatter: ChoicesFormatter,
|
||||
formatterArgs: {
|
||||
iconChoices: {
|
||||
0: 'fa-times text-danger',
|
||||
1: 'fa-check text-primary',
|
||||
2: 'fa-circle text-warning'
|
||||
},
|
||||
typeChange: function(val) {
|
||||
if (!val) {
|
||||
return 2
|
||||
}
|
||||
return val.status
|
||||
},
|
||||
hasTips: true
|
||||
},
|
||||
width: '90px',
|
||||
align: 'center'
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
if (row === vm.clickedRow) {
|
||||
return 'row-clicked'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
rowClick: function(row, column, event) {
|
||||
vm.rightTable.url = `/api/v1/assets/asset-users/?asset_id=${row.id}&latest=1`
|
||||
vm.clickedRow = row
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: true,
|
||||
hasCreate: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
},
|
||||
rightTable: {
|
||||
url: `/api/v1/assets/asset-users/?hostname=ShowFirstAssetRelated&latest=1`,
|
||||
tableConfig: {
|
||||
columns: ['name', 'username', 'version', 'backend', 'backend_display', 'date_created', 'actions'],
|
||||
columnsShow: {
|
||||
min: ['username', 'actions'],
|
||||
default: ['name', 'username', 'version', 'backend_display', 'date_created', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: null,
|
||||
showOverflowTooltip: true
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
return 'row-background-color'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asset-table ::v-deep .row-clicked, .asset-user-table ::v-deep .row-background-color {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.mini-button{
|
||||
width: 12px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
background-color: #1ab394;
|
||||
border-color: #1ab394;
|
||||
color: #FFFFFF;
|
||||
border-radius: 3px;
|
||||
line-height: 1.428;
|
||||
cursor:pointer;
|
||||
}
|
||||
</style>
|
192
src/views/accounts/GatheredUser/GatheredUserList.vue
Normal file
192
src/views/accounts/GatheredUser/GatheredUserList.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col v-show="iShowTree" :span="iShowTree?4:0">
|
||||
<AutoDataZTree
|
||||
ref="AUtoDataZTree"
|
||||
:setting="treeSetting"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="iShowTree?12:14">
|
||||
<div class="mini">
|
||||
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
|
||||
<i v-show="iShowTree" class="fa fa-angle-left fa-x" /><i v-show="!iShowTree" class="fa fa-angle-right fa-x" />
|
||||
</div>
|
||||
</div>
|
||||
<GenericListTable
|
||||
ref="LeftTable"
|
||||
class="asset-table"
|
||||
:header-actions="leftTable.headerActions"
|
||||
:table-config="leftTable.tableConfig"
|
||||
@row-click="leftTable.tableConfig.rowClick"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="iShowTree?8:10">
|
||||
<AssetUserTable
|
||||
ref="RightTable"
|
||||
class="asset-user-table"
|
||||
:url="rightTable.url"
|
||||
:has-left-actions="true"
|
||||
:table-config="rightTable.tableConfig"
|
||||
:has-clone="false"
|
||||
:has-import="false"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import AutoDataZTree from '@/components/AutoDataZTree/index'
|
||||
import { AssetUserTable } from '@/components'
|
||||
import { ChoicesFormatter, DetailFormatter } from '@/components/TableFormatters'
|
||||
|
||||
export default {
|
||||
name: 'AssetAccountList',
|
||||
components: {
|
||||
AutoDataZTree, GenericListTable, AssetUserTable
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
clickedRow: {},
|
||||
iShowTree: true,
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showRefresh: false,
|
||||
showAssets: false,
|
||||
url: '',
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/',
|
||||
callback: {
|
||||
onSelected: function(event, treeNode) {
|
||||
vm.leftTable.tableConfig.url = `/api/v1/assets/assets/?node_id=${treeNode.meta.node.id}`
|
||||
}
|
||||
}
|
||||
},
|
||||
leftTable: {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/',
|
||||
columns: [
|
||||
'hostname', 'ip', 'public_ip', 'admin_user_display',
|
||||
'protocols', 'platform', 'connectivity',
|
||||
'created_by', 'date_created', 'comment', 'org_name'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['hostname', 'ip', 'platform'],
|
||||
default: ['hostname', 'ip', 'connectivity', 'platform']
|
||||
},
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetDetail',
|
||||
routeQuery: {
|
||||
activeTab: 'Detail'
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
connectivity: {
|
||||
label: this.$t('assets.Reachable'),
|
||||
formatter: ChoicesFormatter,
|
||||
formatterArgs: {
|
||||
iconChoices: {
|
||||
0: 'fa-times text-danger',
|
||||
1: 'fa-check text-primary',
|
||||
2: 'fa-circle text-warning'
|
||||
},
|
||||
typeChange: function(val) {
|
||||
if (!val) {
|
||||
return 2
|
||||
}
|
||||
return val.status
|
||||
},
|
||||
hasTips: true
|
||||
},
|
||||
width: '90px',
|
||||
align: 'center'
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
if (row === vm.clickedRow) {
|
||||
return 'row-clicked'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
rowClick: function(row, column, event) {
|
||||
vm.rightTable.url = `/api/v1/assets/gathered-users/?asset_id=${row.id}`
|
||||
vm.clickedRow = row
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: true,
|
||||
hasCreate: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false
|
||||
}
|
||||
},
|
||||
rightTable: {
|
||||
url: `/api/v1/assets/gathered-users/?asset__hostname=ShowFirstAssetRelated`,
|
||||
tableConfig: {
|
||||
columns: [
|
||||
'username', 'date_last_login', 'present', 'ip_last_login', 'date_updated'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['username'],
|
||||
default: [
|
||||
'username', 'date_last_login', 'present', 'ip_last_login', 'date_updated'
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
username: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
present: {
|
||||
width: 80
|
||||
},
|
||||
ip_last_login: {
|
||||
width: 120
|
||||
}
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: false, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true, // 宽度自适应,
|
||||
tooltipEffect: 'dark',
|
||||
rowClassName({ row, rowIndex }) {
|
||||
return 'row-background-color'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asset-table ::v-deep .row-clicked, .asset-user-table ::v-deep .row-background-color {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.mini-button{
|
||||
width: 12px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
background-color: #1ab394;
|
||||
border-color: #1ab394;
|
||||
color: #FFFFFF;
|
||||
border-radius: 3px;
|
||||
line-height: 1.428;
|
||||
cursor:pointer;
|
||||
}
|
||||
</style>
|
@@ -1,78 +0,0 @@
|
||||
<template>
|
||||
<TreeTable :table-config="tableConfig" :tree-setting="treeSetting" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TreeTable from '@/components/TreeTable'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TreeTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showRefresh: true,
|
||||
showAssets: true,
|
||||
url: '/api/v1/assets/gathered-users/',
|
||||
nodeUrl: '/api/v1/assets/nodes/',
|
||||
// ?assets=0不显示资产. =1显示资产
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1'
|
||||
},
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/gathered-users/',
|
||||
hasTree: true,
|
||||
columns: [
|
||||
'hostname', 'ip', 'username', 'date_last_login', 'present',
|
||||
'ip_last_login', 'date_updated'
|
||||
],
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
ip: {
|
||||
width: 120
|
||||
},
|
||||
username: {
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
present: {
|
||||
width: 80
|
||||
},
|
||||
ip_last_login: {
|
||||
width: 120
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasCreate: false,
|
||||
hasLeftActions: false,
|
||||
hasImport: false,
|
||||
searchConfig: {
|
||||
exclude: ['asset'],
|
||||
options: [
|
||||
{
|
||||
label: this.$t('assets.Hostname'),
|
||||
value: 'asset__hostname'
|
||||
},
|
||||
{
|
||||
label: 'IP',
|
||||
value: 'asset__ip'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onGatherUserTasks() {
|
||||
this.$router.push({ name: 'GatherUserTaskList' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
@@ -1,340 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<GenericTreeListPage ref="TreeTablePage" :tree-setting="treeSetting">
|
||||
<template #table>
|
||||
<AssetUserTable ref="table" v-bind="assetUserConfig" />
|
||||
</template>
|
||||
</GenericTreeListPage>
|
||||
<Dialog width="50" :title="this.$t('common.MFAConfirm')" :visible.sync="showMFADialog" :show-confirm="false" :show-cancel="false" :destroy-on-close="true">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div style="line-height: 34px;text-align: center">MFA</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-input v-model="MFAInput" />
|
||||
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="MFAConfirm">{{ this.$t('common.Confirm') }}</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
<Dialog :title="$t('common.Export')" :visible.sync="showExportDialog" @confirm="handleExportConfirm()" @cancel="handleExportCancel()">
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
|
||||
<el-radio v-model="exportOption" class="export-item" label="1">{{ this.$t('common.imExport.ExportAll') }}</el-radio>
|
||||
<br>
|
||||
<el-radio v-model="exportOption" :disabled="selectedRows.length===0" class="export-item" label="2">{{ this.$t('common.imExport.ExportOnlySelectedItems') }}</el-radio>
|
||||
<br>
|
||||
<!-- 去掉导出搜索项-->
|
||||
<!-- <el-radio v-model="exportOption" disabled class="export-item" label="3">{{ this.$t('common.imExport.ExportOnlyFiltered') }}</el-radio>-->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
<Dialog :title="$t('common.Import')" :visible.sync="showImportDialog" @confirm="handleImportConfirm()" @cancel="handleImportCancel()">
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.Import' )" :label-width="'100px'">
|
||||
<el-radio v-model="importOption" class="export-item" label="1">{{ this.$t('common.Create') }}</el-radio>
|
||||
<el-radio v-model="importOption" disabled class="export-item" label="2">{{ this.$t('common.Update') }}</el-radio>
|
||||
<div style="line-height: 1.5">
|
||||
<span v-if="importOption==='1'" class="el-upload__tip">
|
||||
{{ this.$t('common.imExport.downloadImportTemplateMsg') }}
|
||||
<el-link type="success" :underline="false" :href="downloadImportTempUrl">{{ this.$t('common.Download') }}</el-link>
|
||||
</span>
|
||||
<span v-else class="el-upload__tip">`
|
||||
{{ this.$t('common.imExport.downloadUpdateTemplateMsg') }}
|
||||
<el-link type="success" :underline="false" @click="downloadUpdateTempUrl">{{ this.$t('common.Download') }}</el-link>
|
||||
</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('common.Upload' )" :label-width="'100px'">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
action="string"
|
||||
:http-request="handleImport"
|
||||
list-type="text/csv"
|
||||
:limit="1"
|
||||
:auto-upload="false"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<el-button size="mini" type="default">{{ this.$t('common.SelectFile') }}</el-button>
|
||||
<div slot="tip" :class="uploadHelpTextClass" style="line-height: 1.5">{{ this.$t('common.imExport.onlyCSVFilesTips') }}</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div v-if="errorMsg" class="error-msg error-results">
|
||||
<ul v-if="typeof errorMsg === 'object'">
|
||||
<li v-for="(item, index) in errorMsg" :key="item + '-' + index"> {{ item }}</li>
|
||||
</ul>
|
||||
<span v-else>{{ errorMsg }}</span>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage'
|
||||
import { AssetUserTable } from '@/components'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { setUrlParam } from '@/utils/common'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
import * as queryUtil from '@/components/DataTable/compenents/el-data-table/utils/query'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'VaultList',
|
||||
components: {
|
||||
GenericTreeListPage,
|
||||
AssetUserTable,
|
||||
Dialog
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
showImportDialog: false,
|
||||
importOption: '1',
|
||||
isCsv: true,
|
||||
errorMsg: '',
|
||||
showExportDialog: false,
|
||||
exportOption: '1',
|
||||
meta: {},
|
||||
MfaExpired: 0,
|
||||
showMFADialog: false,
|
||||
MFAInput: '',
|
||||
selectedRows: '',
|
||||
assetUserConfig: {
|
||||
hasLeftActions: true,
|
||||
hasCreate: true,
|
||||
hasClone: false,
|
||||
url: '/api/v1/assets/asset-users/',
|
||||
handleImport: function({ selectedRows }) {
|
||||
this.selectedRows = selectedRows
|
||||
this.dialogStatus = 'import'
|
||||
if (!this.needMFAVerify) {
|
||||
this.showMFADialog = false
|
||||
this.showImportDialog = true
|
||||
} else {
|
||||
this.showMFADialog = true
|
||||
}
|
||||
}.bind(this),
|
||||
handleExport: function({ selectedRows }) {
|
||||
this.selectedRows = selectedRows
|
||||
this.dialogStatus = 'export'
|
||||
if (!this.needMFAVerify) {
|
||||
this.showMFADialog = false
|
||||
this.showExportDialog = true
|
||||
} else {
|
||||
this.showMFADialog = true
|
||||
}
|
||||
}.bind(this)
|
||||
},
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showRefresh: false,
|
||||
showAssets: true,
|
||||
url: '/api/v1/assets/asset-users/',
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=1',
|
||||
callback: {
|
||||
onSelected: function(event, treeNode) {
|
||||
let url = vm.assetUserConfig.url
|
||||
if (treeNode.meta.type === 'node') {
|
||||
const nodeId = treeNode.meta.node.id
|
||||
url = setUrlParam(url, 'asset_id', '')
|
||||
url = setUrlParam(url, 'node_id', nodeId)
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
const assetId = treeNode.meta.asset.id
|
||||
url = setUrlParam(url, 'node_id', '')
|
||||
url = setUrlParam(url, 'asset_id', assetId)
|
||||
}
|
||||
setTimeout(() => {
|
||||
vm.assetUserConfig.url = url
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'MFA_TTl',
|
||||
'MFAVerifyAt',
|
||||
'publicSettings'
|
||||
]),
|
||||
needMFAVerify() {
|
||||
if (!this.publicSettings.SECURITY_VIEW_AUTH_NEED_MFA) {
|
||||
return false
|
||||
}
|
||||
const ttl = this.publicSettings.SECURITY_MFA_VERIFY_TTL
|
||||
const now = new Date()
|
||||
return !(this.MFAVerifyAt && (now - this.MFAVerifyAt) < ttl * 1000)
|
||||
},
|
||||
hasSelected() {
|
||||
return this.selectedRows.length > 0
|
||||
},
|
||||
upLoadUrl() {
|
||||
return this.url
|
||||
},
|
||||
downloadImportTempUrl() {
|
||||
const baseUrl = `/api/v1/assets/asset-user-auth-infos/`
|
||||
return baseUrl + '?format=csv&template=import&limit=1'
|
||||
},
|
||||
uploadHelpTextClass() {
|
||||
const cls = ['el-upload__tip']
|
||||
if (!this.isCsv) {
|
||||
cls.push('error-msg')
|
||||
}
|
||||
return cls
|
||||
},
|
||||
...mapGetters([
|
||||
'MFAVerifyAt',
|
||||
'MFA_TTl'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
performUpdate(item) {
|
||||
this.$axios.put(
|
||||
`/api/v1/assets/asset-users/`,
|
||||
item.file,
|
||||
{ headers: { 'Content-Type': 'text/csv' }, disableFlashErrorMsg: true }
|
||||
).then((data) => {
|
||||
const msg = this.$t('common.imExport.updateSuccessMsg', { count: data.length })
|
||||
this.onSuccess(msg)
|
||||
}).catch(error => {
|
||||
this.catchError(error)
|
||||
})
|
||||
},
|
||||
performCreate(item) {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/asset-users/`,
|
||||
item.file,
|
||||
{ headers: { 'Content-Type': 'text/csv' }, disableFlashErrorMsg: true }
|
||||
).then((data) => {
|
||||
const msg = this.$t('common.imExport.createSuccessMsg', { count: data.length })
|
||||
this.onSuccess(msg)
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg') + ' ' + error)
|
||||
this.catchError(error)
|
||||
})
|
||||
},
|
||||
catchError(error) {
|
||||
this.$refs.upload.clearFiles()
|
||||
if (error.response && error.response.status === 400) {
|
||||
const errorData = error.response.data
|
||||
const totalErrorMsg = []
|
||||
errorData.forEach((value, index) => {
|
||||
if (typeof value === 'string') {
|
||||
totalErrorMsg.push(`line ${index}. ${value}`)
|
||||
} else {
|
||||
const errorMsg = [`line ${index}. `]
|
||||
for (const [k, v] of Object.entries(value)) {
|
||||
if (v) {
|
||||
errorMsg.push(`${k}: ${v}`)
|
||||
}
|
||||
}
|
||||
if (errorMsg.length > 1) {
|
||||
totalErrorMsg.push(errorMsg.join(' '))
|
||||
}
|
||||
}
|
||||
})
|
||||
this.errorMsg = totalErrorMsg
|
||||
}
|
||||
},
|
||||
onSuccess(msg) {
|
||||
this.errorMsg = ''
|
||||
this.$message.success(msg)
|
||||
},
|
||||
handleImport(item) {
|
||||
if (this.importOption === '1') {
|
||||
this.performCreate(item)
|
||||
} else {
|
||||
this.performUpdate(item)
|
||||
}
|
||||
},
|
||||
async downloadUpdateTempUrl() {
|
||||
var resources = []
|
||||
const data = this.selectedRows
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
resources.push(data[index].id)
|
||||
}
|
||||
const spm = await createSourceIdCache(resources)
|
||||
const baseUrl = `/api/v1/assets/asset-user-auth-infos/`
|
||||
const url = `${baseUrl}?format=csv&template=update&spm=` + spm.spm
|
||||
return this.downloadCsv(url)
|
||||
},
|
||||
async handleImportConfirm() {
|
||||
this.$refs.upload.submit()
|
||||
this.showImportDialog = false
|
||||
},
|
||||
handleImportCancel() {
|
||||
this.showImportDialog = false
|
||||
},
|
||||
beforeUpload(file) {
|
||||
this.isCsv = _.endsWith(file.name, 'csv')
|
||||
return this.isCsv
|
||||
},
|
||||
downloadCsv(url) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
},
|
||||
async handleExport() {
|
||||
const url = `/api/v1/assets/asset-user-auth-infos/`
|
||||
let query = {}
|
||||
if (this.exportOption === '2') {
|
||||
const resources = []
|
||||
const data = this.selectedRows
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
resources.push(data[index].id)
|
||||
}
|
||||
const spm = await createSourceIdCache(resources)
|
||||
query['spm'] = spm.spm
|
||||
} else if (this.exportOption === '3') {
|
||||
const listTableRef = this.$parent.$parent.$parent.$parent
|
||||
// console.log(listTableRef)
|
||||
// console.log(listTableRef.dataTable)
|
||||
query = listTableRef.dataTable.getQuery()
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
}
|
||||
query['format'] = 'csv'
|
||||
const queryStr =
|
||||
(url.indexOf('?') > -1 ? '&' : '?') +
|
||||
queryUtil.stringify(query, '=', '&')
|
||||
return this.downloadCsv(url + queryStr)
|
||||
},
|
||||
async handleExportConfirm() {
|
||||
await this.handleExport()
|
||||
this.showExportDialog = false
|
||||
},
|
||||
handleExportCancel() {
|
||||
this.showExportDialog = false
|
||||
},
|
||||
MFAConfirm() {
|
||||
if (this.MFAInput.length !== 6) {
|
||||
return this.$message.error(this.$t('common.MFAErrorMsg'))
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/otp/verify/`, {
|
||||
code: this.MFAInput
|
||||
}
|
||||
).then(
|
||||
res => {
|
||||
this.$store.dispatch('users/setMFAVerify')
|
||||
if (this.dialogStatus === 'import') {
|
||||
this.showMFADialog = false
|
||||
this.showImportDialog = true
|
||||
} else {
|
||||
this.showMFADialog = false
|
||||
this.showExportDialog = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -10,47 +10,6 @@ export default {
|
||||
name: 'Xpack',
|
||||
meta: { title: 'X-Pack', icon: 'sitemap', licenseRequired: true },
|
||||
children: [
|
||||
{
|
||||
path: 'change-auth-plan',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/xpack/change-auth-plan/plan' },
|
||||
children: [
|
||||
{
|
||||
path: 'plan',
|
||||
component: () => import('@/views/xpack/ChangeAuthPlan/ChangeAuthPlanList.vue'),
|
||||
name: 'ChangeAuthPlanList',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/xpack/change-auth-plan/plan' }
|
||||
},
|
||||
{
|
||||
path: 'plan/create',
|
||||
component: () => import('@/views/xpack/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'ChangeAuthPlanCreate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlanCreate'), activeMenu: '/xpack/change-auth-plan/plan', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan/:id/update',
|
||||
component: () => import('@/views/xpack/ChangeAuthPlan/ChangeAuthPlanCreateUpdate.vue'),
|
||||
name: 'ChangeAuthPlanUpdate',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlanUpdate'), activeMenu: '/xpack/change-auth-plan/plan', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan/:id',
|
||||
component: () => import('@/views/xpack/ChangeAuthPlan/ChangeAuthPlanDetail/index.vue'),
|
||||
name: 'ChangeAuthPlanDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ChangeAuthPlan'), activeMenu: '/xpack/change-auth-plan/plan' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'plan-execution/:id',
|
||||
component: () => import('@/views/xpack/ChangeAuthPlan/ChangeAuthPlanDetail/ChangeAuthPlanExecution/ChangeAuthPlanExecutionDetail/index.vue'),
|
||||
name: 'ChangeAuthPlanExecutionDetail',
|
||||
meta: { title: i18n.t('xpack.ChangeAuthPlan.ExecutionDetail'), activeMenu: '/xpack/change-auth-plan/plan' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'cloud',
|
||||
component: empty,
|
||||
@@ -127,55 +86,6 @@ export default {
|
||||
name: 'InterfaceSetting',
|
||||
meta: { title: i18n.t('xpack.InterfaceSettings'), permissions: [rolec.PERM_SUPER] }
|
||||
},
|
||||
{
|
||||
path: 'gathered-user',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserList') },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/xpack/GatheredUser/index'),
|
||||
name: 'GatherUserListIndex',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUser'), activeMenu: '/xpack/gathered-user' }
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/xpack/GatheredUser/GatheredUserList'),
|
||||
name: 'GatherUserList',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserList'), activeMenu: '/xpack/gathered-user' }
|
||||
},
|
||||
{
|
||||
path: 'tasks',
|
||||
component: () => import('@/views/xpack/GatheredUser/TaskList'),
|
||||
name: 'GatherUserTaskList',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskList'), activeMenu: '/xpack/gathered-user' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tasks/:id',
|
||||
component: () => import('@/views/xpack/GatheredUser/TaskDetail/index'),
|
||||
name: 'GatherUserTaskDetail',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskDetail'), activeMenu: '/xpack/gathered-user' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tasks/create',
|
||||
component: () => import('@/views/xpack/GatheredUser/TaskCreateUpdate'),
|
||||
name: 'GatherUserTaskCreate',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskCreate'), activeMenu: '/xpack/gathered-user' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tasks/:id/update',
|
||||
component: () => import('@/views/xpack/GatheredUser/TaskCreateUpdate'),
|
||||
name: 'GatherUserTaskUpdate',
|
||||
meta: { title: i18n.t('xpack.GatherUser.GatherUserTaskUpdate'), action: 'update', activeMenu: '/xpack/gathered-user' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'orgs',
|
||||
component: empty,
|
||||
@@ -211,27 +121,6 @@ export default {
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'vault',
|
||||
component: empty,
|
||||
redirect: '',
|
||||
meta: { },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/xpack/Vault/VaultList.vue'),
|
||||
name: 'VaultList',
|
||||
meta: { title: i18n.t('xpack.Vault.Vault'), activeMenu: '/xpack/vault' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: () => import('@/views/xpack/Vault/VaultCreate'),
|
||||
name: 'VaultCreate',
|
||||
meta: { title: i18n.t('xpack.Vault.Create'), activeMenu: '/xpack/vault' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'system-monitor',
|
||||
component: () => import('@/views/xpack/SystemMonitor/index.vue'),
|
||||
|
Reference in New Issue
Block a user