mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-25 22:36:23 +00:00
Merge branch 'master' of https://github.com/jumpserver/lina
This commit is contained in:
@@ -7,3 +7,17 @@ export function terminateSession(data) {
|
|||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSessionDetail(id) {
|
||||||
|
return request({
|
||||||
|
url: `/api/v1/terminal/sessions/${id}/`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSessionCommands(id) {
|
||||||
|
return request({
|
||||||
|
url: `/api/v1/terminal/commands/?session_id=${id}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<DataForm v-loading="loading" :fields="totalFields" v-bind="$attrs" v-on="$listeners">
|
<DataForm ref="form" v-loading="loading" :fields="totalFields" v-bind="$attrs" v-on="$listeners">
|
||||||
<FormGroupHeader v-for="(group, i) in groups" :slot="'id:'+group.name" :key="'group-'+group.name" :title="group.title" :line="i != 0" />
|
<FormGroupHeader v-for="(group, i) in groups" :slot="'id:'+group.name" :key="'group-'+group.name" :title="group.title" :line="i != 0" />
|
||||||
</DataForm>
|
</DataForm>
|
||||||
</template>
|
</template>
|
||||||
@@ -48,7 +48,6 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.optionUrlMeta()
|
this.optionUrlMeta()
|
||||||
console.log('auto data form', this.$attrs)
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
optionUrlMeta() {
|
optionUrlMeta() {
|
||||||
@@ -76,47 +75,65 @@ export default {
|
|||||||
type = ''
|
type = ''
|
||||||
field.component = Select2
|
field.component = Select2
|
||||||
break
|
break
|
||||||
|
case 'string':
|
||||||
|
type = 'input'
|
||||||
|
if (!fieldMeta.max_length) {
|
||||||
|
field.el.type = 'textarea'
|
||||||
|
}
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
type = 'input'
|
type = 'input'
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if (type === 'radio-group') {
|
||||||
|
const options = fieldMeta.choices.map(v => {
|
||||||
|
return { label: v.display_name, value: v.value }
|
||||||
|
})
|
||||||
|
if (options.length > 4) {
|
||||||
|
type = 'select'
|
||||||
|
field.el.filterable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
field.type = type
|
field.type = type
|
||||||
return field
|
return field
|
||||||
},
|
},
|
||||||
generateFieldByName(name, field) {
|
generateFieldByName(name, field) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'email':
|
case 'email':
|
||||||
field.el = { type: 'email' }
|
field.el.type = 'email'
|
||||||
break
|
break
|
||||||
case 'password':
|
case 'password':
|
||||||
field.el = { type: 'password' }
|
field.el.type = 'password'
|
||||||
break
|
break
|
||||||
case 'comment':
|
case 'comment':
|
||||||
field.el = { type: 'textarea' }
|
field.el.type = 'textarea'
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return field
|
return field
|
||||||
},
|
},
|
||||||
generateFieldByOther(field, fieldMeta) {
|
generateFieldByOther(field, fieldMeta) {
|
||||||
|
const filedRules = field.rules || []
|
||||||
if (fieldMeta.required) {
|
if (fieldMeta.required) {
|
||||||
if (field.type === 'input') {
|
if (field.type === 'input') {
|
||||||
field.rules = [rules.Required]
|
filedRules.push(rules.Required)
|
||||||
} else {
|
} else {
|
||||||
field.rules = [rules.RequiredChange]
|
filedRules.push(rules.RequiredChange)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
field.rules = filedRules
|
||||||
return field
|
return field
|
||||||
},
|
},
|
||||||
generateField(name) {
|
generateField(name) {
|
||||||
let field = {}
|
let field = { id: name, prop: name, el: {}}
|
||||||
const fieldMeta = this.meta[name] || {}
|
const fieldMeta = this.meta[name] || {}
|
||||||
field.id = name
|
|
||||||
field.prop = name
|
|
||||||
field.label = fieldMeta.label
|
field.label = fieldMeta.label
|
||||||
field = this.generateFieldByType(fieldMeta.type, field, fieldMeta)
|
field = this.generateFieldByType(fieldMeta.type, field, fieldMeta)
|
||||||
field = this.generateFieldByName(name, field)
|
field = this.generateFieldByName(name, field)
|
||||||
field = this.generateFieldByOther(field, fieldMeta)
|
field = this.generateFieldByOther(field, fieldMeta)
|
||||||
field = Object.assign(field, this.fieldsMeta[name] || {})
|
field = Object.assign(field, this.fieldsMeta[name] || {})
|
||||||
|
if (name === 'name') {
|
||||||
|
console.log(field)
|
||||||
|
}
|
||||||
return field
|
return field
|
||||||
},
|
},
|
||||||
generateFieldGroup(data) {
|
generateFieldGroup(data) {
|
||||||
@@ -132,9 +149,6 @@ export default {
|
|||||||
generateFields(data) {
|
generateFields(data) {
|
||||||
let fields = []
|
let fields = []
|
||||||
for (let field of data) {
|
for (let field of data) {
|
||||||
console.log('is array', field instanceof Array)
|
|
||||||
console.log('is string', typeof field === 'string')
|
|
||||||
console.log('is object', field instanceof Object)
|
|
||||||
if (field instanceof Array) {
|
if (field instanceof Array) {
|
||||||
const items = this.generateFieldGroup(field)
|
const items = this.generateFieldGroup(field)
|
||||||
fields = [...fields, ...items]
|
fields = [...fields, ...items]
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DataTable from '../DataTable'
|
import DataTable from '../DataTable'
|
||||||
import { DetailFormatter, DisplayFormatter, BooleanFormatter, ActionsFormatter } from '@/components/ListTable/formatters/index'
|
import { DetailFormatter, DisplayFormatter, BooleanFormatter, ActionsFormatter } from '@/components/ListTable/formatters'
|
||||||
import { optionUrlMeta } from '@/api/common'
|
import { optionUrlMeta } from '@/api/common'
|
||||||
export default {
|
export default {
|
||||||
name: 'AutoDataTable',
|
name: 'AutoDataTable',
|
||||||
@@ -25,6 +25,11 @@ export default {
|
|||||||
meta: {}
|
meta: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
expandField() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.optionUrlMeta()
|
this.optionUrlMeta()
|
||||||
},
|
},
|
||||||
@@ -54,7 +59,8 @@ export default {
|
|||||||
label: this.$tc('Actions'),
|
label: this.$tc('Actions'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
formatter: ActionsFormatter,
|
formatter: ActionsFormatter,
|
||||||
width: '200px'
|
width: '150px',
|
||||||
|
actions: this.config.actions || {}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'is_valid':
|
case 'is_valid':
|
||||||
|
@@ -42,7 +42,9 @@
|
|||||||
v-else-if="data.type === 'checkbox-group'"
|
v-else-if="data.type === 'checkbox-group'"
|
||||||
:key="opt.label"
|
:key="opt.label"
|
||||||
v-bind="opt"
|
v-bind="opt"
|
||||||
/>
|
>
|
||||||
|
{{ opt.value }}
|
||||||
|
</el-checkbox>
|
||||||
<!-- WARNING: radio 用 label 属性来表示 value 的含义 -->
|
<!-- WARNING: radio 用 label 属性来表示 value 的含义 -->
|
||||||
<!-- FYI: radio 的 value 属性可以在没有 radio-group 时用来关联到同一个 v-model -->
|
<!-- FYI: radio 的 value 属性可以在没有 radio-group 时用来关联到同一个 v-model -->
|
||||||
<el-radio
|
<el-radio
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<ElFormRender
|
<ElFormRender
|
||||||
ref="dataForm"
|
ref="form"
|
||||||
:content="fields"
|
:content="fields"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:form="basicForm"
|
:form="basicForm"
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
<el-form-item v-if="defaultButton">
|
<el-form-item v-if="defaultButton">
|
||||||
<slot name="button-start" />
|
<slot name="button-start" />
|
||||||
<el-button size="small" @click="resetForm('dataForm')">{{ $tc('Reset') }}</el-button>
|
<el-button size="small" @click="resetForm('form')">{{ $tc('Reset') }}</el-button>
|
||||||
<el-button size="small" type="primary" @click="submitForm('dataForm')">{{ $tc('Submit') }}</el-button>
|
<el-button size="small" type="primary" @click="submitForm('form')">{{ $tc('Submit') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<slot name="Actions" />
|
<slot name="Actions" />
|
||||||
</ElFormRender>
|
</ElFormRender>
|
||||||
@@ -53,9 +53,10 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
// 获取表单数据
|
// 获取表单数据
|
||||||
submitForm(formName) {
|
submitForm(formName) {
|
||||||
this.$refs[formName].validate((valid) => {
|
const form = this.$refs[formName]
|
||||||
|
form.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$emit('submit', this.$refs[formName].getFormValue())
|
this.$emit('submit', form.getFormValue(), form)
|
||||||
} else {
|
} else {
|
||||||
this.$emit('invalid', valid)
|
this.$emit('invalid', valid)
|
||||||
return false
|
return false
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
<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>
|
15
src/components/ListTable/formatters/ExpandPreFormatter.vue
Normal file
15
src/components/ListTable/formatters/ExpandPreFormatter.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<pre>{{ cellValue }}</pre>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BaseFormatter from './base'
|
||||||
|
export default {
|
||||||
|
name: 'ExpandPreFormatter',
|
||||||
|
extends: BaseFormatter
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@@ -0,0 +1,21 @@
|
|||||||
|
<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>
|
23
src/components/ListTable/formatters/RouterFormatter.vue
Normal file
23
src/components/ListTable/formatters/RouterFormatter.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<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>
|
@@ -1,6 +1,33 @@
|
|||||||
export { default as DetailFormatter } from './DetailFormatter'
|
import DetailFormatter from './DetailFormatter'
|
||||||
export { default as DisplayFormatter } from './DisplayFormatter'
|
import DisplayFormatter from './DisplayFormatter'
|
||||||
export { default as BooleanFormatter } from './ChoicesFormatter'
|
import BooleanFormatter from './ChoicesFormatter'
|
||||||
export { default as ActionsFormatter } from './ActionsFormatter'
|
import ActionsFormatter from './ActionsFormatter'
|
||||||
export { default as LengthFormatter } from './LengthFormatter'
|
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
|
||||||
|
}
|
||||||
|
@@ -67,7 +67,10 @@ const cn = {
|
|||||||
'cancel': '取消',
|
'cancel': '取消',
|
||||||
'Import': '导入',
|
'Import': '导入',
|
||||||
'Export': '导出',
|
'Export': '导出',
|
||||||
'Other': '其它'
|
'Other': '其它',
|
||||||
|
'Create success': '创建成功',
|
||||||
|
'Deactive selected': '禁用所选',
|
||||||
|
'Active selected': '激活所选'
|
||||||
},
|
},
|
||||||
route: {
|
route: {
|
||||||
'dashboard': '仪表盘',
|
'dashboard': '仪表盘',
|
||||||
@@ -96,6 +99,7 @@ const cn = {
|
|||||||
'Sessions': '会话管理',
|
'Sessions': '会话管理',
|
||||||
'SessionOnline': '在线会话',
|
'SessionOnline': '在线会话',
|
||||||
'SessionOffline': '历史会话',
|
'SessionOffline': '历史会话',
|
||||||
|
'SessionDetail': '会话详情',
|
||||||
'Commands': '命令记录',
|
'Commands': '命令记录',
|
||||||
'WebTerminal': 'Web终端',
|
'WebTerminal': 'Web终端',
|
||||||
'FileManager': '文件管理',
|
'FileManager': '文件管理',
|
||||||
@@ -112,7 +116,8 @@ const cn = {
|
|||||||
'PasswordChangeLog': '改密日志',
|
'PasswordChangeLog': '改密日志',
|
||||||
'Settings': '系统设置',
|
'Settings': '系统设置',
|
||||||
'UserCreate': '创建用户',
|
'UserCreate': '创建用户',
|
||||||
'UserGroupCreate': '创建用户组'
|
'UserGroupCreate': '创建用户组',
|
||||||
|
'UserUpdate': '更新用户'
|
||||||
},
|
},
|
||||||
// 用户模块翻译
|
// 用户模块翻译
|
||||||
users: {
|
users: {
|
||||||
@@ -326,41 +331,22 @@ const cn = {
|
|||||||
'app_path': '应用路径'
|
'app_path': '应用路径'
|
||||||
},
|
},
|
||||||
perms: {
|
perms: {
|
||||||
'asset_permission': '资产授权',
|
|
||||||
'asset_permission_list': '资产授权列表',
|
|
||||||
'asset_permission_detail': '资产授权详情',
|
|
||||||
'create_asset_permission': '创建资产授权规则',
|
|
||||||
'update_asset_permission': '更新资产授权规则',
|
|
||||||
'Asset permissions': '资产授权',
|
'Asset permissions': '资产授权',
|
||||||
'name': '名称',
|
'RefreshPermissionCache': '刷新授权缓存',
|
||||||
'user': '用户',
|
'ReFreshSuccess': '刷新成功',
|
||||||
'userGroup': '用户组',
|
'ReFreshFail': '刷新失败',
|
||||||
'asset': '资产',
|
'All': '全部',
|
||||||
'node': '节点',
|
'Connect': '连接',
|
||||||
'systemUser': '系统用户',
|
'UpDownload': '上传下载',
|
||||||
'validity': '有效',
|
'UploadFile': '上传文件',
|
||||||
'action': '动作',
|
'DownloadFile': '下载文件',
|
||||||
'update': '更新',
|
|
||||||
'delete': '删除',
|
|
||||||
'search': '搜索',
|
|
||||||
'user_count': '用户数量',
|
|
||||||
'user_group_count': '用户组数量',
|
|
||||||
'asset_count': '资产数量',
|
|
||||||
'node_count': '节点数量',
|
|
||||||
'system_user_count': '系统用户数量',
|
|
||||||
'date_start': '开始日期',
|
|
||||||
'date_expired': '失效日期',
|
|
||||||
'date_created': '创建日期',
|
|
||||||
'created_by': '创建者',
|
|
||||||
'comment': '备注',
|
|
||||||
'quick_update': '快速更新',
|
|
||||||
'active': '激活中',
|
|
||||||
'users_and_user_groups': '用户或用户组',
|
|
||||||
'assets_and_node': '资产或节点',
|
|
||||||
'Basic': '基本',
|
'Basic': '基本',
|
||||||
'User': '用户',
|
'User': '用户',
|
||||||
'Asset': '资产',
|
'Asset': '资产',
|
||||||
'Actions': '动作',
|
'Actions': '动作',
|
||||||
|
'UserGroups': '用户组',
|
||||||
|
'Node': '节点',
|
||||||
|
'SystemUser': '系统用户',
|
||||||
//
|
//
|
||||||
'RemoteApp': '远程应用',
|
'RemoteApp': '远程应用',
|
||||||
//
|
//
|
||||||
@@ -373,30 +359,33 @@ const cn = {
|
|||||||
'systemUser': '系统用户',
|
'systemUser': '系统用户',
|
||||||
'remoteAddr': '远端地址',
|
'remoteAddr': '远端地址',
|
||||||
'protocol': '协议',
|
'protocol': '协议',
|
||||||
'loginForm': '登录来源',
|
'loginFrom': '登录来源',
|
||||||
'command': '命令',
|
'command': '命令',
|
||||||
'dateStart': '开始日期',
|
'dateStart': '开始日期',
|
||||||
'duration': '时长',
|
'duration': '时长',
|
||||||
'terminate': '终断',
|
'terminate': '终断',
|
||||||
'date_end': '结束日期',
|
'dateEnd': '结束日期',
|
||||||
'commands': '命令记录',
|
'commands': '命令记录',
|
||||||
'replay': '回放',
|
'replay': '回放',
|
||||||
'download': '下载',
|
'download': '下载',
|
||||||
'RiskLevel': '风险等级',
|
'riskLevel': '风险等级',
|
||||||
'session': '会话',
|
'session': '会话',
|
||||||
'date': '日期',
|
'date': '日期',
|
||||||
'addr': '地址',
|
'addr': '地址',
|
||||||
'active': '激活中',
|
'active': '激活中',
|
||||||
'alive': '在线',
|
'alive': '在线',
|
||||||
'StorageConfiguration': '存储配置',
|
'StorageConfiguration': '存储配置',
|
||||||
'join': '加入'
|
'join': '加入',
|
||||||
|
'goto': '转到',
|
||||||
|
'sessionDetail': '会话详情',
|
||||||
|
'quickModify': '快速修改'
|
||||||
},
|
},
|
||||||
jobcenter: {
|
jobcenter: {
|
||||||
'RunTimes': '执行次数',
|
'RunTimes': '执行次数',
|
||||||
'hosts': '主机',
|
'Hosts': '主机',
|
||||||
'success': '成功',
|
'Success': '成功',
|
||||||
'date': '日期',
|
'Date': '日期',
|
||||||
'time': '时间',
|
'Time': '时间',
|
||||||
'run': '执行'
|
'run': '执行'
|
||||||
},
|
},
|
||||||
tickets: {
|
tickets: {
|
||||||
|
@@ -18,7 +18,11 @@ const en = {
|
|||||||
'assets': 'Assets',
|
'assets': 'Assets',
|
||||||
'applications': 'Applications',
|
'applications': 'Applications',
|
||||||
'perms': 'Perms',
|
'perms': 'Perms',
|
||||||
'sessions': 'Sessions',
|
'Sessions': 'Sessions',
|
||||||
|
'SessionOnline': 'Session Online',
|
||||||
|
'SessionOffline': 'Session Offline',
|
||||||
|
'SessionDetail': 'Session Detail',
|
||||||
|
'Goto': 'Goto',
|
||||||
'jobcenter': 'Job Center'
|
'jobcenter': 'Job Center'
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
@@ -265,18 +269,16 @@ const en = {
|
|||||||
'database_app_count': 'DatabaseApp count'
|
'database_app_count': 'DatabaseApp count'
|
||||||
},
|
},
|
||||||
sessions: {
|
sessions: {
|
||||||
'session_online_list': '',
|
|
||||||
'session_detail': ' Session detail',
|
|
||||||
'id': '',
|
'id': '',
|
||||||
'user': 'Use',
|
'user': 'Use',
|
||||||
'asset': 'Asset',
|
'asset': 'Asset',
|
||||||
'system_user': 'System user',
|
'systemUser': 'System user',
|
||||||
'remote_addr': 'Remote addr',
|
'remoteAddr': 'Remote addr',
|
||||||
'protocol': 'Protocol',
|
'protocol': 'Protocol',
|
||||||
'login_form': 'Login from',
|
'loginFrom': 'Login from',
|
||||||
'command': 'Command',
|
'command': 'Command',
|
||||||
'date_start': 'Date start',
|
'dateStart': 'Date start',
|
||||||
'duration': 'Druation',
|
'duration': 'Duration',
|
||||||
'action': 'Action',
|
'action': 'Action',
|
||||||
'search': 'Search',
|
'search': 'Search',
|
||||||
'terminate_selected': 'Terminate selected',
|
'terminate_selected': 'Terminate selected',
|
||||||
@@ -284,12 +286,15 @@ const en = {
|
|||||||
'submit': 'Submit',
|
'submit': 'Submit',
|
||||||
'terminate': 'Terminate',
|
'terminate': 'Terminate',
|
||||||
'command_list': 'Command list',
|
'command_list': 'Command list',
|
||||||
'date_end': 'Date end',
|
'dateEnd': 'Date end',
|
||||||
'quick_modify': 'Quick modify',
|
'quick_modify': 'Quick modify',
|
||||||
'terminate_session': 'Terminate session',
|
'terminate_session': 'Terminate session',
|
||||||
'confirm': 'Confirm',
|
'confirm': 'Confirm',
|
||||||
'commands': 'Commands',
|
'commands': 'Commands',
|
||||||
'join': 'join'
|
'join': 'join',
|
||||||
|
'goto': 'Goto',
|
||||||
|
'sessionDetail': 'Session Detail',
|
||||||
|
'quickModify': 'Quick Modify'
|
||||||
},
|
},
|
||||||
setting: {
|
setting: {
|
||||||
'setting': 'System Setting',
|
'setting': 'System Setting',
|
||||||
|
@@ -1,10 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page v-loading="loadding">
|
||||||
<IBox>
|
<IBox>
|
||||||
<AutoDataForm :form="form" :fields="fields" :url="url" v-bind="$attrs" v-on="$listeners" @submit="handleSubmit">
|
<AutoDataForm
|
||||||
<slot v-for="item in fields" :slot="`id:${item}`" :name="`id:${item}`" />
|
v-if="!loadding"
|
||||||
<slot v-for="item in fields" :slot="`$id:${item}`" :name="`$id:${item}`" />
|
ref="form"
|
||||||
</AutoDataForm>
|
:method="method"
|
||||||
|
:form="form"
|
||||||
|
:fields="fields"
|
||||||
|
:url="totalUrl"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-on="$listeners"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
/>
|
||||||
</IBox>
|
</IBox>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
@@ -21,46 +28,105 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
method: {
|
|
||||||
type: String,
|
|
||||||
default: 'post'
|
|
||||||
},
|
|
||||||
fields: {
|
fields: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => {
|
default: () => {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
form: {
|
object: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => { return {} }
|
default: () => ({})
|
||||||
|
},
|
||||||
|
initial: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
},
|
},
|
||||||
onSubmit: {
|
onSubmit: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: null
|
default: null
|
||||||
|
},
|
||||||
|
getMethod: {
|
||||||
|
type: Function,
|
||||||
|
default: function() {
|
||||||
|
const params = this.$route.params
|
||||||
|
if (params.id) {
|
||||||
|
return 'put'
|
||||||
|
} else {
|
||||||
|
return 'post'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getUrl: {
|
||||||
|
type: Function,
|
||||||
|
default: function() {
|
||||||
|
const params = this.$route.params
|
||||||
|
let url = this.url
|
||||||
|
if (params.id) {
|
||||||
|
url = `${url}/${params.id}/`
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {},
|
||||||
|
loadding: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
method() {
|
||||||
|
const method = this.getMethod(this)
|
||||||
|
return method
|
||||||
|
},
|
||||||
|
totalUrl() {
|
||||||
|
return this.getUrl()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
console.log('generic', this.$attrs)
|
if (this.method === 'put') {
|
||||||
console.log(this.fields)
|
this.getObjectDetail()
|
||||||
|
} else {
|
||||||
|
this.form = Object.assign(this.form, this.initial)
|
||||||
|
this.loadding = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSubmit(values) {
|
handleSubmit(values, form) {
|
||||||
let handler = this.onSubmit || this.defaultOnSubmit
|
let handler = this.onSubmit || this.defaultOnSubmit
|
||||||
handler = handler.bind(this)
|
handler = handler.bind(this)
|
||||||
|
const fields = form.$refs.elForm.fields
|
||||||
console.log('submit', values)
|
console.log('submit', values)
|
||||||
return handler(values)
|
console.log('form.fields', fields)
|
||||||
|
return handler(values, form)
|
||||||
},
|
},
|
||||||
defaultOnSubmit(validValues) {
|
defaultPerformSubmit(validValues) {
|
||||||
this.$axios.post(this.url, validValues).then(
|
return this.$axios[this.method](this.totalUrl, validValues)
|
||||||
() => {
|
},
|
||||||
const msg = this.$tc('Create success')
|
defaultOnSubmit(validValues, form) {
|
||||||
this.$message.success(msg)
|
this.defaultPerformSubmit(validValues).then(() => {
|
||||||
setTimeout(() => {
|
const msg = this.$tc('Create success')
|
||||||
this.$router.push({ name: 'UserList' })
|
this.$message.success(msg)
|
||||||
}, 500)
|
this.$router.push({ name: 'UserList' })
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(form)
|
||||||
|
const response = error.response
|
||||||
|
const data = response.data
|
||||||
|
if (response.status === 400) {
|
||||||
|
this.errors.name = '你报错了滴滴滴'
|
||||||
|
console.log(data)
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
},
|
||||||
|
getObjectDetail() {
|
||||||
|
this.$axios.get(this.totalUrl).then(data => {
|
||||||
|
this.form = data
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
}).finally(() => {
|
||||||
|
this.loadding = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
import Page from '../Page/'
|
import Page from '../Page/'
|
||||||
import ActionsGroup from '@/components/ActionsGroup'
|
import ActionsGroup from '@/components/ActionsGroup'
|
||||||
export default {
|
export default {
|
||||||
name: 'BaseDetailPage',
|
name: 'GenericDetailPage',
|
||||||
components: {
|
components: {
|
||||||
Page,
|
Page,
|
||||||
ActionsGroup
|
ActionsGroup
|
@@ -3,7 +3,7 @@ export { default as NavHeader } from './NavHeader'
|
|||||||
export { default as AppMain } from './AppMain'
|
export { default as AppMain } from './AppMain'
|
||||||
export { default as Page } from './Page'
|
export { default as Page } from './Page'
|
||||||
export { default as TagsView } from './TagsView'
|
export { default as TagsView } from './TagsView'
|
||||||
export { default as BaseDetailPage } from './BaseDetailPage'
|
export { default as GenericDetailPage } from './GenericDetailPage'
|
||||||
export { default as SubMenuPage } from './SubMenuPage'
|
export { default as SubMenuPage } from './SubMenuPage'
|
||||||
export { default as Footer } from './Footer'
|
export { default as Footer } from './Footer'
|
||||||
export { default as IBox } from './IBox'
|
export { default as IBox } from './IBox'
|
||||||
|
@@ -70,14 +70,14 @@ export const constantRoutes = [
|
|||||||
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
||||||
name: 'UserCreate',
|
name: 'UserCreate',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: 'UserCreate', activeMenu: '/users/users' }
|
meta: { title: 'UserCreate', activeMenu: '/users/users', action: 'create' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'users/update/:id',
|
path: 'users/:id/update',
|
||||||
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
||||||
name: 'UserEdit',
|
name: 'UserUpdate',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: 'UserEdit' }
|
meta: { title: 'UserUpdate', activeMenu: '/users/users', action: 'update' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'users/detail/:id',
|
path: 'users/detail/:id',
|
||||||
@@ -274,6 +274,13 @@ export const constantRoutes = [
|
|||||||
component: () => import('@/views/sessions/CommandList'),
|
component: () => import('@/views/sessions/CommandList'),
|
||||||
meta: { title: 'Commands' }
|
meta: { title: 'Commands' }
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'sessions/:id',
|
||||||
|
name: 'SessionDetail',
|
||||||
|
component: () => import('@/views/sessions/SessionDetail'),
|
||||||
|
meta: { title: 'SessionDetail' },
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'luna',
|
path: 'luna',
|
||||||
name: 'WebTerminal',
|
name: 'WebTerminal',
|
||||||
|
@@ -235,3 +235,29 @@ td .el-button.el-button--mini {
|
|||||||
.el-radio__input.is-checked+.el-radio__label {
|
.el-radio__input.is-checked+.el-radio__label {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-radio__input.is-checked .el-radio__inner {
|
||||||
|
border-color: #409EFF;
|
||||||
|
background-color: #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-checkbox__input.is-checked .el-checkbox__inner {
|
||||||
|
border-color: #409EFF;
|
||||||
|
background-color: #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-radio__inner:hover {
|
||||||
|
border-color: #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-checkbox__input.is-checked .el-checkbox__inner, .el-checkbox__input.is-indeterminate .el-checkbox__inner {
|
||||||
|
border-color: #409EFF;
|
||||||
|
background-color: #409EFF;
|
||||||
|
}
|
||||||
|
.el-checkbox__inner:hover {
|
||||||
|
border-color: #409EFF;
|
||||||
|
}
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
@import './sidebar.scss';
|
@import './sidebar.scss';
|
||||||
@import './element-index.css';
|
@import './element-index.css';
|
||||||
@import './menu.scss';
|
@import './menu.scss';
|
||||||
@import 'vue-select/src/scss/vue-select.scss';
|
|
||||||
@import "./font-awesome/font-awesome.min.css";
|
@import "./font-awesome/font-awesome.min.css";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@@ -53,37 +53,34 @@ service.interceptors.response.use(
|
|||||||
const res = response.data
|
const res = response.data
|
||||||
|
|
||||||
// if the custom code is not 20000, it is judged as an error.
|
// if the custom code is not 20000, it is judged as an error.
|
||||||
if (response.status < 200 || response.status > 300) {
|
if (response.status >= 200 && response.status < 400) {
|
||||||
|
if (response.config.raw === 1) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
} else if (response.status === 50008 || response.status === 50012 || response.status === 50014) {
|
||||||
|
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
|
||||||
|
confirmButtonText: 'Re-Login',
|
||||||
|
cancelButtonText: 'Cancel',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
store.dispatch('user/resetToken').then(() => {
|
||||||
|
location.reload()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else if (response.status === 400) {
|
||||||
|
console.log('status is 400')
|
||||||
|
return Promise.reject(res || 'Error')
|
||||||
|
} else {
|
||||||
Message({
|
Message({
|
||||||
message: res.message || res.error || 'Error',
|
message: res.message || res.error || 'Error',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
duration: 5 * 1000
|
duration: 5 * 1000
|
||||||
})
|
})
|
||||||
|
|
||||||
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
|
||||||
// 自定义错误码
|
|
||||||
if (response.status === 50008 || response.status === 50012 || response.status === 50014) {
|
|
||||||
// to re-login
|
|
||||||
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
|
|
||||||
confirmButtonText: 'Re-Login',
|
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
store.dispatch('user/resetToken').then(() => {
|
|
||||||
location.reload()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return Promise.reject(new Error(res.message || 'Error'))
|
return Promise.reject(new Error(res.message || 'Error'))
|
||||||
} else {
|
|
||||||
if (response.config.raw === 1) {
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('err' + error) // for debug
|
|
||||||
Message({
|
Message({
|
||||||
message: error.message,
|
message: error.message,
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
@@ -3,8 +3,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { timeOffset, toSafeLocalDateStr } from '@/utils/common'
|
||||||
import { GenericListPage } from '@/layout/components'
|
import { GenericListPage } from '@/layout/components'
|
||||||
import { DetailFormatter, ActionsFormatter } from '@/components/ListTable/formatters/index'
|
import { ActionsFormatter } from '@/components/ListTable/formatters/index'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -14,47 +15,71 @@ export default {
|
|||||||
return {
|
return {
|
||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: '/api/v1/ops/tasks/',
|
url: '/api/v1/ops/tasks/',
|
||||||
columns: [
|
columns: ['name', 'runtimes', 'host_amount', 'is_success', 'date_start', 'time', 'actions'],
|
||||||
{
|
columnsMeta: {
|
||||||
prop: 'name',
|
name: {
|
||||||
label: this.$tc('Name'),
|
label: this.$tc('Name'),
|
||||||
formatter: DetailFormatter,
|
showOverflowTooltip: true
|
||||||
sortable: 'custom',
|
|
||||||
route: 'UserDetail'
|
|
||||||
},
|
},
|
||||||
{
|
runtimes: {
|
||||||
prop: 'latest_execution',
|
label: this.$t('jobcenter.RunTimes'),
|
||||||
label: this.$t('jobcenter.RunTimes')
|
formatter: function(row) {
|
||||||
|
const summary = <div>
|
||||||
|
<span class='text-primary'>{row.summary.success}</span>/
|
||||||
|
<span class='text-danger'>{row.summary.failed}</span>/
|
||||||
|
<span>{row.summary.total}</span>
|
||||||
|
</div>
|
||||||
|
return summary
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
host_amount: {
|
||||||
prop: 'latest_execution.hosts_amount',
|
label: this.$t('jobcenter.Hosts'),
|
||||||
label: this.$t('jobcenter.hosts')
|
formatter: function(row) {
|
||||||
|
return row.latest_execution.hosts_amount
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
is_success: {
|
||||||
prop: 'latest_execution.is_success',
|
label: this.$t('jobcenter.Success'),
|
||||||
label: this.$t('jobcenter.success')
|
formatter: row => {
|
||||||
|
if (row.latest_execution.is_success) {
|
||||||
|
return <i class='fa fa-check text-primary'/>
|
||||||
|
}
|
||||||
|
return <i class='fa fa-times text-danger'/>
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
date_start: {
|
||||||
prop: 'latest_execution.date_start',
|
label: this.$t('jobcenter.Date'),
|
||||||
label: this.$t('jobcenter.date'),
|
formatter: function(row) {
|
||||||
sortable: 'custom'
|
return toSafeLocalDateStr(row.latest_execution.date_start)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
time: {
|
||||||
prop: 'latest_execution.timedelta',
|
label: this.$t('jobcenter.Time'),
|
||||||
label: this.$t('jobcenter.time')
|
formatter: function(row) {
|
||||||
|
return timeOffset(row.latest_execution.date_start, row.latest_execution.date_finished)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
actions: {
|
||||||
prop: 'id',
|
prop: 'id',
|
||||||
label: this.$tc('Action'),
|
label: this.$tc('Action'),
|
||||||
align: 'center',
|
|
||||||
formatter: ActionsFormatter,
|
formatter: ActionsFormatter,
|
||||||
width: '200px',
|
actions: {
|
||||||
actions: [
|
hasUpdate: false,
|
||||||
]
|
extraActions: [
|
||||||
|
{
|
||||||
|
name: 'run',
|
||||||
|
title: this.$t('jobcenter.run'),
|
||||||
|
type: 'primary',
|
||||||
|
callback: function({ cellValue, tableData }) {
|
||||||
|
// 跳转页面
|
||||||
|
const replayUrl = '/ops/celery/task/' + cellValue
|
||||||
|
window.open(replayUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
}
|
||||||
hasEdit: false,
|
|
||||||
hasDelete: false
|
|
||||||
},
|
},
|
||||||
headerActions: {
|
headerActions: {
|
||||||
hasCreate: false,
|
hasCreate: false,
|
||||||
|
@@ -11,6 +11,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
|
is_active: true,
|
||||||
|
actions: ['all', 'connect', 'updownload', 'upload_file', 'download_file'],
|
||||||
date_expired: '2099-12-31 00:00:00 +0800'
|
date_expired: '2099-12-31 00:00:00 +0800'
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
@@ -53,7 +55,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
label: this.$t('perms.Actions')
|
label: this.$t('perms.Actions'),
|
||||||
|
type: 'checkbox-group',
|
||||||
|
options: [
|
||||||
|
{ label: 'all', value: this.$t('perms.All') },
|
||||||
|
{ label: 'connect', value: this.$t('perms.Connect') },
|
||||||
|
{ label: 'updownload', value: this.$t('perms.UpDownload') },
|
||||||
|
{ label: 'upload_file', value: this.$t('perms.UploadFile') },
|
||||||
|
{ label: 'download_file', value: this.$t('perms.DownloadFile') }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
is_active: {
|
is_active: {
|
||||||
type: 'checkbox'
|
type: 'checkbox'
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { GenericListPage } from '@/layout/components'
|
import { GenericListPage } from '@/layout/components'
|
||||||
import { LengthFormatter } from '@/components/ListTable/formatters/index'
|
import { LengthFormatter, ExpandAssetPermissionFormatter } from '@/components/ListTable/formatters/index'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -14,8 +14,13 @@ export default {
|
|||||||
return {
|
return {
|
||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: '/api/v1/perms/asset-permissions/',
|
url: '/api/v1/perms/asset-permissions/',
|
||||||
columns: ['name', 'users', 'user_groups', 'assets', 'nodes', 'system_users', 'is_active', 'actions'],
|
hasSelection: false,
|
||||||
|
columns: ['expand', 'name', 'users', 'user_groups', 'assets', 'nodes', 'system_users', 'is_active', 'actions'],
|
||||||
columnsMeta: {
|
columnsMeta: {
|
||||||
|
expand: {
|
||||||
|
type: 'expand',
|
||||||
|
formatter: ExpandAssetPermissionFormatter
|
||||||
|
},
|
||||||
users: {
|
users: {
|
||||||
formatter: LengthFormatter
|
formatter: LengthFormatter
|
||||||
},
|
},
|
||||||
@@ -36,9 +41,29 @@ export default {
|
|||||||
headerActions: {
|
headerActions: {
|
||||||
hasDelete: false,
|
hasDelete: false,
|
||||||
hasUpdate: false,
|
hasUpdate: false,
|
||||||
createRoute: 'AssetPermissionCreate'
|
hasBulkDelete: false,
|
||||||
|
createRoute: 'AssetPermissionCreate',
|
||||||
|
extraActions: [
|
||||||
|
{
|
||||||
|
name: 'RefreshPermissionCache',
|
||||||
|
title: this.$t('perms.RefreshPermissionCache'),
|
||||||
|
type: 'primary',
|
||||||
|
has: true,
|
||||||
|
callback: this.HandleRefreshPermissionCache
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
HandleRefreshPermissionCache() {
|
||||||
|
const url = '/api/v1/perms/asset-permissions/cache/refresh/'
|
||||||
|
this.$axios.get(url).then(res => {
|
||||||
|
this.$message.success(this.$t('perms.ReFreshSuccess'))
|
||||||
|
}).catch(err => {
|
||||||
|
this.$message.error(this.$t('perms.ReFreshFail') + ':' + err)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { GenericListPage } from '@/layout/components'
|
import { GenericListPage } from '@/layout/components'
|
||||||
|
import { toSafeLocalDateStr } from '@/utils/common'
|
||||||
|
import { RouterFormatter, OutputExpandFormatter } from '@/components/ListTable/formatters'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -12,55 +14,47 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tableConfig: {
|
tableConfig: {
|
||||||
axiosConfig: {
|
|
||||||
raw: 1,
|
|
||||||
params: {
|
|
||||||
display: 1,
|
|
||||||
is_finished: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hasSelection: false,
|
hasSelection: false,
|
||||||
hasOperation: false,
|
|
||||||
url: '/api/v1/terminal/commands/',
|
url: '/api/v1/terminal/commands/',
|
||||||
columns: [
|
columns: [
|
||||||
{
|
'expandCol', 'input', 'risk_level', 'user',
|
||||||
type: 'expand'
|
'asset', 'system_user', 'session', 'timestamp'
|
||||||
|
],
|
||||||
|
columnsMeta: {
|
||||||
|
expandCol: {
|
||||||
|
type: 'expand',
|
||||||
|
prop: 'output',
|
||||||
|
formatter: OutputExpandFormatter
|
||||||
},
|
},
|
||||||
{
|
input: {
|
||||||
prop: 'input',
|
|
||||||
label: this.$t('sessions.command')
|
label: this.$t('sessions.command')
|
||||||
},
|
},
|
||||||
{
|
risk_level: {
|
||||||
prop: 'output',
|
label: this.$t('sessions.riskLevel')
|
||||||
label: '命令输出结果 (怎么放到隐藏内容 ??)',
|
|
||||||
expand: true
|
|
||||||
},
|
},
|
||||||
{
|
user: {
|
||||||
prop: 'risk_level',
|
label: this.$t('sessions.user')
|
||||||
label: this.$t('sessions.RiskLevel')
|
|
||||||
},
|
},
|
||||||
{
|
asset: {
|
||||||
prop: 'user',
|
|
||||||
label: this.$t('sessions.user'),
|
|
||||||
sortable: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'asset',
|
|
||||||
label: this.$t('sessions.asset')
|
label: this.$t('sessions.asset')
|
||||||
},
|
},
|
||||||
{
|
system_user: {
|
||||||
prop: 'system_user',
|
|
||||||
label: this.$t('sessions.systemUser')
|
label: this.$t('sessions.systemUser')
|
||||||
},
|
},
|
||||||
{
|
session: {
|
||||||
prop: 'session',
|
label: this.$t('sessions.session'),
|
||||||
label: this.$t('sessions.session')
|
formatter: RouterFormatter,
|
||||||
|
route: 'SessionDetail',
|
||||||
|
linkName: this.$t('sessions.goto')
|
||||||
},
|
},
|
||||||
{
|
timestamp: {
|
||||||
prop: 'timestamp',
|
label: this.$t('sessions.date'),
|
||||||
label: this.$t('sessions.date')
|
formatter: function(row) {
|
||||||
|
return toSafeLocalDateStr(row.timestamp * 1000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
|
||||||
|
},
|
||||||
tableActions: {
|
tableActions: {
|
||||||
hasEdit: false,
|
hasEdit: false,
|
||||||
hasDelete: false
|
hasDelete: false
|
||||||
|
168
src/views/sessions/SessionDetail.vue
Normal file
168
src/views/sessions/SessionDetail.vue
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
|
||||||
|
<div slot="detail">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="14">
|
||||||
|
<DetailCard :title="cardTitle" :items="detailItems" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="10">
|
||||||
|
<el-card class="box-card primary">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<i class="fa fa-user" />
|
||||||
|
<span>{{ cardActions }}</span>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
<div slot="command">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="14">
|
||||||
|
<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-user" />
|
||||||
|
<span>{{ cardActions }}</span>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</GenericDetailPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { GenericDetailPage } from '@/layout/components'
|
||||||
|
import DetailCard from '@/components/DetailCard/index'
|
||||||
|
import ListTable from '@/components/ListTable'
|
||||||
|
import { getSessionDetail, getSessionCommands } from '@/api/sessions'
|
||||||
|
import { OutputExpandFormatter } from '@/components/ListTable/formatters'
|
||||||
|
import { toSafeLocalDateStr } from '@/utils/common'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SessionDetail',
|
||||||
|
components: {
|
||||||
|
GenericDetailPage,
|
||||||
|
DetailCard,
|
||||||
|
ListTable
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tableConfig: {
|
||||||
|
hasSelection: false,
|
||||||
|
url: `/api/v1/terminal/commands/?session_id=${this.$route.params.id}`,
|
||||||
|
columns: [
|
||||||
|
'expandCol', 'index', 'input', 'timestamp'
|
||||||
|
],
|
||||||
|
columnsMeta: {
|
||||||
|
expandCol: {
|
||||||
|
type: 'expand',
|
||||||
|
prop: 'output',
|
||||||
|
formatter: OutputExpandFormatter
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: 'index'
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
label: this.$t('sessions.command')
|
||||||
|
},
|
||||||
|
timestamp: {
|
||||||
|
label: this.$t('sessions.date'),
|
||||||
|
formatter: function(row) {
|
||||||
|
return toSafeLocalDateStr(row.timestamp * 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
headerActions: {
|
||||||
|
hasExport: false,
|
||||||
|
hasImport: false,
|
||||||
|
hasRefresh: false,
|
||||||
|
hasCreate: false,
|
||||||
|
hasBulkDelete: false,
|
||||||
|
hasBulkUpdate: false,
|
||||||
|
hasLeftActions: false,
|
||||||
|
hasSearch: false,
|
||||||
|
hasRightActions: false
|
||||||
|
},
|
||||||
|
activeSubMenu: 'detail',
|
||||||
|
sessionData: {},
|
||||||
|
commandData: {},
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
title: this.$t('route.SessionDetail'),
|
||||||
|
name: 'detail'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('sessions.command'),
|
||||||
|
name: 'command'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
title() {
|
||||||
|
return this.$t('sessions.sessionDetail')
|
||||||
|
},
|
||||||
|
cardTitle() { return this.sessionData.id },
|
||||||
|
cardActions() {
|
||||||
|
return this.$t('sessions.quickModify')
|
||||||
|
},
|
||||||
|
detailItems() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.user'),
|
||||||
|
value: this.sessionData.user
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.asset'),
|
||||||
|
value: this.sessionData.asset
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.systemUser'),
|
||||||
|
value: this.sessionData.system_user
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.protocol'),
|
||||||
|
value: this.sessionData.protocol
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.loginFrom'),
|
||||||
|
value: this.sessionData.login_from
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.remoteAddr'),
|
||||||
|
value: this.sessionData.remote_addr
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.dateStart'),
|
||||||
|
value: this.sessionData.date_start
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.dateEnd'),
|
||||||
|
value: this.sessionData.date_end
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
getSessionDetail(this.$route.params.id).then(data => {
|
||||||
|
this.sessionData = data
|
||||||
|
})
|
||||||
|
|
||||||
|
getSessionCommands(this.$route.params.id).then(data => {
|
||||||
|
this.commandData = data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@@ -22,14 +22,16 @@ export default {
|
|||||||
],
|
],
|
||||||
columnsMeta: {
|
columnsMeta: {
|
||||||
index: {
|
index: {
|
||||||
type: 'index',
|
label: this.$t('sessions.id'),
|
||||||
label: this.$t('sessions.id')
|
formatter: function(row, column, cellValue, index) {
|
||||||
|
return <a class='detail el-link el-link--success is-underline' href= { '/terminal/sessions/' + row.id }>{ index + 1}</a>
|
||||||
|
}
|
||||||
},
|
},
|
||||||
command_amount: {
|
command_amount: {
|
||||||
label: this.$t('sessions.command')
|
label: this.$t('sessions.command')
|
||||||
},
|
},
|
||||||
login_from: {
|
login_from: {
|
||||||
label: this.$t('sessions.loginForm')
|
label: this.$t('sessions.loginFrom')
|
||||||
},
|
},
|
||||||
protocol: {
|
protocol: {
|
||||||
label: this.$t('sessions.protocol'),
|
label: this.$t('sessions.protocol'),
|
||||||
|
@@ -22,8 +22,10 @@ export default {
|
|||||||
],
|
],
|
||||||
columnsMeta: {
|
columnsMeta: {
|
||||||
index: {
|
index: {
|
||||||
type: 'index',
|
label: this.$t('sessions.id'),
|
||||||
label: this.$t('sessions.id')
|
formatter: function(row, column, cellValue, index) {
|
||||||
|
return <a class='detail el-link el-link--success is-underline' href= { '/terminal/sessions/' + row.id }>{ index + 1}</a>
|
||||||
|
}
|
||||||
},
|
},
|
||||||
command_amount: {
|
command_amount: {
|
||||||
label: this.$t('sessions.command')
|
label: this.$t('sessions.command')
|
||||||
|
@@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<GenericCreateUpdatePage :fields="fields" :form="form" :fields-meta="fieldsMeta" :url="url">
|
<GenericCreateUpdatePage :fields="fields" :initial="initial" :fields-meta="fieldsMeta" :url="url" />
|
||||||
<!-- <FormGroupHeader slot="id:name" title="账户" :line="false" />-->
|
|
||||||
<!-- <FormGroupHeader slot="id:password_strategy" title="认证" :line="true" />-->
|
|
||||||
<!-- <FormGroupHeader slot="id:role" title="角色安全" :line="true" />-->
|
|
||||||
<!-- <FormGroupHeader slot="id:phone" title="认证" :line="true" />-->
|
|
||||||
</GenericCreateUpdatePage>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -14,30 +9,46 @@ export default {
|
|||||||
GenericCreateUpdatePage
|
GenericCreateUpdatePage
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const errors = { name: '' }
|
||||||
return {
|
return {
|
||||||
form: {
|
initial: {
|
||||||
password_strategy: 0,
|
password_strategy: 0,
|
||||||
mfa_level: 0,
|
mfa_level: 0,
|
||||||
source: 'ldap',
|
source: 'local',
|
||||||
role: 'Admin',
|
role: 'Admin',
|
||||||
date_expired: '2099-12-31 00:00:00 +0800'
|
date_expired: '2099-12-31 00:00:00 +0800'
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
[this.$t('users.' + 'Account'), ['name', 'username', 'email', 'groups']],
|
[this.$t('users.' + 'Account'), ['name', 'username', 'email', 'groups']],
|
||||||
[this.$t('users.' + 'Authentication'), ['password_strategy', 'password', 'mfa_level', 'source']],
|
[this.$t('users.' + 'Authentication'), ['password_strategy', 'password', 'public_key', 'mfa_level', 'source']],
|
||||||
[this.$t('users.' + 'Secure'), ['role', 'date_expired']],
|
[this.$t('users.' + 'Secure'), ['role', 'date_expired']],
|
||||||
[this.$tc('Other'), ['phone', 'wechat', 'comment']]
|
[this.$tc('Other'), ['phone', 'wechat', 'comment']]
|
||||||
],
|
],
|
||||||
|
errors: errors,
|
||||||
url: '/api/v1/users/users/',
|
url: '/api/v1/users/users/',
|
||||||
fieldsMeta: {
|
fieldsMeta: {
|
||||||
|
name: {
|
||||||
|
el: {
|
||||||
|
error: '无措'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
password_strategy: {
|
||||||
|
hidden: () => {
|
||||||
|
return this.$route.params.id
|
||||||
|
}
|
||||||
|
},
|
||||||
password: {
|
password: {
|
||||||
hidden: (formValue, item) => {
|
hidden: (formValue, item) => {
|
||||||
console.log('hidden password', formValue.password_strategy)
|
console.log('hidden password', formValue.password_strategy)
|
||||||
if (this.$route.params.id === undefined) {
|
if (this.$route.meta.action === 'update') {
|
||||||
return formValue.password_strategy !== 1
|
return false
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return formValue.password_strategy !== 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
public_key: {
|
||||||
|
hidden: (formValue, item) => {
|
||||||
|
return this.$route.meta.action !== 'update'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
groups: {
|
groups: {
|
||||||
@@ -49,6 +60,11 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.errors.name = 'dididi'
|
||||||
|
}, 3000)
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
debug() {
|
debug() {
|
||||||
console.log(this)
|
console.log(this)
|
||||||
@@ -58,10 +74,4 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.el-form /deep/ .el-select{
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
.el-form /deep/ .el-form-item__content > .el-date-editor{
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
|
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
|
||||||
<div slot="info">
|
<div slot="info">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="14">
|
<el-col :span="14">
|
||||||
@@ -18,18 +18,18 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</BaseDetailPage>
|
</GenericDetailPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getUserGroupDetail, getUserGroupMembers } from '@/api/user'
|
import { getUserGroupDetail, getUserGroupMembers } from '@/api/user'
|
||||||
import { BaseDetailPage } from '@/layout/components'
|
import { GenericDetailPage } from '@/layout/components'
|
||||||
import DetailCard from '@/components/DetailCard'
|
import DetailCard from '@/components/DetailCard'
|
||||||
import Select2 from '@/components/Select2'
|
import Select2 from '@/components/Select2'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
BaseDetailPage,
|
GenericDetailPage,
|
||||||
DetailCard,
|
DetailCard,
|
||||||
Select2
|
Select2
|
||||||
},
|
},
|
||||||
|
@@ -26,7 +26,8 @@ export default {
|
|||||||
performBulkDelete: function(rows) {
|
performBulkDelete: function(rows) {
|
||||||
console.log('hello')
|
console.log('hello')
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
helpMessage: '用户列表'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,14 +14,18 @@ export default {
|
|||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: '/api/v1/users/users/',
|
url: '/api/v1/users/users/',
|
||||||
columns: [
|
columns: [
|
||||||
'name', 'username', 'role', 'groups_display', 'source', 'is_active', 'actions'
|
'name', 'username', 'role', 'groups_display', 'source', 'is_valid', 'actions'
|
||||||
],
|
],
|
||||||
detailRoute: 'UserDetail'
|
columnsMeta: {
|
||||||
|
|
||||||
|
},
|
||||||
|
detailRoute: 'UserDetail',
|
||||||
|
actions: {
|
||||||
|
updateRoute: 'UserUpdate'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
headerActions: {
|
headerActions: {
|
||||||
createRoute: 'UserCreate',
|
createRoute: 'UserCreate',
|
||||||
onCreate: () => {
|
|
||||||
},
|
|
||||||
extraMoreActions: [
|
extraMoreActions: [
|
||||||
{
|
{
|
||||||
name: 'deactiveSelected',
|
name: 'deactiveSelected',
|
||||||
|
Reference in New Issue
Block a user