This commit is contained in:
zhoutianchi
2026-02-24 17:06:57 +08:00
parent 9699cdc849
commit b971e6de52
4 changed files with 76 additions and 107 deletions

View File

@@ -4,7 +4,7 @@
<LockScreen v-if="themeConfig.isLockScreen" />
<Settings ref="settingsRef" v-show="themeConfig.lockScreenTime > 1" />
<CloseFull v-if="!themeConfig.isLockScreen" />
<ChangeRoleFir ref="changeRoleFirRef" />
<ChangeRole ref="changeRoleFirRef" title="首次登录请选择角色" :require-select-to-close="true" />
</el-config-provider>
</template>
@@ -22,7 +22,7 @@ import setIntroduction from '/@/utils/setIconfont';
const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
const Settings = defineAsyncComponent(() => import('./layout/navBars/breadcrumb/settings.vue'));
const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
const ChangeRoleFir = defineAsyncComponent(() => import('/@/views/admin/system/role/changeRole-fir.vue'));
const ChangeRole = defineAsyncComponent(() => import('/@/views/admin/system/role/change-role.vue'));
// 定义变量内容
const { messages, locale } = useI18n();
@@ -56,10 +56,19 @@ onBeforeMount(() => {
// 设置批量第三方 js
setIntroduction.jsCdn();
});
// 页面加载时
// 角色选择弹框是否已在本轮打开过(防止事件被触发两次)
let roleDialogOpenedThisSession = false
onMounted(() => {
// 唯一入口:只通过事件打开,且只打开一次;延迟打开以等待异步组件挂载
mittBus.on('openRoleSelectDialog', () => {
if (roleDialogOpenedThisSession) return
roleDialogOpenedThisSession = true
setTimeout(() => {
changeRoleFirRef.value?.open()
}, 300)
})
nextTick(() => {
// 监听布局配'置弹窗点击打开
// 监听布局配置弹窗点击打开
mittBus.on('openSettingsDrawer', () => {
settingsRef.value.openDrawer();
});
@@ -72,18 +81,12 @@ onMounted(() => {
if (Session.get('isTagsViewCurrenFull')) {
stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull'));
}
// 全局判断:已登录但 Local 缺少角色信息时弹出角色选择;弹框已触发则不再重复弹出
// 与请求拦截器共用同一逻辑:先设标志再 emit由监听器统一打开监听器内会延迟 300ms 以等待异步组件挂载)
if (Session.getToken() && needRoleSelection() && !isRoleDialogTriggered()) {
setRoleDialogTriggered(true);
setTimeout(() => {
changeRoleFirRef.value?.open();
}, 300);
setRoleDialogTriggered(true)
mittBus.emit('openRoleSelectDialog')
}
// 请求拦截器里也会在发送请求时判断并 emit此处统一监听打开弹框
mittBus.on('openRoleSelectDialog', () => {
changeRoleFirRef.value?.open();
});
});
})
});
// 页面销毁时,关闭监听
onUnmounted(() => {

View File

@@ -253,15 +253,7 @@ const getIsDot = () => {
});
};
// 登录后若存储中无角色信息则弹出角色切换框
const openChangeRoleIfMissing = () => {
const hasRole = Local.get('roleCode') && Local.get('roleName') && Local.get('roleId')
if (!hasRole) {
nextTick(() => {
setTimeout(() => ChangeRoleRef.value?.open(), 100)
})
}
}
// 首次登录缺角色时由 App.vue + 请求拦截器统一弹出「首次登录请选择角色」弹框,此处不再自动打开
// 页面加载时
onMounted(() => {
@@ -271,7 +263,6 @@ onMounted(() => {
}
useFlowJob().topJobList()
getIsDot()
openChangeRoleIfMissing()
});
</script>

View File

@@ -1,56 +1,79 @@
<template>
<el-dialog
v-model="visible"
title="角色切换"
:title="dialogTitle"
width="50%"
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
:before-close="handleBeforeClose"
center
>
<el-form>
<!-- <el-form-item label="学校">-->
<!-- <el-tag>{{schoolName}}</el-tag>-->
<!-- </el-form-item>-->
<el-form-item label="角色" class="role-form-item">
<el-form-item class="role-form-item">
<el-radio-group v-model="radio" class="role-radio-group" @change="handleChangeRole">
<el-radio-button
v-for="item in allRole"
:key="item.roleCode"
:label="item.roleCode"
>
{{ item.roleName }}
</el-radio-button>
<template v-for="(roles, groupName) in allRoleGroups" :key="groupName">
<div class="role-group">
<el-divider>{{ groupName }}</el-divider>
<el-radio-button
v-for="item in roles"
:key="item.roleCode"
:label="item.roleCode"
>
{{ item.roleName }}
</el-radio-button>
</div>
</template>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<!-- <el-button type="primary" @click="handleChangeRole">切换</el-button>-->
<template v-if="!requireSelectToClose" #footer>
<el-button @click="handleFooterClose"> </el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed, toRef } from 'vue'
import { listAllRole } from '/@/api/admin/role'
import { Local } from '/@/utils/storage'
import { useMessage } from '/@/hooks/message'
/** 弹框标题,如「角色切换」「登录角色选择」 */
const props = withDefaults(
defineProps<{ title?: string; requireSelectToClose?: boolean }>(),
{ title: '角色切换', requireSelectToClose: false }
)
const dialogTitle = computed(() => props.title)
const visible = ref(false)
const radio = ref('')
const allRole = reactive<any[]>([])
/** 按分组名分组的角色列表:{ "未分组": [{ roleId, roleName, roleCode, ... }], ... } */
const allRoleGroups = ref<Record<string, any[]>>({})
const requireSelectToClose = toRef(props, 'requireSelectToClose')
const open = () => {
if (visible.value) return
visible.value = true
listAllRole().then((res) => {
Object.assign(allRole, res.data)
allRoleGroups.value = res.data && typeof res.data === 'object' && !Array.isArray(res.data)
? res.data
: { '未分组': Array.isArray(res.data) ? res.data : [] }
radio.value = Local.get('roleCode')
visible.value = true
})
}
/** 根据 roleCode 从分组数据中查找角色 */
const findRoleByCode = (code: string) => {
for (const roles of Object.values(allRoleGroups.value)) {
if (!Array.isArray(roles)) continue
const found = roles.find((r: any) => r.roleCode === code)
if (found) return found
}
return null
}
const canClose = () => {
if (!radio.value) {
useMessage().warning('请选择一个角色')
@@ -60,6 +83,10 @@ const canClose = () => {
}
const handleBeforeClose = (done: () => void) => {
if (requireSelectToClose.value) {
useMessage().warning('请先选择登录角色')
return
}
if (!canClose()) return
done()
}
@@ -70,7 +97,7 @@ const handleFooterClose = () => {
}
const handleChangeRole = (label: string) => {
const obj = allRole.find((v: any) => v.roleCode === label)
const obj = findRoleByCode(label)
if (!obj) return
Local.set('roleCode', obj.roleCode)
Local.set('roleName', obj.roleName)
@@ -94,6 +121,18 @@ defineExpose({
flex-wrap: wrap;
}
}
.role-group {
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
}
.group-name {
font-size: 13px;
color: var(--el-text-color-secondary);
margin-bottom: 6px;
}
.role-radio-group {
display: flex;
flex-wrap: wrap;

View File

@@ -1,64 +0,0 @@
<template>
<el-dialog v-model="visible" width="50%" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false" center>
<template #title>
<div style="margin: 0 auto;width:100%;text-align:center;font-size:18px;font-weight:bold;">
登录角色选择
</div>
</template>
<div style="margin: 0 auto;width:100%;text-align:center;font-size:18px;font-weight:bold;">
<el-radio-group v-model="radio">
<el-radio-button v-for="(item,index) in allRole" :key="index" :label="item.roleCode" @click.native="handleChangeRole(item.roleCode)">{{item.roleName}}</el-radio-button>
</el-radio-group>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import {listAllRole} from '/@/api/admin/role'
import {Local, Session} from '/@/utils/storage';
import {useMessage} from "/@/hooks/message";
// import {querySchoolName} from "/@/api/admin/tenant"
const visible=ref(false)
const radio=ref('')
const allRole = reactive<any[]>([])
const schoolName=ref('')
const open = () => {
listAllRole().then(res => {
Object.assign(allRole, res.data)
radio.value = Local.get('roleCode')
visible.value = true
})
}
// 必须选择角色后才能关闭,禁止点击遮罩/ESC 关闭(不调用 done 即不关闭)
const handleBeforeClose = (_done: () => void) => {
useMessage().warning('请先选择登录角色')
}
const handleChangeRole = (label: any) => {
let obj:any=allRole.find((v:any) => v.roleCode == label)
Local.set("roleCode",obj.roleCode)
Local.set("roleName",obj.roleName)
Local.set("roleId",obj.roleId)
useMessage().success("操作成功")
setTimeout(()=>{
window.location.reload()
},500)
}
// const handleQuerySchoolName=()=>{
// querySchoolName({id:Session.get("tenantId")}).then((res:any)=>{
// schoolName.value=res.data
// })
// }
defineExpose({
open
})
</script>
<style scoped>
</style>