mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-25 14:34:46 +00:00
perf: asset permission set
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
:is="component"
|
||||
ref="SearchInput"
|
||||
v-model.trim="filterValue"
|
||||
:fetch-suggestions="autocomplete"
|
||||
:fetch-suggestions="autocomplete ? autocomplete : () => {}"
|
||||
:placeholder="iPlaceholder"
|
||||
:type="inputType"
|
||||
class="search-input"
|
||||
@@ -78,16 +78,18 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterTags: this.value,
|
||||
focus: false,
|
||||
filterValue: '',
|
||||
isCheckShowPassword: this.replaceShowPassword,
|
||||
component: this.autocomplete ? 'el-autocomplete' : 'el-input'
|
||||
filterTags: this.value,
|
||||
isCheckShowPassword: this.replaceShowPassword
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iPlaceholder() {
|
||||
return `${this.placeholder} (${this.$t('EnterToContinue')})`
|
||||
},
|
||||
component() {
|
||||
return this.autocomplete !== null ? 'el-autocomplete' : 'el-input'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -98,7 +100,7 @@ export default {
|
||||
methods: {
|
||||
handleTagClose(tag) {
|
||||
this.filterTags.splice(this.filterTags.indexOf(tag), 1)
|
||||
this.$emit('change', this.filterTags)
|
||||
this.handleConfirm()
|
||||
},
|
||||
handleSelect(item) {
|
||||
this.filterValue = item.value
|
||||
@@ -113,14 +115,15 @@ export default {
|
||||
if (!this.filterTags.includes(this.filterValue)) {
|
||||
this.filterTags.push(this.filterValue)
|
||||
this.filterValue = ''
|
||||
this.$emit('change', this.filterTags)
|
||||
}
|
||||
this.$refs.SearchInput.focus()
|
||||
this.$emit('change', this.filterTags)
|
||||
this.$emit('input', this.filterTags)
|
||||
// this.$refs.SearchInput.focus()
|
||||
},
|
||||
handleTagClick(v, k) {
|
||||
this.$delete(this.filterTags, k)
|
||||
this.filterValue = v
|
||||
this.$refs.SearchInput.focus()
|
||||
// this.$refs.SearchInput.focus()
|
||||
},
|
||||
matchRule(value) {
|
||||
const regex = new RegExp(this.replaceRule)
|
||||
@@ -189,7 +192,7 @@ export default {
|
||||
}
|
||||
|
||||
.filter-field ::v-deep .el-input__inner {
|
||||
height: 28px !important;
|
||||
height: 27px !important;
|
||||
}
|
||||
|
||||
.show-password {
|
||||
|
||||
@@ -1,53 +1,59 @@
|
||||
<template>
|
||||
<el-form class="account-content" @submit.native.prevent>
|
||||
<el-form-item>
|
||||
<el-checkbox-group v-model="choicesSelected">
|
||||
<el-checkbox
|
||||
v-for="(i) in choices"
|
||||
<el-radio-group v-model="realRadioSelected" @input="handleRadioChanged">
|
||||
<el-radio
|
||||
v-for="(i) in realChoices"
|
||||
:key="i.label"
|
||||
:disabled="i.disabled"
|
||||
: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-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<div v-if="showSpecAccounts" class="spec-accounts spec-zone">
|
||||
<div class="group-title">{{ $t('SpecAccount') }}</div>
|
||||
<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">
|
||||
{{ addTemplateHelpText }}
|
||||
</span>
|
||||
<div v-if="showSpecAccounts" class="spec-accounts spec-zone">
|
||||
<div class="group-title">{{ $t('SpecAccount') }}</div>
|
||||
<TagInput
|
||||
v-model="specAccountsInput"
|
||||
:autocomplete="autocomplete"
|
||||
:tag-type="getTagType"
|
||||
@change="handleTagChange"
|
||||
/>
|
||||
<span v-if="showAddTemplate">
|
||||
<el-button size="mini" type="primary" @click="showTemplateDialog=true">
|
||||
{{ $t('TemplateAdd') }}
|
||||
</el-button>
|
||||
<span class="help-block">
|
||||
{{ addTemplateHelpText }}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="showVirtualAccountCheckbox" class="spec-zone">
|
||||
<div class="group-title">{{ $t('VirtualAccounts') }}</div>
|
||||
<el-checkbox
|
||||
<div v-if="showNotAccounts" class="not-accounts spec-zone">
|
||||
<div class="group-title">{{ $t('ExcludeAccount') }}</div>
|
||||
<TagInput v-model="excludeAccountsInput" @change="handleTagChange" />
|
||||
</div>
|
||||
|
||||
<div v-if="showVirtualAccount" class="spec-zone virtual-choices">
|
||||
<el-checkbox v-model="virtualChecked"> Virtual Account</el-checkbox>
|
||||
<el-select v-model="virtualSelected" :multiple="true" @change="handleVirtualChecked">
|
||||
<el-option
|
||||
v-for="i in virtualAccounts"
|
||||
:key="i.label"
|
||||
:label="i.value"
|
||||
@change="handleCheckboxCheck(i, $event)"
|
||||
:label="i.label"
|
||||
:value="i.value"
|
||||
>
|
||||
{{ 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-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<Dialog
|
||||
@@ -65,12 +71,15 @@
|
||||
<script>
|
||||
import { TagInput } from '@/components/Form/FormFields'
|
||||
import {
|
||||
AccountLabelMapper,
|
||||
accountTemplateTable,
|
||||
AllAccount,
|
||||
AnonymousAccount,
|
||||
ManualAccount,
|
||||
NotAccount,
|
||||
realChoices,
|
||||
SameAccount,
|
||||
SpecAccount
|
||||
SpecAccount,
|
||||
virtualAccounts
|
||||
} from '@/views/perms/const'
|
||||
import ListTable from '@/components/Table/ListTable'
|
||||
import Dialog from '@/components/Dialog'
|
||||
@@ -116,50 +125,20 @@ export default {
|
||||
data() {
|
||||
const vm = this
|
||||
const virtual = '@VIRTUAL'
|
||||
const choices = [
|
||||
{
|
||||
label: AccountLabelMapper[AllAccount],
|
||||
value: AllAccount,
|
||||
tip: this.$t('AllAccountTip')
|
||||
},
|
||||
{
|
||||
label: AccountLabelMapper[SpecAccount],
|
||||
value: SpecAccount,
|
||||
tip: this.$t('SpecAccountTip')
|
||||
},
|
||||
{
|
||||
label: this.$t('VirtualAccounts'),
|
||||
value: virtual,
|
||||
tip: this.$t('VirtualAccountHelpMsg'),
|
||||
disabled: !this.showVirtualAccount,
|
||||
has: this.showVirtualAccount !== false
|
||||
}
|
||||
]
|
||||
return {
|
||||
ALL: AllAccount,
|
||||
SPEC: SpecAccount,
|
||||
VIRTUAL: virtual,
|
||||
EXCLUDE: NotAccount,
|
||||
showTemplateDialog: false,
|
||||
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')
|
||||
}
|
||||
],
|
||||
realRadioSelected: this.ALL,
|
||||
realChoices: realChoices,
|
||||
virtualChecked: false,
|
||||
virtualSelected: [],
|
||||
output: [],
|
||||
excludeAccountsInput: [],
|
||||
virtualAccounts: virtualAccounts,
|
||||
virtualAccountsNames: [ManualAccount, SameAccount, AnonymousAccount],
|
||||
choicesSelected: [this.ALL],
|
||||
specAccountsInput: [],
|
||||
specAccountsTemplate: [],
|
||||
showSpecAccounts: false,
|
||||
@@ -170,43 +149,8 @@ export default {
|
||||
return 'info'
|
||||
}
|
||||
},
|
||||
accountTemplateTable: {
|
||||
tableConfig: {
|
||||
url: '/api/v1/accounts/account-templates/',
|
||||
columns: [
|
||||
'name', 'username', 'has_secret', 'comment',
|
||||
'date_created', 'date_updated'
|
||||
],
|
||||
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
|
||||
}
|
||||
},
|
||||
showNotAccounts: false,
|
||||
accountTemplateTable: accountTemplateTable,
|
||||
autocomplete: (query, cb) => {
|
||||
const data = {
|
||||
username: query,
|
||||
@@ -228,52 +172,55 @@ 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
|
||||
watch: {
|
||||
realRadioSelected(val) {
|
||||
this.showSpecAccounts = val === this.SPEC
|
||||
this.showNotAccounts = val === this.EXCLUDE
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initDefaultChoice()
|
||||
setTimeout(() => {
|
||||
if (this.value.length === 0) {
|
||||
this.$emit('input', ['@ALL'])
|
||||
} else {
|
||||
this.$emit('input', this.value)
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getVirtualChoices(val) {
|
||||
return this.virtualAccounts.filter(i => {
|
||||
return val.includes(i.value)
|
||||
}).map(i => i.value)
|
||||
},
|
||||
getExcludeChoices(val) {
|
||||
return val.filter(i => i.startsWith('!')).map(i => i.substring(1))
|
||||
},
|
||||
getSpecValues(val) {
|
||||
return val.filter(i => !i.startsWith('@') && !i.startsWith('!'))
|
||||
},
|
||||
initDefaultChoice() {
|
||||
const choicesSelected = this.value.filter(i => {
|
||||
return i.startsWith('@') && i !== this.SPEC && i !== this.VIRTUAL
|
||||
})
|
||||
// 是否添加特定账号选择
|
||||
const specAccountsInput = this.value.filter(i => !i.startsWith('@') && i !== this.SPEC)
|
||||
if (specAccountsInput.length > 0 && !choicesSelected.includes(this.ALL)) {
|
||||
choicesSelected.push(this.SPEC)
|
||||
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)) {
|
||||
choicesSelected.push(this.VIRTUAL)
|
||||
const value = this.value || []
|
||||
if (value.length === 0) {
|
||||
value.push(this.ALL)
|
||||
}
|
||||
|
||||
// 如果没有就设置 ALL
|
||||
if (choicesSelected.length === 0) {
|
||||
choicesSelected.push(this.ALL)
|
||||
const specAccountsInput = this.getSpecValues(value)
|
||||
// const excludeAccountsInput = this.getExcludeChoices(value)
|
||||
// 先清理 radio
|
||||
const isAll = value.includes(this.ALL)
|
||||
if (isAll) {
|
||||
this.realRadioSelected = this.ALL
|
||||
} else if (specAccountsInput.length > 0) {
|
||||
this.realRadioSelected = this.SPEC
|
||||
this.specAccountsInput = specAccountsInput
|
||||
// } else if (excludeAccountsInput.length > 0) {
|
||||
// this.realRadioSelected = this.EXCLUDE
|
||||
// this.excludeAccountsInput = excludeAccountsInput
|
||||
} else {
|
||||
this.realRadioSelected = this.ALL
|
||||
}
|
||||
|
||||
// 清理虚拟账号
|
||||
const virtualChoices = this.getVirtualChoices(this.value)
|
||||
if (virtualChoices.length > 0) {
|
||||
this.virtualChecked = true
|
||||
this.virtualSelected = virtualChoices
|
||||
}
|
||||
this.choicesSelected = choicesSelected
|
||||
this.specAccountsInput = specAccountsInput
|
||||
},
|
||||
handleAccountTemplateCancel() {
|
||||
this.showTemplateDialog = false
|
||||
@@ -288,33 +235,32 @@ export default {
|
||||
this.outputValue()
|
||||
}, 100)
|
||||
},
|
||||
handleCheckboxCheck(item, checked) {
|
||||
if (item.value === this.SPEC) {
|
||||
this.showSpecAccounts = checked
|
||||
} else if (item.value === this.ALL) {
|
||||
this.showSpecAccounts = checked ? false : checked
|
||||
}
|
||||
if (item.value === this.ALL) {
|
||||
this.choicesSelected = this.choicesSelected.filter(i => i !== 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))
|
||||
}
|
||||
}
|
||||
handleVirtualChecked(evt, checked) {
|
||||
this.outputValue()
|
||||
},
|
||||
handleTagChange(val) {
|
||||
this.specAccountsInput = val
|
||||
handleRadioChanged(value) {
|
||||
this.outputValue()
|
||||
},
|
||||
handleTagChange() {
|
||||
this.outputValue()
|
||||
},
|
||||
outputValue() {
|
||||
let choicesSelected = this.choicesSelected
|
||||
if (this.showSpecAccounts) {
|
||||
// 这是真是的
|
||||
let choicesSelected = []
|
||||
if (this.realRadioSelected === this.ALL) {
|
||||
choicesSelected = [this.ALL]
|
||||
} else if (this.realRadioSelected === this.SPEC && this.showSpecAccounts) {
|
||||
const templateIds = this.specAccountsTemplate.map(i => `%${i.id}`)
|
||||
choicesSelected = [...this.choicesSelected, ...this.specAccountsInput, ...templateIds]
|
||||
choicesSelected = [this.realRadioSelected, ...this.specAccountsInput, ...templateIds]
|
||||
}
|
||||
// else if (this.realRadioSelected === this.EXCLUDE && this.excludeAccountsInput) {
|
||||
// choicesSelected = [...this.excludeAccountsInput].map(i => '!' + i)
|
||||
// }
|
||||
|
||||
if (this.virtualChecked) {
|
||||
choicesSelected = [...choicesSelected, ...this.virtualSelected]
|
||||
}
|
||||
|
||||
this.$emit('input', choicesSelected)
|
||||
this.$emit('change', choicesSelected)
|
||||
}
|
||||
@@ -349,13 +295,19 @@ export default {
|
||||
|
||||
.spec-zone {
|
||||
border-bottom: dashed 1px var(--color-border);
|
||||
padding-bottom: 5px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-choices {
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.account-content {
|
||||
::v-deep {
|
||||
.el-form-item__content {
|
||||
|
||||
@@ -154,6 +154,7 @@ export const AssetPermissionListPageSearchConfigOptions = [
|
||||
|
||||
export const AllAccount = '@ALL'
|
||||
export const SpecAccount = '@SPEC'
|
||||
export const NotAccount = '@NOT'
|
||||
export const SameAccount = '@USER'
|
||||
export const ManualAccount = '@INPUT'
|
||||
export const AnonymousAccount = '@ANON'
|
||||
@@ -161,7 +162,82 @@ export const AnonymousAccount = '@ANON'
|
||||
export const AccountLabelMapper = {
|
||||
[AllAccount]: i18n.t('AllAccounts'),
|
||||
[SpecAccount]: i18n.t('SpecAccount'),
|
||||
[NotAccount]: i18n.t('ExcludeAccount'),
|
||||
[SameAccount]: i18n.t('SameAccount'),
|
||||
[ManualAccount]: i18n.t('ManualAccount'),
|
||||
[AnonymousAccount]: i18n.t('AnonymousAccount')
|
||||
}
|
||||
|
||||
export const realChoices = [
|
||||
{
|
||||
label: AccountLabelMapper[AllAccount],
|
||||
value: AllAccount,
|
||||
tip: i18n.t('AllAccountTip')
|
||||
},
|
||||
{
|
||||
label: AccountLabelMapper[SpecAccount],
|
||||
value: SpecAccount,
|
||||
tip: i18n.t('SpecAccountTip')
|
||||
}
|
||||
// {
|
||||
// label: AccountLabelMapper[NotAccount],
|
||||
// value: NotAccount,
|
||||
// tip: i18n.t('NotAccountTip')
|
||||
// }
|
||||
]
|
||||
|
||||
export const virtualAccounts = [
|
||||
{
|
||||
label: AccountLabelMapper[ManualAccount],
|
||||
value: ManualAccount,
|
||||
tip: i18n.t('ManualAccountTip')
|
||||
},
|
||||
{
|
||||
label: AccountLabelMapper[SameAccount],
|
||||
value: SameAccount,
|
||||
tip: i18n.t('SameAccountTip')
|
||||
},
|
||||
{
|
||||
label: AccountLabelMapper[AnonymousAccount],
|
||||
value: AnonymousAccount,
|
||||
tip: i18n.t('AnonymousAccountTip')
|
||||
}
|
||||
]
|
||||
|
||||
export const accountTemplateTable = {
|
||||
tableConfig: {
|
||||
url: '/api/v1/accounts/account-templates/',
|
||||
columns: [
|
||||
'name', 'username', 'has_secret', 'comment',
|
||||
'date_created', 'date_updated'
|
||||
],
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ export default {
|
||||
this.$axios.get(url).then(res => {
|
||||
return this.makeCredReq(res)
|
||||
}).then((options) => {
|
||||
if (!location.protocol.startsWith('https')) {
|
||||
if (!location.protocol.startsWith('https') && location.host !== 'localhost') {
|
||||
throw new Error(this.$tc('HTTPSRequiredForSupport'))
|
||||
}
|
||||
return navigator.credentials.create(options)
|
||||
|
||||
@@ -24,17 +24,22 @@
|
||||
style="margin-top: 15px"
|
||||
type="warning"
|
||||
/>
|
||||
<IBox v-if="!store.getters.publicSettings['PRIVACY_MODE']" :title="$tc('InformationModification')" fa="fa-edit">
|
||||
<IBox
|
||||
v-if="!store.getters.publicSettings['PRIVACY_MODE']"
|
||||
:title="$tc('InformationModification')"
|
||||
class="update-info"
|
||||
fa="fa-edit"
|
||||
>
|
||||
<table>
|
||||
<tr>
|
||||
<td> {{ $t('Phone') }}</td>
|
||||
<td>
|
||||
<td class="label"> {{ $t('Phone') }}</td>
|
||||
<td class="value">
|
||||
<PhoneInput :value="object.phone" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{ $t('WeChat') }}</td>
|
||||
<td>
|
||||
<td class="label"> {{ $t('WeChat') }}</td>
|
||||
<td class="value">
|
||||
<el-input v-model="object.wechat" />
|
||||
</td>
|
||||
</tr>
|
||||
@@ -487,6 +492,21 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.update-info {
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
.label {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.value {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user