当前位置: 首页 > news >正文

若依前后端分离版学习笔记(十八)——页面权限,页签缓存以及图标,字典,参数的使用

一、页面权限

封装指令权限,能简单快速实现按钮级别的权限判断

1.1 hasRole

角色权限处理

 /*** v-hasRole 角色权限处理* Copyright (c) 2019 ruoyi*/
import useUserStore from '@/store/modules/user'export default {mounted(el, binding, vnode) {const { value } = bindingconst super_admin = "admin"// 从useUserStore中获取当前用户的角色列表const roles = useUserStore().roles// 如果传入的指令值存在,value为非空数组if (value && value instanceof Array && value.length > 0) {const roleFlag = value// 验证用户是否具有指定角色之一,或者是否为超级管理员 adminconst hasRole = roles.some(role => {return super_admin === role || roleFlag.includes(role)})// 如果不具有相应角色,则从DOM中移除该元素if (!hasRole) {el.parentNode && el.parentNode.removeChild(el)}} else {throw new Error(`请设置角色权限标签值`)}}
}

使用示例

<el-button v-hasRole="['admin', 'editor']">编辑</el-button>

1.2 hasPermi

权限标识处理

import useUserStore from '@/store/modules/user'export default {mounted(el, binding, vnode) {const { value } = bindingconst all_permission = "*:*:*"// 从useUserStore获取权限标识列表const permissions = useUserStore().permissions// 检查传入的指令值是否为非空数组if (value && value instanceof Array && value.length > 0) {const permissionFlag = value// 判断用户权限是否有全部权限或具有指定权限const hasPermissions = permissions.some(permission => {return all_permission === permission || permissionFlag.includes(permission)})// 如果不具有指定权限,则移除DOM元素if (!hasPermissions) {el.parentNode && el.parentNode.removeChild(el)}} else {throw new Error(`请设置操作权限标签值`)}}
}

使用示例

<el-button v-hasPermi="['system:user:add', 'system:user:edit']">新增用户</el-button>

1.3 使用示例

示例代码

<!-- 父组件 -->
<template><!-- hasRole 使用示例 --><div style="margin: 20px; padding: 20px; border: 1px solid #ccc;"><h3>角色权限控制示例 (v-hasRole)</h3><el-button v-hasRole="['admin']" type="primary">仅管理员可见</el-button>// hasRole.js中设置了admin所有可见,所以这里v-hasRole="['common']" 管理员也是有权限的<el-button v-hasRole="['common']" type="success">编辑者和管理员可见</el-button></div><!-- hasPermi 使用示例 --><div style="margin: 20px; padding: 20px; border: 1px solid #ccc;"><h3>操作权限控制示例 (v-hasPermi)</h3><el-button v-hasPermi="['system:user:add']" type="primary">新增用户</el-button><el-button v-hasPermi="['system:user:edit']" type="success">编辑用户</el-button><el-button v-hasPermi="['system:user:remove']" type="danger">删除用户</el-button><el-button v-hasPermi="['system:user:add', 'system:user:edit']" type="warning">新增或编辑用户</el-button></div><!-- 函数式权限检查示例 --><div style="margin: 20px; padding: 20px; border: 1px solid #ccc;"><h3>函数式权限检查</h3><div v-if="checkRole(['admin'])"><p>这是通过函数检查显示的内容 - 仅管理员可见</p></div><div v-if="checkPermi(['system:config:edit'])"><p>这是通过函数检查显示的内容 - 编辑者和管理员可见</p></div></div>
</template><script setup>
import { checkPermi, checkRole } from '@/utils/permission'</script>

admin账号查看
在这里插入图片描述

ry(普通角色)账号查看

这里注意要给普通角色添加新增的目录权限

在这里插入图片描述

v-if 是 Vue 的条件渲染指令,它根据表达式的真假值来决定是否渲染某个元素或组件;当 v-if 的值为 true 时,元素会被渲染到 DOM 中;
当 v-if 的值为 false 时,元素不会被渲染到 DOM 中(完全不存在于 DOM 树中)

二、页签缓存

页签缓存是一个重要的用户体验优化功能。在ruoyi中,它允许用户在切换不同页面时保持页面状态,避免重复加载和数据丢失。在ruoyi中,页签缓存主要通过Vue的组件实现

<template><section class="app-main"><router-view v-slot="{ Component, route }"><transition name="fade-transform" mode="out-in"><keep-alive :include="tagsViewStore.cachedViews"><component v-if="!route.meta.link" :is="Component" :key="route.path"/></keep-alive></transition></router-view></section>
</template>
  • keep-alive是Vue内置组件,用于缓存动态组件
  • :include="tagsViewStore.cachedViews"指定了需要缓存的组件列表
  • 只有在cachedViews数组中的组件才会被缓存

使用keep-alive进行组件缓存时,必须确保路由配置和组件的name属性保持一致,否则会导致缓存失效或者出现其他问题。在Vue中,keep-alive组件通过include属性来决定哪些组件需要被缓存。默认情况下,keep-alive会优先匹配组件的name属性。如果路由配置中的name与组件定义的name不一致,就会导致缓存机制失效。

在系统管理-菜单管理中可以配置菜单页签是否缓存,默认为缓存。
在这里插入图片描述

缓存的具体管理在src→store→modules→tagsViews.js中具体实现

addCachedView(view) {// 如果该页面已在缓存列表中,则不再重复添加if (this.cachedViews.includes(views.name)) return// 如果该页面的路由配置中meta.noCache不为true,则将路由的name添加到缓存列表if (!view.meta.noCache) {this.cachedViews.push(view.name)    }
}

实际使用场景
1.用户首次访问/system/user页面,系统会加载用户管理组件
2.由于该路由未设置meta.noCache=true,所以该页面组件会被添加到cachedViews列表中
3.当用户切换到其他页面(如角色管理)再切换回来时,由于组件已在cachedViews列表中,keep-alive会直接从缓存中恢复组件状态,而不会重新创建组件
4.这样用户在用户管理页面中的操作状态(如表格的分页、筛选条件等)会被保留

三、使用图标

3.1 图标

icon图标放在src→assets→icons下

3.2 全局SvgIcon组件

src→components→SvgIcon→index.vue

<template><svg :class="svgClass" aria-hidden="true"><use :xlink:href="iconName" :fill="color" /></svg>
</template><script>
export default defineComponent({// 定义从父组件接收的值props: {iconClass: {type: String,required: true},className: {type: String,default: ''},color: {type: String,default: ''},},setup(props) {// 要在模板中使用的响应式数据和方法return {iconName: computed(() => `#icon-${props.iconClass}`),svgClass: computed(() => {if (props.className) {return `svg-icon ${props.className}`}return 'svg-icon'})}}
})
</script>// 定义组件样式
<style scope lang="scss">
.sub-el-icon,
.nav-icon {display: inline-block;font-size: 15px;margin-right: 12px;position: relative;
}.svg-icon {width: 1em;height: 1em;position: relative;fill: currentColor;vertical-align: -2px;
}
</style>

使用方式

<!-- icon-class 为 icon 的名字; class-name 为 icon 自定义 class-->
<!-- 基本用法 -->
<svg-icon icon-class="user" /><!-- 带颜色 -->
<svg-icon icon-class="edit" color="#409EFF" /><!-- 带额外CSS-->
<svg-icon icon-class="dashboard" class-name="custom-class" />

实际示例

<script setup></script><template><div class="app-container">msg</div><svg-icon icon-class="user" color = "#409EFF" class-name="user-class"/><svg-icon icon-class="password" class-name="password-class"/>
</template><style scoped lang="scss">
.password-class{font-size: 200px;fill: red;
}
</style>

显示效果
在这里插入图片描述

3.3 新增图标

提示
如果是从iconfont下载的图标,记得使用如 Sketch 等工具规范一下图标的大小问题,不然可能会造成项目中的图标大小尺寸不统一的问题。 项目中使用的图标都是 128*128 大小规格的。

将新图标放到src→assets→icons下,并使用即可,如:

<svg-icon icon-class="newIcon" class-name="newIcon-class"/>

四、使用字典

数据字典系统是一个重要的功能模块,用于管理系统中的各种枚举数据,如状态、性别、类型等。它通过前后端配合,实现了数据字典的统一管理和使用。
流程:
1.初始化:通过 useDict 函数加载所需字典数据
2.缓存:将获取的字典数据存储在 dict.js 存储模块中,避免重复请求
3.显示:通过 DictTag 组件根据字典值显示对应标签
4.更新:当字典数据发生变化时,可以刷新缓存

4.1 核心组件和实现

4.1.1 DictTag组件

src→components→DictTag→index.vue是项目中用于显示字典标签的核心组件,它可以根据字典值显示对应的标签文本,并支持不同的显示样式。

<template><div>// 遍历所有字典选项<template v-for="(item, index) in options">// 通过 values.includes(item.value) 判断当前值是否匹配字典项<template v-if="values.includes(item.value)"><span// 根据是否有自定义样式类和类型,决定使用普通 span 标签还是 el-tag 组件显示v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)":key="item.value":index="index":class="item.elTagClass">{{ item.label + " " }}</span><el-tagv-else:disable-transitions="true":key="item.value + ''":index="index":type="item.elTagType":class="item.elTagClass">{{ item.label + " " }}</el-tag></template></template></div>
</template><script setup>
// 记录未匹配的项
const unmatchArray = ref([])// 接收属性
const props = defineProps({// 数据options: {type: Array,default: null,},// 当前的值value: [Number, String, Array],// 当未找到匹配的数据时,显示valueshowValue: {type: Boolean,default: true,},// 分隔符,默认为逗号separator: {type: String,default: ",",}
})// 计算属性 values 用于处理传入的值,将其统一转换为字符串数组
const values = computed(() => {if (props.value === null || typeof props.value === 'undefined' || props.value === '') return []return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator)
})const unmatch = computed(() => {unmatchArray.value = []// 没有value不显示if (props.value === null || typeof props.value === 'undefined' || props.value === '' || !Array.isArray(props.options) || props.options.length === 0) return false// 传入值为数组let unmatch = false // 添加一个标志来判断是否有未匹配项values.value.forEach(item => {if (!props.options.some(v => v.value === item)) {unmatchArray.value.push(item)unmatch = true // 如果有未匹配项,将标志设置为true}})return unmatch // 返回标志的值
})function handleArray(array) {if (array.length === 0) return ""return array.reduce((pre, cur) => {return pre + " " + cur})
}
</script><style scoped>
.el-tag + .el-tag {margin-left: 10px;
}
</style>

4.1.2 字典获取工具

src→utils→dict.js 用于获取字段数据的工具函数

import useDictStore from '@/store/modules/dict'
import { getDicts } from '@/api/system/dict/data'/*** 获取字典数据*/// 接收多个字典类型参数
export function useDict(...args) {const res = ref({})return (() => {// 循环处理每个参数args.forEach((dictType, index) => {res.value[dictType] = []// 先尝试从本地获取const dicts = useDictStore().getDict(dictType)if (dicts) {res.value[dictType] = dicts} else {// 本地没有则调用api获取getDicts(dictType).then(resp => {// 将获取到的数据转换为统一格式(包含 label、value、elTagType、elTagClass)res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))useDictStore().setDict(dictType, res.value[dictType])})}})return toRefs(res.value)})()
}

字典api接口
src→api→system→dict→data.js

// 根据字典类型查询字典数据信息
export function getDicts(dictType) {return request({url: '/system/dict/data/type/' + dictType,method: 'get'})
}

4.1.3 字典存储

src→store→modules→dict.js 存储模块管理字典数据,避免重复请求

const useDictStore = defineStore('dict',{state: () => ({dict: new Array()}),actions: {// 获取字典getDict(_key) {if (_key == null && _key == "") {return null}try {for (let i = 0; i < this.dict.length; i++) {if (this.dict[i].key == _key) {return this.dict[i].value}}} catch (e) {return null}},// 设置字典setDict(_key, value) {if (_key !== null && _key !== "") {this.dict.push({key: _key,value: value})}},// 删除字典removeDict(_key) {var bln = falsetry {for (let i = 0; i < this.dict.length; i++) {if (this.dict[i].key == _key) {this.dict.splice(i, 1)return true}}} catch (e) {bln = false}return bln},// 清空字典cleanDict() {this.dict = new Array()},// 初始字典initDict() {}}})export default useDictStore

4.2 实际使用示例

在用户管理模块中的使用
在src/views/system/user/index.vue中

// 获取两个字典 sys_normal_disable: 通用状态字典(正常/停用),sys_user_sex: 用户性别字典
const { sys_normal_disable, sys_user_sex } = proxy.useDict("sys_normal_disable", "sys_user_sex")

模板中使用

<!-- 状态选择 -->
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px"><el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select><!-- 性别选择 -->
<el-select v-model="form.sex" placeholder="请选择"><el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select><!-- 状态显示 -->
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible"><template #default="scope"><el-switchv-model="scope.row.status"active-value="0"inactive-value="1"@change="handleStatusChange(scope.row)"></el-switch></template>
</el-table-column>

在字典数据管理中的使用
在 src/views/system/dict/data.vue 中:

<el-table-column label="状态" align="center" prop="status"><template #default="scope">// 这里使用了DicTag组件显示状态,通过:options传入字典选项,通过:value传入当前值<dict-tag :options="sys_normal_disable" :value="scope.row.status" /></template>
</el-table-column>

字典更新机制
在 src/views/system/dict/data.vue中

/** 提交按钮 */
function submitForm() {proxy.$refs["dataRef"].validate(valid => {if (valid) {if (form.value.dictCode != undefined) {updateData(form.value).then(response => {// 更新字典后清除缓存useDictStore().removeDict(queryParams.value.dictType)proxy.$modal.msgSuccess("修改成功")open.value = falsegetList()})} else {addData(form.value).then(response => {// 新增字典后清除缓存useDictStore().removeDict(queryParams.value.dictType)proxy.$modal.msgSuccess("新增成功")open.value = falsegetList()})}}})
}

点击刷新缓存按钮,调用api /system/dict/data 刷新缓存

五、使用参数

参数设置是提供开发人员、实施人员的动态系统配置参数,不需要去频繁修改后台配置文件,也无需重启服务器即可生效。

5.1 参数修改流程

1.查看参数列表
用户在参数配置页面查看所有系统参数,包括参数名称、建名、键值等信息。
在这里插入图片描述
2.修改参数
2.1 点击修改按钮
2.2 修改参数键值
2.3 确定提交修改
3.刷新缓存

5.2 实现

api接口 src/api/system/config.js

  • listConfig:查询参数列表
  • getConfig:查询单个参数详情
  • addConfig:新增参数
  • updateConfig:修改参数
  • delConfig:删除参数
  • refreshCache:刷新参数缓存
    src/views/system/config/index.vue 主要修改逻辑如下
/** 提交按钮 */
function submitForm() {proxy.$refs["configRef"].validate(valid => {if (valid) {if (form.value.configId != undefined) {updateConfig(form.value).then(response => {proxy.$modal.msgSuccess("修改成功")open.value = falsegetList()})} else {addConfig(form.value).then(response => {proxy.$modal.msgSuccess("新增成功")open.value = falsegetList()})}}})
}

当用户修改参数并提交时,会调用updateConfig API接口将更改保存到数据库。
调用refreshCache接口来清除后端缓存,确保修改的参数能够立即生效:

/** 刷新缓存按钮操作 */
function handleRefreshCache() {refreshCache().then(() => {proxy.$modal.msgSuccess("刷新缓存成功")})
}
5.3 参数使用
在用户管理页面 /src/views/system/user/index.vue 中可以看到
onMounted(() => {getDeptTree()getList()proxy.getConfigKey("sys.user.initPassword").then(response => {initPassword.value = response.msg})
})

在组件挂载时执行,通过调用getConfigKey(“sys.user.initPassword”)获取系统配置的默认密码参数值,并将其存储在initPassword.value中。

http://www.dtcms.com/a/427009.html

相关文章:

  • 莱芜网站建设哪家好在线logo制作生成免费
  • 哈尔滨网站建设价格网站设计怎么学
  • 再发《管理世界》!智能制造试点DID(2000-2023)
  • SpringCloudGateway:像快递分拣中心一样的API网关
  • 真家宽IP vs 数据中心IP:Cliproxy为何成为跨境电商首选?
  • 声光可调滤光器(AOTF):光谱相机的“电子调谐旋钮”
  • skynet-socket.lua源码分析
  • 悠然无界大模型BLM-1.0:跨空间、跨任务与跨本体泛化的里程碑
  • 安康那个公司做网站好wordpress主题滑动
  • 提升UI走查效率:开发阶段的布局与CSS技巧
  • 5G RedCap模组在智慧城市建设中的应用分析
  • AI视频生成技术:从想象到现实的视觉革命
  • 如何将多个PDF文件中的图片批量提取出来
  • 【编译原理笔记】1.2 The Structure of Compiler
  • 序列化 实现保存临时数据
  • 【Rust GUI开发入门】编写一个本地音乐播放器(10. 拼装UI组件)
  • 【区块链】Fiat24 深度解读(含 Flutter 集成与 SDK 骨架)
  • 下载站推广谷歌搜索引擎网页版入口
  • Linux任务迁移函数和空闲负载均衡函数的实现
  • Web接入层的“铁三角”---防盗链、反向代理,负载均衡(nginx)
  • 精读 C++20 设计模式:行为型设计模式 — 访问者模式
  • 哪里可以做网站啊网站上传照片 传不上去
  • 鸿蒙NEXT NearLink Kit入门指南:重新定义短距无线通信
  • 微服务架构:基于Spring Cloud ,构建同城生活服务平台
  • 青岛网站推WordPress主题ao破解版
  • 做网站运营的简历网站开发补充协议 违约
  • Java-Spring入门指南(十三)SpringMVC基本概念与核心流程详解
  • Java Web实战 - 实现用户登录功能
  • 设计模式详解——工厂模式
  • 【大模型】KNighter: 内容审查 漏洞分析