perf: rechange asset permission accounts

This commit is contained in:
ibuler
2024-06-06 16:55:07 +08:00
parent a89c32e668
commit 659a3864f7
6 changed files with 97 additions and 447 deletions

View File

@@ -30,11 +30,12 @@ export default {
}
},
data() {
const resourceDisplay = this.$t('WordSep') + this.resource.toLowerCase()
return {
type: 'all', // all, selected
types: [
{ name: 'all', label: this.$t('All') + this.$t('WordSep') + this.resourceLower },
{ name: 'spec', label: this.$t('Spec') + this.$t('WordSep') + this.resourceLower }
{ name: 'all', label: this.$t('All') + resourceDisplay },
{ name: 'spec', label: this.$t('Spec') + resourceDisplay }
],
selected: []
}
@@ -46,9 +47,6 @@ export default {
} else {
return this.selected
}
},
resourceLower() {
return this.resource.toLowerCase()
}
},
mounted() {

View File

@@ -87,7 +87,7 @@ export default {
},
computed: {
iPlaceholder() {
return `${this.placeholder} ( ${this.$t('EnterToContinue')} )`
return `${this.placeholder} (${this.$t('EnterToContinue')})`
}
},
@@ -165,31 +165,32 @@ export default {
border-color: #C0C4CC;
}
&>>> .el-tag {
& > > > .el-tag {
margin-top: 1px;
font-family: sans-serif !important;
}
&>>> .el-autocomplete {
& > > > .el-autocomplete {
height: 28px;
}
}
.search-input {
flex: 1;
&>>> .el-input__inner {
& > > > .el-input__inner {
max-width: 100%;
border: none;
padding-left: 10px;
}
}
.el-input >>> .el-input__inner {
.el-input > > > .el-input__inner {
border: none !important;
font-size: 13px;
}
.filter-field >>> .el-input__inner {
.filter-field > > > .el-input__inner {
height: 28px;
}
@@ -197,6 +198,7 @@ export default {
display: inherit;
padding-right: 6px;
cursor: pointer;
&:hover {
color: #999999;
}

View File

@@ -15,8 +15,6 @@ import { getDayFuture } from '@/utils/time'
import AccountFormatter from './components/AccountFormatter'
import { AllAccount } from '../const'
import ProtocolsSelect from '@/components/Form/FormFields/AllOrSpec.vue'
import RealFormatter from './components/RealFormatter.vue'
import VirtualFormatter from './components/VirtualFormatter.vue'
export default {
name: 'AccountFormatter',
@@ -45,7 +43,7 @@ export default {
[this.$t('Basic'), ['name']],
[this.$t('User'), ['users', 'user_groups']],
[this.$t('Asset'), ['assets', 'nodes']],
[this.$t('Account'), ['real_accounts', 'virtual_accounts']],
[this.$t('Account'), ['accounts']],
[this.$t('Protocol'), ['protocols']],
[this.$t('Action'), ['actions']],
[this.$t('Other'), ['is_active', 'date_start', 'date_expired', 'comment']]
@@ -121,12 +119,6 @@ export default {
this.fieldsMeta.accounts.el.nodes = formValue.nodes
}
},
real_accounts: {
component: RealFormatter
},
virtual_accounts: {
component: VirtualFormatter
},
actions: {
label: this.$t('Action'),
helpText: this.$t('ActionsTips')

View File

@@ -1,10 +1,9 @@
<template>
<el-form @submit.native.prevent>
<el-form class="account-content" @submit.native.prevent>
<el-form-item>
<el-checkbox-group v-model="choicesSelected">
<div class="group-title">资产上的账号</div>
<el-checkbox
v-for="(i) in choices.slice(0, 2)"
v-for="(i) in choices"
:key="i.label"
:label="i.value"
@change="handleCheckboxCheck(i, $event)"
@@ -16,6 +15,7 @@
</el-checkbox>
<div v-if="showSpecAccounts" class="spec-accounts">
<div class="group-title">{{ $t('SpecAccount') }}</div>
<TagInput
:autocomplete="autocomplete"
:tag-type="getTagType"
@@ -26,26 +26,27 @@
<el-button size="mini" type="primary" @click="showTemplateDialog=true">
{{ $t('TemplateAdd') }}
</el-button>
<span class="help-block" style="display: inline">
<span class="help-block">
{{ addTemplateHelpText }}
</span>
</span>
</div>
<div class="group-title">虚拟账号</div>
<el-checkbox
v-for="(i) in choices.slice(2, )"
:key="i.label"
:label="i.value"
@change="handleCheckboxCheck(i, $event)"
>
{{ i.label }}
<el-tooltip :content="i.tip" :open-delay="500" placement="top">
<i class="fa fa-question-circle-o" />
</el-tooltip>
</el-checkbox>
<div v-if="showVirtualAccountCheckbox">
<div class="group-title">{{ $t('VirtualAccounts') }}</div>
<el-checkbox
v-for="i in virtualAccounts"
:key="i.label"
:label="i.value"
@change="handleCheckboxCheck(i, $event)"
>
{{ i.label }}
<el-tooltip :content="i.tip" :open-delay="500" placement="top">
<i class="fa fa-question-circle-o" />
</el-tooltip>
</el-checkbox>
</div>
</el-checkbox-group>
</el-form-item>
<Dialog
@@ -108,6 +109,7 @@ export default {
},
data() {
const vm = this
const virtual = '@VIRTUAL'
const choices = [
{
label: AccountLabelMapper[AllAccount],
@@ -120,29 +122,36 @@ export default {
tip: this.$t('SpecAccountTip')
},
{
label: AccountLabelMapper[ManualAccount],
value: ManualAccount,
tip: this.$t('ManualAccountTip')
},
{
label: AccountLabelMapper[SameAccount],
value: SameAccount,
tip: this.$t('SameAccountTip')
},
{
label: AccountLabelMapper[AnonymousAccount],
value: AnonymousAccount,
tip: this.$t('AnonymousAccountTip')
label: this.$t('VirtualAccounts'),
value: virtual,
tip: this.$t('VirtualAccountHelpMsg'),
disabled: !this.showVirtualAccount
}
]
return {
ALL: AllAccount,
SPEC: SpecAccount,
VIRTUAL: virtual,
showTemplateDialog: false,
choices: choices.filter(i => {
const isVirtualAccount = [SameAccount, ManualAccount, AnonymousAccount].includes(i.value)
return !(isVirtualAccount && !this.showVirtualAccount)
}),
choices: choices,
virtualAccounts: [
{
label: AccountLabelMapper[ManualAccount],
value: ManualAccount,
tip: this.$t('ManualAccountTip')
},
{
label: AccountLabelMapper[SameAccount],
value: SameAccount,
tip: this.$t('SameAccountTip')
},
{
label: AccountLabelMapper[AnonymousAccount],
value: AnonymousAccount,
tip: this.$t('AnonymousAccountTip')
}
],
virtualAccountsNames: [ManualAccount, SameAccount, AnonymousAccount],
choicesSelected: [this.ALL],
specAccountsInput: [],
specAccountsTemplate: [],
@@ -212,6 +221,17 @@ export default {
}
}
},
computed: {
showVirtualAccountCheckbox() {
if (!this.showVirtualAccount) {
return false
}
const hasVirtual = this.choicesSelected.filter(i => {
return i && i.startsWith('@') && i !== '@ALL' && i !== '@SPEC'
})
return hasVirtual.length > 0
}
},
mounted() {
this.initDefaultChoice()
setTimeout(() => {
@@ -225,6 +245,8 @@ export default {
methods: {
initDefaultChoice() {
const choicesSelected = this.value.filter(i => i.startsWith('@'))
// 是否添加特定账号选择
const specAccountsInput = this.value.filter(i => !i.startsWith('@'))
if (specAccountsInput.length > 0 && !choicesSelected.includes(this.ALL)) {
choicesSelected.push(this.SPEC)
@@ -233,6 +255,16 @@ export default {
if (this.value.indexOf(this.SPEC) > -1) {
this.showSpecAccounts = true
}
// 是否添加虚拟账号选择
const hasVirtual = this.value.filter(i => {
return i && i.startsWith('@') && i !== '@ALL' && i !== '@SPEC'
})
if (hasVirtual.length > 0 && !choicesSelected.includes(this.VIRTUAL)) {
this.choicesSelected = [...choicesSelected, this.VIRTUAL]
}
// 如果没有就设置 ALL
if (choicesSelected.length === 0) {
choicesSelected.push(this.ALL)
}
@@ -260,9 +292,12 @@ export default {
}
if (item.value === this.ALL) {
this.choicesSelected = this.choicesSelected.filter(i => i !== this.SPEC)
}
if (item.value === this.SPEC) {
} else if (item.value === this.SPEC) {
this.choicesSelected = this.choicesSelected.filter(i => i !== this.ALL)
} else if (item.value === this.VIRTUAL) {
if (!checked) {
this.choicesSelected = this.choicesSelected.filter(i => !this.virtualAccountsNames.includes(i))
}
}
this.outputValue()
},
@@ -290,13 +325,9 @@ export default {
.spec-accounts {
::v-deep {
.el-select {
.filter-field {
width: 100%;
margin-bottom: 3px;
}
.help-block {
display: block !important;
margin-bottom: 3px !important;
}
}
}
@@ -307,23 +338,19 @@ export default {
}
.group-title {
font-size: 12px;
font-size: 13px;
color: var(--color-text-secondary);
//border-bottom: dashed 1px var(--color-border);
margin-top: 5px;
font-weight: 500;
}
.account-content {
::v-deep {
.el-form-item__content {
width: 90% !important;
}
}
}
//::v-deep .el-checkbox-group {
// display: grid;
// grid-template-columns: repeat(3, 1fr);
//}
//
//::v-deep .el-checkbox-group label:nth-child(1),
//::v-deep .el-checkbox-group label:nth-child(2) {
// grid-row: 1 / 2;
//}
//
//::v-deep .el-checkbox-group label:nth-child(3),
//::v-deep .el-checkbox-group label:nth-child(4),
//::v-deep .el-checkbox-group label:nth-child(5) {
// grid-row: 2 / 3;
//}
</style>

View File

@@ -1,263 +0,0 @@
<template>
<el-form @submit.native.prevent>
<el-form-item>
<el-radio-group v-model="choiceSelected" @input="handleRadioCheck">
<el-radio
v-for="(i) in choices"
:key="i.label"
:label="i.value"
>
{{ i.label }}
<el-tooltip :content="i.tip" :open-delay="500" placement="top">
<i class="fa fa-question-circle-o" />
</el-tooltip>
</el-radio>
</el-radio-group>
<div v-if="showSpecAccounts" class="spec-accounts">
<TagInput
:autocomplete="autocomplete"
:tag-type="getTagType"
:value="specAccountsInput"
@change="handleTagChange"
/>
<span v-if="showAddTemplate">
<el-button size="mini" type="primary" @click="showTemplateDialog=true">
{{ $t('TemplateAdd') }}
</el-button>
<span class="help-block" style="display: inline">
{{ addTemplateHelpText }}
</span>
</span>
</div>
</el-form-item>
<Dialog
v-if="showTemplateDialog"
:title="$tc('AccountTemplate')"
:visible.sync="showTemplateDialog"
@cancel="handleAccountTemplateCancel"
@confirm="handleAccountTemplateConfirm"
>
<ListTable ref="templateTable" v-bind="accountTemplateTable" />
</Dialog>
</el-form>
</template>
<script>
import { TagInput } from '@/components/Form/FormFields'
import { AccountLabelMapper, AllAccount, SpecAccount } from '@/views/perms/const'
import ListTable from '@/components/Table/ListTable'
import Dialog from '@/components/Dialog'
export default {
components: {
TagInput,
ListTable,
Dialog
},
props: {
value: {
type: [Array, String],
default: () => []
},
assets: {
type: [Array],
default: () => []
},
nodes: {
type: [Array],
default: () => []
},
oid: {
type: String,
default: ''
},
showAddTemplate: {
type: Boolean,
default: true
},
addTemplateHelpText: {
type: String,
default() {
return this.$t('TemplateHelpText')
}
}
},
data() {
const vm = this
const choices = [
{
label: AccountLabelMapper[AllAccount],
value: AllAccount,
tip: this.$t('AllAccountTip')
},
{
label: AccountLabelMapper[SpecAccount],
value: SpecAccount,
tip: this.$t('SpecAccountTip')
}
]
return {
ALL: AllAccount,
SPEC: SpecAccount,
showTemplateDialog: false,
choices: choices,
choiceSelected: this.ALL,
specAccountsInput: [],
specAccountsTemplate: [],
showSpecAccounts: false,
getTagType: (tag) => {
if (vm.specAccountsTemplate.filter(i => i.username === tag).length > 0) {
return 'primary'
} else {
return 'info'
}
},
accountTemplateTable: {
tableConfig: {
url: '/api/v1/accounts/account-templates/',
columns: [
'name', 'username', 'has_secret', 'comment'
],
columnsMeta: {
name: {
formatterArgs: {
openInNewPage: true,
getRoute({ row, col, cellValue }) {
return {
name: 'AccountTemplateDetail',
params: {
id: row.id
}
}
}
}
},
has_secret: {
formatterArgs: {
showFalse: false
}
},
actions: {
has: false
}
}
},
headerActions: {
hasLeftActions: false,
hasImport: false,
hasExport: false
}
},
autocomplete: (query, cb) => {
const data = {
username: query,
assets: this.assets.slice(0, 20),
nodes: this.nodes.slice(0, 20).map(item => {
return typeof item === 'object' ? item.pk : item
})
}
this.$axios.post(
'/api/v1/accounts/accounts/username-suggestions/',
data, { params: { oid: this.oid }}
).then(res => {
if (!res) res = []
const data = res
.filter(item => vm.value.indexOf(item) === -1)
.map(v => ({ value: v, label: v }))
cb(data)
})
}
}
},
mounted() {
this.initDefaultChoice()
},
methods: {
initDefaultChoice() {
this.choiceSelected = this.value.indexOf(this.ALL) >= 0 ? this.ALL : this.SPEC
this.specAccountsInput = this.value.filter(i => !i.startsWith('@'))
if (this.choiceSelected === this.SPEC) {
this.showSpecAccounts = true
}
},
handleAccountTemplateCancel() {
this.showTemplateDialog = false
},
handleAccountTemplateConfirm() {
this.specAccountsTemplate = this.$refs.templateTable.selectedRows
const added = this.specAccountsTemplate.map(i => i.username)
this.specAccountsInput = this.specAccountsInput.filter(i => !added.includes(i)).concat(added)
this.outputValue()
setTimeout(() => {
this.showTemplateDialog = false
this.outputValue()
}, 100)
},
handleRadioCheck(item) {
this.showSpecAccounts = item === this.SPEC
this.outputValue()
},
handleTagChange(val) {
this.specAccountsInput = val
this.outputValue()
},
outputValue() {
let choicesSelected = []
if (this.choiceSelected === this.ALL) {
choicesSelected = [this.ALL]
} else {
const templateIds = this.specAccountsTemplate.map(i => `%${i.id}`)
choicesSelected = [...this.specAccountsInput, ...templateIds]
}
this.$emit('input', choicesSelected)
this.$emit('change', choicesSelected)
}
}
}
</script>
<style lang="scss" scoped>
.select ::v-deep .el-input.el-input--suffix {
width: 100px
}
.spec-accounts {
::v-deep {
.el-select {
width: 100%;
margin-bottom: 3px;
}
.help-block {
display: block !important;
}
}
}
.help-text {
font-size: 12px;
color: #999999;
}
.group-title {
font-size: 12px;
color: var(--color-text-secondary);
}
//::v-deep .el-checkbox-group {
// display: grid;
// grid-template-columns: repeat(3, 1fr);
//}
//
//::v-deep .el-checkbox-group label:nth-child(1),
//::v-deep .el-checkbox-group label:nth-child(2) {
// grid-row: 1 / 2;
//}
//
//::v-deep .el-checkbox-group label:nth-child(3),
//::v-deep .el-checkbox-group label:nth-child(4),
//::v-deep .el-checkbox-group label:nth-child(5) {
// grid-row: 2 / 3;
//}
</style>

View File

@@ -1,106 +0,0 @@
<template>
<el-form @submit.native.prevent>
<el-form-item>
<el-checkbox-group v-model="choicesSelected">
<el-checkbox
v-for="(i) in choices"
:key="i.label"
:label="i.value"
@change="handleCheckboxCheck(i, $event)"
>
{{ i.label }}
<el-tooltip :content="i.tip" :open-delay="500" placement="top">
<i class="fa fa-question-circle-o" />
</el-tooltip>
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
</template>
<script>
import { AccountLabelMapper, AnonymousAccount, ManualAccount, SameAccount } from '@/views/perms/const'
export default {
components: {},
props: {
value: {
type: [Array, String],
default: () => []
}
},
data() {
const choices = [
{
label: AccountLabelMapper[ManualAccount],
value: ManualAccount,
tip: this.$t('ManualAccountTip')
},
{
label: AccountLabelMapper[SameAccount],
value: SameAccount,
tip: this.$t('SameAccountTip')
},
{
label: AccountLabelMapper[AnonymousAccount],
value: AnonymousAccount,
tip: this.$t('AnonymousAccountTip')
}
]
return {
choices: choices,
choicesSelected: []
}
},
mounted() {
this.initDefaultChoice()
},
methods: {
initDefaultChoice() {
this.choicesSelected = this.value.filter(i => {
return i.startsWith('@')
}).filter(i => {
return !['@ALL', '@SPEC'].includes(i)
})
},
handleCheckboxCheck() {
this.outputValue()
},
outputValue() {
console.log('outputValue', this.choicesSelected)
this.$emit('input', this.choicesSelected)
this.$emit('change', this.choicesSelected)
}
}
}
</script>
<style lang="scss" scoped>
.select ::v-deep .el-input.el-input--suffix {
width: 100px
}
.spec-accounts {
::v-deep {
.el-select {
width: 100%;
margin-bottom: 3px;
}
.help-block {
display: block !important;
}
}
}
.help-text {
font-size: 12px;
color: #999999;
}
.group-title {
font-size: 12px;
color: var(--color-text-secondary);
}
</style>