【Vue3】el-checkbox-group实现权限配置和应用

一. 需求

  1. 针对不同等级的用户,配置不同的可见项

  2. 配置效果如下
    (1)新增,获取数据列表在这里插入图片描述
    (2)编辑,回显数据列表
    在这里插入图片描述

  3. 应用效果如下
    (1)父级配置
    在这里插入图片描述
    (2)子级配置
    在这里插入图片描述

二. 数据格式

  1. 普通用户列表、vip用户列表、svip用户列表 共用一个List
// type == 0 父:级可配置
// type == 2 :父级必然存在 
// type == 1 :type==2的 子级(若有的必然存在,可通过name进行筛选)
List:[
	{
		id: 1,
		children:null,
		createTime: null,
		name: "par1",
		value: "父1",
		isDel: 0,
		sort: 1,
		type: 0,
	},
	{
		id: 2,
		children:null,
		createTime: null,
		name: "par2",
		value: "父2",
		isDel: 0,
		sort: 2,
		type: 0,
	},
	{
		id: 3,
		children:null,
		createTime: null,
		name: "par3",
		value: "父3",
		isDel: 0,
		sort: 3,
		type: 0,
	},
	{
		id: 4,
		children:null,
		createTime: null,
		name: "par4",
		value: "父4",
		isDel: 0,
		sort: 4,
		type: 0,
	},
	{
		id: 5,
		children:null,
		createTime: null,
		name: "par5",
		value: "父5",
		isDel: 0,
		sort: 5,
		type: 0,
	},
	{
		id: 6,
		children:[
			{
				id: 7,
				children:null,
				createTime: null,
				name: "child1",
				value: "子1",
				isDel: 0,
				sort: 1,
				type: 1,
			},
			{
				id: 8,
				children:null,
				createTime: null,
				name: "child2",
				value: "子2",
				isDel: 0,
				sort: 2,
				type: 1,
			},
			{
				id: 9,
				children:null,
				createTime: null,
				name: "child3",
				value: "子3",
				isDel: 0,
				sort: 3,
				type: 1,
			},
			{
				id: 10,
				children:null,
				createTime: null,
				name: "child4",
				value: "子4",
				isDel: 0,
				sort: 4,
				type: 1,
			},
			{
				id: 11,
				children:null,
				createTime: null,
				name: "child5",
				value: "子5",
				isDel: 0,
				sort: 5,
				type: 1,
			},
			{
				id: 12,
				children:null,
				createTime: null,
				name: "child6",
				value: "子6",
				isDel: 0,
				sort: 6,
				type: 1,
			},
			{
				id: 13,
				children:null,
				createTime: null,
				name: "child7",
				value: "子7",
				isDel: 0,
				sort: 7,
				type: 1,
			},
		],
		createTime: null,
		name: "par6",
		value: "父6",
		isDel: 0,
		sort: 6,
		type: 2,
	},
]
  1. 思路:调用接口获取List,将同一个List 分别赋值给三个不同的数组。

三. 实现

  1. 数据获取并渲染 及 回显 功能
<template>
  <div>
    <el-form ref="detailRef" :model="form" :rules="rules" label-width="140px">
        <el-form-item label="普通用户" prop="ordinaryUser">
          <el-checkbox-group v-model="form.ordinaryUser">
            <el-checkbox v-for="item in ordinaryUser" v-show="item.type == 0" :key="item.id"
              class="check-box"
              :label="item.name"
              >{{ item.value }}</el-checkbox
            >
            <div>
              <el-checkbox v-for="item in ordinaryUser" v-show="item.type == 1" :key="item.id"
                class="check-box"
                :label="item.name"
                >{{ item.value }}</el-checkbox
              >
            </div>
          </el-checkbox-group>
        </el-form-item>
        <el-form-item label="VIP用户" prop="vipUser">
          <el-checkbox-group v-model="form.vipUser">
            <el-checkbox v-for="item in vipUser" v-show="item.type == 0" :key="item.id"
              class="check-box"
              :label="item.name"
              >{{ item.value }}</el-checkbox
            >
            <div>
              <el-checkbox v-for="item in vipUser" v-show="item.type == 1" :key="item.id"
                class="check-box"
                :label="item.name"
                >{{ item.value }}</el-checkbox
              >
            </div>
          </el-checkbox-group>
        </el-form-item>
        <el-form-item label="SVIP用户" prop="svipUser">
          <el-checkbox-group v-model="form.svipUser">
            <el-checkbox v-for="item in svipUser" v-show="item.type == 0" :key="item.id"
              class="check-box"
              :label="item.name"
              >{{ item.value }}</el-checkbox
            >
            <div>
              <el-checkbox v-for="item in vipUser" v-show="item.type == 1" :key="item.id"
                class="check-box"
                :label="item.name"
                >{{ item.value }}</el-checkbox
              >
            </div>
          </el-checkbox-group>
        </el-form-item>
    </el-form>
    <div>
      <el-button @click="handleClick">取 消</el-button>
      <el-button type="primary" @click="submitForm">确 认</el-button>
    </div>
  </div>
</template>
<script setup name="ManageMenu">
import { getList,update } from '@/api/xxx/xxx'
import { getConfigList } from '@/api/xxx/xxxConfig'
import { reactive } from '@vue/reactivity'
import { ref } from 'vue'

const { proxy } = getCurrentInstance()

const route = useRoute()
const configId = route.params.id //  通过路由获取到 配置id

const ordinaryUser = ref([]) // 普通用户
const vipUser = ref([]) // vip用户
const svipUser = ref([]) // svip用户
const selectStartLevel = reactive([]) // 当前选中项
const allStartLevel = ref([]) // 全部数据

const selectOrdinaryUser = ref([]) // 当前选中的普通用户可见项
const selectVipUser = ref([]) // 当前选中的vip用户可见项
const selectSVipUser = ref([]) // 当前选中的svip用户可见

const data = reactive({
  form: {},
  rules: {
    ordinaryUser: [{ type: 'array', required: true, message: '必填', trigger: ['blur'] }],
    vipUser: [{ type: 'array', required: true, message: '必填', trigger: ['blur'] }],
    svipUser: [{ type: 'array', required: true, message: '必填', trigger: ['blur'] }]
  }
})

// 重置表单
const reset = () => {
  form.value = {
    id: null,
    ordinaryUser: [],
    vipUser: [],
    svipUser: [],
    List: [] // 给后端传/回显数据的数组
  }
  proxy.resetForm('detailRef')
}

/**
 * 初始化列表数据
 */
onMounted(() => {
  reset()
  getCList()
  // 数据回显
  if (configId != null) {
   getActivityManageListDetails ({ configId: Number(configId) }).then(res => {
      if (res.code === 200) {
        form.value = res.data
        form.value.ordinaryUser = form.value.List
          .filter(item => item.rankConfig === 3 && item.configFlag === 1)
          .map(item => item.name)
        form.value.vipUser = form.value.List
          .filter(item => item.rankConfig === 2 && item.configFlag === 1)
          .map(item => item.name)
        form.value.svipUser = form.value.List
          .filter(item => item.rankConfig === 1 && item.configFlag === 1)
          .map(item => item.name)
      }
    })
  }
})

/**
 * 扁平化配置项数据
 */
const getCList = () => {
   // 获取配置项 并并扁平化,同时设置等级
  getConfigList().then(res => {
  	// res.data 数据格式就是 上述List
    ordinaryUser.value = treeToArray(res.data, 3) // 三级
    vipUser.value = treeToArray(res.data, 2) // 二级
    svipUser.value = treeToArray(res.data, 1) // 一级
    // 将扁平化的数据,整理放到一个数组中
    allStartLevel.value = [...ordinaryUser.value, ...vipUser.value, ...svipUser.value]
    // 过滤到type != 2 的数据 type=2,这一项因为需求在代码中写死了,时时刻刻存在所以要筛查掉
    allStartLevel.value = allStartLevel.value.filter(item => item.type !== 2)
  })
}

/**
 * 点击确定
 */
const submitForm = () => {
  selectOrdinaryUser.value = form.value.ordinaryUser.map(item => ({ rankConfig: 3, dictEnglishName: item }))
  selectVipUser.value = form.value.vipUser.map(item => ({ rankConfig: 2, dictEnglishName: item }))
  selectSVipUser.value = form.value.svipUser.map(item => ({ rankConfig: 1, dictEnglishName: item }))
  // 当前选中项
  selectStartLevel.value = [...selectOrdinaryUser.value, ...selectVipUser.value, ...selectSVipUser.value]
  // 设置选中项对应的星级 是否选中
  allStartLevel.value.forEach(item => {
    item.configId = item.id
    selectStartLevel.value.forEach(val => {
      if (item.rankConfig === val.rankConfig && item.name === val.name) {
        item.configFlag = 1
      }
    })
  })
  // 设置级别权限
 form.value.List = allStartLevel.value
  proxy.$refs['detailRef'].validate(valid => {
    if (valid) {
      console.log(...form.value, '校验成功了吗');
      if (configId != null) {
         update({ id: Number(configId), ...form.value }).then(res => {
           if (res.code === 200) {
             proxy.$modal.msgSuccess('编辑成功')
             handleClick()
             reset()
           }
         })
       } else{
         update({ id: 0, ...form.value }).then(res => {
           if (res.code === 200) {
             proxy.$modal.msgSuccess('新增成功')
             handleClick()
             reset()
           }
         })
       }
    }
  })
}

/**
 * 弹窗取消
 */
const handleClick = async () => {
  console.log('弹窗取消')
}

/**
 * 数组扁平化(reduce)
 */
const treeToArray = (tree, rankConfig) => {
  return tree.reduce((res, item) => {
    const { children, ...i } = item
    i.rankConfig = rankConfig
    i.configFlag = 0
    return res.concat(i, children && children.length ? treeToArray(children, rankConfig) : [])
  }, [])
}
</script>

<style scoped>
.check-box{
  width:90px
}
</style>
  1. 权限的应用(此处只处理父级)
<template>
   <el-tabs v-model="activeName" type="card" style="max-width: 100%" @tab-change="handleClick">
      <el-tab-pane v-for="item in leftData" :key="item.id" :label="item.value" :name="item.name">
         <component :is="allLeftCompontents[item.name]" :dataDetail="dataDetail"></component>
      </el-tab-pane>
   </el-tabs>
</template>
<script setup>
import Parent1 from '@/views/xxx/parent1'
import Parent2 from '@/views/xxx/parent2'
import Parent3 from '@/views/xxx/parent3'
import Parent4 from '@/views/xxx/parent4'
import Parent5 from '@/views/xxx/parent5'
import Parent6 from '@/views/xxx/parent6'
import { getApplyDetail } from "@/api/xxx"
import { getConfigListByConfigId } from "@/api/xxx"


const route = useRoute()
const id = route.params.id // 路由 获取id
const leftData = ref([]) // 配置数据项
const currentTab = ref('') // 当前选中tab项
const activeName = ref('') // 当前选中tab的名称
const dataDetail = reactive({}) // 获取详情

const allLeftCompontents = {
  par1: markRaw(Parent1),
  par2: markRaw(Parent2),
  par3: markRaw(Parent3),
  par4: markRaw(Parent4),
  par5: markRaw(Parent5),
  par6: markRaw(Parent6)
}

onMounted(() => {
  // 获取详情
  getApplyDetail({ id: id }).then(res => {
    if (res.code === 200) {
    	dataDetail.configId = res.data.configId
    	dataDetail.level = res.data.level
        // 获取等级权限
        getSatReviewConfigList()
    }
  })
})

/**
 * 获取配置项
 */
const getSatReviewConfigList = () => {
   getConfigListByConfigId({configId:dataDetail.configId , rankConfig: dataDetail.level}).then(result => {
          leftData.value = result.data
          // 初始加载第一个tab
          activeName.value = leftData.value[0].name
          handleClick(activeName.value)
      })
}

/**
 * 点击切换标签项
 */
const handleClick = (val) => {
  currentTab.value = val
}
</script>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Selenium+python】自动化测试登录界面

前言&#xff1a;已经学习selenium许久了&#xff0c;奈何公司的项目还在码代码中...&#xff0c;感觉自己学的东西快忘的差不多了&#xff0c;所以就找个网站练练手&#xff0c;顺便回顾一下UI自动化的知识&#xff0c;也希望跟我一样的小白有所受益。 一、用例分析&#xff…

Benjamin Button‘sLetter to Daughter 英语阅读

Benjamin ButtonsLetter to Daughter 来源: The Curious Case of Benjamin Button 官方翻译 For what its worth: Its never too late, or in my case, too early to bewhoever you want to be. Theres no time limit. Start whenever you want. You can change or stay t…

向量点乘有哪些作用呢

如下&#xff1a; 1.找到两个向量之间的夹角(不用多说) 2.求一个向量投影在另一个向量的投影&#xff1a; 我们把图中b的在a上的投影向量称作b1吧&#xff0c;因为b1就在a上&#xff0c;所以只需要求出b1的大小&#xff0c;然后乘以a的单位向量&#xff0c;我们就得到向量b1了…

【LeetCode热题100】114. 二叉树展开为链表(二叉树)

一.题目要求 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。 …

KeepAlived使用介绍

目录 1、Introduce 2、基本使用 &#xff08;1&#xff09;安装 &#xff08;2&#xff09;配置文件 &#xff08;3&#xff09;使用教程 1、Introduce keepalived是一个用于实现高可用性和负载均衡的开源软件。它提供了一种轻量级的方式来管理多个服务器&#xff0c;并确保…

隐私计算实训营学习六:隐语PIR介绍及开发指南

文章目录 一、隐语实现的PIR总体介绍1.1 PIR的定义和种类1.2 隐语PIR功能分层 二、Index PIR-SealPIR介绍三、Keyword PIR- Labeled PSI介绍四、隐语PIR后续计划 一、隐语实现的PIR总体介绍 1.1 PIR的定义和种类 PIR(Private Information Retrieval PIR)隐匿查询&#xff1a;…

YOLOv8改进 | 低照度检测 | 2024最新改进CPA-Enhancer链式思考网络(适用低照度、图像去雾、雨天、雪天)

一、本文介绍 本文给大家带来的2024.3月份最新改进机制&#xff0c;由CPA-Enhancer: Chain-of-Thought Prompted Adaptive Enhancer for Object Detection under Unknown Degradations论文提出的CPA-Enhancer链式思考网络&#xff0c;CPA-Enhancer通过引入链式思考提示机制&am…

使用虚幻引擎为AR体验提供动力

Powering AR Experiences with Unreal Engine ​​​​​​​ 目录 1. 虚幻引擎概述 2. 虚幻引擎如何为AR体验提供动力 3. 虚幻引擎中AR体验的组成部分是什么&#xff1f; 4. 使用虚幻引擎创建AR体验 5. 虚幻引擎中AR的优化提示 6. 将互动性融入AR与虚幻引擎 7. 在AR中…

C++_Function包装器和bind

文章目录 前言第一种第二种 仿函数第三种 lambda表达式 一、Function包装器二、使用场景三、std::bind 前言 到目前为止的学习&#xff0c;我们知晓了三种方式来传函数。 第一种 #include<iostream>int Plus(int i, int j) {return i j; }int main() {int(*func)(int…

从大厂裸辞半年,我靠它成功赚到了第一桶金,如果你失业了,建议这样做,不然时间太久了就完了

程序员接私活和创业是许多技术从业者关注的话题。下面我将介绍一些程序员接私活和创业的渠道和建议&#xff1a; 接私活的渠道&#xff1a; 自媒体平台&#xff1a; 可以利用社交媒体、个人博客、技术社区等平台展示自己的作品和技能&#xff0c;吸引潜在客户。自由工作平台&…

竞赛课第五周(并查集+Treap树的应用)

目的&#xff1a; &#xff08;1&#xff09;熟悉并掌握并查集的应用 &#xff08;2&#xff09;熟悉并掌握BST &#xff08;3&#xff09;熟悉并掌握Treap树的建立与应用 实验内容&#xff1a; 1.并查集 poj 1611 嫌疑人 严重急性呼吸系统综合症 (SARS) 是一种病因不明的…

书生·浦语大模型-第一节课笔记

视频总结 23年发布的模型在一些材料中归位指令微调模型&#xff0c;后面逐渐升级应该已经是train的模型了 技术报告总结 InternLM2 Technical Report 评测与特点 6 dimensions and 30 benchmarks, long-context modeling, and open-ended subjective evaluations长文本…

智能革命:ChatGPT3.5与GPT4.0的融合,携手DALL·E 3和Midjourney开启艺术新纪元

迷图网(kk.zlrxjh.top)是一个融合了顶尖人工智能技术的多功能助手&#xff0c;集成了ChatGPT3.5、GPT4.0、DALLE 3和Midjourney等多种智能系统&#xff0c;为用户提供了丰富的体验。以下是对这些技术的概述&#xff1a; ChatGPT3.5是由OpenAI开发的一个自然语言处理模型&#x…

设计模式学习笔记 - 设计模式与范式 -行为型:2.观察者模式(下):实现一个异步非阻塞的EventBus框架

概述 《1.观察者模式&#xff08;上&#xff09;》我们学习了观察者模式的原理、实现、应用场景&#xff0c;重点节介绍了不同应用场景下&#xff0c;几种不同的实现方式&#xff0c;包括&#xff1a;同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞最经典的实现…

springboot配置文件application.properties,application.yml/application.yaml

application.properties Springboot提供的一种属性配置方式&#xff1a;application.properties 初始时配置文件中只有一行语句。 启动时&#xff0c;比如tomcat的端口号默认8080&#xff0c;路径默认。如果我们要改变端口号及路径之类的可以在application.properties中配置。…

基于微信小程序的自习室预约系统的设计与实现

基于微信小程序的自习室预约系统的设计与实现 文章目录 基于微信小程序的自习室预约系统的设计与实现1、前言介绍2、功能设计3、功能实现4、开发技术简介5、系统物理架构6、系统流程图7、库表设计8、关键代码9、源码获取10、 &#x1f389;写在最后 1、前言介绍 伴随着信息技术…

ESP8266 WiFi物联网智能插座—上位机软件实现

1、软件架构 上位机主要作为下位机数据上传服务端以及节点调试的控制端&#xff0c;可以等效认为是专属版本调试工具。针对智能插座协议&#xff0c;对于下位机进行可视化监测和管理。 软件技术架构如下&#xff0c;主要为针对 Windows 的PC 端应用程序&#xff0c;采用WPF以及…

pyqt 创建右键菜单栏

class MainModule(QMainWindow, Ui_MainWindow):def __init__(self):super().__init__(parentNone)self.setupUi(self)# 允许出现菜单栏self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)# 对空间添加右键菜单栏处理 self.tableWidget.customContextMenuRequested.…

C练习题(1)

变种水仙花&#xff08;来自牛课网&#xff09; 题目 变种水仙花数 - Lily Number&#xff1a;把任意的数字&#xff0c;从中间拆分成两个数字&#xff0c;比如1461 可以拆分成&#xff08;1和461&#xff09;,&#xff08;14和61&#xff09;,&#xff08;146和1),如果所有拆…

【Web】NSSCTF Round#20 Basic 两道0解题的赛后谈

目录 前言 baby-Codeigniter 组合拳&#xff01; 前言 本想着说看看go的gin框架就睡了的&#xff0c;r3师傅提醒说赛题环境已经上了&#xff0c;那不赶紧研究下&#x1f600; 主要来谈谈做题的心路历程 baby-Codeigniter 拿到题目的第一反应应该是&#xff1a;“什么是C…