Vue3.5 企业级管理系统实战(十七):角色管理

news2025/5/11 13:52:28

本篇主要探讨角色管理功能,其中菜单权限这里先不实现,后续在菜单管理中再进行实现。接口部分依然是使用 Apifox mock 的。

1 角色 api

在 src/api/role.ts 中添加角色相关 api,代码如下:

//src/api/role.ts
import service from "./config/request";
import type { ApiResponse } from "./type";

export interface IRole {
  id: number;
  name: string;
  description: string;
  is_default: number;
}

//定义state类型
export interface IRoleState {
  roles: IRole[];
  count: number;
}

export interface IRoleParams {
  pageNum: number;
  pageSize: number;
}

// 获取角色
export const getRoles = (
  params = { pageNum: 0, pageSize: 10 }
): Promise<ApiResponse<IRoleState>> => {
  return service.get("/role", {
    params
  });
};

// 新增角色
export const addRole = (data: IRole): Promise<ApiResponse> => {
  return service.post("/role", data);
};

// 更新角色
export const updateRole = (
  id: number,
  data: Partial<IRole>
): Promise<ApiResponse> => {
  return service.put("/role/" + id, data);
};

// 删除角色
export const removeRole = (id: number): Promise<ApiResponse> => {
  return service.delete("/role/" + id);
};

2 角色 store

在 src/stores/role.ts 中添加角色相关方法,代码如下:

//src/stores/role.ts
import type { IRole, IRoleParams, IRoleState } from "@/api/role";
import {
  getRoles as getRolesApi,
  addRole as addRoleApi,
  updateRole as updateRoleApi,
  removeRole as removeRoleApi
} from "@/api/role";
type WithRoleParmas = IRole & IRoleParams;

export const useRoleStore = defineStore("role", () => {
  //状态
  const state = reactive<IRoleState>({
    roles: [],
    count: 0
  });
  //获取角色
  const getRoles = async (params: IRoleParams) => {
    const res = await getRolesApi(params);
    const { data } = res;
    state.roles = data.roles;
    state.count = data.count;
  };
  //添加角色
  const addRole = async (data: WithRoleParmas) => {
    const { pageNum, pageSize, ...obj } = data;
    const res = await addRoleApi(obj);
    if (res.code == 0) {
      getRoles({ pageNum, pageSize });
    }
  };
  //修改角色
  const updateRole = async (data: WithRoleParmas) => {
    const { pageNum, pageSize, ...obj } = data;
    const res = await updateRoleApi(obj.id, obj);
    if (res.code == 0) {
      getRoles({ pageNum, pageSize });
    }
  };
  //删除角色
  const removeRole = async (data: WithRoleParmas) => {
    const { pageNum, pageSize, id } = data;
    const res = await removeRoleApi(id);
    if (res.code == 0) {
      getRoles({ pageNum, pageSize });
    }
  };

  return { getRoles, addRole, updateRole, removeRole, state };
});

3 角色管理页面开发

角色管理页面文件结构如下图所示:

3.1 角色处理函数封装

在 src/views/system/role/roleHelpers.ts 中封装角色处理的相关操作函数(增删改查),代码如下:

//src/views/system/role/roleHelpers.ts
// 从 @/api/role 模块中导入 IRole 类型
import type { IRole } from "@/api/role";
// 从 @/stores/role 模块中导入 useRoleStore 函数
import { useRoleStore } from "@/stores/role";

/**
 * 自定义组合式函数,用于处理角色相关的操作
 * @param pageSize - 每页显示的记录数,使用 Ref 类型
 * @param pageNum - 当前页码,使用 Ref 类型
 * @returns 包含角色操作方法和状态的对象
 */
export const useRoleHelpers = ({
  pageSize,
  pageNum
}: {
  pageSize: Ref<number>;
  pageNum: Ref<number>;
}) => {
  // 获取当前组件实例的代理对象
  const { proxy } = getCurrentInstance()!;
  // 定义编辑类型,-1 表示初始状态,0 表示编辑,1 表示新增
  const editType = ref(-1);
  // 定义模态框的可见状态
  const visible = ref(false);
  // 定义要编辑的数据,初始值为 undefined
  const editData = ref<IRole | undefined>(undefined);
  // 获取角色状态管理仓库的实例
  const store = useRoleStore();
  // 计算面板的标题,根据编辑类型决定显示“增加角色”还是“修改角色”
  const panelTitle = computed(() =>
    editType.value == 1 ? "增加角色" : "修改角色"
  );

  /**
   * 处理编辑角色的操作
   * @param role - 要编辑的角色对象
   */
  const handleEditRole = (role: IRole) => {
    // 设置编辑类型为 0,表示编辑
    editType.value = 0;
    // 复制要编辑的角色数据
    editData.value = { ...role };
    // 显示模态框
    visible.value = true;
  };

  /**
   * 处理添加新角色的操作
   */
  const hanleAddRole = () => {
    // 设置编辑类型为 1,表示新增
    editType.value = 1;
    // 初始化要编辑的数据为空的角色对象
    editData.value = {} as IRole;
    // 显示模态框
    visible.value = true;
  };

  /**
   * 添加新角色的异步方法
   * @param data - 要添加的角色数据
   */
  const addNewRole = async (data: IRole) => {
    // 调用仓库的 addRole 方法添加角色,并传递分页信息
    await store.addRole({
      ...data,
      pageNum: pageNum.value,
      pageSize: pageSize.value
    });
    // 显示成功提示信息
    proxy?.$message.success("角色添加成功");
    // 隐藏模态框
    visible.value = false;
  };

  /**
   * 编辑角色的异步方法
   * @param data - 要编辑的角色数据
   */
  const editRow = async (data: IRole) => {
    // 调用仓库的 updateRole 方法更新角色,并传递分页信息
    await store.updateRole({
      ...data,
      pageNum: pageNum.value,
      pageSize: pageSize.value
    });
    // 显示成功提示信息
    proxy?.$message.success("角色编辑成功");
    // 隐藏模态框
    visible.value = false;
  };

  /**
   * 处理提交表单的异步方法,根据编辑类型调用不同的处理方法
   * @param data - 表单提交的角色数据
   */
  const handleSubmit = async (data: IRole) => {
    if (editType.value === 1) {
      // 如果是新增类型,调用 addNewRole 方法
      await addNewRole(data);
    } else {
      // 如果是编辑类型,调用 editRow 方法
      await editRow(data);
    }
  };

  /**
   * 处理删除角色的异步方法
   * @param data - 要删除的角色数据
   */
  const handleRemove = async (data: IRole) => {
    try {
      // 弹出确认对话框,确认是否删除角色
      await proxy?.$confirm("你确定删除" + data.name + "角色吗?", {
        type: "warning"
      });
      // 调用仓库的 removeRole 方法删除角色,并传递分页信息
      await store.removeRole({
        ...data,
        pageNum: pageNum.value,
        pageSize: pageSize.value
      });
      // 显示成功提示信息
      proxy?.$message.success("角色删除成功");
    } catch {
      // 如果用户取消删除,显示取消提示信息
      proxy?.$message.info("取消删除");
    }
  };

  // 返回包含角色操作方法和状态的对象
  return {
    handleSubmit,
    handleRemove,
    handleEditRole,
    hanleAddRole,
    panelTitle,
    editType,
    visible,
    editData
  };
};

3.2 editorRole 组件封装

在 src/views/system/role/components/editorRole.vue 中,对角色的新增编辑页面进行封装,代码如下:

//src/views/system/role/components/editorRole.vue 
<template>
  <el-form :model="editData" label-width="auto" style="max-width: 600px">
    <el-form-item label="角色名称">
      <el-input v-model="editData.name" />
    </el-form-item>
    <el-form-item label="描述">
      <el-input v-model="editData.description" />
    </el-form-item>
    <el-form-item label="是否是默认角色 ">
      <el-switch
        v-model="editData.is_default"
        :active-value="1"
        :inactive-value="0"
      ></el-switch>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm">提交</el-button>
      <el-button @click="handleReset">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import type { IRole } from "@/api/role";
import type { PropType } from "vue";
import { ref, defineProps, watchEffect, defineEmits } from "vue";

// 定义 editData 响应式变量,用于存储表单数据,初始值为空对象
const editData = ref({
  name: "",
  description: "",
  is_default: 0
});

// 定义组件接收的 props
const { data, type } = defineProps({
  data: {
    // 指定 data 的类型为 IRole 对象
    type: Object as PropType<IRole>,
    // 如果未传入 data,默认返回空对象
    default: () => ({})
  },
  type: {
    // 指定 type 的类型为数字
    type: Number,
    // type 为必填项
    required: true
  }
});

// 定义默认表单数据,用于重置表单
const defaultProps = {
  name: "",
  description: "",
  is_default: 0
};

// 重置表单数据的函数,将默认数据和传入的 data 合并
const resetForm = () => {
  editData.value = { ...defaultProps, ...data };
};

// 监听 data 的变化,当 data 改变时重置表单
watchEffect(() => {
  if (data) {
    resetForm();
  }
});

// 定义自定义事件,用于向父组件发送表单数据
const emit = defineEmits(["submit"]);

// 提交表单的函数,触发 submit 事件并传递表单数据
const submitForm = () => {
  emit("submit", editData.value);
};

// 处理重置操作的函数,调用 resetForm 重置表单
const handleReset = () => {
  resetForm();
};
</script>

3.3 角色管理页面

修改 src/views/system/role/index.vue,编写角色管理静态页面,代码如下:

//src/views/system/role/index.vue
<template>
  <div p-30px>
    <h2>角色管理</h2>
    <el-button @click="hanleAddRole">角色添加</el-button>
    <el-table :data="roles" style="width: 100%">
      <el-table-column prop="id" label="角色id" width="180" />
      <el-table-column prop="name" label="角色名称" width="180" />
      <el-table-column prop="description" label="描述" />
      <el-table-column
        prop="is_default"
        label=" 默认角色"
        :formatter="formatter"
      />
      <el-table-column label="操作" fixed="right">
        <template #default="scope">
          <el-button link @click="handleEditRole(scope.row)">编辑</el-button>
          <el-button link @click="handleRemove(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      :page-sizes="[1, 5, 10, 20]"
      layout="prev, pager, next, sizes, total"
      :total="count"
      :page-size="pageSize"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
    <!-- 右侧面板组件,使用 v-model 绑定 visible 控制显示隐藏,设置标题 -->
    <right-panel v-model="visible" :title="panelTitle">
      <!-- 角色编辑组件,传递编辑类型和编辑数据,监听 submit 事件 -->
      <editor-role
        :type="editType"
        :data="editData"
        @submit="handleSubmit"
      ></editor-role>
    </right-panel>
  </div>
</template>

<script lang="ts" setup>
import type { IRole } from "@/api/role";
import { useRoleStore } from "@/stores/role";
import { useRoleHelpers } from "./roleHelpers";
import { ref, toRefs, watchEffect } from "vue";

// 获取角色状态管理仓库实例
const store = useRoleStore();
// 当前页码,初始为 0
const pageNum = ref(0);
// 每页显示的记录数,初始为 10
const pageSize = ref(10);

// 从 useRoleHelpers 组合式函数中解构出所需的方法和状态
const {
  handleSubmit,
  handleRemove,
  handleEditRole,
  hanleAddRole,
  panelTitle,
  editType,
  visible,
  editData
} = useRoleHelpers({ pageNum, pageSize });

// 将仓库状态中的 count 和 roles 转换为响应式引用
const { count, roles } = toRefs(store.state);

// 监听 pageNum 和 pageSize 的变化,当变化时重新获取角色数据
watchEffect(() => {
  store.getRoles({ pageNum: pageNum.value, pageSize: pageSize.value });
});

// 处理每页显示记录数改变的方法
const handleSizeChange = (val: number) => {
  pageSize.value = val;
};

// 处理当前页码改变的方法
const handleCurrentChange = (val: number) => {
  pageNum.value = val - 1;
};

// 格式化是否为默认角色的显示内容
const formatter = (row: IRole) => {
  return row.is_default ? "是" : "否";
};
</script>

npm run dev 启动项目后,页面效果如下:

以上,就是角色管理的全部内容。

下一篇将继续探讨 用户管理,敬请期待~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QTableWidget实现多级表头、表头冻结效果

最终效果&#xff1a; 实现思路&#xff1a;如果只用一个表格的话写起来比较麻烦&#xff0c;可以考虑使用两个QTableWidget组合&#xff0c;把复杂的表头一个用QTableWidget显示&#xff0c;其他内容用另一个QTableWidget。 #include "mainwindow.h" #include &qu…

A2A大模型协议及Java示例

A2A大模型协议概述 1. 协议作用 A2A协议旨在解决以下问题&#xff1a; 数据交换&#xff1a;不同应用程序之间的数据格式可能不一致&#xff0c;A2A协议通过定义统一的接口和数据格式解决这一问题。模型调用&#xff1a;提供标准化的接口&#xff0c;使得外部应用可以轻松调…

CMake 入门实践

CMake 入门实践 第一章 概念与基础项目1.1 CMake 基础认知1.2 最小 CMake 项目1.3 构建流程验证 第二章 多文件项目管理2.1 项目结构2.2 源码示例2.3 CMake 配置 第三章 库文件管理实战3.1 项目结构3.2 核心配置3.3 接口设计 第四章 构建类型与编译优化4.1 构建类型配置4.2 构建…

异地多活单元化架构下的微服务体系

治理服务间的跨IDC调用&#xff0c;而数据库层面还是要跨IDC 服务注册中心拆开、 金融要求&#xff0c;距离太远&#xff0c;异地备库&#xff0c;如果延迟没读到数据就可能有资损&#xff0c;IDC3平时不能用&#xff0c;IDC1挂了还是有数据同步问题&#xff0c;IDC3日常维护…

HarmonyOS NEXT——DevEco Studio的使用(还没写完)

一、IDE环境的搭建 Windows环境 运行环境要求 为保证DevEco Studio正常运行&#xff0c;建议电脑配置满足如下要求&#xff1a; 操作系统&#xff1a;Windows10 64位、Windows11 64位 内存&#xff1a;16GB及以上 硬盘&#xff1a;100GB及以上 分辨率&#xff1a;1280*8…

Windows系统Jenkins企业级实战

目标 在Windows操作系统上使用Jenkins完成代码的自动拉取、编译、打包、发布工作。 实施 1.安装Java开发工具包&#xff08;JDK&#xff09; Jenkins是基于Java的应用程序&#xff0c;因此需要先安装JDK。可以从Oracle官网或OpenJDK下载适合的JDK版本。推荐java17版本&#x…

C# 方法(ref局部变量和ref返回)

>本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 ref局部变量和ref返回 …

滑动窗口,438找出字符串中所有字母的异位词

1.题目 2.解析 这道题我们用滑动窗口来实现&#xff0c;加上哈希表和vector容器的使用来实现这道题目&#xff0c;每次滑动之后我们都对其和答案进行比较&#xff0c;如果全部相等我们返回left&#xff0c;不相等继续滑动即可。 本质就是我们把p中相同数量的字母框起来&#…

「国产嵌入式仿真平台:高精度虚实融合如何终结Proteus时代?」——从教学实验到低空经济,揭秘新一代AI赋能的产业级教学工具

引言&#xff1a;从Proteus到国产平台的范式革新 在高校嵌入式实验教学中&#xff0c;仿真工具的选择直接影响学生的工程能力培养与创新思维发展。长期以来&#xff0c;Proteus作为经典工具占据主导地位&#xff0c;但其设计理念已难以满足现代复杂系统教学与国产化技术需求。…

《Python星球日记》 第52天:反向传播与优化器

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、引言二、反向传播算法原理简述1. 什么是反向传播&#xff1f;2. 从数学角度…

Java常用类概述

Java常用类概述 一、字符串三剑客1. String&#xff08;不可变字符串&#xff09;2. StringBuilder&#xff08;可变&#xff0c;线程不安全&#xff09;3. StringBuffer&#xff08;可变&#xff0c;线程安全&#xff09; 二、日期时间类&#xff08;重点掌握新版API&#xff…

C++STL——priority_queue

优先队列 前言优先队列仿函数头文件 前言 本篇主要讲解优先队列及其底层实现。 优先队列 优先队列的本质就是个堆&#xff0c;其与queue一样&#xff0c;都是容器适配器&#xff0c;不过优先队列是默认为vector实现的。priority_queue的接口优先队列默认为大根堆。 仿函数 …

深入解析WPF中的3D图形编程:材质与光照

引言 在Windows Presentation Foundation (WPF) 中创建三维(3D)图形是一项既有趣又具有挑战性的任务。为了帮助开发者更好地理解如何使用WPF进行3D图形的渲染&#xff0c;本文将深入探讨GeometryModel3D类及其相关的材质和光源设置。 1、GeometryModel3D类简介 GeometryMode…

SolidWork-2023 鼠標工程

地址 https://github.com/MartinxMax/SW2023-Project/tree/main/mouse 鼠標

vscode预览模式(点击文件时默认覆盖当前标签,标签名称显示为斜体,可通过双击该标签取消)覆盖标签、新窗打开

文章目录 VS Code 预览模式如何取消预览模式&#xff08;即“固定”标签页&#xff09;&#xff1f;预览模式有什么用&#xff1f; VS Code 预览模式 在 VS Code 中&#xff0c;当你单击文件浏览器&#xff08;例如&#xff0c;资源管理器侧边栏&#xff09;中的某个文件时&am…

记录踩过的坑-金蝶云苍穹平台-轻分析和轻报表(慢慢更新)

未发现AppIdName(qing rpt)服务或访问服务网络异常 前提是有许可和权限。 去console&#xff08;云基础平台控制台&#xff09;&#xff0c;点击服务管理&#xff0c;编辑mservice-更新升级-环境变量&#xff0c;在appIds里增加qing_rpt 查看数据库 如果是采用公共数据源连接…

每日一题洛谷T534125 合数c++

字符串输入&#xff0c;看所有位数加起来的数是不是3的倍数 是&#xff0c;直接输出&#xff0c;不是&#xff0c;删除1或2 特判全是1和全是2的情况 直接检测末尾数字可以特判2 特判1时&#xff0c;还要特判11和111&#xff0c;其他数字&#xff0c;k是奇数时是质数&#x…

数据链共享:从印巴空战到工业控制的跨越性应用

摘要 本文通过对印巴空战中数据链共享发挥关键作用的分析&#xff0c;引出数据链共享在工业控制领域同样具有重大价值的观点。深入阐述 DIOS 工业控制操作系统作为工业数据链共享基础技术的特点、架构及应用优势&#xff0c;对比空战场景与工业控制场景下数据链共享的相…

图解gpt之Seq2Seq架构与序列到序列模型

今天深入探讨如何构建更强大的序列到序列模型&#xff0c;特别是Seq2Seq架构。序列到序列模型&#xff0c;顾名思义&#xff0c;它的核心任务就是将一个序列映射到另一个序列。这个序列可以是文本&#xff0c;也可以是其他符号序列。最早&#xff0c;人们尝试用一个单一的RNN来…

Linux--JsonCpp

1.JsonCpp 简介 JsonCpp 是一个用于 C 的 JSON 解析和生成库&#xff0c;支持 JSON 数据的读写、解析和序列化。它提供了简单的 API 来操作 JSON 对象、数组、字符串、数字等类型&#xff0c;是 C 开发中处理 JSON 数据的常用工具。 核心功能与类 JsonCpp 主要包含以下核心类…