mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-14 14:19:16 +00:00
@@ -792,6 +792,9 @@
|
|||||||
"OrgUser": "组织用户",
|
"OrgUser": "组织用户",
|
||||||
"OrgAdmin": "组织管理员",
|
"OrgAdmin": "组织管理员",
|
||||||
"OrgAuditor": "组织审计员",
|
"OrgAuditor": "组织审计员",
|
||||||
|
"InviteUser": "邀请用户",
|
||||||
|
"Invite": "邀请",
|
||||||
|
"InviteUserInOrg": "邀请用户加入此组织",
|
||||||
"Guide": "向导",
|
"Guide": "向导",
|
||||||
"HelpText": {
|
"HelpText": {
|
||||||
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!",
|
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!",
|
||||||
|
@@ -787,10 +787,14 @@
|
|||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"FingerPrint": "Fingerprint",
|
"FingerPrint": "Fingerprint",
|
||||||
"FirstLogin": "First login",
|
"FirstLogin": "First login",
|
||||||
|
"InviteUser": "Invite user",
|
||||||
|
"InviteUserInOrg": "Invite user in this org",
|
||||||
|
"Invite": "Invite",
|
||||||
"Guide": "Guide",
|
"Guide": "Guide",
|
||||||
"OrgUser": "Org User",
|
"OrgUser": "Org User",
|
||||||
"OrgAdmin": "Org Admin",
|
"OrgAdmin": "Org Admin",
|
||||||
"OrgAuditor": "Org Auditor",
|
"OrgAuditor": "Org Auditor",
|
||||||
|
|
||||||
"HelpText": {
|
"HelpText": {
|
||||||
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "Enable multi-factor authentication to make the account more secure <br/> After is enabled, you will enter the multi-factor authentication binding process on your next login <br/> You can also bind directly in (personal information -> fast modifier -> modifier multiple factor Settings)",
|
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "Enable multi-factor authentication to make the account more secure <br/> After is enabled, you will enter the multi-factor authentication binding process on your next login <br/> You can also bind directly in (personal information -> fast modifier -> modifier multiple factor Settings)",
|
||||||
"MFAOfUserFirstLoginUserGuidePage": "To protect the security of you and the company <br/> please properly keep your account, password, key and other important and sensitive information <br/> (e.g., set a complex password and enable multi-factor authentication)",
|
"MFAOfUserFirstLoginUserGuidePage": "To protect the security of you and the company <br/> please properly keep your account, password, key and other important and sensitive information <br/> (e.g., set a complex password and enable multi-factor authentication)",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Page v-bind="$attrs">
|
<Page v-bind="$attrs">
|
||||||
<ListTable v-bind="$attrs" />
|
<ListTable ref="ListTable" v-bind="$attrs" />
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@@ -1,11 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
<GenericListPage
|
||||||
|
ref="GenericListPage"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:header-actions="headerActions"
|
||||||
|
/>
|
||||||
<GenericUpdateFormDialog
|
<GenericUpdateFormDialog
|
||||||
:selected-rows="updateSelectedDialogSetting.selectedRows"
|
:selected-rows="updateSelectedDialogSetting.selectedRows"
|
||||||
:form-setting="updateSelectedDialogSetting.formSetting"
|
:form-setting="updateSelectedDialogSetting.formSetting"
|
||||||
:dialog-setting="updateSelectedDialogSetting.dialogSetting"
|
:dialog-setting="updateSelectedDialogSetting.dialogSetting"
|
||||||
/>
|
/>
|
||||||
|
<InviteUsersDialog :setting="InviteDialogSetting" @close="handleInviteDialogClose" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -15,9 +20,11 @@ import { GenericListPage } from '@/layout/components'
|
|||||||
import { GenericUpdateFormDialog } from '@/layout/components'
|
import { GenericUpdateFormDialog } from '@/layout/components'
|
||||||
import { createSourceIdCache } from '@/api/common'
|
import { createSourceIdCache } from '@/api/common'
|
||||||
import { getDayFuture } from '@/utils/common'
|
import { getDayFuture } from '@/utils/common'
|
||||||
|
import InviteUsersDialog from '@/views/users/User/components/InviteUsersDialog'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
InviteUsersDialog,
|
||||||
GenericListPage,
|
GenericListPage,
|
||||||
GenericUpdateFormDialog
|
GenericUpdateFormDialog
|
||||||
},
|
},
|
||||||
@@ -27,7 +34,13 @@ export default {
|
|||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: '/api/v1/users/users/',
|
url: '/api/v1/users/users/',
|
||||||
columns: [
|
columns: [
|
||||||
'name', 'username', 'groups_display', 'total_role_display', 'source', 'is_valid', 'actions'
|
'name',
|
||||||
|
'username',
|
||||||
|
'groups_display',
|
||||||
|
'total_role_display',
|
||||||
|
'source',
|
||||||
|
'is_valid',
|
||||||
|
'actions'
|
||||||
],
|
],
|
||||||
columnsMeta: {
|
columnsMeta: {
|
||||||
username: {
|
username: {
|
||||||
@@ -70,6 +83,17 @@ export default {
|
|||||||
},
|
},
|
||||||
headerActions: {
|
headerActions: {
|
||||||
hasBulkDelete: false,
|
hasBulkDelete: false,
|
||||||
|
extraActions: [
|
||||||
|
{
|
||||||
|
name: this.$t('users.InviteUser'),
|
||||||
|
title: this.$t('users.InviteUser'),
|
||||||
|
can:
|
||||||
|
(JSON.parse(this.$cookie.get('jms_current_org'))
|
||||||
|
? JSON.parse(this.$cookie.get('jms_current_org')).id
|
||||||
|
: '') !== 'DEFAULT',
|
||||||
|
callback: function() { this.InviteDialogSetting.InviteDialogVisible = true }.bind(this)
|
||||||
|
}
|
||||||
|
],
|
||||||
extraMoreActions: [
|
extraMoreActions: [
|
||||||
{
|
{
|
||||||
title: this.$t('common.deleteSelected'),
|
title: this.$t('common.deleteSelected'),
|
||||||
@@ -135,9 +159,7 @@ export default {
|
|||||||
initial: {
|
initial: {
|
||||||
date_expired: getDayFuture(36500, new Date()).toISOString()
|
date_expired: getDayFuture(36500, new Date()).toISOString()
|
||||||
},
|
},
|
||||||
fields: [
|
fields: ['groups', 'date_expired', 'comment'],
|
||||||
'groups', 'date_expired', 'comment'
|
|
||||||
],
|
|
||||||
url: '/api/v1/users/users/',
|
url: '/api/v1/users/users/',
|
||||||
fieldsMeta: {
|
fieldsMeta: {
|
||||||
groups: {
|
groups: {
|
||||||
@@ -154,36 +176,36 @@ export default {
|
|||||||
date_expired: {
|
date_expired: {
|
||||||
label: this.$t('common.dateExpired'),
|
label: this.$t('common.dateExpired'),
|
||||||
hidden: () => false
|
hidden: () => false
|
||||||
|
|
||||||
},
|
},
|
||||||
comment: {
|
comment: {
|
||||||
label: this.$t('common.Comment'),
|
label: this.$t('common.Comment'),
|
||||||
hidden: () => false
|
hidden: () => false
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
InviteDialogSetting: {
|
||||||
|
InviteDialogVisible: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters(['currentOrg', 'currentUser', 'device']),
|
||||||
'currentOrg',
|
|
||||||
'currentUser',
|
|
||||||
'device'
|
|
||||||
]),
|
|
||||||
currentOrgIsDefault() {
|
currentOrgIsDefault() {
|
||||||
return this.currentOrg.id === 'DEFAULT' || this.currentOrg.id === ''
|
return this.currentOrg.id === 'DEFAULT' || this.currentOrg.id === ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (!this.currentOrgIsDefault) {
|
if (!this.currentOrgIsDefault) {
|
||||||
this.headerActions.extraMoreActions[0].title = this.$t('common.removeSelected')
|
this.headerActions.extraMoreActions[0].title = this.$t(
|
||||||
|
'common.removeSelected'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
removeUserFromOrg({ row, col, reload }) {
|
removeUserFromOrg({ row, col, reload }) {
|
||||||
const msg = this.$t('users.removeFromOrgWarningMsg') + ' "' + row.name + '"'
|
const msg =
|
||||||
|
this.$t('users.removeFromOrgWarningMsg') + ' "' + row.name + '"'
|
||||||
const title = this.$t('common.Info')
|
const title = this.$t('common.Info')
|
||||||
const performDelete = function() {
|
const performDelete = function() {
|
||||||
const url = `/api/v1/users/users/${row.id}/`
|
const url = `/api/v1/users/users/${row.id}/`
|
||||||
@@ -214,7 +236,13 @@ export default {
|
|||||||
if (!this.currentOrgIsDefault) {
|
if (!this.currentOrgIsDefault) {
|
||||||
msgPrefix = this.$t('common.removeWarningMsg')
|
msgPrefix = this.$t('common.removeWarningMsg')
|
||||||
}
|
}
|
||||||
const msg = msgPrefix + ' ' + selectedRows.length + ' ' + this.$t('common.rows') + ' ?'
|
const msg =
|
||||||
|
msgPrefix +
|
||||||
|
' ' +
|
||||||
|
selectedRows.length +
|
||||||
|
' ' +
|
||||||
|
this.$t('common.rows') +
|
||||||
|
' ?'
|
||||||
const title = this.$t('common.Info')
|
const title = this.$t('common.Info')
|
||||||
const performDelete = this.performBulkDelete
|
const performDelete = this.performBulkDelete
|
||||||
this.$alert(msg, title, {
|
this.$alert(msg, title, {
|
||||||
@@ -248,17 +276,30 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
async performBulkDelete(selectedRows) {
|
async performBulkDelete(selectedRows) {
|
||||||
const ids = selectedRows.map((v) => {
|
const ids = selectedRows.map(v => {
|
||||||
return v.id
|
return v.id
|
||||||
})
|
})
|
||||||
const data = await createSourceIdCache(ids)
|
const data = await createSourceIdCache(ids)
|
||||||
const url = `${this.tableConfig.url}?spm=` + data.spm
|
const url = `${this.tableConfig.url}?spm=` + data.spm
|
||||||
return this.$axios.delete(url)
|
return this.$axios.delete(url)
|
||||||
|
},
|
||||||
|
handleInviteDialogClose() {
|
||||||
|
this.InviteDialogSetting.InviteDialogVisible = false
|
||||||
|
this.$refs.GenericListPage.$refs.ListTable.reloadTable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.asset-select-dialog ::v-deep .transition-box:first-child {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
}
|
||||||
|
.dialog ::v-deep .el-input {
|
||||||
|
width: 25.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog ::v-deep .el-dialog__footer {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
154
src/views/users/User/components/InviteUsersDialog.vue
Normal file
154
src/views/users/User/components/InviteUsersDialog.vue
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog
|
||||||
|
v-if="setting.InviteDialogVisible"
|
||||||
|
:title="this.$t('users.InviteUserInOrg')"
|
||||||
|
:visible.sync="setting.InviteDialogVisible"
|
||||||
|
custom-class="asset-select-dialog"
|
||||||
|
:show-cancel="false"
|
||||||
|
:show-confirm="false"
|
||||||
|
width="28%"
|
||||||
|
top="15vh"
|
||||||
|
after
|
||||||
|
:destroy-on-close="true"
|
||||||
|
@close="clearSelect"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
v-model="InviteValue"
|
||||||
|
multiple
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
size="small"
|
||||||
|
reserve-keyword
|
||||||
|
:placeholder="this.$t('setting.usernamePlaceholder')"
|
||||||
|
:remote-method="remoteMethod"
|
||||||
|
:loading="selectLoading"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in InviteOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-collapse-transition>
|
||||||
|
<div
|
||||||
|
v-if="InviteValue.length > 0"
|
||||||
|
style="margin-top:15px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction:column;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:center;"
|
||||||
|
>
|
||||||
|
<el-checkbox-group
|
||||||
|
v-model="rulesList"
|
||||||
|
size="small"
|
||||||
|
style="display: flex;
|
||||||
|
flex-direction:row;
|
||||||
|
justify-content:center;"
|
||||||
|
>
|
||||||
|
<el-checkbox label="User" checked>{{ $t('users.OrgUser') }}</el-checkbox>
|
||||||
|
<el-checkbox label="Auditor">{{ $t('users.OrgAuditor') }}</el-checkbox>
|
||||||
|
<el-checkbox label="Admin">{{ $t('users.OrgAdmin') }}</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:loading="InviteLoading"
|
||||||
|
size="small"
|
||||||
|
style="margin-top: 20px;width: 10vw"
|
||||||
|
@click="InviteConfirm"
|
||||||
|
>{{ $t('users.Invite') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-collapse-transition>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Dialog from '@/components/Dialog'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Dialog
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
setting: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return { InviteDialogVisible: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectLoading: false,
|
||||||
|
InviteLoading: false,
|
||||||
|
InviteOptions: [],
|
||||||
|
InviteValue: [],
|
||||||
|
rulesList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['currentOrg', 'currentUser', 'device'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
remoteMethod(query) {
|
||||||
|
if (query !== '') {
|
||||||
|
this.InviteOptions = []
|
||||||
|
this.selectLoading = true
|
||||||
|
this.$axios
|
||||||
|
.get(` /api/v1/users/users/?search=${query}&all=1`)
|
||||||
|
.then(result => {
|
||||||
|
console.log(result)
|
||||||
|
for (let i = 0; i < result.length; i++) {
|
||||||
|
this.InviteOptions.push({
|
||||||
|
value: result[i].id,
|
||||||
|
label: result[i].name + '(' + result[i].username + ')'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.selectLoading = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.InviteOptions = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearSelect() {
|
||||||
|
this.InviteValue = []
|
||||||
|
this.rulesList = []
|
||||||
|
this.InviteOptions = []
|
||||||
|
},
|
||||||
|
InviteConfirm() {
|
||||||
|
this.InviteLoading = true
|
||||||
|
const data = []
|
||||||
|
for (const rule of this.rulesList) {
|
||||||
|
for (const user of this.InviteValue) {
|
||||||
|
data.push({
|
||||||
|
org: this.currentOrg.id,
|
||||||
|
user: user,
|
||||||
|
role: rule
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$axios.post(`/api/v1/orgs/org-memeber-relation/?org_id=${this.currentOrg.id}&ignore_already_exist=1`, data).then(() => {
|
||||||
|
this.$message.success(this.$t('common.AddSuccessMsg'))
|
||||||
|
}).finally(() => {
|
||||||
|
this.InviteLoading = false
|
||||||
|
this.clearSelect()
|
||||||
|
this.$emit('close')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.dialog ::v-deep .el-input {
|
||||||
|
width: 25.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog ::v-deep .el-dialog__footer {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
Reference in New Issue
Block a user