Files
school-developer/src/views/admin/system/role/change-role.vue
zhoutianchi 2653c7446b 1
2026-02-25 15:40:01 +08:00

161 lines
4.1 KiB
Vue

<template>
<el-dialog
v-model="visible"
:title="dialogTitle"
width="80%"
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
:before-close="handleBeforeClose"
center
>
<el-form>
<el-form-item class="role-form-item">
<el-radio-group v-model="radio" class="role-radio-group" @change="handleChangeRole">
<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 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('')
/** 按分组名分组的角色列表:{ "未分组": [{ 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) => {
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')
})
}
/** 根据 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('请选择一个角色')
return false
}
return true
}
const handleBeforeClose = (done: () => void) => {
if (requireSelectToClose.value) {
useMessage().warning('请先选择登录角色')
return
}
if (!canClose()) return
done()
}
const handleFooterClose = () => {
if (!canClose()) return
visible.value = false
}
const handleChangeRole = (label: string) => {
const obj = findRoleByCode(label)
if (!obj) return
Local.set('roleCode', obj.roleCode)
Local.set('roleName', obj.roleName)
Local.set('roleId', obj.roleId)
useMessage().success('操作成功')
setTimeout(() => {
// 切换角色后统一回到首页,避免停留在诸如 jsonflow/run-job/do-job 等内部路由
window.location.hash = '#/'
window.location.reload()
}, 500)
}
defineExpose({
open
})
</script>
<style scoped lang="scss">
.role-form-item {
:deep(.el-form-item__content) {
flex-wrap: wrap;
}
}
.role-group {
width: 100%;
flex: 0 0 100%;
margin-bottom: 12px;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px 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;
gap: 8px;
align-items: flex-start;
/* 每个分组内按钮可换行,分组之间不重叠 */
:deep(.el-radio-button) {
margin: 0;
}
:deep(.el-radio-button__inner) {
border-radius: 6px !important;
border: 1px solid var(--el-border-color) !important;
margin-left: 0 !important;
}
:deep(.el-radio-button.is-active .el-radio-button__inner) {
border-color: var(--el-color-primary) !important;
}
}
</style>