mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-25 14:25: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
|
||||
})
|
||||
}
|
||||
|
||||
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>
|
||||
<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" />
|
||||
</DataForm>
|
||||
</template>
|
||||
@@ -48,7 +48,6 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.optionUrlMeta()
|
||||
console.log('auto data form', this.$attrs)
|
||||
},
|
||||
methods: {
|
||||
optionUrlMeta() {
|
||||
@@ -76,47 +75,65 @@ export default {
|
||||
type = ''
|
||||
field.component = Select2
|
||||
break
|
||||
case 'string':
|
||||
type = 'input'
|
||||
if (!fieldMeta.max_length) {
|
||||
field.el.type = 'textarea'
|
||||
}
|
||||
break
|
||||
default:
|
||||
type = 'input'
|
||||
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
|
||||
return field
|
||||
},
|
||||
generateFieldByName(name, field) {
|
||||
switch (name) {
|
||||
case 'email':
|
||||
field.el = { type: 'email' }
|
||||
field.el.type = 'email'
|
||||
break
|
||||
case 'password':
|
||||
field.el = { type: 'password' }
|
||||
field.el.type = 'password'
|
||||
break
|
||||
case 'comment':
|
||||
field.el = { type: 'textarea' }
|
||||
field.el.type = 'textarea'
|
||||
break
|
||||
}
|
||||
return field
|
||||
},
|
||||
generateFieldByOther(field, fieldMeta) {
|
||||
const filedRules = field.rules || []
|
||||
if (fieldMeta.required) {
|
||||
if (field.type === 'input') {
|
||||
field.rules = [rules.Required]
|
||||
filedRules.push(rules.Required)
|
||||
} else {
|
||||
field.rules = [rules.RequiredChange]
|
||||
filedRules.push(rules.RequiredChange)
|
||||
}
|
||||
}
|
||||
field.rules = filedRules
|
||||
return field
|
||||
},
|
||||
generateField(name) {
|
||||
let field = {}
|
||||
let field = { id: name, prop: name, el: {}}
|
||||
const fieldMeta = this.meta[name] || {}
|
||||
field.id = name
|
||||
field.prop = name
|
||||
field.label = fieldMeta.label
|
||||
field = this.generateFieldByType(fieldMeta.type, field, fieldMeta)
|
||||
field = this.generateFieldByName(name, field)
|
||||
field = this.generateFieldByOther(field, fieldMeta)
|
||||
field = Object.assign(field, this.fieldsMeta[name] || {})
|
||||
if (name === 'name') {
|
||||
console.log(field)
|
||||
}
|
||||
return field
|
||||
},
|
||||
generateFieldGroup(data) {
|
||||
@@ -132,9 +149,6 @@ export default {
|
||||
generateFields(data) {
|
||||
let fields = []
|
||||
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) {
|
||||
const items = this.generateFieldGroup(field)
|
||||
fields = [...fields, ...items]
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
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'
|
||||
export default {
|
||||
name: 'AutoDataTable',
|
||||
@@ -25,6 +25,11 @@ export default {
|
||||
meta: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
expandField() {
|
||||
return true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.optionUrlMeta()
|
||||
},
|
||||
@@ -54,7 +59,8 @@ export default {
|
||||
label: this.$tc('Actions'),
|
||||
align: 'center',
|
||||
formatter: ActionsFormatter,
|
||||
width: '200px'
|
||||
width: '150px',
|
||||
actions: this.config.actions || {}
|
||||
}
|
||||
break
|
||||
case 'is_valid':
|
||||
|
@@ -42,7 +42,9 @@
|
||||
v-else-if="data.type === 'checkbox-group'"
|
||||
:key="opt.label"
|
||||
v-bind="opt"
|
||||
/>
|
||||
>
|
||||
{{ opt.value }}
|
||||
</el-checkbox>
|
||||
<!-- WARNING: radio 用 label 属性来表示 value 的含义 -->
|
||||
<!-- FYI: radio 的 value 属性可以在没有 radio-group 时用来关联到同一个 v-model -->
|
||||
<el-radio
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<ElFormRender
|
||||
ref="dataForm"
|
||||
ref="form"
|
||||
:content="fields"
|
||||
v-bind="$attrs"
|
||||
:form="basicForm"
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
<el-form-item v-if="defaultButton">
|
||||
<slot name="button-start" />
|
||||
<el-button size="small" @click="resetForm('dataForm')">{{ $tc('Reset') }}</el-button>
|
||||
<el-button size="small" type="primary" @click="submitForm('dataForm')">{{ $tc('Submit') }}</el-button>
|
||||
<el-button size="small" @click="resetForm('form')">{{ $tc('Reset') }}</el-button>
|
||||
<el-button size="small" type="primary" @click="submitForm('form')">{{ $tc('Submit') }}</el-button>
|
||||
</el-form-item>
|
||||
<slot name="Actions" />
|
||||
</ElFormRender>
|
||||
@@ -53,9 +53,10 @@ export default {
|
||||
methods: {
|
||||
// 获取表单数据
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
const form = this.$refs[formName]
|
||||
form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit('submit', this.$refs[formName].getFormValue())
|
||||
this.$emit('submit', form.getFormValue(), form)
|
||||
} else {
|
||||
this.$emit('invalid', valid)
|
||||
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'
|
||||
export { default as DisplayFormatter } from './DisplayFormatter'
|
||||
export { default as BooleanFormatter } from './ChoicesFormatter'
|
||||
export { default as ActionsFormatter } from './ActionsFormatter'
|
||||
export { default as LengthFormatter } from './LengthFormatter'
|
||||
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
|
||||
}
|
||||
|
@@ -67,7 +67,10 @@ const cn = {
|
||||
'cancel': '取消',
|
||||
'Import': '导入',
|
||||
'Export': '导出',
|
||||
'Other': '其它'
|
||||
'Other': '其它',
|
||||
'Create success': '创建成功',
|
||||
'Deactive selected': '禁用所选',
|
||||
'Active selected': '激活所选'
|
||||
},
|
||||
route: {
|
||||
'dashboard': '仪表盘',
|
||||
@@ -96,6 +99,7 @@ const cn = {
|
||||
'Sessions': '会话管理',
|
||||
'SessionOnline': '在线会话',
|
||||
'SessionOffline': '历史会话',
|
||||
'SessionDetail': '会话详情',
|
||||
'Commands': '命令记录',
|
||||
'WebTerminal': 'Web终端',
|
||||
'FileManager': '文件管理',
|
||||
@@ -112,7 +116,8 @@ const cn = {
|
||||
'PasswordChangeLog': '改密日志',
|
||||
'Settings': '系统设置',
|
||||
'UserCreate': '创建用户',
|
||||
'UserGroupCreate': '创建用户组'
|
||||
'UserGroupCreate': '创建用户组',
|
||||
'UserUpdate': '更新用户'
|
||||
},
|
||||
// 用户模块翻译
|
||||
users: {
|
||||
@@ -326,41 +331,22 @@ const cn = {
|
||||
'app_path': '应用路径'
|
||||
},
|
||||
perms: {
|
||||
'asset_permission': '资产授权',
|
||||
'asset_permission_list': '资产授权列表',
|
||||
'asset_permission_detail': '资产授权详情',
|
||||
'create_asset_permission': '创建资产授权规则',
|
||||
'update_asset_permission': '更新资产授权规则',
|
||||
'Asset permissions': '资产授权',
|
||||
'name': '名称',
|
||||
'user': '用户',
|
||||
'userGroup': '用户组',
|
||||
'asset': '资产',
|
||||
'node': '节点',
|
||||
'systemUser': '系统用户',
|
||||
'validity': '有效',
|
||||
'action': '动作',
|
||||
'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': '资产或节点',
|
||||
'RefreshPermissionCache': '刷新授权缓存',
|
||||
'ReFreshSuccess': '刷新成功',
|
||||
'ReFreshFail': '刷新失败',
|
||||
'All': '全部',
|
||||
'Connect': '连接',
|
||||
'UpDownload': '上传下载',
|
||||
'UploadFile': '上传文件',
|
||||
'DownloadFile': '下载文件',
|
||||
'Basic': '基本',
|
||||
'User': '用户',
|
||||
'Asset': '资产',
|
||||
'Actions': '动作',
|
||||
'UserGroups': '用户组',
|
||||
'Node': '节点',
|
||||
'SystemUser': '系统用户',
|
||||
//
|
||||
'RemoteApp': '远程应用',
|
||||
//
|
||||
@@ -373,30 +359,33 @@ const cn = {
|
||||
'systemUser': '系统用户',
|
||||
'remoteAddr': '远端地址',
|
||||
'protocol': '协议',
|
||||
'loginForm': '登录来源',
|
||||
'loginFrom': '登录来源',
|
||||
'command': '命令',
|
||||
'dateStart': '开始日期',
|
||||
'duration': '时长',
|
||||
'terminate': '终断',
|
||||
'date_end': '结束日期',
|
||||
'dateEnd': '结束日期',
|
||||
'commands': '命令记录',
|
||||
'replay': '回放',
|
||||
'download': '下载',
|
||||
'RiskLevel': '风险等级',
|
||||
'riskLevel': '风险等级',
|
||||
'session': '会话',
|
||||
'date': '日期',
|
||||
'addr': '地址',
|
||||
'active': '激活中',
|
||||
'alive': '在线',
|
||||
'StorageConfiguration': '存储配置',
|
||||
'join': '加入'
|
||||
'join': '加入',
|
||||
'goto': '转到',
|
||||
'sessionDetail': '会话详情',
|
||||
'quickModify': '快速修改'
|
||||
},
|
||||
jobcenter: {
|
||||
'RunTimes': '执行次数',
|
||||
'hosts': '主机',
|
||||
'success': '成功',
|
||||
'date': '日期',
|
||||
'time': '时间',
|
||||
'Hosts': '主机',
|
||||
'Success': '成功',
|
||||
'Date': '日期',
|
||||
'Time': '时间',
|
||||
'run': '执行'
|
||||
},
|
||||
tickets: {
|
||||
|
@@ -18,7 +18,11 @@ const en = {
|
||||
'assets': 'Assets',
|
||||
'applications': 'Applications',
|
||||
'perms': 'Perms',
|
||||
'sessions': 'Sessions',
|
||||
'Sessions': 'Sessions',
|
||||
'SessionOnline': 'Session Online',
|
||||
'SessionOffline': 'Session Offline',
|
||||
'SessionDetail': 'Session Detail',
|
||||
'Goto': 'Goto',
|
||||
'jobcenter': 'Job Center'
|
||||
},
|
||||
users: {
|
||||
@@ -265,18 +269,16 @@ const en = {
|
||||
'database_app_count': 'DatabaseApp count'
|
||||
},
|
||||
sessions: {
|
||||
'session_online_list': '',
|
||||
'session_detail': ' Session detail',
|
||||
'id': '',
|
||||
'user': 'Use',
|
||||
'asset': 'Asset',
|
||||
'system_user': 'System user',
|
||||
'remote_addr': 'Remote addr',
|
||||
'systemUser': 'System user',
|
||||
'remoteAddr': 'Remote addr',
|
||||
'protocol': 'Protocol',
|
||||
'login_form': 'Login from',
|
||||
'loginFrom': 'Login from',
|
||||
'command': 'Command',
|
||||
'date_start': 'Date start',
|
||||
'duration': 'Druation',
|
||||
'dateStart': 'Date start',
|
||||
'duration': 'Duration',
|
||||
'action': 'Action',
|
||||
'search': 'Search',
|
||||
'terminate_selected': 'Terminate selected',
|
||||
@@ -284,12 +286,15 @@ const en = {
|
||||
'submit': 'Submit',
|
||||
'terminate': 'Terminate',
|
||||
'command_list': 'Command list',
|
||||
'date_end': 'Date end',
|
||||
'dateEnd': 'Date end',
|
||||
'quick_modify': 'Quick modify',
|
||||
'terminate_session': 'Terminate session',
|
||||
'confirm': 'Confirm',
|
||||
'commands': 'Commands',
|
||||
'join': 'join'
|
||||
'join': 'join',
|
||||
'goto': 'Goto',
|
||||
'sessionDetail': 'Session Detail',
|
||||
'quickModify': 'Quick Modify'
|
||||
},
|
||||
setting: {
|
||||
'setting': 'System Setting',
|
||||
|
@@ -1,10 +1,17 @@
|
||||
<template>
|
||||
<Page>
|
||||
<Page v-loading="loadding">
|
||||
<IBox>
|
||||
<AutoDataForm :form="form" :fields="fields" :url="url" v-bind="$attrs" v-on="$listeners" @submit="handleSubmit">
|
||||
<slot v-for="item in fields" :slot="`id:${item}`" :name="`id:${item}`" />
|
||||
<slot v-for="item in fields" :slot="`$id:${item}`" :name="`$id:${item}`" />
|
||||
</AutoDataForm>
|
||||
<AutoDataForm
|
||||
v-if="!loadding"
|
||||
ref="form"
|
||||
:method="method"
|
||||
:form="form"
|
||||
:fields="fields"
|
||||
:url="totalUrl"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
@submit="handleSubmit"
|
||||
/>
|
||||
</IBox>
|
||||
</Page>
|
||||
</template>
|
||||
@@ -21,46 +28,105 @@ export default {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
method: {
|
||||
type: String,
|
||||
default: 'post'
|
||||
},
|
||||
fields: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
form: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => { return {} }
|
||||
default: () => ({})
|
||||
},
|
||||
initial: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
onSubmit: {
|
||||
type: Function,
|
||||
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() {
|
||||
console.log('generic', this.$attrs)
|
||||
console.log(this.fields)
|
||||
if (this.method === 'put') {
|
||||
this.getObjectDetail()
|
||||
} else {
|
||||
this.form = Object.assign(this.form, this.initial)
|
||||
this.loadding = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSubmit(values) {
|
||||
handleSubmit(values, form) {
|
||||
let handler = this.onSubmit || this.defaultOnSubmit
|
||||
handler = handler.bind(this)
|
||||
const fields = form.$refs.elForm.fields
|
||||
console.log('submit', values)
|
||||
return handler(values)
|
||||
console.log('form.fields', fields)
|
||||
return handler(values, form)
|
||||
},
|
||||
defaultOnSubmit(validValues) {
|
||||
this.$axios.post(this.url, validValues).then(
|
||||
() => {
|
||||
const msg = this.$tc('Create success')
|
||||
this.$message.success(msg)
|
||||
setTimeout(() => {
|
||||
this.$router.push({ name: 'UserList' })
|
||||
}, 500)
|
||||
defaultPerformSubmit(validValues) {
|
||||
return this.$axios[this.method](this.totalUrl, validValues)
|
||||
},
|
||||
defaultOnSubmit(validValues, form) {
|
||||
this.defaultPerformSubmit(validValues).then(() => {
|
||||
const msg = this.$tc('Create success')
|
||||
this.$message.success(msg)
|
||||
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 ActionsGroup from '@/components/ActionsGroup'
|
||||
export default {
|
||||
name: 'BaseDetailPage',
|
||||
name: 'GenericDetailPage',
|
||||
components: {
|
||||
Page,
|
||||
ActionsGroup
|
@@ -3,7 +3,7 @@ export { default as NavHeader } from './NavHeader'
|
||||
export { default as AppMain } from './AppMain'
|
||||
export { default as Page } from './Page'
|
||||
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 Footer } from './Footer'
|
||||
export { default as IBox } from './IBox'
|
||||
|
@@ -70,14 +70,14 @@ export const constantRoutes = [
|
||||
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
||||
name: 'UserCreate',
|
||||
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
|
||||
name: 'UserEdit',
|
||||
name: 'UserUpdate',
|
||||
hidden: true,
|
||||
meta: { title: 'UserEdit' }
|
||||
meta: { title: 'UserUpdate', activeMenu: '/users/users', action: 'update' }
|
||||
},
|
||||
{
|
||||
path: 'users/detail/:id',
|
||||
@@ -274,6 +274,13 @@ export const constantRoutes = [
|
||||
component: () => import('@/views/sessions/CommandList'),
|
||||
meta: { title: 'Commands' }
|
||||
},
|
||||
{
|
||||
path: 'sessions/:id',
|
||||
name: 'SessionDetail',
|
||||
component: () => import('@/views/sessions/SessionDetail'),
|
||||
meta: { title: 'SessionDetail' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'luna',
|
||||
name: 'WebTerminal',
|
||||
|
@@ -235,3 +235,29 @@ td .el-button.el-button--mini {
|
||||
.el-radio__input.is-checked+.el-radio__label {
|
||||
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 './element-index.css';
|
||||
@import './menu.scss';
|
||||
@import 'vue-select/src/scss/vue-select.scss';
|
||||
@import "./font-awesome/font-awesome.min.css";
|
||||
|
||||
body {
|
||||
|
@@ -53,37 +53,34 @@ service.interceptors.response.use(
|
||||
const res = response.data
|
||||
|
||||
// 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: res.message || res.error || 'Error',
|
||||
type: 'error',
|
||||
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'))
|
||||
} else {
|
||||
if (response.config.raw === 1) {
|
||||
return response
|
||||
}
|
||||
return res
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error) // for debug
|
||||
Message({
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
|
@@ -3,8 +3,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { timeOffset, toSafeLocalDateStr } from '@/utils/common'
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { DetailFormatter, ActionsFormatter } from '@/components/ListTable/formatters/index'
|
||||
import { ActionsFormatter } from '@/components/ListTable/formatters/index'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -14,47 +15,71 @@ export default {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/ops/tasks/',
|
||||
columns: [
|
||||
{
|
||||
prop: 'name',
|
||||
columns: ['name', 'runtimes', 'host_amount', 'is_success', 'date_start', 'time', 'actions'],
|
||||
columnsMeta: {
|
||||
name: {
|
||||
label: this.$tc('Name'),
|
||||
formatter: DetailFormatter,
|
||||
sortable: 'custom',
|
||||
route: 'UserDetail'
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'latest_execution',
|
||||
label: this.$t('jobcenter.RunTimes')
|
||||
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
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'latest_execution.hosts_amount',
|
||||
label: this.$t('jobcenter.hosts')
|
||||
host_amount: {
|
||||
label: this.$t('jobcenter.Hosts'),
|
||||
formatter: function(row) {
|
||||
return row.latest_execution.hosts_amount
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'latest_execution.is_success',
|
||||
label: this.$t('jobcenter.success')
|
||||
is_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'/>
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'latest_execution.date_start',
|
||||
label: this.$t('jobcenter.date'),
|
||||
sortable: 'custom'
|
||||
date_start: {
|
||||
label: this.$t('jobcenter.Date'),
|
||||
formatter: function(row) {
|
||||
return toSafeLocalDateStr(row.latest_execution.date_start)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'latest_execution.timedelta',
|
||||
label: this.$t('jobcenter.time')
|
||||
time: {
|
||||
label: this.$t('jobcenter.Time'),
|
||||
formatter: function(row) {
|
||||
return timeOffset(row.latest_execution.date_start, row.latest_execution.date_finished)
|
||||
}
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
prop: 'id',
|
||||
label: this.$tc('Action'),
|
||||
align: 'center',
|
||||
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: {
|
||||
hasCreate: false,
|
||||
|
@@ -11,6 +11,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
is_active: true,
|
||||
actions: ['all', 'connect', 'updownload', 'upload_file', 'download_file'],
|
||||
date_expired: '2099-12-31 00:00:00 +0800'
|
||||
},
|
||||
fields: [
|
||||
@@ -53,7 +55,15 @@ export default {
|
||||
}
|
||||
},
|
||||
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: {
|
||||
type: 'checkbox'
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { LengthFormatter } from '@/components/ListTable/formatters/index'
|
||||
import { LengthFormatter, ExpandAssetPermissionFormatter } from '@/components/ListTable/formatters/index'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -14,8 +14,13 @@ export default {
|
||||
return {
|
||||
tableConfig: {
|
||||
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: {
|
||||
expand: {
|
||||
type: 'expand',
|
||||
formatter: ExpandAssetPermissionFormatter
|
||||
},
|
||||
users: {
|
||||
formatter: LengthFormatter
|
||||
},
|
||||
@@ -36,9 +41,29 @@ export default {
|
||||
headerActions: {
|
||||
hasDelete: 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>
|
||||
|
@@ -4,6 +4,8 @@
|
||||
|
||||
<script>
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import { RouterFormatter, OutputExpandFormatter } from '@/components/ListTable/formatters'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -12,55 +14,47 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
axiosConfig: {
|
||||
raw: 1,
|
||||
params: {
|
||||
display: 1,
|
||||
is_finished: 0
|
||||
}
|
||||
},
|
||||
hasSelection: false,
|
||||
hasOperation: false,
|
||||
url: '/api/v1/terminal/commands/',
|
||||
columns: [
|
||||
{
|
||||
type: 'expand'
|
||||
'expandCol', 'input', 'risk_level', 'user',
|
||||
'asset', 'system_user', 'session', 'timestamp'
|
||||
],
|
||||
columnsMeta: {
|
||||
expandCol: {
|
||||
type: 'expand',
|
||||
prop: 'output',
|
||||
formatter: OutputExpandFormatter
|
||||
},
|
||||
{
|
||||
prop: 'input',
|
||||
input: {
|
||||
label: this.$t('sessions.command')
|
||||
},
|
||||
{
|
||||
prop: 'output',
|
||||
label: '命令输出结果 (怎么放到隐藏内容 ??)',
|
||||
expand: true
|
||||
risk_level: {
|
||||
label: this.$t('sessions.riskLevel')
|
||||
},
|
||||
{
|
||||
prop: 'risk_level',
|
||||
label: this.$t('sessions.RiskLevel')
|
||||
user: {
|
||||
label: this.$t('sessions.user')
|
||||
},
|
||||
{
|
||||
prop: 'user',
|
||||
label: this.$t('sessions.user'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
prop: 'asset',
|
||||
asset: {
|
||||
label: this.$t('sessions.asset')
|
||||
},
|
||||
{
|
||||
prop: 'system_user',
|
||||
system_user: {
|
||||
label: this.$t('sessions.systemUser')
|
||||
},
|
||||
{
|
||||
prop: 'session',
|
||||
label: this.$t('sessions.session')
|
||||
session: {
|
||||
label: this.$t('sessions.session'),
|
||||
formatter: RouterFormatter,
|
||||
route: 'SessionDetail',
|
||||
linkName: this.$t('sessions.goto')
|
||||
},
|
||||
{
|
||||
prop: 'timestamp',
|
||||
label: this.$t('sessions.date')
|
||||
timestamp: {
|
||||
label: this.$t('sessions.date'),
|
||||
formatter: function(row) {
|
||||
return toSafeLocalDateStr(row.timestamp * 1000)
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
},
|
||||
tableActions: {
|
||||
hasEdit: 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: {
|
||||
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: {
|
||||
label: this.$t('sessions.command')
|
||||
},
|
||||
login_from: {
|
||||
label: this.$t('sessions.loginForm')
|
||||
label: this.$t('sessions.loginFrom')
|
||||
},
|
||||
protocol: {
|
||||
label: this.$t('sessions.protocol'),
|
||||
|
@@ -22,8 +22,10 @@ export default {
|
||||
],
|
||||
columnsMeta: {
|
||||
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: {
|
||||
label: this.$t('sessions.command')
|
||||
|
@@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<GenericCreateUpdatePage :fields="fields" :form="form" :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>
|
||||
<GenericCreateUpdatePage :fields="fields" :initial="initial" :fields-meta="fieldsMeta" :url="url" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -14,30 +9,46 @@ export default {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
const errors = { name: '' }
|
||||
return {
|
||||
form: {
|
||||
initial: {
|
||||
password_strategy: 0,
|
||||
mfa_level: 0,
|
||||
source: 'ldap',
|
||||
source: 'local',
|
||||
role: 'Admin',
|
||||
date_expired: '2099-12-31 00:00:00 +0800'
|
||||
},
|
||||
fields: [
|
||||
[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.$tc('Other'), ['phone', 'wechat', 'comment']]
|
||||
],
|
||||
errors: errors,
|
||||
url: '/api/v1/users/users/',
|
||||
fieldsMeta: {
|
||||
name: {
|
||||
el: {
|
||||
error: '无措'
|
||||
}
|
||||
},
|
||||
password_strategy: {
|
||||
hidden: () => {
|
||||
return this.$route.params.id
|
||||
}
|
||||
},
|
||||
password: {
|
||||
hidden: (formValue, item) => {
|
||||
console.log('hidden password', formValue.password_strategy)
|
||||
if (this.$route.params.id === undefined) {
|
||||
return formValue.password_strategy !== 1
|
||||
} else {
|
||||
return true
|
||||
if (this.$route.meta.action === 'update') {
|
||||
return false
|
||||
}
|
||||
return formValue.password_strategy !== 1
|
||||
}
|
||||
},
|
||||
public_key: {
|
||||
hidden: (formValue, item) => {
|
||||
return this.$route.meta.action !== 'update'
|
||||
}
|
||||
},
|
||||
groups: {
|
||||
@@ -49,6 +60,11 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.errors.name = 'dididi'
|
||||
}, 3000)
|
||||
},
|
||||
methods: {
|
||||
debug() {
|
||||
console.log(this)
|
||||
@@ -58,10 +74,4 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.el-form /deep/ .el-select{
|
||||
width:100%;
|
||||
}
|
||||
.el-form /deep/ .el-form-item__content > .el-date-editor{
|
||||
width:100%;
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BaseDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
|
||||
<GenericDetailPage :submenu="submenu" :active-menu="activeSubMenu" :title="title">
|
||||
<div slot="info">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
@@ -18,18 +18,18 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</BaseDetailPage>
|
||||
</GenericDetailPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUserGroupDetail, getUserGroupMembers } from '@/api/user'
|
||||
import { BaseDetailPage } from '@/layout/components'
|
||||
import { GenericDetailPage } from '@/layout/components'
|
||||
import DetailCard from '@/components/DetailCard'
|
||||
import Select2 from '@/components/Select2'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BaseDetailPage,
|
||||
GenericDetailPage,
|
||||
DetailCard,
|
||||
Select2
|
||||
},
|
||||
|
@@ -26,7 +26,8 @@ export default {
|
||||
performBulkDelete: function(rows) {
|
||||
console.log('hello')
|
||||
}
|
||||
}
|
||||
},
|
||||
helpMessage: '用户列表'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,14 +14,18 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/users/users/',
|
||||
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: {
|
||||
createRoute: 'UserCreate',
|
||||
onCreate: () => {
|
||||
},
|
||||
extraMoreActions: [
|
||||
{
|
||||
name: 'deactiveSelected',
|
||||
|
Reference in New Issue
Block a user