feat: 添加邀请用户进入组织功能 (#411)

* feat: 添加邀请用户进入组织功能
This commit is contained in:
Orange
2020-09-29 15:10:48 +08:00
committed by GitHub
parent ad88daef9a
commit 30143f833a
5 changed files with 219 additions and 17 deletions

View File

@@ -792,6 +792,9 @@
"OrgUser": "组织用户", "OrgUser": "组织用户",
"OrgAdmin": "组织管理员", "OrgAdmin": "组织管理员",
"OrgAuditor": "组织审计员", "OrgAuditor": "组织审计员",
"InviteUser": "邀请用户",
"Invite": "邀请",
"InviteUserInOrg": "邀请用户加入此组织",
"Guide": "向导", "Guide": "向导",
"HelpText": { "HelpText": {
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!", "MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!",

View File

@@ -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)",

View File

@@ -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>

View File

@@ -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>

View 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>