mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-14 03:46:26 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee55cebf0e | ||
|
|
2e5096f386 | ||
|
|
bf57ee8910 | ||
|
|
f86f08f2b6 | ||
|
|
6eb429823d | ||
|
|
d6be84026c | ||
|
|
4a7680ec7a |
@@ -24,9 +24,9 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
|
||||
)
|
||||
|
||||
app.listen(port, function () {
|
||||
// debug(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
||||
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
||||
if (report) {
|
||||
// debug(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
||||
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
@@ -56,7 +56,7 @@ const responseFake = (url, type, respond) => {
|
||||
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
|
||||
type: type || 'get',
|
||||
response(req, res) {
|
||||
// debug('request invoke:' + req.path)
|
||||
console.log('request invoke:' + req.path)
|
||||
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ module.exports = app => {
|
||||
mockRoutesLength = mockRoutes.mockRoutesLength
|
||||
mockStartIndex = mockRoutes.mockStartIndex
|
||||
|
||||
// debug(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
|
||||
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
|
||||
} catch (error) {
|
||||
// debug(chalk.redBright(error))
|
||||
console.log(chalk.redBright(error))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
"axios": "0.21.1",
|
||||
"axios-retry": "^3.1.9",
|
||||
"cron-parser": "^4.0.0",
|
||||
"crypto-js": "^4.1.1",
|
||||
"deepmerge": "^4.2.2",
|
||||
"echarts": "^4.7.0",
|
||||
"element-ui": "2.13.2",
|
||||
@@ -33,7 +32,6 @@
|
||||
"install": "^0.13.0",
|
||||
"jquery": "^3.5.0",
|
||||
"js-cookie": "2.2.0",
|
||||
"jsencrypt": "^3.2.1",
|
||||
"krry-transfer": "^1.7.3",
|
||||
"less": "^3.10.3",
|
||||
"less-loader": "^5.0.0",
|
||||
|
||||
@@ -68,15 +68,9 @@ export function importLdapUser(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getPublicSettings(isOpen) {
|
||||
let url
|
||||
if (isOpen) {
|
||||
url = '/api/v1/settings/public/open/'
|
||||
} else {
|
||||
url = '/api/v1/settings/public/'
|
||||
}
|
||||
export function getPublicSettings() {
|
||||
return request({
|
||||
url: url,
|
||||
url: '/api/v1/settings/public/',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<UserConfirmDialog
|
||||
@UserConfirmDone="getAuthInfo"
|
||||
@UserConfirmCancel="exit"
|
||||
<MFAVerifyDialog
|
||||
@MFAVerifyDone="getAuthInfo"
|
||||
@MFAVerifyCancel="exit"
|
||||
/>
|
||||
<Dialog
|
||||
:title="dialogTitle"
|
||||
@@ -36,12 +36,12 @@
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import UserConfirmDialog from '@/components/UserConfirmDialog'
|
||||
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
|
||||
export default {
|
||||
name: 'ShowSecretInfo',
|
||||
components: {
|
||||
Dialog,
|
||||
UserConfirmDialog
|
||||
MFAVerifyDialog
|
||||
},
|
||||
props: {
|
||||
account: {
|
||||
@@ -60,6 +60,9 @@ export default {
|
||||
showAuthInfo: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAuthInfo()
|
||||
},
|
||||
methods: {
|
||||
getAuthInfo() {
|
||||
const url = `/api/v1/assets/account-secrets/${this.account.id}/`
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { UpdateToken, UploadKey } from '@/components/FormFields'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
export default {
|
||||
name: 'UpdateSecretInfo',
|
||||
components: {
|
||||
@@ -62,10 +61,10 @@ export default {
|
||||
handleConfirm() {
|
||||
const data = {}
|
||||
if (this.authInfo.password !== '') {
|
||||
data.password = encryptPassword(this.authInfo.password)
|
||||
data.password = this.authInfo.password
|
||||
}
|
||||
if (this.authInfo.private_key !== '') {
|
||||
data.private_key = encryptPassword(this.authInfo.private_key)
|
||||
data.private_key = this.authInfo.private_key
|
||||
if (this.authInfo.passphrase) data.passphrase = this.authInfo.passphrase
|
||||
}
|
||||
this.$axios.patch(
|
||||
|
||||
@@ -146,7 +146,9 @@ export default {
|
||||
vm.showUpdateSecretDialog = false
|
||||
setTimeout(() => {
|
||||
vm.showUpdateSecretDialog = true
|
||||
console.log('Show update1: ', vm.showUpdateSecretDialog)
|
||||
})
|
||||
console.log('Show update2: ', vm.showUpdateSecretDialog)
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -156,8 +158,7 @@ export default {
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: this.hasLeftActions,
|
||||
hasMoreActions: true,
|
||||
hasCreate: false,
|
||||
hasMoreActions: false,
|
||||
hasImport: false,
|
||||
hasExport: this.$hasPerm('assets.view_assetaccountsecret'),
|
||||
exportOptions: {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<el-link :href="announcement.link" target="_blank" class="link-more">
|
||||
{{ $t('common.ViewMore') }}
|
||||
</el-link>
|
||||
<i class="fa fa-external-link" />
|
||||
<i class="fa fa-share-square-o" />
|
||||
</span>
|
||||
</el-alert>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<UserConfirmDialog
|
||||
@UserConfirmDone="getAuthInfo"
|
||||
@UserConfirmCancel="exit"
|
||||
<MFAVerifyDialog
|
||||
@MFAVerifyDone="getAuthInfo"
|
||||
@MFAVerifyCancel="exit"
|
||||
/>
|
||||
<Dialog
|
||||
:title="dialogTitle"
|
||||
@@ -33,12 +33,12 @@
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import UserConfirmDialog from '@/components/UserConfirmDialog'
|
||||
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
|
||||
export default {
|
||||
name: 'ShowSecretInfo',
|
||||
components: {
|
||||
Dialog,
|
||||
UserConfirmDialog
|
||||
MFAVerifyDialog
|
||||
},
|
||||
props: {
|
||||
account: {
|
||||
@@ -57,6 +57,9 @@ export default {
|
||||
showAuthInfo: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAuthInfo()
|
||||
},
|
||||
methods: {
|
||||
getAuthInfo() {
|
||||
const url = `/api/v1/applications/account-secrets/${this.account.id}/`
|
||||
|
||||
@@ -38,10 +38,6 @@ export default {
|
||||
hasClone: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
systemUserDisabled: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -88,7 +84,7 @@ export default {
|
||||
showOverflowTooltip: true,
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
can: this.systemUserDisabled && this.$hasPerm('assets.view_systemuser'),
|
||||
can: this.$hasPerm('assets.view_systemuser'),
|
||||
getTitle({ row }) {
|
||||
return row.systemuser_display
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import NestedField from '@/components/AutoDataForm/components/NestedField'
|
||||
import Swicher from '@/components/FormFields/Swicher'
|
||||
import rules from '@/components/DataForm/rules'
|
||||
import { assignIfNot } from '@/utils/common'
|
||||
|
||||
@@ -46,8 +45,7 @@ export class FormFieldGenerator {
|
||||
}
|
||||
break
|
||||
case 'boolean':
|
||||
type = ''
|
||||
field.component = Swicher
|
||||
type = 'checkbox'
|
||||
break
|
||||
case 'nested object':
|
||||
type = 'nestedField'
|
||||
|
||||
@@ -85,9 +85,6 @@ export default {
|
||||
{ label: i18n.t('common.No'), value: false }
|
||||
]
|
||||
}
|
||||
if (option.value === 'id') {
|
||||
option.label = 'ID'
|
||||
}
|
||||
vm.internalOptions.push(option)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -82,8 +82,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
refreshTree: function() {
|
||||
// const refreshIconRef = $('#tree-refresh')
|
||||
// refreshIconRef.click()
|
||||
const refreshIconRef = $('#tree-refresh')
|
||||
refreshIconRef.click()
|
||||
},
|
||||
editTreeNode: function() {
|
||||
this.hideRMenu()
|
||||
@@ -112,17 +112,16 @@ export default {
|
||||
}
|
||||
let url = ''
|
||||
const query = Object.assign({}, this.$route.query)
|
||||
const objectId = treeNode.meta.data.id
|
||||
if (treeNode.meta.type === 'node') {
|
||||
this.currentNode = treeNode
|
||||
this.currentNodeId = treeNode.meta.data.id
|
||||
query['node'] = this.currentNodeId
|
||||
query['asset'] = ''
|
||||
url = `${this.setting.url}${combinator}node_id=${objectId}&show_current_asset=${show_current_asset}`
|
||||
url = `${this.setting.url}${combinator}node_id=${treeNode.meta.data.id}&show_current_asset=${show_current_asset}`
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
query['asset'] = treeNode.meta.data.id
|
||||
query['node'] = ''
|
||||
url = `${this.setting.url}${combinator}asset_id=${objectId}&show_current_asset=${show_current_asset}`
|
||||
url = `${this.setting.url}${combinator}asset_id=${treeNode.meta.data.id}&show_current_asset=${show_current_asset}`
|
||||
}
|
||||
this.$router.push({ query })
|
||||
this.$emit('urlChange', url)
|
||||
@@ -152,12 +151,11 @@ export default {
|
||||
url,
|
||||
{ 'value': treeNode.name }
|
||||
).then(res => {
|
||||
let assetsAmount = treeNode.meta.data['assetsAmount']
|
||||
let assetsAmount = treeNode.meta.data.assetsAmount
|
||||
if (!assetsAmount) {
|
||||
assetsAmount = 0
|
||||
}
|
||||
treeNode.name = treeNode.name + ' (' + assetsAmount + ')'
|
||||
treeNode.meta.data = res
|
||||
this.zTree.updateNode(treeNode)
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}).finally(() => { this.refreshTree() })
|
||||
@@ -229,7 +227,7 @@ export default {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
}).finally()
|
||||
}).finally(() => this.refreshTree())
|
||||
},
|
||||
createTreeNode: function() {
|
||||
this.hideRMenu()
|
||||
@@ -245,14 +243,13 @@ export default {
|
||||
id: data['key'],
|
||||
name: data['value'],
|
||||
pId: parentNode.id,
|
||||
isParent: true,
|
||||
meta: {
|
||||
data: data,
|
||||
type: 'node'
|
||||
data: data
|
||||
}
|
||||
}
|
||||
newNode.checked = this.zTree.getSelectedNodes()[0].checked
|
||||
this.zTree.addNodes(parentNode, 0, newNode)
|
||||
// vm.$refs.dataztree.refresh()
|
||||
const node = this.zTree.getNodeByParam('id', newNode.id, parentNode)
|
||||
this.currentNodeId = node.meta.data.id || newNode.id
|
||||
this.zTree.editName(node)
|
||||
|
||||
@@ -238,7 +238,7 @@ export default {
|
||||
updateContabValue(name, value, from) {
|
||||
this.contabValueObj[name] = value
|
||||
if (from && from !== name) {
|
||||
// debug(`来自组件 ${from} 改变了 ${name} ${value}`)
|
||||
console.log(`来自组件 ${from} 改变了 ${name} ${value}`)
|
||||
this.changeRadio(name, value)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -53,7 +53,7 @@ export default {
|
||||
}
|
||||
} catch (error) {
|
||||
this.isShow = false
|
||||
// debug(error, 'error')
|
||||
console.log(error, 'error')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ export default {
|
||||
* - el-form 的 resetFields 不会触发 input & change 事件,无法监听
|
||||
* - bug1: https://github.com/FEMessage/el-data-table/issues/176#issuecomment-587280825
|
||||
* - bug2:
|
||||
* 0. 建议先在监听器 watch.value 里 // debug(v.name, oldV.name)
|
||||
* 0. 建议先在监听器 watch.value 里 console.log(v.name, oldV.name)
|
||||
* 1. 打开 basic 示例
|
||||
* 2. 在 label 为 name 的输入框里输入 1,此时 log:'1' ''
|
||||
* 3. 点击 reset 按钮,此时 log 两条数据: '1' '1', '' ''
|
||||
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
},
|
||||
handleClick(button) {
|
||||
const callback = button.callback || function(values, form) {
|
||||
// debug('Click ', button.title, ': ', values)
|
||||
// console.log('Click ', button.title, ': ', values)
|
||||
}
|
||||
const form = this.$refs['form']
|
||||
const values = form.getFormValue()
|
||||
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
defaultCallback: function(action) {
|
||||
// debug(action)
|
||||
// console.log(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Password
|
||||
<password
|
||||
:value="value"
|
||||
v-bind="iAttrs"
|
||||
class="el-input password-input"
|
||||
@@ -32,8 +32,7 @@ export default {
|
||||
const defaultAttrs = {
|
||||
secureLength: 7,
|
||||
defaultClass: 'el-input__inner',
|
||||
toggle: true,
|
||||
showStrengthMeter: false
|
||||
toggle: true
|
||||
}
|
||||
return Object.assign(defaultAttrs, this.attrs)
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
attrs: {
|
||||
showStrengthMeter: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<UserConfirmDialog
|
||||
<MFAVerifyDialog
|
||||
v-if="mfaDialogShow"
|
||||
@UserConfirmDone="showExportDialog"
|
||||
@UserConfirmCancel="handleExportCancel"
|
||||
@MFAVerifyDone="showExportDialog"
|
||||
@MFAVerifyCancel="handleExportCancel"
|
||||
/>
|
||||
<Dialog
|
||||
v-if="exportDialogShow"
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
import UserConfirmDialog from '@/components/UserConfirmDialog'
|
||||
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
import * as queryUtil from '@/components/DataTable/compenents/el-data-table/utils/query'
|
||||
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
name: 'ExportDialog',
|
||||
components: {
|
||||
Dialog,
|
||||
UserConfirmDialog
|
||||
MFAVerifyDialog
|
||||
},
|
||||
props: {
|
||||
selectedRows: {
|
||||
|
||||
@@ -83,7 +83,7 @@ export default {
|
||||
default: () => ''
|
||||
},
|
||||
canImportCreate: {
|
||||
type: [Boolean, Function],
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
canImportUpdate: {
|
||||
@@ -205,9 +205,8 @@ export default {
|
||||
}
|
||||
return this.url.indexOf('?') === -1 ? `${this.url}?${query}` : `${this.url}&${query}`
|
||||
},
|
||||
// eslint-disable-next-line handle-callback-err
|
||||
catchError(error) {
|
||||
// debug(error)
|
||||
console.log(error)
|
||||
},
|
||||
onSuccess(msg) {
|
||||
this.errorMsg = ''
|
||||
|
||||
@@ -78,7 +78,7 @@ export default {
|
||||
default: () => []
|
||||
},
|
||||
canCreate: {
|
||||
type: [Boolean, Function],
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
canBulkUpdate: {
|
||||
|
||||
@@ -171,10 +171,7 @@ export default {
|
||||
float: right;
|
||||
}
|
||||
.mobile .search.right {
|
||||
float: none;
|
||||
}
|
||||
.mobile .search.right .action-search {
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
.mobile .right-side {
|
||||
padding-top: 5px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export function cleanActions(actions, canDefaults, { selectedRows, reloadTable }) {
|
||||
// debug('Start clean actions: ', selectedRows.length, reloadTable)
|
||||
// console.log('Start clean actions: ', selectedRows.length, reloadTable)
|
||||
const cleanedActions = []
|
||||
const cloneActions = _.cloneDeep(actions)
|
||||
cloneActions.forEach((action) => {
|
||||
|
||||
@@ -84,22 +84,15 @@ export default {
|
||||
extraQuery: this.extraQuery
|
||||
})
|
||||
const formatterArgs = {
|
||||
'columnsMeta.actions.formatterArgs.canUpdate': () => {
|
||||
return this.hasActionPerm('change') && !this.currentOrgIsRoot
|
||||
},
|
||||
'columnsMeta.actions.formatterArgs.canUpdate': 'change',
|
||||
'columnsMeta.actions.formatterArgs.canDelete': 'delete',
|
||||
'columnsMeta.actions.formatterArgs.canClone': () => {
|
||||
return this.hasActionPerm('add') && !this.currentOrgIsRoot
|
||||
},
|
||||
'columnsMeta.actions.formatterArgs.canClone': 'add',
|
||||
'columnsMeta.name.formatterArgs.can': 'view'
|
||||
}
|
||||
|
||||
for (const [arg, action] of Object.entries(formatterArgs)) {
|
||||
const notSet = _.get(config, arg) === undefined
|
||||
const isFunction = typeof action === 'function'
|
||||
if (notSet) {
|
||||
const hasActionPerm = isFunction ? action() : this.hasActionPerm(action)
|
||||
_.set(config, arg, hasActionPerm)
|
||||
_.set(config, arg, this.hasActionPerm(action))
|
||||
}
|
||||
}
|
||||
this.$log.debug('Header actions', this.headerActions)
|
||||
|
||||
77
src/components/MFAVerifyDialog/index.vue
Normal file
77
src/components/MFAVerifyDialog/index.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:title="$t('common.MFAVerify')"
|
||||
:width="'50'"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:visible.sync="visible"
|
||||
:destroy-on-close="true"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="4" :sm="24">
|
||||
<div style="line-height: 34px;text-align: center">MFA</div>
|
||||
</el-col>
|
||||
<el-col :md="14" :sm="24">
|
||||
<el-input v-model="MFAToken" />
|
||||
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :md="4" :sm="24">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="verifyMFA">
|
||||
{{ this.$t('common.Confirm') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
|
||||
export default {
|
||||
name: 'MFAVerifyDialog',
|
||||
components: {
|
||||
Dialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
MFAToken: '',
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (!val) {
|
||||
this.$emit('MFAVerifyCancel', true)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$axios.get('/api/v1/authentication/otp/verify/', { disableFlashErrorMsg: true }).then(() => {
|
||||
this.$emit('MFAVerifyDone', true)
|
||||
}).catch(err => {
|
||||
this.$log.debug('Verify otp code error: ', err)
|
||||
this.visible = true
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
verifyMFA() {
|
||||
if (this.MFAToken.length !== 6) {
|
||||
return this.$message.error(this.$tc('common.MFAErrorMsg'))
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/otp/verify/`, {
|
||||
code: this.MFAToken
|
||||
}
|
||||
).then(res => {
|
||||
this.$emit('MFAVerifyDone', true)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -61,6 +61,10 @@ const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
|
||||
done()
|
||||
reload()
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
} catch (error) {
|
||||
if (!error.response || !error.response.data || !error.response.data.msg) {
|
||||
this.$message.error(this.$t('common.deleteErrorMsg') + ' ' + error)
|
||||
}
|
||||
} finally {
|
||||
instance.confirmButtonLoading = false
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export default {
|
||||
}
|
||||
// const locale = this.$i18n.locale
|
||||
// const value = dt.toLocaleString(locale, { hourCycle: 'h23' })
|
||||
// debug(this.$i18n.locale)
|
||||
// console.log(this.$i18n.locale)
|
||||
return {
|
||||
value: value
|
||||
}
|
||||
|
||||
@@ -106,9 +106,35 @@ export default {
|
||||
handler(val) {
|
||||
if (val && val.length > 0) {
|
||||
const routeFilter = this.checkInTableColumns()
|
||||
this.filterTagSearch(routeFilter)
|
||||
const routerSearch = routeFilter.search || {}
|
||||
let routerSearchAttrs = []
|
||||
if (typeof routerSearch?.value === 'string') {
|
||||
routerSearchAttrs = routerSearch?.value?.split(',') || []
|
||||
}
|
||||
|
||||
for (const attr of routerSearchAttrs) {
|
||||
routeFilter[`search_${attr}`] = {
|
||||
...routerSearch,
|
||||
value: attr
|
||||
}
|
||||
}
|
||||
if (routerSearchAttrs.length !== 0) {
|
||||
delete routeFilter.search
|
||||
}
|
||||
|
||||
const asFilterTags = _.cloneDeep(this.filterTags)
|
||||
this.filterTags = {
|
||||
...asFilterTags,
|
||||
...routeFilter
|
||||
}
|
||||
if (Object.keys(routeFilter).length > 0) {
|
||||
setTimeout(() => {
|
||||
return this.$emit('tagSearch', this.filterMaps)
|
||||
}, 490)
|
||||
}
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
@@ -123,90 +149,43 @@ export default {
|
||||
methods: {
|
||||
// 获取url中的查询条件,判断是不是包含在当前查询条件里
|
||||
checkInTableColumns() {
|
||||
const searchFieldOptions = {}
|
||||
const queryInfoValues = this.options.map((i) => i.value)
|
||||
const routeQuery = this.getUrlQuery ? this.$route?.query : {}
|
||||
const routeQueryKeysLength = Object.keys(routeQuery).length
|
||||
if (routeQueryKeysLength < 1) return searchFieldOptions
|
||||
|
||||
for (const [key, value] of Object.entries(routeQuery)) {
|
||||
const valueDecode = decodeURI(value)
|
||||
const isSearch = key === 'search'
|
||||
|
||||
if (isSearch) {
|
||||
searchFieldOptions[key] = {
|
||||
key,
|
||||
label: '',
|
||||
value: valueDecode
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (queryInfoValues.includes(key)) {
|
||||
searchFieldOptions[key] = this.getInQueryInfoFields(key, value)
|
||||
}
|
||||
const routeQueryKeys = Object.keys(routeQuery)
|
||||
const routeQueryKeysLength = routeQueryKeys.length
|
||||
const keys = {}
|
||||
if (routeQueryKeysLength < 1) {
|
||||
return keys
|
||||
}
|
||||
return searchFieldOptions
|
||||
},
|
||||
getInQueryInfoFields(key, value) {
|
||||
let searchFieldOption = {}
|
||||
let valueDecode = decodeURI(value)
|
||||
const currentOptions = this.options || []
|
||||
for (const [key, value] of Object.entries(routeQuery)) {
|
||||
let valueDecode = decodeURI(value)
|
||||
const isSearch = key !== 'search'
|
||||
const curOptions = this.options || []
|
||||
|
||||
for (let k = 0, len = currentOptions.length; k < len; k++) {
|
||||
const current = currentOptions[k]
|
||||
if (key === current.value) {
|
||||
const curChildren = current.children || []
|
||||
if (current?.type === 'boolean') {
|
||||
for (let k = 0, len = curOptions.length; k < len; k++) {
|
||||
const cur = curOptions[k]
|
||||
if (cur?.type === 'boolean') {
|
||||
valueDecode = !!valueDecode
|
||||
}
|
||||
searchFieldOption = {
|
||||
...current,
|
||||
key,
|
||||
label: current.label,
|
||||
value: valueDecode
|
||||
}
|
||||
if (curChildren.length > 0) {
|
||||
for (const item of curChildren) {
|
||||
if (valueDecode === item.value) {
|
||||
searchFieldOption.valueLabel = item.label
|
||||
break
|
||||
if (key === cur.value || !isSearch) {
|
||||
const curChildren = cur.children || []
|
||||
keys[key] = {
|
||||
...cur,
|
||||
key,
|
||||
label: isSearch ? cur.label : '',
|
||||
value: valueDecode
|
||||
}
|
||||
if (isSearch && curChildren.length > 0) {
|
||||
for (const item of curChildren) {
|
||||
if (valueDecode === item.value) {
|
||||
keys[key].valueLabel = item.label
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return searchFieldOption
|
||||
},
|
||||
filterTagSearch(routeFilter) {
|
||||
const routerSearch = routeFilter.search || {}
|
||||
let routerSearchAttrs = []
|
||||
if (typeof routerSearch?.value === 'string') {
|
||||
routerSearchAttrs = routerSearch?.value?.split(',') || []
|
||||
}
|
||||
|
||||
for (const attr of routerSearchAttrs) {
|
||||
routeFilter[`search_${attr}`] = {
|
||||
...routerSearch,
|
||||
value: attr
|
||||
}
|
||||
}
|
||||
|
||||
if (routerSearchAttrs.length !== 0) {
|
||||
delete routeFilter.search
|
||||
}
|
||||
const asFilterTags = _.cloneDeep(this.filterTags)
|
||||
this.filterTags = {
|
||||
...asFilterTags,
|
||||
...routeFilter
|
||||
}
|
||||
if (Object.keys(routeFilter).length > 0) {
|
||||
setTimeout(() => {
|
||||
return this.$emit('tagSearch', this.filterMaps)
|
||||
}, 490)
|
||||
}
|
||||
return keys
|
||||
},
|
||||
getValueLabel(key, value) {
|
||||
for (const field of this.options) {
|
||||
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// debug(this.treeSetting)
|
||||
// console.log(this.treeSetting)
|
||||
},
|
||||
methods: {
|
||||
handleUrlChange(url) {
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:title="$t('common.CurrentUserVerify')"
|
||||
:width="'50'"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:visible.sync="visible"
|
||||
:destroy-on-close="true"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="4" :sm="24">
|
||||
<div style="line-height: 34px;text-align: center">{{ Label }}</div>
|
||||
</el-col>
|
||||
<el-col :md="14" :sm="24">
|
||||
<el-input v-model="SecretKey" :show-password="showPassword" />
|
||||
<span class="help-tips help-block">{{ HelpText }}</span>
|
||||
</el-col>
|
||||
<el-col :md="4" :sm="24">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="userConfirm">
|
||||
{{ this.$t('common.Confirm') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script>
|
||||
import Dialog from '@/components/Dialog'
|
||||
|
||||
export default {
|
||||
name: 'UserConfirmDialog',
|
||||
components: {
|
||||
Dialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Label: '',
|
||||
HelpText: '',
|
||||
ConfirmType: '',
|
||||
SecretKey: '',
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
showPassword() {
|
||||
if (this.ConfirmType === 'password') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (!val) {
|
||||
this.$emit('UserConfirmCancel', true)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$axios.get('/api/v1/authentication/confirm/', { disableFlashErrorMsg: true }).then(() => {
|
||||
this.$emit('UserConfirmDone', true)
|
||||
}).catch(err => {
|
||||
this.$log.debug('Verify otp code error: ', err)
|
||||
const backends = err.response.data.backends
|
||||
backends.sort((a, b) => b.level - a.level)
|
||||
this.ConfirmType = backends[0].name
|
||||
if (this.ConfirmType === 'relogin') {
|
||||
this.visible = false
|
||||
return this.$message.error(this.$t('auth.ReLoginErr'))
|
||||
}
|
||||
|
||||
if (this.ConfirmType === 'mfa') {
|
||||
this.Label = 'MFA'
|
||||
this.HelpText = this.$t('common.MFARequireForSecurity')
|
||||
this.visible = true
|
||||
} else if (this.ConfirmType === 'password') {
|
||||
this.Label = this.$t('setting.password')
|
||||
this.HelpText = this.$t('common.PasswordRequireForSecurity')
|
||||
this.visible = true
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
userConfirm() {
|
||||
if (this.ConfirmType === 'mfa' && this.SecretKey.length !== 6) {
|
||||
return this.$message.error(this.$tc('common.MFAErrorMsg'))
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/confirm/`, {
|
||||
confirm_type: this.ConfirmType,
|
||||
secret_key: this.SecretKey
|
||||
}
|
||||
).then(res => {
|
||||
this.$emit('UserConfirmDone', true)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -25,6 +25,6 @@ export { default as UploadField } from './FormFields/UploadField'
|
||||
export { default as AccountListTable } from './AccountListTable/index'
|
||||
export { default as AppAccountListTable } from './AppAccountListTable'
|
||||
export { default as AssetRelationCard } from './AssetRelationCard'
|
||||
export { default as UserConfirmDialog } from './UserConfirmDialog'
|
||||
export { default as MFAVerifyDialog } from './MFAVerifyDialog'
|
||||
export { default as Announcement } from './Announcement'
|
||||
export { default as CronTab } from './CronTab'
|
||||
|
||||
@@ -18,7 +18,7 @@ router.beforeEach(async(to, from, next) => {
|
||||
next()
|
||||
} catch (e) {
|
||||
const msg = 'Start service error: ' + e
|
||||
// debug(e)
|
||||
console.log(e)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -246,12 +246,9 @@
|
||||
},
|
||||
"auth": {
|
||||
"LoginRequiredMsg": "You account has logout, Please login again",
|
||||
"ReLogin": "Re-Login",
|
||||
"ReLoginErr": "Login time has exceeded 5 minutes, please login again"
|
||||
"ReLogin": "Re-Login"
|
||||
},
|
||||
"common": {
|
||||
"ChangeViewHelpText": "Click to change view",
|
||||
"Component": "component",
|
||||
"PrivateCloud": "Private cloud",
|
||||
"PublicCloud": "Public cloud",
|
||||
"Correlation": "Correlation",
|
||||
@@ -270,7 +267,6 @@
|
||||
"Database": "Database",
|
||||
"Params": "Params",
|
||||
"MFAVerify": "Verify MFA",
|
||||
"CurrentUserVerify": "Verify Current User",
|
||||
"ViewSecret": "View secret",
|
||||
"ConnectWebSocketError": "Connect Websocket failed",
|
||||
"Nothing": "Nothing",
|
||||
@@ -417,7 +413,7 @@
|
||||
"downloadUpdateTemplateMsg": "Download update template",
|
||||
"onlyCSVFilesTips": "Only csv supported",
|
||||
"updateSuccessMsg": "Update success, total: {count}",
|
||||
"dragUploadFileInfo": "Drag file here or click here to upload",
|
||||
"dragUploadFileInfo": "Drag file here or click to upload",
|
||||
"uploadCsvLth10MHelpText": "csv/xlsx files with a size less than 10M",
|
||||
"hasImportErrorItemMsg": "There is an error item, click the x icon to view the details, and continue to import after editing"
|
||||
},
|
||||
@@ -437,7 +433,6 @@
|
||||
"Logout": "Logout",
|
||||
"Profile": "Profile",
|
||||
"Support": "Support",
|
||||
"Download": "Download",
|
||||
"UserPage": "User page",
|
||||
"View": "View",
|
||||
"EnterpriseEdition": "Enterprise edition"
|
||||
@@ -696,7 +691,7 @@
|
||||
"AssetPermissionUpdate": "Asset permissions update",
|
||||
"AssetUpdate": "Asset update",
|
||||
"Assets": "Assets",
|
||||
"LogsAudit": "Logs audit",
|
||||
"LogsAudits": "Logs audit",
|
||||
"SessionsAudit": "Sessions audit",
|
||||
"SessionList": "Session list",
|
||||
"BatchCommand": "Batch Command",
|
||||
@@ -893,12 +888,12 @@
|
||||
"UseProtocol": "Use protocol",
|
||||
"SessionState": "Session state",
|
||||
"Monitor": "Monitor",
|
||||
"RazorNotSupport": "RDP Client session not support now",
|
||||
"XRDPNotSupport": "RDP Client session not support now",
|
||||
"sessionMonitor": "Session Monitor",
|
||||
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later",
|
||||
"helpText": {
|
||||
"esUrl": "Tip: If you have multiple hosts, use comma (, ) to split (eg: http://www.jumpserver.a.com, http://www.jumpserver.b.com)",
|
||||
"esIndex":"Es provides the default index: jumpserver. If you choose to build an index by date, this blank is the index prefix",
|
||||
"esIndex":"Es provides the default index: jumpserver",
|
||||
"esDocType": "Es provides the default document type: command"
|
||||
}
|
||||
},
|
||||
@@ -1075,7 +1070,6 @@
|
||||
"refreshLdapCache":"Refreshing Ldap cache ",
|
||||
"LicenseExpired": "License expired",
|
||||
"LicenseWillBe": "License will expire at ",
|
||||
"LicenseReachedAssetAmountLimit": "The number of assets has exceeded the license limit",
|
||||
"Expire": "Expire",
|
||||
"WeCom": "WeCom",
|
||||
"DingTalk": "DingTalk",
|
||||
@@ -1383,7 +1377,6 @@
|
||||
"HuaweiPrivatecloud": "Huawei Private Cloud",
|
||||
"OpenStack": "OpenStack",
|
||||
"GCP": "Google Cloud Platform",
|
||||
"FC": "Fusion Compute",
|
||||
"AWS_China": "AWS(China)",
|
||||
"AWS_Int": "AWS(International)",
|
||||
"HuaweiCloud": "Huawei Cloud",
|
||||
|
||||
@@ -251,12 +251,9 @@
|
||||
},
|
||||
"auth": {
|
||||
"LoginRequiredMsg": "アカウントが終了しました。ログインし直してください",
|
||||
"ReLogin": "再ログイン",
|
||||
"ReLoginErr": "ログイン時間が 5 分を超えました。もう一度ログインしてください"
|
||||
"ReLogin": "再ログイン"
|
||||
},
|
||||
"common": {
|
||||
"ChangeViewHelpText": "クリックしてさまざまなビューにアクセス",
|
||||
"Component": "コンポーネント",
|
||||
"PrivateCloud": "プライベートクラウド",
|
||||
"PublicCloud": "パブリッククラウド",
|
||||
"Correlation": "関連",
|
||||
@@ -278,7 +275,6 @@
|
||||
"DateUpdated": "更新日",
|
||||
"ApprovaLevel": "承認情報",
|
||||
"MFAVerify": "MFAの検証",
|
||||
"CurrentUserVerify": "現在のユーザー検証",
|
||||
"ViewSecret": "パスワードの確認",
|
||||
"ConnectWebSocketError": "Webソケット接続に失敗しました",
|
||||
"Action": "アクション",
|
||||
@@ -429,7 +425,7 @@
|
||||
"onlyCSVFilesTips": "Csvファイルのインポートのみサポート",
|
||||
"updateSuccessMsg": "更新のインポートに成功しました。合計:{count}",
|
||||
"uploadCsvLth10MHelpText": "Csv/xlsxのみアップロードでき、10m以下です",
|
||||
"dragUploadFileInfo": "ここにファイルをドラッグするか、ここをクリックしてアップロードしてください",
|
||||
"dragUploadFileInfo": "ファイルをここにドラッグするか、アップロードをクリックします",
|
||||
"hasImportErrorItemMsg": "インポート失敗項目があります。左側のxをクリックして失敗原因を確認し、表をクリックして編集した後、失敗項目のインポートを続けることができます"
|
||||
},
|
||||
"fileType": "ファイルタイプ",
|
||||
@@ -449,7 +445,6 @@
|
||||
"Logout": "ログインを終了する",
|
||||
"Profile": "個人情報",
|
||||
"Support": "サポート",
|
||||
"Download": "ダウンロード",
|
||||
"UserPage": "ユーザービュー",
|
||||
"View": "ビュー",
|
||||
"EnterpriseEdition": "企業版"
|
||||
@@ -914,12 +909,12 @@
|
||||
"UseProtocol": "使用契約",
|
||||
"SessionState": "セッションステータス",
|
||||
"Monitor": "モニタリング",
|
||||
"RazorNotSupport": "RDPクライアントセッションは、監視をサポートしていません",
|
||||
"XRDPNotSupport": "RDPクライアントセッションは、監視をサポートしていません",
|
||||
"sessionMonitor": "モニタリング",
|
||||
"TerminateTaskSendSuccessMsg": "最終タスクが発行されました。後で更新して確認してください。",
|
||||
"helpText": {
|
||||
"esUrl": "ヒント: 複数のホストがある場合は、カンマ ( , ) で分割します。 (Eg: http://www.jumpserver.a.com:3000、http://www.jumpserver.b.com:3000)",
|
||||
"esIndex": "Esはデフォルトindexを提供します。日付による索引の作成を選択した場合、この空は索引接頭辞です。",
|
||||
"esIndex": "Esはデフォルトindexを提供します。",
|
||||
"esDocType": "Esデフォルトのドキュメントタイプ: command"
|
||||
}
|
||||
},
|
||||
@@ -1103,7 +1098,6 @@
|
||||
"refreshLdapCache": "Ldapキャッシュを更新します。後でお願いします。",
|
||||
"LicenseExpired": "ライセンスが期限切れです",
|
||||
"LicenseWillBe": "ライセンスはまもなく",
|
||||
"LicenseReachedAssetAmountLimit": "アセットの数がライセンス制限を超えました",
|
||||
"Expire": "期限切れ",
|
||||
"WeCom": "企業wechat",
|
||||
"DingTalk": "ホッチキス",
|
||||
@@ -1426,7 +1420,6 @@
|
||||
"HuaweiPrivatecloud": "ファーウェイプライベートクラウド",
|
||||
"OpenStack": "OpenStack",
|
||||
"GCP": "Googleクラウド",
|
||||
"FC": "Fusion Compute",
|
||||
"AWS_China": "AWS(中国)",
|
||||
"AWS_Int": "AWS (国際)",
|
||||
"HuaweiCloud": "ファーウェイ雲",
|
||||
|
||||
@@ -251,11 +251,9 @@
|
||||
},
|
||||
"auth": {
|
||||
"LoginRequiredMsg": "账号已退出,请重新登录",
|
||||
"ReLogin": "重新登录",
|
||||
"ReLoginErr": "登录时长已超过 5 分钟,请重新登录"
|
||||
"ReLogin": "重新登录"
|
||||
},
|
||||
"common": {
|
||||
"ChangeViewHelpText": "点击切换不同视图",
|
||||
"Component": "组件",
|
||||
"PrivateCloud": "私有云",
|
||||
"PublicCloud": "公有云",
|
||||
@@ -278,7 +276,6 @@
|
||||
"DateUpdated": "更新日期",
|
||||
"ApprovaLevel": "审批信息",
|
||||
"MFAVerify": "验证 MFA",
|
||||
"CurrentUserVerify": "验证当前用户",
|
||||
"ViewSecret": "查看密码",
|
||||
"ConnectWebSocketError": "连接 WebSocket 失败",
|
||||
"Action": "动作",
|
||||
@@ -429,7 +426,7 @@
|
||||
"onlyCSVFilesTips": "仅支持csv文件导入",
|
||||
"updateSuccessMsg": "导入更新成功,总共:{count}",
|
||||
"uploadCsvLth10MHelpText": "只能上传 csv/xlsx, 且不超过 10M",
|
||||
"dragUploadFileInfo": "将文件拖到此处,或点击此处上传",
|
||||
"dragUploadFileInfo": "将文件拖到此处,或点击上传",
|
||||
"hasImportErrorItemMsg": "存在导入失败项,点击左侧 x 查看失败原因,点击表格编辑后,可以继续导入失败项"
|
||||
},
|
||||
"fileType": "文件类型",
|
||||
@@ -449,7 +446,6 @@
|
||||
"Logout": "退出登录",
|
||||
"Profile": "个人信息",
|
||||
"Support": "支持",
|
||||
"Download": "下载",
|
||||
"UserPage": "用户视图",
|
||||
"View": "视图",
|
||||
"EnterpriseEdition": "企业版"
|
||||
@@ -914,13 +910,13 @@
|
||||
"UseProtocol": "使用协议",
|
||||
"SessionState": "会话状态",
|
||||
"Monitor": "监控",
|
||||
"RazorNotSupport": "RDP 客户端会话, 暂不支持监控",
|
||||
"XRDPNotSupport": "RDP 客户端会话, 暂不支持监控",
|
||||
"sessionMonitor": "监控",
|
||||
"TerminateTaskSendSuccessMsg": "终断任务已下发,请稍后刷新查看",
|
||||
"helpText": {
|
||||
"esUrl": "提示:如果有多台主机,请使用逗号 ( , ) 进行分割。(eg: http://www.jumpserver.a.com:3000,http://www.jumpserver.b.com:3000)",
|
||||
"esIndex": "es 提供默认 index:jumpserver。如果开启按日期建立索引,那么输入的值会作为索引前缀",
|
||||
"esDocType": "es 默认文档类型:command"
|
||||
"esIndex": "es提供默认index:jumpserver",
|
||||
"esDocType": "es默认文档类型:command"
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
@@ -1103,7 +1099,6 @@
|
||||
"refreshLdapCache":"刷新Ldap缓存,请稍后",
|
||||
"LicenseExpired": "许可证已经过期",
|
||||
"LicenseWillBe": "许可证即将在 ",
|
||||
"LicenseReachedAssetAmountLimit": "资产数量已经超过许可证数量限制",
|
||||
"Expire": " 过期",
|
||||
"WeCom": "企业微信",
|
||||
"DingTalk": "钉钉",
|
||||
@@ -1426,7 +1421,6 @@
|
||||
"HuaweiPrivatecloud": "华为私有云",
|
||||
"OpenStack": "OpenStack",
|
||||
"GCP": "谷歌云",
|
||||
"FC": "Fusion Compute",
|
||||
"AWS_China": "AWS(中国)",
|
||||
"AWS_Int": "AWS(国际)",
|
||||
"HuaweiCloud": "华为云",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div class="footer" :class="device" :style="style">
|
||||
<div class="pull-right version">
|
||||
<div class="footer" :style="style">
|
||||
<div class="pull-right">
|
||||
Version <strong> dev </strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
|
||||
</div>
|
||||
<div>{{ corporation }}</div>
|
||||
<div style="padding-left:20px;">
|
||||
{{ publicSettings.XPACK_LICENSE_INFO.corporation }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -25,10 +27,7 @@ export default {
|
||||
if (this.device === 'mobile') {
|
||||
return ''
|
||||
}
|
||||
return this.sidebar.opened ? ('margin-left: 220px;') : ('margin-left: 54px')
|
||||
},
|
||||
corporation() {
|
||||
return this.publicSettings.XPACK_LICENSE_INFO.corporation
|
||||
return this.sidebar.opened ? ('margin-left: 210px;') : ('margin-left: 54px')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,9 +38,9 @@ export default {
|
||||
height: 35px !important;
|
||||
}
|
||||
.pull-right {
|
||||
float: right
|
||||
float: right!important;
|
||||
}
|
||||
.footer {
|
||||
.footer{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -56,11 +55,4 @@ export default {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.mobile.footer {
|
||||
text-align: center;
|
||||
}
|
||||
.mobile.footer .pull-right{
|
||||
float: none;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
<script>
|
||||
import AutoDataForm from '@/components/AutoDataForm'
|
||||
import { getUpdateObjURL } from '@/utils/common'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
|
||||
export default {
|
||||
name: 'GenericCreateUpdateForm',
|
||||
components: {
|
||||
@@ -138,16 +136,6 @@ export default {
|
||||
if (params.id) {
|
||||
url = getUpdateObjURL(url, params.id)
|
||||
}
|
||||
|
||||
const clone_from = this.$route.query['clone_from']
|
||||
const query = clone_from ? `clone_from=${clone_from}` : ''
|
||||
if (query) {
|
||||
if (url.indexOf('?') === -1) {
|
||||
url = `${url}?${query}`
|
||||
} else {
|
||||
url = `${url}&${query}`
|
||||
}
|
||||
}
|
||||
return url
|
||||
}
|
||||
},
|
||||
@@ -230,10 +218,6 @@ export default {
|
||||
hasDetailInMsg: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
encryptedFields: {
|
||||
type: Array,
|
||||
default: () => ['password', 'token', 'private_key']
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -281,27 +265,10 @@ export default {
|
||||
isUpdateMethod() {
|
||||
return ['put', 'patch'].indexOf(this.method.toLowerCase()) > -1
|
||||
},
|
||||
encryptFields(values) {
|
||||
// 批量提交,clean 后可能是个数组
|
||||
if (values instanceof Array) {
|
||||
return values.map((item) => this.encryptFields(item))
|
||||
}
|
||||
values = { ...values }
|
||||
for (const field of this.encryptedFields) {
|
||||
let value = values[field]
|
||||
if (!value || typeof value !== 'string') {
|
||||
continue
|
||||
}
|
||||
value = encryptPassword(value)
|
||||
values[field] = value
|
||||
}
|
||||
return values
|
||||
},
|
||||
handleSubmit(values, formName, addContinue) {
|
||||
let handler = this.onSubmit || this.defaultOnSubmit
|
||||
handler = handler.bind(this)
|
||||
values = this.cleanFormValue(values)
|
||||
values = this.encryptFields(values)
|
||||
return handler(values, formName, addContinue)
|
||||
},
|
||||
defaultOnSubmit(validValues, formName, addContinue) {
|
||||
|
||||
@@ -98,11 +98,11 @@ export default {
|
||||
const vm = this
|
||||
return {
|
||||
submitMethod: () => 'patch',
|
||||
cleanFormValue: (value) => {
|
||||
cleanFormValue: function(value) {
|
||||
const filterValue = {}
|
||||
Object.keys(value)
|
||||
.filter((key) => vm.checkedFields?.includes(key))
|
||||
.forEach((key) => { filterValue[key] = value[key] })
|
||||
Object.keys(value).filter((key) => vm.checkedFields?.includes(key)).forEach((key) => {
|
||||
filterValue[key] = value[key]
|
||||
})
|
||||
const formValue = []
|
||||
let object = {}
|
||||
for (const row of vm.selectedRows) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="docs">{{ $t('common.nav.Docs') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="support">{{ $t('common.nav.Support') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="toolsDownload">{{ $t('common.nav.Download') }}</el-dropdown-item>
|
||||
<el-dropdown-item v-if="!hasLicence" command="enterprise">{{ $t('common.nav.EnterpriseEdition') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
@@ -44,9 +43,6 @@ export default {
|
||||
case 'enterprise':
|
||||
window.open('https://jumpserver.org/enterprise.html', '_blank')
|
||||
break
|
||||
case 'toolsDownload':
|
||||
window.open('/core/download/', '_blank')
|
||||
break
|
||||
default:
|
||||
window.open(this.URLSite.HELP_DOCUMENT_URL, '_blank')
|
||||
break
|
||||
|
||||
@@ -1,40 +1,31 @@
|
||||
<template>
|
||||
<el-tooltip
|
||||
v-model="iShowTip"
|
||||
:manual="true"
|
||||
:content="tipText"
|
||||
class="item"
|
||||
effect="dark"
|
||||
placement="bottom-start"
|
||||
<el-menu
|
||||
:default-active="currentViewRoute.name"
|
||||
class="menu-main"
|
||||
:class="mode"
|
||||
:mode="mode"
|
||||
@select="handleSelectView"
|
||||
>
|
||||
<el-menu
|
||||
:default-active="currentViewRoute.name"
|
||||
class="menu-main"
|
||||
:class="mode"
|
||||
:mode="mode"
|
||||
@select="handleSelectView"
|
||||
<el-submenu
|
||||
index="2"
|
||||
popper-class="view-switcher"
|
||||
>
|
||||
<el-submenu
|
||||
index="2"
|
||||
popper-class="view-switcher"
|
||||
<template slot="title">
|
||||
<span class="title-label">
|
||||
<i class="fa fa-bars" />
|
||||
<span>{{ $t('common.nav.View') }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="view of views"
|
||||
:key="view.name"
|
||||
:index="view.name"
|
||||
>
|
||||
<template slot="title">
|
||||
<span class="title-label">
|
||||
<i class="fa fa-bars" />
|
||||
<span>{{ $t('common.nav.View') }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="view of views"
|
||||
:key="view.name"
|
||||
:index="view.name"
|
||||
>
|
||||
<i v-if="mode === 'horizontal'" class="icons" :class="view.meta.icon" />
|
||||
<span slot="title" class="icons-title">{{ view.meta.title }}</span>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</el-tooltip>
|
||||
<i v-if="mode === 'horizontal'" class="icons" :class="view.meta.icon" />
|
||||
<span slot="title" class="icons-title">{{ view.meta.title }}</span>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -55,7 +46,6 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tipText: this.$t('common.ChangeViewHelpText'),
|
||||
showTip: true
|
||||
}
|
||||
},
|
||||
@@ -82,36 +72,6 @@ export default {
|
||||
},
|
||||
currentView() {
|
||||
return this.viewsMapper[this.currentViewRoute.name]
|
||||
},
|
||||
tipHasRead: {
|
||||
set(val) {
|
||||
localStorage.setItem('viewSwitcherTip', val)
|
||||
},
|
||||
get() {
|
||||
return localStorage.getItem('viewSwitcherTip')
|
||||
}
|
||||
},
|
||||
iShowTip: {
|
||||
get() {
|
||||
if (this.mode !== 'horizontal') {
|
||||
return false
|
||||
}
|
||||
if (this.views.length < 2) {
|
||||
return false
|
||||
}
|
||||
if (this.tipHasRead) {
|
||||
return false
|
||||
}
|
||||
return this.showTip
|
||||
},
|
||||
set(val) {
|
||||
this.showTip = val
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile/i.test(navigator.userAgent)) {
|
||||
this.showTip = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -120,10 +80,6 @@ export default {
|
||||
localStorage.setItem('PreView', key)
|
||||
// Next 之前要重置 init 状态,否则这些路由守卫就不走了
|
||||
await store.dispatch('app/reset')
|
||||
if (!this.tipHasRead) {
|
||||
this.tipHasRead = '1'
|
||||
this.iShowTip = false
|
||||
}
|
||||
this.$router.push(routeName)
|
||||
}
|
||||
}
|
||||
@@ -153,6 +109,7 @@ export default {
|
||||
padding: 10px 10px;
|
||||
text-align: center;
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
&:hover {
|
||||
color: inherit;
|
||||
i {
|
||||
@@ -160,10 +117,10 @@ export default {
|
||||
}
|
||||
}
|
||||
&:first-child {
|
||||
margin-left: 16px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: 16px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
.el-submenu.is-opened {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<SystemSetting />
|
||||
</el-tooltip>
|
||||
</li>
|
||||
<li v-if="ticketsEnabled" class="header-item header-hover">
|
||||
<li v-if="this.$hasLicense() && this.$hasPerm('tickets.view_ticket')" class="header-item header-hover">
|
||||
<Tickets />
|
||||
</li>
|
||||
<li class="header-item active-menu">
|
||||
@@ -69,12 +69,7 @@ export default {
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar', 'publicSettings', 'currentOrgRoles', 'currentViewRoute'
|
||||
]),
|
||||
ticketsEnabled() {
|
||||
return this.publicSettings['TICKETS_ENABLED'] &&
|
||||
this.$hasLicense() &&
|
||||
this.$hasPerm('tickets.view_ticket')
|
||||
}
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
<div class="active-mobile">
|
||||
<ViewSwitcher mode="vertical" class="mobile-view-switch" />
|
||||
<Organization v-if="$hasLicense()" class="organization" />
|
||||
<Organization class="organization" />
|
||||
</div>
|
||||
<div class="nav-title" :class="{'collapsed': isCollapse}">
|
||||
{{ isTitle }}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<template>
|
||||
<div v-if="!loading">
|
||||
<el-alert v-if="licenseMsg" type="error">
|
||||
{{ licenseMsg }} !
|
||||
<router-link :to="{ name: 'License' }" style="padding-left: 5px">
|
||||
{{ $t('common.View') }} <i class="fa fa-external-link" />
|
||||
</router-link>
|
||||
<el-alert v-if="isExpire" type="error">
|
||||
{{ isExpire }}
|
||||
</el-alert>
|
||||
</div>
|
||||
</template>
|
||||
@@ -14,7 +11,7 @@ import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'LicenseRelatedTip',
|
||||
name: 'LicenseExpireTip',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
@@ -26,15 +23,8 @@ export default {
|
||||
'publicSettings',
|
||||
'currentUser'
|
||||
]),
|
||||
licenseMsg() {
|
||||
if (this.isExpire) {
|
||||
return this.isExpire
|
||||
} else {
|
||||
return this.reachedAssetAmountLimit
|
||||
}
|
||||
},
|
||||
isExpire() {
|
||||
if (!this.publicSettings.XPACK_ENABLED || !this.$hasPerm('settings.change_license')) {
|
||||
if (!this.publicSettings.XPACK_ENABLED || this.currentUser.role !== 'Admin') {
|
||||
return false
|
||||
}
|
||||
const intervalDays = this.getIntervalDays(this.licenseData.date_expired)
|
||||
@@ -45,19 +35,10 @@ export default {
|
||||
return this.$t('setting.LicenseWillBe') + this.licenseData.date_expired + this.$t('setting.Expire')
|
||||
}
|
||||
return false
|
||||
},
|
||||
reachedAssetAmountLimit() {
|
||||
if (!this.publicSettings.XPACK_ENABLED || !this.$hasPerm('settings.change_license')) {
|
||||
return false
|
||||
}
|
||||
if (this.licenseData['current_asset_count'] > this.licenseData.asset_count) {
|
||||
return this.$t('setting.LicenseReachedAssetAmountLimit')
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.publicSettings.XPACK_ENABLED && this.$hasPerm('settings.change_license')) {
|
||||
if (this.publicSettings.XPACK_ENABLED && this.currentUser.role === 'Admin') {
|
||||
this.$axios.get('/api/v1/xpack/license/detail').then(res => {
|
||||
this.licenseData = res
|
||||
}).finally(() => {
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot name="globalNotification">
|
||||
<LicenseRelatedTip />
|
||||
<LicenseExpireTip />
|
||||
<PasswordExpireTip />
|
||||
</slot>
|
||||
<div class="page-heading">
|
||||
@@ -21,12 +21,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LicenseRelatedTip from '@/layout/components/Page/LicenseRelatedTip'
|
||||
import LicenseExpireTip from '@/layout/components/Page/LicenseExpireTip'
|
||||
import PasswordExpireTip from '@/layout/components/Page/PasswordExpireTip'
|
||||
export default {
|
||||
name: 'PageHeading',
|
||||
components: {
|
||||
LicenseRelatedTip,
|
||||
LicenseExpireTip,
|
||||
PasswordExpireTip
|
||||
},
|
||||
props: {
|
||||
|
||||
@@ -126,7 +126,7 @@ function cleanRoute(tmp, parent) {
|
||||
} else {
|
||||
tmp.meta.fullPath = parentFullPath ? parentFullPath + '/' + tmp.path : parentFullPath
|
||||
}
|
||||
// debug('Full path: ', tmp.meta.fullPath)
|
||||
// console.log('Full path: ', tmp.meta.fullPath)
|
||||
}
|
||||
// 设置默认active menu
|
||||
if (tmp.meta.type === 'crud' && !tmp.meta.activeMenu) {
|
||||
|
||||
@@ -32,25 +32,24 @@ const actions = {
|
||||
commit('CHANGE_SETTING', data)
|
||||
},
|
||||
// get user Profile
|
||||
getPublicSettings({ commit, state }, isOpen) {
|
||||
getPublicSettings({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getPublicSettings(isOpen).then(response => {
|
||||
const data = response || {}
|
||||
if (isOpen) {
|
||||
const faviconURL = data['LOGO_URLS']?.favicon
|
||||
let link = document.querySelector("link[rel*='icon']")
|
||||
if (!link) {
|
||||
link = document.createElement('link')
|
||||
link.type = 'image/x-icon'
|
||||
link.rel = 'shortcut icon'
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
}
|
||||
if (faviconURL) {
|
||||
link.href = faviconURL
|
||||
}
|
||||
// 动态修改Title
|
||||
document.title = data['LOGIN_TITLE']
|
||||
getPublicSettings().then(response => {
|
||||
const data = response.data || {}
|
||||
const faviconURL = data['LOGO_URLS']?.favicon
|
||||
let link = document.querySelector("link[rel*='icon']")
|
||||
if (!link) {
|
||||
link = document.createElement('link')
|
||||
link.type = 'image/x-icon'
|
||||
link.rel = 'shortcut icon'
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
}
|
||||
if (faviconURL) {
|
||||
link.href = faviconURL
|
||||
}
|
||||
|
||||
// 动态修改Title
|
||||
document.title = data['LOGIN_TITLE']
|
||||
commit('SET_PUBLIC_SETTINGS', data)
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
|
||||
@@ -82,7 +82,7 @@ const actions = {
|
||||
commit('SET_PROFILE', response)
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
// debug(error)
|
||||
// console.log(error)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* fade */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s;
|
||||
transition: opacity 0.28s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
@@ -14,7 +14,7 @@
|
||||
/* fade-transform */
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all .2s;
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
@@ -30,7 +30,7 @@
|
||||
/* breadcrumb transition */
|
||||
.breadcrumb-enter-active,
|
||||
.breadcrumb-leave-active {
|
||||
transition: all .25s;
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-enter,
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
.breadcrumb-move {
|
||||
transition: all .25s;
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import VueCookie from 'vue-cookie'
|
||||
|
||||
const TOKEN_KEY = 'csrftoken'
|
||||
const CURRENT_ORG_KEY = 'jms_current_org'
|
||||
const CURRENT_ROLE_KEY = 'jms_current_role'
|
||||
let cookieNamePrefix = VueCookie.get('SESSION_COOKIE_NAME_PREFIX')
|
||||
if (!cookieNamePrefix || ['""', "''"].indexOf(cookieNamePrefix) > -1) {
|
||||
cookieNamePrefix = ''
|
||||
}
|
||||
const TOKEN_KEY = `${cookieNamePrefix}csrftoken`
|
||||
|
||||
export function getTokenFromCookie() {
|
||||
return VueCookie.get(TOKEN_KEY)
|
||||
}
|
||||
|
||||
export function setTokenToCookie(value, expires) {
|
||||
return VueCookie.set(TOKEN_KEY, value, { expires: expires })
|
||||
let cookieNamePrefix = VueCookie.get('SESSION_COOKIE_NAME_PREFIX')
|
||||
if (!cookieNamePrefix || ['""', "''"].indexOf(cookieNamePrefix) > -1) {
|
||||
cookieNamePrefix = ''
|
||||
}
|
||||
return VueCookie.get(cookieNamePrefix + TOKEN_KEY)
|
||||
}
|
||||
|
||||
export function getCurrentRoleLocal(username) {
|
||||
|
||||
@@ -160,8 +160,6 @@ export function hasUUID(s) {
|
||||
}
|
||||
|
||||
export function replaceUUID(s, n) {
|
||||
const index = s.search(uuidPattern)
|
||||
if (index > 0) return s.substr(0, index)
|
||||
return s.replace(uuidPattern, n)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { JSEncrypt } from 'jsencrypt'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import VueCookie from 'vue-cookie'
|
||||
|
||||
export function fillKey(key) {
|
||||
let keySize = 128
|
||||
// 如果超过 key 16 位, 最大取 32 位,需要更改填充
|
||||
if (key.length > 16) {
|
||||
key = key.slice(0, 32)
|
||||
keySize = keySize * 2
|
||||
}
|
||||
const filledKeyLength = keySize / 8
|
||||
if (key.length >= filledKeyLength) {
|
||||
return key.slice(0, filledKeyLength)
|
||||
}
|
||||
const filledKey = Buffer.alloc(keySize / 8)
|
||||
const keys = Buffer.from(key)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
filledKey[i] = keys[i]
|
||||
}
|
||||
return filledKey
|
||||
}
|
||||
|
||||
export function aesEncrypt(text, originKey) {
|
||||
const key = CryptoJS.enc.Utf8.parse(fillKey(originKey))
|
||||
return CryptoJS.AES.encrypt(text, key, {
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.ZeroPadding
|
||||
}).toString()
|
||||
}
|
||||
|
||||
export function rsaEncrypt(text, pubKey) {
|
||||
const jsEncrypt = new JSEncrypt()
|
||||
jsEncrypt.setPublicKey(pubKey)
|
||||
return jsEncrypt.encrypt(text)
|
||||
}
|
||||
|
||||
export function getCookie(name) {
|
||||
return VueCookie.get(name)
|
||||
}
|
||||
|
||||
export function encryptPassword(password) {
|
||||
if (!password) {
|
||||
return ''
|
||||
}
|
||||
const aesKey = (Math.random() + 1).toString(36).substring(2)
|
||||
// public key 是 base64 存储的
|
||||
const rsaPublicKeyText = getCookie('jms_public_key')
|
||||
.replaceAll('"', '')
|
||||
const rsaPublicKey = atob(rsaPublicKeyText)
|
||||
const keyCipher = rsaEncrypt(aesKey, rsaPublicKey)
|
||||
const passwordCipher = aesEncrypt(password, aesKey)
|
||||
return `${keyCipher}:${passwordCipher}`
|
||||
}
|
||||
|
||||
window.aesEncrypt = aesEncrypt
|
||||
|
||||
@@ -36,7 +36,7 @@ function beforeRequestAddTimezone(config) {
|
||||
try {
|
||||
config.headers['X-TZ'] = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
} catch (e) {
|
||||
// debug('Current browser not support Intl tools')
|
||||
console.log('Current browser not support Intl tools')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ service.interceptors.request.use(
|
||||
},
|
||||
error => {
|
||||
// do something with request error
|
||||
// debug(error) // for debug
|
||||
console.log(error) // for debug
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
import store from '@/store'
|
||||
import router, { resetRouter } from '@/router'
|
||||
import Vue from 'vue'
|
||||
import VueCookie from 'vue-cookie'
|
||||
import { Message } from 'element-ui'
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
import { getTokenFromCookie } from '@/utils/auth'
|
||||
import orgUtil from '@/utils/org'
|
||||
import orgs from '@/api/orgs'
|
||||
import { getPropView, isViewHasOrgs } from '@/utils/jms'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist
|
||||
|
||||
@@ -20,25 +19,15 @@ async function checkLogin({ to, from, next }) {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
next()
|
||||
}
|
||||
// Determine whether the user has logged in
|
||||
const sessionExpire = VueCookie.get('jms_session_expire')
|
||||
if (!sessionExpire) {
|
||||
request.get(process.env['VUE_APP_LOGOUT_PATH']).finally(() => {
|
||||
// determine whether the user has logged in
|
||||
const hasToken = getTokenFromCookie()
|
||||
if (!hasToken) {
|
||||
setTimeout(() => {
|
||||
window.location = process.env.VUE_APP_LOGIN_PATH
|
||||
})
|
||||
return reject('No session mark found in cookie')
|
||||
} else if (sessionExpire === 'close') {
|
||||
let startTime = new Date().getTime()
|
||||
setInterval(() => {
|
||||
const endTime = new Date().getTime()
|
||||
const delta = (endTime - startTime)
|
||||
startTime = endTime
|
||||
Vue.$log.debug('Set session expire: ', delta)
|
||||
VueCookie.set('jms_session_expire', 'close', { expires: '2m' })
|
||||
}, 10 * 1000)
|
||||
} else if (sessionExpire === 'age') {
|
||||
Vue.$log.debug('Session expire on age')
|
||||
}, 100)
|
||||
return reject('No token found in cookie')
|
||||
}
|
||||
|
||||
try {
|
||||
return await store.dispatch('users/getProfile')
|
||||
} catch (e) {
|
||||
@@ -53,11 +42,11 @@ async function checkLogin({ to, from, next }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getPublicSetting({ to, from, next }, isOpen) {
|
||||
async function getPublicSetting({ to, from, next }) {
|
||||
// 获取Public settings
|
||||
const publicSettings = store.getters.publicSettings
|
||||
if (!publicSettings || !isOpen) {
|
||||
await store.dispatch('settings/getPublicSettings', isOpen)
|
||||
if (!publicSettings) {
|
||||
await store.dispatch('settings/getPublicSettings')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,10 +142,8 @@ export async function startup({ to, from, next }) {
|
||||
await store.dispatch('app/init')
|
||||
|
||||
// set page title
|
||||
// await getOpenPublicSetting({ to, from, next })
|
||||
await getPublicSetting({ to, from, next }, true)
|
||||
await getPublicSetting({ to, from, next })
|
||||
await checkLogin({ to, from, next })
|
||||
await getPublicSetting({ to, from, next }, false)
|
||||
await changeCurrentViewIfNeed({ to, from, next })
|
||||
await changeCurrentOrgIfNeed({ to, from, next })
|
||||
await generatePageRoutes({ to, from, next })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<GenericTreeListPage ref="TreeTablePage" :tree-setting="treeSetting">
|
||||
<template #table>
|
||||
<AccountListTable ref="table" :url="accountsUrl" :has-left-actions="true" />
|
||||
<AccountListTable ref="table" :url="accountsUrl" />
|
||||
</template>
|
||||
</GenericTreeListPage>
|
||||
</template>
|
||||
|
||||
@@ -7,7 +7,6 @@ import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { REMOTE_APP_TYPE_FIELDS_MAP, REMOTE_APP_TYPE_META_MAP, REMOTE_APP_PATH_DEFAULT_MAP } from './const'
|
||||
import rules from '@/components/DataForm/rules'
|
||||
import { UpdateToken } from '@/components/FormFields'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -70,20 +69,9 @@ export default {
|
||||
}
|
||||
return `${url}?type=${this.$route.query.type}`
|
||||
},
|
||||
cleanFormValue(values) {
|
||||
values.category = 'remote_app'
|
||||
const encryptedFields = [
|
||||
'chrome_password', 'custom_password',
|
||||
'mysql_workbench_password', 'vmware_password'
|
||||
]
|
||||
const attrs = values.attrs
|
||||
for (const item of encryptedFields) {
|
||||
const value = attrs[item]
|
||||
if (value) {
|
||||
attrs[item] = encryptPassword(value)
|
||||
}
|
||||
}
|
||||
return values
|
||||
cleanFormValue(value) {
|
||||
value.category = 'remote_app'
|
||||
return value
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<el-row :gutter="24">
|
||||
<el-col :md="16" :sm="24">
|
||||
<AccountListTable ref="ListTable" :url="assetUserUrl" :has-import="false" :has-clone="false" :has-left-actions="true" />
|
||||
<AccountListTable ref="ListTable" :url="assetUserUrl" :has-import="false" :has-clone="false" />
|
||||
</el-col>
|
||||
<el-col :md="8" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
|
||||
@@ -1,45 +1,79 @@
|
||||
<template>
|
||||
<div>
|
||||
<GenericTreeListPage
|
||||
ref="TreeList"
|
||||
:table-config="tableConfig"
|
||||
:help-message="helpMessage"
|
||||
:header-actions="headerActions"
|
||||
:tree-setting="treeSetting"
|
||||
>
|
||||
<TreeMenu
|
||||
slot="rMenu"
|
||||
:tree="treeRef"
|
||||
@showAll="showAll"
|
||||
/>
|
||||
<GenericTreeListPage ref="TreeList" :table-config="tableConfig" :help-message="helpMessage" :header-actions="headerActions" :tree-setting="treeSetting">
|
||||
<div slot="rMenu">
|
||||
<!-- <li class="divider" />-->
|
||||
<li id="m_add_asset_to_node" v-perms="'assets.add_assettonode'" class="rmenu" tabindex="-1" @click="rMenuAddAssetToNode">
|
||||
<i class="fa fa-clone" /> {{ this.$t('tree.AddAssetToNode') }}
|
||||
</li>
|
||||
<li id="m_move_asset_to_node" v-perms="'assets.move_assettonode'" class="rmenu" tabindex="-1" @click="rMenuMoveAssetToNode">
|
||||
<i class="fa fa-scissors" /> {{ this.$t('tree.MoveAssetToNode') }}
|
||||
</li>
|
||||
<li v-if="$hasPerm('assets.move_assettonode | assets.add_assettonode')" class="divider" />
|
||||
<li id="m_update_node_asset_hardware_info" v-perms="'assets.refresh_assethardwareinfo'" class="rmenu" tabindex="-1" @click="rMenuUpdateNodeAssetHardwareInfo">
|
||||
<i class="fa fa-refresh" /> {{ this.$t('tree.UpdateNodeAssetHardwareInfo') }}
|
||||
</li>
|
||||
<li id="m_test_node_asset_connectivity" v-perms="'assets.test_assetconnectivity'" class="rmenu" tabindex="-1" @click="rMenuTestNodeAssetConnectivity">
|
||||
<i class="fa fa-link" /> {{ this.$t('tree.TestNodeAssetConnectivity') }}
|
||||
</li>
|
||||
<li v-if="$hasPerm('assets.add_assettonode | assets.test_assetconnectivity')" class="divider" />
|
||||
<li id="m_show_asset_only_current_node" class="rmenu" tabindex="-1" @click="rMenuShowAssetOnlyCurrentNode">
|
||||
<i class="fa fa-indent" /> {{ this.$t('tree.ShowAssetOnlyCurrentNode') }}
|
||||
</li>
|
||||
<li id="m_show_asset_all_children_node" class="rmenu" tabindex="-1" @click="rMenuShowAssetAllChildrenNode">
|
||||
<i class="fa fa-align-justify" /> {{ this.$t('tree.ShowAssetAllChildrenNode') }}
|
||||
</li>
|
||||
<li class="divider" />
|
||||
<li id="m_check_assets_amount" v-perms="'assets.change_node'" class="rmenu" tabindex="-1" @click="rCheckAssetsAmount">
|
||||
<i class="fa fa-clone" /> {{ this.$t('tree.CheckAssetsAmount') }}
|
||||
</li>
|
||||
<li id="m_show_node_info" class="rmenu" tabindex="-1" @click="rMenuShowNodeInfo">
|
||||
<i class="fa fa-info-circle" /> {{ this.$t('tree.ShowNodeInfo') }}
|
||||
</li>
|
||||
</div>
|
||||
</GenericTreeListPage>
|
||||
|
||||
<Dialog width="30%" :title="this.$t('assets.NodeInformation')" :visible.sync="nodeInfoDialogSetting.dialogVisible" :show-cancel="false" :show-confirm="false">
|
||||
<el-row v-for="item in nodeInfoDialogSetting.items" :key="'card-' + item.key" :gutter="10" class="item">
|
||||
<el-col :md="6" :sm="24"><div class="item-label"><label>{{ item.label }}: </label></div></el-col>
|
||||
<el-col :md="18" :sm="24"><div class="item-text">{{ item.value }}</div></el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
<AssetBulkUpdateDialog
|
||||
:visible.sync="updateSelectedDialogSetting.visible"
|
||||
v-bind="updateSelectedDialogSetting"
|
||||
/>
|
||||
<NodeAssetsUpdateDialog
|
||||
:visible.sync="nodeAssetsUpdateDialog.visible"
|
||||
v-bind="nodeAssetsUpdateDialog"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage/index'
|
||||
import { DetailFormatter, ActionsFormatter, TagsFormatter } from '@/components/TableFormatters'
|
||||
import {
|
||||
DetailFormatter,
|
||||
ActionsFormatter,
|
||||
TagsFormatter
|
||||
} from '@/components/TableFormatters'
|
||||
import $ from '@/utils/jquery-vendor'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { connectivityMeta } from '@/components/AccountListTable/const'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
import AssetBulkUpdateDialog from './AssetBulkUpdateDialog'
|
||||
import TreeMenu from './TreeMenu'
|
||||
import NodeAssetsUpdateDialog from './NodeAssetsUpdateDialog'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericTreeListPage,
|
||||
Dialog,
|
||||
AssetBulkUpdateDialog,
|
||||
TreeMenu
|
||||
NodeAssetsUpdateDialog
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
treeRef: null,
|
||||
treeSetting: {
|
||||
showMenu: true,
|
||||
showRefresh: true,
|
||||
@@ -124,10 +158,7 @@ export default {
|
||||
type: 'primary',
|
||||
can: vm.$hasPerm('assets.refresh_assethardwareinfo'),
|
||||
callback: function({ cellValue, tableData, row }) {
|
||||
return this.$router.push({
|
||||
name: 'AssetMoreInformationEdit',
|
||||
params: { id: row.id }
|
||||
})
|
||||
return this.$router.push({ name: 'AssetMoreInformationEdit', params: { id: row.id }})
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -198,8 +229,8 @@ export default {
|
||||
title: this.$t('common.updateSelected'),
|
||||
can: ({ selectedRows }) => {
|
||||
return selectedRows.length > 0 &&
|
||||
!vm.currentOrgIsRoot &&
|
||||
vm.$hasPerm('assets.change_asset')
|
||||
!vm.currentOrgIsRoot &&
|
||||
vm.$hasPerm('assets.change_asset')
|
||||
},
|
||||
callback: ({ selectedRows }) => {
|
||||
vm.updateSelectedDialogSetting.selectedRows = selectedRows
|
||||
@@ -214,8 +245,8 @@ export default {
|
||||
return false
|
||||
}
|
||||
return selectedRows.length > 0 &&
|
||||
!vm.currentOrgIsRoot &&
|
||||
vm.$hasPerm('assets.change_node')
|
||||
!vm.currentOrgIsRoot &&
|
||||
vm.$hasPerm('assets.change_node')
|
||||
},
|
||||
callback: function({ selectedRows, reloadTable }) {
|
||||
const assetsId = []
|
||||
@@ -238,9 +269,18 @@ export default {
|
||||
]
|
||||
},
|
||||
helpMessage: this.$t('assets.AssetListHelpMessage'),
|
||||
nodeInfoDialogSetting: {
|
||||
dialogVisible: false,
|
||||
items: []
|
||||
},
|
||||
updateSelectedDialogSetting: {
|
||||
visible: false,
|
||||
selectedRows: []
|
||||
},
|
||||
nodeAssetsUpdateDialog: {
|
||||
visible: false,
|
||||
action: 'add',
|
||||
selectNode: null
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -253,7 +293,6 @@ export default {
|
||||
this.treeSetting.showCreate = this.$hasPerm('assets.add_node')
|
||||
this.treeSetting.showUpdate = this.$hasPerm('assets.change_node')
|
||||
this.treeSetting.showDelete = this.$hasPerm('assets.delete_node')
|
||||
this.treeRef = this.$refs.TreeList
|
||||
},
|
||||
methods: {
|
||||
decorateRMenu() {
|
||||
@@ -266,18 +305,145 @@ export default {
|
||||
$('#m_show_asset_only_current_node').css('color', '#606266')
|
||||
}
|
||||
},
|
||||
showAll({ node, showCurrentAsset }) {
|
||||
this.$cookie.set('show_current_asset', showCurrentAsset, 1)
|
||||
hideRMenu() {
|
||||
this.$refs.TreeList.hideRMenu()
|
||||
},
|
||||
getSelectedNodes() {
|
||||
return this.$refs.TreeList.getSelectedNodes()
|
||||
},
|
||||
rMenuAddAssetToNode() {
|
||||
this.nodeAssetsUpdateDialog.visible = true
|
||||
this.nodeAssetsUpdateDialog.action = 'add'
|
||||
this.nodeAssetsUpdateDialog.selectNode = this.getSelectedNodes()[0]
|
||||
},
|
||||
rMenuMoveAssetToNode() {
|
||||
this.nodeAssetsUpdateDialog.visible = true
|
||||
this.nodeAssetsUpdateDialog.action = 'move'
|
||||
this.nodeAssetsUpdateDialog.selectNode = this.getSelectedNodes()[0]
|
||||
},
|
||||
rMenuUpdateNodeAssetHardwareInfo: function() {
|
||||
this.hideRMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/nodes/${currentNode.meta.data.id}/tasks/`,
|
||||
{ 'action': 'refresh' }
|
||||
).then((res) => {
|
||||
openTaskPage(res['task'])
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
rMenuTestNodeAssetConnectivity: function() {
|
||||
this.hideRMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/nodes/${currentNode.meta.data.id}/tasks/`,
|
||||
{ 'action': 'test' }
|
||||
).then((res) => {
|
||||
openTaskPage(res['task'])
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
rMenuShowAssetOnlyCurrentNode: function() {
|
||||
this.hideRMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$cookie.set('show_current_asset', '1', 1)
|
||||
this.decorateRMenu()
|
||||
const url = `${this.treeSetting.url}?node_id=${node.meta.data.id}&show_current_asset=${showCurrentAsset}`
|
||||
const url = `${this.treeSetting.url}?node_id=${currentNode.meta.data.id}&show_current_asset=1`
|
||||
this.$refs.TreeList.$refs.TreeTable.handleUrlChange(url)
|
||||
},
|
||||
rMenuShowAssetAllChildrenNode: function() {
|
||||
this.hideRMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$cookie.set('show_current_asset', '0', 1)
|
||||
this.decorateRMenu()
|
||||
const url = `${this.treeSetting.url}?node_id=${currentNode.meta.data.id}&show_current_asset=0`
|
||||
this.$refs.TreeList.$refs.TreeTable.handleUrlChange(url)
|
||||
},
|
||||
rMenuShowNodeInfo: function() {
|
||||
this.hideRMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$axios.get(
|
||||
`/api/v1/assets/nodes/${currentNode.meta.data.id}/`
|
||||
).then(res => {
|
||||
this.nodeInfoDialogSetting.dialogVisible = true
|
||||
this.nodeInfoDialogSetting.items = [
|
||||
{ key: 'id', label: 'ID', value: res.id },
|
||||
{ key: 'name', label: this.$t('assets.Name'), value: res.name },
|
||||
{ key: 'fullName', label: this.$t('assets.FullName'), value: res.full_value }
|
||||
]
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.ErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
rCheckAssetsAmount: function() {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/nodes/check_assets_amount_task/`
|
||||
).then(res => {
|
||||
openTaskPage(res['task'])
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asset-select-dialog >>> .transition-box:first-child {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
.rmenu {
|
||||
font-size: 12px;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #606266;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rmenu > a:hover, .dropdown-menu > a:focus {
|
||||
color: #262626;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.rmenu:hover{
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.divider{
|
||||
margin: 1px 0;
|
||||
list-style: none outside none;
|
||||
background-color: #e5e5e5;
|
||||
height: 1px
|
||||
}
|
||||
|
||||
.asset-select-dialog >>> .transition-box:first-child {
|
||||
background-color: #f3f3f3 ;
|
||||
}
|
||||
|
||||
.el-row {
|
||||
margin-bottom: 20px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -95,7 +95,6 @@ export default {
|
||||
computed: {
|
||||
iVisible: {
|
||||
set(val) {
|
||||
this.$parent?.hideMenu()
|
||||
this.$emit('update:visible', val)
|
||||
},
|
||||
get() {
|
||||
@@ -134,7 +133,6 @@ export default {
|
||||
$('#tree-refresh').trigger('click')
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}).catch(error => {
|
||||
this.$parent?.hideMenu()
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<li id="m_add_asset_to_node" v-perms="'assets.add_assettonode'" class="rmenu" tabindex="-1" @click="rMenuAddAssetToNode">
|
||||
<i class="fa fa-clone" /> {{ this.$t('tree.AddAssetToNode') }}
|
||||
</li>
|
||||
<li id="m_move_asset_to_node" v-perms="'assets.move_assettonode'" class="rmenu" tabindex="-1" @click="rMenuMoveAssetToNode">
|
||||
<i class="fa fa-scissors" /> {{ this.$t('tree.MoveAssetToNode') }}
|
||||
</li>
|
||||
<li v-if="$hasPerm('assets.move_assettonode | assets.add_assettonode')" class="divider" />
|
||||
<li id="m_update_node_asset_hardware_info" v-perms="'assets.refresh_assethardwareinfo'" class="rmenu" tabindex="-1" @click="rMenuUpdateNodeAssetHardwareInfo">
|
||||
<i class="fa fa-refresh" /> {{ this.$t('tree.UpdateNodeAssetHardwareInfo') }}
|
||||
</li>
|
||||
<li id="m_test_node_asset_connectivity" v-perms="'assets.test_assetconnectivity'" class="rmenu" tabindex="-1" @click="rMenuTestNodeAssetConnectivity">
|
||||
<i class="fa fa-link" /> {{ this.$t('tree.TestNodeAssetConnectivity') }}
|
||||
</li>
|
||||
<li v-if="$hasPerm('assets.add_assettonode | assets.test_assetconnectivity')" class="divider" />
|
||||
<li id="m_show_asset_only_current_node" class="rmenu" tabindex="-1" @click="rMenuShowAssetOnlyCurrentNode">
|
||||
<i class="fa fa-indent" /> {{ this.$t('tree.ShowAssetOnlyCurrentNode') }}
|
||||
</li>
|
||||
<li id="m_show_asset_all_children_node" class="rmenu" tabindex="-1" @click="rMenuShowAssetAllChildrenNode">
|
||||
<i class="fa fa-align-justify" /> {{ this.$t('tree.ShowAssetAllChildrenNode') }}
|
||||
</li>
|
||||
<li class="divider" />
|
||||
<li id="m_check_assets_amount" v-perms="'assets.change_node'" class="rmenu" tabindex="-1" @click="rCheckAssetsAmount">
|
||||
<i class="fa fa-clone" /> {{ this.$t('tree.CheckAssetsAmount') }}
|
||||
</li>
|
||||
<li id="m_show_node_info" class="rmenu" tabindex="-1" @click="rMenuShowNodeInfo">
|
||||
<i class="fa fa-info-circle" /> {{ this.$t('tree.ShowNodeInfo') }}
|
||||
</li>
|
||||
<NodeAssetsUpdateDialog
|
||||
:visible.sync="nodeAssetsUpdateDialog.visible"
|
||||
v-bind="nodeAssetsUpdateDialog"
|
||||
/>
|
||||
<Dialog
|
||||
width="50%"
|
||||
:title="this.$t('assets.NodeInformation')"
|
||||
:visible.sync="nodeInfoDialogSetting.dialogVisible"
|
||||
:show-cancel="false"
|
||||
:show-confirm="false"
|
||||
>
|
||||
<el-row
|
||||
v-for="item in nodeInfoDialogSetting.items"
|
||||
:key="'card-' + item.key"
|
||||
:gutter="10"
|
||||
class="item"
|
||||
>
|
||||
<el-col :md="6" :sm="24">
|
||||
<div class="item-label"><label>{{ item.label }}: </label></div>
|
||||
</el-col>
|
||||
<el-col :md="18" :sm="24">
|
||||
<div class="item-text">{{ item.value }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
import NodeAssetsUpdateDialog from './NodeAssetsUpdateDialog'
|
||||
import Dialog from '@/components/Dialog'
|
||||
|
||||
export default {
|
||||
name: 'TreeMenu',
|
||||
components: {
|
||||
NodeAssetsUpdateDialog,
|
||||
Dialog
|
||||
},
|
||||
props: {
|
||||
tree: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nodeAssetsUpdateDialog: {
|
||||
visible: false,
|
||||
action: 'add',
|
||||
selectNode: null
|
||||
},
|
||||
nodeInfoDialogSetting: {
|
||||
dialogVisible: false,
|
||||
items: []
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rMenuAddAssetToNode() {
|
||||
this.nodeAssetsUpdateDialog.visible = true
|
||||
this.nodeAssetsUpdateDialog.action = 'add'
|
||||
this.nodeAssetsUpdateDialog.selectNode = this.getSelectedNodes()[0]
|
||||
},
|
||||
rMenuMoveAssetToNode() {
|
||||
this.nodeAssetsUpdateDialog.visible = true
|
||||
this.nodeAssetsUpdateDialog.action = 'move'
|
||||
this.nodeAssetsUpdateDialog.selectNode = this.getSelectedNodes()[0]
|
||||
},
|
||||
rMenuUpdateNodeAssetHardwareInfo() {
|
||||
this.hideMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/nodes/${currentNode.meta.data.id}/tasks/`,
|
||||
{ 'action': 'refresh' }
|
||||
).then((res) => {
|
||||
openTaskPage(res['task'])
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
rMenuTestNodeAssetConnectivity() {
|
||||
this.hideMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/nodes/${currentNode.meta.data.id}/tasks/`,
|
||||
{ 'action': 'test' }
|
||||
).then((res) => {
|
||||
openTaskPage(res['task'])
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
rMenuShowAssetOnlyCurrentNode() {
|
||||
this.hideMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$emit('showAll', { node: currentNode, showCurrentAsset: 1 })
|
||||
},
|
||||
rMenuShowAssetAllChildrenNode() {
|
||||
this.hideMenu()
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) {
|
||||
return
|
||||
}
|
||||
this.$emit('showAll', { node: currentNode, showCurrentAsset: 0 })
|
||||
},
|
||||
async rMenuShowNodeInfo() {
|
||||
const currentNode = this.getSelectedNodes()[0]
|
||||
if (!currentNode) return
|
||||
|
||||
try {
|
||||
const res = await this.$axios.get(`/api/v1/assets/nodes/${currentNode.meta.data.id}/`)
|
||||
this.nodeInfoDialogSetting.dialogVisible = true
|
||||
this.nodeInfoDialogSetting.items = [
|
||||
{ key: 'id', label: 'ID', value: res.id },
|
||||
{ key: 'name', label: this.$t('assets.Name'), value: res.name },
|
||||
{ key: 'fullName', label: this.$t('assets.FullName'), value: res.full_value }
|
||||
]
|
||||
} catch (error) {
|
||||
this.$message.error(this.$t('common.ErrorMsg' + ' ' + error))
|
||||
}
|
||||
},
|
||||
rCheckAssetsAmount() {
|
||||
this.$axios.post(
|
||||
`/api/v1/assets/nodes/check_assets_amount_task/`
|
||||
).then(res => {
|
||||
openTaskPage(res['task'])
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
hideMenu() {
|
||||
// debug('Tree: ', this.tree)
|
||||
this.tree.hideRMenu()
|
||||
},
|
||||
getSelectedNodes() {
|
||||
return this.tree.getSelectedNodes()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rmenu {
|
||||
font-size: 12px;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #606266;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.rMenu li {
|
||||
margin: 6px 0;
|
||||
cursor: pointer;
|
||||
list-style: none outside none;
|
||||
}
|
||||
|
||||
.rmenu > a:hover, .dropdown-menu > a:focus {
|
||||
color: #262626;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.rmenu:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 1px 0;
|
||||
list-style: none outside none;
|
||||
background-color: #e5e5e5;
|
||||
height: 1px
|
||||
}
|
||||
|
||||
.el-row {
|
||||
margin-bottom: 20px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -10,7 +10,6 @@ import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun } from '../const'
|
||||
import { UploadKey } from '@/components'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -32,7 +31,6 @@ export default {
|
||||
],
|
||||
fieldsMeta: {
|
||||
attrs: {
|
||||
encryptedFields: ['access_key_secret'],
|
||||
fields: accountProviderAttrs.attrs,
|
||||
fieldsMeta: {
|
||||
service_account_key: {
|
||||
@@ -63,20 +61,6 @@ export default {
|
||||
url = `${url}${params.id}/`
|
||||
}
|
||||
return `${url}?provider=${accountProvider}`
|
||||
},
|
||||
cleanFormValue(values) {
|
||||
const encryptedFields = [
|
||||
'access_key_secret', 'password', 'client_secret',
|
||||
'oc_password', 'sc_password'
|
||||
]
|
||||
const attrs = values.attrs
|
||||
for (const item of encryptedFields) {
|
||||
const value = attrs[item]
|
||||
if (value) {
|
||||
attrs[item] = encryptPassword(value)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script type="text/jsx">
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun, aws_china, aws_international, huaweicloud, qcloud, azure, azure_international, vmware, nutanix, qingcloud_private, huaweicloud_private, openstack, gcp, baiducloud, jdcloud, fc } from '../const'
|
||||
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun, aws_china, aws_international, huaweicloud, qcloud, azure, azure_international, vmware, nutanix, qingcloud_private, huaweicloud_private, openstack, gcp, baiducloud, jdcloud } from '../const'
|
||||
|
||||
export default {
|
||||
name: 'AccountList',
|
||||
@@ -134,10 +134,6 @@ export default {
|
||||
{
|
||||
name: nutanix,
|
||||
title: ACCOUNT_PROVIDER_ATTRS_MAP[nutanix].title
|
||||
},
|
||||
{
|
||||
name: fc,
|
||||
title: ACCOUNT_PROVIDER_ATTRS_MAP[fc].title
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ export const qingcloud_private = 'qingcloud_private'
|
||||
export const huaweicloud_private = 'huaweicloud_private'
|
||||
export const openstack = 'openstack'
|
||||
export const gcp = 'gcp'
|
||||
export const fc = 'fc'
|
||||
export const baiducloud = 'baiducloud'
|
||||
export const jdcloud = 'jdcloud'
|
||||
|
||||
@@ -92,10 +91,5 @@ export const ACCOUNT_PROVIDER_ATTRS_MAP = {
|
||||
name: gcp,
|
||||
title: i18n.t('xpack.Cloud.GCP'),
|
||||
attrs: ['service_account_key']
|
||||
},
|
||||
[fc]: {
|
||||
name: fc,
|
||||
title: i18n.t('xpack.Cloud.FC'),
|
||||
attrs: ['api_endpoint', 'username', 'password']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :md="10" :sm="24">
|
||||
<RelationCard ref="users" v-bind="userRelationConfig" />
|
||||
<RelationCard ref="userGroups" type="info" v-bind="userGroupsRelationConfig" class="card-margin" />
|
||||
<RelationCard ref="applications" type="warning" v-bind="applicationsRelationConfig" class="card-margin" />
|
||||
<RelationCard ref="systemUsers" type="danger" v-bind="systemUserRelationConfig" class="card-margin" />
|
||||
<RelationCard ref="systemUserRelation" v-bind="systemUserRelationConfig" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
@@ -29,58 +26,42 @@ export default {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const disabled = !this.$hasPerm('assets.change_commandfilter')
|
||||
const defaultTransformOption = (item, filed) => {
|
||||
const currentFiled = item[filed] ? item[filed] : filed === 'username' ? '*' : ''
|
||||
return { label: item.name + '(' + currentFiled + ')', value: item.id }
|
||||
}
|
||||
return {
|
||||
userRelationConfig: {
|
||||
disabled,
|
||||
icon: 'fa-user',
|
||||
title: this.$t('common.User'),
|
||||
objectsAjax: {
|
||||
url: '/api/v1/users/users/?fields_size=mini',
|
||||
transformOption: (item) => defaultTransformOption(item, 'username')
|
||||
},
|
||||
hasObjectsId: this.object.users,
|
||||
performAdd: item => this.performAddHandle(item, 'users'),
|
||||
performDelete: item => this.performDeleteHandle(item, 'users')
|
||||
},
|
||||
userGroupsRelationConfig: {
|
||||
disabled,
|
||||
icon: 'fa-users',
|
||||
title: this.$t('users.UserGroups'),
|
||||
objectsAjax: {
|
||||
url: '/api/v1/users/groups/'
|
||||
},
|
||||
hasObjectsId: this.object.user_groups,
|
||||
performAdd: item => this.performAddHandle(item, 'user_groups'),
|
||||
performDelete: item => this.performDeleteHandle(item, 'user_groups')
|
||||
},
|
||||
applicationsRelationConfig: {
|
||||
disabled,
|
||||
icon: 'fa-th',
|
||||
title: this.$t('assets.Applications'),
|
||||
objectsAjax: {
|
||||
url: `/api/v1/applications/applications/?category__in=db,cloud`,
|
||||
transformOption: (item) => defaultTransformOption(item, 'type_display')
|
||||
},
|
||||
hasObjectsId: this.object.applications,
|
||||
performAdd: item => this.performAddHandle(item, 'applications'),
|
||||
performDelete: item => this.performDeleteHandle(item, 'applications')
|
||||
},
|
||||
systemUserRelationConfig: {
|
||||
disabled,
|
||||
icon: 'fa-info-circle',
|
||||
title: this.$t('assets.SystemUser'),
|
||||
icon: 'fa-info',
|
||||
title: this.$t('perms.addSystemUserToThisPermission'),
|
||||
objectsAjax: {
|
||||
url: `/api/v1/assets/system-users/?protocol__in=ssh,telnet,mysql,postgresql,mariadb,oracle,sqlserver,k8s`,
|
||||
transformOption: (item) => defaultTransformOption(item, 'username')
|
||||
transformOption: (item) => {
|
||||
const username = item.username || '*'
|
||||
return { label: item.name + '(' + username + ')', value: item.id }
|
||||
}
|
||||
},
|
||||
hasObjectsId: this.object.system_users,
|
||||
performAdd: item => this.performAddHandle(item, 'system_users'),
|
||||
performDelete: item => this.performDeleteHandle(item, 'system_users')
|
||||
performAdd: (items) => {
|
||||
const newData = []
|
||||
const value = this.$refs.systemUserRelation.iHasObjects
|
||||
value.map(v => {
|
||||
newData.push(v.value)
|
||||
})
|
||||
const relationUrl = `/api/v1/assets/cmd-filters/${this.object.id}/`
|
||||
items.map(v => {
|
||||
newData.push(v.value)
|
||||
})
|
||||
return this.$axios.patch(relationUrl, { system_users: newData })
|
||||
},
|
||||
performDelete: (item) => {
|
||||
const itemId = item.value
|
||||
const newData = []
|
||||
const value = this.$refs.systemUserRelation.iHasObjects
|
||||
value.map(v => {
|
||||
if (v.value !== itemId) {
|
||||
newData.push(v.value)
|
||||
}
|
||||
})
|
||||
const relationUrl = `/api/v1/assets/cmd-filters/${this.object.id}/`
|
||||
return this.$axios.patch(relationUrl, { system_users: newData })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -109,38 +90,10 @@ export default {
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
performAddHandle(item, updateField) {
|
||||
const newDatas = []
|
||||
const updateFieldRef = _.camelCase(updateField)
|
||||
const options = this.$refs[updateFieldRef].iHasObjects
|
||||
const relationUrl = `/api/v1/assets/cmd-filters/${this.object.id}/`
|
||||
options.forEach(v => newDatas.push(v.value))
|
||||
item.forEach(v => newDatas.push(v.value))
|
||||
|
||||
return this.$axios.patch(relationUrl, { [updateField]: newDatas })
|
||||
},
|
||||
performDeleteHandle(item, updateField) {
|
||||
const newDatas = []
|
||||
const itemId = item?.value || ''
|
||||
const updateFieldRef = _.camelCase(updateField)
|
||||
const options = this.$refs[updateFieldRef].iHasObjects
|
||||
const relationUrl = `/api/v1/assets/cmd-filters/${this.object.id}/`
|
||||
options.forEach(v => {
|
||||
if (v.value !== itemId) {
|
||||
newDatas.push(v.value)
|
||||
}
|
||||
})
|
||||
|
||||
return this.$axios.patch(relationUrl, { [updateField]: newDatas })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
.card-margin {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
canClone: () => vm.$hasPerm('assets.add_platform'),
|
||||
canClone: vm.$hasPerm('assets.add_platform'),
|
||||
canUpdate: ({ row }) => !row.internal && vm.$hasPerm('assets.change_platform'),
|
||||
canDelete: ({ row }) => !row.internal && vm.$hasPerm('assets.delete_platform')
|
||||
}
|
||||
@@ -34,10 +34,7 @@ export default {
|
||||
hasRightActions: true,
|
||||
hasMoreActions: false,
|
||||
hasBulkDelete: false,
|
||||
createRoute: 'PlatformCreate',
|
||||
canCreate: () => {
|
||||
return this.$hasPerm('assets.add_platform')
|
||||
}
|
||||
createRoute: 'PlatformCreate'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ export default {
|
||||
[this.$t('common.Command filter'), ['cmd_filters']],
|
||||
[this.$t('common.Other'), ['priority', 'comment']]
|
||||
],
|
||||
encryptedFields: ['password'],
|
||||
fieldsMeta: {
|
||||
login_mode: fields.login_mode,
|
||||
username: fields.username,
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="20" :sm="24">
|
||||
<AppAccountListTable
|
||||
ref="ListTable"
|
||||
:url="accountUrl"
|
||||
:has-import="false"
|
||||
:has-clone="false"
|
||||
:system-user-disabled="systemUserDisabled"
|
||||
/>
|
||||
<AppAccountListTable ref="ListTable" :url="accountUrl" :has-import="false" :has-clone="false" />
|
||||
</el-col>
|
||||
<el-col :md="4" :sm="24" />
|
||||
</el-row>
|
||||
@@ -30,8 +24,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accountUrl: `/api/v1/applications/accounts/?systemuser=${this.object.id}`,
|
||||
systemUserDisabled: false
|
||||
accountUrl: `/api/v1/applications/accounts/?systemuser=${this.object.id}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert type="success">
|
||||
<el-alert type="info">
|
||||
<b>{{ Tips.title }}</b>: <span>{{ Tips.body }}</span>
|
||||
</el-alert>
|
||||
<el-row :gutter="20">
|
||||
|
||||
@@ -116,7 +116,7 @@ export default {
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
// debug('error submit!!')
|
||||
console.log('error submit!!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
90
src/views/myhome/components/Announcement.vue
Normal file
90
src/views/myhome/components/Announcement.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<el-card class="box-card" shadow="never">
|
||||
<div slot="header" class="title">
|
||||
<span>{{ $t('common.Announcement') }}</span>
|
||||
</div>
|
||||
<ul class="content">
|
||||
<li v-if="announcement.content" class="item">
|
||||
<p class="item-title">【{{ announcement.subject }}】</p>
|
||||
<p class="item-content">{{ announcement.content }}</p>
|
||||
<span v-if="announcement.link">
|
||||
<el-link :href="announcement.link" target="_blank" class="item-url">
|
||||
{{ $t('common.ViewMore') }}
|
||||
</el-link>
|
||||
<i class="fa fa-share-square-o icon-url" />
|
||||
</span>
|
||||
</li>
|
||||
<li v-else class="other">{{ $t('common.noAnnouncement') }}</li>
|
||||
</ul>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Announcement',
|
||||
data() {
|
||||
return {
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'publicSettings'
|
||||
]),
|
||||
announcement() {
|
||||
const ann = this.publicSettings?.ANNOUNCEMENT || {}
|
||||
return {
|
||||
id: ann?.ID,
|
||||
subject: ann?.SUBJECT || '',
|
||||
content: ann?.CONTENT || '',
|
||||
link: ann?.LINK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
ul,li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none
|
||||
}
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.title {
|
||||
font-weight: 500;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
.item {
|
||||
margin-bottom: 16px;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
.item-title {
|
||||
display: inline-block;
|
||||
color: #8b9db6;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
vertical-align: middle;
|
||||
margin-left: -10px;
|
||||
}
|
||||
.item-content {
|
||||
white-space: pre-wrap;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.item-url {
|
||||
color: #8b9db6!important;
|
||||
}
|
||||
.other {
|
||||
text-align: center;
|
||||
}
|
||||
.icon-url {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -46,13 +46,13 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
cardTitle() {
|
||||
return this.object.display_name
|
||||
return this.object.name
|
||||
},
|
||||
detailCardItems() {
|
||||
return [
|
||||
{
|
||||
key: this.$t('common.Name'),
|
||||
value: this.object.display_name
|
||||
value: this.object.name
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateCreated'),
|
||||
|
||||
@@ -25,9 +25,6 @@ export default {
|
||||
return {
|
||||
TaskDetail: {},
|
||||
config: {
|
||||
getTitle(row) {
|
||||
return row['display_name']
|
||||
},
|
||||
activeMenu: 'TaskDetail',
|
||||
submenu: [
|
||||
{
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
import { timeOffset, toSafeLocalDateStr } from '@/utils/common'
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
const performDelete = function({ row }) {
|
||||
const id = row.id
|
||||
const url = `${this.url}${id}/`
|
||||
return this.$axios.delete(url)
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -88,27 +83,6 @@ export default {
|
||||
hasUpdate: false,
|
||||
hasClone: false,
|
||||
canDelete: this.$hasPerm('ops.delete_task'),
|
||||
onDelete: function({ row, col, cellValue, reload }) {
|
||||
const msg = this.$t('common.deleteWarningMsg') + ` "${row.display_name || row.name}" ` + '?'
|
||||
const title = this.$t('common.Info')
|
||||
this.$alert(msg, title, {
|
||||
type: 'warning',
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
showCancelButton: true,
|
||||
beforeClose: async(action, instance, done) => {
|
||||
if (action !== 'confirm') return done()
|
||||
instance.confirmButtonLoading = true
|
||||
try {
|
||||
await performDelete.bind(this)({ row: row, col: col })
|
||||
done()
|
||||
reload()
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
} finally {
|
||||
instance.confirmButtonLoading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
name: 'run',
|
||||
|
||||
@@ -33,8 +33,7 @@ export default {
|
||||
title: this.$t('common.Active'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
model: this.object.is_active,
|
||||
disabled: !this.$hasPerm('perms.change_applicationpermission')
|
||||
model: this.object.is_active
|
||||
},
|
||||
callbacks: {
|
||||
change: function(val) {
|
||||
|
||||
@@ -74,7 +74,7 @@ export default {
|
||||
this.$message.error(this.$t('common.PleaseAgreeToTheTerms'))
|
||||
return Promise.reject()
|
||||
}
|
||||
return this.$axios['patch'](this.url, validValues)
|
||||
return this.$axios['put'](this.url, validValues)
|
||||
},
|
||||
onPerformSuccess() {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<Page v-bind="$attrs">
|
||||
<UserConfirmDialog
|
||||
v-if="showPasswordDialog"
|
||||
:visible.sync="showPasswordDialog"
|
||||
@UserConfirmDone="verifyDone"
|
||||
@UserConfirmCancel="exit"
|
||||
/>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="14" :sm="24">
|
||||
@@ -26,6 +20,28 @@
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<Dialog
|
||||
width="50"
|
||||
top="20vh"
|
||||
:title="this.$t('common.PasswordConfirm')"
|
||||
:visible.sync="showPasswordDialog"
|
||||
:show-confirm="false"
|
||||
:show-cancel="false"
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="4" :sm="24">
|
||||
<div style="line-height: 34px">{{ $t('assets.Password') }}</div>
|
||||
</el-col>
|
||||
<el-col :md="14" :sm="24">
|
||||
<el-input v-model="passwordInput" type="password" />
|
||||
<span class="help-tips help-block">{{ $t('common.PasswordRequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :md="4" :sm="24">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="passConfirm">{{ this.$t('common.Confirm') }}</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
@@ -34,7 +50,7 @@
|
||||
import Page from '@/layout/components/Page'
|
||||
import DetailCard from '@/components/DetailCard'
|
||||
import QuickActions from '@/components/QuickActions'
|
||||
import UserConfirmDialog from '@/components/UserConfirmDialog'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import store from '@/store'
|
||||
|
||||
@@ -44,7 +60,7 @@ export default {
|
||||
Page,
|
||||
DetailCard,
|
||||
QuickActions,
|
||||
UserConfirmDialog
|
||||
Dialog
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
@@ -56,6 +72,7 @@ export default {
|
||||
return {
|
||||
url: `/api/v1/users/profile/`,
|
||||
showPasswordDialog: false,
|
||||
passwordInput: '',
|
||||
currentEdit: '',
|
||||
authQuickActions: [
|
||||
{
|
||||
@@ -308,19 +325,23 @@ export default {
|
||||
}
|
||||
return backendList
|
||||
},
|
||||
verifyDone() {
|
||||
if (!this.object[`is_${this.currentEdit}_bound`]) {
|
||||
window.location.href = `/core/auth/${this.currentEdit}/qr/bind/?redirect_url=${this.$route.fullPath}`
|
||||
} else {
|
||||
this.$axios.post(`/api/v1/authentication/${this.currentEdit}/qr/unbind/`).then(res => {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
this.$store.dispatch('users/getProfile')
|
||||
})
|
||||
}
|
||||
passConfirm() {
|
||||
this.$axios.post(
|
||||
`/api/v1/authentication/password/verify/`, {
|
||||
password: this.passwordInput
|
||||
}
|
||||
).then(res => {
|
||||
if (!this.object[`is_${this.currentEdit}_bound`]) {
|
||||
window.location.href = `/core/auth/${this.currentEdit}/qr/bind/?redirect_url=${this.$route.fullPath}`
|
||||
} else {
|
||||
this.$axios.post(`/api/v1/authentication/${this.currentEdit}/qr/unbind/`).then(res => {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
this.$store.dispatch('users/getProfile')
|
||||
})
|
||||
}
|
||||
})
|
||||
this.passwordInput = ''
|
||||
this.showPasswordDialog = false
|
||||
},
|
||||
exit() {
|
||||
this.$emit('update:visible', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<IBox>
|
||||
<GenericCreateUpdateForm
|
||||
:fields="fields"
|
||||
:encrypted-fields="encryptedFields"
|
||||
:fields-meta="fieldsMeta"
|
||||
:initial="object"
|
||||
:url="url"
|
||||
@@ -18,7 +17,6 @@ import GenericCreateUpdateForm from '@/layout/components/GenericCreateUpdateForm
|
||||
import UserPassword from '@/components/FormFields/UserPassword'
|
||||
import { IBox } from '@/components'
|
||||
import rules from '@/components/DataForm/rules'
|
||||
import { PasswordInput } from '@/components/FormFields'
|
||||
|
||||
export default {
|
||||
name: 'PasswordUpdate',
|
||||
@@ -36,11 +34,12 @@ export default {
|
||||
return {
|
||||
url: '/api/v1/users/profile/password/',
|
||||
fields: ['old_password', 'new_password', 'new_password_again'],
|
||||
encryptedFields: ['old_password', 'new_password', 'new_password_again'],
|
||||
fieldsMeta: {
|
||||
old_password: {
|
||||
label: this.$t('users.OldPassword'),
|
||||
component: PasswordInput
|
||||
el: {
|
||||
type: 'password'
|
||||
}
|
||||
},
|
||||
new_password: {
|
||||
label: this.$t('users.NewPassword'),
|
||||
@@ -49,7 +48,9 @@ export default {
|
||||
},
|
||||
new_password_again: {
|
||||
label: this.$t('users.ConfirmPassword'),
|
||||
component: PasswordInput
|
||||
el: {
|
||||
type: 'password'
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSuccessNextRoute: {
|
||||
|
||||
@@ -31,12 +31,6 @@ export default {
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
is_finished: {
|
||||
width: '150px',
|
||||
formatterArgs: {
|
||||
showFalse: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
},
|
||||
tip: ({ row }) => {
|
||||
if (row.login_from === 'RT') {
|
||||
return this.$t('sessions.RazorNotSupport')
|
||||
return this.$t('sessions.XRDPNotSupport')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
@@ -21,9 +21,7 @@ export default {
|
||||
settings: {
|
||||
url: '/api/v1/settings/setting/?category=cas',
|
||||
fields: [
|
||||
[this.$t('common.Basic'), [
|
||||
'AUTH_CAS', 'CAS_SERVER_URL', 'CAS_ROOT_PROXIED_AS', 'CAS_VERSION'
|
||||
]],
|
||||
[this.$t('common.Basic'), ['AUTH_CAS', 'CAS_SERVER_URL', 'CAS_ROOT_PROXIED_AS', 'CAS_VERSION']],
|
||||
[this.$t('common.Other'), [
|
||||
'CAS_LOGOUT_COMPLETELY', 'CAS_USERNAME_ATTRIBUTE',
|
||||
'CAS_APPLY_ATTRIBUTES_TO_USER', 'CAS_RENAME_ATTRIBUTES',
|
||||
|
||||
@@ -35,7 +35,6 @@ export default {
|
||||
}
|
||||
}
|
||||
],
|
||||
encryptedFields: ['DINGTALK_APPSECRET'],
|
||||
fields: [
|
||||
[
|
||||
this.$t('common.BasicInfo'),
|
||||
|
||||
@@ -37,7 +37,6 @@ export default {
|
||||
}
|
||||
}
|
||||
],
|
||||
encryptedFields: ['FEISHU_APP_SECRET'],
|
||||
fields: [
|
||||
[
|
||||
this.$t('common.BasicInfo'),
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
<script>
|
||||
import BaseAuth from './Base'
|
||||
import { JsonEditor, UpdateToken } from '@/components/FormFields'
|
||||
import { JsonRequired } from '@/components/DataForm/rules'
|
||||
import { UpdateToken } from '@/components/FormFields'
|
||||
|
||||
export default {
|
||||
name: 'OIDC',
|
||||
@@ -20,21 +19,21 @@ export default {
|
||||
return {
|
||||
settings: {
|
||||
url: '/api/v1/settings/setting/?category=oidc',
|
||||
encryptedFields: ['AUTH_OPENID_CLIENT_SECRET'],
|
||||
fields: [
|
||||
[this.$t('common.Basic'), [
|
||||
'AUTH_OPENID', 'BASE_SITE_URL', 'AUTH_OPENID_CLIENT_ID',
|
||||
'AUTH_OPENID_CLIENT_SECRET', 'AUTH_OPENID_CLIENT_AUTH_METHOD'
|
||||
'AUTH_OPENID_CLIENT_SECRET'
|
||||
]],
|
||||
[this.$t('common.Params'), [
|
||||
'AUTH_OPENID_KEYCLOAK', 'AUTH_OPENID_SERVER_URL', 'AUTH_OPENID_REALM_NAME',
|
||||
'AUTH_OPENID_KEYCLOAK',
|
||||
'AUTH_OPENID_SERVER_URL', 'AUTH_OPENID_REALM_NAME',
|
||||
'AUTH_OPENID_PROVIDER_ENDPOINT', 'AUTH_OPENID_PROVIDER_AUTHORIZATION_ENDPOINT',
|
||||
'AUTH_OPENID_PROVIDER_TOKEN_ENDPOINT', 'AUTH_OPENID_PROVIDER_JWKS_ENDPOINT',
|
||||
'AUTH_OPENID_PROVIDER_USERINFO_ENDPOINT', 'AUTH_OPENID_PROVIDER_END_SESSION_ENDPOINT',
|
||||
'AUTH_OPENID_PROVIDER_SIGNATURE_ALG', 'AUTH_OPENID_PROVIDER_SIGNATURE_KEY',
|
||||
'AUTH_OPENID_SCOPES', 'AUTH_OPENID_ID_TOKEN_MAX_AGE', 'AUTH_OPENID_ID_TOKEN_INCLUDE_CLAIMS',
|
||||
'AUTH_OPENID_USE_STATE', 'AUTH_OPENID_USE_NONCE', 'AUTH_OPENID_ALWAYS_UPDATE_USER',
|
||||
'AUTH_OPENID_IGNORE_SSL_VERIFICATION', 'AUTH_OPENID_SHARE_SESSION', 'AUTH_OPENID_USER_ATTR_MAP'
|
||||
'AUTH_OPENID_IGNORE_SSL_VERIFICATION', 'AUTH_OPENID_SHARE_SESSION'
|
||||
]]
|
||||
],
|
||||
fieldsMeta: {
|
||||
@@ -108,24 +107,9 @@ export default {
|
||||
'AUTH_OPENID_IGNORE_SSL_VERIFICATION': {
|
||||
},
|
||||
'AUTH_OPENID_SHARE_SESSION': {
|
||||
},
|
||||
'AUTH_OPENID_USER_ATTR_MAP': {
|
||||
component: JsonEditor,
|
||||
label: this.$t('setting.authLdapUserAttrMap'),
|
||||
rules: [JsonRequired]
|
||||
}
|
||||
},
|
||||
submitMethod: () => 'patch',
|
||||
afterGetFormValue(obj) {
|
||||
obj.AUTH_OPENID_USER_ATTR_MAP = JSON.stringify(obj.AUTH_OPENID_USER_ATTR_MAP)
|
||||
return obj
|
||||
},
|
||||
cleanFormValue(data) {
|
||||
if (data['AUTH_OPENID_USER_ATTR_MAP']) {
|
||||
data['AUTH_OPENID_USER_ATTR_MAP'] = JSON.parse(data['AUTH_OPENID_USER_ATTR_MAP'])
|
||||
}
|
||||
return data
|
||||
}
|
||||
submitMethod: () => 'patch'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ export default {
|
||||
return {
|
||||
settings: {
|
||||
url: '/api/v1/settings/setting/?category=radius',
|
||||
encryptedFields: ['RADIUS_SECRET'],
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['AUTH_RADIUS', 'RADIUS_SERVER', 'RADIUS_PORT', 'RADIUS_SECRET']],
|
||||
[this.$t('common.Other'), ['OTP_IN_RADIUS']]
|
||||
|
||||
@@ -36,7 +36,6 @@ export default {
|
||||
}
|
||||
}
|
||||
],
|
||||
encryptedFields: ['WECOM_SECRET'],
|
||||
fields: [
|
||||
[
|
||||
this.$t('common.BasicInfo'),
|
||||
|
||||
@@ -23,13 +23,12 @@ export default {
|
||||
fields: [
|
||||
[
|
||||
this.$t('common.BasicInfo'), [
|
||||
'SITE_URL', // 'USER_GUIDE_URL',
|
||||
'SITE_URL', 'USER_GUIDE_URL',
|
||||
'GLOBAL_ORG_DISPLAY_NAME'
|
||||
]
|
||||
],
|
||||
[
|
||||
this.$t('setting.Feature'), [
|
||||
'TICKETS_ENABLED',
|
||||
'ANNOUNCEMENT_ENABLED'
|
||||
]
|
||||
]
|
||||
@@ -43,11 +42,6 @@ export default {
|
||||
return !this.$store.getters.hasValidLicense
|
||||
}
|
||||
},
|
||||
TICKETS_ENABLED: {
|
||||
hidden: () => {
|
||||
return !this.$store.getters.hasValidLicense
|
||||
}
|
||||
},
|
||||
ANNOUNCEMENT_ENABLED: {
|
||||
// label: '公告',
|
||||
component: Announcement
|
||||
|
||||
@@ -31,7 +31,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
encryptedFields: ['EMAIL_HOST_PASSWORD'],
|
||||
fields: [
|
||||
[
|
||||
this.$t('common.BasicInfo'),
|
||||
|
||||
@@ -16,24 +16,43 @@
|
||||
@error="handlerListTableXHRError($event)"
|
||||
/>
|
||||
<div slot="footer">
|
||||
<el-button size="small" @click="hiddenDialog">{{ $t('common.Cancel') }}</el-button>
|
||||
<el-button type="primary" size="small" :loading="dialogLdapUserImportLoginStatus" @click="importUserClick">{{ $t('common.Import') }}</el-button>
|
||||
<el-button type="primary" size="small" :loading="dialogLdapUserImportAllLoginStatus" @click="importAllUserClick">{{ $t('common.ImportAll') }}</el-button>
|
||||
<el-button @click="hiddenDialog">{{ $t('common.Cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="dialogLdapUserImportLoginStatus" @click="importUserClick">{{ $t('common.Import') }}</el-button>
|
||||
<el-button type="primary" :loading="dialogLdapUserImportAllLoginStatus" @click="importAllUserClick">{{ $t('common.ImportAll') }}</el-button>
|
||||
</div>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
:title="$t('setting.SyncSetting')"
|
||||
:visible.sync="settings.visible"
|
||||
:destroy-on-close="true"
|
||||
:show-cancel="false"
|
||||
:show-confirm="false"
|
||||
width="50%"
|
||||
top="10%"
|
||||
>
|
||||
<GenericCreateUpdateForm
|
||||
v-bind="settings"
|
||||
:has-detail-in-msg="false"
|
||||
/>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListTable from '@/components/ListTable'
|
||||
import { GenericCreateUpdateForm } from '@/layout/components'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import { importLdapUser, refreshLdapUserCache, startLdapUserCache } from '@/api/settings'
|
||||
import { CronTab } from '@/components'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
|
||||
export default {
|
||||
name: 'ImportDialog',
|
||||
components: {
|
||||
ListTable,
|
||||
Dialog
|
||||
Dialog,
|
||||
GenericCreateUpdateForm
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -54,11 +73,21 @@ export default {
|
||||
this.refreshed = true
|
||||
}
|
||||
reloadTable()
|
||||
}
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
name: 'setting',
|
||||
title: this.$t('setting.SyncSetting'),
|
||||
type: 'primary',
|
||||
callback: function() {
|
||||
this.settings.visible = true
|
||||
}.bind(this)
|
||||
}
|
||||
]
|
||||
},
|
||||
tableConfig: {
|
||||
url: '/api/v1/settings/ldap/users/',
|
||||
columns: ['username', 'name', 'email', 'groups', 'existing'],
|
||||
columns: ['username', 'name', 'email', 'existing'],
|
||||
columnsMeta: {
|
||||
username: {
|
||||
label: this.$t('users.Username'),
|
||||
@@ -68,13 +97,6 @@ export default {
|
||||
label: this.$t('users.Name'),
|
||||
width: '180px'
|
||||
},
|
||||
groups: {
|
||||
label: this.$t('users.UserGroups'),
|
||||
showOverflowTooltip: true,
|
||||
formatter: function(row) {
|
||||
return <span> {row.groups.join(' | ')} </span>
|
||||
}
|
||||
},
|
||||
email: {
|
||||
label: this.$t('users.Email')
|
||||
},
|
||||
@@ -83,6 +105,41 @@ export default {
|
||||
width: '120px'
|
||||
}
|
||||
}
|
||||
},
|
||||
settings: {
|
||||
visible: false,
|
||||
url: '/api/v1/settings/setting/?category=ldap',
|
||||
fields: ['AUTH_LDAP_SYNC_ORG_ID', 'AUTH_LDAP_SYNC_IS_PERIODIC', 'AUTH_LDAP_SYNC_CRONTAB', 'AUTH_LDAP_SYNC_INTERVAL'],
|
||||
fieldsMeta: {
|
||||
AUTH_LDAP_SYNC_ORG_ID: {
|
||||
component: Select2,
|
||||
rules: [Required],
|
||||
el: {
|
||||
multiple: false,
|
||||
ajax: {
|
||||
url: '/api/v1/orgs/orgs/',
|
||||
transformOption: (item) => {
|
||||
return { label: item.name, value: item.id }
|
||||
}
|
||||
}
|
||||
},
|
||||
hidden: (formValue) => {
|
||||
return !this.$hasLicense()
|
||||
}
|
||||
},
|
||||
AUTH_LDAP_SYNC_IS_PERIODIC: {
|
||||
type: 'switch'
|
||||
},
|
||||
AUTH_LDAP_SYNC_CRONTAB: {
|
||||
component: CronTab,
|
||||
helpText: this.$t('xpack.HelpText.CrontabOfCreateUpdatePage')
|
||||
},
|
||||
AUTH_LDAP_SYNC_INTERVAL: {
|
||||
rules: [Required],
|
||||
helpText: this.$t('xpack.HelpText.IntervalOfCreateUpdatePage')
|
||||
}
|
||||
},
|
||||
submitMethod: () => 'patch'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:title="$t('setting.SyncSetting')"
|
||||
:destroy-on-close="true"
|
||||
:show-cancel="false"
|
||||
:show-confirm="false"
|
||||
width="50%"
|
||||
top="10%"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<GenericCreateUpdateForm
|
||||
v-bind="settings"
|
||||
:has-detail-in-msg="false"
|
||||
/>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdateForm } from '@/layout/components'
|
||||
import { Dialog } from '@/components'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
import { CronTab } from '@/components'
|
||||
export default {
|
||||
name: 'SyncSettingDialog',
|
||||
components: {
|
||||
GenericCreateUpdateForm,
|
||||
Dialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
settings: {
|
||||
visible: false,
|
||||
url: '/api/v1/settings/setting/?category=ldap',
|
||||
fields: ['AUTH_LDAP_SYNC_ORG_ID', 'AUTH_LDAP_SYNC_IS_PERIODIC', 'AUTH_LDAP_SYNC_CRONTAB', 'AUTH_LDAP_SYNC_INTERVAL'],
|
||||
fieldsMeta: {
|
||||
AUTH_LDAP_SYNC_ORG_ID: {
|
||||
component: Select2,
|
||||
rules: [Required],
|
||||
el: {
|
||||
multiple: false,
|
||||
ajax: {
|
||||
url: '/api/v1/orgs/orgs/',
|
||||
transformOption: (item) => {
|
||||
return { label: item.name, value: item.id }
|
||||
}
|
||||
}
|
||||
},
|
||||
hidden: (formValue) => {
|
||||
return !this.$hasLicense()
|
||||
}
|
||||
},
|
||||
AUTH_LDAP_SYNC_IS_PERIODIC: {
|
||||
type: 'switch'
|
||||
},
|
||||
AUTH_LDAP_SYNC_CRONTAB: {
|
||||
component: CronTab,
|
||||
helpText: this.$t('xpack.HelpText.CrontabOfCreateUpdatePage')
|
||||
},
|
||||
AUTH_LDAP_SYNC_INTERVAL: {
|
||||
rules: [Required],
|
||||
helpText: this.$t('xpack.HelpText.IntervalOfCreateUpdatePage')
|
||||
}
|
||||
},
|
||||
submitMethod: () => 'patch'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -3,7 +3,6 @@
|
||||
<GenericCreateUpdateForm v-bind="$data" />
|
||||
<ImportDialog :visible.sync="dialogLdapUserImport" />
|
||||
<TestLoginDialog :visible.sync="dialogTest" />
|
||||
<SyncSettingDialog :visible.sync="dialogSyncSetting" />
|
||||
</IBox>
|
||||
</template>
|
||||
<script>
|
||||
@@ -11,7 +10,6 @@ import GenericCreateUpdateForm from '@/layout/components/GenericCreateUpdateForm
|
||||
import { testLdapSetting } from '@/api/settings'
|
||||
import ImportDialog from './ImportDialog'
|
||||
import TestLoginDialog from './TestLoginDialog'
|
||||
import SyncSettingDialog from './SyncSettingDialog'
|
||||
import { IBox } from '@/components'
|
||||
import rules from '@/components/DataForm/rules'
|
||||
import { JsonRequired } from '@/components/DataForm/rules'
|
||||
@@ -23,15 +21,12 @@ export default {
|
||||
GenericCreateUpdateForm,
|
||||
IBox,
|
||||
ImportDialog,
|
||||
TestLoginDialog,
|
||||
SyncSettingDialog
|
||||
TestLoginDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogTest: false,
|
||||
dialogLdapUserImport: false,
|
||||
dialogSyncSetting: false,
|
||||
encryptedFields: ['AUTH_LDAP_BIND_PASSWORD'],
|
||||
fields: [
|
||||
[
|
||||
this.$t('setting.LDAPServerInfo'),
|
||||
@@ -100,12 +95,6 @@ export default {
|
||||
callback: function(value, form) {
|
||||
this.dialogLdapUserImport = true
|
||||
}.bind(this)
|
||||
},
|
||||
{
|
||||
title: this.$t('setting.SyncSetting'),
|
||||
callback: function(value, form) {
|
||||
this.dialogSyncSetting = true
|
||||
}.bind(this)
|
||||
}
|
||||
],
|
||||
submitMethod: () => 'patch',
|
||||
|
||||
@@ -101,16 +101,8 @@ export default {
|
||||
).then(newSub => {
|
||||
const msgType = this.idMessageTypeMapper[newSub.message_type]
|
||||
msgType.receivers = newSub.receivers
|
||||
this.tableData.forEach(i => {
|
||||
for (const item of i.children) {
|
||||
if (item.id === newSub.message_type) {
|
||||
item.receivers = newSub.receivers
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
// debug(err)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
getNameDisplay(header) {
|
||||
|
||||
@@ -27,9 +27,9 @@ export default {
|
||||
]
|
||||
],
|
||||
[
|
||||
`RDP ${comp}(Razor)`,
|
||||
`RDP ${comp}(XRDP)`,
|
||||
[
|
||||
'TERMINAL_RAZOR_ENABLED'
|
||||
'XRDP_ENABLED'
|
||||
]
|
||||
],
|
||||
[
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
TERMINAL_TELNET_REGEX: {
|
||||
type: 'input'
|
||||
},
|
||||
TERMINAL_RAZOR_ENABLED: {
|
||||
XRDP_ENABLED: {
|
||||
helpText: this.$i18n.t('common.Info') + ': ' + this.$i18n.t('setting.SettingInEndpointHelpText'),
|
||||
hidden: () => {
|
||||
return !this.$store.getters.hasValidLicense
|
||||
|
||||
@@ -21,10 +21,7 @@ export default {
|
||||
[this.$t('common.Basic'), ['name', 'host']],
|
||||
[
|
||||
this.$t('applications.port'),
|
||||
[
|
||||
'http_port', 'https_port', 'ssh_port', 'rdp_port',
|
||||
'mysql_port', 'mariadb_port', 'postgresql_port', 'redis_port'
|
||||
]
|
||||
['http_port', 'https_port', 'ssh_port', 'rdp_port', 'mysql_port', 'mariadb_port', 'postgresql_port']
|
||||
],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
|
||||
@@ -18,7 +18,7 @@ export default {
|
||||
'name', 'host',
|
||||
'http_port', 'https_port', 'ssh_port',
|
||||
'rdp_port', 'mysql_port', 'mariadb_port',
|
||||
'postgresql_port', 'redis_port',
|
||||
'postgresql_port',
|
||||
'date_created', 'comment', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
|
||||
@@ -89,7 +89,6 @@ export default {
|
||||
guacamole: 'Guacamole',
|
||||
lion: 'Lion',
|
||||
xrdp: 'XRDP',
|
||||
razor: 'Razor',
|
||||
core: 'Core',
|
||||
celery: 'Celery',
|
||||
magnus: 'Magnus'
|
||||
|
||||
@@ -31,7 +31,7 @@ export default {
|
||||
helpText: this.$t('sessions.SetToDefaultStorage')
|
||||
},
|
||||
meta: {
|
||||
fields: ['HOSTS', 'INDEX_BY_DATE', 'INDEX', 'IGNORE_VERIFY_CERTS'],
|
||||
fields: ['HOSTS', 'INDEX', 'IGNORE_VERIFY_CERTS'],
|
||||
fieldsMeta: {
|
||||
HOSTS: {
|
||||
helpText: this.$t('sessions.helpText.esUrl')
|
||||
@@ -61,7 +61,6 @@ export default {
|
||||
return validValues
|
||||
},
|
||||
cleanFormValue(value) {
|
||||
value.meta.INDEX = value.meta?.INDEX?.toLowerCase()
|
||||
value.meta.HOSTS = value.meta.HOSTS.split(',').map(item => (item.trim()))
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
import GenericCreateUpdatePage from '@/layout/components/GenericCreateUpdatePage'
|
||||
import { STORAGE_TYPE_META_MAP } from '../../../sessions/const'
|
||||
import { UpdateToken } from '@/components/FormFields'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
|
||||
export default {
|
||||
name: 'ReplayStorageUpdate',
|
||||
@@ -49,7 +48,7 @@ export default {
|
||||
meta: {
|
||||
fields: storageTypeMeta.meta,
|
||||
fieldsMeta: {
|
||||
SECRET_KEY: {
|
||||
ACCESS_KEY: {
|
||||
component: UpdateToken
|
||||
}
|
||||
}
|
||||
@@ -57,19 +56,16 @@ export default {
|
||||
is_default: {
|
||||
helpText: this.$t('sessions.SetToDefaultStorage')
|
||||
}
|
||||
},
|
||||
cleanFormValue(values) {
|
||||
const encryptedFields = ['SECRET_KEY', 'ACCOUNT_KEY']
|
||||
const meta = values.meta
|
||||
for (const item of encryptedFields) {
|
||||
const val = meta[item]
|
||||
if (val) {
|
||||
meta[item] = encryptPassword(val)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -79,7 +79,6 @@ export default {
|
||||
onSubmit: function(validValues) {
|
||||
const url = '/api/v1/terminal/terminals/'
|
||||
const msg = this.$t('common.updateSuccessMsg')
|
||||
validValues = Object.values(validValues)
|
||||
this.$axios.patch(url, validValues).then((res) => {
|
||||
this.$message.success(msg)
|
||||
this.dialogSettings.visible = false
|
||||
@@ -109,16 +108,11 @@ export default {
|
||||
},
|
||||
columns: [
|
||||
'name', 'remote_addr', 'session_online',
|
||||
'stat.cpu_load', 'stat.disk_used', 'stat.memory_used',
|
||||
'status', 'is_active', 'is_alive', 'actions'
|
||||
'stat.cpu_load',
|
||||
'stat.disk_used', 'stat.memory_used',
|
||||
'status',
|
||||
'is_active', 'is_alive', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name'],
|
||||
default: [
|
||||
'name', 'session_online', 'stat.cpu_load', 'stat.disk_used',
|
||||
'stat.memory_used', 'status'
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
sortable: 'custom',
|
||||
@@ -180,6 +174,7 @@ export default {
|
||||
},
|
||||
headerActions: {
|
||||
hasCreate: false,
|
||||
hasBulkDelete: false,
|
||||
hasUpload: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user