接上文权限控制:https://blog.csdn.net/XiugongHao/article/details/145337904?
1. 从菜单中获取所有按钮权限
import { defineStore } from "pinia";
import type { ILoginData } from "@/services/modules/login/type";
import { getUserInfoById, getUserMenusByRoleId, userLogin } from "@/services/modules/login";
import { localCache } from "@/utils/cache";
import { LOGIN_TOKEN, USER_INFO, USER_MENUS } from "@/constants";
import type { ILoginState } from "@/stores/modules/login/type";
import router from "@/router";
import { mapMenuListToPermission, mapMenus } from "@/utils/mapMenus";
import useSystemStore from "@/stores/modules/main/system/system";
const useLoginStore = defineStore("login", {
state: (): ILoginState => ({
userInfo: localCache.getCache(USER_INFO) ?? {},
token: localCache.getCache(LOGIN_TOKEN) ?? "",
userMenus: localCache.getCache(USER_MENUS) ?? [],
permissions: []
}),
actions: {
async userLoginAction(loginData: ILoginData) {
// 获取用户登录返回信息
const res = await userLogin(loginData);
const id = res.data.id;
// 处理 token
this.token = res.data.token;
localCache.setCache(LOGIN_TOKEN, res.data.token);
// 获取用户信息
const userInfoResult = await getUserInfoById(id);
this.userInfo = userInfoResult.data;
localCache.setCache(USER_INFO, userInfoResult.data);
// 获取权限
const userMenusResult = await getUserMenusByRoleId(id);
this.userMenus = userMenusResult.data;
localCache.setCache(USER_MENUS, userMenusResult.data);
// 获取所有 role 和 department 和 menu 数据
const systemStore = useSystemStore();
await systemStore.postRoleListAction();
await systemStore.postDepartmentListAction();
await systemStore.postMenuListAction();
// 获取当前用户的按钮权限列表
this.permissions = mapMenuListToPermission(this.userMenus);
// 动态添加路由
const routes = mapMenus(this.userMenus);
routes.forEach((route) => router.addRoute("main", route));
// 路由跳转到首页
router.push("/");
},
loadAsyncRoutes() {
// 用户刷新 动态获取路由 防止因为刷新导致缓存的动态路由丢失
if (this.token && this.userMenus && this.userInfo) {
const systemStore = useSystemStore();
// 获取所有 role 和 department 和 menu 数据
systemStore.postRoleListAction();
systemStore.postDepartmentListAction();
systemStore.postMenuListAction();
// 获取按钮权限列表
this.permissions = mapMenuListToPermission(this.userMenus);
// 动态添加路由
const routes = mapMenus(this.userMenus);
routes.forEach((route) => {
router.addRoute("main", route);
});
}
}
}
});
export default useLoginStore;
2. 在组件中按钮权限的判断逻辑
抽离 hooks:
import useLoginStore from "@/stores/modules/login/login";
function usePermission(pageName: string, handleName: string) {
const queryPermission = `${pageName}:${handleName}`;
const permissions = useLoginStore().permissions;
return !!permissions.find((item) => item.includes(queryPermission));
}
export default usePermission;
page-content.vue
<template>
<div class="content">
<div class="header">
<h3 class="title">{{ contentConfig?.header?.title ?? "数据列表" }}</h3>
<el-button v-if="isCreate" type="primary" @click="handleNewData">{{
contentConfig?.header?.btnText ?? "新建数据"
}}</el-button>
</div>
<div class="table">
<el-table
:data="pageList"
:border="true"
:row-key="contentConfig?.childrenTree?.rowKey"
style="width: 100%"
>
<template v-for="item in contentConfig.propsList" :key="item.prop">
<!-- <el-table-column align="center" :label="item.label" :prop="item.prop" :width="item.width ?? '150px'"></el-table-column>-->
<el-table-column
v-if="item.type === 'index' || item.type === 'selection'"
align="center"
v-bind="item"
/>
<el-table-column v-else-if="item.type === 'custom'" align="center" v-bind="item">
<template #default="scope">
<slot :name="item.slotName" v-bind="scope" :prop="item.prop" :leaderRange="10" />
</template>
</el-table-column>
<el-table-column v-else align="center" v-bind="item">
<template #default="scope">
<span v-if="item.type === 'timer'">{{ formatUTC(scope.row[item.prop]) }}</span>
<span v-else-if="item.type === 'handler'">
<el-button
v-if="isUpdate"
type="primary"
size="small"
icon="EditPen"
link
@click="handleEditClick(scope.row)"
>
编辑
</el-button>
<el-button
v-if="isDelete"
type="danger"
size="small"
icon="Delete"
link
@click="handleDeleteClick(scope.row.id)"
>
删除
</el-button>
</span>
<span v-else>{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
</template>
</el-table>
</div>
<div class="footer">
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:page-sizes="[10, 20, 30]"
layout="total, sizes, prev, pager, next, jumper"
:total="pageTotalCount"
@update:currentPage="handleCurrentChange"
@update:pageSize="handlePageSizeChange"
/>
</div>
</div>
</template>
<script setup lang="ts" name="content">
import { storeToRefs } from "pinia";
import { ref } from "vue";
import useSystemStore from "@/stores/modules/main/system/system";
import { formatUTC } from "@/utils/format";
import usePermission from "@/hooks/usePermission";
const { contentConfig } = defineProps(["contentConfig"]);
const emit = defineEmits(["newDataClick", "editDataClick"]);
// 0.判断是否有增删改查的权限
const isCreate = usePermission(contentConfig.pageName, "create");
const isDelete = usePermission(contentConfig.pageName, "delete");
const isUpdate = usePermission(contentConfig.pageName, "update");
const isQuery = usePermission(contentConfig.pageName, "query");
// 1.请求数据
const systemStore = useSystemStore();
const currentPage = ref(1);
const pageSize = ref(10);
systemStore.$onAction(({ name, after }) => {
after(() => {
if (
name === "deletePageByIdAction" ||
name === "editPageDataAction" ||
name === "newPageDataAction"
) {
currentPage.value = 1;
}
})
});
function fetchPageListData(queryInfo: any = {}) {
// 0.判断是否具有查询权限
if (!isQuery) return;
// 1.获取offset和size
const size = pageSize.value;
const offset = (currentPage.value - 1) * size;
// 2.发生网络请求
systemStore.postPageListAction(contentConfig.pageName, { offset, size, ...queryInfo });
}
fetchPageListData();
// 2.展示数据
const { pageList, pageTotalCount } = storeToRefs(systemStore);
// 3.绑定分页数据
function handleCurrentChange() {
fetchPageListData();
}
function handlePageSizeChange(newPageSize: number) {
pageSize.value = newPageSize;
fetchPageListData();
}
function handleResetClick() {
currentPage.value = 1;
pageSize.value = 10;
fetchPageListData();
}
// 4.新建数据的处理
function handleNewData() {
emit("newDataClick");
}
// 5.删除和编辑操作
function handleDeleteClick(id: number) {
systemStore.deletePageByIdAction(contentConfig.pageName, id);
}
function handleEditClick(data: any) {
emit("editDataClick", data);
}
// 暴露函数
defineExpose({
fetchPageListData,
handleResetClick
});
</script>
<style scoped lang="less">
.content {
margin-top: 20px;
padding: 20px;
background-color: #fff;
.header {
display: flex;
height: 45px;
padding: 0 5px;
justify-content: space-between;
align-items: center;
.title {
font-size: 20px;
font-weight: 700;
}
.handler {
align-items: center;
}
}
.table {
:deep(.el-table__cell) {
padding: 14px 0;
}
}
.footer {
display: flex;
justify-content: flex-end;
margin-top: 15px;
}
}
</style>