按钮权限控制

发布于:2025-02-10 ⋅ 阅读:(77) ⋅ 点赞:(0)

接上文权限控制: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>


网站公告

今日签到

点亮在社区的每一天
去签到