Vue3.5 企业级管理系统实战(十八):用户管理

本篇主要探讨用户管理功能,接口部分依然是使用 Apifox mock 模拟。

1 用户 api

在 src/api/user.ts 中添加用户相关 CRUD 接口,代码如下:

//src/api/user.ts 
import request from "@/api/config/request";
// 从 "./type" 模块中导入 ApiResponse 类型,用于定义接口响应数据的结构
import type { ApiResponse } from "./type";
import type { IRole } from "./role";/*** 定义用户登录所需的数据结构* @interface IUserLoginData* @property {string} username - 用户登录使用的用户名* @property {string} password - 用户登录使用的密码*/
export interface IUserLoginData {username: string;password: string;
}/*** 定义登录接口响应的数据结构* @interface ILoginResponseData* @property {string} token - 登录成功后返回的令牌,用于后续请求的身份验证*/
export interface ILoginResponseData {token: string;
}/*** 登录接口* @param {IUserLoginData} data - 用户登录所需的数据,包含用户名和密码* @returns {Promise<ApiResponse<ILoginResponseData>>} - 返回一个 Promise 对象,该对象解析为包含登录响应数据的 ApiResponse 类型*/
export const login = (data: IUserLoginData
): Promise<ApiResponse<ILoginResponseData>> => {return request.post("/4642164-4292760-default/287017559", data);
};
//test
export const logout_error = (): Promise<ApiResponse<ILoginResponseData>> => {return request.post("/4642164-4292760-default/auth/401");
};//个人中心接口
export interface Profile {id: number;username: string;email: string;mobile: string;isSuper: boolean;status: boolean;avatar: string;description: string;roles: IRole[];roleIds?: number[]; // 修改用户的时候,后端接受只要id
}export interface IUsers {users: Profile[];count: number;
}// 查询参数
export interface IUserQuery {pageNum?: number;pageSize?: number;mobile?: string;status?: boolean;username?: string;
}// 获取用户列表的接口
export const getUsers = (params: IUserQuery): Promise<ApiResponse<IUsers>> => {const {pageNum = 0,pageSize = 10,username = "",status,mobile = ""} = params;return request.get("/user", {params: {pageNum,pageSize,username,status,mobile}});
};// 删除用户
export const removeUser = (id: number): Promise<ApiResponse> => {return request.delete(`/user/${id}`);
};// 添加用户
export const addUser = (data: Profile): Promise<ApiResponse> => {return request.post("/auth/register", data);
};// 编辑用户
export const updateUser = (id: number, data: Profile): Promise<ApiResponse> => {return request.put(`/user/${id}`, data);
};

2 用户 Store

在 src/stores/user.ts 中添加用户相关方法,代码如下:

//src/stores/user.ts
import type { IUserLoginData, IUserQuery, IUsers, Profile } from "@/api/user";
import {login as loginApi,getUsers as getUsersApi, // 获取用户addUser as addUserApi,removeUser as removeUserApi,updateUser as updateUserApi
} from "@/api/user";
import { setToken, removeToken } from "@/utils/auth";
import { useTagsView } from "./tagsView";
import type { IRole } from "@/api/role";
export type IProfileQuery = Profile & {pageNum?: number;pageSize?: number;
};
export const useUserStore = defineStore("user", () => {const state = reactive({token: "",users: [] as IUsers["users"], // 用户列表count: 0, // 用户个数roles: [] as IRole[],userInfo: {} as Profile});const tagsViewStore = useTagsView();const login = async (userInfo: IUserLoginData) => {try {const { username, password } = userInfo;const response = await loginApi({ username: username.trim(), password });const { data } = response;state.token = data.token;setToken(data.token);} catch (e) {return Promise.reject(e);}};const logout = () => {state.token = "";removeToken();// 所有的信息都应该情况tagsViewStore.delAllView(); // ...};// 获取全部用户const getAllUsers = async (params: IUserQuery) => {const res = await getUsersApi(params);const { data } = res;state.users = data.users;state.count = data.count;};// 添加用户const addUser = async (data: IProfileQuery) => {const { pageSize, pageNum, ...params } = data;const res = await addUserApi(params);if (res.code === 0) {getAllUsers({pageSize,pageNum});}};// 删除用户const removeUser = async (data: IProfileQuery) => {const { pageSize, pageNum, id } = data;const res = await removeUserApi(id);if (res.code === 0) {getAllUsers({pageSize,pageNum});}};//编辑用户const editUser = async (data: IProfileQuery) => {const { pageSize, pageNum, ...params } = data;const res = await updateUserApi(params.id, params);if (res.code === 0) {getAllUsers({pageSize,pageNum});}};return {login,state,logout,getAllUsers,editUser,removeUser,addUser};
});

3 用户管理界面实现

3.1 editorUser 组件封装

在 src/views/system/user/components/editorUser.vue 中,实现用户新增编辑组件,代码如下:

//src/views/system/user/components/editorUser.vue
<template><div class="editor-container" p-20px><el-formref="editFormRef":model="editData":rules="menuFormRules"label-width="80px"><el-form-item label="用户名" prop="username"><el-input v-model="editData.username" placeholder="请输入用户名" /></el-form-item><el-form-item label="手机" prop="mobile"><el-inputv-model="editData.mobile"placeholder="请输入手机"maxlength="11"/></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="editData.email" placeholder="请输入邮箱" /></el-form-item><el-form-item label="状态" prop="status"><el-switch v-model="editData.status" /></el-form-item><el-form-item label="角色分配" prop="roleIds"><el-select multiple v-model="editData.roleIds" placeholder="请选择角色"><el-optionv-for="item in editData.roles":key="item.id":label="item.name":value="item.id"></el-option></el-select></el-form-item><el-form-item label="说明" prop="description"><el-inputtype="textarea":rows="3"v-model="editData.description"placeholder="请输入说明"/></el-form-item><el-form-item><el-button type="primary" @click="submitMenuForm">提交</el-button></el-form-item></el-form></div>
</template><script lang="ts" setup>
import type { Profile } from "@/api/user";
import type { FormInstance, FormItemRule } from "element-plus";
import type { PropType } from "vue";const props = defineProps({type: {// 操作类型 0编辑 1新增type: Number,required: true},data: {type: Object as PropType<Profile>}
});
const emit = defineEmits(["submit"]);const editFormRef = ref<FormInstance | null>(null);
const editData = ref<Partial<Profile>>({username: "",email: "",mobile: "",description: "",status: true
});// 验证规则
const validateMobile = (rule: unknown,value: string,callback: (arg?: Error) => void
) => {if (!isNaN(Number(value)) && value.length === 11) {callback();}callback(new Error("请输入正确格式手机号!"));
};const menuFormRules = {username: {required: true,message: "请输入用户名",trigger: "blur"},email: [{required: true,message: "请输入邮箱",trigger: "blur"},{type: "email",message: "请输入正确的邮箱地址",trigger: ["blur", "change"]}] as FormItemRule[],mobile: [{required: true,message: "请输入手机",trigger: "blur"},{message: "请输入正确11位手机号",trigger: "blur",validator: validateMobile}],roleIds: {required: true,message: "请至少选择一个角色!",trigger: "blur"}
};const defaultProps = {username: "",email: "",mobile: "",description: "",status: true
};watchEffect(() => {if (props.data) {// 移除之前表单效验结果editFormRef.value?.clearValidate();editData.value = { ...defaultProps, ...props.data };}
});// 提交编辑菜单
const submitMenuForm = () => {(editFormRef.value as FormInstance).validate((valid) => {if (valid) {emit("submit", editData.value);}});
};
</script>

3.2 用户管理页面

在 src/views/system/user/index.vue 中,编写用户管理静态页面,代码如下:

//src/views/system/user/index.vue
<template><div class="user-container" p-30px><h2>用户管理</h2><el-button type="primary" plain @click="handleAddUser" class="mb">添加用户</el-button><el-form :inline="true" :model="formQuery" ref="queryFormRef"><el-form-item label="用户名" prop="username"><el-inputv-model="formQuery.username"placeholder="请输入用户名"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-inputv-model="formQuery.mobile"placeholder="请输入手机号"></el-input></el-form-item><el-form-item label="状态" prop="status" w-200px><el-select v-model="formQuery.status" placeholder="状态"><el-option label="全部" value="all"></el-option><el-option label="禁用" :value="0"></el-option><el-option label="正常" :value="1"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="handleSubmitQuery">查询</el-button><el-button type="default" @click="handleResetFeilds">重置</el-button></el-form-item></el-form><div class="user-list"><el-table :data="users" max-height="400"><el-table-column prop="username" label="用户名"> </el-table-column><el-table-column prop="mobile" label="手机"> </el-table-column><el-table-column prop="email" label="邮箱"> </el-table-column><el-table-column prop="status" label="状态" :formatter="formatter"></el-table-column><el-table-column prop="createdAt" label="创建时间"> </el-table-column><el-table-column label="操作" fixed="right" width="150px"><template #default="scope"><el-buttonsize="small"link@click="handleEditUser(scope.$index, scope.row)">编辑</el-button><el-buttonsize="small"link@click="handleDeleteUser(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><div class="user-container"><div class="user-list"><!--用户展示--><div class="user-pagination"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange"background:total="total":page-sizes="[1, 5, 10, 20]":page-size="pageSize"layout="total, prev, pager, next, sizes,jumper"></el-pagination></div></div></div></div><right-panel v-model="panelVisible" :title="panelTitle" :size="330"><editor-user:type="editType":data="editData"@submit="handleSubmitUser"/></right-panel></div>
</template><script lang="ts" setup>
import type { IUserQuery, Profile } from "@/api/user";
import { useRoleStore } from "@/stores/role";
import { type IProfileQuery, useUserStore } from "@/stores/user";
import type { FormInstance } from "element-plus";
const store = useUserStore();
// 用户列表
const users = computed(() => store.state.users);
// 分页相关状态
const pageNum = ref(0);
const pageSize = ref(10);
// 获取用户列表 支持分页
const getUserList = () => {store.getAllUsers({pageNum: pageNum.value,pageSize: pageSize.value,...formQuery// ... 搜索条件} as unknown as IUserQuery);
};
// 格式化status
const formatter = (row: Profile) => {return row.status ? "正常" : "禁用";
};
// 不使用watchEffect
onMounted(() => {getUserList();
});
// 删除用户
const { proxy } = getCurrentInstance()!;
const handleDeleteUser = async (index: number, row: Profile) => {try {await proxy?.$confirm(`您确认要删除用户${row.username}吗?`, "删除确认", {type: "warning"});await store.removeUser({id: row.id,pageNum: pageNum.value,pageSize: pageSize.value} as IProfileQuery);proxy?.$message.success("用户删除成功");} catch {proxy?.$message({type: "info",message: "已取消删除"});}
};
const handleEditUser = (index: number, row: Profile) => {editType.value = 0;editData.value = { ...row };// 获取当前编辑用户 现有角色列表editData.value.roleIds = row.roles.map((item) => item.id);editData.value.roles = roles.value!; // 所有角色列表panelVisible.value = true;
};
// 用户总条数
const total = computed(() => store.state.count);
// 分页
const handleSizeChange = (val: number) => {pageSize.value = val;getUserList();
};
const handleCurrentChange = (val: number) => {pageNum.value = val - 1; // 页码后端是从0开始的getUserList();
};// 查询参数
const formQuery = reactive({username: "",status: "all",mobile: ""
});
const handleSubmitQuery = () => {getUserList();
};// 重置
const queryFormRef = useTemplateRef<FormInstance | null>("queryFormRef");
const handleResetFeilds = () => {(queryFormRef.value as FormInstance).resetFields();getUserList();
};const editData = ref<Profile | undefined>(undefined);
// 控制面板显示
const panelVisible = ref(false);
const editType = ref(1);
const panelTitle = computed(() =>editType.value === 1 ? "新增用户" : "编辑用户"
);
const storeRole = useRoleStore();
storeRole.getRoles({pageNum: pageNum.value,pageSize: pageSize.value,flag: 0
});
const roles = computed(() => storeRole.state.roles); // 角色const handleAddUser = () => {editType.value = 1;editData.value = {} as Profile;editData.value.roles = roles.value; // 所有角色列表editData.value.roleIds = []; // 所选角色id列表panelVisible.value = true;
};
const editUser = async (data: IProfileQuery) => {store.editUser({...data,pageSize: pageSize.value,pageNum: pageNum.value});(queryFormRef.value as FormInstance).resetFields();proxy?.$message.success("用户编辑成功");panelVisible.value = false;
};
const handleSubmitUser = (data: Profile) => {if (editType.value === 1) {// 新增addNewUser(data);} else {editUser(data);}
};
const addNewUser = (data: Profile) => {store.addUser({...data,pageSize: pageSize.value,pageNum: pageNum.value});(queryFormRef.value as FormInstance).resetFields();proxy?.$message.success("用户添加成功");panelVisible.value = false;
};
</script>

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

以上,就是用户管理的全部内容。

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

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

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

相关文章

【C】初阶数据结构14 -- 归并排序

本篇文章主要是讲解经典的排序算法 -- 归并排序 目录 1 递归版本的归并排序 1&#xff09; 算法思想 2&#xff09; 代码 3&#xff09; 时间复杂度与空间复杂度分析 &#xff08;1&#xff09; 时间复杂度 &#xff08;2&#xff09; 空间复杂度 2 迭代版本的归并…

【相机标定】OpenCV 相机标定中的重投影误差与角点三维坐标计算详解

摘要&#xff1a; 本文将从以下几个方面展开&#xff0c;结合典型代码深入解析 OpenCV 中的相机标定过程&#xff0c;重点阐述重投影误差的计算方法与实际意义&#xff0c;并通过一个 calcBoardCornerPositions() 函数详细讲解棋盘格角点三维坐标的构建逻辑。 在计算机视觉领域…

RabbitMQ-运维

文章目录 前言运维-集群介绍多机多节点单机多节点 多机多节点下载配置hosts⽂件配置Erlang Cookie启动节点构建集群查看集群状态 单机多节点安装启动两个节点再启动两个节点验证RabbitMQ启动成功搭建集群把rabbit2, rabbit3添加到集群 宕机演示仲裁队列介绍raft算法协议 raft基…

JVM之内存管理(一)

部分内容来源&#xff1a;JavaGuide二哥Java 图解JVM内存结构 内存管理快速复习 栈帧&#xff1a;局部变量表&#xff0c;动态链接&#xff08;符号引用转为真实引用&#xff09;&#xff0c;操作数栈&#xff08;存储中间结算结果&#xff09;&#xff0c;方法返回地址 运行时…

无线射频模块如何通过CE RED认证?关键规范与准备策略详解

随着无线通信设备在欧洲市场的广泛应用&#xff0c;CE RED认证已成为模块类产品进入欧盟的强制通行证。作为专注于LoRa模块、对讲模块与FSK射频模块研发的技术企业&#xff0c;我们深知从设计、测试到量产&#xff0c;每一个环节都需紧扣合规底线。本文将围绕CE RED认证核心要求…

Golang中集合相关的库

一切编程语言的底层结构都是数组&#xff0c;其它复杂数据结构如Map, Stack&#xff0c;Heap和Queue都是基于数组建立起来的。 Go语言主流工具库推荐&#xff08;含常用数据结构实现&#xff09; 以下是目前Go生态中最主流且活跃的工具库&#xff0c;包含队列、栈、优先级队列…

ABAP 导入Excel形成内表

文章目录 创建导入模板程序实现代码代码解析运行结果 创建导入模板 程序实现 代码 *&---------------------------------------------------------------------* *& Report Z_EXCEL_UPLOAD_LHY *&--------------------------------------------------------------…

特殊配合力(SCA)作为全基因组关联分析(GWAS)的表型,其生物学意义和应用价值

生物学意义 解析非加性遗传效应 特殊配合力(SCA)主要反映特定亲本组合的杂交优势,由非加性遗传效应(如显性、超显性、上位性)驱动。显性效应涉及等位基因间的显性互作,上位性效应则涉及不同位点间的基因互作。通过SCA-GWAS,可以定位调控这些非加性效应的关键基因组区域…

应急响应基础模拟靶机-security1

PS:杰克创建在流量包(result.pcap)在根目录下&#xff0c;请根据已有信息进行分析 1、攻击者使用的端口扫描工具是? 2、通过流量及日志审计&#xff0c;攻击者上传shell的时访问web使用IP地址是多少? 3、审计流量日志&#xff0c;攻击者反弹shell的地址及端口? 4、攻击者…

uniapp-商城-47-后台 分类数据的生成(通过数据)

在第46章节中&#xff0c;我们为后台数据创建了分类的数据表结构schema&#xff0c;使得可以通过后台添加数据并保存&#xff0c;同时使用云函数进行数据库数据的读取。文章详细介绍了如何通过前端代码实现分类管理功能&#xff0c;包括获取数据、添加、更新和删除分类。主要代…

ClickHouse的基本操作说明

说明 文章内容包括数据库管理、表操作及查询等核心功能 创建数据库 -- 默认引擎&#xff08;Atomic&#xff09; CREATE DATABASE IF NOT EXISTS test_db; -- MySQL引擎&#xff08;映射外部MySQL数据库&#xff09; CREATE DATABASE mysql_db ENGINE MySQL(host:port, m…

Nacos源码—7.Nacos升级gRPC分析四

大纲 5.服务变动时如何通知订阅的客户端 6.微服务实例信息如何同步集群节点 6.微服务实例信息如何同步集群节点 (1)服务端处理服务注册时会发布一个ClientChangedEvent事件 (2)ClientChangedEvent事件的处理源码 (3)集群节点处理数据同步请求的源码 (1)服务端处理服务注册…

《Overlapping Experiment Infrastructure: More, Better, Faster》论文阅读笔记

文章目录 1 背景2 三个核心概念3 Launch层&#xff1a;特性发布的专用机制4 流量分发策略和条件筛选4.1 四种流量分发类型4.2 条件筛选机制 5 工具链与监控体系6 实验设计原则7 培训参考与推荐 1 背景 谷歌&#xff08;Google&#xff09;以数据驱动著称&#xff0c;几乎所有可…

国芯思辰| 医疗AED可使用2通道24位模拟前端SC2946(ADS1292)

生物电信号监测技术在医疗健康行业中发展迅速&#xff0c;成为评估人体生理健康状况的关键手段。心电&#xff08;ECG&#xff09;、脑电&#xff08;EEG&#xff09;和肌电&#xff08;EMG&#xff09;等信号&#xff0c;通过精密模拟前端芯片捕捉和处理&#xff0c;对医疗诊断…

数据结构【二叉搜索树(BST)】

二叉搜索树 1. 二叉搜索树的概念2. 二叉搜索树的性能分析3.二叉搜索树的插入4. 二叉搜索树的查找5. 二叉搜索树的删除6.二叉搜索树的实现代码7. 二叉搜索树key和key/value使用场景7.1 key搜索场景&#xff1a;7.2 key/value搜索场景&#xff1a; 1. 二叉搜索树的概念 二叉搜索…

RDMA高性能网络通信实践

RDMA高性能网络通信实践 一、背景介绍二、方法设计A.实现方案B.关键技术点 三、代码及注释四、注意事项 一、背景介绍 远程直接内存访问&#xff08;RDMA&#xff09;技术通过绕过操作系统内核和CPU直接访问远程内存&#xff0c;实现了超低延迟、高吞吐量的网络通信。该技术广…

ndarray数组掩码操作,True和False获取数据

#数组掩码的表示方法 def testht05():a np.arange(1,10)mask [True,False,True,True,False,True,False,True,True]print(a[mask]) 另外的用法&#xff1a; #掩码操作获取子集 def testht06():a np.arange(1,100)print(a[a%3 0 & (a%7 0)] )b np.array([A,"B&qu…

索引工具explain

EXPLAIN 是 MySQL 中一个非常有用的工具,用于分析查询的执行计划。通过 EXPLAIN,你可以了解 MySQL 是如何执行查询的,包括它如何使用索引、表的扫描方式等。这有助于优化查询性能。以下是 EXPLAIN 输出的各个字段的详细解释: 基本用法 EXPLAIN SELECT * FROM table_name …

Git回顾

参考视频:【GeekHour】一小时Git教程 一句话定义&#xff1a;Git是一个免费开源的分布式版本控制系统。 版本控制系统可以分为两种&#xff0c;1.集中式&#xff08;SVN&#xff0c;CVS&#xff09;&#xff1b;2.分布式&#xff08;git&#xff09; git的工作区域和文件状态…

python打卡day20

特征降维------特征组合&#xff08;以SVD为例&#xff09; 知识点回顾&#xff1a; 奇异值的应用&#xff1a; 特征降维&#xff1a;对高维数据减小计算量、可视化数据重构&#xff1a;比如重构信号、重构图像&#xff08;可以实现有损压缩&#xff0c;k 越小压缩率越高&#…