Merge branch 'master' of github.com:jumpserver/lina

This commit is contained in:
ibuler
2020-04-22 17:44:03 +08:00
36 changed files with 440 additions and 1415 deletions

View File

@@ -0,0 +1,61 @@
<template>
<el-card class="box-card primary box-margin">
<div slot="header" class="clearfix">
<i v-if="icon" :class="'fa ' + icon" />
<span>{{ title }}</span>
</div>
<div>
<el-table class="el-table" :data="content" :show-header="false">
<el-table-column prop="name" />
<el-table-column prop="is_active" align="right">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_active"
active-color="#1ab394"
inactive-color="#ff4949"
@change="HandleChangeAction(scope.$index, scope.row)"
/>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</template>
<script>
export default {
name: 'ActiveCard',
props: {
title: {
type: String,
default: ''
},
icon: {
type: String,
default: ''
},
content: {
type: Array,
default: () => []
},
url: {
type: String,
default: ''
}
},
methods: {
HandleChangeAction(index, row) {
this.$axios.patch(
this.url,
{ is_active: row.is_active }
).then(res => {
this.$message(this.$tc('Update success'))
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -30,7 +30,7 @@ export default {
},
methods: {
optionUrlMeta() {
const url = `${this.config.url}?draw=1&display=1`
const url = (this.config.url.indexOf('?') === -1) ? `${this.config.url}?draw=1&display=1` : `${this.config.url}&draw=1&display=1`
optionUrlMeta(url).then(data => {
this.meta = data.actions[this.method.toUpperCase()] || {}
this.generateColumns()

View File

@@ -3,7 +3,7 @@
<span v-show="row.users.length"><label>{{ this.$t('perms.User') }}:</label>{{ format(row.users) }}<br></span>
<span v-show="row.user_groups.length"><label>{{ this.$t('perms.UserGroups') }}:</label>{{ format(row.user_groups) }}<br></span>
<span v-show="row.assets.length"><label>{{ this.$t('perms.Asset') }}:</label>{{ format(row.assets) }}<br></span>
<span v-show="row.nodes.length"><label>{{ this.$t('perms.Node') }}</label>:{{ format(row.nodes) }}<br></span>
<span v-show="row.nodes.length"><label>{{ this.$t('perms.Node') }}:</label>{{ format(row.nodes) }}<br></span>
<span v-show="row.system_users.length"><label>{{ this.$t('perms.SystemUser') }}:</label>{{ format(row.system_users) }}<br></span>
<span v-show="row.actions.length"><label>{{ this.$t('perms.Actions') }}:</label>{{ format(row.actions) }}</span>
</div>

View File

@@ -2,7 +2,7 @@
<div>
<TableAction :table-url="tableConfig.url" :search-table="search" v-bind="headerActions" :selected-rows="selectedRows" :reload-table="reloadTable" />
<el-card class="table-content" shadow="never">
<AutoDataTable ref="dataTable" :config="tableConfig" @selection-change="handleSelectionChange" />
<AutoDataTable :key="tableConfig.url" ref="dataTable" :config="tableConfig" @selection-change="handleSelectionChange" />
<Dialog :title="$tc('Export')" :visible.sync="showExportDialog" center @confirm="handleDialogConfirm('export')" @cancel="handleDialogCancel('export')">
<el-form>
<el-form-item :label="this.$t('action.ExportRange')" :label-width="'100px'">

View File

@@ -1,5 +1,5 @@
<template>
<el-card class="box-card primary">
<el-card class="box-card primary box-margin">
<div slot="header" class="clearfix">
<i v-if="icon" :class="'fa ' + icon" />
<span>{{ title }}</span>
@@ -100,4 +100,7 @@ export default {
tr.item td {
border-top: 1px solid #e7eaec;
}
.box-margin {
margin-bottom: 20px;
}
</style>

View File

@@ -1,114 +0,0 @@
<template>
<DataTable ref="dataTable" v-loading="loading" :config="totalConfig" v-bind="$attrs" v-on="$listeners" />
</template>
<script>
import DataTable from '@/components/DataTable'
import { DetailFormatter, DisplayFormatter, BooleanFormatter, ActionsFormatter } from '@/components/ListTable/formatters'
import { optionUrlMeta } from '@/api/common'
export default {
name: 'TreeAutoDataTable',
components: {
DataTable
},
props: {
config: {
type: Object,
default: () => ({})
}
},
data() {
return {
loading: true,
method: 'get',
totalConfig: {},
meta: {}
}
},
mounted() {
this.optionUrlMeta()
},
methods: {
optionUrlMeta() {
const url = `${this.config.url}draw=1&display=1`
optionUrlMeta(url).then(data => {
this.meta = data.actions[this.method.toUpperCase()] || {}
this.generateColumns()
}).catch(() => {
this.totalConfig = this.config
}).finally(() => {
this.loading = false
})
},
generateColumnByName(name, col) {
switch (name) {
case 'name':
col.formatter = DetailFormatter
col.sortable = 'custom'
col.route = this.config.detailRoute
break
case 'actions':
col = {
prop: 'id',
label: this.$tc('Actions'),
align: 'center',
formatter: ActionsFormatter,
width: '150px',
actions: this.config.actions || {}
}
break
case 'is_valid':
col.label = this.$tc('Validity')
col.formatter = BooleanFormatter
col.align = 'center'
col.width = '80px'
break
case 'comment':
col.showOverflowTooltip = true
}
return col
},
generateColumnByType(type, col) {
switch (type) {
case 'choice':
col.sortable = 'custom'
col.formatter = DisplayFormatter
break
case 'boolean':
col.formatter = BooleanFormatter
col.align = 'center'
col.width = '80px'
break
}
return col
},
generateColumn(name) {
const colMeta = this.meta[name] || {}
const customMeta = this.config.columnsMeta ? this.config.columnsMeta[name] : {}
let col = { prop: name, label: colMeta.label }
col = this.generateColumnByName(name, col)
col = this.generateColumnByType(colMeta.type, col)
col = Object.assign(col, customMeta)
return col
},
generateColumns() {
const config = Object.assign({}, this.config)
const columns = []
for (let col of this.config.columns) {
if (typeof col === 'object') {
columns.push(col)
} else if (typeof col === 'string') {
col = this.generateColumn(col)
columns.push(col)
}
}
this.totalConfig = Object.assign(config, { columns: columns })
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,285 +0,0 @@
<template>
<div class="table-header">
<slot name="header">
<div v-if="hasLeftActions" class="table-header-left-side">
<ActionsGroup :actions="actions" :more-actions="moreActions" class="header-action" @actionClick="handleActionClick" />
</div>
<div class="table-action-right-side">
<el-input v-if="hasSearch" v-model="keyword" suffix-icon="el-icon-search" :placeholder="$tc('Search')" class="right-side-item action-search" size="small" clearable @change="handleSearch" @input="handleSearch" />
<ActionsGroup :is-fa="true" :actions="defaultRightSideActions" class="right-side-actions right-side-item" @actionClick="handleActionClick" />
</div>
</slot>
</div>
</template>
<script>
import ActionsGroup from '@/components/ActionsGroup'
import _ from 'lodash'
import { createSourceIdCache } from '@/api/common'
const defaultTrue = { type: Boolean, default: true }
const defaultFalse = { type: Boolean, default: false }
export default {
name: 'TableAction',
components: {
ActionsGroup
},
props: {
hasExport: defaultTrue,
hasImport: defaultTrue,
hasRefresh: defaultTrue,
hasCreate: defaultTrue,
hasBulkDelete: defaultTrue,
hasBulkUpdate: defaultFalse,
hasLeftActions: defaultTrue,
hasSearch: defaultTrue,
hasRightActions: defaultTrue,
tableUrl: {
type: String,
default: ''
},
createRoute: {
type: String,
default: () => {
return this.$route.name.replace('List', 'Create')
}
},
reloadTable: {
type: Function,
default: () => {}
},
performBulkDelete: {
type: Function,
default: () => {}
},
searchTable: {
type: Function,
default: () => {}
},
selectedRows: {
type: Array,
default: () => ([])
},
extraActions: {
type: Array,
default: () => ([])
},
extraMoreActions: {
type: Array,
default: () => ([])
},
extraRightSideActions: {
type: Array,
default: () => ([])
}
},
data() {
return {
keyword: '',
defaultRightSideActions: [
{ name: 'actionExport', fa: 'fa-download', has: this.hasExport, callback: this.handleExport },
{ name: 'actionImport', fa: 'fa-upload', has: this.hasImport, callback: this.handleImport },
{ name: 'actionRefresh', fa: 'fa-refresh', has: this.hasRefresh, callback: this.handleRefresh }
],
defaultActions: [
{
name: 'actionCreate',
title: this.$tc('Create'),
type: 'primary',
has: this.hasCreate,
can: true,
callback: this.handleCreate
}
],
defaultMoreActions: [
{
title: this.$tc('Delete selected'),
name: 'actionDeleteSelected',
can: (rows) => rows.length > 0,
has: this.hasBulkDelete,
callback: this.defaultBulkDeleteCallback
},
{
title: this.$tc('Update selected'),
name: 'actionUpdateSelected',
can: (rows) => rows.length > 0,
has: this.hasBulkUpdate,
callback: this.handleBulkUpdate
}
],
dialogExportVisible: false,
exportValue: 2
}
},
computed: {
rightSideActions() {
const actions = [...this.defaultRightSideActions, ...this.extraRightSideActions]
return this.cleanActions(actions)
},
actions() {
const actions = [...this.defaultActions, ...this.extraActions]
return this.cleanActions(actions)
},
moreActions() {
const actions = [...this.defaultMoreActions, ...this.extraMoreActions]
return this.cleanActions(actions)
},
namedActions() {
const totalActions = [...this.actions, ...this.moreActions, ...this.rightSideActions]
const actions = {}
for (const action of totalActions) {
if (!action || !action.hasOwnProperty('name')) {
continue
}
actions[action.name] = action
}
return actions
}
},
methods: {
handleSearch: _.debounce(function() {
this.searchTable({ search: this.keyword })
}, 500),
handleActionClick(item) {
console.log('name cations')
let handler = this.namedActions[item] ? this.namedActions[item].callback : null
if (!handler) {
handler = () => {
console.log('No handler found for ', item)
}
}
handler(this.selectedRows)
},
handleCreate() {
const routeName = this.createRoute
this.$router.push({ name: routeName })
console.log('handle create')
},
defaultBulkDeleteCallback(rows) {
const msg = this.$tc('Are you sure to delete') + ' ' + rows.length + ' ' + this.$tc('rows')
const title = this.$tc('Info')
const performDelete = this.performBulkDelete || this.defaultPerformBulkDelete
this.$alert(msg, title, {
type: 'warning',
confirmButtonClass: 'el-button--danger',
showCancelButton: true,
beforeClose: async(action, instance, done) => {
if (action !== 'confirm') return done()
instance.confirmButtonLoading = true
try {
await performDelete(rows)
done()
this.reloadTable()
this.$message.success(this.$tc('Delete success'))
} catch (error) {
this.$message.error(this.$tc('Delete failed'))
console.warn(error)
} finally {
instance.confirmButtonLoading = false
}
}
}).catch(() => {
/* 取消*/
})
},
async defaultPerformBulkDelete(rows) {
const ids = rows.map((v) => {
return v.id
})
const data = await createSourceIdCache(ids)
const url = `${this.tableUrl}?spm=` + data.spm
return this.$axios.delete(url)
},
handleBulkUpdate(rows) {
},
handleExport(row) {
console.log(row)
this.$eventBus.$emit('showExportDialog', row)
},
handleImport(row) {
console.log(row)
this.$eventBus.$emit('showImportDialog', row)
},
handleRefresh() {
this.reloadTable()
},
cleanActions(actions) {
const validActions = []
for (const action of actions) {
let ok = this.checkItem(action, 'has')
if (!ok) {
continue
}
ok = this.checkItem(action, 'can')
action.disabled = !ok
validActions.push(action)
}
return validActions
},
checkItem(item, attr) {
let ok = item[attr]
if (typeof ok === 'function') {
ok = ok(this.selectedRows)
} else if (ok == null) {
ok = true
}
return ok
}
}
}
</script>
<style scoped>
.table-header {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.right-side-item {
}
.right-side-actions >>> .el-button {
border: none;
padding: 5px;
font-size: 14px;
width: 26px;
height: 26px;
color: #888;
background-color: transparent;
}
.right-side-actions >>> .fa {
height: 16px;
width: 16px;
}
.right-side-actions >>> .el-button:hover {
background-color: rgb(0, 0, 0, 0.05);
}
.action-search >>> .el-input__suffix i {
font-weight: 500;
color: #888;
}
.right-side-actions {
display: flex;
padding-left: 10px;
align-items: center;
justify-content:center;
}
.table-action-right-side {
display: flex;
justify-content:center;
}
.export-item {
display: block;
padding: 5px 20px;
}
</style>

View File

@@ -1,139 +0,0 @@
<template>
<ActionsGroup :size="'mini'" :actions="actions" :more-actions="moreActions" @actionClick="handleActionClick" />
</template>
<script>
import ActionsGroup from '@/components/ActionsGroup/index'
import BaseFormatter from './base'
const defaultPerformDelete = function({ row, col }) {
const id = row.id
const url = `${this.url}${id}/`
return this.$axios.delete(url)
}
const defaultUpdateCallback = function({ row, col }) {
const id = row.id
const defaultRoute = this.$route.name.replace('List', 'Update')
const routeName = col.actions.updateRoute || defaultRoute
this.$router.push({ name: routeName, params: { id: id }})
}
const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
const msg = this.$tc('Are you sure to delete') + ' "' + row.name + '"'
const title = this.$tc('Info')
const performDelete = col.actions.performDelete || defaultPerformDelete.bind(this)
this.$alert(msg, title, {
type: 'warning',
confirmButtonClass: 'el-button--danger',
showCancelButton: true,
beforeClose: async(action, instance, done) => {
if (action !== 'confirm') return done()
instance.confirmButtonLoading = true
try {
await performDelete({ row: row, col: col })
done()
reload()
this.$message.success(this.$tc('Delete success'))
} catch (error) {
this.$message.error(this.$tc('Delete failed'))
} finally {
instance.confirmButtonLoading = false
}
}
}).catch(() => {
/* 取消*/
})
}
export default {
name: 'ActionsFormatter',
components: { ActionsGroup },
extends: BaseFormatter,
data() {
const colActions = this.col.actions || {}
const defaultActions = [
{
name: 'update',
title: this.$tc('Update'),
type: 'primary',
has: colActions.hasUpdate !== false,
can: colActions.canUpdate !== false,
callback: colActions.onUpdate || defaultUpdateCallback.bind(this)
},
{
name: 'delete',
title: this.$tc('Delete'),
type: 'danger',
has: colActions.hasDelete !== false,
can: colActions.canDelete !== false,
callback: colActions.onDelete || defaultDeleteCallback.bind(this)
}
]
const extraActions = colActions.extraActions || []
return {
defaultActions: defaultActions,
extraActions: extraActions
}
},
computed: {
validActions() {
const actions = [...this.defaultActions, ...this.extraActions]
const validActions = []
for (const v of actions) {
const has = this.checkItem(v, 'has')
if (!has) {
continue
}
const can = this.checkItem(v, 'can')
v.disabled = !can
validActions.push(v)
}
return validActions
},
actions() {
return this.validActions.slice(0, 2)
},
moreActions() {
return this.validActions.slice(2, this.validActions.length)
},
namedValidActions() {
const actions = {}
for (const action of this.validActions) {
if (!action || !action.hasOwnProperty('name')) {
continue
}
actions[action.name] = action
}
return actions
}
},
methods: {
handleActionClick(item) {
const action = this.namedValidActions[item]
if (action && action.callback) {
const attrs = {
reload: this.reload,
row: this.row,
col: this.col,
cellValue: this.cellValue,
tableData: this.tableData
}
action.callback(attrs)
}
},
checkItem(item, attr) {
let ok = item[attr]
if (typeof ok === 'function') {
ok = ok(this.row, this.cellValue)
} else if (ok == null) {
ok = true
}
return ok
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,31 +0,0 @@
<template>
<div>
<i :class="'fa ' + iconClass" />
</div>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'ChoicesFormatter',
extends: BaseFormatter,
data() {
return {
defaultIconChoices: {
true: 'fa-check text-primary',
false: 'fa-times text-danger'
}
}
},
computed: {
iconClass() {
const key = !!this.cellValue
return this.defaultIconChoices[key]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,24 +0,0 @@
<template>
<el-link class="detail" :type="col.type || 'success'" @click="goDetail">{{ cellValue }}</el-link>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'DetailFormatter',
extends: BaseFormatter,
methods: {
goDetail() {
const defaultRoute = this.$route.name.replace('List', 'Detail')
const routeName = this.col.route || defaultRoute
this.$router.push({ name: routeName, params: { id: this.row.id }})
}
}
}
</script>
<style scoped>
.detail {
font-weight: 400;
}
</style>

View File

@@ -1,24 +0,0 @@
<template>
<span>{{ display }}</span>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'DisplayFormatter',
extends: BaseFormatter,
data() {
let displayKey = this.col.displayKey
if (!displayKey) {
displayKey = this.col.prop + '_display'
}
return {
display: this.row[displayKey]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,37 +0,0 @@
<template>
<div style="border: none; background: none;">
<span v-show="row.users.length"><label>{{ this.$t('perms.User') }}:</label>{{ format(row.users) }}<br></span>
<span v-show="row.user_groups.length"><label>{{ this.$t('perms.UserGroups') }}:</label>{{ format(row.user_groups) }}<br></span>
<span v-show="row.assets.length"><label>{{ this.$t('perms.Asset') }}:</label>{{ format(row.assets) }}<br></span>
<span v-show="row.nodes.length"><label>{{ this.$t('perms.Node') }}</label>:{{ format(row.nodes) }}<br></span>
<span v-show="row.system_users.length"><label>{{ this.$t('perms.SystemUser') }}:</label>{{ format(row.system_users) }}<br></span>
<span v-show="row.actions.length"><label>{{ this.$t('perms.Actions') }}:</label>{{ format(row.actions) }}</span>
</div>
</template>
<script>
import BaseFormatter from '@/components/ListTable/formatters/base'
export default {
name: 'ExpandAssetPermissionFormatter',
extends: BaseFormatter,
methods: {
format(val) {
if (val instanceof Array) {
return val.join(',')
}
return val
}
}
}
</script>
<style scoped>
label {
display: inline-block;
max-width: 100%;
margin: 5px;
font-weight: 700;
}
</style>

View File

@@ -1,15 +0,0 @@
<template>
<pre>{{ cellValue }}</pre>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'ExpandPreFormatter',
extends: BaseFormatter
}
</script>
<style scoped>
</style>

View File

@@ -1,23 +0,0 @@
<template>
<span>{{ getCellValueLength }}</span>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'LengthFormatter',
extends: BaseFormatter,
computed: {
getCellValueLength() {
if (this.cellValue instanceof Array) {
return this.cellValue.length
}
return this.cellValue
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,21 +0,0 @@
<template>
<pre style="border: none; background: none; white-space: pre-wrap">
{{ '$ '+ row.input }}
<br>
{{ row.output }}
</pre>
</template>
<script>
import BaseFormatter from '@/components/ListTable/formatters/base'
export default {
name: 'OutputExpandFormatter',
extends: BaseFormatter
}
</script>
<style scoped>
</style>

View File

@@ -1,23 +0,0 @@
<template>
<el-link class="detail" :type="col.type || 'success'" @click="goDetail">{{ col.linkName }}</el-link>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'RouterFormatter',
extends: BaseFormatter,
methods: {
goDetail() {
const routeName = this.col.route || ''
this.$router.push({ name: routeName, params: { id: this.cellValue }})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,39 +0,0 @@
<template>
<div />
</template>
<script>
export default {
name: 'BaseFormatter',
props: {
reload: {
type: Function,
default: ({ reloading }) => ({})
},
row: {
type: Object,
default: () => ({})
},
col: {
type: Object,
default: () => ({})
},
cellValue: {
type: [String, Boolean, Number, Object, Array],
default: null
},
tableData: {
type: Array,
default: () => ({})
},
url: {
type: String,
default: ''
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,33 +0,0 @@
import DetailFormatter from './DetailFormatter'
import DisplayFormatter from './DisplayFormatter'
import BooleanFormatter from './ChoicesFormatter'
import ActionsFormatter from './ActionsFormatter'
import ExpandPreFormatter from './ExpandPreFormatter'
import LengthFormatter from './LengthFormatter'
import RouterFormatter from './RouterFormatter'
import OutputExpandFormatter from './OutputExpandFormatter'
import ExpandAssetPermissionFormatter from './ExpandAssetPermissionFormatter'
export default {
DetailFormatter,
DisplayFormatter,
BooleanFormatter,
ActionsFormatter,
ExpandPreFormatter,
LengthFormatter,
RouterFormatter,
OutputExpandFormatter,
ExpandAssetPermissionFormatter
}
export {
DetailFormatter,
DisplayFormatter,
BooleanFormatter,
ActionsFormatter,
ExpandPreFormatter,
LengthFormatter,
RouterFormatter,
OutputExpandFormatter,
ExpandAssetPermissionFormatter
}

View File

@@ -1,200 +0,0 @@
<template>
<div>
<TableAction :table-url="tableConfig.url" :search-table="search" v-bind="headerActions" :selected-rows="selectedRows" :reload-table="reloadTable" />
<el-card class="table-content" shadow="never">
<TreeAutoDataTable ref="dataTable" :config="tableConfig" @selection-change="handleSelectionChange" />
<Dialog :title="$tc('Export')" :visible.sync="showExportDialog" center @confirm="handleDialogConfirm('export')" @cancel="handleDialogCancel('export')">
<el-form>
<el-form-item :label="this.$t('action.ExportRange')" :label-width="'100px'">
<el-radio v-model="exportOption" class="export-item" label="1">{{ this.$t('action.ExportAll') }}</el-radio>
<el-radio v-model="exportOption" class="export-item" label="2">{{ this.$t('action.ExportOnlySelectedItems') }}</el-radio>
<!-- <el-radio v-model="exportOption" class="export-item" label="3">仅导出搜索项</el-radio> -->
</el-form-item>
</el-form>
</Dialog>
<Dialog :title="importtitle" :visible.sync="showImportDialog" center @confirm="handleDialogConfirm('import')" @cancel="handleDialogCancel('import')">
<el-form>
<el-form-item :label="importtitle" :label-width="'100px'">
<el-radio v-model="importOption" class="export-item" label="1">{{ this.$tc('Import') }}</el-radio>
<el-radio v-model="importOption" class="export-item" label="2">{{ this.$tc('Update') }}</el-radio>
</el-form-item>
</el-form>
<div v-if="importOption==='1'" style="margin-bottom:20px;margin-left: 55px;">{{ this.$t('action.DownloadTheImportedTemplateOrUseTheExportedCSVFormat') }} <a style="color: #428bca;" :href="downloadImportTempUrl">{{ this.$t('action.DownloadImportTemplate') }}</a></div>
<div v-else style="margin-bottom:20px;margin-left: 55px;">{{ this.$t('action.DownloadTheUpdatedTemplateOrUsTheExportedCSVFormat') }} <a style="color: #428bca;" @click="downloadUpdateTempUrl">{{ this.$t('action.DownloadUpdateTemplate') }}</a></div>
<div style="margin-left:55px;">
<el-upload
class="upload-card"
action="string"
:http-request="upload"
list-type="text/csv"
:limit="1"
>
<el-button size="small" type="primary">{{ this.$t('action.Upload') }}</el-button>
<div slot="tip" class="el-upload__tip">{{ this.$t('action.OnlyCSVFilesCanBeUploaded') }}</div>
</el-upload>
</div>
</Dialog>
</el-card>
</div>
</template>
<script>
/* eslint-disable no-unused-vars */
import TreeAutoDataTable from '../TreeAutoDataTable'
import Dialog from '@/components/Dialog'
import TableAction from './TableAction'
import { createSourceIdCache } from '@/api/common'
export default {
name: 'TreeListTable',
components: {
TreeAutoDataTable,
TableAction,
Dialog
},
props: {
// 定义 table 的配置
tableConfig: {
type: Object,
default: () => ({})
},
// 是否显示table左侧的action
headerActions: {
type: Object,
default: () => ({})
}
},
data() {
return {
selectedRows: [],
showExportDialog: false,
showImportDialog: false,
importOption: '1',
exportOption: '1',
meta: {}
}
},
computed: {
hasSelected() {
return this.selectedRows.length > 0
},
upLoadUrl() {
return this.tableConfig.url
},
importtitle() {
if (this.importOption === '1') { return this.$tc('Import') } else { return this.$tc('Update') }
},
downloadImportTempUrl() {
return process.env.VUE_APP_BASE_API + this.tableConfig.url + '?format=csv&template=import&limit=1'
}
},
watch: {
tableConfig: function(val) {
// 空函数, 方便组件刷新
}
},
mounted() {
this.$eventBus.$on('showExportDialog', (row) => {
this.showExportDialog = true
})
this.$eventBus.$on('showImportDialog', (row) => {
this.showImportDialog = true
})
},
methods: {
upload(item) {
console.log(item)
this.$axios.put(
this.upLoadUrl,
item.file
).then((res) =>
console.log(res)
)
},
downloadCsv(url) {
const a = document.createElement('a')
a.href = url
a.click()
window.URL.revokeObjectURL(url)
},
handleSelectionChange(val) {
this.selectedRows = val
},
reloadTable() {
this.$refs.dataTable.$refs.dataTable.getList()
},
search(attrs) {
return this.$refs.dataTable.$refs.dataTable.search(attrs)
},
async handleExport() {
let data
var resources = []
if (this.exportOption === '1') {
data = this.$refs.dataTable.$refs.dataTable.getData()
} else if (this.exportOption === '2') {
data = this.selectedRows
} else {
data = []
}
for (let index = 0; index < data.length; index++) {
resources.push(data[index].id)
}
const spm = await createSourceIdCache(resources)
const url = process.env.VUE_APP_BASE_API + `${this.tableConfig.url}?format=csv&?spm=` + spm.spm
return this.downloadCsv(url)
},
handleImport() {
},
async downloadUpdateTempUrl() {
var resources = []
const data = this.$refs.dataTable.$refs.dataTable.getData()
for (let index = 0; index < data.length; index++) {
resources.push(data[index].id)
}
const spm = await createSourceIdCache(resources)
const url = process.env.VUE_APP_BASE_API + `${this.tableConfig.url}?format=csv&template=update&spm=` + spm.spm
return this.downloadCsv(url)
},
async handleDialogConfirm(val) {
switch (val) {
case 'export':
await this.handleExport()
this.showExportDialog = false
break
case 'import':
await this.handleImport()
this.showImportDialog = false
break
default:
break
}
},
handleDialogCancel(val) {
switch (val) {
case 'export':
this.showExportDialog = false
break
case 'import':
this.showImportDialog = false
break
default:
break
}
}
}
}
</script>
<style lang="less" scoped>
.table-content {
margin-top: 10px;
}
//修改颜色
// .el-button--text{
// color: #409EFF;
// }
</style>

View File

@@ -1,45 +1,34 @@
<template>
<Page>
<el-alert v-if="helpMessage" type="success"> {{ helpMessage }} </el-alert>
<el-collapse-transition>
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
<div v-show="ShowTree" :style="ShowTree?('width:250px;'):('width:0;')" class="transition-box">
<AutoDataZTree :setting="treeSetting" @urlChange="handleUrlChange" />
<el-collapse-transition>
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
<div v-show="ShowTree" :style="ShowTree?('width:250px;'):('width:0;')" class="transition-box">
<AutoDataZTree :setting="treeSetting" @urlChange="handleUrlChange" />
</div>
<div :style="ShowTree?('display: flex;width: calc(100% - 250px);'):('display: flex;width:100%;')">
<div class="mini">
<div style="display:block" class="mini-button" @click="ShowTree=!ShowTree">
<i v-show="ShowTree" class="fa fa-angle-left fa-x" /><i v-show="!ShowTree" class="fa fa-angle-right fa-x" />
</div>
</div>
<div :style="ShowTree?('display: flex;width: calc(100% - 250px);'):('display: flex;width:100%;')">
<div class="mini">
<div style="display:block" class="mini-button" @click="ShowTree=!ShowTree">
<i v-show="ShowTree" class="fa fa-angle-left fa-x" /><i v-show="!ShowTree" class="fa fa-angle-right fa-x" />
</div>
</div>
<div class="transition-box" style="width: calc(100% - 17px);">
<TreeListTable :table-config="internalTableConfig" :header-actions="headerActions" />
</div>
<div class="transition-box" style="width: calc(100% - 17px);">
<ListTable :table-config="internalTableConfig" :header-actions="headerActions" />
</div>
</div>
</el-collapse-transition>
</Page>
</div>
</el-collapse-transition>
</template>
<script>
import { Page } from '@/layout/components'
// import TreeNode from '../TreeNode'
// import ZTree from '../ZTree'
import AutoDataZTree from '../AutoDataZTree'
import TreeListTable from './components/TreeListTable'
import ListTable from '../ListTable'
export default {
name: 'TreeTable',
components: {
Page,
TreeListTable,
ListTable,
AutoDataZTree
},
props: {
...TreeListTable.props,
helpMessage: {
type: String,
default: null
}
...ListTable.props
},
data() {
return {
@@ -55,6 +44,7 @@ export default {
methods: {
handleUrlChange(_url) {
this.$set(this.internalTableConfig, 'url', _url)
console.log(this.internalTableConfig)
}
}
}

View File

@@ -12,6 +12,7 @@ export { default as formGroupHeader } from './formGroupHeader'
export { default as Hamburger } from './Hamburger'
export { default as ListTable } from './ListTable'
export { default as RelationCard } from './RelationCard'
export { default as ActiveCard } from './ActiveCard'
export { default as Select2 } from './Select2'
export { default as SvgIcon } from './SvgIcon'
export { default as TreeTable } from './TreeTable'

View File

@@ -129,7 +129,9 @@ const cn = {
'UserUpdate': '更新用户',
'AdminUserCreate': '创建管理用户',
'PlatformCreate': '创建系统平台',
'PlatformUpdate': '更新系统平台'
'PlatformUpdate': '更新系统平台',
'CommandFilterCreate': '创建命令过滤器',
'CommandFilterUpdate': '更新命令过滤器'
},
// 用户模块翻译
users: {
@@ -374,6 +376,8 @@ const cn = {
'UsersAndUserGroups': '用户或用户组',
'AssetAndNode': '资产或节点',
'Active': '激活中',
'AddUserToAssetPermission': '添加用户',
'AddGroupToAssetPermission': '添加用户组',
//
'RemoteApp': '远程应用',
'RemoteAppCount': '远程应用数量',

View File

@@ -0,0 +1,29 @@
<template>
<Page>
<el-alert v-if="helpMessage" type="success"> {{ helpMessage }} </el-alert>
<TreeTable :table-config="tableConfig" :header-actions="headerActions" />
</Page>
</template>
<script>
import { Page } from '@/layout/components'
import TreeTable from '@/components/TreeTable'
export default {
name: 'GenericTreeListPage',
components: {
Page, TreeTable
},
props: {
...TreeTable.props,
helpMessage: {
type: String,
default: null
}
}
}
</script>
<style scoped>
</style>

View File

@@ -138,7 +138,8 @@ export const constantRoutes = [
path: 'domains/create',
name: 'DomainCreate',
component: () => import('@/views/assets/DomainCreateUpdate.vue'),
meta: { title: 'DomainList' }
meta: { title: 'DomainList' },
hidden: true
},
{
path: 'domains/:id/gateway',
@@ -177,22 +178,22 @@ export const constantRoutes = [
{
path: 'cmd-filters/update/:id',
component: () => import('@/views/assets/CommandFilterCreateUpdate.vue'), // Parent router-view
name: 'PlatformUpdate',
meta: { title: 'PlatformUpdate' },
name: 'CommandFilterUpdate',
meta: { title: 'CommandFilterUpdate' },
hidden: true
},
{
path: 'cmd-filters/create',
component: () => import('@/views/assets/CommandFilterCreateUpdate.vue'), // Parent router-view
name: 'PlatformCreate',
meta: { title: 'PlatformCreate' },
name: 'CommandFilterCreate',
meta: { title: 'CommandFilterCreate' },
hidden: true
},
{
path: 'platform/:id',
component: () => import('@/views/assets/PlatformDetail.vue'), // Parent router-view
name: 'PlatformDetail',
meta: { title: 'PlatformDetail' },
path: 'cmd-filters/:id',
component: () => import('@/views/assets/CommandFilterDetail.vue'), // Parent router-view
name: 'CommandFilterDetail',
meta: { title: 'CommandFilterDetail' },
hidden: true
},
{
@@ -415,18 +416,18 @@ export const constantRoutes = [
{
path: '/ops/',
component: Layout,
redirect: '/ops/task/',
redirect: '/ops/tasks/',
name: 'JobCenter',
meta: { title: 'JobCenter', icon: 'coffee' },
children: [
{
path: 'task',
path: 'tasks',
name: 'TaskList',
component: () => import('@/views/jobcenter/TaskList'),
meta: { title: 'TaskList', activeMenu: '/ops/task' }
},
{
path: 'task/:id',
path: 'tasks/:id',
component: () => import('@/views/jobcenter/TaskDetail'),
name: 'TaskDetail',
hidden: true,

View File

@@ -1,19 +1,20 @@
<template>
<TreeTable :table-config="tableConfig" :header-actions="headerActions" />
<GenericTreeListPage :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import TreeTable from '@/components/TreeTable'
import GenericTreeListPage from '@/layout/components/GenericTreeListPage'
import { DetailFormatter, ActionsFormatter, BooleanFormatter } from '@/components/ListTable/formatters/index'
export default {
components: {
TreeTable
GenericTreeListPage
},
data() {
return {
tableConfig: {
url: '/api/v1/assets/assets/',
hasTree: true,
treeSetting: {
showMenu: true,
showRefresh: true,

View File

@@ -13,33 +13,10 @@ export default {
},
fields: [
// [this.$t('perms.' + 'Basic'), ['name', 'base', 'security', 'console', 'comment']]
['', ['name', 'comment']]
],
fieldsMeta: {
},
performSubmit: function(formdata) {
console.log(formdata)
var postData = {}
if (formdata.base === 'Windows') {
postData.meta = {}
postData.meta.security = formdata.security
postData.meta.console = (formdata.console === 'true')
}
postData.name = formdata.name
postData.base = formdata.base
postData.comment = formdata.comment || ''
const params = this.$route.params
if (params.id) {
return this.$axios.put(
`${this.url}${params.id}/`, postData
)
} else {
return this.$axios.post(
this.url, postData
)
}
},
url: '/api/v1/assets/cmd-filters/'
}

View File

@@ -0,0 +1,38 @@
<template>
<GenericDetailPage :object="object" :submenu="submenu" :active-menu="activeSubMenu" :title="title" />
</template>
<script>
import { GenericDetailPage } from '@/layout/components'
export default {
name: 'CommandFilterDetail',
components: {
GenericDetailPage
},
data() {
return {
object: { name: '' },
submenu: [
{
title: this.$t('perms.AssetPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.AssetPermissionDetail'),
name: 'rule'
}
],
activeSubMenu: 'detail'
}
},
computed: {
title() {
return this.$t('perms.AssetPermissionDetail')
}
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -1,5 +1,5 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title" />
<GenericDetailPage :object="object" :submenu="submenu" :active-menu="activeSubMenu" :title="title" />
</template>
<script>
@@ -11,6 +11,7 @@ export default {
},
data() {
return {
object: { name: '' },
submenu: [
{
title: this.$t('perms.AssetPermissionDetail'),

View File

@@ -1,5 +1,5 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<GenericDetailPage :object.sync="adhocDetail" v-bind="config">
<div slot="adhocDetail">
<el-row :gutter="20">
<el-col :span="14">
@@ -52,25 +52,27 @@ export default {
data() {
return {
flag: false,
adhocDetail: { name: '' },
config: {
activeMenu: 'adhocDetail',
title: this.$t('jobcenter.TaskDetail'),
submenu: [
{
title: this.$t('jobcenter.versionDetail'),
name: 'adhocDetail'
},
{
title: this.$t('jobcenter.VersionRunExecution'),
name: 'versionRunExecution'
}
],
hasRightSide: false
},
adhocData: '',
versionDetailData: {},
activeSubMenu: 'adhocDetail',
submenu: [
{
title: this.$t('jobcenter.versionDetail'),
name: 'adhocDetail'
},
{
title: this.$t('jobcenter.VersionRunExecution'),
name: 'versionRunExecution'
}
]
versionDetailData: {}
}
},
computed: {
title() {
return this.$t('jobcenter.TaskDetail')
},
cardTitle() {
return 'api 没有该数据'
},

View File

@@ -1,5 +1,5 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<GenericDetailPage :object.sync="historyExecutionDetail" v-bind="config">
<div slot="executionDetail">
<el-row :gutter="20">
<el-col :span="14">
@@ -48,25 +48,30 @@ export default {
data() {
return {
flag: false,
defaultValue: '',
historyExecutionDetailData: {},
activeSubMenu: 'executionDetail',
submenu: [
{
title: this.$t('jobcenter.ExecutionDetail'),
name: 'executionDetail'
},
{
title: this.$t('jobcenter.Output'),
name: 'outPut'
historyExecutionDetail: { name: '' },
config: {
activeMenu: 'executionDetail',
title: this.$t('jobcenter.ExecutionDetail'),
submenu: [
{
title: this.$t('jobcenter.ExecutionDetail'),
name: 'executionDetail'
},
{
title: this.$t('jobcenter.Output'),
name: 'outPut'
}
],
hasRightSide: false,
actions: {
detailApiUrl: `/api/v1/ops/adhoc-executions/${this.$route.params.id}/`
}
]
},
defaultValue: '',
historyExecutionDetailData: {}
}
},
computed: {
title() {
return this.$t('jobcenter.TaskDetail')
},
cardTitle() {
return `${this.historyExecutionDetailData.task_display}:${this.historyExecutionDetailData.adhoc_short_id}`
},

View File

@@ -1,5 +1,5 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<GenericDetailPage :object.sync="taskDetail" v-bind="config">
<div slot="detail">
<el-row :gutter="20">
<el-col :span="14">
@@ -58,32 +58,33 @@ export default {
data() {
return {
flag: false,
taskData: {},
activeSubMenu: 'detail',
submenu: [
{
title: this.$t('jobcenter.TaskDetail'),
name: 'detail'
},
{
title: this.$t('jobcenter.TaskVersions'),
name: 'taskVersions'
},
{
title: this.$t('jobcenter.Execution'),
name: 'execution'
},
{
title: this.$t('jobcenter.LaskExecutionOutput'),
name: 'laskExecutionOutput'
}
]
taskDetail: { name: '' },
config: {
activeMenu: 'detail',
submenu: [
{
title: this.$t('jobcenter.TaskDetail'),
name: 'detail'
},
{
title: this.$t('jobcenter.TaskVersions'),
name: 'taskVersions'
},
{
title: this.$t('jobcenter.Execution'),
name: 'execution'
},
{
title: this.$t('jobcenter.LaskExecutionOutput'),
name: 'laskExecutionOutput'
}
],
hasRightSide: false
},
taskData: {}
}
},
computed: {
title() {
return this.$t('jobcenter.TaskDetail')
},
cardTitle() {
return this.taskData.name
},

View File

@@ -7,10 +7,10 @@
<el-card class="box-card primary">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ userCardActions }}</span>
<span>{{ assetCardActions }}</span>
</div>
<div>
<Select2 v-model="selectUser.value" v-bind="selectUser" />
<Select2 v-model="selectAsset.value" v-bind="selectAsset" />
</div>
</el-card>
</el-col>
@@ -18,10 +18,21 @@
<el-card class="box-card success">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ userGroupCardActions }}</span>
<span>{{ nodeCardActions }}</span>
</div>
<div>
<Select2 v-model="selectUserGroup.value" v-bind="selectUserGroup" />
<Select2 v-model="selectNode.value" v-bind="selectNode" />
</div>
</el-card>
</el-col>
<el-col :span="10">
<el-card class="box-card warning">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ systemUserCardActions }}</span>
</div>
<div>
<Select2 v-model="selectSystemUser.value" v-bind="selectSystemUser" />
</div>
</el-card>
</el-col>
@@ -33,7 +44,7 @@ import ListTable from '@/components/ListTable'
import Select2 from '@/components/Select2'
export default {
name: 'AssetPermissionUser',
name: 'AssetPermissionAsset',
components: {
ListTable,
Select2
@@ -41,13 +52,13 @@ export default {
data() {
return {
tableConfig: {
url: `/api/v1/perms/asset-permissions/${this.$route.params.id}/users/all/`,
url: `/api/v1/perms/asset-permissions/${this.$route.params.id}/assets/all/`,
columns: [
'user_display'
'asset_display'
],
columnsMeta: {
user_display: {
label: this.$t('perms.User')
asset_display: {
label: this.$t('perms.Asset')
}
}
},
@@ -62,26 +73,35 @@ export default {
hasSearch: false,
hasRightActions: false
},
assetPermissionUser: [],
assetPermissionUserGroup: [],
selectUser: {
url: '/api/v1/users/users/',
initial: this.assetPermissionUser,
assetPermissionAsset: [],
assetPermissionNode: [],
assetPermissionSystemUser: [],
selectAsset: {
url: '/api/v1/assets/assets/',
initial: this.assetPermissionAsset,
value: []
},
selectUserGroup: {
url: '/api/v1/users/groups/',
initial: this.assetPermissionUserGroup,
selectNode: {
url: '/api/v1/assets/nodes/',
initial: this.assetPermissionNode,
value: []
},
selectSystemUser: {
url: '/api/v1/assets/system-users/',
initial: this.assetPermissionSystemUser,
value: []
}
}
},
computed: {
userCardActions() {
return this.$t('perms.User')
assetCardActions() {
return this.$t('perms.Asset')
},
userGroupCardActions() {
return this.$t('perms.UserGroups')
nodeCardActions() {
return this.$t('perms.Node')
},
systemUserCardActions() {
return this.$t('perms.SystemUser')
}
}
}

View File

@@ -1,45 +1,33 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<div slot="detail">
<el-row :gutter="20">
<el-col :span="14">
<DetailCard v-if="flag" :title="cardTitle" :items="detailCardItems" />
</el-col>
<el-col :span="10">
<el-card class="box-card primary">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ detailCardActions }}</span>
</div>
<el-table class="el-table" :data="detailCardActionData" :show-header="false">
<el-table-column prop="name" />
<el-table-column prop="is_active" align="right">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_active"
active-color="#13ce66"
inactive-color="#ff4949"
@change="HandleChangeAction(scope.$index, scope.row)"
/>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
<div slot="userAndUserGroups">
<AssetPermissionUser />
</div>
<div slot="assetAndNode">
<AssetPermissionAsset />
</div>
<GenericDetailPage :object.sync="assetPermission" v-bind="config">
<template #detail>
<div>
<el-row :gutter="20">
<el-col :md="14" :sm="24">
<DetailCard v-if="flag" :title="cardTitle" :items="detailCardItems" />
</el-col>
<el-col :md="10" :sm="24">
<ActiveCard v-bind="activeConfig" />
</el-col>
</el-row>
</div>
</template>
<template #userAndUserGroups>
<div>
<AssetPermissionUser />
</div>
</template>
<template #assetAndNode>
<div>
<AssetPermissionAsset />
</div>
</template>
</GenericDetailPage>
</template>
<script>
import { GenericDetailPage } from '@/layout/components'
import DetailCard from '@/components/DetailCard/index'
import { DetailCard, ActiveCard } from '@/components'
import { getAssetPermissionDetail } from '@/api/perms'
import { toSafeLocalDateStr } from '@/utils/common'
import AssetPermissionUser from './AssetPermissionUser'
@@ -50,40 +38,49 @@ export default {
components: {
GenericDetailPage,
DetailCard,
ActiveCard,
AssetPermissionUser,
AssetPermissionAsset
},
data() {
return {
flag: false,
activeSubMenu: 'detail',
assetPermissionData: {},
submenu: [
{
title: this.$t('perms.AssetPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.UsersAndUserGroups'),
name: 'userAndUserGroups'
},
{
title: this.$t('perms.AssetAndNode'),
name: 'assetAndNode'
}
]
assetPermission: { name: '' },
config: {
activeMenu: 'detail',
submenu: [
{
title: this.$t('perms.AssetPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.UsersAndUserGroups'),
name: 'userAndUserGroups'
},
{
title: this.$t('perms.AssetAndNode'),
name: 'assetAndNode'
}
]
},
activeConfig: {
icon: 'fa-info',
title: this.$t('perms.QuickModify'),
content: [
{
name: this.$t('perms.Active'),
is_active: true
}
],
url: `/api/v1/perms/asset-permissions/${this.$route.params.id}/`
},
assetPermissionData: {}
}
},
computed: {
title() {
return this.$t('perms.AssetPermissionDetail')
},
cardTitle() {
return this.assetPermissionData.id
},
detailCardActions() {
return this.$t('perms.QuickModify')
},
detailCardItems() {
return [
{
@@ -132,14 +129,6 @@ export default {
value: this.assetPermissionData.comment
}
]
},
detailCardActionData() {
return [
{
name: this.$t('perms.Active'),
is_active: true
}
]
}
},
mounted() {
@@ -149,13 +138,10 @@ export default {
getAssetPermissionDetailData() {
getAssetPermissionDetail(this.$route.params.id).then(data => {
this.assetPermissionData = data
this.activeConfig.content[0].is_active = data.is_active
this.flag = true
})
},
HandleChangeAction: function(index, row) {
const url = `/api/v1/perms/asset-permissions/${this.$route.params.id}/`
console.log(url)
},
getDataLength(data) {
if (data instanceof Array) {
return data.length

View File

@@ -1,64 +1,35 @@
<template>
<el-row :gutter="20">
<el-col :span="14">
<el-col :md="14" :sm="24">
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
</el-col>
<el-col :span="10">
<el-card class="box-card primary">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ assetCardActions }}</span>
</div>
<div>
<Select2 v-model="selectAsset.value" v-bind="selectAsset" />
</div>
</el-card>
</el-col>
<el-col :span="10">
<el-card class="box-card success">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ nodeCardActions }}</span>
</div>
<div>
<Select2 v-model="selectNode.value" v-bind="selectNode" />
</div>
</el-card>
</el-col>
<el-col :span="10">
<el-card class="box-card warning">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ systemUserCardActions }}</span>
</div>
<div>
<Select2 v-model="selectSystemUser.value" v-bind="selectSystemUser" />
</div>
</el-card>
<el-col :md="10" :sm="24">
<RelationCard v-if="!userReletionConfig.loading" v-bind="userReletionConfig" />
<RelationCard v-if="!groupReletionConfig.loading" v-bind="groupReletionConfig" />
</el-col>
</el-row>
</template>
<script>
import ListTable from '@/components/ListTable'
import Select2 from '@/components/Select2'
import { RelationCard } from '@/components'
export default {
name: 'AssetPermissionAsset',
name: 'AssetPermissionUser',
components: {
ListTable,
Select2
RelationCard
},
data() {
return {
tableConfig: {
url: `/api/v1/perms/asset-permissions/${this.$route.params.id}/assets/all/`,
url: `/api/v1/perms/asset-permissions/${this.$route.params.id}/users/all/`,
columns: [
'asset_display'
'user_display'
],
columnsMeta: {
asset_display: {
label: this.$t('perms.Asset')
user_display: {
label: this.$t('perms.User')
}
}
},
@@ -73,36 +44,26 @@ export default {
hasSearch: false,
hasRightActions: false
},
assetPermissionAsset: [],
assetPermissionNode: [],
assetPermissionSystemUser: [],
selectAsset: {
url: '/api/v1/assets/assets/',
initial: this.assetPermissionAsset,
value: []
assetPermissionUser: [],
assetPermissionUserGroup: [],
userReletionConfig: {
icon: 'fa-user',
title: this.$t('perms.AddUserToAssetPermission'),
url: '/api/v1/users/users/',
value: [],
loading: false
},
selectNode: {
url: '/api/v1/assets/nodes/',
initial: this.assetPermissionNode,
value: []
},
selectSystemUser: {
url: '/api/v1/assets/system-users/',
initial: this.assetPermissionSystemUser,
value: []
groupReletionConfig: {
icon: 'fa-group',
title: this.$t('perms.AddGroupToAssetPermission'),
url: '/api/v1/users/groups/',
value: [],
loading: false
}
}
},
computed: {
assetCardActions() {
return this.$t('perms.Asset')
},
nodeCardActions() {
return this.$t('perms.Node')
},
systemUserCardActions() {
return this.$t('perms.SystemUser')
}
mounted() {
// 获取用户组成员
}
}
</script>

View File

@@ -1,30 +1,12 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<GenericDetailPage :object.sync="databaseAppPermission" v-bind="config">
<div slot="detail">
<el-row :gutter="20">
<el-col :span="14">
<el-col :md="14" :sm="24">
<DetailCard v-if="flag" :title="cardTitle" :items="detailCardItems" />
</el-col>
<el-col :span="10">
<el-card class="box-card primary">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ detailCardActions }}</span>
</div>
<el-table class="el-table" :data="detailCardActionData" :show-header="false">
<el-table-column prop="name" />
<el-table-column prop="is_active" align="right">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_active"
active-color="#13ce66"
inactive-color="#ff4949"
@change="HandleChangeAction(scope.$index, scope.row)"
/>
</template>
</el-table-column>
</el-table>
</el-card>
<el-col :md="10" :sm="24">
<ActiveCard v-bind="activeConfig" />
</el-col>
</el-row>
</div>
@@ -39,7 +21,7 @@
<script>
import { GenericDetailPage } from '@/layout/components'
import DetailCard from '@/components/DetailCard/index'
import { DetailCard, ActiveCard } from '@/components'
import { getDatabaseAppPermissionDetail } from '@/api/perms'
import { toSafeLocalDateStr } from '@/utils/common'
import DatabaseAppPermissionUser from './DatabaseAppPermissionUser'
@@ -51,39 +33,48 @@ export default {
DatabaseAppPermissionDatabaseApp,
DatabaseAppPermissionUser,
GenericDetailPage,
DetailCard
DetailCard,
ActiveCard
},
data() {
return {
flag: false,
activeSubMenu: 'detail',
databaseAppData: {},
submenu: [
{
title: this.$t('perms.DatabaseAppPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.UsersAndUserGroups'),
name: 'userAndUserGroups'
},
{
title: this.$t('perms.DatabaseApp'),
name: 'databaseApp'
}
]
databaseAppPermission: { name: '' },
config: {
activeMenu: 'detail',
submenu: [
{
title: this.$t('perms.DatabaseAppPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.UsersAndUserGroups'),
name: 'userAndUserGroups'
},
{
title: this.$t('perms.DatabaseApp'),
name: 'databaseApp'
}
]
},
activeConfig: {
icon: 'fa-info',
title: this.$t('perms.QuickModify'),
content: [
{
name: this.$t('perms.Active'),
is_active: true
}
],
url: `/api/v1/perms/database-app-permissions/${this.$route.params.id}/`
},
databaseAppData: {}
}
},
computed: {
title() {
return this.$t('perms.DatabaseAppPermissionDetail')
},
cardTitle() {
return this.databaseAppData.id
},
detailCardActions() {
return this.$t('perms.QuickModify')
},
detailCardItems() {
return [
{
@@ -127,14 +118,6 @@ export default {
value: this.databaseAppData.comment
}
]
},
detailCardActionData() {
return [
{
name: this.$t('perms.Active'),
is_active: true
}
]
}
},
mounted() {
@@ -144,13 +127,10 @@ export default {
getDatabaseAppPermissionDetailData() {
getDatabaseAppPermissionDetail(this.$route.params.id).then(data => {
this.databaseAppData = data
this.activeConfig.content[0].is_active = data.is_active
this.flag = true
})
},
HandleChangeAction: function(index, row) {
const url = `/api/v1/perms/database-app-permissions/${this.$route.params.id}/`
console.log(url)
},
getDataLength(data) {
if (data instanceof Array) {
return data.length

View File

@@ -1,30 +1,12 @@
<template>
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
<GenericDetailPage :object.sync="remoteAppPermission" v-bind="config">
<div slot="detail">
<el-row :gutter="20">
<el-col :span="14">
<DetailCard v-if="flag" :title="cardTitle" :items="detailCardItems" />
</el-col>
<el-col :span="10">
<el-card class="box-card primary">
<div slot="header" class="clearfix">
<i class="fa fa-info" />
<span>{{ detailCardActions }}</span>
</div>
<el-table class="el-table" :data="detailCardActionData" :show-header="false">
<el-table-column prop="name" />
<el-table-column prop="is_active" align="right">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_active"
active-color="#13ce66"
inactive-color="#ff4949"
@change="HandleChangeAction(scope.$index, scope.row)"
/>
</template>
</el-table-column>
</el-table>
</el-card>
<ActiveCard v-bind="activeConfig" />
</el-col>
</el-row>
</div>
@@ -39,7 +21,7 @@
<script>
import { GenericDetailPage } from '@/layout/components'
import DetailCard from '@/components/DetailCard/index'
import { DetailCard, ActiveCard } from '@/components'
import { getRemoteAppPermissionDetail } from '@/api/perms'
import { toSafeLocalDateStr } from '@/utils/common'
import RemoteAppPermissionUser from './RemoteAppPermissionUser'
@@ -51,27 +33,42 @@ export default {
RemoteAppPermissionUser,
RemoteAppPermissionRemoteApp,
GenericDetailPage,
DetailCard
DetailCard,
ActiveCard
},
data() {
return {
flag: false,
activeSubMenu: 'detail',
remoteAppPermission: { name: '' },
config: {
activeMenu: 'detail',
submenu: [
{
title: this.$t('perms.RemoteAppPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.UsersAndUserGroups'),
name: 'userAndUserGroups'
},
{
title: this.$t('perms.RemoteApp'),
name: 'remoteApp'
}
]
},
activeConfig: {
icon: 'fa-info',
title: this.$t('perms.QuickModify'),
content: [
{
name: this.$t('perms.Active'),
is_active: true
}
],
url: `/api/v1/perms/remote-app-permissions/${this.$route.params.id}/`
},
remoteAppData: {},
submenu: [
{
title: this.$t('perms.RemoteAppPermissionDetail'),
name: 'detail'
},
{
title: this.$t('perms.UsersAndUserGroups'),
name: 'userAndUserGroups'
},
{
title: this.$t('perms.RemoteApp'),
name: 'remoteApp'
}
],
remoteAppPermissionRemoteApp: [],
remoteAppPermissionSystemUser: [],
selectRemoteApp: {
@@ -87,15 +84,9 @@ export default {
}
},
computed: {
title() {
return this.$t('perms.RemoteAppPermissionDetail')
},
cardTitle() {
return this.remoteAppData.id
},
detailCardActions() {
return this.$t('perms.QuickModify')
},
detailCardItems() {
return [
{
@@ -139,20 +130,6 @@ export default {
value: this.remoteAppData.comment
}
]
},
detailCardActionData() {
return [
{
name: this.$t('perms.Active'),
is_active: true
}
]
},
remoteAppCardActions() {
return this.$t('perms.RemoteApp')
},
systemUserCardActions() {
return this.$t('perms.SystemUser')
}
},
mounted() {
@@ -161,16 +138,11 @@ export default {
methods: {
getRemoteAppPermissionDetailData() {
getRemoteAppPermissionDetail(this.$route.params.id).then(data => {
console.log('详情数据==>', data)
this.remoteAppData = data
this.activeConfig.content[0].is_active = data.is_active
this.flag = true
})
},
HandleChangeAction: function(index, row) {
const url = `/api/v1/perms/remote-app-permissions/${this.$route.params.id}/`
console.log('点击激活的url==>', url)
console.log('激活的数据==>', row)
},
getDataLength(data) {
if (data instanceof Array) {
return data.length