Merge pull request #1053 from jumpserver/dev

v2.14.0 rc3
This commit is contained in:
Jiangjie.Bai
2021-09-15 21:06:24 +08:00
committed by GitHub
38 changed files with 621 additions and 375 deletions

View File

@@ -97,6 +97,7 @@ export default {
} }
}, },
props: { props: {
// eslint-disable-next-line vue/require-default-prop
data: Object, data: Object,
prop: { prop: {
type: String, type: String,
@@ -104,10 +105,13 @@ export default {
return this.data.id return this.data.id
} }
}, },
// eslint-disable-next-line vue/require-prop-types,vue/require-default-prop
itemValue: {}, itemValue: {},
// eslint-disable-next-line vue/require-default-prop
value: Object, value: Object,
disabled: Boolean, disabled: Boolean,
readonly: Boolean, readonly: Boolean,
// eslint-disable-next-line vue/require-default-prop
options: Array options: Array
}, },
data() { data() {

View File

@@ -94,7 +94,12 @@ export default {
tableConfig() { tableConfig() {
const tableDefaultConfig = this.defaultConfig const tableDefaultConfig = this.defaultConfig
tableDefaultConfig.paginationSize = _.get(this.globalTableConfig, 'paginationSize', 15) tableDefaultConfig.paginationSize = _.get(this.globalTableConfig, 'paginationSize', 15)
let tableAttrs = tableDefaultConfig.tableAttrs
if (this.config.tableAttrs) {
tableAttrs = Object.assign(tableAttrs, this.config.tableAttrs)
}
const config = Object.assign(tableDefaultConfig, this.config) const config = Object.assign(tableDefaultConfig, this.config)
config.tableAttrs = tableAttrs
return config return config
}, },
iListeners() { iListeners() {

View File

@@ -8,8 +8,8 @@
:remote="remote" :remote="remote"
:remote-method="filterOptions" :remote-method="filterOptions"
:multiple="multiple" :multiple="multiple"
filterable
:clearable="clearable" :clearable="clearable"
filterable
popper-append-to-body popper-append-to-body
class="select2" class="select2"
v-bind="$attrs" v-bind="$attrs"
@@ -98,7 +98,6 @@ export default {
return { return {
loading: false, loading: false,
initialized: false, initialized: false,
iValue: this.multiple ? [] : '',
defaultParams: _.cloneDeep(defaultParams), defaultParams: _.cloneDeep(defaultParams),
params: _.cloneDeep(defaultParams), params: _.cloneDeep(defaultParams),
iOptions: this.options || [], iOptions: this.options || [],
@@ -113,6 +112,14 @@ export default {
optionsValues() { optionsValues() {
return this.iOptions.map((v) => v.value) return this.iOptions.map((v) => v.value)
}, },
iValue: {
set(val) {
this.$emit('input', val)
},
get() {
return this.value
}
},
iAjax() { iAjax() {
const defaultPageSize = 10 const defaultPageSize = 10
const defaultMakeParams = (params) => { const defaultMakeParams = (params) => {

View File

@@ -421,6 +421,7 @@ export default {
.importTable >>> .cell { .importTable >>> .cell {
min-height: 20px; min-height: 20px;
height: 100%; height: 100%;
overflow: auto;
} }
</style> </style>

View File

@@ -551,7 +551,7 @@
"systemUserCount": "系统用户数量", "systemUserCount": "系统用户数量",
"upDownload": "上传下载", "upDownload": "上传下载",
"uploadFile": "上传文件", "uploadFile": "上传文件",
"clipboardCopyPaste":"复制粘贴", "clipboardCopyPaste":"剪贴板复制粘贴",
"clipboardCopy":"剪切板复制", "clipboardCopy":"剪切板复制",
"clipboardPaste":"剪切板粘贴", "clipboardPaste":"剪切板粘贴",
"userCount": "用户数量", "userCount": "用户数量",
@@ -567,6 +567,7 @@
"AssetAccount": "资产账号", "AssetAccount": "资产账号",
"ApplicationAccount": "应用账号", "ApplicationAccount": "应用账号",
"Ticket":"工单", "Ticket":"工单",
"SessionDetail": "会话详情",
"CommandConfirm": "命令复核", "CommandConfirm": "命令复核",
"AdminUserCreate": "创建管理用户", "AdminUserCreate": "创建管理用户",
"AdminUserDetail": "管理用户详情", "AdminUserDetail": "管理用户详情",
@@ -576,6 +577,7 @@
"AssetCreate": "创建资产", "AssetCreate": "创建资产",
"AssetDetail": "资产详情", "AssetDetail": "资产详情",
"AssetList": "资产列表", "AssetList": "资产列表",
"Session": "会话",
"AssetPermission": "资产授权", "AssetPermission": "资产授权",
"AssetPermissionCreate": "创建资产授权规则", "AssetPermissionCreate": "创建资产授权规则",
"AssetPermissionDetail": "资产授权详情", "AssetPermissionDetail": "资产授权详情",
@@ -831,7 +833,8 @@
"authLdapSearchFilter": "用户过滤器", "authLdapSearchFilter": "用户过滤器",
"authLdapSearchOu": "用户OU", "authLdapSearchOu": "用户OU",
"authLdapServerUri": "LDAP地址", "authLdapServerUri": "LDAP地址",
"authLdapUserAttrMap": "LDAP属性映射", "authLdapUserAttrMap": "用户属性映射",
"authCASAttrMap": "用户属性映射",
"SignaturesAndTemplates": "Signatures and Templates", "SignaturesAndTemplates": "Signatures and Templates",
"unselectedUser": "没有选择用户", "unselectedUser": "没有选择用户",
"auto": "自动", "auto": "自动",
@@ -979,7 +982,7 @@
"user": "用户", "user": "用户",
"Status": "状态", "Status": "状态",
"Open": "待处理", "Open": "待处理",
"OrgName":"组织名称", "OrgName":"授权组织名称",
"AssignedInfo":"审批信息", "AssignedInfo":"审批信息",
"OpenTicket": "创建工单", "OpenTicket": "创建工单",
"HandleTicket": "处理工单", "HandleTicket": "处理工单",
@@ -1036,6 +1039,10 @@
"DatePasswordUpdated": "密码更新日期", "DatePasswordUpdated": "密码更新日期",
"DescribeOfGuide": "欢迎使用JumpServer堡垒机系统获取更多信息请点击", "DescribeOfGuide": "欢迎使用JumpServer堡垒机系统获取更多信息请点击",
"Email": "邮件", "Email": "邮件",
"Phone": "手机号",
"WeCom": "企业微信",
"DingTalk": "钉钉",
"FeiShu": "飞书",
"FingerPrint": "指纹", "FingerPrint": "指纹",
"FirstLogin": "首次登录", "FirstLogin": "首次登录",
"OrgUser": "组织用户", "OrgUser": "组织用户",

View File

@@ -551,6 +551,7 @@
}, },
"route": { "route": {
"": "", "": "",
"SessionDetail": "SessionDetail",
"Accounts": "Accounts", "Accounts": "Accounts",
"AssetAccount": "Asset account", "AssetAccount": "Asset account",
"ApplicationAccount": "Application account", "ApplicationAccount": "Application account",
@@ -813,6 +814,7 @@
"authLdapSearchOu": "User OU", "authLdapSearchOu": "User OU",
"authLdapServerUri": "LDAP server", "authLdapServerUri": "LDAP server",
"authLdapUserAttrMap": "User attr map", "authLdapUserAttrMap": "User attr map",
"authCASAttrMap": "User attr map",
"unselectedUser": "Unselected user", "unselectedUser": "Unselected user",
"auto": "Auto", "auto": "Auto",
"basicSetting": "Basic setting", "basicSetting": "Basic setting",
@@ -1006,6 +1008,10 @@
"DatePasswordUpdated": "Date password updated", "DatePasswordUpdated": "Date password updated",
"DescribeOfGuide": "Welcome to JumpServer. Click here for more information", "DescribeOfGuide": "Welcome to JumpServer. Click here for more information",
"Email": "Email", "Email": "Email",
"Phone": "Phone",
"WeCom": "WeCom",
"DingTalk": "DingTalk",
"FeiShu": "FeiShu",
"FingerPrint": "Fingerprint", "FingerPrint": "Fingerprint",
"FirstLogin": "First login", "FirstLogin": "First login",
"InviteUser": "Invite user", "InviteUser": "Invite user",

View File

@@ -1,7 +1,7 @@
<template> <template>
<Dialog <Dialog
:title="this.$t('common.updateSelected')" :title="this.$t('common.updateSelected')"
:visible.sync="dialogSetting.dialogVisible" :visible.sync="iVisible"
width="70%" width="70%"
top="1vh" top="1vh"
:show-cancel="false" :show-cancel="false"
@@ -45,13 +45,13 @@ export default {
type: Array, type: Array,
default: () => ([]) default: () => ([])
}, },
dialogSetting: {
type: Object,
default: () => ({})
},
formSetting: { formSetting: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
visible: {
type: Boolean,
default: false
} }
}, },
data: function() { data: function() {
@@ -62,6 +62,16 @@ export default {
iFormSetting: {} iFormSetting: {}
} }
}, },
computed: {
iVisible: {
set(val) {
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
},
mounted() { mounted() {
const defaultFormSetting = this.getDefaultFormSetting() const defaultFormSetting = this.getDefaultFormSetting()
this.iFormSetting = Object.assign({}, this.formSetting, defaultFormSetting) this.iFormSetting = Object.assign({}, this.formSetting, defaultFormSetting)
@@ -100,7 +110,7 @@ export default {
this.$axios.patch(url, validValues).then((res) => { this.$axios.patch(url, validValues).then((res) => {
vm.$emit('update') vm.$emit('update')
this.$message.success(msg) this.$message.success(msg)
vm.dialogSetting.dialogVisible = false this.iVisible = false
}).catch(error => { }).catch(error => {
this.$emit('submitError', error) this.$emit('submitError', error)
const response = error.response const response = error.response

View File

@@ -5,6 +5,7 @@ export default [
path: 'asset-accounts', path: 'asset-accounts',
component: empty, component: empty,
meta: { title: i18n.t('route.AssetAccount') }, meta: { title: i18n.t('route.AssetAccount') },
redirect: '',
children: [ children: [
{ {
path: '', path: '',
@@ -17,6 +18,7 @@ export default [
{ {
path: 'application-accounts', path: 'application-accounts',
component: empty, component: empty,
redirect: '',
meta: { title: i18n.t('route.AssetAccount') }, meta: { title: i18n.t('route.AssetAccount') },
children: [ children: [
{ {

View File

@@ -39,8 +39,8 @@ export default [
}, },
{ {
path: 'databases', path: 'databases',
name: 'DatabaseAppList',
component: empty, component: empty,
redirect: '',
meta: { title: i18n.t('route.DatabaseApp') }, meta: { title: i18n.t('route.DatabaseApp') },
children: [ children: [
{ {
@@ -74,7 +74,6 @@ export default [
}, },
{ {
path: 'kubernetes', path: 'kubernetes',
name: 'KubernetesAppList',
component: empty, component: empty,
meta: { title: i18n.t('route.KubernetesApp') }, meta: { title: i18n.t('route.KubernetesApp') },
children: [ children: [

View File

@@ -5,24 +5,32 @@ import { BASE_URL } from '@/utils/common'
export default [ export default [
{ {
path: 'session', path: 'sessions',
name: 'SessionList', component: empty,
component: () => import('@/views/sessions/SessionList/index'), redirect: '',
meta: { title: i18n.t('route.Sessions'), permissions: [rolec.PERM_AUDIT] } meta: { title: i18n.t('route.Sessions'), permissions: [rolec.PERM_AUDIT] },
children: [
{
path: '',
name: 'SessionList',
component: () => import('@/views/sessions/SessionList/index'),
meta: { title: i18n.t('route.Sessions'), permissions: [rolec.PERM_AUDIT] }
},
{
path: ':id',
name: 'SessionDetail',
component: () => import('@/views/sessions/SessionDetail/index'),
meta: { title: i18n.t('route.SessionDetail'), activeMenu: '/terminal/sessions' },
hidden: true
}
]
}, },
{ {
path: 'command', path: 'commands',
name: 'CommandList', name: 'CommandList',
component: () => import('@/views/sessions/CommandList'), component: () => import('@/views/sessions/CommandList'),
meta: { title: i18n.t('route.Commands'), permissions: [rolec.PERM_AUDIT] } meta: { title: i18n.t('route.Commands'), permissions: [rolec.PERM_AUDIT] }
}, },
{
path: 'sessions/:id',
name: 'SessionDetail',
component: () => import('@/views/sessions/SessionDetail/index'),
meta: { title: i18n.t('route.SessionDetail'), activeMenu: '/terminal/session', permissions: [rolec.PERM_AUDIT] },
hidden: true
},
{ {
path: `${BASE_URL}/luna/?_=${Date.now()}`, path: `${BASE_URL}/luna/?_=${Date.now()}`,
name: 'WebTerminal', name: 'WebTerminal',
@@ -66,37 +74,41 @@ export default [
}, },
{ {
path: 'storages', path: 'storages',
name: 'Storage', component: empty,
component: () => import('@/views/sessions/Storage/index'),
meta: { activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, meta: { activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
hidden: true redirect: '',
}, hidden: true,
{ children: [
path: 'replay-storage/create', {
name: 'CreateReplayStorage', path: '',
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'), name: 'Storage',
meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, component: () => import('@/views/sessions/Storage/index'),
hidden: true meta: { activeMenu: '/terminal/terminal' }
}, },
{ {
path: 'command-storage/create', path: 'replay-storage/create',
name: 'CreateCommandStorage', name: 'CreateReplayStorage',
component: () => import('@/views/sessions/CommandStorageCreateUpdate'), component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal' }
hidden: true },
}, {
{ path: 'replay-storage/:id/update',
path: 'replay-storage/:id/update', name: 'ReplayStorageUpdate',
name: 'ReplayStorageUpdate', component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'), meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal' }
meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, },
hidden: true {
}, path: 'command-storage/create',
{ name: 'CreateCommandStorage',
path: 'command-storage/:id/update', component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
name: 'CommandStorageUpdate', meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal' }
component: () => import('@/views/sessions/CommandStorageCreateUpdate'), },
meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, {
hidden: true path: 'command-storage/:id/update',
name: 'CommandStorageUpdate',
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal' }
}
]
} }
] ]

View File

@@ -61,6 +61,7 @@ export default [
path: 'flows', path: 'flows',
name: 'TicketFlowList', name: 'TicketFlowList',
component: empty, component: empty,
redirect: '',
meta: { title: i18n.t('route.TicketFlow'), icon: 'check-square-o', activeMenu: '/tickets/tickets' }, meta: { title: i18n.t('route.TicketFlow'), icon: 'check-square-o', activeMenu: '/tickets/tickets' },
hidden: true, hidden: true,
children: [ children: [

View File

@@ -459,25 +459,8 @@ a {
color: $--color-text-primary; color: $--color-text-primary;
} }
//.el-dialog__wrapper { .el-dialog__wrapper {
// display: flex;
// align-items: center;
// justify-content: center;
//}
.el-dialog {
display: flex; display: flex;
flex-direction: column; align-items: center;
margin:0 !important; justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-height: calc(100vh - 30px);
max-width: calc(100vh - 30px);
}
.el-dialog .el-dialog__body {
flex: 1;
overflow: auto;
} }

View File

@@ -4,7 +4,7 @@
<script> <script>
import GenericTreeListPage from '@/layout/components/GenericTreeListPage/index' import GenericTreeListPage from '@/layout/components/GenericTreeListPage/index'
import { ActionsFormatter, SystemUserFormatter, DialogDetailFormatter } from '@/components/TableFormatters' import { SystemUserFormatter, DialogDetailFormatter } from '@/components/TableFormatters'
export default { export default {
components: { components: {
GenericTreeListPage GenericTreeListPage
@@ -33,8 +33,9 @@ export default {
tableConfig: { tableConfig: {
url: '/api/v1/perms/users/assets/', url: '/api/v1/perms/users/assets/',
hasTree: true, hasTree: true,
columns: [ columns: ['hostname', 'ip', 'system_users', 'platform', 'comment', 'actions'],
{ columnsMeta: {
hostname: {
prop: 'hostname', prop: 'hostname',
label: this.$t('assets.Hostname'), label: this.$t('assets.Hostname'),
formatter: DialogDetailFormatter, formatter: DialogDetailFormatter,
@@ -72,17 +73,15 @@ export default {
}, },
sortable: true sortable: true
}, },
{ ip: {
prop: 'ip',
label: this.$t('assets.ip'),
sortable: 'custom', sortable: 'custom',
width: '180px' width: '150px'
}, },
{ system_users: {
prop: 'SystemUsers', showOverflowTooltip: true,
align: 'center', align: 'center',
label: this.$t('assets.SystemUsers'), label: this.$t('assets.SystemUsers'),
width: '200px', width: '150px',
formatter: SystemUserFormatter, formatter: SystemUserFormatter,
formatterArgs: { formatterArgs: {
getUrl: ({ row }) => { getUrl: ({ row }) => {
@@ -90,23 +89,14 @@ export default {
} }
} }
}, },
{ platform: {
prop: 'platform',
label: this.$t('assets.Platform'),
width: '120px' width: '120px'
}, },
{ comment: {
prop: 'comment',
label: this.$t('assets.Comment'),
showOverflowTooltip: true, showOverflowTooltip: true,
width: '180px' width: '100px'
}, },
{ actions: {
prop: 'id',
align: 'center',
formatter: ActionsFormatter,
width: '100px',
label: this.$t('common.action'),
formatterArgs: { formatterArgs: {
hasDelete: false, hasDelete: false,
loading: true, loading: true,
@@ -117,30 +107,23 @@ export default {
name: 'connect', name: 'connect',
fa: 'fa-terminal', fa: 'fa-terminal',
type: 'primary', type: 'primary',
can: function({ row, cellValue }) { can: ({ row }) => row.is_active,
return row.is_active callback: ({ row }) => {
},
callback: function({ row, col, cellValue, reload }) {
window.open(`/luna/?login_to=${row.id}`, '_blank') window.open(`/luna/?login_to=${row.id}`, '_blank')
} }
}, },
{ {
name: 'favor', name: 'favor',
type: 'info', type: 'info',
fa: function({ row, cellValue }) { fa: ({ row }) => {
if (this.checkFavorite(row.id)) { return this.checkFavorite(row.id) ? 'fa-star' : 'fa-star-o'
return 'fa-star' },
} callback: ({ row }) => this.toggleFavorite(row.id)
return 'fa-star-o'
}.bind(this),
callback: function({ row, col, cellValue, reload }) {
this.addOrDeleteFavorite(row.id)
}.bind(this)
} }
] ]
} }
} }
], },
tableAttrs: { tableAttrs: {
rowClassName({ row }) { rowClassName({ row }) {
return !row.is_active ? 'row_disabled' : '' return !row.is_active ? 'row_disabled' : ''
@@ -160,25 +143,32 @@ export default {
}, },
methods: { methods: {
refreshAllFavorites() { refreshAllFavorites() {
const actionsIndex = this.tableConfig.columns.length - 1 const formatterArgs = this.tableConfig.columnsMeta.actions.formatterArgs
this.tableConfig.columns[actionsIndex].formatterArgs.loading = true formatterArgs.loading = true
this.$axios.get('/api/v1/assets/favorite-assets/').then(resp => { this.$axios.get('/api/v1/assets/favorite-assets/').then(resp => {
this.allFavorites = resp this.allFavorites = resp
this.tableConfig.columns[actionsIndex].formatterArgs.loading = false formatterArgs.loading = false
}) })
}, },
addOrDeleteFavorite(assetId) { favor(assetId) {
if (this.checkFavorite(assetId)) { const data = { asset: assetId }
this.$axios.delete(`/api/v1/assets/favorite-assets/?asset=${assetId}`).then( const url = '/api/v1/assets/favorite-assets/'
res => this.removeFavorite(assetId) this.$axios.post(url, data).then(
) () => this.allFavorites.push({ asset: assetId })
)
},
disfavor(assetId) {
const url = `/api/v1/assets/favorite-assets/?asset=${assetId}`
this.$axios.delete(url).then(() => {
this.allFavorites = this.allFavorites.filter(item => item['asset'] !== assetId)
})
},
toggleFavorite(assetId) {
const favorite = this.checkFavorite(assetId)
if (favorite) {
this.disfavor(assetId)
} else { } else {
const data = { this.favor(assetId)
asset: assetId
}
this.$axios.post('/api/v1/assets/favorite-assets/', data).then(
res => this.addFavorite(assetId)
)
} }
}, },
checkFavorite(assetId) { checkFavorite(assetId) {
@@ -189,12 +179,6 @@ export default {
} }
}) })
return ok return ok
},
removeFavorite(assetId) {
this.allFavorites = this.allFavorites.filter(item => item['asset'] !== assetId)
},
addFavorite(assetId) {
this.allFavorites.push({ asset: assetId })
} }
} }
} }

View File

@@ -87,6 +87,15 @@ export function toSafeLocalDateStr(d) {
return date_s return date_s
} }
export function forMatAction(vm, d) {
d.forEach(function(item, index, arr) {
if ([vm.$t('perms.clipboardCopyPaste'), vm.$t('perms.upDownload'), vm.$t('perms.all')].includes(item)) {
arr.splice(index, 1)
}
})
return d.join(', ')
}
export function getApiPath(that) { export function getApiPath(that) {
let pagePath = that.$route.path let pagePath = that.$route.path
const pagePathArray = pagePath.split('/') const pagePathArray = pagePath.split('/')

View File

@@ -0,0 +1,106 @@
<template>
<GenericUpdateFormDialog
v-if="visible"
:selected-rows="selectedRows"
:form-setting="formSetting"
:visible="visible"
v-on="$listeners"
/>
</template>
<script>
import { GenericUpdateFormDialog } from '@/layout/components'
import Protocols from '@/views/assets/Asset/components/Protocols'
import rules from '@/components/DataForm/rules'
export default {
name: 'AssetBulkUpdateDialog',
components: {
GenericUpdateFormDialog
},
props: {
visible: {
type: Boolean,
default: false
},
selectedRows: {
type: Array,
default: () => ([])
}
},
data() {
return {
formSetting: {
url: '/api/v1/assets/assets/',
hasSaveContinue: false,
initial: {
platform: 'Linux',
protocols: ['ssh/22']
},
fields: [
'platform', 'protocols', 'domain', 'admin_user', 'labels', 'comment'
],
fieldsMeta: {
platform: {
label: this.$t('assets.Platform'),
hidden: () => false,
el: {
multiple: false,
ajax: {
url: '/api/v1/assets/platforms/',
transformOption: (item) => {
return { label: `${item.name}`, value: item.name }
}
}
}
},
protocols: {
label: this.$t('assets.Protocols'),
component: Protocols
},
domain: {
label: this.$t('assets.Domain'),
hidden: () => false,
el: {
multiple: false,
ajax: {
url: '/api/v1/assets/domains/'
}
}
},
admin_user: {
rules: [rules.RequiredChange],
label: this.$t('assets.AdminUser'),
hidden: () => false,
el: {
multiple: false,
ajax: {
url: '/api/v1/assets/admin-users/',
transformOption: (item) => {
return { label: `${item.name}(${item.username})`, value: item.id }
}
}
}
},
labels: {
label: this.$t('assets.Label'),
hidden: () => false,
el: {
ajax: {
url: '/api/v1/assets/labels/'
}
}
},
comment: {
label: this.$t('common.Comment'),
hidden: () => false
}
}
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -38,29 +38,13 @@
<el-col :span="18"><div class="item-text">{{ item.value }}</div></el-col> <el-col :span="18"><div class="item-text">{{ item.value }}</div></el-col>
</el-row> </el-row>
</Dialog> </Dialog>
<div class="asset-select-dialog"> <AssetBulkUpdateDialog
<Dialog :visible.sync="updateSelectedDialogSetting.visible"
v-if="assetTreeTableDialogSetting.dialogVisible" v-bind="updateSelectedDialogSetting"
:title="this.$t('assets.Assets')" />
:visible.sync="assetTreeTableDialogSetting.dialogVisible" <NodeAssetsUpdateDialog
width="70%" :visible.sync="nodeAssetsUpdateDialog.visible"
top="1vh" v-bind="nodeAssetsUpdateDialog"
@confirm="assetTreeTableDialogHandleConfirm"
@cancel="assetTreeTableDialogHandleCancel"
>
<TreeTable
ref="TreeTable"
:tree-setting="assetTreeTableDialogSetting.treeSetting"
:table-config="assetTreeTableDialogSetting.tableConfig"
:header-actions="assetTreeTableDialogSetting.headerActions"
/>
</Dialog>
</div>
<GenericUpdateFormDialog
v-if="updateSelectedDialogSetting.dialogSetting.dialogVisible"
:selected-rows="updateSelectedDialogSetting.selectedRows"
:form-setting="updateSelectedDialogSetting.formSetting"
:dialog-setting="updateSelectedDialogSetting.dialogSetting"
/> />
</div> </div>
</template> </template>
@@ -70,20 +54,18 @@ import GenericTreeListPage from '@/layout/components/GenericTreeListPage/index'
import { DetailFormatter, ActionsFormatter } from '@/components/TableFormatters' import { DetailFormatter, ActionsFormatter } from '@/components/TableFormatters'
import $ from '@/utils/jquery-vendor' import $ from '@/utils/jquery-vendor'
import Dialog from '@/components/Dialog' import Dialog from '@/components/Dialog'
import TreeTable from '@/components/TreeTable'
import { GenericUpdateFormDialog } from '@/layout/components'
import rules from '@/components/DataForm/rules'
import Protocols from '@/views/assets/Asset/components/Protocols/index'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { connectivityMeta } from '@/components/AccountListTable/const' import { connectivityMeta } from '@/components/AccountListTable/const'
import { openTaskPage } from '@/utils/jms' import { openTaskPage } from '@/utils/jms'
import AssetBulkUpdateDialog from './AssetBulkUpdateDialog'
import NodeAssetsUpdateDialog from './NodeAssetsUpdateDialog'
export default { export default {
components: { components: {
GenericTreeListPage, GenericTreeListPage,
Dialog, Dialog,
TreeTable, AssetBulkUpdateDialog,
GenericUpdateFormDialog NodeAssetsUpdateDialog
}, },
data() { data() {
const vm = this const vm = this
@@ -220,9 +202,9 @@ export default {
name: 'updateSelected', name: 'updateSelected',
title: this.$t('common.updateSelected'), title: this.$t('common.updateSelected'),
can: ({ selectedRows }) => selectedRows.length > 0 && !this.$store.getters.currentOrgIsRoot, can: ({ selectedRows }) => selectedRows.length > 0 && !this.$store.getters.currentOrgIsRoot,
callback: ({ selectedRows, reloadTable }) => { callback: ({ selectedRows }) => {
vm.updateSelectedDialogSetting.dialogSetting.dialogVisible = true
vm.updateSelectedDialogSetting.selectedRows = selectedRows vm.updateSelectedDialogSetting.selectedRows = selectedRows
vm.updateSelectedDialogSetting.visible = true
} }
}, },
{ {
@@ -259,125 +241,14 @@ export default {
dialogVisible: false, dialogVisible: false,
items: [] items: []
}, },
assetTreeTableDialogSetting: {
dialogVisible: false,
assetsSelected: [],
action: '',
treeSetting: {
showMenu: false,
showRefresh: true,
showAssets: false,
url: '/api/v1/assets/assets/?fields_size=mini',
nodeUrl: '/api/v1/assets/nodes/',
// ?assets=0不显示资产. =1显示资产
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=0'
},
tableConfig: {
url: '/api/v1/assets/assets/',
hasTree: true,
columns: [
{
prop: 'hostname',
label: this.$t('assets.Hostname'),
sortable: true,
formatter: DetailFormatter,
formatterArgs: {
route: 'AssetDetail'
}
},
{
prop: 'ip',
label: this.$t('assets.ip'),
sortable: 'custom'
}
],
listeners: {
'toggle-row-selection': (isSelected, row) => {
if (isSelected) {
this.addRowToAssetsSelected(row)
} else {
this.removeRowFromAssetsSelected(row)
}
}
}
},
headerActions: {
hasLeftActions: false,
hasRightActions: false
}
},
updateSelectedDialogSetting: { updateSelectedDialogSetting: {
selectedRows: [], visible: false,
dialogSetting: { selectedRows: []
dialogVisible: false },
}, nodeAssetsUpdateDialog: {
formSetting: { visible: false,
url: '/api/v1/assets/assets/', action: 'add',
hasSaveContinue: false, selectNode: null
initial: {
platform: 'Linux',
protocols: ['ssh/22']
},
fields: [
'platform', 'protocols', 'domain', 'admin_user', 'labels', 'comment'
],
fieldsMeta: {
platform: {
label: this.$t('assets.Platform'),
hidden: () => false,
el: {
multiple: false,
ajax: {
url: '/api/v1/assets/platforms/',
transformOption: (item) => {
return { label: `${item.name}`, value: item.name }
}
}
}
},
protocols: {
label: this.$t('assets.Protocols'),
component: Protocols
},
domain: {
label: this.$t('assets.Domain'),
hidden: () => false,
el: {
multiple: false,
ajax: {
url: '/api/v1/assets/domains/'
}
}
},
admin_user: {
rules: [rules.RequiredChange],
label: this.$t('assets.AdminUser'),
hidden: () => false,
el: {
multiple: false,
ajax: {
url: '/api/v1/assets/admin-users/',
transformOption: (item) => {
return { label: `${item.name}(${item.username})`, value: item.id }
}
}
}
},
labels: {
label: this.$t('assets.Label'),
hidden: () => false,
el: {
ajax: {
url: '/api/v1/assets/labels/'
}
}
},
comment: {
label: this.$t('common.Comment'),
hidden: () => false
}
}
}
} }
} }
}, },
@@ -405,13 +276,15 @@ export default {
getSelectedNodes() { getSelectedNodes() {
return this.$refs.TreeList.getSelectedNodes() return this.$refs.TreeList.getSelectedNodes()
}, },
rMenuAddAssetToNode: function() { rMenuAddAssetToNode() {
this.assetTreeTableDialogSetting.dialogVisible = true this.nodeAssetsUpdateDialog.visible = true
this.assetTreeTableDialogSetting.action = 'add' this.nodeAssetsUpdateDialog.action = 'add'
this.nodeAssetsUpdateDialog.selectNode = this.getSelectedNodes()[0]
}, },
rMenuMoveAssetToNode: function() { rMenuMoveAssetToNode() {
this.assetTreeTableDialogSetting.dialogVisible = true this.nodeAssetsUpdateDialog.visible = true
this.assetTreeTableDialogSetting.action = 'move' this.nodeAssetsUpdateDialog.action = 'move'
this.nodeAssetsUpdateDialog.selectNode = this.getSelectedNodes()[0]
}, },
rMenuUpdateNodeAssetHardwareInfo: function() { rMenuUpdateNodeAssetHardwareInfo: function() {
this.hideRMenu() this.hideRMenu()
@@ -493,43 +366,6 @@ export default {
}).catch(error => { }).catch(error => {
this.$message.error(this.$t('common.getErrorMsg' + ' ' + error)) this.$message.error(this.$t('common.getErrorMsg' + ' ' + error))
}) })
},
addRowToAssetsSelected(row) {
const selectValueIndex = this.assetTreeTableDialogSetting.assetsSelected.indexOf(row.id)
if (selectValueIndex === -1) {
this.assetTreeTableDialogSetting.assetsSelected.push(row.id)
}
},
removeRowFromAssetsSelected(row) {
const selectValueIndex = this.assetTreeTableDialogSetting.assetsSelected.indexOf(row.id)
if (selectValueIndex > -1) {
this.assetTreeTableDialogSetting.assetsSelected.splice(selectValueIndex, 1)
}
},
assetTreeTableDialogHandleConfirm() {
const currentNode = this.getSelectedNodes()[0]
const assetsSelected = this.assetTreeTableDialogSetting.assetsSelected
if (!currentNode || assetsSelected.length === 0) {
return
}
let url = `/api/v1/assets/nodes/${currentNode.meta.data.id}/assets/add/`
if (this.assetTreeTableDialogSetting.action === 'move') {
url = `/api/v1/assets/nodes/${currentNode.meta.data.id}/assets/replace/`
}
this.$axios.put(
url, { assets: assetsSelected }
).then(res => {
this.assetTreeTableDialogSetting.dialogVisible = false
this.assetTreeTableDialogSetting.assetsSelected = []
$('#tree-refresh').trigger('click')
this.$message.success(this.$t('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
})
},
assetTreeTableDialogHandleCancel() {
this.assetTreeTableDialogSetting.dialogVisible = false
this.assetTreeTableDialogSetting.assetsSelected = []
} }
} }
} }

View File

@@ -0,0 +1,150 @@
<template>
<div class="asset-select-dialog">
<Dialog
v-if="iVisible"
:title="this.$t('assets.Assets')"
:visible.sync="iVisible"
width="70%"
top="1vh"
@confirm="assetTreeTableDialogHandleConfirm"
@cancel="assetTreeTableDialogHandleCancel"
>
<TreeTable
ref="TreeTable"
:tree-setting="treeSetting"
:table-config="tableConfig"
:header-actions="headerActions"
/>
</Dialog>
</div>
</template>
<script>
import Dialog from '@/components/Dialog'
import TreeTable from '@/components/TreeTable'
import { DetailFormatter } from '@/components/TableFormatters'
import $ from '@/utils/jquery-vendor'
export default {
name: 'NodeAssetsUpdate',
components: {
Dialog,
TreeTable
},
props: {
visible: {
type: Boolean,
default: false
},
action: {
type: String,
default: 'add'
},
selectNode: {
type: Object,
default: null
}
},
data() {
return {
dialogVisible: false,
assetsSelected: [],
treeSetting: {
showMenu: false,
showRefresh: true,
showAssets: false,
url: '/api/v1/assets/assets/?fields_size=mini',
nodeUrl: '/api/v1/assets/nodes/',
// ?assets=0不显示资产. =1显示资产
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=0'
},
tableConfig: {
url: '/api/v1/assets/assets/',
hasTree: true,
columns: [
{
prop: 'hostname',
label: this.$t('assets.Hostname'),
sortable: true,
formatter: DetailFormatter,
formatterArgs: {
route: 'AssetDetail'
}
},
{
prop: 'ip',
label: this.$t('assets.ip'),
sortable: 'custom'
}
],
listeners: {
'toggle-row-selection': (isSelected, row) => {
if (isSelected) {
this.addRowToAssetsSelected(row)
} else {
this.removeRowFromAssetsSelected(row)
}
}
}
},
headerActions: {
hasLeftActions: false,
hasRightActions: false
}
}
},
computed: {
iVisible: {
set(val) {
console.log('set val: ', val)
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
},
methods: {
addRowToAssetsSelected(row) {
const selectValueIndex = this.assetsSelected.indexOf(row.id)
if (selectValueIndex === -1) {
this.assetsSelected.push(row.id)
}
},
removeRowFromAssetsSelected(row) {
const selectValueIndex = this.assetsSelected.indexOf(row.id)
if (selectValueIndex > -1) {
this.assetsSelected.splice(selectValueIndex, 1)
}
},
assetTreeTableDialogHandleConfirm() {
const currentNode = this.selectNode
const assetsSelected = this.assetsSelected
if (!currentNode || assetsSelected.length === 0) {
return
}
let url = `/api/v1/assets/nodes/${currentNode.meta.data.id}/assets/add/`
if (this.action === 'move') {
url = `/api/v1/assets/nodes/${currentNode.meta.data.id}/assets/replace/`
}
this.$axios.put(
url, { assets: assetsSelected }
).then(res => {
this.dialogVisible = false
this.assetsSelected = []
$('#tree-refresh').trigger('click')
this.$message.success(this.$t('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
})
},
assetTreeTableDialogHandleCancel() {
this.dialogVisible = false
this.assetsSelected = []
}
}
}
</script>
<style scoped>
</style>

View File

@@ -52,7 +52,6 @@ export default {
} }
}, },
password: { password: {
helpText: this.$t('assets.PasswordWithoutSpecialCharHelpText'),
hidden: (formValue) => { hidden: (formValue) => {
if (!this.$route.params.id) { if (!this.$route.params.id) {
return false return false

View File

@@ -1,5 +1,5 @@
<template> <template>
<component :is="systemUserProtocolComponent" :title="title" /> <component :is="systemUserProtocolComponent" :title="iTitle" />
</template> </template>
<script> <script>
@@ -9,10 +9,19 @@ export default {
name: 'AdminUserCreate', name: 'AdminUserCreate',
data() { data() {
return { return {
title: this.$t('route.SystemUserCreate') + ' - ' + this.$t('assets.AdminUser')
} }
}, },
computed: { computed: {
iTitle() {
const params = this.$route.params
let title = ''
if (params.id) {
title = this.$t('route.SystemUserUpdate')
} else {
title = this.$t('route.SystemUserCreate')
}
return title + '-' + this.$t('assets.AdminUser')
},
systemUserProtocolComponent() { systemUserProtocolComponent() {
return SSH return SSH
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<component :is="systemUserProtocolComponent" :title="title" /> <component :is="systemUserProtocolComponent" :title="iTitle" />
</template> </template>
<script> <script>
@@ -14,12 +14,21 @@ export default {
components: { SSH, RDP, VncOrTelnet, Database }, components: { SSH, RDP, VncOrTelnet, Database },
data() { data() {
return { return {
title: this.$t('route.SystemUserCreate') + ' - ' + this.$t('assets.CommonUser')
} }
}, },
method: { method: {
}, },
computed: { computed: {
iTitle() {
const params = this.$route.params
let title = ''
if (params.id) {
title = this.$t('route.SystemUserUpdate')
} else {
title = this.$t('route.SystemUserCreate')
}
return title + '-' + this.$t('assets.CommonUser')
},
systemUserProtocolComponent() { systemUserProtocolComponent() {
const query = this.$route.query const query = this.$route.query
const protocol = query.protocol const protocol = query.protocol

View File

@@ -162,8 +162,7 @@ export default {
return { label: item.full_value, value: item.id } return { label: item.full_value, value: item.id }
} }
}, },
hasObjectsId: [], hasObjectsId: this.object.nodes,
hasObjects: [],
performAdd: (items) => { performAdd: (items) => {
const relationUrl = `/api/v1/assets/system-users-nodes-relations/` const relationUrl = `/api/v1/assets/system-users-nodes-relations/`
const objectId = this.object.id const objectId = this.object.id

View File

@@ -10,6 +10,7 @@
<script> <script>
import BaseAuth from './Base' import BaseAuth from './Base'
import { JsonRequired } from '@/components/DataForm/rules'
export default { export default {
name: 'Cas', name: 'Cas',
components: { components: {
@@ -26,14 +27,34 @@ export default {
settings: { settings: {
url: '/api/v1/settings/setting/?category=cas', url: '/api/v1/settings/setting/?category=cas',
fields: [ fields: [
[this.$t('common.Basic'), ['AUTH_CAS', 'CAS_SERVER_URL', 'CAS_VERSION']], [this.$t('common.Basic'), ['AUTH_CAS', 'CAS_SERVER_URL', 'CAS_ROOT_PROXIED_AS', 'CAS_VERSION']],
[this.$t('common.Other'), [ [this.$t('common.Other'), [
'CAS_LOGOUT_COMPLETELY', 'CAS_USERNAME_ATTRIBUTE', 'CAS_LOGOUT_COMPLETELY', 'CAS_USERNAME_ATTRIBUTE',
'CAS_APPLY_ATTRIBUTES_TO_USER', 'CAS_RENAME_ATTRIBUTES', 'CAS_APPLY_ATTRIBUTES_TO_USER', 'CAS_RENAME_ATTRIBUTES',
'CAS_CREATE_USER' 'CAS_CREATE_USER'
]] ]]
], ],
submitMethod: () => 'patch' fieldsMeta: {
CAS_RENAME_ATTRIBUTES: {
component: 'el-input',
el: {
type: 'textarea'
},
label: this.$t('setting.authCASAttrMap'),
rules: [JsonRequired]
}
},
submitMethod: () => 'patch',
afterGetFormValue(obj) {
obj.CAS_RENAME_ATTRIBUTES = JSON.stringify(obj.CAS_RENAME_ATTRIBUTES)
return obj
},
cleanFormValue(data) {
if (data['CAS_RENAME_ATTRIBUTES']) {
data['CAS_RENAME_ATTRIBUTES'] = JSON.parse(data['CAS_RENAME_ATTRIBUTES'])
}
return data
}
} }
} }
}, },

View File

@@ -61,6 +61,15 @@ export default {
}, },
AUTH_SSO: { AUTH_SSO: {
component: SSO component: SSO
},
FORGOT_PASSWORD_URL: {
on: {
change([value], updateForm) {
if (value && !value.startsWith('http')) {
updateForm({ FORGOT_PASSWORD_URL: 'http://' + value })
}
}
}
} }
}, },
submitMethod() { submitMethod() {

View File

@@ -94,7 +94,12 @@ export default {
this.dialogVisible = true this.dialogVisible = true
}, },
async initBackends() { async initBackends() {
this.receiveBackends = await this.$axios.get('/api/v1/notifications/backends/') const backends = await this.$axios.get('/api/v1/notifications/backends/')
backends.forEach(backend => {
if (backend.name !== 'site_msg') {
this.receiveBackends.push(backend)
}
})
}, },
async initSubscriptions() { async initSubscriptions() {
const subscriptions = await this.$axios.get('/api/v1/notifications/system-msg-subscription/') const subscriptions = await this.$axios.get('/api/v1/notifications/system-msg-subscription/')

View File

@@ -34,7 +34,7 @@ export default {
[ [
this.$t('setting.Ops'), this.$t('setting.Ops'),
[ [
'PERIOD_TASK_ENABLED', 'WINDOWS_SSH_DEFAULT_SHELL' 'WINDOWS_SSH_DEFAULT_SHELL'
] ]
], ],
[ [

View File

@@ -6,6 +6,7 @@
:fields-meta="fieldsMeta" :fields-meta="fieldsMeta"
:submit-method="submitMethod" :submit-method="submitMethod"
:has-detail-in-msg="false" :has-detail-in-msg="false"
@submitSuccess="onSubmitSuccess()"
/> />
</IBox> </IBox>
</template> </template>
@@ -65,6 +66,16 @@ export default {
title: this.$t('setting.insecureCommandEmailUpdate') title: this.$t('setting.insecureCommandEmailUpdate')
} }
}, },
LOGIN_CONFIRM_ENABLE: {
hidden: () => {
return !this.$store.getters.hasValidLicense
}
},
SECURITY_WATERMARK_ENABLED: {
hidden: () => {
return !this.$store.getters.hasValidLicense
}
},
PasswordRule: { PasswordRule: {
label: this.$t('setting.PasswordCheckRule'), label: this.$t('setting.PasswordCheckRule'),
component: PasswordRule component: PasswordRule
@@ -80,6 +91,9 @@ export default {
methods: { methods: {
submitMethod() { submitMethod() {
return 'patch' return 'patch'
},
onSubmitSuccess() {
window.location.reload()
} }
} }
} }

View File

@@ -16,12 +16,19 @@ export default {
return { return {
fields: [ fields: [
[ [
'KoKo', [ 'KoKo',
[
'TERMINAL_PASSWORD_AUTH', 'TERMINAL_PUBLIC_KEY_AUTH', 'TERMINAL_PASSWORD_AUTH', 'TERMINAL_PUBLIC_KEY_AUTH',
'TERMINAL_ASSET_LIST_SORT_BY', 'TERMINAL_ASSET_LIST_PAGE_SIZE', 'TERMINAL_ASSET_LIST_SORT_BY', 'TERMINAL_ASSET_LIST_PAGE_SIZE',
'TERMINAL_TELNET_REGEX' 'TERMINAL_TELNET_REGEX'
] ]
], ],
[
'XRDP',
[
'XRDP_ENABLED', 'TERMINAL_RDP_ADDR'
]
],
[ [
this.$t('common.Other'), this.$t('common.Other'),
[ [
@@ -32,6 +39,19 @@ export default {
fieldsMeta: { fieldsMeta: {
TERMINAL_TELNET_REGEX: { TERMINAL_TELNET_REGEX: {
type: 'input' type: 'input'
},
TERMINAL_RDP_ADDR: {
hidden: () => {
return !this.$store.getters.hasValidLicense
}
},
XRDP_ENABLED: {
hidden: () => {
return !this.$store.getters.hasValidLicense
},
el: {
hiddenGroup: true
}
} }
}, },
url: '/api/v1/settings/setting/?category=terminal', url: '/api/v1/settings/setting/?category=terminal',
@@ -52,14 +72,6 @@ export default {
} }
}, },
mounted() { mounted() {
if (this.$store.getters.hasValidLicense) {
const xRDPFields = [
'XRDP', [
'TERMINAL_RDP_ADDR', 'XRDP_ENABLED'
]
]
this.fields.splice(1, 0, xRDPFields)
}
}, },
methods: { methods: {
} }

View File

@@ -101,8 +101,12 @@ export default {
key: this.$t('tickets.PermissionName'), key: this.$t('tickets.PermissionName'),
value: this.object.meta.apply_permission_name, value: this.object.meta.apply_permission_name,
formatter: function(item, value) { formatter: function(item, value) {
const to = { name: 'AssetPermissionDetail', params: { id: vm.object.id }} const to = { name: 'ApplicationPermissionDetail', params: { id: vm.object.id }, query: { oid: vm.object.org_id }}
return <router-link to={to}>{ value }</router-link> if (vm.object.status === 'closed' && vm.object.state === 'approved') {
return <router-link to={to}>{ value }</router-link>
} else {
return <span>{ value }</span>
}
} }
}, },
{ {

View File

@@ -12,7 +12,7 @@
<script> <script>
import { formatTime, getDateTimeStamp } from '@/utils/index' import { formatTime, getDateTimeStamp } from '@/utils/index'
import { toSafeLocalDateStr } from '@/utils/common' import { toSafeLocalDateStr, forMatAction } from '@/utils/common'
import { STATUS_MAP } from '../../const' import { STATUS_MAP } from '../../const'
import GenericTicketDetail from '@/views/tickets/components/GenericTicketDetail' import GenericTicketDetail from '@/views/tickets/components/GenericTicketDetail'
export default { export default {
@@ -79,7 +79,7 @@ export default {
}, },
{ {
key: this.$t('assets.Action'), key: this.$t('assets.Action'),
value: this.object.meta['apply_actions_display'] value: forMatAction(this, this.object.meta['apply_actions_display'])
}, },
{ {
key: this.$t('common.dateStart'), key: this.$t('common.dateStart'),
@@ -98,8 +98,12 @@ export default {
key: this.$t('tickets.PermissionName'), key: this.$t('tickets.PermissionName'),
value: this.object.meta.apply_permission_name, value: this.object.meta.apply_permission_name,
formatter: function(item, value) { formatter: function(item, value) {
const to = { name: 'AssetPermissionDetail', params: { id: vm.object.id }} const to = { name: 'AssetPermissionDetail', params: { id: vm.object.id }, query: { oid: vm.object.org_id }}
return <router-link to={to}>{ value }</router-link> if (vm.object.status === 'closed' && vm.object.state === 'approved') {
return <router-link to={to}>{ value }</router-link>
} else {
return <span>{ value }</span>
}
} }
}, },
{ {
@@ -112,7 +116,7 @@ export default {
}, },
{ {
key: this.$t('assets.Action'), key: this.$t('assets.Action'),
value: this.object.meta['apply_actions_display'] value: forMatAction(this, this.object.meta['apply_actions_display'])
}, },
{ {
key: this.$t('common.dateStart'), key: this.$t('common.dateStart'),

View File

@@ -25,7 +25,8 @@ export default {
meta: { meta: {
apply_date_expired: date_expired, apply_date_expired: date_expired,
apply_date_start: date_start, apply_date_start: date_start,
apply_actions: ['all', 'connect', 'updownload', 'upload_file', 'download_file'] apply_actions: ['all', 'connect', 'updownload', 'upload_file', 'download_file'],
apply_assets: []
}, },
org_id: '', org_id: '',
type: 'apply_asset' type: 'apply_asset'
@@ -87,13 +88,15 @@ export default {
component: Select2, component: Select2,
el: { el: {
multiple: false, multiple: false,
options: this.$store.state.users.profile.user_all_orgs.map((item) => { options: this.$store.state.users.profile['user_all_orgs'].map((item) => {
return { label: item.name, value: item.id } return { label: item.name, value: item.id }
}) })
}, },
hidden: (form) => { hidden: (form) => {
this.fieldsMeta.meta.fieldsMeta.apply_system_users.el.ajax.url = `/api/v1/assets/system-users/suggestions/?oid=${form['org_id']}&protocol__in=rdp,ssh,vnc,telnet` const fieldsMeta = this.fieldsMeta.meta.fieldsMeta
this.fieldsMeta.meta.fieldsMeta.apply_assets.el.ajax.url = `/api/v1/assets/assets/suggestions/?oid=${form['org_id']}` fieldsMeta.apply_system_users.el.ajax.url = `/api/v1/assets/system-users/suggestions/?oid=${form['org_id']}&protocol__in=rdp,ssh,vnc,telnet`
fieldsMeta.apply_assets.el.value = []
fieldsMeta.apply_assets.el.ajax.url = `/api/v1/assets/assets/suggestions/?oid=${form['org_id']}`
} }
} }
}, },
@@ -104,8 +107,8 @@ export default {
} }
}, },
mounted() { mounted() {
if (this.$store.state.users.profile.user_all_orgs.length > 0) { if (this.$store.state.users.profile['user_all_orgs'].length > 0) {
this.initial.org_id = this.$store.state.users.profile.user_all_orgs[0].id this.initial.org_id = this.$store.state.users.profile['user_all_orgs'][0].id
} }
this.loading = false this.loading = false
}, },

View File

@@ -69,7 +69,7 @@ export default {
value: '' value: ''
}] }]
this.object.rules.forEach((item, index) => { this.object.rules.forEach((item, index) => {
if (index === 0) { if (item.level === 1) {
approvalData[0].value = item.strategy_display approvalData[0].value = item.strategy_display
approvalData[1].value = item.assignees_display.join(',') approvalData[1].value = item.assignees_display.join(',')
} else { } else {

View File

@@ -44,6 +44,8 @@ export default {
data['rules'] = data['rules'].slice(0, data['approval_level']) data['rules'] = data['rules'].slice(0, data['approval_level'])
return data return data
}, },
onPerformError() {
},
updateSuccessNextRoute: { name: 'TicketList' }, updateSuccessNextRoute: { name: 'TicketList' },
createSuccessNextRoute: { name: 'TicketList' } createSuccessNextRoute: { name: 'TicketList' }
} }

View File

@@ -31,6 +31,7 @@ export default {
TicketFlow TicketFlow
}, },
data() { data() {
const vm = this
return { return {
assignedTicketCount: 0, assignedTicketCount: 0,
config: { config: {
@@ -47,7 +48,10 @@ export default {
{ {
title: '流程设置', title: '流程设置',
icon: 'fa-gear', icon: 'fa-gear',
name: 'TicketFlow' name: 'TicketFlow',
hidden: () => {
return !(vm.$store.getters.currentUserIsSuperAdmin || vm.$store.getters.currentUserIsAdmin)
}
} }
] ]
} }

View File

@@ -7,12 +7,12 @@
<el-row :gutter="10"> <el-row :gutter="10">
<el-col v-for="item in detailCardItems" :key="'card-' + item.key" :span="12"> <el-col v-for="item in detailCardItems" :key="'card-' + item.key" :span="12">
<el-row class="item"> <el-row class="item">
<el-col :span="6"> <el-col :span="4">
<div :style="{ 'text-align': 'align' }" class="item-label"> <div :style="{ 'text-align': 'align' }" class="item-label">
<label>{{ item.key }}: </label> <label>{{ item.key }}: </label>
</div> </div>
</el-col> </el-col>
<el-col :span="18"> <el-col :span="20">
<div class="item-text"> <div class="item-text">
<ItemValue v-bind="item" /> <ItemValue v-bind="item" />
</div> </div>
@@ -24,12 +24,12 @@
<el-row :gutter="10"> <el-row :gutter="10">
<el-col v-for="item in specialCardItems" :key="'card-' + item.key" :span="12"> <el-col v-for="item in specialCardItems" :key="'card-' + item.key" :span="12">
<el-row class="item"> <el-row class="item">
<el-col :span="6"> <el-col :span="4">
<div :style="{ 'text-align': 'align' }" class="item-label"> <div :style="{ 'text-align': 'align' }" class="item-label">
<label>{{ item.key }}: </label> <label>{{ item.key }}: </label>
</div> </div>
</el-col> </el-col>
<el-col :span="18"> <el-col :span="20">
<div class="item-text"> <div class="item-text">
<ItemValue v-bind="item" /> <ItemValue v-bind="item" />
</div> </div>

View File

@@ -1,6 +1,6 @@
<template> <template>
<IBox> <IBox>
<div style="height: 660px;"> <div style="height: 540px;">
<el-steps direction="vertical" :active="ticketSteps"> <el-steps direction="vertical" :active="ticketSteps">
<el-step <el-step
:title="`${this.$t('tickets.OpenTicket')}${object.type_display}`" :title="`${this.$t('tickets.OpenTicket')}${object.type_display}`"
@@ -17,17 +17,17 @@
:title="`${thisCopy.$t('tickets.HandleTicket')}`" :title="`${thisCopy.$t('tickets.HandleTicket')}`"
> >
<div slot="description"> <div slot="description">
<el-tag :type="`${thisCopy.statusMap[item.state].type}`"> {{ `${thisCopy.statusMap[item.state].title}` }} </el-tag> <el-tag size="medium" :type="`${thisCopy.statusMap[item.state].type}`"> {{ `${thisCopy.statusMap[item.state].title}` }} </el-tag>
</div> </div>
<div v-if="item.state==='closed'" slot="description" style="color: blue"> <div slot="description"><el-button type="text" style="color: blue" @click="lookOver(item.assignees_display)">点击查看 受理人</el-button></div>
<div v-if="item.state==='closed'" slot="description">
<div>{{ `${thisCopy.$t('tickets.Assignee')}${object.applicant_display}` }}</div> <div>{{ `${thisCopy.$t('tickets.Assignee')}${object.applicant_display}` }}</div>
<div>{{ `${thisCopy.$t('common.dateFinished')}: ${toSafeLocalDateStr(item.approval_date)}` }}</div> <div>{{ `${thisCopy.$t('common.dateFinished')}: ${toSafeLocalDateStr(item.approval_date)}` }}</div>
</div> </div>
<div v-if="item.state!=='notified' && item.state!=='closed'" slot="description" style="color: blue"> <div v-if="item.state!=='notified' && item.state!=='closed'" slot="description">
<div>{{ `${thisCopy.$t('tickets.Assignee')}${item.processor_display}` }}</div> <div>{{ `${thisCopy.$t('tickets.Assignee')}${item.processor_display}` }}</div>
<div>{{ `${thisCopy.$t('common.dateFinished')}: ${toSafeLocalDateStr(item.approval_date)}` }}</div> <div>{{ `${thisCopy.$t('common.dateFinished')}: ${toSafeLocalDateStr(item.approval_date)}` }}</div>
</div> </div>
<div slot="description">{{ `${thisCopy.$t('tickets.Assignees')}${item.assignees_display}` }}</div>
</el-step> </el-step>
<el-step <el-step
:title="`${this.$t('tickets.FinishedTicket')}`" :title="`${this.$t('tickets.FinishedTicket')}`"
@@ -89,6 +89,19 @@ export default {
}, },
toSafeLocalDateStr(dataStr) { toSafeLocalDateStr(dataStr) {
return toSafeLocalDateStr(dataStr) return toSafeLocalDateStr(dataStr)
},
lookOver(assignees_display) {
const h = this.$createElement
const content = []
assignees_display.forEach(item => {
content.push(h('p', null, item),)
})
this.$msgbox({
title: '相关受理人',
message: h('p', null, content),
showCancelButton: false,
showConfirmButton: false
})
} }
} }
} }

View File

@@ -58,7 +58,7 @@ export default {
title: this.$t('users.quickUpdate.resetMFA'), title: this.$t('users.quickUpdate.resetMFA'),
attrs: { attrs: {
type: 'primary', type: 'primary',
disabled: !this.object.mfa_enabled, disabled: !this.object.mfa_enabled || this.object.id === this.$store.state.users.profile.id,
label: this.$t('common.Reset') label: this.$t('common.Reset')
}, },
callbacks: { callbacks: {
@@ -239,6 +239,22 @@ export default {
key: this.$t('users.Email'), key: this.$t('users.Email'),
value: this.object.email value: this.object.email
}, },
{
key: this.$t('users.Phone'),
value: this.object.phone
},
{
key: this.$t('users.WeCom'),
value: this.object.wecom_id
},
{
key: this.$t('users.DingTalk'),
value: this.object.dingtalk_id
},
{
key: this.$t('users.FeiShu'),
value: this.object.feishu_id
},
{ {
key: this.$t('users.Role'), key: this.$t('users.Role'),
value: this.object.total_role_display value: this.object.total_role_display

View File

@@ -8,7 +8,7 @@
<GenericUpdateFormDialog <GenericUpdateFormDialog
:selected-rows="updateSelectedDialogSetting.selectedRows" :selected-rows="updateSelectedDialogSetting.selectedRows"
:form-setting="updateSelectedDialogSetting.formSetting" :form-setting="updateSelectedDialogSetting.formSetting"
:dialog-setting="updateSelectedDialogSetting.dialogSetting" :visible.sync="updateSelectedDialogSetting.visible"
@update="handleDialogUpdate" @update="handleDialogUpdate"
/> />
<InviteUsersDialog :setting="InviteDialogSetting" @close="handleInviteDialogClose" /> <InviteUsersDialog :setting="InviteDialogSetting" @close="handleInviteDialogClose" />
@@ -166,7 +166,7 @@ export default {
title: this.$t('common.updateSelected'), title: this.$t('common.updateSelected'),
can: ({ selectedRows }) => selectedRows.length > 0 && !vm.currentOrgIsRoot, can: ({ selectedRows }) => selectedRows.length > 0 && !vm.currentOrgIsRoot,
callback: ({ selectedRows, reloadTable }) => { callback: ({ selectedRows, reloadTable }) => {
vm.updateSelectedDialogSetting.dialogSetting.dialogVisible = true vm.updateSelectedDialogSetting.visible = true
vm.updateSelectedDialogSetting.selectedRows = selectedRows vm.updateSelectedDialogSetting.selectedRows = selectedRows
} }
} }
@@ -174,9 +174,7 @@ export default {
}, },
updateSelectedDialogSetting: { updateSelectedDialogSetting: {
selectedRows: [], selectedRows: [],
dialogSetting: { visible: false,
dialogVisible: false
},
formSetting: { formSetting: {
initial: { initial: {
date_expired: getDayFuture(36500, new Date()).toISOString() date_expired: getDayFuture(36500, new Date()).toISOString()

View File

@@ -39,6 +39,9 @@ export default {
el: { el: {
toFormat: 'object' toFormat: 'object'
} }
},
password: {
rules: this.$route.params.id ? [] : [Required]
} }
} }
}, },