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>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<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">
|
<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">
|
<div v-if="MFAConfirmed">
|
||||||
<el-form label-position="right" label-width="80px" :model="MFAInfo">
|
<el-form label-position="right" label-width="80px" :model="MFAInfo">
|
||||||
@@ -93,6 +93,10 @@ export default {
|
|||||||
hasClone: {
|
hasClone: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -114,36 +118,31 @@ export default {
|
|||||||
password: '',
|
password: '',
|
||||||
private_key: ''
|
private_key: ''
|
||||||
},
|
},
|
||||||
tableConfig: {
|
defaultTableConfig: {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
columns: [
|
columns: ['hostname', 'ip', 'username', 'version', 'date_created', 'actions'],
|
||||||
{
|
columnsMeta: {
|
||||||
prop: 'hostname',
|
'hostname': {
|
||||||
label: this.$t('assets.Hostname'),
|
label: this.$t('assets.Hostname'),
|
||||||
showOverflowTooltip: true
|
showOverflowTooltip: true
|
||||||
},
|
},
|
||||||
{
|
'ip': {
|
||||||
prop: 'ip',
|
|
||||||
label: this.$t('assets.ip'),
|
label: this.$t('assets.ip'),
|
||||||
width: '120px'
|
width: '120px'
|
||||||
},
|
},
|
||||||
{
|
'username': {
|
||||||
prop: 'username',
|
|
||||||
label: this.$t('assets.Username'),
|
label: this.$t('assets.Username'),
|
||||||
showOverflowTooltip: true
|
showOverflowTooltip: true
|
||||||
},
|
},
|
||||||
{
|
'version': {
|
||||||
prop: 'version',
|
|
||||||
label: this.$t('assets.Version'),
|
label: this.$t('assets.Version'),
|
||||||
width: '70px'
|
width: '70px'
|
||||||
},
|
},
|
||||||
{
|
'date_created': {
|
||||||
prop: 'date_created',
|
|
||||||
label: this.$t('assets.date_joined'),
|
label: this.$t('assets.date_joined'),
|
||||||
formatter: DateFormatter
|
formatter: DateFormatter
|
||||||
},
|
},
|
||||||
{
|
'actions': {
|
||||||
prop: 'id',
|
|
||||||
label: this.$t('common.Action'),
|
label: this.$t('common.Action'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 150,
|
width: 150,
|
||||||
@@ -211,7 +210,7 @@ export default {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
extraQuery: {
|
extraQuery: {
|
||||||
latest: 1
|
latest: 1
|
||||||
}
|
}
|
||||||
@@ -256,16 +255,19 @@ export default {
|
|||||||
const ttl = this.publicSettings.SECURITY_MFA_VERIFY_TTL
|
const ttl = this.publicSettings.SECURITY_MFA_VERIFY_TTL
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
return !(this.MFAVerifyAt && (now - this.MFAVerifyAt) < ttl * 1000)
|
return !(this.MFAVerifyAt && (now - this.MFAVerifyAt) < ttl * 1000)
|
||||||
|
},
|
||||||
|
iTableConfig() {
|
||||||
|
return Object.assign(this.defaultTableConfig, this.tableConfig)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
url(iNew) {
|
url(iNew) {
|
||||||
this.$set(this.tableConfig, 'url', iNew)
|
this.$set(this.iTableConfig, 'url', iNew)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.otherActions) {
|
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) {
|
for (const item of this.otherActions) {
|
||||||
actionColumn.formatterArgs.extraActions.push(item)
|
actionColumn.formatterArgs.extraActions.push(item)
|
||||||
}
|
}
|
||||||
|
@@ -522,6 +522,9 @@
|
|||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"": "",
|
"": "",
|
||||||
|
"Accounts": "账号管理",
|
||||||
|
"AssetAccount": "资产账号",
|
||||||
|
"ApplicationAccount": "应用账号",
|
||||||
"Ticket":"工单",
|
"Ticket":"工单",
|
||||||
"CommandConfirm": "命令复核",
|
"CommandConfirm": "命令复核",
|
||||||
"AdminUserCreate": "创建管理用户",
|
"AdminUserCreate": "创建管理用户",
|
||||||
|
@@ -520,6 +520,9 @@
|
|||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"": "",
|
"": "",
|
||||||
|
"Accounts": "Accounts",
|
||||||
|
"AssetAccount": "Asset account",
|
||||||
|
"ApplicationAccount": "Application account",
|
||||||
"Ticket": "Tickets",
|
"Ticket": "Tickets",
|
||||||
"CommandConfirm": "Command confirm",
|
"CommandConfirm": "Command confirm",
|
||||||
"AdminUserCreate": "Admin user create",
|
"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 AuditsRoutes from './audits'
|
||||||
import commonRoutes from './common'
|
import commonRoutes from './common'
|
||||||
import aclRoutes from './acl'
|
import aclRoutes from './acl'
|
||||||
|
import AccountRoutes from './accounts'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constantRoutes
|
* constantRoutes
|
||||||
@@ -110,6 +111,18 @@ export const allRoleRoutes = [
|
|||||||
meta: { title: i18n.t('route.Applications'), icon: 'th' },
|
meta: { title: i18n.t('route.Applications'), icon: 'th' },
|
||||||
children: ApplicationsRoute
|
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/',
|
path: '/perms/',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
@@ -88,11 +88,14 @@ export function toSafeLocalDateStr(d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getApiPath(that) {
|
export function getApiPath(that) {
|
||||||
const pagePath = that.$route.path
|
let pagePath = that.$route.path
|
||||||
const isOrgPath = pagePath.split('/').indexOf('orgs') !== -1
|
const pagePathArray = pagePath.split('/')
|
||||||
if (isOrgPath) {
|
if (pagePathArray.indexOf('orgs') !== -1) {
|
||||||
return `/api/v1/orgs/orgs/${pagePath.split('/').pop()}/`
|
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}/`
|
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',
|
name: 'Xpack',
|
||||||
meta: { title: 'X-Pack', icon: 'sitemap', licenseRequired: true },
|
meta: { title: 'X-Pack', icon: 'sitemap', licenseRequired: true },
|
||||||
children: [
|
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',
|
path: 'cloud',
|
||||||
component: empty,
|
component: empty,
|
||||||
@@ -127,55 +86,6 @@ export default {
|
|||||||
name: 'InterfaceSetting',
|
name: 'InterfaceSetting',
|
||||||
meta: { title: i18n.t('xpack.InterfaceSettings'), permissions: [rolec.PERM_SUPER] }
|
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',
|
path: 'orgs',
|
||||||
component: empty,
|
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',
|
path: 'system-monitor',
|
||||||
component: () => import('@/views/xpack/SystemMonitor/index.vue'),
|
component: () => import('@/views/xpack/SystemMonitor/index.vue'),
|
||||||
|
Reference in New Issue
Block a user