角色管理页面接口完成
This commit is contained in:
@@ -4,7 +4,7 @@ import { useAppStore } from '@/store/modules/app';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { NButton } from 'naive-ui';
|
||||
import { NButton, NIcon } from 'naive-ui';
|
||||
import { roleListApi, editRoleApi } from '@/service/api/role';
|
||||
|
||||
const router = useRouter();
|
||||
@@ -12,6 +12,9 @@ const appStore = useAppStore();
|
||||
const themeStore = useThemeStore();
|
||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||
|
||||
const routeTree = ref<any[]>([]);
|
||||
const allPaths = ref<string[]>([]);
|
||||
const defaultCheckedKeys = ref<string[]>([]);
|
||||
const loading = ref<boolean>(false);
|
||||
const btnLoading = ref<boolean>(false);
|
||||
const formRef = ref<any>(null);
|
||||
@@ -94,6 +97,12 @@ const getList = async () => {
|
||||
// 设置权限
|
||||
const handleSetPermission = (row: any) => {
|
||||
currentRole.value = JSON.parse(JSON.stringify(row));
|
||||
// 所有权限
|
||||
if(currentRole.value?.perms.length===1 && currentRole.value?.perms[0] === '*'){
|
||||
defaultCheckedKeys.value = allPaths.value;
|
||||
}else{
|
||||
defaultCheckedKeys.value = currentRole.value?.perms || [];
|
||||
}
|
||||
permissionModal.value = true;
|
||||
}
|
||||
// 编辑角色
|
||||
@@ -125,15 +134,82 @@ const saveRole = (e: MouseEvent) => {
|
||||
// 保存权限
|
||||
const savePermission = async () => {
|
||||
btnLoading.value = true;
|
||||
setTimeout(() => {
|
||||
currentRole.value.perms = defaultCheckedKeys.value;
|
||||
try {
|
||||
await editRoleApi(currentRole.value);
|
||||
window.$message?.success('操作成功')
|
||||
btnLoading.value = false;
|
||||
permissionModal.value = false;
|
||||
}, 1000)
|
||||
getList();
|
||||
} finally {
|
||||
btnLoading.value = false;
|
||||
}
|
||||
}
|
||||
// 更新选中权限
|
||||
const updateCheckedKeys = (keys: string[]) => {
|
||||
defaultCheckedKeys.value = keys;
|
||||
}
|
||||
|
||||
// 复制title到顶层
|
||||
const copyTitleToTop = (node:any) => {
|
||||
// 创建新节点,复制原节点所有属性
|
||||
const newNode = { ...node }
|
||||
|
||||
// 如果存在 meta.title,则复制到顶层
|
||||
if (node.meta?.title) {
|
||||
newNode.title = node.meta.title
|
||||
} else {
|
||||
// 可选:没有 title 时用 name 代替
|
||||
newNode.title = node.name || ''
|
||||
}
|
||||
// 如果有 children,递归处理每个子节点
|
||||
if (Array.isArray(newNode.children) && newNode.children.length > 0) {
|
||||
newNode.children = newNode.children.map((child:any) => copyTitleToTop(child))
|
||||
}
|
||||
return newNode
|
||||
}
|
||||
// 获取所有路由路径
|
||||
const getAllPaths = (tree:any) => {
|
||||
let paths:string[] = []
|
||||
tree.forEach((node:any) => {
|
||||
if (node.path) paths.push(node.path)
|
||||
if (Array.isArray(node.children) && node.children.length) {
|
||||
paths = paths.concat(getAllPaths(node.children))
|
||||
}
|
||||
})
|
||||
return paths
|
||||
}
|
||||
// 获取所有路由
|
||||
const getAllRoutes = () => {
|
||||
const filtered = router.getRoutes().filter((item:any) => {
|
||||
// 条件1:有name且非常量
|
||||
if (item.name === undefined || item.meta?.constant === true) return false;
|
||||
// 条件2:path中斜杠数量 < 2(即只有一级)
|
||||
const path = item.path || '';
|
||||
const slashCount = (path.match(/\//g) || []).length;
|
||||
if (slashCount >= 2) return false;
|
||||
return true;
|
||||
})
|
||||
const tree = filtered.map((item:any) => copyTitleToTop(item));
|
||||
routeTree.value = tree;
|
||||
allPaths.value = getAllPaths(tree);
|
||||
}
|
||||
|
||||
// tree自定义渲染图标
|
||||
const renderIcon = (node:any) => {
|
||||
// 如果节点没有 children 或 children 为空数组,则不显示图标
|
||||
if (!node.option.children || node.option.children.length === 0) {
|
||||
return null; // 返回 null 表示不渲染任何图标
|
||||
}
|
||||
// 有子节点:返回 undefined 表示使用默认展开图标,也可自定义
|
||||
return h(Icon,{
|
||||
icon: node.option.expanded ? 'bi:caret-down-fill' : 'bi:caret-right-fill',
|
||||
class: 'size-12px',
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const allRoutes = router.getRoutes();
|
||||
getAllRoutes();
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
@@ -192,12 +268,24 @@ onMounted(() => {
|
||||
<!-- 设置权限抽屉 -->
|
||||
<NDrawer v-model:show="permissionModal" :width="502" placement="right">
|
||||
<NDrawerContent :title="`设置权限-${currentRole.name}`" closable>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-[10px]">
|
||||
<NButton @click="permissionModal = false">取消</NButton>
|
||||
<NButton type="primary" :loading="btnLoading" @click="savePermission">保存</NButton>
|
||||
</div>
|
||||
</template>
|
||||
<NTree
|
||||
block-line
|
||||
cascade
|
||||
checkable
|
||||
key-field="path"
|
||||
label-field="title"
|
||||
:selectable="false"
|
||||
:data="routeTree"
|
||||
:default-checked-keys="defaultCheckedKeys"
|
||||
@update:checked-keys="updateCheckedKeys"
|
||||
:render-switcher-icon="renderIcon"
|
||||
/>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-[10px]">
|
||||
<NButton @click="permissionModal = false">取消</NButton>
|
||||
<NButton type="primary" :loading="btnLoading" @click="savePermission">保存</NButton>
|
||||
</div>
|
||||
</template>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</NCard>
|
||||
|
||||
Reference in New Issue
Block a user