挑战一周完成Vue3项目Day4: 用户管理+角色管理+菜单管理+首页+暗黑模式/主题切换

一、用户管理

1.静态搭建

src/views/acl/user/index.vue

<template><el-card style="height:80px;"><el-form :inline="true" class="form"><el-form-item label="用户名:"><el-input placeholder="请你输入用户名"></el-input></el-form-item><el-form-item><el-button type="primary" size="default">搜索</el-button><el-button type="primary" size="default">重置</el-button></el-form-item></el-form></el-card><el-card style="margin:10px 0;"><el-button type="primary" size="default">添加用户</el-button><el-button type="primary" size="default">批量删除</el-button><!-- table展示表单信息 --><el-table style="margin:10px 0;" border><el-table-column type="selection" align="center"></el-table-column><el-table-column label="#" align="center"></el-table-column><el-table-column label="ID" align="center"></el-table-column><el-table-column label="用户名字" align="center"></el-table-column><el-table-column label="用户名称" align="center"></el-table-column><el-table-column label="用户角色" align="center"></el-table-column><el-table-column label="创建时间" align="center"></el-table-column><el-table-column label="更新时间" align="center"></el-table-column><el-table-column label="操作" width="260px" align="center"></el-table-column></el-table><!-- 分页器 --><el-paginationv-model:current-page="pageNo"v-model:page-size="pageSize":page-sizes="[3,5,7,9]":background="true"layout="prev, pager, next, jumper,->,size,total":total="400"/></el-card>
</template><script setup lang="ts">
import {ref} from 'vue';
// 展示当前页
let pageNo=ref<number>(1)
// 每页几个数据
let pageSize=ref<number>(5)
</script><style scoped>
.form{display: flex;justify-content: space-between;align-items: center;
}
</style>

2.业务实现流程

2.1展示已有账号的数据 

1.一上来就发请求获取数据,点击不同的页码也要发请求
2.定义接口数据
3.获取数据
4.存储数据
5.展示数据(在table和分页器都要展示)

2.2添加与修改用户 

1.静态搭建
抽屉结构》drawer
添加点击按钮和编辑按钮弹出抽屉事件

 2.完成添加业务
(1)添加地址接口(判断携带参数有无id)和定义数据
(2)收集数据用v-model收集到定义好的userParams里面。(定义参数userParams收集用户信息的响应式数据)
(3)添加点击保存按钮回调save.(code=200判断添加/更新有无id,关闭抽屉并弹出相应的提示信息,再次获取最新数据getHasUser)
(4)添加取消按钮的回调cancel.
(5)每次点击确定或者取消都要清空数据:在addUser里面清空数据

3.表单校验功能
(1)校验username,name,password
(2)给抽屉的身体部分添加校验规则:rules="rules"(告诉表单数据数据收集:model="userParams"并给表单项添加prop)
(3)校验规则


// 校验用户名字回调函数
const validatorUsername = (rule: any, value: any, callBack: any) => {// 用户名字|昵称,长度至少五位if (value.trim().length >= 5) {callBack()} else {callBack(new Error('用户名字至少五位'))}
}
// 校验用户昵称回调函数
const validatorName = (rule: any, value: any, callBack: any) => {// 用户名字|昵称,长度至少五位if (value.trim().length >= 5) {callBack()} else {callBack(new Error('用户昵称至少五位'))}
}
// 校验用户名字回调函数
const validatorPassword = (rule: any, value: any, callBack: any) => {// 用户名字|昵称,长度至少六位if (value.trim().length >= 6) {callBack()} else {callBack(new Error('用户密码至少六位'))}
}
// 表单校验的规则对象
const rules = {// 用户名字username: [{ required: true, trigger: 'blur', validator: validatorUsername }],// 用户昵称name: [{ required: true, trigger: 'blur', validator: validatorName }],// 用户密码password: [{ required: true, trigger: 'blur', validator: validatorPassword }]
}

(4)注意:务必要在点击addUaer时进行校验

// 点击保存按钮的时候,务必需要保证表单全部符合条件再去发请求await formRef.value.validate()

(5)用nexttick和清空表单校验信息在addUser内
 

// 清除上一次的错误提示信息nextTick(() => {formRef.value.clearValidate('username')formRef.value.clearValidate('name')formRef.value.clearValidate('password')})

(6)注意触发时机,trigger要用blur不用change(因为会清空数据自动发生变化,无法清空校验错误信息)

 4.更新业务完成
(1)动态展示标题和是否有密码

<template #header><h4>{{ userParams.id ? '更新用户' : '添加用户' }}</h4></template><el-form-item label="用户密码" prop="password" v-if="!userParams.id">

(2)updateUser回调记得清空数据

// 更新已有的用户按钮的回调
// row:即为已有用户的账号信息
const updateUser = (row: User) => {// 抽屉显示出来drawer.value = true// 存储收集已有的账号xinxObject.assign(userParams, row)// 清除上一次的错误提示信息nextTick(() => {formRef.value.clearValidate('username')formRef.value.clearValidate('name')})
}

(3)判断添加留在第一页、更新停留在当前页。在save内:

再添加了window刷新之后,这个可要可不要

// 获取最新的全部账号信息getHasUser(userParams.id ? pageNo.value : 1)

(4)解决修改到当前登录用户信息需要重新登录的问题,在save内:

// 浏览器自动刷新一次(为了解决修改到当前登录用户信息需要重新登录的问题)window.location.reload()

2.3 分配角色

1.静态搭建
》抽屉el-drwer》全选框el-checkbox》复选框el-checkbox-group
点击分配角色按钮出现抽屉结构@click="setRole(row)"
展示用户姓名username信息:存储数据》展示数据》禁用效果

<!-- 抽屉结构:用于某个已有账号进行职位分配 --><el-drawer v-model="drawer1"><template #header><h4>分配角色用户</h4></template><template #default><el-form><el-form-item label="用户姓名"><el-input v-model="userParams.username" :disabled="true"></el-input></el-form-item><el-form-item label="角色列表"><el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">全选</el-checkbox><!-- 显示职位的复选框 --><el-checkbox-group v-model="userRole" @change="handleCheckedCitiesChange"><el-checkbox v-for="(role, index) in allRole" :key="index" :label="role">{{ role.roleName }}</el-checkbox></el-checkbox-group></el-form-item></el-form></template><template #footer><div style="flex: auto"><el-button @click="drawer1 = false">取消</el-button><el-button type="primary" @click="confirmClick">确认</el-button></div></template></el-drawer>

2.分配角色业务
(1)定义API接口和方法,返回数据的ts类型
(2)获取全部职位数据allRolesList和当前用户职位的数据assignRoles:setRole里
(3)存储数据:
(4)展示所有职位:通过v-for和role.roleName展示
(5)展示勾选当前用户角色:v-model="userRole"
(6)全选、全不选效果,不确定样式

// 分配角色按钮的回调
const setRole = async (row: User) => {// 存储已有的用户信息Object.assign(userParams, row)//获取全部的职位的数据与当前用户已有的职位的数据let result: AllRoleResponseData = await reqAllRole((userParams.id as number))if (result.code === 200) {//存储全部的职位allRole.value = result.data.allRolesList//存储当前用户已有的职位  userRole.value = result.data.assignRoles// 抽屉显示出来drawer1.value = true}
}//收集顶部复选框全选数据
const checkAll = ref<boolean>(false)
//控制顶部全选复选框不确定的样式
const isIndeterminate = ref<boolean>(true)
//存储全部职位的数据
let allRole = ref<AllRole>([])
//当前用户已有的职位
let userRole = ref<AllRole>([])
//顶部的全部复选框的change事件
const handleCheckAllChange = (val: boolean) => {//val:true(全选)|false(没有全选)userRole.value = val ? allRole.value : []//不确定的样式(确定样式)isIndeterminate.value = false
}
//顶部全部的复选框的change事件
const handleCheckedCitiesChange = (value: string[]) => {//顶部复选框的勾选数据//代表:勾选上的项目个数与全部的职位个数相等,顶部的复选框勾选上checkAll.value = value.length === allRole.value.length//不确定的样式isIndeterminate.value = value.length !== allRole.value.length
}

3.点击确定取消业务
(1)定义接口方法,ts类型
(2)取消按钮
<el-button @click="drawer1 = false">取消</el-button>
(3)确定按钮@click="confirmClick"
需要收集参数(当前用户id,收集到的职位id)》分配用户职位(判断,提示信息,获取更新完毕用户的信息,更新后留在当前页)

// 确定按钮的回调(分配职位)
const confirmClick = async () => {// 收集参数let data: SetRoleData = {userId: (userParams.id as number),roleIdList: userRole.value.map(item => {return (item.id as number)})}// 分配用户的职位let result: any = await reqSetUserRole(data)if (result.code === 200) {// 提示信息ElMessage({type: 'success',message: '分配职务成功'})// 关闭抽屉drawer1.value = false// 获取更新完毕用户的信息,更新完毕留在当前页getHasUser(pageNo.value)}
}

2.4删除业务 

(1)定义删除某一个账号和批量删除的API接口、方法,ts数据类型定义
(2)气泡确认框

<el-popconfirm :title="`你确定要删除${row.username}?`" width="260px" @confirm="deleteUser(row.id)"><template #reference><el-button type="primary" size="small" icon="Delete">删除</el-button></template></el-popconfirm>

(3)删除某一个用户
绑定事件@confirm="deleteUser(row.id)"(要根据id去删除)
发送请求判断是否成功之后,再捞一次数据,判断回到当前页还是上一页

// 删除某一个用户
const deleteUser = async (userId: number) => {let result: any = await reqRemoveUser(userId)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功'})getHasUser(userArr.value.length > 1 ? pageNo.value : pageNo.value - 1)}
}

(4)批量删除
在table身上绑定@selection-change="selectChange"》选中和存储批量删除的用户Id
给批量删除按钮判断是否需要禁用效果,:disabled="selectIdArr.length?false:true"并绑定点击事件deleteSelectUser

//准备一个数组存储批量删除的用户的ID
let selectIdArr = ref<User[]>([])
//table复选框勾选的时候会触发的事件
const selectChange = (value: any) => {selectIdArr.value = value
}// 批量删除按钮的回调
const deleteSelectUser = async () => {//整理批量删除的参数let idsList: any = selectIdArr.value.map(item => {return item.id})//批量删除的请求let result: any = await reqSelectUser(idsList)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功'})getHasUser(userArr.value.length > 1 ? pageNo.value : pageNo.value - 1)}
}

2.5搜索业务

(1)收集用户输入进来的关键字
        

<el-input placeholder="请输入用户名称" v-model="keyword"></el-input>
//定义响应式数据:收集用户输入进来的关键字
let keyword = ref<string>('')

(2)搜索按钮添加禁用效果
:disabled="keyword?false:true"
(3)搜索按钮绑定事件search
要注意的是,要给获取用户账号信息的接口添加一个username字段,才可以搜索

// 获取用户账号信息的接口
export const reqUserInfo = (page: number, limit: number, username: string) => request.get<any, UserResponseData>(API.ALLUSER_URL + `${page}/${limit}/?username=${username}`)
// 搜索按钮的回调
const search = () => {//根据关键字获取相应的用户数据getHasUser()//清空关键字keyword.value = ''
}

(4)重置按钮reset
要引入之前的仓库,来刷新

import useLayOutSettingStore from '@/store/modules/setting'
//获取模板setting仓库
let settingStore = useLayOutSettingStore()
//重置按钮
const reset = () => {settingStore.refresh = !settingStore.refresh
}

3.代码 

src/api/acl/user/index.ts

// 用户管理模块的接口
import request from '@/utils/request'
import type {AllRoleResponseData,SetRoleData,User,UserResponseData
} from './type'
enum API {// 获取全部已有用户账号信息ALLUSER_URL = '/admin/acl/user/',// 添加一个新的用户账号ADDUSER_URL = '/admin/acl/user/save',// 更新已有的用户账号UPDATEUSER_URL = '/admin/acl/user/update',//获取全部职位,当前账号拥有的职位接口ALLROLEURL = '/admin/acl/user/toAssign/',//给已有的用户分配角色接口SETROLE_URL = '/admin/acl/user/doAssignRole',//删除某一个账号DELETEUSER_URL = '/admin/acl/user/remove/',//批量删除的接口DELETEALLUSER_URL = '/admin/acl/user/batchRemove',
}
// 获取用户账号信息的接口
export const reqUserInfo = (page: number, limit: number, username: string) => request.get<any, UserResponseData>(API.ALLUSER_URL + `${page}/${limit}/?username=${username}`)
// 添加用户与更新已有用户的接口
export const reqAddOrUpdateUser = (data: User) => {// 携带参数有ID更新if (data.id) {return request.put<any, any>(API.UPDATEUSER_URL, data)} else {return request.post<any, any>(API.ADDUSER_URL, data)}
}//获取全部职位以及包含当前用户的已有的职位
export const reqAllRole = (userId: number) =>request.get<any, AllRoleResponseData>(API.ALLROLEURL + userId)
//分配职位
export const reqSetUserRole = (data: SetRoleData) =>request.post<any, any>(API.SETROLE_URL, data)
//删除某一个账号的信息
export const reqRemoveUser = (userId: number) =>request.delete<any, any>(API.DELETEUSER_URL + userId)
//批量删除的接口
export const reqSelectUser = (idList: number[]) =>request.delete(API.DELETEALLUSER_URL, { data: idList })

 src/api/acl/user/type.ts 

//账号信息的ts类型
export interface ResponseData {code: numbermessage: stringok: boolean}//代表一个账号信息的ts类型export interface User {id?: numbercreateTime?: stringupdateTime?: stringusername?: stringpassword?: stringname?: stringphone?: nullroleName?: string}//数组包含全部的用户信息export type Records = User[]//获取全部用户信息接口返回的数据ts类型export interface UserResponseData extends ResponseData {data: {records: Recordstotal: numbersize: numbercurrent: numberpages: number}}//代表一个职位的ts类型export interface RoleData {id?: numbercreateTime?: stringupdateTime?: stringroleName: stringremark: null}//全部职位的列表export type AllRole = RoleData[]//获取全部职位的接口返回的数据ts类型export interface AllRoleResponseData extends ResponseData {data: {assignRoles: AllRoleallRolesList: AllRole}}//给用户分配职位接口携带参数的ts类型export interface SetRoleData {roleIdList: number[]userId: number}

src/views/acl/user/index.vue   

<template><el-card style="height: 80px;"><el-form :inline="true" class="form"><el-form-item label="用户名:"><el-input placeholder="请输入用户名称" v-model="keyword"></el-input></el-form-item><el-form-item><el-button type="primary" @click="search">搜索</el-button><el-button type="primary" plain @click="reset">重置</el-button></el-form-item></el-form></el-card><el-card style="margin: 10px 0;"><el-button type="primary" size="default" @click="addUser">添加用户</el-button><el-button type="danger" size="default" @click="deleteSelectUser">批量删除</el-button><!-- table展示用户信息 --><el-table @selection-change="selectChange" style="margin: 10px 0;" border :data="userArr"><el-table-column type="selection" align="center"></el-table-column><el-table-column label="#" align="center" type="index"></el-table-column><el-table-column label="id" prop="id"></el-table-column><el-table-column label="用户名字" prop="username" show-overflow-tooltip></el-table-column><el-table-column label="用户名称" prop="name" show-overflow-tooltip></el-table-column><el-table-column label="用户角色" prop="roleName" show-overflow-tooltip></el-table-column><el-table-column label="创建时间" prop="createTime" show-overflow-tooltip></el-table-column><el-table-column label="更新时间" prop="updateTime" show-overflow-tooltip></el-table-column><el-table-column label="操作" width="300px" align="center"><template #="{ row, $index }"><el-button type="primary" size="small" icon="User" @click="setRole(row)">分配角色</el-button><el-button type="primary" size="small" icon="Edit" @click="updateUser(row)">编辑</el-button><el-popconfirm :title="`你确定要删除${row.username}?`" width="260px" @confirm="deleteUser(row.id)"><template #reference><el-button type="primary" size="small" icon="Delete">删除</el-button></template></el-popconfirm></template></el-table-column></el-table><el-pagination v-model:current-page="pageNo" v-model:page-size="pageSize" :page-sizes="[5, 7, 9, 11]":background="true" layout="prev, pager, next, jumper,->,sizes,total" :total="total" @current-change="getHasUser"@size-change="handler" /></el-card><!-- 抽屉结构:完成添加新的用户账号更新已有的账号信息 --><el-drawer v-model="drawer"><template #header><h4>{{ userParams.id ? '更新用户' : '添加用户' }}</h4></template><template #default><el-form :model="userParams" :rules="rules" ref="formRef"><el-form-item label="用户姓名" prop="username"><el-input placeholder="请您输入用户姓名" v-model="userParams.username"></el-input></el-form-item><el-form-item label="用户昵称" prop="name"><el-input placeholder="请您输入用户昵称" v-model="userParams.name"></el-input></el-form-item><el-form-item label="用户密码" prop="password" v-if="!userParams.id"><el-input placeholder="请您输入用户密码" v-model="userParams.password"></el-input></el-form-item></el-form></template><template #footer><div style="flex: auto"><el-button @click="cancel">取消</el-button><el-button type="primary" @click="save">确认</el-button></div></template></el-drawer><!-- 抽屉结构:用于某个已有账号进行职位分配 --><el-drawer v-model="drawer1"><template #header><h4>分配角色用户</h4></template><template #default><el-form><el-form-item label="用户姓名"><el-input v-model="userParams.username" :disabled="true"></el-input></el-form-item><el-form-item label="角色列表"><el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">全选</el-checkbox><!-- 显示职位的复选框 --><el-checkbox-group v-model="userRole" @change="handleCheckedCitiesChange"><el-checkbox v-for="(role, index) in allRole" :key="index" :label="role">{{ role.roleName }}</el-checkbox></el-checkbox-group></el-form-item></el-form></template><template #footer><div style="flex: auto"><el-button @click="drawer1 = false">取消</el-button><el-button type="primary" @click="confirmClick">确认</el-button></div></template></el-drawer>
</template><script setup lang="ts">
import useLayOutSettingStore from '@/store/modules/setting'
import { reqAddOrUpdateUser, reqAllRole, reqRemoveUser, reqSelectUser, reqSetUserRole, reqUserInfo } from '@/api/acl/user';
import type { AllRole, AllRoleResponseData, Records, SetRoleData, User, UserResponseData } from '@/api/acl/user/type'
import { ElMessage } from 'element-plus';
import { nextTick, onMounted, reactive, ref } from 'vue';
// 默认页码
let pageNo = ref<number>(1)
// 一页展示几条数据
let pageSize = ref<number>(10)
// 用户总个数
let total = ref<number>(0)
// 存储全部用户的数组
let userArr = ref<Records>([])
// 定义响应式数据控制抽屉的显示与隐藏
let drawer = ref<boolean>(false)
// 控制分配角色抽屉显示与隐藏
let drawer1 = ref<boolean>(false)
// 收集用户信息的响应式数据
let userParams = reactive<User>({username: '',name: '',password: ''
})
// 获取dorm组件实例
let formRef = ref()
//定义响应式数据:收集用户输入进来的关键字
let keyword = ref<string>('')
//获取模板setting仓库
let settingStore = useLayOutSettingStore()
// 组件挂载完毕
onMounted(() => {getHasUser()
})
// 获取全部已有用户信息
const getHasUser = async (pager = 1) => {// 收集当前页码pageNo.value = pagerlet result: UserResponseData = await reqUserInfo(pageNo.value, pageSize.value, keyword.value)if (result.code === 200) {total.value = result.data.totaluserArr.value = result.data.records}
}
// 分页器下拉菜单的自定义事件的回调
const handler = () => {getHasUser()
}
// 添加用户按钮的回调
const addUser = () => {// 抽屉显示出来drawer.value = true// 清空数据Object.assign(userParams, {id: 0,username: '',name: '',password: ''})// 清除上一次的错误提示信息nextTick(() => {formRef.value.clearValidate('username')formRef.value.clearValidate('name')formRef.value.clearValidate('password')})
}
// 更新已有的用户按钮的回调
// row:即为已有用户的账号信息
const updateUser = (row: User) => {// 抽屉显示出来drawer.value = true// 存储收集已有的账号xinxObject.assign(userParams, row)// 清除上一次的错误提示信息nextTick(() => {formRef.value.clearValidate('username')formRef.value.clearValidate('name')})
}// 保存按钮的回调
const save = async () => {// 点击保存按钮的时候,务必需要保证表单全部符合条件再去发请求await formRef.value.validate()// 保存按钮:添加新的用户|更新已有的用户账号信息let result: any = await reqAddOrUpdateUser(userParams)if (result.code === 200) {// 关闭抽屉drawer.value = false// 提示信息ElMessage({type: 'success',message: userParams.id ? '更新成功' : '添加成功'})// 获取最新的全部账号信息// getHasUser(userParams.id ? pageNo.value : 1)// 浏览器自动刷新一次(为了解决修改到当前登录用户信息需要重新登录的问题)window.location.reload()} else {// 关闭抽屉drawer.value = false// 提示信息ElMessage({type: 'error',message: userParams.id ? '更新失败' : '添加失败'})}
}
// 取消按钮的回调
const cancel = () => {// 关闭抽屉drawer.value = false
}
// 校验用户名字回调函数
const validatorUsername = (rule: any, value: any, callBack: any) => {// 用户名字|昵称,长度至少五位if (value.trim().length >= 5) {callBack()} else {callBack(new Error('用户名字至少五位'))}
}
// 校验用户昵称回调函数
const validatorName = (rule: any, value: any, callBack: any) => {// 用户名字|昵称,长度至少五位if (value.trim().length >= 5) {callBack()} else {callBack(new Error('用户昵称至少五位'))}
}
// 校验用户名字回调函数
const validatorPassword = (rule: any, value: any, callBack: any) => {// 用户名字|昵称,长度至少六位if (value.trim().length >= 6) {callBack()} else {callBack(new Error('用户密码至少六位'))}
}
// 表单校验的规则对象
const rules = {// 用户名字username: [{ required: true, trigger: 'blur', validator: validatorUsername }],// 用户昵称name: [{ required: true, trigger: 'blur', validator: validatorName }],// 用户密码password: [{ required: true, trigger: 'blur', validator: validatorPassword }]
}// 分配角色按钮的回调
const setRole = async (row: User) => {// 存储已有的用户信息Object.assign(userParams, row)//获取全部的职位的数据与当前用户已有的职位的数据let result: AllRoleResponseData = await reqAllRole((userParams.id as number))if (result.code === 200) {//存储全部的职位allRole.value = result.data.allRolesList//存储当前用户已有的职位  userRole.value = result.data.assignRoles// 抽屉显示出来drawer1.value = true}
}//收集顶部复选框全选数据
const checkAll = ref<boolean>(false)
//控制顶部全选复选框不确定的样式
const isIndeterminate = ref<boolean>(true)
//存储全部职位的数据
let allRole = ref<AllRole>([])
//当前用户已有的职位
let userRole = ref<AllRole>([])
//顶部的全部复选框的change事件
const handleCheckAllChange = (val: boolean) => {//val:true(全选)|false(没有全选)userRole.value = val ? allRole.value : []//不确定的样式(确定样式)isIndeterminate.value = false
}
//顶部全部的复选框的change事件
const handleCheckedCitiesChange = (value: string[]) => {//顶部复选框的勾选数据//代表:勾选上的项目个数与全部的职位个数相等,顶部的复选框勾选上checkAll.value = value.length === allRole.value.length//不确定的样式isIndeterminate.value = value.length !== allRole.value.length
}
// 确定按钮的回调(分配职位)
const confirmClick = async () => {// 收集参数let data: SetRoleData = {userId: (userParams.id as number),roleIdList: userRole.value.map(item => {return (item.id as number)})}// 分配用户的职位let result: any = await reqSetUserRole(data)if (result.code === 200) {// 提示信息ElMessage({type: 'success',message: '分配职务成功'})// 关闭抽屉drawer1.value = false// 获取更新完毕用户的信息,更新完毕留在当前页getHasUser(pageNo.value)}
}// 删除某一个用户
const deleteUser = async (userId: number) => {let result: any = await reqRemoveUser(userId)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功'})getHasUser(userArr.value.length > 1 ? pageNo.value : pageNo.value - 1)}
}//准备一个数组存储批量删除的用户的ID
let selectIdArr = ref<User[]>([])
//table复选框勾选的时候会触发的事件
const selectChange = (value: any) => {selectIdArr.value = value
}// 批量删除按钮的回调
const deleteSelectUser = async () => {//整理批量删除的参数let idsList: any = selectIdArr.value.map(item => {return item.id})//批量删除的请求let result: any = await reqSelectUser(idsList)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功'})getHasUser(userArr.value.length > 1 ? pageNo.value : pageNo.value - 1)}
}// 搜索按钮的回调
const search = () => {//根据关键字获取相应的用户数据getHasUser()//清空关键字keyword.value = ''
}
//重置按钮
const reset = () => {settingStore.refresh = !settingStore.refresh
}
</script><style scoped>
.form {display: flex;justify-content: space-between;align-items: center;
}
</style>

 二、角色管理 

1.静态搭建

静态搭建这一部分和用户管理的极为相似这里就不细写。

2.业务实现流程

2.1数据的展示

2.1角色管理模块数据的展示
(1)定义API接口,方法,数据类型
(2)挂载时和切换页码时发送请求展示已有数据,引入onMounted和请求方法
(3)获取数据,存储全部已有的职位
(4)展示数据
分页器
:total="total" @current-change="getHasRole" @size-change="sizeChange",
table用:data="roleArr"
其他的用prop展示

// 组件挂载完毕
onMounted(() => {// 获取角色请求getHasRole()
})
// 获取全部已有的角色信息的方法|分页器当前页码发生变化的回调
const getHasRole = async (pager = 1) => {// 修改当前页码pageNo.value = pagerlet result: RoleResponseData = await reqRoleInfo(pageNo.value,pageSize.value,keyword.value,)if (result.code === 200) {total.value = result.data.totalroleArr.value = result.data.records}
}
// 分页器下拉菜单的自定义事件的回调
const sizeChange = () => {getHasRole()
}

(5)搜索重置功能
先收集到输入的数据keyword,搜索按钮禁用效果,绑定search方法和重置reset方法

// 搜索按钮的回调
const search = () => {//根据关键字获取相应的角色数据getHasRole()//清空关键字keyword.value = ''
}//获取模板setting仓库
let settingStore = useLayOutSettingStore()
// 重置按钮的回调
const reset = () => {settingStore.refresh = !settingStore.refresh
}

 2.2添加和更新角色

1.静态搭建
(1)添加新增角色更新角色的 地址和方法(两者可以封装到一个函数方法里面,唯一的区别就是有无id,新增没有id,更新有id)
(2)dialog对话框
(3)控制对话框显示与隐藏。给添加和编辑按钮添加事件addRole,updateRole(row)
(4)取消按钮 @click="dialogVisible = false"

<!-- 添加角色与更新已有角色的结构:对话框 --><el-dialog :title="roleParams.id ? '更新' : '添加'" v-model="dialogVisible"><el-form :model="roleParams" :rules="rules" ref="form"><el-form-item label="角色名称" prop="roleName"><el-input placeholder="请填写角色名称" v-model="roleParams.roleName"></el-input></el-form-item></el-form><template #footer><el-button size="default" @click="dialogVisible = false">取消</el-button><el-button type="primary" size="default" @click="save">确认</el-button></template></el-dialog>

2.完成添加职位

收集到新增的职位数据》表单校验》判断》再次获取全部已有数据》清空数据》清空错误提示》将对话框隐藏(记得更新返回的是当前页还是添加上一页)
(1)收集新增职位数据

// 收集新增岗位数据
let roleParams = reactive<RoleData>({roleName: '',
})

(2)自定义表单校验

// 自定义校验规则的回调
const validatorRoleName = (rule: any, value: any, callBack: any) => {// 角色名称,长度至少五位if (value.trim().length >= 2) {callBack()} else {callBack(new Error('角色名称至少两位'))}
}
// 角色校验规则
const rules = {roleName: [{ required: true, trigger: 'blur', validator: validatorRoleName }],
}

(3)确定按钮save的回调

// 确定按钮的回调
const save = async () => {// 表单校验结果,结果通过再发请求,结果没通过不应该发请求await form.value.validate()// 添加职位|更新角色的请求let result: any = await reqAddOrUpdateRole(roleParams)if (result.code === 200) {// 提示信息ElMessage({type: 'success',message: roleParams.id ? '添加成功' : '更新成功',})// 再次获取全部已有角色getHasRole(roleArr.value.length > 1 ? pageNo.value : pageNo.value - 1)} else {// 提示信息ElMessage({type: 'error',message: roleParams.id ? '添加失败' : '更新失败',})}// 对话框隐藏dialogVisible.value = false
}


(4)添加按钮的回调

// 添加角色按钮的回调
const addRole = () => {// 对话框显示出来dialogVisible.value = true// 清空数据Object.assign(roleParams, {roleName: '',id: 0,})// 清空上一次表单校验错误提示nextTick(() => {form.value.clearValidate('roleName')})
}

3.更新(修改)按钮完成

updateRole回调

// 更新角色按钮的回调
const updateRole = (row: RoleData) => {// 对话框显示出来dialogVisible.value = true// 存储已有角色---带有id的Object.assign(roleParams, row)// 清空上一次表单校验错误提示nextTick(() => {form.value.clearValidate('roleName')})
}

 2.3分配权限

(1)静态搭建:抽屉组件drawer》tree树形控件

<!-- 抽屉组件:分配角色的菜单权限与按钮权限 --><el-drawer v-model="drawer"><template #header><h4>分配菜单与按钮的权限</h4></template><template #default><el-tree ref="tree" :data="menuArr" show-checkbox node-key="id" default-expand-all:default-checked-keys="selectArr" :props="defaultProps" /></template><template #footer><div style="flex: auto"><el-button @click="drawer = false">取消</el-button><el-button type="primary" @click="handler">确认</el-button></div></template></el-drawer>

(2)书写API接口和方法,定义数据类型
(3)分配权限按钮的回调setPermission

//分配权限按钮的回调
//已有的职位的数据
const setPermission = async (row: RoleData) => {//抽屉显示出来drawer.value = true//收集当前要分类权限的职位的数据Object.assign(roleParams, row)//根据职位获取权限的数据let result: MenuResponseData = await reqAllMenuList(roleParams.id as number)if (result.code === 200) {menuArr.value = result.dataselectArr.value = filterSelectArr(menuArr.value, [])}
}const defaultProps = {children: 'children',label: 'name',
}

(4)展示菜单权限数据和按钮数据::data="menuArr"
(5)勾选用户已有的权限
准备数组存储四级select为true的id;


//准备一个数组:数组用于存储勾选的节点的ID(四级的)
let selectArr = ref<number[]>([])

 过滤四级的id.(递归)

const filterSelectArr = (allData: any, initArr: any) => {allData.forEach((item: any) => {if (item.select && item.level === 4) {initArr.push(item.id)}if (item.children && item.children.length > 0) {filterSelectArr(item.children, initArr)}})return initArr
}

(6)抽屉确定按钮的回调

携带职位的id,选中节点的id,半选的id》下发权限》判断》页面刷新window

//抽屉确定按钮的回调
const handler = async () => {//职位的IDconst roleId = roleParams.id as number//选中节点的IDlet arr = tree.value.getCheckedKeys()//半选的IDlet arr1 = tree.value.getHalfCheckedKeys()let permissionId = arr.concat(arr1)//下发权限let result: any = await reqSetPermission(roleId, permissionId)if (result.code === 200) {//抽屉关闭drawer.value = false//提示信息ElMessage({type: 'success',message: '分配权限成功',})//页面刷新window.location.reload()}
}

2.3删除业务

(1)编写API方法,定义数据类型
(2)气泡确认框

<el-popconfirm :title="`你确定要删除${row.roleName}?`" width="260px" @confirm="removeRole(row.id)"><template #reference><el-button type="primary" size="small" icon="Delete">删除</el-button></template></el-popconfirm>

(3)删除的回调 removeRole
 

//删除已有的职位
const removeRole = async (id: number) => {let result: any = await reqRemoveRole(id)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功',})getHasRole(roleArr.value.length > 1 ? pageNo.value : pageNo.value - 1)}
}

3.代码 

src/api/acl/role/index.ts

// 角色管理模块的接口
import request from '@/utils/request'
import type { RoleResponseData, RoleData, MenuResponseData } from './type'
// 枚举地址
enum API {// 获取全部角色的接口ALLROLE_URL = '/admin/acl/role/',// 新增角色的接口地址ADDROLE_URL = '/admin/acl/role/save',// 更新已有的角色UPDATEROLE_URL = '/admin/acl/role/update',//获取全部的菜单与按钮的数据ALLPERMISSION = '/admin/acl/permission/toAssign/',//给相应的职位分配权限SETPERMISTION_URL = '/admin/acl/permission/doAssign/?',//删除已有的职位REMOVEROLE_URL = '/admin/acl/role/remove/',
}// 获取全部的角色
export const reqRoleInfo = (page: number, limit: number, roleName: string) =>request.get<any, RoleResponseData>(API.ALLROLE_URL + `${page}/${limit}/?roleName=${roleName}`,)
// 添加与更新角色接口
export const reqAddOrUpdateRole = (data: RoleData) => {if (data.id) {return request.put<any, any>(API.UPDATEROLE_URL, data)} else {return request.post<any, any>(API.ADDROLE_URL, data)}
}
//获取全部菜单与按钮权限数据
export const reqAllMenuList = (roleId: number) =>request.get<any, MenuResponseData>(API.ALLPERMISSION + roleId)
//给相应的职位下发权限
export const reqSetPermission = (roleId: number, permissionId: number[]) =>request.post(API.SETPERMISTION_URL + `roleId=${roleId}&permissionId=${permissionId}`,)
//删除已有的职位
export const reqRemoveRole = (roleId: number) =>request.delete<any, any>(API.REMOVEROLE_URL + roleId)

 src/api/acl/role/type.ts

export interface ResponseData {code: numbermessage: stringok: boolean}//职位数据类型export interface RoleData {id?: numbercreateTime?: stringupdateTime?: stringroleName: stringremark?: null}//全部职位的数组的ts类型export type Records = RoleData[]//全部职位数据的相应的ts类型export interface RoleResponseData extends ResponseData {data: {records: Recordstotal: numbersize: numbercurrent: numberorders: []optimizeCountSql: booleanhitCount: booleancountId: nullmaxLimit: nullsearchCount: booleanpages: number}}//菜单与按钮数据的ts类型export interface MunuData {id: numbercreateTime: stringupdateTime: stringpid: numbername: stringcode: stringtoCode: stringtype: numberstatus: nulllevel: numberchildren?: MenuListselect: boolean}export type MenuList = MunuData[]//菜单权限与按钮权限数据的ts类型export interface MenuResponseData extends ResponseData {data: MenuList}

src/views/acl/role/index.vue   

PS:filterSelectArr方法只需要过滤最深一个层级的id(即第四级),因为只要判断最深一级是否有勾选,如果有一个或多个勾选了,则它相关的所有上级必定是勾选状态;如果一个也没勾选,则它相关的所有上级必定也是未勾选状态。

<template><el-card style="height: 80px"><el-form :inline="true" class="form"><el-form-item label="角色名称"><el-input placeholder="角色名称" v-model="keyword"></el-input></el-form-item><el-form-item><el-button type="primary" @click="search">搜索</el-button><el-button type="primary" plain="primary" @click="reset">重置</el-button></el-form-item></el-form></el-card><el-card style="margin: 10px 0"><el-button type="primary" size="default" icon="Plus" @click="addRole">添加角色</el-button><el-table border style="margin: 10px 0" :data="roleArr"><el-table-column type="index" label="#" align="center"></el-table-column><el-table-column label="id" align="center" prop="id"></el-table-column><el-table-columnlabel="角色名称"align="center"show-overflow-tooltipprop="roleName"></el-table-column><el-table-columnlabel="创建时间"align="center"show-overflow-tooltipprop="createTime"></el-table-column><el-table-columnlabel="更新时间"align="center"show-overflow-tooltipprop="updateTime"></el-table-column><el-table-column label="操作" width="300px" align="center"><template #="{ row, $index }"><el-buttontype="primary"size="small"icon="User"@click="setPermission(row)">分配权限</el-button><el-buttontype="primary"size="small"icon="Edit"@click="updateRole(row)">编辑</el-button><el-popconfirm:title="`你确定要删除${row.roleName}?`"width="260px"@confirm="removeRole(row.id)"><template #reference><el-button type="primary" size="small" icon="Delete">删除</el-button></template></el-popconfirm></template></el-table-column></el-table><el-paginationv-model:current-page="pageNo"v-model:page-size="pageSize":page-sizes="[10, 20, 30, 40]":background="true"layout="prev, pager, next, jumper,->,sizes,total":total="total"@current-change="getHasRole"@size-change="sizeChange"/></el-card><!-- 添加角色与更新已有角色的结构:对话框 --><el-dialog :title="roleParams.id ? '更新' : '添加'" v-model="dialogVisible"><el-form :model="roleParams" :rules="rules" ref="form"><el-form-item label="角色名称" prop="roleName"><el-inputplaceholder="请填写角色名称"v-model="roleParams.roleName"></el-input></el-form-item></el-form><template #footer><el-button size="default" @click="dialogVisible = false">取消</el-button><el-button type="primary" size="default" @click="save">确认</el-button></template></el-dialog><!-- 抽屉组件:分配角色的菜单权限与按钮权限 --><el-drawer v-model="drawer"><template #header><h4>分配菜单与按钮的权限</h4></template><template #default><el-treeref="tree":data="menuArr"show-checkboxnode-key="id"default-expand-all:default-checked-keys="selectArr":props="defaultProps"/></template><template #footer><div style="flex: auto"><el-button @click="drawer = false">取消</el-button><el-button type="primary" @click="handler">确认</el-button></div></template></el-drawer>
</template><script setup lang="ts">
import useLayOutSettingStore from '@/store/modules/setting'
import {reqAddOrUpdateRole,reqAllMenuList,reqRemoveRole,reqRoleInfo,reqSetPermission,
} from '@/api/acl/role'
import type {RoleResponseData,Records,RoleData,MenuResponseData,MenuList,
} from '@/api/acl/role/type'
import { nextTick, onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
// 当前页码
let pageNo = ref<number>(1)
// 一夜展示几条数据
let pageSize = ref<number>(10)
// 角色总个数
let total = ref<number>(0)
// 存储全部角色的数组
let roleArr = ref<Records>([])
// 搜索角色关键字
let keyword = ref<string>('')
// 控制对话框显示与隐藏
let dialogVisible = ref<boolean>(false)
// 收集新增岗位数据
let roleParams = reactive<RoleData>({roleName: '',
})
// 控制抽屉显示与隐藏
let drawer = ref<boolean>(false)
// 获取form组件实例
let form = ref<any>()
//定义数组存储用户权限的数据
let menuArr = ref<MenuList>([])
//准备一个数组:数组用于存储勾选的节点的ID(四级的)
let selectArr = ref<number[]>([])
//获取tree组件实例
let tree = ref<any>()
// 组件挂载完毕
onMounted(() => {// 获取角色请求getHasRole()
})
// 获取全部已有的角色信息的方法|分页器当前页码发生变化的回调
const getHasRole = async (pager = 1) => {// 修改当前页码pageNo.value = pagerlet result: RoleResponseData = await reqRoleInfo(pageNo.value,pageSize.value,keyword.value,)if (result.code === 200) {total.value = result.data.totalroleArr.value = result.data.records}
}
// 分页器下拉菜单的自定义事件的回调
const sizeChange = () => {getHasRole()
}
// 搜索按钮的回调
const search = () => {//根据关键字获取相应的角色数据getHasRole()//清空关键字keyword.value = ''
}//获取模板setting仓库
let settingStore = useLayOutSettingStore()
// 重置按钮的回调
const reset = () => {settingStore.refresh = !settingStore.refresh
}
// 添加角色按钮的回调
const addRole = () => {// 对话框显示出来dialogVisible.value = true// 清空数据Object.assign(roleParams, {roleName: '',id: 0,})// 清空上一次表单校验错误提示nextTick(() => {form.value.clearValidate('roleName')})
}
// 更新角色按钮的回调
const updateRole = (row: RoleData) => {// 对话框显示出来dialogVisible.value = true// 存储已有角色---带有id的Object.assign(roleParams, row)// 清空上一次表单校验错误提示nextTick(() => {form.value.clearValidate('roleName')})
}// 自定义校验规则的回调
const validatorRoleName = (rule: any, value: any, callBack: any) => {// 角色名称,长度至少五位if (value.trim().length >= 2) {callBack()} else {callBack(new Error('角色名称至少两位'))}
}
// 角色校验规则
const rules = {roleName: [{ required: true, trigger: 'blur', validator: validatorRoleName }],
}// 确定按钮的回调
const save = async () => {// 表单校验结果,结果通过再发请求,结果没通过不应该发请求await form.value.validate()// 添加职位|更新角色的请求let result: any = await reqAddOrUpdateRole(roleParams)if (result.code === 200) {// 提示信息ElMessage({type: 'success',message: roleParams.id ? '添加成功' : '更新成功',})// 再次获取全部已有角色getHasRole(roleArr.value.length > 1 ? pageNo.value : pageNo.value - 1)} else {// 提示信息ElMessage({type: 'error',message: roleParams.id ? '添加失败' : '更新失败',})}// 对话框隐藏dialogVisible.value = false
}//分配权限按钮的回调
//已有的职位的数据
const setPermission = async (row: RoleData) => {//抽屉显示出来drawer.value = true//收集当前要分类权限的职位的数据Object.assign(roleParams, row)//根据职位获取权限的数据let result: MenuResponseData = await reqAllMenuList(roleParams.id as number)if (result.code === 200) {menuArr.value = result.dataselectArr.value = filterSelectArr(menuArr.value, [])}
}const defaultProps = {children: 'children',label: 'name',
}const filterSelectArr = (allData: any, initArr: any) => {allData.forEach((item: any) => {if (item.select && item.level === 4) {initArr.push(item.id)}if (item.children && item.children.length > 0) {filterSelectArr(item.children, initArr)}})return initArr
}//抽屉确定按钮的回调
const handler = async () => {//职位的IDconst roleId = roleParams.id as number//选中节点的IDlet arr = tree.value.getCheckedKeys()//半选的IDlet arr1 = tree.value.getHalfCheckedKeys()let permissionId = arr.concat(arr1)//下发权限let result: any = await reqSetPermission(roleId, permissionId)if (result.code === 200) {//抽屉关闭drawer.value = false//提示信息ElMessage({type: 'success',message: '分配权限成功',})//页面刷新window.location.reload()}
}
//删除已有的职位
const removeRole = async (id: number) => {let result: any = await reqRemoveRole(id)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功',})getHasRole(roleArr.value.length > 1 ? pageNo.value : pageNo.value - 1)}
}
</script><style scoped>
.form {display: flex;justify-content: space-between;align-items: center;
}
</style>

三、菜单管理 

1.展示已有菜单数据

展示已有菜单数据
(1)编写API接口,方法,定义数据类型
(2)静态搭建:table组件

<el-table :data="permisstinArr" style="width: 100%; margin-bottom: 20px" row-key="id" border><el-table-column label="名称" prop="name"></el-table-column><el-table-column label="权限值" prop="code"></el-table-column><el-table-column label="修改时间" prop="updateTime"></el-table-column><el-table-column label="操作"><!-- row:即为已有菜单对象|按钮对象的数据 --><template #="{ row, $index }"><el-button @click="addPermission(row)" type="primary" size="small" :disabled="row.level === 4">{{ row.level === 3 ? '添加功能' : '添加菜单' }}</el-button><el-button @click="updatePermission(row)" type="primary" size="small" :disabled="row.level === 1">编辑</el-button><el-popconfirm :title="`你确定要删除${row.name}?`" width="260px" @confirm="removeMenu(row.id)"><template #reference><el-button type="primary" size="small" :disabled="row.level === 1">删除</el-button></template></el-popconfirm></template></el-table-column></el-table>

(3)组件挂载完毕获取菜单数据
(4)获取菜单数据
获取》存储》判断

// 组件挂载完毕
onMounted(() => {getHasPermission()
})//  获取菜单数据的方法
const getHasPermission = async () => {let result: PermissionResponseData = await reqAllPermission()if (result.code === 200) {permisstinArr.value = result.data}
}

(5)展示数据
el-table中:data="permisstinArr"
el-table-column中:prop
(6)判断按钮是否禁用
一级禁用编辑和删除按钮
四级禁用添加菜单按钮

 2.添加与更新菜单

(1)静态搭建
el-dialog》

<!-- 对话框组件:添加或者更新已有的菜单的数据结构 --><el-dialog v-model="dialogVisible" :title="menuData.id ? '更新菜单' : '添加菜单'" width="30%"><!-- 表单组件:收集新增与已有菜单的数据 --><el-form><el-form-item label="名称"><el-input placeholder="请输入菜单名称" v-model="menuData.name"></el-input></el-form-item><el-form-item label="权限"><el-input placeholder="请输入权限值" v-model="menuData.code"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="save">确认</el-button></span></template></el-dialog>

(2)控制对话框的显示与隐藏
// 控制对话框的显示与隐藏
let dialogVisible = ref<boolean>(false)
(3)添加菜单按钮的回调addPermission(row)

// 添加菜单按钮的回调
const addPermission = (row: Permission) => {// 清空数据Object.assign(menuData, {id: 0,code: '',level: 0,name: '',pid: 0,})// 对话框显示出来dialogVisible.value = true// 收集新增菜单的level数值menuData.level = row.level + 1// 给谁新增子菜单menuData.pid = row.id as number
}

(4)编辑菜单按钮的回调updatePermission(row)

// 编辑已有菜单
const updatePermission = (row: Permission) => {// 对话框显示出来dialogVisible.value = true//点击修改按钮:收集已有的菜单的数据进行更新Object.assign(menuData, row)
}

(5)确定按钮的回调save

// 确认按钮的回调
const save = async () => {let result: any = await reqAddOrUpdateMenu(menuData)if (result.code === 200) {//对话框隐藏dialogVisible.value = false// 信息提示ElMessage({type: 'success',message: menuData.id ? '更新成功' : '添加成功',})//再次获取全部最新的菜单的数据getHasPermission()}
}

(6)取消按钮
@click="dialogVisible = false"
(7)记得定义API接口、方法以及数据类型

3.删除已有菜单

(1)编写API接口、方法,定义数据类型
(2)删除按钮的回调。
静态》el-popconfirm

<el-popconfirm :title="`你确定要删除${row.name}?`" width="260px" @confirm="removeMenu(row.id)"><template #reference><el-button type="primary" size="small" :disabled="row.level === 1">删除</el-button></template></el-popconfirm>

发送请求》再次更新数据

// 删除按钮的回调
const removeMenu = async (id: number) => {let result: any = await reqRemoveMenu(id)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功',})getHasPermission()}
}

4.代码 

src/api/acl/menu/index.ts

import request from '@/utils/request'
import type { PermissionResponseData, MenuParams } from './type'
//枚举地址
enum API {//获取全部菜单与按钮的标识数据ALLPERMISSION_URL = '/admin/acl/permission',//给某一级菜单新增一个子菜单ADDMENU_URL = '/admin/acl/permission/save',//更新某一个已有的菜单UPDATE_URL = '/admin/acl/permission/update',//删除已有的菜单DELETEMENU_URL = '/admin/acl/permission/remove/',
}
//获取菜单数据
export const reqAllPermission = () =>request.get<any, PermissionResponseData>(API.ALLPERMISSION_URL)
//添加与更新菜单的方法
export const reqAddOrUpdateMenu = (data: MenuParams) => {if (data.id) {return request.put<any, any>(API.UPDATE_URL, data)} else {return request.post<any, any>(API.ADDMENU_URL, data)}
}//删除某一个已有的菜单
export const reqRemoveMenu = (id: number) =>request.delete<any, any>(API.DELETEMENU_URL + id)

  src/api/acl/menu/type.ts

//数据类型定义
export interface ResponseData {code: numbermessage: stringok: boolean
}
//菜单数据与按钮数据的ts类型
export interface Permission {id?: numbercreateTime: stringupdateTime: stringpid: numbername: stringcode: nulltoCode: nulltype: numberstatus: nulllevel: numberchildren?: PermissionListselect: boolean
}
export type PermissionList = Permission[]
//菜单接口返回的数据类型
export interface PermissionResponseData extends ResponseData {data: PermissionList
}//添加与修改菜单携带的参数的ts类型
export interface MenuParams {id?: number //IDcode: string //权限数值level: number //几级菜单name: string //菜单的名字pid: number //菜单的ID
}

src/views/acl/permission/index.vue   

<template><el-table:data="permisstinArr"style="width: 100%; margin-bottom: 20px"row-key="id"border><el-table-column label="名称" prop="name"></el-table-column><el-table-column label="权限值" prop="code"></el-table-column><el-table-column label="修改时间" prop="updateTime"></el-table-column><el-table-column label="操作"><!-- row:即为已有菜单对象|按钮对象的数据 --><template #="{ row, $inde }"><el-button@click="addPermission(row)"type="primary"size="small":disabled="row.level === 4">{{ row.level === 3 ? '添加功能' : '添加菜单' }}</el-button><el-button@click="updatePermission(row)"type="primary"size="small":disabled="row.level === 1">编辑</el-button><el-popconfirm:title="`你确定要删除${row.name}?`"width="260px"@confirm="removeMenu(row.id)"><template #reference><el-button type="primary" size="small" :disabled="row.level === 1">删除</el-button></template></el-popconfirm></template></el-table-column></el-table><!-- 对话框组件:添加或者更新已有的菜单的数据结构 --><el-dialogv-model="dialogVisible":title="menuData.id ? '更新菜单' : '添加菜单'"width="30%"><!-- 表单组件:收集新增与已有菜单的数据 --><el-form><el-form-item label="名称"><el-inputplaceholder="请输入菜单名称"v-model="menuData.name"></el-input></el-form-item><el-form-item label="权限"><el-input placeholder="请输入权限值" v-model="menuData.code"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="save">确认</el-button></span></template></el-dialog>
</template><script setup lang="ts">
import {reqAddOrUpdateMenu,reqAllPermission,reqRemoveMenu,
} from '@/api/acl/menu'
import {MenuParams,Permission,PermissionList,PermissionResponseData,
} from '@/api/acl/menu/type'
import { ElMessage } from 'element-plus'
import { onMounted, reactive, ref } from 'vue'
let permisstinArr = ref<PermissionList>([])
// 控制对话框的显示与隐藏
let dialogVisible = ref<boolean>(false)
// 携带的参数
let menuData = reactive<MenuParams>({code: '',level: 0,name: '',pid: 0,
})
// 组件挂载完毕
onMounted(() => {getHasPermission()
})//  获取菜单数据的方法
const getHasPermission = async () => {let result: PermissionResponseData = await reqAllPermission()if (result.code === 200) {permisstinArr.value = result.data}
}// 添加菜单按钮的回调
const addPermission = (row: Permission) => {// 清空数据Object.assign(menuData, {id: 0,code: '',level: 0,name: '',pid: 0,})// 对话框显示出来dialogVisible.value = true// 收集新增菜单的level数值menuData.level = row.level + 1// 给谁新增子菜单menuData.pid = row.id as number
}// 编辑已有菜单
const updatePermission = (row: Permission) => {// 对话框显示出来dialogVisible.value = true//点击修改按钮:收集已有的菜单的数据进行更新Object.assign(menuData, row)
}// 确认按钮的回调
const save = async () => {let result: any = await reqAddOrUpdateMenu(menuData)if (result.code === 200) {//对话框隐藏dialogVisible.value = false// 信息提示ElMessage({type: 'success',message: menuData.id ? '更新成功' : '添加成功',})//再次获取全部最新的菜单的数据getHasPermission()}
}// 删除按钮的回调
const removeMenu = async (id: number) => {let result: any = await reqRemoveMenu(id)if (result.code === 200) {ElMessage({type: 'success',message: '删除成功',})getHasPermission()}
}
</script><style scoped></style>

四、首页

src/views/home/index.vue   

<template><el-card><div class="box"><img :src="userStore.avatar" class="avatar"><div class="info"><h3>{{ getTime() }}好!{{ userStore.username }}</h3><p>椰果甄选运营平台</p></div></div></el-card><div class="bottom"><svg-icon name="welcome" width="600px" height="300px"></svg-icon></div>
</template><script setup lang="ts">
import { getTime } from '@/utils/time'
// 引入用户相关的仓库,获取当前用户的头像、昵称
import useUserStore from '@/store/modules/user'
// 获取存储用户信息的仓库对象
let userStore = useUserStore()
</script><style scoped lang="scss">
.box {display: flex;align-items: center;.avatar {width: 100px;height: 100px;border-radius: 50%;}.info {margin-left: 20px;h3 {font-size: 28px;font-weight: 500;}p {margin-top: 20px;color: #a49a9a;}}
}.bottom {display: flex;justify-content: center;margin-top: 100px;
}
</style>

五、暗黑模式和主题颜色的切换

暗黑模式使用可参考:暗黑模式 | Element Plus (element-plus.org) 

主题颜色使用可参考:主题 | Element Plus (element-plus.org) 

暗黑模式需要在main.ts文件中引入所需的样式

import 'element-plus/theme-chalk/dark/css-vars.css'

src/layout/tabbar/setting/index.vue  

<el-popover placement="bottom" title="主题设置" :width="300" trigger="hover"><!-- 表单元素 --><el-form><el-form-item label="主题颜色"><el-color-picker @click.stop append-to-body @change="setColor" v-model="color" size="small" show-alpha:predefine="predefineColors" :teleported="false" /></el-form-item><el-form-item label="暗黑模式"><el-switch @change="changeDark" v-model="dark" class="mt-2" style="margin-left: 24px" inline-promptactive-icon="Moon" inactive-icon="Sunny" /></el-form-item></el-form><template #reference><el-button size="small" icon="Setting" circle></el-button></template></el-popover>import { ref } from 'vue'
//收集开关的数据
let dark = ref<boolean>(false);
//颜色组件组件的数据
const color = ref('rgba(255, 69, 0, 0.68)')
const predefineColors = ref(['#ff4500','#ff8c00','#ffd700','#90ee90','#00ced1','#1e90ff','#c71585','rgba(255, 69, 0, 0.68)','rgb(255, 120, 0)','hsv(51, 100, 98)','hsva(120, 40, 94, 0.5)','hsl(181, 100%, 37%)','hsla(209, 100%, 56%, 0.73)','#c7158577',
])// switch开关的chang事件进行暗黑模式的切换
const changeDark = () => {//获取HTML根节点let html = document.documentElement//判断HTML标签是否有类名darkdark.value ? html.className = 'dark' : html.className = ''
}// 主题颜色的设置
const setColor = () => {//通知js修改根节点的样式对象的属性与属性值let html = document.documentElementhtml.style.setProperty('--el-color-primary', color.value)
}

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

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

相关文章

LT2611UX四端口 LVDS转 HDMI2.0,带音频

描述LT2611UX 是一款面向机顶盒、DVD 应用的高性能 LVDS 至 HDMI2.0 转换器。LVDS输入可配置为单端口、双端口或四端口&#xff0c;具有1个高速时钟通道和3~4个高速数据通道&#xff0c;工作速率最高为1.2Gbps/通道&#xff0c;可支持高达19.2Gbps的总带宽。LT2611UX 支持灵活的…

设计模式之MVC模式

在编程江湖闯荡多年&#xff0c;我手中打磨过的设计模式多如繁星&#xff0c;但论及经典与实用&#xff0c; MVC&#xff08;Model-View-Controller&#xff09;模式 绝对是个中翘楚&#xff01;它不仅是Web应用的骨架&#xff0c;更是软件架构的智慧结晶。今天&#xff0c;咱们…

tomcat篇-windows 运行tomcat的startup.bat时,终端打印的中文显示为乱码

当运行Tomcat的startup.bat时&#xff0c;如果终端中中文显示为乱码&#xff0c;这通常是因为Tomcat使用的日志输出编码与Windows命令行默认的编码不匹配。针对这一问题&#xff0c;你可以尝试以下步骤来解决&#xff1a; 1、执行startup.bat&#xff0c;在输出的窗口右击&…

从Paint 3D入门glTF

Paint 3D Microsoft Paint 3D是微软的一款图像编辑软件&#xff0c;它是传统的Microsoft Paint程序的升级版。 这个新版本的Paint专注于三维设计和创作&#xff0c;使用户可以使用简单的工具创建和编辑三维模型。 Microsoft Paint 3D具有直观的界面和易于使用的工具&#xff0…

笔记-用Python脚本启停JAR程序

用Python脚本启停JAR程序&#xff0c;需要用到python中的以下内置模块 subprocess 是 Python 的一个标准库模块&#xff0c;用于在新进程中执行子命令&#xff0c;获取子进程的输入/输出/错误以及返回码等os 是 Python 的一个标准库模块&#xff0c;它提供了与操作系统交互的功…

ICode国际青少年编程竞赛- Python-1级训练场-for循环练习

ICode国际青少年编程竞赛- Python-1级训练场-for循环练习 1、 for i in range(3):Dev.step(4)Dev.turnLeft()2、 for i in range(3):Dev.step(2)Dev.turnRight()Dev.step(2)Dev.turnLeft()3、 for i in range(3):Dev.step(2)Dev.turnRight()Dev.step(2)Dev.turnLeft()4、 for…

ubuntu与redhat的不同之处

华子目录 什么是ubuntu概述 ubuntu版本简介桌面版服务器版 安装部署部署后的设置设置root密码关闭防火墙启用允许root进行ssh登录更改apt源安装所需软件 网络配置Netplan概述配置详解配置文件DHCP静态IP设置设置 软件安装方法apt安装软件作用常用命令配置apt源 deb软件包安装概…

C语言中的三大循环

C语言中为我们提供了三种循环语句&#xff0c;今天我就来与诸君细谈其中之奥妙。循环这一板块总结的内容较多&#xff0c;而且&#xff0c;很重要&#xff01;&#xff08;敲黑板&#xff01;&#xff01;&#xff01;)&#xff0c;所以诸君一定要对此上心&#xff0c;耐住性子…

golang反射

go反射 反射基本介绍应用场景基本使用结构体注意练习最佳实践遍历结构体的方法&#xff0c;调用接头体的方法&#xff0c;获取结构体的标签 反射 基本介绍 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型(type)、类别(kind)如果是结构体变量&#xff0c;…

设计模式: 工厂模式

工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一&#xff0c;这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 工厂模式提供了一种创建对象的方式&#xff0c;而无需指定要创建的具体类。 工厂模式属于创建型…

【Web】D^3CTF之浅聊d3pythonhttp——TE-CL请求走私

目录 step0 题目信息 step1 jwt空密钥伪造 step1.5 有关TE&CL的lab step2 TE-CL请求走私 payload1 payload2 step0 题目信息 注意到题目源码前端是flask写的&#xff0c;后端是web.py写的 frontend from flask import Flask, request, redirect, render_templat…

万界星空科技商业开源MES+项目合作+商业开源低代码平台

今天我想和大家分享的是一套商业开源的 MES制造执行管理系统带源码。对于制造业而言&#xff0c;MES 是一个至关重要的系统&#xff0c;它可以帮助企业提高生产效率、优化资源利用、提高产品质量&#xff0c;从而增强市场竞争力。 什么是 MES&#xff1f; MES 是指通过计算机技…

安装部署大语言模型 | 通义千问

下载安装 进入ollama的仓库下载 「 qwen 7b 」 libraryGet up and running with large language models.https://ollama.com/library查找阿里的 「 qwen 」 根据自己的电脑配置情况&#xff0c;选择合适的模型 总体来说&#xff0c;模型是越大&#xff0c;效果越好&#xff0c…

数据库(MySQL)基础:约束

一、概述 1.概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 2.目的&#xff1a;保证数据库中数据的正确、有效性和完整性。 3.分类 约束描述关键字非空约束限制该字段的数据不能为nullnot null唯一约束保证该字段的所有数据都是唯一…

JSP在页面用<%=调用声明函数时出现HTTP 500错误

JSP在页面用<%调用声明函数时出现HTTP 500错误 错误描述&#xff1a; Eclipse在编写JSP页面时&#xff0c;在其中采用<%&#xff01;%>方式声明了函数&#xff0c;然后在页面中用<%函数名%>方式调用时&#xff0c;出现HTTP状态500错误&#xff0c;提示为&#…

PC通过串口发送指令控制LED+串口中断

如何让单片机接收数据&#xff1f; 首先要打开SCON中的串行接收控制位REN。当REN1时为允许接收状态&#xff0c;可以接收信息。 因此令SCON 0x50&#xff1b; 怎么知道收到数据&#xff1f; 利用RI接收中断请求标志位。当串行接收到第8位结束时由内部硬件自动置为RI1&#…

LabVIEW机械臂控制与图像处理示教平台

LabVIEW机械臂控制与图像处理示教平台 随着工业自动化技术的快速发展&#xff0c;工业机器人在制造业中的应用越来越广泛&#xff0c;它们在提高生产效率、降低人工成本以及保证产品质量方面发挥着重要作用。然而&#xff0c;传统的工业机器人编程和操作需要专业知识&#xff…

Git使用指北

目录 创建一个Git仓库本地仓库添加文件文件提交到本地仓库缓冲区添加远程仓库地址本地仓库推送到远程仓库创建新的分支拉取代码同步删除缓冲区的文件&#xff0c;远程仓库的文件.gitignore文件 创建一个Git仓库 Git仓库分为远程和本地两种&#xff0c;远程仓库如Githu上创建的…

计算机网络之传输层TCP\UDP协议

UDP协议 用户数据报协议UDP概述 UDP只在IP数据报服务之上增加了很少功能&#xff0c;即复用分用和差错检测功能 UDP的主要特点&#xff1a; UDP是无连接的&#xff0c;减少开销和发送数据之前的时延 UDP使用最大努力交付&#xff0c;即不保证可靠交付&#xff0c;可靠性由U…

Debian 12 tomcat 9 catalina 日志信息 中文显示乱码

目录 问题现象 解决办法&#xff1a; 1、设定Debian locale 2、设定catalina.sh utf8字符集 问题现象 Debian 12 linux操作系统中&#xff0c;tomcat 9 catalina 启动日志输出 中文乱码 解决办法&#xff1a; 1、设定Debian locale 先确保系统本身就支持中文的 Debian …