mirror of
https://github.com/jumpserver/lina.git
synced 2025-08-02 07:27:01 +00:00
merge: with dev
This commit is contained in:
commit
61b2b0fb23
@ -496,3 +496,11 @@ td .el-button.el-button--mini {
|
||||
.el-alert.el-alert--error.is-light {
|
||||
border-color: var(--color-danger-light);
|
||||
}
|
||||
|
||||
#nprogress .bar {
|
||||
background: light-5!important;
|
||||
}
|
||||
|
||||
#nprogress .peg {
|
||||
box-shadow: 0 0 10px light-5, 0 0 5px light-5!important;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ export default {
|
||||
fields: [
|
||||
[this.$t('assets.Asset'), ['assets']],
|
||||
[this.$t('accounts.AccountTemplate'), ['template']],
|
||||
[this.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from']],
|
||||
[this.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from', 'su_from_username']],
|
||||
[this.$t('assets.Secret'), [
|
||||
'secret_type', 'secret', 'ssh_key',
|
||||
'token', 'access_key', 'passphrase'
|
||||
@ -167,6 +167,12 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
su_from_username: {
|
||||
label: this.$t('assets.UserSwitchFrom'),
|
||||
hidden: (formValue) => {
|
||||
return this.platform || this.asset
|
||||
}
|
||||
},
|
||||
secret: {
|
||||
label: this.$t('assets.Password'),
|
||||
component: UpdateToken,
|
||||
|
@ -25,8 +25,8 @@
|
||||
<AccountCreateUpdate
|
||||
v-if="showAddTemplateDialog"
|
||||
:account="account"
|
||||
:asset="iAsset"
|
||||
:add-template="true"
|
||||
:asset="iAsset"
|
||||
:title="accountCreateUpdateTitle"
|
||||
:visible.sync="showAddTemplateDialog"
|
||||
@add="addAccountSuccess"
|
||||
@ -103,6 +103,13 @@ export default {
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
columnsDefault: {
|
||||
type: Array,
|
||||
default: () => ([
|
||||
'name', 'username', 'asset', 'privileged',
|
||||
'secret_type', 'date_updated'
|
||||
])
|
||||
},
|
||||
headerExtraActions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
@ -135,6 +142,10 @@ export default {
|
||||
'name', 'username', 'asset', 'privileged',
|
||||
'secret_type', 'source', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'username', 'actions'],
|
||||
default: this.columnsDefault
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
formatter: function(row) {
|
||||
@ -294,7 +305,8 @@ export default {
|
||||
},
|
||||
exportOptions: {
|
||||
url: this.exportUrl,
|
||||
mfaVerifyRequired: true
|
||||
mfaVerifyRequired: true,
|
||||
tips: this.$t('accounts.AccountExportTips')
|
||||
},
|
||||
importOptions: {
|
||||
canImportCreate: this.$hasPerm('accounts.add_account'),
|
||||
|
@ -29,7 +29,9 @@
|
||||
:cell-value="secretInfo.secret"
|
||||
:col="{ formatterArgs: {
|
||||
name: account['name'],
|
||||
secretType: secretType || ''
|
||||
}}"
|
||||
@input="onShowKeyCopyFormatterChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="secretType === 'ssh_key'" :label="$tc('assets.sshKeyFingerprint')">
|
||||
@ -67,6 +69,7 @@ import Dialog from '@/components/Dialog'
|
||||
import PasswordHistoryDialog from './PasswordHistoryDialog'
|
||||
import UserConfirmDialog from '@/components/UserConfirmDialog'
|
||||
import { ShowKeyCopyFormatter } from '@/components/TableFormatters'
|
||||
import { encryptPassword } from '@/utils/crypto'
|
||||
|
||||
export default {
|
||||
name: 'ShowSecretInfo',
|
||||
@ -102,6 +105,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modifiedSecret: '',
|
||||
secretInfo: {},
|
||||
versions: '-',
|
||||
showSecret: false,
|
||||
@ -129,9 +133,19 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
accountConfirmHandle() {
|
||||
this.modifiedSecret && this.onChangeSecretSubmit()
|
||||
this.showSecret = false
|
||||
this.mfaDialogVisible = false
|
||||
},
|
||||
onChangeSecretSubmit() {
|
||||
const params = {
|
||||
name: this.secretInfo.name,
|
||||
secret: encryptPassword(this.modifiedSecret)
|
||||
}
|
||||
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, params).then(() => {
|
||||
this.$message.success(this.$tc('common.updateSuccessMsg'))
|
||||
})
|
||||
},
|
||||
getAuthInfo() {
|
||||
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
|
||||
this.secretInfo = resp
|
||||
@ -144,6 +158,10 @@ export default {
|
||||
},
|
||||
showHistoryDialog() {
|
||||
this.showPasswordHistoryDialog = true
|
||||
},
|
||||
onShowKeyCopyFormatterChange(value) {
|
||||
if (value === this.secretInfo.secret) return
|
||||
this.modifiedSecret = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,12 @@
|
||||
<script type="text/jsx">
|
||||
import DataTable from '../DataTable'
|
||||
import {
|
||||
ActionsFormatter, ArrayFormatter, ChoicesFormatter, DateFormatter, DetailFormatter, DisplayFormatter,
|
||||
ActionsFormatter,
|
||||
ArrayFormatter,
|
||||
ChoicesFormatter,
|
||||
DateFormatter,
|
||||
DetailFormatter,
|
||||
DisplayFormatter,
|
||||
ObjectRelatedFormatter
|
||||
} from '@/components/TableFormatters'
|
||||
import i18n from '@/i18n/i18n'
|
||||
@ -329,7 +334,7 @@ export default {
|
||||
|
||||
// 最小列
|
||||
const minColumnsNames = _.get(this.iConfig, 'columnsShow.min', ['actions', 'id'])
|
||||
.filter(n => defaultColumnsNames.indexOf(n) > -1)
|
||||
.filter(n => totalColumnsNames.includes(n))
|
||||
|
||||
// 应该显示的列
|
||||
const _tableConfig = localStorage.getItem('tableConfig')
|
||||
|
@ -148,12 +148,12 @@ export default {
|
||||
rootNodeAddDom(rootNode) {
|
||||
const { showSearch, showRefresh } = this.treeSetting
|
||||
const searchIcon = `
|
||||
<a class="tree-action-btn" id='search-btn' onclick="onSearch()">
|
||||
<i class='fa fa-search tree-banner-icon'></i>
|
||||
<a class="tree-action-btn" id="search-btn" onclick="onSearch()">
|
||||
<i class="fa fa-search tree-banner-icon"></i>
|
||||
</a>`
|
||||
const refreshIcon = `
|
||||
<a id='tree-refresh' class="tree-action-btn" onclick='refresh()'>
|
||||
<i class='fa fa-refresh'></i>
|
||||
<a id="tree-refresh" class="tree-action-btn" onclick="refresh()">
|
||||
<i class="fa fa-refresh"></i>
|
||||
</a>`
|
||||
const treeActions = `${showSearch ? searchIcon : ''}${showRefresh ? refreshIcon : ''}`
|
||||
const icons = `
|
||||
@ -306,7 +306,7 @@ export default {
|
||||
this.zTree.hideNodes(treeNodes)
|
||||
}
|
||||
|
||||
let treeUrl = this.treeSetting.treeUrl
|
||||
let treeUrl = this.treeSetting.searchUrl ? this.treeSetting.searchUrl : this.treeSetting.treeUrl
|
||||
const filterField = treeUrl.includes('?') ? `&search=${keyword}` : `?search=${keyword}`
|
||||
if (treeUrl.indexOf('assets/nodes/children/tree') > -1) {
|
||||
treeUrl = treeUrl + '&all=all'
|
||||
@ -336,259 +336,261 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-track:horizontal {
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
}
|
||||
div.rMenu {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
text-align: left;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
float: left;
|
||||
padding: 0 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dataTables_wrapper .dataTables_processing {
|
||||
opacity: .9;
|
||||
border: none;
|
||||
}
|
||||
::-webkit-scrollbar-track:horizontal {
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
div.rMenu li {
|
||||
margin: 6px 0;
|
||||
cursor: pointer;
|
||||
list-style: none outside none;
|
||||
}
|
||||
div.rMenu {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
text-align: left;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
float: left;
|
||||
padding: 0 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
border: medium none;
|
||||
min-width: 160px;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
left: 0;
|
||||
list-style: none outside none;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
text-shadow: none;
|
||||
top: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_processing {
|
||||
opacity: .9;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ztree ::v-deep .fa {
|
||||
font: normal normal normal 14px/1 FontAwesome !important;
|
||||
}
|
||||
div.rMenu li {
|
||||
margin: 6px 0;
|
||||
cursor: pointer;
|
||||
list-style: none outside none;
|
||||
}
|
||||
|
||||
.dropdown a:hover {
|
||||
background-color: #f1f1f1
|
||||
}
|
||||
.dropdown-menu {
|
||||
border: medium none;
|
||||
min-width: 160px;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
left: 0;
|
||||
list-style: none outside none;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
text-shadow: none;
|
||||
top: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
border-radius: 3px;
|
||||
color: inherit;
|
||||
line-height: 25px;
|
||||
margin: 4px;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ztree ::v-deep .fa {
|
||||
font: normal normal normal 14px/1 FontAwesome !important;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {
|
||||
color: #262626;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.dropdown a:hover {
|
||||
background-color: #f1f1f1
|
||||
}
|
||||
|
||||
.treebox {
|
||||
.dropdown-menu > li > a {
|
||||
border-radius: 3px;
|
||||
color: inherit;
|
||||
line-height: 25px;
|
||||
margin: 4px;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {
|
||||
color: #262626;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.treebox {
|
||||
background-color: transparent;
|
||||
|
||||
> > > .ztree {
|
||||
overflow: auto;
|
||||
background-color: transparent;
|
||||
height: calc(100vh - 237px);
|
||||
|
||||
>>> .ztree {
|
||||
overflow: auto;
|
||||
background-color: transparent;
|
||||
height: calc(100vh - 237px);
|
||||
li {
|
||||
background-color: transparent !important;
|
||||
|
||||
li {
|
||||
.button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
ul {
|
||||
background-color: transparent !important;
|
||||
|
||||
.button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
ul {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep #tree-refresh {
|
||||
margin-left: 3px;
|
||||
}
|
||||
::v-deep #tree-refresh {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
::v-deep .tree-banner-icon-zone {
|
||||
position: absolute;
|
||||
right: 7px;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
::v-deep .tree-banner-icon-zone {
|
||||
position: absolute;
|
||||
right: 7px;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
|
||||
.fa {
|
||||
color: #838385 !important;;
|
||||
|
||||
&:hover {
|
||||
color: #606266 !important;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .tree-search {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
border-radius: 12px;
|
||||
vertical-align: sub;
|
||||
transition: .25s;
|
||||
overflow: hidden;
|
||||
|
||||
.fa {
|
||||
width: 13px !important;
|
||||
}
|
||||
|
||||
.fa-search {
|
||||
padding-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .tree-search .tree-banner-icon {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 6px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background-color: transparent !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::v-deep .tree-search.active {
|
||||
width: 160px;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
|
||||
::v-deep .tree-search.active:hover {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
::v-deep .tree-search input {
|
||||
position: relative;
|
||||
left: 20px;
|
||||
width: 133px;
|
||||
height: 100%;
|
||||
background-color: #ffffff !important;
|
||||
color: #606266;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tree-header {
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
padding: 0 5px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: #D7D8DC;
|
||||
|
||||
.rotate {
|
||||
transition: all .1 .8s;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.fa-caret-down {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.special {
|
||||
top: 1px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tree-empty {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.fixed-tree-search {
|
||||
margin-bottom: 10px;
|
||||
|
||||
& > > > .el-input__inner {
|
||||
border-radius: 4px;
|
||||
background: #fafafa;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
& > > > .el-input__suffix {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
& > > > .el-input__prefix {
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
& > > > .el-input__suffix-inner {
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-refresh {
|
||||
border-radius: 4px;
|
||||
padding: 0 1px;
|
||||
z-index: 1;
|
||||
.fa {
|
||||
color: #838385 !important;;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #606266;
|
||||
border-color: #d2d2d2;
|
||||
background-color: #e6e6e6;
|
||||
color: #606266 !important;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
::v-deep .tree-search {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
border-radius: 12px;
|
||||
vertical-align: sub;
|
||||
transition: .25s;
|
||||
overflow: hidden;
|
||||
|
||||
.fa {
|
||||
width: 13px !important;
|
||||
}
|
||||
|
||||
.fa-search {
|
||||
padding-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .tree-search .tree-banner-icon {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 6px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background-color: transparent !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::v-deep .tree-search.active {
|
||||
width: 160px;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
|
||||
::v-deep .tree-search.active:hover {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
::v-deep .tree-search input {
|
||||
position: relative;
|
||||
left: 20px;
|
||||
width: 133px;
|
||||
height: 100%;
|
||||
background-color: #ffffff !important;
|
||||
color: #606266;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tree-header {
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
padding: 0 5px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: #D7D8DC;
|
||||
|
||||
.rotate {
|
||||
transition: all .1 .8s;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.fa-caret-down {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.special {
|
||||
top: 1px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tree-empty {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.fixed-tree-search {
|
||||
margin-bottom: 10px;
|
||||
|
||||
& > > > .el-input__inner {
|
||||
border-radius: 4px;
|
||||
background: #fafafa;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
.tree-action-btn {
|
||||
padding: 0 2px;
|
||||
color: red;
|
||||
& > > > .el-input__suffix {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
& > > > .el-input__prefix {
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
& > > > .el-input__suffix-inner {
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-refresh {
|
||||
border-radius: 4px;
|
||||
padding: 0 1px;
|
||||
z-index: 1;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #606266;
|
||||
border-color: #d2d2d2;
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tree-action-btn {
|
||||
padding: 0 2px;
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
@ -20,6 +20,7 @@
|
||||
<el-autocomplete
|
||||
v-if="item.type === 'input' && item.el.autoComplete"
|
||||
v-model="item.value"
|
||||
:placeholder="item.placeholder"
|
||||
:fetch-suggestions="item.el.query"
|
||||
class="inline-input"
|
||||
size="mini"
|
||||
|
@ -41,37 +41,23 @@ export default {
|
||||
shortcuts: [
|
||||
{
|
||||
text: this.$t('common.DateLast24Hours'),
|
||||
onClick(picker) {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
onClick: (picker) => this.onShortcutClick(picker, 1)
|
||||
},
|
||||
{
|
||||
text: this.$t('common.DateLastWeek'),
|
||||
onClick(picker) {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
onClick: (picker) => this.onShortcutClick(picker, 7)
|
||||
}, {
|
||||
text: this.$t('common.DateLastMonth'),
|
||||
onClick(picker) {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
onClick: (picker) => this.onShortcutClick(picker, 30)
|
||||
}, {
|
||||
text: this.$t('common.DateLast3Months'),
|
||||
onClick(picker) {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
onClick: (picker) => this.onShortcutClick(picker, 90)
|
||||
}, {
|
||||
text: this.$t('common.DateLastHarfYear'),
|
||||
onClick: (picker) => this.onShortcutClick(picker, 183)
|
||||
}, {
|
||||
text: this.$t('common.DateLastYear'),
|
||||
onClick: (picker) => this.onShortcutClick(picker, 365)
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -86,6 +72,12 @@ export default {
|
||||
this.$log.debug('Date change: ', val)
|
||||
this.$emit('dateChange', val)
|
||||
}
|
||||
},
|
||||
onShortcutClick(picker, day) {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * day)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,7 +100,7 @@ export default {
|
||||
.el-input__inner {
|
||||
border: 1px solid #dcdee2;
|
||||
border-radius: 3px;
|
||||
height: 32x;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-date-editor ::v-deep .el-range-separator {
|
||||
|
@ -57,7 +57,7 @@ export default {
|
||||
if (!this.rawValue.phone) {
|
||||
return ''
|
||||
}
|
||||
return `${this.rawValue.code} ${this.rawValue.phone}`
|
||||
return `${this.rawValue.code}${this.rawValue.phone}`
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -10,7 +10,7 @@
|
||||
width="70%"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-alert v-if="disabled" type="success">
|
||||
<el-alert v-if="disabled && platformDetail" type="success">
|
||||
{{ $t('assets.InheritPlatformConfig') }}
|
||||
<el-link :href="platformDetail" class="link-more" target="_blank">
|
||||
{{ $t('common.View') }}
|
||||
@ -48,8 +48,9 @@ export default {
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
const platform = this.$route.query.platform
|
||||
return {
|
||||
baseAttrs: ['primary', 'required', 'default'], // 基础属性, 放到 setting 中处理了,处理完成后,还得返回回去
|
||||
baseAttrs: ['primary', 'required', 'default', 'public'], // 基础属性, 放到 setting 中处理了,处理完成后,还得返回回去
|
||||
defaultSetting: {
|
||||
sftp_enabled: true,
|
||||
sftp_home: '/tmp',
|
||||
@ -61,7 +62,7 @@ export default {
|
||||
},
|
||||
loading: true,
|
||||
form: {},
|
||||
platformDetail: '#/console/assets/platforms/' + this.$route.query.platform,
|
||||
platformDetail: platform ? '#/console/assets/platforms/' + platform : '',
|
||||
config: {
|
||||
hasSaveContinue: false,
|
||||
hasButtons: !this.disabled,
|
||||
@ -101,6 +102,13 @@ export default {
|
||||
type: 'switch',
|
||||
helpText: this.$t('assets.DefaultProtocol'),
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
id: 'public',
|
||||
label: this.$t('assets.Public'),
|
||||
type: 'switch',
|
||||
helpText: this.$t('assets.PublicProtocol'),
|
||||
disabled: false
|
||||
}
|
||||
]],
|
||||
[this.$t('assets.LoginConfig'), [
|
||||
|
@ -90,10 +90,12 @@ export default {
|
||||
default: () => ([])
|
||||
},
|
||||
readonly: {
|
||||
// 这个是在详情中,不可编辑,包括所有
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
settingReadonly: {
|
||||
// 这个是在资产添加时设置协议使用,不能修改 setting
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
@ -146,6 +148,11 @@ export default {
|
||||
},
|
||||
items: {
|
||||
handler(value) {
|
||||
if (this.settingReadonly) {
|
||||
value = value.map(i => {
|
||||
return { name: i.name, port: i.port }
|
||||
})
|
||||
}
|
||||
this.$emit('input', value)
|
||||
},
|
||||
immediate: true,
|
||||
@ -218,6 +225,7 @@ export default {
|
||||
items[0].primary = true
|
||||
items[0].default = true
|
||||
items[0].required = true
|
||||
items[0].public = true
|
||||
} else if (primaryProtocols.length > 1) {
|
||||
primaryProtocols.slice(1, primaryProtocols.length).forEach(item => {
|
||||
item.primary = false
|
||||
|
@ -17,6 +17,9 @@
|
||||
@cancel="handleExportCancel()"
|
||||
@confirm="handleExportConfirm()"
|
||||
>
|
||||
<el-alert v-if="tips" :type="tipsType">
|
||||
{{ tips }}
|
||||
</el-alert>
|
||||
<el-form label-position="left" style="padding-left: 20px">
|
||||
<el-form-item :label="$tc('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportTypeOption">
|
||||
@ -92,6 +95,14 @@ export default {
|
||||
canExportFiltered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
tips: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
tipsType: {
|
||||
type: String,
|
||||
default: 'success'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -2,16 +2,23 @@
|
||||
<tr>
|
||||
<td>{{ action.title }}:</td>
|
||||
<td>
|
||||
<span>
|
||||
<component
|
||||
:is="iType"
|
||||
v-model="action.attrs.model"
|
||||
v-bind="action.attrs"
|
||||
v-on="callbacks"
|
||||
>
|
||||
{{ label }}
|
||||
</component>
|
||||
</span>
|
||||
<el-popover
|
||||
placement="left-end"
|
||||
trigger="hover"
|
||||
:disabled="!action.attrs.showTip"
|
||||
:content="action.attrs.tip"
|
||||
>
|
||||
<span slot="reference">
|
||||
<component
|
||||
:is="iType"
|
||||
v-model="action.attrs.model"
|
||||
v-bind="action.attrs"
|
||||
v-on="callbacks"
|
||||
>
|
||||
{{ label }}
|
||||
</component>
|
||||
</span>
|
||||
</el-popover>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
@ -29,6 +29,7 @@ export default {
|
||||
getRoute: null,
|
||||
routeQuery: null,
|
||||
can: true,
|
||||
openInNewPage: false,
|
||||
getTitle({ col, row, cellValue }) {
|
||||
return cellValue
|
||||
},
|
||||
@ -98,7 +99,12 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
goDetail() {
|
||||
this.$router.push(this.detailRoute)
|
||||
if (this.formatterArgs.openInNewPage) {
|
||||
const { href } = this.$router.resolve(this.detailRoute)
|
||||
window.open(href, '_blank')
|
||||
} else {
|
||||
this.$router.push(this.detailRoute)
|
||||
}
|
||||
// const routeName = this.formatterArgs.route
|
||||
// this.$log.debug('Will go to detail route: ', routeName)
|
||||
// this.$router.push({ name: routeName, params: { id: this.row.id }, query: routeQuery })
|
||||
|
@ -1,31 +1,26 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<pre class="text">{{ currentValue }}</pre>
|
||||
<span v-if="cellValue" class="action">
|
||||
<el-tooltip
|
||||
v-if="hasShow"
|
||||
effect="dark"
|
||||
placement="top"
|
||||
:content="$tc('common.View')"
|
||||
>
|
||||
<i class="fa" :class="isShow ? 'fa-eye-slash' : 'fa-eye'" @click="onShow()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="hasDownload"
|
||||
effect="dark"
|
||||
placement="top"
|
||||
:content="$tc('common.Download')"
|
||||
>
|
||||
<i class="fa fa-download" @click="onDownload()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="hasCopy"
|
||||
effect="dark"
|
||||
placement="top"
|
||||
:content="$tc('common.Copy')"
|
||||
>
|
||||
<i class="fa fa-clone" @click="onCopy()" />
|
||||
</el-tooltip>
|
||||
<pre v-if="!isEdit" class="text">{{ currentValue }}</pre>
|
||||
<el-input
|
||||
v-else
|
||||
ref="editInput"
|
||||
v-model="realValue"
|
||||
size="small"
|
||||
class="text edit-input"
|
||||
@blur="onEditBlur"
|
||||
/>
|
||||
<span v-if="realValue" class="action">
|
||||
<template v-for="(item, index) in iActions">
|
||||
<el-tooltip
|
||||
v-if="item.has"
|
||||
:key="index"
|
||||
effect="dark"
|
||||
placement="top"
|
||||
:content="item.tooltip"
|
||||
>
|
||||
<i class="fa" :class="[item.class, item.icon]" @click="item.action()" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@ -47,6 +42,7 @@ export default {
|
||||
hasShow: true,
|
||||
hasDownload: true,
|
||||
hasCopy: true,
|
||||
hasEdit: true,
|
||||
defaultShow: false
|
||||
}
|
||||
}
|
||||
@ -54,6 +50,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
realValue: this.cellValue,
|
||||
formatterArgs: Object.assign(this.formatterArgsDefault, this.col.formatterArgs || {}),
|
||||
isShow: false
|
||||
}
|
||||
@ -68,14 +66,46 @@ export default {
|
||||
hasCopy: function() {
|
||||
return this.formatterArgs.hasCopy
|
||||
},
|
||||
hasEdit: function() {
|
||||
return this.formatterArgs.hasEdit
|
||||
},
|
||||
name: function() {
|
||||
return this.formatterArgs.name
|
||||
},
|
||||
iActions() {
|
||||
const actions = [
|
||||
{
|
||||
has: this.hasEdit && this.formatterArgs?.secretType === 'password',
|
||||
class: this.isEdit ? 'fa-check' : 'fa-pencil',
|
||||
action: this.onEdit,
|
||||
tooltip: this.$t('common.Edit')
|
||||
},
|
||||
{
|
||||
has: this.hasShow,
|
||||
class: this.isShow ? 'fa-eye-slash' : 'fa-eye',
|
||||
action: this.onShow,
|
||||
tooltip: this.$t('common.View')
|
||||
},
|
||||
{
|
||||
has: this.hasDownload,
|
||||
icon: 'fa-download',
|
||||
action: this.onDownload,
|
||||
tooltip: this.$t('common.Download')
|
||||
},
|
||||
{
|
||||
has: this.hasCopy,
|
||||
icon: 'fa-clone',
|
||||
action: this.onCopy,
|
||||
tooltip: this.$t('common.Copy')
|
||||
}
|
||||
]
|
||||
return actions
|
||||
},
|
||||
currentValue() {
|
||||
if (this.isShow) {
|
||||
return this.cellValue || '-'
|
||||
return this.realValue || '-'
|
||||
} else {
|
||||
return this.cellValue ? '******' : '-'
|
||||
return this.realValue ? '******' : '-'
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -87,10 +117,21 @@ export default {
|
||||
this.isShow = !this.isShow
|
||||
},
|
||||
onCopy() {
|
||||
copy(this.cellValue)
|
||||
copy(this.realValue)
|
||||
},
|
||||
onDownload() {
|
||||
downloadText(this.cellValue, this.name + '.txt')
|
||||
downloadText(this.realValue, this.name + '.txt')
|
||||
},
|
||||
onEdit() {
|
||||
this.isEdit = !this.isEdit
|
||||
if (this.isEdit) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.editInput.focus()
|
||||
})
|
||||
}
|
||||
},
|
||||
onEditBlur() {
|
||||
this.$emit('input', this.realValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,4 +169,10 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-input >>> input {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
height: 30px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tag
|
||||
v-for="tag of cellValue"
|
||||
v-for="tag of iTags"
|
||||
:key="tag"
|
||||
:type="getTagType(tag)"
|
||||
class="tag-formatter"
|
||||
@ -24,6 +24,9 @@ export default {
|
||||
return {
|
||||
getTagType(tag) {
|
||||
return 'primary'
|
||||
},
|
||||
getTags(cellValue) {
|
||||
return cellValue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -34,6 +37,11 @@ export default {
|
||||
formatterArgs: Object.assign(this.formatterArgsDefault, this.col.formatterArgs)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iTags() {
|
||||
return this.formatterArgs.getTags(this.cellValue)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTagType(tag) {
|
||||
return this.formatterArgs.getTagType(tag)
|
||||
|
@ -1,6 +1,8 @@
|
||||
{
|
||||
"": "",
|
||||
"accounts": {
|
||||
"GenerateSuccessMsg": "Accounts generated successfully",
|
||||
"GenerateAccounts": "Regenerate accounts",
|
||||
"Accounts": "Accounts",
|
||||
"SelectAccount": "Select account",
|
||||
"UpdateSecret": "Update secret",
|
||||
@ -106,6 +108,7 @@
|
||||
},
|
||||
"DynamicUsername": "Dynamic username",
|
||||
"AutoCreate": "Auto create",
|
||||
"AccountExportTips": "The exported information contains account secret, which involves sensitive information. The exported format is an encrypted zip file (if no encryption password is set, please go to personal information to set the file encryption password).",
|
||||
"TaskID": "Task ID",
|
||||
"AccountTemplate": "Account template",
|
||||
"AddAccountResult": "Add account result"
|
||||
@ -336,6 +339,7 @@
|
||||
"Pending": "Pending",
|
||||
"Platform": "Platform",
|
||||
"PlatformDetail": "Platform detail",
|
||||
"DefaultDatabase": "Default database",
|
||||
"UseSSL": "Enable SSL",
|
||||
"ProtocolsGroup": "Protocols group",
|
||||
"DefaultPort": "Default port",
|
||||
@ -345,6 +349,8 @@
|
||||
"RequiredProtocol": "Required agreement, which must be selected when adding assets",
|
||||
"Default": "Default",
|
||||
"DefaultProtocol": "Default agreement, which will be selected by default when adding assets",
|
||||
"Public": "Public",
|
||||
"PublicProtocol": "If it is a public protocol, it will be displayed when connecting assets",
|
||||
"LoginConfig": "Login config",
|
||||
"UserNameSelector": "User name input box selector",
|
||||
"PasswordSelector": "Password Input Box Selector",
|
||||
@ -462,6 +468,8 @@
|
||||
},
|
||||
"common": {
|
||||
"BatchProcessing": "Select {Number} items",
|
||||
"Generate": "Generate",
|
||||
"BatchProcessing": "Batch processing(select {Number} items)",
|
||||
"ServerError": "Server Error",
|
||||
"CommunityEdition": "Community Edition",
|
||||
"EnterpriseEdition": "Enterprise Edition",
|
||||
@ -564,6 +572,8 @@
|
||||
"Resource": "Resource",
|
||||
"DateLast24Hours": "Last 24 hours",
|
||||
"DateLast3Months": "Last 3 months",
|
||||
"DateLastHarfYear": "Last half year",
|
||||
"DateLastYear": "Last year",
|
||||
"DateLastMonth": "Last month",
|
||||
"DateLastWeek": "Last week",
|
||||
"DateStart": "Date start",
|
||||
@ -625,6 +635,7 @@
|
||||
"Username": "Username",
|
||||
"Validity": "Validity",
|
||||
"Invalidity": "Invalidity",
|
||||
"Edit": "Edit",
|
||||
"View": "View",
|
||||
"Yes": "Yes",
|
||||
"action": "Action",
|
||||
@ -901,6 +912,7 @@
|
||||
"TotalJobLog": "Total job log"
|
||||
},
|
||||
"ops": {
|
||||
"EnterRunUser": "Enter run user",
|
||||
"Save": "Save",
|
||||
"Reset": "Reset",
|
||||
"SystemError": "System Error",
|
||||
@ -1009,6 +1021,7 @@
|
||||
"CloseConfirmMessage": "The file has changed, do you want to save it?",
|
||||
"privilegeOnly": "Select only privileged accounts",
|
||||
"UploadPlaybook": "Upload Playbook",
|
||||
"CreatePlaybook": "Create Playbook",
|
||||
"Rename": "Rename",
|
||||
"instantAdhoc": "Instant command",
|
||||
"Summary(success/total)": "Overview (Success/Total)",
|
||||
@ -1350,6 +1363,7 @@
|
||||
},
|
||||
"terminal": {
|
||||
"Author": "Author",
|
||||
"Uploading": "File uploading",
|
||||
"UploadSucceed": "Upload succeed",
|
||||
"UploadFailed": "Upload failed",
|
||||
"Applets": "Remote apps",
|
||||
@ -1745,6 +1759,7 @@
|
||||
"UpdateNodeAssetHardwareInfo": "Update node asset hardware information"
|
||||
},
|
||||
"users": {
|
||||
"UnbindHelpText": "The user is not a local user and cannot be unbound. Contact the administrator",
|
||||
"SetStatus": "Set status",
|
||||
"Set": "Set",
|
||||
"NotSet": "Not set",
|
||||
|
@ -3,6 +3,8 @@
|
||||
"accounts": {
|
||||
"Accounts": "アカウント",
|
||||
"SelectAccount": "アカウントを選択",
|
||||
"GenerateSuccessMsg": "アカウントの生成に成功しました",
|
||||
"GenerateAccounts": "アカウントを再生成する",
|
||||
"UpdateSecret": "機密の更新",
|
||||
"AccountPolicy": "アカウントポリシー",
|
||||
"BulkCreateStrategy": "作成時に要件を満たしていないアカウント(例:鍵タイプが規則に合わない、一意のキー制約がある、上記のポリシーを選択することができます)について。",
|
||||
@ -106,6 +108,7 @@
|
||||
},
|
||||
"DynamicUsername": "動的ユーザー名",
|
||||
"AutoCreate": "自動作成",
|
||||
"AccountExportTips": "エクスポート情報には機密情報を含むアカウント暗号文が含まれており、エクスポートされたフォーマットは暗号化されたzipファイルです(暗号化パスワードが設定されていない場合は、個人情報にファイル暗号化パスワードを設定してください)。",
|
||||
"TaskID": "タスク ID",
|
||||
"AccountTemplate": "账号模版",
|
||||
"AddAccountResult": "账号批量添加结果"
|
||||
@ -329,6 +332,7 @@
|
||||
"Pending": "待つ",
|
||||
"Platform": "システムプラットフォーム",
|
||||
"PlatformDetail": "プラットフォームの詳細",
|
||||
"DefaultDatabase": "デフォルト・データベース",
|
||||
"UseSSL": "SSLを立ち上げます",
|
||||
"ProtocolsGroup": "プロトコル・グループ",
|
||||
"DefaultPort": "デフォルトポート",
|
||||
@ -338,6 +342,8 @@
|
||||
"RequiredProtocol": "必要なプロトコル、資産の追加時に選択する必要があります",
|
||||
"Default": "デフォルト",
|
||||
"DefaultProtocol": "デフォルトのプロトコル、資産の追加時にデフォルトで選択",
|
||||
"Public": "ありふれた",
|
||||
"PublicProtocol": "資産への接続時にパブリック・プロトコルが表示される場合",
|
||||
"LoginConfig": "ログイン構成",
|
||||
"UserNameSelector": "ユーザー名入力ボックスセレクタ",
|
||||
"PasswordSelector": "パスワード入力ボックスセレクタ",
|
||||
@ -462,6 +468,8 @@
|
||||
},
|
||||
"common": {
|
||||
"BatchProcessing": "選択 {Number} 項目",
|
||||
"Generate": "生成",
|
||||
"BatchProcessing": "一括処理(選択 {Number} 項目)",
|
||||
"ServerError": "サーバーエラー",
|
||||
"RestoreDefault": "デフォルトに戻す",
|
||||
"DownloadCenter": "ダウンロードセンター",
|
||||
@ -563,6 +571,8 @@
|
||||
"Resource": "リソース",
|
||||
"DateLast24Hours": "最近の日",
|
||||
"DateLast3Months": "直近3月",
|
||||
"DateLastHarfYear": "ここ半年です",
|
||||
"DateLastYear": "ここ1年です",
|
||||
"DateLastMonth": "直近1月",
|
||||
"DateLastWeek": "最近の一週間",
|
||||
"DateStart": "開始日",
|
||||
@ -623,6 +633,7 @@
|
||||
"Username": "ユーザー名",
|
||||
"Validity": "有効",
|
||||
"Invalidity": "無効",
|
||||
"Edit": "編集",
|
||||
"View": "表示",
|
||||
"Yes": "はい",
|
||||
"action": "アクション",
|
||||
@ -900,6 +911,7 @@
|
||||
"Weekly": "週ごと"
|
||||
},
|
||||
"ops": {
|
||||
"EnterRunUser": "実行ユーザーの入力",
|
||||
"Save": "保存#ホゾン#",
|
||||
"Reset": "リストア",
|
||||
"SystemError": "システムエラー",
|
||||
@ -1004,6 +1016,7 @@
|
||||
"CloseConfirmMessage": "ファイルが変更されました,保存しますか?",
|
||||
"privilegeOnly": "特権アカウントのみを選択",
|
||||
"UploadPlaybook": "アップロード Playbook",
|
||||
"CreatePlaybook": "を作成 Playbook",
|
||||
"Rename": "名前を変更",
|
||||
"RUNNING": "ランニング",
|
||||
"instantAdhoc": "インスタントコマンド",
|
||||
@ -1345,6 +1358,7 @@
|
||||
},
|
||||
"terminal": {
|
||||
"Author": "作者",
|
||||
"Uploading": "ファイルのアップロード",
|
||||
"UploadSucceed": "アップロード成功",
|
||||
"UploadFailed": "アップロードに失敗しました",
|
||||
"Applets": "リモートアプリケーション",
|
||||
@ -1737,6 +1751,7 @@
|
||||
"UpdateNodeAssetHardwareInfo": "ノード資産ハードウェア情報の更新"
|
||||
},
|
||||
"users": {
|
||||
"UnbindHelpText": "このユーザーはローカルユーザーではありませんので、解除できません。管理者に連絡してください。",
|
||||
"SetStatus": "ステータスの設定",
|
||||
"Set": "設定",
|
||||
"NotSet": "未設定",
|
||||
|
@ -3,6 +3,8 @@
|
||||
"accounts": {
|
||||
"Accounts": "账号",
|
||||
"SelectAccount": "选择账号",
|
||||
"GenerateSuccessMsg": "账号生成成功",
|
||||
"GenerateAccounts": "重新生成账号",
|
||||
"UpdateSecret": "更新密文",
|
||||
"AddAccountResult": "账号批量添加结果",
|
||||
"AccountPolicy": "账号策略",
|
||||
@ -19,6 +21,7 @@
|
||||
"PleaseClickLeftApplicationToViewApplicationAccount": "应用账号列表,点击左侧应用进行查看",
|
||||
"PleaseClickLeftAssetToViewGatheredUser": "收集用户列表,点击左侧资产进行查看",
|
||||
"AutoCreate": "自动创建",
|
||||
"AccountExportTips": "导出信息中包含账号密文涉及敏感信息,导出的格式为一个加密的zip文件(若没有设置加密密码,请前往个人信息中设置文件加密密码)。",
|
||||
"AccountPush": {
|
||||
"WindowsPushHelpText": "windows 资产暂不支持推送密钥",
|
||||
"AccountPushList": "账号推送",
|
||||
@ -347,6 +350,7 @@
|
||||
"Pending": "等待",
|
||||
"Platform": "系统平台",
|
||||
"PlatformDetail": "平台详情",
|
||||
"DefaultDatabase": "默认数据库",
|
||||
"UseSSL": "开启 SSL",
|
||||
"ProtocolsGroup": "协议",
|
||||
"DefaultPort": "默认端口",
|
||||
@ -356,6 +360,8 @@
|
||||
"RequiredProtocol": "必需协议, 添加资产时必须选择, 可以设置多个",
|
||||
"Default": "默认的",
|
||||
"DefaultProtocol": "默认协议, 添加资产时默认会选择",
|
||||
"Public": "公共的",
|
||||
"PublicProtocol": "如果是公共协议在连接资产时会显示",
|
||||
"LoginConfig": "登录配置",
|
||||
"UserNameSelector": "用户名输入框选择器",
|
||||
"PasswordSelector": "密码输入框选择器",
|
||||
@ -385,7 +391,6 @@
|
||||
"Refresh": "刷新",
|
||||
"RefreshHardware": "更新硬件信息",
|
||||
"RemoteAppListHelpMessage": "使用此功能前,请确保已将应用加载器上传到应用服务器并成功发布为一个 RemoteApp 应用 <b><a href='https://github.com/jumpserver/Jmservisor/releases'>下载应用加载器</a></b>",
|
||||
|
||||
"RemoteApps": "远程应用",
|
||||
"Applications": "应用",
|
||||
"RemoteType": "应用类型",
|
||||
@ -483,6 +488,8 @@
|
||||
"RelOr": "或",
|
||||
"RelNot": "非",
|
||||
"BatchProcessing": "选中 {Number} 项",
|
||||
"Generate": "生成",
|
||||
"BatchProcessing": "批量处理(选中 {Number} 项)",
|
||||
"Created": "已创建",
|
||||
"Updated": "已更新",
|
||||
"Skipped": "已跳过",
|
||||
@ -606,6 +613,8 @@
|
||||
"Resource": "资源",
|
||||
"DateLast24Hours": "最近一天",
|
||||
"DateLast3Months": "最近三月",
|
||||
"DateLastHarfYear": "最近半年",
|
||||
"DateLastYear": "最近一年",
|
||||
"DateLastMonth": "最近一月",
|
||||
"DateLastWeek": "最近一周",
|
||||
"DateStart": "开始日期",
|
||||
@ -668,6 +677,7 @@
|
||||
"Username": "用户名",
|
||||
"Validity": "有效",
|
||||
"Invalidity": "无效",
|
||||
"Edit": "编辑",
|
||||
"View": "查看",
|
||||
"Yes": "是",
|
||||
"action": "动作",
|
||||
@ -903,6 +913,7 @@
|
||||
"Weekly": "按周"
|
||||
},
|
||||
"ops": {
|
||||
"EnterRunUser": "输入运行用户",
|
||||
"Save": "保存",
|
||||
"Reset": "还原",
|
||||
"SystemError": "系统错误",
|
||||
@ -932,6 +943,7 @@
|
||||
"SelectCreateMethod": "选择创建方式",
|
||||
"Workspace": "工作空间",
|
||||
"UploadPlaybook": "上传 Playbook",
|
||||
"CreatePlaybook": "创建 Playbook",
|
||||
"RequiredAssetOrNode": "请至少选择一个资产或节点",
|
||||
"RequiredContent": "请输入命令",
|
||||
"RequiredRunas": "请输入运行用户",
|
||||
@ -1344,6 +1356,7 @@
|
||||
"Author": "作者",
|
||||
"BasePort": "监听端口",
|
||||
"DatabasePort": "数据库协议端口",
|
||||
"Uploading": "文件上传中",
|
||||
"UploadSucceed": "上传成功",
|
||||
"UploadFailed": "上传失败",
|
||||
"Applets": "远程应用",
|
||||
@ -1737,6 +1750,7 @@
|
||||
"UpdateNodeAssetHardwareInfo": "更新节点资产硬件信息"
|
||||
},
|
||||
"users": {
|
||||
"UnbindHelpText": "此用户非本地用户,无法进行解绑,请联系管理员",
|
||||
"SetStatus": "设置状态",
|
||||
"Set": "已设置",
|
||||
"NotSet": "未设置",
|
||||
|
@ -115,7 +115,7 @@ export default {
|
||||
this.$router.push({ name: 'OrganizationList' })
|
||||
break
|
||||
default:
|
||||
orgUtil.changeOrg(org)
|
||||
orgUtil.changeOrg(org, true, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,12 +36,13 @@ export default [
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/assets/Cloud/Account/AccountList'),
|
||||
component: () => import('@/views/assets/Cloud/'),
|
||||
name: 'AccountList',
|
||||
hidden: true,
|
||||
meta: {
|
||||
title: i18n.t('xpack.Cloud.AccountList'),
|
||||
permissions: ['xpack.view_account']
|
||||
permissions: ['xpack.view_account'],
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -90,7 +91,7 @@ export default [
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/assets/Cloud/SyncInstanceTask/SyncInstanceTaskList'),
|
||||
component: () => import('@/views/assets/Cloud/'),
|
||||
name: 'SyncInstanceTaskList',
|
||||
hidden: true,
|
||||
meta: {
|
||||
|
@ -223,7 +223,7 @@ export default {
|
||||
hidden: true,
|
||||
component: () => import('@/views/ops/Template/Playbook/PlaybookCreateUpdate'),
|
||||
meta: {
|
||||
title: i18n.t('ops.PlaybookCreate'),
|
||||
title: i18n.t('ops.CreatePlaybook'),
|
||||
permissions: ['ops.add_playbook'],
|
||||
activeMenu: '/workbench/ops/templates'
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ const mutations = {
|
||||
state.profile = profile
|
||||
state.username = profile.username
|
||||
state.perms = profile.perms
|
||||
state.isSuperAdmin = profile['is_superuser']
|
||||
state.consoleOrgs = profile['console_orgs']
|
||||
state.workbenchOrgs = profile['workbench_orgs']
|
||||
state.noRootWorkbenchOrgs = profile['workbench_orgs'].filter(item => {
|
||||
|
BIN
src/styles/icons/switch.png
Normal file
BIN
src/styles/icons/switch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 236 B |
@ -243,12 +243,15 @@
|
||||
.ztree li span.button.public_ico_docu::before,
|
||||
.ztree li span.button.router_ico_docu::before,
|
||||
.ztree li span.button.other_ico_docu::before,
|
||||
.ztree li span.button.switch_ico_docu::before,
|
||||
.ztree li span.button.firewall_ico_docu::before,
|
||||
.ztree li span.button.general_ico_docu::before {
|
||||
content: "\F07B";
|
||||
}
|
||||
|
||||
.ztree li span.button.switch_ico_docu {
|
||||
background: url('./icons/switch.png') no-repeat center left transparent;
|
||||
}
|
||||
|
||||
.ztree li span.button.k8s_ico_docu {
|
||||
background: url('./icons/k8s.png') center left no-repeat;
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ export function formatDate(inputTime) {
|
||||
}
|
||||
|
||||
const uuidPattern = /[0-9a-zA-Z\-]{36}/
|
||||
const uuidRegex = /\/([a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12})\//
|
||||
|
||||
export function hasUUID(path) {
|
||||
const index = path.indexOf('?')
|
||||
@ -165,6 +166,15 @@ export function hasUUID(path) {
|
||||
return path.search(uuidPattern) !== -1
|
||||
}
|
||||
|
||||
export function getUuidUpdateFromUrl(path) {
|
||||
const matches = uuidRegex.exec(path)
|
||||
if (matches !== null) {
|
||||
return matches[1]
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export function replaceUUID(s, n) {
|
||||
const index = s.search(uuidPattern)
|
||||
if (index > 0) return s.substr(0, index)
|
||||
|
@ -1,5 +1,4 @@
|
||||
import store from '@/store'
|
||||
import { hasUUID, replaceUUID } from '@/utils/common'
|
||||
|
||||
export const DEFAULT_ORG_ID = '00000000-0000-0000-0000-000000000002'
|
||||
export const SYSTEM_ORG_ID = '00000000-0000-0000-0000-000000000004'
|
||||
@ -18,21 +17,27 @@ async function change2PropOrg() {
|
||||
await changeOrg(org)
|
||||
}
|
||||
|
||||
async function changeOrg(org, reload = true) {
|
||||
async function changeOrg(org, reload = true, vm = null) {
|
||||
await store.dispatch('users/setCurrentOrg', org)
|
||||
await store.dispatch('app/reset')
|
||||
let path = location.href
|
||||
if (hasUUID(path)) {
|
||||
path = replaceUUID(path, '')
|
||||
path = _.trimEnd(path, '/')
|
||||
location.href = path
|
||||
} else {
|
||||
const index = path.indexOf('?')
|
||||
if (index !== -1) {
|
||||
location.href = path.substring(0, index)
|
||||
}
|
||||
setTimeout(() => location.reload(), 400)
|
||||
let path = location.hash.slice(1)
|
||||
const index = path.indexOf('?')
|
||||
if (index !== -1) {
|
||||
path = path.slice(0, index)
|
||||
}
|
||||
const idRegex = /\/(-?\d+(\.\d+)?|[a-fA-F0-9]{8}-(?:[a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})\//
|
||||
const i = path.search(idRegex)
|
||||
if (i !== -1) {
|
||||
path = path.slice(0, i + 1)
|
||||
}
|
||||
if (vm) {
|
||||
const result = vm.$router.resolve({ path })
|
||||
if (result.resolved.name === '404') {
|
||||
path = '/'
|
||||
}
|
||||
}
|
||||
location.hash = '#' + path
|
||||
setTimeout(() => location.reload(), 400)
|
||||
}
|
||||
|
||||
function hasCurrentOrgPermission() {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { getUuidUpdateFromUrl } from '@/utils/common'
|
||||
import { UpdateToken } from '@/components/FormFields'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
|
||||
export const templateFields = (vm) => {
|
||||
return [
|
||||
[vm.$t('common.Basic'), ['name', 'username', 'privileged']],
|
||||
[vm.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from']],
|
||||
[vm.$t('assets.Secret'), [
|
||||
'secret_type', 'secret', 'ssh_key', 'token',
|
||||
'access_key', 'passphrase'
|
||||
@ -12,7 +14,21 @@ export const templateFields = (vm) => {
|
||||
}
|
||||
|
||||
export const templateFieldsMeta = (vm) => {
|
||||
const id = getUuidUpdateFromUrl(vm.$route.path)
|
||||
return {
|
||||
su_from: {
|
||||
component: Select2,
|
||||
el: {
|
||||
multiple: false,
|
||||
clearable: true,
|
||||
ajax: {
|
||||
url: `/api/v1/accounts/account-templates/su-from-account-templates/?${id ? 'template_id=' + id : ''}`,
|
||||
transformOption: (item) => {
|
||||
return { label: `${item.name}(${item.username})`, value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
secret: {
|
||||
label: vm.$t('assets.Password'),
|
||||
component: UpdateToken,
|
||||
|
@ -74,6 +74,7 @@ export default {
|
||||
delete values['accounts']
|
||||
} else {
|
||||
const accounts = values?.accounts || []
|
||||
accounts.reverse()
|
||||
values.accounts = accounts.map((item) => {
|
||||
item['secret'] = encryptPassword(item['secret'])
|
||||
return item
|
||||
@ -152,6 +153,8 @@ export default {
|
||||
if (i.name === 'http') {
|
||||
i.display_name = 'http(s)'
|
||||
}
|
||||
// 这个不删除会导致时,把 platform id 提交成 asset 的
|
||||
delete i['id']
|
||||
return i
|
||||
})
|
||||
const protocolChoices = this.defaultConfig.fieldsMeta.protocols.el.choices
|
||||
|
@ -41,7 +41,9 @@ export default {
|
||||
getAddFieldsMeta() {
|
||||
const platform = this.$route.query.type
|
||||
const fieldsMeta = {
|
||||
db_name: [],
|
||||
db_name: {
|
||||
label: this.$t('assets.DefaultDatabase')
|
||||
},
|
||||
use_ssl: {
|
||||
label: this.$t('common.UseSSL'),
|
||||
component: 'el-switch'
|
||||
|
@ -149,7 +149,7 @@ export default {
|
||||
nodes_display: {
|
||||
formatter: ArrayFormatter
|
||||
},
|
||||
info: {
|
||||
gathered_info: {
|
||||
label: this.$t('assets.HardwareInfo'),
|
||||
formatter: HostInfoFormatter,
|
||||
formatterArgs: {
|
||||
@ -164,8 +164,13 @@ export default {
|
||||
}
|
||||
},
|
||||
connectivity: connectivityMeta,
|
||||
labels_display: {
|
||||
formatter: TagsFormatter
|
||||
labels: {
|
||||
formatter: TagsFormatter,
|
||||
formatterArgs: {
|
||||
getTags(cellValue) {
|
||||
return cellValue.map(item => `${item.name}:${item.value}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
formatter: ActionsFormatter,
|
||||
@ -299,11 +304,12 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
optionInfo(iNew) {
|
||||
this.$set(this.defaultConfig.columnsMeta.info.formatterArgs, 'info', iNew)
|
||||
this.$set(this.defaultConfig.columnsMeta.gathered_info.formatterArgs, 'info', iNew)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAssetBulkUpdate() {
|
||||
this.updateSelectedDialogSetting.visible = false
|
||||
this.$refs.ListTable.reloadTable()
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ export default {
|
||||
this.nodeInfoDialogSetting.dialogVisible = true
|
||||
this.nodeInfoDialogSetting.items = [
|
||||
{ key: 'id', label: 'ID', value: res.id },
|
||||
{ key: 'key', label: 'KEY', value: res.key },
|
||||
{ key: 'name', label: this.$t('assets.Name'), value: res.name },
|
||||
{ key: 'fullName', label: this.$t('assets.FullName'), value: res.full_value }
|
||||
]
|
||||
|
@ -11,34 +11,14 @@ export default {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
const nodesInitial = []
|
||||
if (this.$route.query['node']) {
|
||||
nodesInitial.push(this.$route.query.node)
|
||||
}
|
||||
return {
|
||||
initial: {
|
||||
is_active: true,
|
||||
platform: 'Linux',
|
||||
protocols: ['ssh/22'],
|
||||
nodes: nodesInitial
|
||||
},
|
||||
initial: {},
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'address']],
|
||||
[this.$t('assets.Hardware'), ['info']]
|
||||
[this.$t('assets.Hardware'), ['gathered_info']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
platform: {
|
||||
el: {
|
||||
multiple: false,
|
||||
ajax: {
|
||||
url: '/api/v1/assets/platforms/',
|
||||
transformOption: (item) => {
|
||||
return { label: `${item.name}`, value: item.name }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
info: {
|
||||
gathered_info: {
|
||||
fields: [
|
||||
'vendor', 'model', 'sn', 'cpu_model', 'cpu_count',
|
||||
'cpu_cores', 'cpu_vcpus', 'memory', 'disk_total',
|
||||
|
@ -123,17 +123,8 @@ export default {
|
||||
}
|
||||
attrs[item] = encryptPassword(value)
|
||||
}
|
||||
const toListFields = ['ip_group']
|
||||
for (const item of toListFields) {
|
||||
let value = attrs[item]
|
||||
if (!value) {
|
||||
continue
|
||||
}
|
||||
value = value?.split(',') || []
|
||||
value = value.filter((value, index) => {
|
||||
if (value) return true
|
||||
})
|
||||
attrs[item] = value
|
||||
if (Array.isArray(attrs.ip_group)) {
|
||||
values.attrs.ip_group = attrs.ip_group.filter(Boolean)
|
||||
}
|
||||
return values
|
||||
},
|
||||
@ -141,9 +132,6 @@ export default {
|
||||
if (!formValue.attrs) {
|
||||
return formValue
|
||||
}
|
||||
if (Array.isArray(formValue.attrs.ip_group)) {
|
||||
formValue.attrs.ip_group = formValue.attrs.ip_group.toString()
|
||||
}
|
||||
return formValue
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +78,13 @@ export default {
|
||||
nodes_display: {
|
||||
formatter: ArrayFormatter
|
||||
},
|
||||
labels_display: {
|
||||
formatter: TagsFormatter
|
||||
labels: {
|
||||
formatter: TagsFormatter,
|
||||
formatterArgs: {
|
||||
getTags(cellValue) {
|
||||
return cellValue.map(item => `${item.name}:${item.value}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
connectivity: connectivityMeta,
|
||||
actions: {
|
||||
|
@ -82,6 +82,12 @@ export default {
|
||||
if (obj['category'] && obj['type']) {
|
||||
obj['category_type'] = [obj['category'].value, obj['type'].value]
|
||||
}
|
||||
obj.protocols = obj.protocols.map(i => {
|
||||
if (i.name === 'http') {
|
||||
i.display_name = 'http(s)'
|
||||
}
|
||||
return i
|
||||
})
|
||||
return obj
|
||||
},
|
||||
defaultOptions: {}
|
||||
|
@ -61,14 +61,14 @@ export default {
|
||||
quickActions: [],
|
||||
url: `/api/v1/assets/platforms/${this.object.id}`,
|
||||
detailFields: [
|
||||
'name', 'charset', 'internal',
|
||||
'id', 'name', 'charset', 'internal',
|
||||
{
|
||||
key: this.$t('assets.Type'),
|
||||
value: `${this.object.category?.label}/${this.object.type?.label}`
|
||||
},
|
||||
'su_method',
|
||||
'comment'
|
||||
'su_method', 'comment'
|
||||
],
|
||||
|
||||
protocolChoices: null,
|
||||
constraints: {}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ready: false,
|
||||
ready: true,
|
||||
currentStatus: '',
|
||||
currentTaskId: '',
|
||||
executionInfo: {
|
||||
@ -79,7 +79,7 @@ export default {
|
||||
showOpenAdhocDialog: false,
|
||||
showOpenAdhocSaveDialog: false,
|
||||
DataZTree: 0,
|
||||
runas: 'root',
|
||||
runas: '',
|
||||
runasPolicy: 'skip',
|
||||
command: '',
|
||||
module: 'shell',
|
||||
@ -107,10 +107,24 @@ export default {
|
||||
type: 'input',
|
||||
name: this.$t('ops.runAs'),
|
||||
align: 'left',
|
||||
value: 'root',
|
||||
value: '',
|
||||
placeholder: this.$tc('ops.EnterRunUser'),
|
||||
tip: this.$tc('ops.RunasHelpText'),
|
||||
el: {
|
||||
autoComplete: true
|
||||
autoComplete: true,
|
||||
query: (query, cb) => {
|
||||
const { hosts, nodes } = this.getSelectedNodesAndHosts()
|
||||
this.$axios.post('/api/v1/ops/username-hints/', {
|
||||
nodes: nodes,
|
||||
assets: hosts,
|
||||
query: query
|
||||
}).then(data => {
|
||||
const ns = data.map(item => {
|
||||
return { value: item.username }
|
||||
})
|
||||
cb(ns)
|
||||
})
|
||||
}
|
||||
},
|
||||
options: [],
|
||||
callback: (option) => {
|
||||
@ -213,6 +227,7 @@ export default {
|
||||
},
|
||||
treeSetting: {
|
||||
treeUrl: '/api/v1/perms/users/self/nodes/children-with-assets/tree/',
|
||||
searchUrl: '/api/v1/perms/users/self/assets/tree/',
|
||||
showRefresh: true,
|
||||
showMenu: false,
|
||||
showSearch: true,
|
||||
@ -241,7 +256,6 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async initData() {
|
||||
await this.getFrequentUsernames()
|
||||
this.recoverStatus()
|
||||
},
|
||||
recoverStatus() {
|
||||
@ -267,17 +281,6 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
getFrequentUsernames() {
|
||||
this.$axios.get('/api/v1/ops/frequent-username').then(data => {
|
||||
this.toolbar.left.runas.el.query = (query, cb) => {
|
||||
const ns = data.map(item => {
|
||||
return { value: item.username }
|
||||
})
|
||||
cb(ns)
|
||||
}
|
||||
this.ready = true
|
||||
})
|
||||
},
|
||||
onSelectAdhoc(adhoc) {
|
||||
this.command = adhoc.args
|
||||
},
|
||||
@ -332,7 +335,7 @@ export default {
|
||||
getSelectedNodes() {
|
||||
return this.ztree.getCheckedNodes().filter(node => {
|
||||
const status = node.getCheckStatus()
|
||||
return status.half === false
|
||||
return node.id !== 'search' && status.half === false
|
||||
})
|
||||
},
|
||||
|
||||
@ -344,10 +347,7 @@ export default {
|
||||
}, 100)
|
||||
},
|
||||
|
||||
execute() {
|
||||
// const size = 'rows=' + this.xterm.rows + '&cols=' + this.xterm.cols
|
||||
const url = '/api/v1/ops/jobs/?'
|
||||
|
||||
getSelectedNodesAndHosts() {
|
||||
const hosts = this.getSelectedNodes().filter((item) => {
|
||||
return item.meta.type !== 'node'
|
||||
}).map(function(node) {
|
||||
@ -359,6 +359,12 @@ export default {
|
||||
}).map(function(node) {
|
||||
return node.meta.data.id
|
||||
})
|
||||
return { hosts, nodes }
|
||||
},
|
||||
execute() {
|
||||
// const size = 'rows=' + this.xterm.rows + '&cols=' + this.xterm.cols
|
||||
const url = '/api/v1/ops/jobs/?'
|
||||
const { hosts, nodes } = this.getSelectedNodesAndHosts()
|
||||
|
||||
if (hosts.length === 0 && nodes.length === 0) {
|
||||
this.$message.error(this.$tc('ops.RequiredAssetOrNode'))
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<Page v-bind="$attrs">
|
||||
<AssetTreeTable
|
||||
ref="AssetTreeTable"
|
||||
:header-actions="headerActions"
|
||||
:table-config="tableConfig"
|
||||
:tree-setting="treeSetting"
|
||||
@ -8,6 +9,7 @@
|
||||
<PermBulkUpdateDialog
|
||||
:visible.sync="updateSelectedDialogSetting.visible"
|
||||
v-bind="updateSelectedDialogSetting"
|
||||
@update="handlePermBulkUpdate"
|
||||
/>
|
||||
</Page>
|
||||
</template>
|
||||
@ -174,7 +176,12 @@ export default {
|
||||
computed: {
|
||||
...mapGetters(['currentOrgIsRoot'])
|
||||
},
|
||||
methods: {}
|
||||
methods: {
|
||||
handlePermBulkUpdate() {
|
||||
this.updateSelectedDialogSetting.visible = false
|
||||
this.$refs.AssetTreeTable.$refs.TreeList.$refs?.ListTable?.reloadTable()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -63,7 +63,10 @@ export default {
|
||||
title: this.$t('users.setWeCom'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$store.state.users.profile.wecom_id ? this.$t('common.unbind') : this.$t('common.bind')
|
||||
label: this.getLabel('wecom'),
|
||||
disabled: this.isDisabled('wecom'),
|
||||
showTip: this.isDisabled('wecom'),
|
||||
tip: this.$t('users.UnbindHelpText')
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_WECOM,
|
||||
callbacks: {
|
||||
@ -77,7 +80,10 @@ export default {
|
||||
title: this.$t('users.setDingTalk'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$store.state.users.profile.dingtalk_id ? this.$t('common.unbind') : this.$t('common.bind')
|
||||
label: this.getLabel('dingtalk'),
|
||||
disabled: this.isDisabled('dingtalk'),
|
||||
showTip: this.isDisabled('dingtalk'),
|
||||
tip: this.$t('users.UnbindHelpText')
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_DINGTALK,
|
||||
callbacks: {
|
||||
@ -91,7 +97,10 @@ export default {
|
||||
title: this.$t('users.setFeiShu'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$store.state.users.profile.feishu_id ? this.$t('common.unbind') : this.$t('common.bind')
|
||||
label: this.getLabel('feishu'),
|
||||
disabled: this.isDisabled('feishu'),
|
||||
showTip: this.isDisabled('feishu'),
|
||||
tip: this.$t('users.UnbindHelpText')
|
||||
},
|
||||
has: this.$store.getters.publicSettings.AUTH_FEISHU,
|
||||
callbacks: {
|
||||
@ -118,7 +127,7 @@ export default {
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$t('common.Update'),
|
||||
disabled: this.$store.state.users.profile.source.value !== 'local'
|
||||
disabled: !this.isUserFromSource('local')
|
||||
},
|
||||
callbacks: {
|
||||
click: function() {
|
||||
@ -300,6 +309,18 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isBind(sourceName) {
|
||||
return !!this.$store.state.users.profile[`${sourceName}_id`]
|
||||
},
|
||||
getLabel(sourceName) {
|
||||
return this.isBind(sourceName) ? this.$t('common.unbind') : this.$t('common.bind')
|
||||
},
|
||||
isUserFromSource(sourceName) {
|
||||
return this.$store.state.users.profile.source.value === sourceName
|
||||
},
|
||||
isDisabled(sourceName) {
|
||||
return this.isBind(sourceName) && !this.isUserFromSource('local')
|
||||
},
|
||||
updateUserReceiveBackends(val) {
|
||||
this.$axios.patch(
|
||||
`/api/v1/notifications/user-msg-subscription/${this.object.id}/`,
|
||||
|
@ -88,6 +88,7 @@ export default {
|
||||
formatter: DetailFormatter,
|
||||
width: '80px',
|
||||
formatterArgs: {
|
||||
openInNewPage: true,
|
||||
can: this.$hasPerm('terminal.view_session'),
|
||||
getTitle() {
|
||||
return vm.$t('sessions.goto')
|
||||
|
@ -2,6 +2,8 @@
|
||||
<Dialog
|
||||
:show-cancel="false"
|
||||
:title="$tc('common.OfflineUpload')"
|
||||
:before-close="handleClose"
|
||||
:loading-status="!isFinished"
|
||||
v-bind="$attrs"
|
||||
@cancel="onCancel"
|
||||
@confirm="onSubmit"
|
||||
@ -53,7 +55,8 @@ export default {
|
||||
return {
|
||||
hasFileFormatOrSizeError: false,
|
||||
renderError: '',
|
||||
file: null
|
||||
file: null,
|
||||
isFinished: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -65,6 +68,13 @@ export default {
|
||||
},
|
||||
beforeUpload(file) {
|
||||
},
|
||||
handleClose(done) {
|
||||
if (this.isFinished) {
|
||||
done()
|
||||
} else {
|
||||
this.$message.warning(this.$tc('terminal.Uploading'))
|
||||
}
|
||||
},
|
||||
onCancel() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
@ -72,6 +82,7 @@ export default {
|
||||
if (!this.file) {
|
||||
return
|
||||
}
|
||||
this.isFinished = false
|
||||
const form = new FormData()
|
||||
form.append('file', this.file.raw)
|
||||
this.$axios.post(
|
||||
@ -82,10 +93,12 @@ export default {
|
||||
disableFlashErrorMsg: true
|
||||
}
|
||||
).then(res => {
|
||||
this.isFinished = true
|
||||
this.$message.success(this.$tc('terminal.UploadSucceed'))
|
||||
this.$emit('update:visible', false)
|
||||
this.$emit('upload-event', res)
|
||||
}).catch(err => {
|
||||
this.isFinished = true
|
||||
const error = err.response.data
|
||||
const msg = error?.message || error?.detail || error?.error || JSON.stringify(error)
|
||||
this.$message.error(msg)
|
||||
|
@ -1,13 +1,22 @@
|
||||
<template>
|
||||
<Account :object.sync="object" :columns-meta="columnsMeta" />
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="16" :sm="24">
|
||||
<Account :columns-meta="columnsMeta" :object.sync="object" />
|
||||
</el-col>
|
||||
<el-col :md="8" :sm="24">
|
||||
<QuickActions :actions="quickActions" type="primary" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Account from '@/views/assets/Asset/AssetDetail/Account'
|
||||
import { QuickActions } from '@/components'
|
||||
|
||||
export default {
|
||||
name: 'Accounts',
|
||||
components: {
|
||||
Account
|
||||
QuickActions, Account
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
@ -25,7 +34,25 @@ export default {
|
||||
label: this.$t('assets.Asset'),
|
||||
formatter: (row) => <span>{row.asset.name}</span>
|
||||
}
|
||||
}
|
||||
},
|
||||
quickActions: [
|
||||
{
|
||||
title: this.$t('accounts.GenerateAccounts'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$t('common.Generate')
|
||||
},
|
||||
callbacks: {
|
||||
click: function() {
|
||||
this.$axios.put(
|
||||
`/api/v1/terminal/applet-hosts/${this.object.id}/generate-accounts/`,
|
||||
).then(res => {
|
||||
this.$message.success(this.$tc('accounts.GenerateSuccessMsg'))
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,17 +25,6 @@ export default {
|
||||
]
|
||||
]
|
||||
],
|
||||
fieldsMeta: {
|
||||
FORGOT_PASSWORD_URL: {
|
||||
on: {
|
||||
change([value], updateForm) {
|
||||
if (value && !value.startsWith('http')) {
|
||||
updateForm({ FORGOT_PASSWORD_URL: 'http://' + value })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
submitMethod() {
|
||||
return 'patch'
|
||||
}
|
||||
|
@ -70,19 +70,14 @@ export default {
|
||||
],
|
||||
successUrl: { name: 'Settings', params: { activeMenu: 'EmailContent' }},
|
||||
fieldsMeta: {},
|
||||
afterGetFormValue(validValues) {
|
||||
validValues.SECURITY_LOGIN_IP_BLACK_LIST = validValues.SECURITY_LOGIN_IP_BLACK_LIST.toString()
|
||||
validValues.SECURITY_LOGIN_IP_WHITE_LIST = validValues.SECURITY_LOGIN_IP_WHITE_LIST.toString()
|
||||
return validValues
|
||||
},
|
||||
cleanFormValue(value) {
|
||||
const ipBlackList = value.SECURITY_LOGIN_IP_BLACK_LIST
|
||||
const ipWhiltList = value.SECURITY_LOGIN_IP_WHITE_LIST
|
||||
if (!Array.isArray(ipBlackList)) {
|
||||
value.SECURITY_LOGIN_IP_BLACK_LIST = ipBlackList ? ipBlackList.split(',') : []
|
||||
if (Array.isArray(ipBlackList)) {
|
||||
value.SECURITY_LOGIN_IP_BLACK_LIST = ipBlackList.filter(Boolean)
|
||||
}
|
||||
if (!Array.isArray(ipWhiltList)) {
|
||||
value.SECURITY_LOGIN_IP_WHITE_LIST = ipWhiltList ? ipWhiltList.split(',') : []
|
||||
if (Array.isArray(ipWhiltList)) {
|
||||
value.SECURITY_LOGIN_IP_WHITE_LIST = ipWhiltList.filter(Boolean)
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
@ -3,7 +3,6 @@
|
||||
v-bind="$data"
|
||||
:create-success-next-route="successUrl"
|
||||
:update-success-next-route="successUrl"
|
||||
:after-get-form-value="afterGetFormValue"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -18,7 +17,7 @@ export default {
|
||||
return {
|
||||
url: '/api/v1/terminal/endpoint-rules/',
|
||||
initial: {
|
||||
ip_group: '*'
|
||||
ip_group: ['*']
|
||||
},
|
||||
successUrl: { name: 'TerminalSetting', params: { activeMenu: 'EndpointRuleList' }},
|
||||
fields: [
|
||||
@ -41,14 +40,10 @@ export default {
|
||||
},
|
||||
hasDetailInMsg: false,
|
||||
cleanFormValue(value) {
|
||||
if (!Array.isArray(value.ip_group)) {
|
||||
value.ip_group = value.ip_group ? value.ip_group.split(',') : []
|
||||
if (Array.isArray(value.ip_group)) {
|
||||
value.ip_group = value.ip_group.filter(Boolean)
|
||||
}
|
||||
return value
|
||||
},
|
||||
afterGetFormValue(formValue) {
|
||||
formValue.ip_group = formValue.ip_group?.toString()
|
||||
return formValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,8 @@ export default {
|
||||
core: 'Core',
|
||||
celery: 'Celery',
|
||||
magnus: 'Magnus',
|
||||
tinker: 'Tinker'
|
||||
tinker: 'Tinker',
|
||||
video_worker: 'Video-Worker'
|
||||
}
|
||||
return nameMapper[this.componentMetric.type]
|
||||
}
|
||||
|
@ -65,7 +65,6 @@ export default {
|
||||
if (!validValues?.meta?.HOSTS) {
|
||||
return validValues
|
||||
}
|
||||
validValues.meta.HOSTS = validValues.meta.HOSTS.toString()
|
||||
return validValues
|
||||
},
|
||||
cleanFormValue(value) {
|
||||
|
@ -51,7 +51,7 @@ export default {
|
||||
key: this.$t('tickets.ApplyFromSession'),
|
||||
value: object.apply_from_session,
|
||||
formatter: function(item, value) {
|
||||
const to = { name: 'SessionDetail', params: { id: value }, query: { oid: object.org_id }}
|
||||
const to = { name: 'SessionDetail', params: { id: value?.id }, query: { oid: object.org_id }}
|
||||
if (!this.$hasPerm('terminal.view_session')) {
|
||||
return <span>{this.$t('sessions.session')}</span>
|
||||
}
|
||||
|
@ -181,14 +181,14 @@ export default {
|
||||
key: this.$t('users.Phone'),
|
||||
formatter: () => {
|
||||
const phoneObj = this.object.phone
|
||||
return <div>{phoneObj?.code} {phoneObj?.phone}</div>
|
||||
return <div>{phoneObj?.code}{phoneObj?.phone}</div>
|
||||
}
|
||||
},
|
||||
'wecom_id', 'dingtalk_id', 'feishu_id',
|
||||
{
|
||||
key: this.$t('users.Role'),
|
||||
formatter: (item, val) => {
|
||||
const rolesDisplay = this.object.org_roles.concat(this.object.system_roles)
|
||||
const rolesDisplay = this.object.org_roles.concat(this.object.system_roles || [])
|
||||
const dom = rolesDisplay.map(item => {
|
||||
return <el-tag size='mini'>{item.display_name}</el-tag>
|
||||
})
|
||||
|
@ -12,6 +12,7 @@ import UserAssetPermissionRules from './UserAssetPermissionRules'
|
||||
import UserGrantedAssets from './UserGrantedAssets'
|
||||
import UserLoginACLList from '@/views/acl/UserLoginACL/UserLoginACLList'
|
||||
import UserInfo from './UserInfo'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -28,7 +29,10 @@ export default {
|
||||
config: {
|
||||
activeMenu: 'UserInfo',
|
||||
actions: {
|
||||
canUpdate: this.$hasPerm('users.change_user')
|
||||
canUpdate: () => {
|
||||
return this.$hasPerm('users.change_user') &&
|
||||
!(!this.currentUserIsSuperAdmin && this.user['is_superuser'])
|
||||
}
|
||||
},
|
||||
submenu: [
|
||||
{
|
||||
@ -54,6 +58,11 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentUserIsSuperAdmin'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
handleTabClick(tab) {
|
||||
this.$log.debug('Current nav is: ', this.config.activeMenu)
|
||||
|
@ -87,6 +87,12 @@ export default {
|
||||
return this.$store.getters.hasValidLicense && !this.currentOrgIsRoot
|
||||
}
|
||||
},
|
||||
phone: {
|
||||
formatter: (row) => {
|
||||
const phoneObj = row.phone
|
||||
return <div>{phoneObj?.code}{phoneObj?.phone}</div>
|
||||
}
|
||||
},
|
||||
login_blocked: {
|
||||
width: '90px',
|
||||
formatterArgs: {
|
||||
@ -122,7 +128,10 @@ export default {
|
||||
formatterArgs: {
|
||||
fixed: 'right',
|
||||
hasDelete: hasDelete,
|
||||
canUpdate: this.$hasPerm('users.change_user'),
|
||||
canUpdate: ({ row }) => {
|
||||
return this.$hasPerm('users.change_user') &&
|
||||
!(!this.currentUserIsSuperAdmin && row['is_superuser'])
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
title: this.$t('users.Remove'),
|
||||
@ -284,6 +293,7 @@ export default {
|
||||
this.$refs.GenericListPage.$refs.ListTable.$refs.ListTable.reloadTable()
|
||||
},
|
||||
handleDialogUpdate() {
|
||||
this.updateSelectedDialogSetting.visible = false
|
||||
this.$refs.GenericListPage.$refs.ListTable.$refs.ListTable.reloadTable()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user