Compare commits

...

14 Commits

Author SHA1 Message Date
ibuler
56f6c17275 perf: 优先选择上个 org 切换 2024-05-16 13:53:47 +08:00
ibuler
e1bde89b29 fix: 修复切换到全局组织回不来的问题
perf: 修改组织切换
2024-05-15 19:14:58 +08:00
feng626
e9da168c9f Merge pull request #3930 from jumpserver/pr@dev@mfa
perf: User personal settings mfa new window opens
2024-05-15 16:41:15 +08:00
feng
c19ef24ec9 perf: User personal settings mfa new window opens 2024-05-15 16:40:17 +08:00
wangruidong
fb7c4a8b2a fix: 竖屏审批工单时,动作显示不出来 2024-05-15 15:33:03 +08:00
wangruidong
428ba49f9c perf: 根据type生成导出文件名 2024-05-11 10:02:53 +08:00
ibuler
7602d6e270 fix: 修复自动切换到 root org 回不来的问题 2024-05-10 19:07:46 +08:00
wangruidong
7b62ce2d33 fix: 批量传输下载结果文件名undefined 2024-05-07 14:42:06 +08:00
jiangweidong
6ed40c45b0 perf: 云同步支持同步完成后自动删除云端已经释放的资产 2024-05-07 14:40:29 +08:00
wangruidong
31238e0398 fix: 命令存储创建es后跳转路由不对 2024-04-28 10:24:44 +08:00
wangruidong
676ac2bbf6 perf: 创建、更新用户时MFA选项根据系统设置选项进行动态渲染 2024-04-26 11:35:12 +08:00
Bai
d5415b84c9 feat: Support asset tree node drag to another one 2024-04-24 18:06:12 +08:00
Bai
5e91917ba4 perf: 优化 Web 资产详情时根据 autofill 类型返回对应的 spec_info 信息 2024-04-23 13:08:59 +08:00
zhaojisen
c4361b4c17 perf: 修复默认值相关内容,优化按钮禁用条件 2024-04-23 10:17:43 +08:00
19 changed files with 123 additions and 68 deletions

View File

@@ -106,16 +106,28 @@ export default {
if (Array.isArray(value)) { if (Array.isArray(value)) {
if (typeof value[0] === 'object') { if (typeof value[0] === 'object') {
value.forEach(item => { const firstValue = value[0]
const fieldName = `${name}.${item.name}` if (firstValue.hasOwnProperty('name')) {
if (excludes.includes(fieldName)) { value.forEach(item => {
return const fieldName = `${name}.${item.name}`
} if (excludes.includes(fieldName)) {
this.items.push({ return
key: item.label, }
value: item.value this.items.push({
key: item.label,
value: item.value
})
}) })
}) } else {
value.forEach((item, index) => {
const v = Object.entries(item).map(([key, value]) => `${key}:${value}`).join(', ')
const data = { value: v }
if (index === 0) {
data['key'] = label
}
this.items.push(data)
})
}
} else if (typeof value[0] === 'string') { } else if (typeof value[0] === 'string') {
value.forEach((item, index) => { value.forEach((item, index) => {
let data = {} let data = {}

View File

@@ -53,27 +53,34 @@ export default {
}, },
props: { props: {
boxTitle: { boxTitle: {
type: Array type: Array,
default: () => []
}, },
boxOperation: { boxOperation: {
type: Array type: Array,
default: () => []
}, },
// 地域数据 // 地域数据
dataObj: { dataObj: {
type: Object type: Object,
default: () => {}
}, },
// 已选数据 // 已选数据
selectedData: { selectedData: {
type: Array type: Array,
default: () => []
}, },
onChangeSelected: { onChangeSelected: {
type: Function type: Function,
default: () => () => {}
}, },
filterable: { filterable: {
type: Boolean type: Boolean,
default: () => false
}, },
filterPlaceholder: { filterPlaceholder: {
type: String type: String,
default: () => ''
} }
}, },
data() { data() {

View File

@@ -46,7 +46,7 @@
<div class="vip-footer"> <div class="vip-footer">
<el-button <el-button
type="text" type="text"
:disabled="selectedDistrict.length > 0 ? false : true" :disabled="selectedDistrict.length<=0"
size="small" size="small"
round round
@click="checkedSelected" @click="checkedSelected"
@@ -62,23 +62,29 @@ export default {
components: {}, components: {},
props: { props: {
title: { title: {
type: String type: String,
default: () => ''
}, },
operation: { operation: {
type: String type: String,
default: () => ''
}, },
operateId: { operateId: {
type: Number type: Number,
default: () => 0
}, },
// 区域数据 // 区域数据
districtList: { districtList: {
type: Array type: Array,
default: () => []
}, },
filterable: { filterable: {
type: Boolean type: Boolean,
default: () => false
}, },
filterPlaceholder: { filterPlaceholder: {
type: String type: String,
default: () => ''
} }
}, },
data() { data() {

View File

@@ -39,7 +39,7 @@ export default {
showRenameBtn: false, showRenameBtn: false,
drag: { drag: {
isCopy: false, isCopy: false,
isMove: false isMove: true
} }
}, },
callback: { callback: {

View File

@@ -83,7 +83,7 @@ export default {
callback: () => { callback: () => {
this.xterm.selectAll() this.xterm.selectAll()
const text = this.xterm.getSelection() const text = this.xterm.getSelection()
const filename = `shortcut_cmd_${this.$route.query?.taskId}.log` const filename = `${this.$route.query?.type}_${this.$route.query?.taskId}.log`
downloadText(text, filename) downloadText(text, filename)
} }
} }

View File

@@ -2135,7 +2135,8 @@
"passwordWillExpiredSuffixMsg": " days.Please change your password as soon as possible.", "passwordWillExpiredSuffixMsg": " days.Please change your password as soon as possible.",
"dateLastLogin": "Date last login", "dateLastLogin": "Date last login",
"AddAllMembersWarningMsg": "Are you sure you want to add all members?", "AddAllMembersWarningMsg": "Are you sure you want to add all members?",
"disallowSelfUpdateFields": "Not allowed to modify the current fields oneself" "disallowSelfUpdateFields": "Not allowed to modify the current fields oneself",
"GlobalDisableMfaMsg": "Global enforcement has been enabled"
}, },
"notifications": { "notifications": {
"MessageType": "Message Type", "MessageType": "Message Type",
@@ -2271,6 +2272,8 @@
"HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo)2. Instance name and Partial IP (instanceDemo-250.1)", "HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo)2. Instance name and Partial IP (instanceDemo-250.1)",
"IsAlwaysUpdate": "Keep assets up to date", "IsAlwaysUpdate": "Keep assets up to date",
"FullySynchronous": "Assets fully synchronized", "FullySynchronous": "Assets fully synchronized",
"ReleaseAssets": "Release assets",
"ReleaseAssetsHelpTips": "Whether to automatically delete assets synchronized through this task and released on the cloud at the end of the task",
"AccountCreate": "Create account", "AccountCreate": "Create account",
"AccountList": "Account list", "AccountList": "Account list",
"AccountUpdate": "Update account", "AccountUpdate": "Update account",

View File

@@ -2124,7 +2124,8 @@
"passwordWillExpiredPrefixMsg": "パスワードはまもなく", "passwordWillExpiredPrefixMsg": "パスワードはまもなく",
"passwordWillExpiredSuffixMsg": "期限が切れた後、できるだけ早くパスワードを変更してください。", "passwordWillExpiredSuffixMsg": "期限が切れた後、できるだけ早くパスワードを変更してください。",
"AddAllMembersWarningMsg": "すべてのメンバーを追加してもよろしいですか?", "AddAllMembersWarningMsg": "すべてのメンバーを追加してもよろしいですか?",
"disallowSelfUpdateFields": "現在のフィールドを自分で変更することは許可されていません" "disallowSelfUpdateFields": "現在のフィールドを自分で変更することは許可されていません",
"GlobalDisableMfaMsg": "グローバルでの強制が有効になっています"
}, },
"notifications": { "notifications": {
"MessageType": "メッセージタイプ", "MessageType": "メッセージタイプ",
@@ -2267,6 +2268,8 @@
"HostnameStrategy": "資産を生成するためにホスト名。例: 1. インスタンス名 (instanceDemo) 2.インスタンス名と一部IP (下位2桁) (instanceDemo-250.1)", "HostnameStrategy": "資産を生成するためにホスト名。例: 1. インスタンス名 (instanceDemo) 2.インスタンス名と一部IP (下位2桁) (instanceDemo-250.1)",
"IsAlwaysUpdate": "資産は常に最新です", "IsAlwaysUpdate": "資産は常に最新です",
"FullySynchronous": "資産完全にシンクロします", "FullySynchronous": "資産完全にシンクロします",
"ReleaseAssets": "資産の同期解放",
"ReleaseAssetsHelpTips": "タスクの終了時に、このタスクを介して同期され、クラウド上で解放された資産を自動的に削除するかどうか",
"AccountCreate": "アカウントの作成", "AccountCreate": "アカウントの作成",
"AccountList": "アカウントリスト", "AccountList": "アカウントリスト",
"AccountUpdate": "アカウントの更新", "AccountUpdate": "アカウントの更新",
@@ -2425,4 +2428,4 @@
"BindResource": "リソースを関連付ける", "BindResource": "リソースを関連付ける",
"SelectResource": "リソースを選択" "SelectResource": "リソースを選択"
} }
} }

View File

@@ -2115,7 +2115,8 @@
"passwordExpired": "密码过期了", "passwordExpired": "密码过期了",
"passwordWillExpiredPrefixMsg": "密码即将在 ", "passwordWillExpiredPrefixMsg": "密码即将在 ",
"passwordWillExpiredSuffixMsg": "天 后过期,请尽快修改您的密码。", "passwordWillExpiredSuffixMsg": "天 后过期,请尽快修改您的密码。",
"disallowSelfUpdateFields": "不允许自己修改当前字段" "disallowSelfUpdateFields": "不允许自己修改当前字段",
"GlobalDisableMfaMsg": "全局已强制开启"
}, },
"notifications": { "notifications": {
"MessageType": "消息类型", "MessageType": "消息类型",
@@ -2186,6 +2187,8 @@
"HostnameStrategy": "用于生成资产主机名。例如1. 实例名称 (instanceDemo)2. 实例名称和部分IP(后两位) (instanceDemo-250.1)", "HostnameStrategy": "用于生成资产主机名。例如1. 实例名称 (instanceDemo)2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",
"IsAlwaysUpdate": "资产保持最新", "IsAlwaysUpdate": "资产保持最新",
"FullySynchronous": "资产完全同步", "FullySynchronous": "资产完全同步",
"ReleaseAssets": "同步释放资产",
"ReleaseAssetsHelpTips": "是否在任务结束时,自动删除通过此任务同步下来且已经在云上释放的资产",
"AccountCreate": "创建账户", "AccountCreate": "创建账户",
"AccountList": "云账号", "AccountList": "云账号",
"AccountUpdate": "更新账户", "AccountUpdate": "更新账户",

View File

@@ -1,5 +1,7 @@
import { getProfile as apiGetProfile, logout } from '@/api/users' import { getProfile as apiGetProfile, logout } from '@/api/users'
import { getCurrentOrgLocal, getPreOrgLocal, getTokenFromCookie, saveCurrentOrgLocal, setPreOrgLocal } from '@/utils/auth' import {
getCurrentOrgLocal, getPreOrgLocal, getTokenFromCookie, saveCurrentOrgLocal, setPreOrgLocal
} from '@/utils/auth'
import orgUtil from '@/utils/org' import orgUtil from '@/utils/org'
import { resetRouter } from '@/router' import { resetRouter } from '@/router'
import Vue from 'vue' import Vue from 'vue'
@@ -70,7 +72,7 @@ const mutations = {
}, },
SET_CURRENT_ORG(state, org) { SET_CURRENT_ORG(state, org) {
// 系统组织和全局组织不设置成 Pre org // 系统组织和全局组织不设置成 Pre org
if (!state.currentOrg?.autoEnter) { if (!state.currentOrg?.autoEnter && !state.currentOrg?.is_root) {
state.preOrg = state.currentOrg state.preOrg = state.currentOrg
setPreOrgLocal(state.username, state.currentOrg) setPreOrgLocal(state.username, state.currentOrg)
} }
@@ -142,7 +144,7 @@ const actions = {
const systemOrg = { const systemOrg = {
id: orgUtil.SYSTEM_ORG_ID, id: orgUtil.SYSTEM_ORG_ID,
name: 'SystemSetting', name: 'SystemSetting',
autoEnter: true autoEnter: new Date().getTime()
} }
commit('SET_CURRENT_ORG', systemOrg) commit('SET_CURRENT_ORG', systemOrg)
}, },
@@ -157,7 +159,8 @@ const actions = {
const globalOrg = { const globalOrg = {
id: orgUtil.GLOBAL_ORG_ID, id: orgUtil.GLOBAL_ORG_ID,
name: 'Global', name: 'Global',
autoEnter: true is_root: true,
autoEnter: new Date().getTime()
} }
commit('SET_CURRENT_ORG', globalOrg) commit('SET_CURRENT_ORG', globalOrg)
}, },

View File

@@ -8,6 +8,11 @@ export const GLOBAL_ORG_ID = '00000000-0000-0000-0000-000000000000'
function getPropOrg() { function getPropOrg() {
const orgs = store.getters.usingOrgs const orgs = store.getters.usingOrgs
const preOrg = store.getters.preOrg || {}
const preFound = orgs.find((item) => item.id === preOrg.id)
if (preFound) {
return preFound
}
const defaultOrg = orgs.find((item) => item.is_default) const defaultOrg = orgs.find((item) => item.is_default)
if (defaultOrg) { if (defaultOrg) {
return defaultOrg return defaultOrg
@@ -62,7 +67,7 @@ async function changeOrg(org, reload = true, vm = null) {
} }
} }
location.hash = '#' + path location.hash = '#' + path
setTimeout(() => location.reload(), 400) setTimeout(() => location.reload(), 500)
} }
function hasCurrentOrgPermission() { function hasCurrentOrgPermission() {

View File

@@ -8,6 +8,7 @@ import orgs from '@/api/orgs'
import { getPropView, isViewHasOrgs } from '@/utils/jms' import { getPropView, isViewHasOrgs } from '@/utils/jms'
const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist
const autoEnterOrgs = ['00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000000']
function reject(msg) { function reject(msg) {
return new Promise((resolve, reject) => reject(msg)) return new Promise((resolve, reject) => reject(msg))
@@ -42,6 +43,10 @@ async function getPublicSetting({ to, from, next }, isOpen) {
async function refreshCurrentOrg() { async function refreshCurrentOrg() {
return orgs.getCurrentOrg().then(org => { return orgs.getCurrentOrg().then(org => {
// Root 就不刷新本地的了, 会影响 autoEnter
if (autoEnterOrgs.indexOf(org.id) !== -1) {
return
}
store.dispatch('users/setCurrentOrg', org) store.dispatch('users/setCurrentOrg', org)
}) })
} }
@@ -60,9 +65,16 @@ async function changeCurrentOrgIfNeed({ to, from, next }) {
Vue.$log.error('Current org is null or not a object: ', currentOrg) Vue.$log.error('Current org is null or not a object: ', currentOrg)
await orgUtil.change2PropOrg({ to, from, next }) await orgUtil.change2PropOrg({ to, from, next })
} }
if (currentOrg.name === 'SystemSetting') { const globalOrgPath = [
const preOrg = store.getters.preOrg '/console/perms/login-acls/', '/console/users/roles/',
await orgUtil.changeOrg(preOrg) '/console/perms/connect-method-acls/', '/settings/'
]
if (autoEnterOrgs.indexOf(currentOrg.id) !== -1 && currentOrg.autoEnter) {
const delta = new Date().getTime() - currentOrg.autoEnter
const notNeedChange = globalOrgPath.find(path => to.path.indexOf(path) === 0)
if (!notNeedChange && delta > 3000) {
await orgUtil.change2PropOrg({ to, from, next })
}
return return
} }
if (!orgUtil.hasCurrentOrgPermission()) { if (!orgUtil.hasCurrentOrgPermission()) {

View File

@@ -221,8 +221,7 @@ export default {
url: `/api/v1/assets/assets/${this.object.id}/`, url: `/api/v1/assets/assets/${this.object.id}/`,
object: this.object, object: this.object,
nested: 'spec_info', nested: 'spec_info',
showUndefine: true, showUndefine: true
excludes: ['script']
}, },
customInfoConfig: { customInfoConfig: {
title: this.$t('common.CustomInfo'), title: this.$t('common.CustomInfo'),

View File

@@ -26,7 +26,7 @@ export default {
[this.$t('xpack.Cloud.CloudSource'), ['account', 'regions']], [this.$t('xpack.Cloud.CloudSource'), ['account', 'regions']],
[this.$t('xpack.Cloud.SaveSetting'), [ [this.$t('xpack.Cloud.SaveSetting'), [
'hostname_strategy', 'ip_network_segment_group', 'hostname_strategy', 'ip_network_segment_group',
'sync_ip_type', 'is_always_update', 'fully_synchronous' 'sync_ip_type', 'is_always_update', 'fully_synchronous', 'release_assets'
]], ]],
[this.$t('xpack.Cloud.SyncStrategy'), ['strategy']], [this.$t('xpack.Cloud.SyncStrategy'), ['strategy']],
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']], [this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
@@ -68,6 +68,11 @@ export default {
label: this.$t('xpack.Cloud.FullySynchronous'), label: this.$t('xpack.Cloud.FullySynchronous'),
helpTips: this.$t('xpack.Cloud.FullySynchronousHelpTips') helpTips: this.$t('xpack.Cloud.FullySynchronousHelpTips')
}, },
release_assets: {
type: 'switch',
label: this.$t('xpack.Cloud.ReleaseAssets'),
helpTips: this.$t('xpack.Cloud.ReleaseAssetsHelpTips')
},
regions: { regions: {
component: Select2, component: Select2,
el: { el: {

View File

@@ -119,7 +119,7 @@
import { TreeTable } from '@/components' import { TreeTable } from '@/components'
import Term from '@/components/Widgets/Term' import Term from '@/components/Widgets/Term'
import Page from '@/layout/components/Page' import Page from '@/layout/components/Page'
import { createJob, getJob, getTaskDetail, JobUploadFile } from '@/api/ops' import { createJob, getTaskDetail, JobUploadFile } from '@/api/ops'
import { formatFileSize } from '@/utils/common' import { formatFileSize } from '@/utils/common'
import store from '@/store' import store from '@/store'
@@ -230,28 +230,9 @@ export default {
}, },
mounted() { mounted() {
this.enableWS() this.enableWS()
this.initData()
}, },
methods: { methods: {
formatFileSize, formatFileSize,
async initData() {
this.recoverStatus()
},
recoverStatus() {
if (this.$route.query.taskId) {
this.currentTaskId = this.$route.query.taskId
getTaskDetail(this.currentTaskId).then(data => {
getJob(data.job_id).then(res => {
this.runAsInput.value = res.runas
this.runAsInput.callback(res.runas)
this.executionInfo.status = data['status']
this.executionInfo.timeCost = data['time_cost']
this.setCostTimeInterval()
this.writeExecutionOutput()
})
})
}
},
enableWS() { enableWS() {
const scheme = document.location.protocol === 'https:' ? 'wss' : 'ws' const scheme = document.location.protocol === 'https:' ? 'wss' : 'ws'
const port = document.location.port ? ':' + document.location.port : '' const port = document.location.port ? ':' + document.location.port : ''
@@ -281,7 +262,7 @@ export default {
} }
}, },
taskStatusStat(summary) { taskStatusStat(summary) {
const { ok, failures, dark, excludes, skipped } = summary const { ok = [], failures = [], dark = [], excludes = [], skipped = [] } = summary
const failedKeys = Object.keys(failures) const failedKeys = Object.keys(failures)
const darkKeys = Object.keys(dark) const darkKeys = Object.keys(dark)
@@ -439,6 +420,7 @@ export default {
this.executionInfo.timeCost = 0 this.executionInfo.timeCost = 0
this.executionInfo.status = 'running' this.executionInfo.status = 'running'
this.currentTaskId = res.task_id this.currentTaskId = res.task_id
this.$router.replace({ query: { taskId: this.currentTaskId, type: 'file_upload' }})
this.setCostTimeInterval() this.setCostTimeInterval()
this.writeExecutionOutput() this.writeExecutionOutput()
}).catch(() => { }).catch(() => {

View File

@@ -446,7 +446,7 @@ export default {
this.executionInfo.timeCost = 0 this.executionInfo.timeCost = 0
this.executionInfo.status = 'running' this.executionInfo.status = 'running'
this.currentTaskId = res.task_id this.currentTaskId = res.task_id
this.$router.replace({ query: { taskId: this.currentTaskId }}) this.$router.replace({ query: { taskId: this.currentTaskId, type: 'shortcut_cmd' }})
this.setCostTimeInterval() this.setCostTimeInterval()
this.writeExecutionOutput() this.writeExecutionOutput()
this.setBtn() this.setBtn()
@@ -455,7 +455,7 @@ export default {
stop() { stop() {
StopJob({ task_id: this.currentTaskId }).then(() => { StopJob({ task_id: this.currentTaskId }).then(() => {
this.xterm.write('\x1b[31m' + this.xterm.write('\x1b[31m' +
this.$tc('ops.StopLogOutput').replace('currentTaskId', this.currentTaskId) + '\x1b[0m') this.$tc('ops.StopLogOutput').replace('currentTaskId', this.currentTaskId) + '\x1b[0m')
this.xterm.write(this.wrapperError('')) this.xterm.write(this.wrapperError(''))
this.getTaskStatus() this.getTaskStatus()
}).catch((e) => { }).catch((e) => {

View File

@@ -143,7 +143,7 @@ export default {
}, },
callbacks: { callbacks: {
click: function() { click: function() {
window.location.href = `/core/auth/profile/mfa/` window.open('/core/auth/profile/mfa/', '_blank')
} }
} }
}, },

View File

@@ -19,7 +19,7 @@ export default {
data() { data() {
const commandType = this.$route.query.type || 'es' const commandType = this.$route.query.type || 'es'
return { return {
successUrl: { name: 'TerminalSetting', params: { activeMenu: 'CommandStorage' }}, successUrl: { name: 'Storage', params: { activeMenu: 'CommandStorage' }},
initial: { initial: {
type: commandType, type: commandType,
doc_type: 'command', doc_type: 'command',

View File

@@ -44,7 +44,7 @@
<BasicTree <BasicTree
v-model="requestForm.actions" v-model="requestForm.actions"
:tree="treeNodes" :tree="treeNodes"
style="width: 30% !important" style="width: 100%"
/> />
</el-form-item> </el-form-item>

View File

@@ -8,6 +8,7 @@ import { PhoneInput, UserPassword } from '@/components/Form/FormFields'
import rules from '@/components/Form/DataForm/rules' import rules from '@/components/Form/DataForm/rules'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { Select2 } from '@/components' import { Select2 } from '@/components'
import store from '@/store'
export default { export default {
components: { components: {
@@ -40,6 +41,9 @@ export default {
return this.$route.params.id || formValue.source !== 'local' return this.$route.params.id || formValue.source !== 'local'
} }
}, },
mfa_level: {
disabled: false
},
email: { email: {
rules: [ rules: [
rules.EmailCheck, rules.EmailCheck,
@@ -148,8 +152,8 @@ export default {
}, },
hidden: () => { hidden: () => {
return !this.$store.getters.hasValidLicense || return !this.$store.getters.hasValidLicense ||
!this.$hasPerm('rbac.add_orgrolebinding') || !this.$hasPerm('rbac.add_orgrolebinding') ||
this.$store.getters.currentOrgIsRoot this.$store.getters.currentOrgIsRoot
}, },
helpText: this.$t('users.HelpText.OrgRoleHelpText') helpText: this.$t('users.HelpText.OrgRoleHelpText')
}, },
@@ -212,6 +216,7 @@ export default {
this.fieldsMeta.groups.el.disabled = true this.fieldsMeta.groups.el.disabled = true
} }
await this.setDefaultRoles() await this.setDefaultRoles()
this.disableMFAFieldIfNeed(null)
this.loading = false this.loading = false
}, },
methods: { methods: {
@@ -229,11 +234,21 @@ export default {
if (this.$route.query.clone_from) { if (this.$route.query.clone_from) {
this.user.groups = [] this.user.groups = []
} }
this.disableMFAFieldIfNeed(user)
}, },
async setDefaultRoles() { async setDefaultRoles() {
const roles = await this.$axios.get('/api/v1/rbac/roles/') const roles = await this.$axios.get('/api/v1/rbac/roles/')
this.initial.system_roles = roles.filter(role => role.name === 'User').map(role => role.id) this.initial.system_roles = roles.filter(role => role.name === 'User').map(role => role.id)
this.initial.org_roles = roles.filter(role => role.name === 'OrgUser').map(role => role.id) this.initial.org_roles = roles.filter(role => role.name === 'OrgUser').map(role => role.id)
},
disableMFAFieldIfNeed(user) {
// SECURITY_MFA_AUTH 0 不开启 1 全局开启 2 管理员开启
const adminUserIsNeed = (user?.is_superuser || user?.is_org_admin) && this.$route.meta.action === 'update' &&
store.getters.publicSettings['SECURITY_MFA_AUTH'] === 2
if (store.getters.publicSettings['SECURITY_MFA_AUTH'] === 1 || adminUserIsNeed) {
this.fieldsMeta['mfa_level'].disabled = true
this.fieldsMeta['mfa_level'].helpText = this.$t('users.GlobalDisableMfaMsg')
}
} }
} }
} }