什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

说明

    该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。

    该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。

    说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。

友情提醒:本篇文章是属于系列文章,看该文章前,建议先看之前文章,可以更好理解项目结构。

qq群:801913255,进群有什么不懂的尽管问,群主都会耐心解答。

有兴趣的朋友,请关注我吧(*^▽^*)。

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

关注我,学不会你来打我

前言

该篇文章是实现【功能级权限】的开篇文章,其主要实现内容如下图↓

该图为功能级权限匹配插件

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

创建模型和数据源

在实现组件前,先要使用TS把模型和数据源创建好

我的文档目录如:Src->model->match->index.ts    依托于开源项目OverallAuth2.0统一权限分发中心的系统架构

创建匹配条件的关系

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

//组条件 export const matchingGroup = [     {         label: '',         value: 'And',         disabled: false     },     {         label: '',         value: 'Or',         disabled: false     } ]

View Code

创建匹配组件模型

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

//公式匹配模型 export interface matchingData {      id: string;     // 父级id     pid: string;     //匹配组(and,or)      matchGroup: string;     //层级     level: number;     //匹配条件     matchingWhere: matchingWhereData[];     //子集     children: matchingData[]; }  //匹配条件模型 export interface matchingWhereData {     //主键     id: string;     //字段key(选中的字段)     fieldKey: string;     //等式符号key(选中的符号)     matchEquationKey: string;     //匹配数据key(选中的匹配值)     matchDataKey: string; }

View Code

创建生成随机id的方法

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

/* 生成随机不重复id */ export const randamId = function () {     let n = 1;     let arr = [];     for (let i = 0; i < n; i++) {         arr[i] = parseInt((Math.random() * 10000000000).toString());     }     for (let i = 0; i < n; i++) {         for (let j = i + 1; j < n; j++) {             if (arr[i] === arr[j]) {                 randamId();                 return false;             }         }     }     return ("Item-" + arr).toString(); };

View Code

编写组件

我的页面目录:Src->views->match->index.vue      Src->views->match->match.vue

编写match.vue页面代码

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

<template>   <div class="plandiv">     <div v-for="item in data" :key="item.id" class="forDiv">       <div class="groupDiv">         <div class="groupBackColor">           <div style="width: 20%">             <el-select               v-model="item.matchGroup"               placeholder="请选择"               style="                 float: left;                 margin-right: 10px;                 margin-left: 10px;                 min-width: 100px;               "             >               <el-option                 v-for="group in matchingGroup"                 :key="group.value"                 :label="group.label"                 :value="group.value"               />             </el-select>           </div>           <div style="width: 80%">             <div class="buttonStyle">这里放操作按钮</div>           </div>         </div>       </div>     </div>   </div> </template> <script  lang="ts" > import {   matchingData,   matchingGroup,   matchingWhere,   matchingEquation,   positionList, } from "@/model/match"; import { defineComponent, PropType } from "vue";  export default defineComponent({   name: "xc-match",   props: {     data: {       type: Object as PropType<matchingData[]>,       required: true,     },   },   setup() {     return {       matchingGroup,       matchingWhere,       matchingEquation,       positionList,     };   },   components: {}, }); </script>  <style  scoped> /* 最外层样式 */ .plandiv {   background-color: white;   height: auto; } /* 循环层样式 */ .forDiv {   overflow-y: auto; } /* 分组样式 */ .groupDiv {   border: 1px solid #919aa3;   width: auto;   height: auto;   margin-top: 5px;   margin-right: 20px;   margin-bottom: 10px;   margin-left: 20px; } /* 组条件背景色 */ .groupBackColor {   background-color: #919aa3;   height: 50px;   line-height: 50px;   display: flex;   width: 100%;   justify-content: center;   align-items: center; }  /* 按钮样式 */ .buttonStyle {   text-align: left;   margin-left: 20px; } </style>

View Code

编写index.vue页面代码

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

<template>     <match :data="pageList"></match> </template> <script lang="ts" setup> import { matchingData, randamId } from "@/model/match"; import { ref } from "vue"; import match from "../match/match.vue"; const pageList = ref<matchingData[]>([   {     id: "Group-1",     pid: "0",     matchGroup: "And",     level: 1,     matchingWhere: [       {         id: randamId().toString(),         fieldKey: "",         matchEquationKey: "",         matchDataKey: "",       },     ],     children: [],   }, ]); </script>

View Code

index.vue页面中,我们添加了一条分组的默认值。查看下效果

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

添加分组按钮

在class='buttonStyle' div中添加如下代码

 

<el-button icon="CirclePlus" plain @click="addGroup(item)"                 >新增分组</el-button               >               <el-button icon="Plus" plain @click="addItem(item)"                 >新增条件</el-button               >               <el-button                 v-if="item.level !== 1"                 type="danger"                 icon="Delete"                 @click="deleteGroup(item)"                 >删除分组</el-button               >

 

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

添加按钮事件

添加前,我们必须先安装一个插件:npm install number-precision

在setup(props)中添加如下代码,并retrun事件

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

//最多组     const maxGroup = ref<number>(5);     //最多层级     const maxLevel = ref<number>(3);     //最多条件     const maxWhere = ref<number>(10);      // 添加组事件     const addGroup = function (item: matchingData) {       //获取当前组的长度       var listGroupLength = item.children.length;        //添加前验证最多添加多少层级       if (item.level >= maxLevel.value) {         ElMessage({           message: "最多添加" + maxLevel.value + "",           type: "warning",         });         return;       }        //添加前验证能添加多少组       if (listGroupLength >= maxGroup.value) {         ElMessage({           message: "每层下最多添加" + maxGroup.value + "个组",           type: "warning",         });         return;       }        //当前组必须要有条件才能添加下级组       if (item.matchingWhere.length == 0) {         ElMessage({           message: "当前组下无任何条件,不能添加分组!",           type: "warning",         });         return;       }        //组织要添加节点的数据       var groupId = item.id + "-" + (listGroupLength + 1);       var groupPid = item.id;       var groupLevel = item.level + 1;        //找到对应的下标       const index = props.data.findIndex((s) => {         if (s.id === item.id) {           return true;         }       });        //精确插入当前节点及插入位置       var indexLength = listGroupLength + 1;       item.children.splice(plus(...[index, indexLength]), 0, {         id: groupId,         pid: groupPid,         matchGroup: "Or",         level: groupLevel,         matchingWhere: [],         children: [],       });     };          // 删除组     const deleteGroup = function (item: matchingData) {       GetGroupSpliceIndex(item.id, props.data);     };      //递归删除组     const GetGroupSpliceIndex = (id: string, list: matchingData[]) => {       //找到删除数据下标       const index = list.findIndex((p: { id: string }) => {         if (p.id === id) {           return true;         }       });       if (index === -1) GetGroupSpliceIndex(id, list[0].children);       list.forEach((f: { id: string }) => {         if (f.id == id) {           list.splice(index, 1);         }       });     };

View Code

这个时候,我们点击按钮,不会出现下级。因为递归的重要一步,并没有完成。

在match.vue 页面中找到有class="groupDiv" 的div,在div中的末尾添加如下代码

   <xc-match           v-if="item.children && item.children.length"           :data="item.children"         />

以上代码是实现递归的关键,位置一定要准。

说明一点xc-match一定要和页面导出的名称一样。

看效果图

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

添加条件及条件按钮

添加条件项

在match.vue页面xc-match元素前,添加如下代码

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

 <div           class="itemBackColor"           v-for="whereItem in item.matchingWhere"           :key="whereItem.id"         >           <!-- 匹配条件 -->           <el-select             v-model="whereItem.fieldKey"             placeholder="请选择匹配条件"             style="width: 240px"           >             <el-option               v-for="where in matchingWhere"               :key="where.value"               :label="where.label"               :value="where.value"             />           </el-select>           <!-- 匹配等式 -->           <el-select             v-model="whereItem.matchEquationKey"             placeholder="请选择等式"             style="width: 240px"           >             <el-option               v-for="equation in matchingEquation"               :key="equation.value"               :label="equation.label"               :value="equation.value"             />           </el-select>           <!-- 匹配值 -->           <el-input-number             v-model="whereItem.matchDataKey"             :step="1"             min="1"             max="200"             step-strictly             style="width: 240px"             v-if="whereItem.fieldKey === 'Age'"           />           <el-select             v-else-if="whereItem.fieldKey === 'Position'"             v-model="whereItem.matchDataKey"             placeholder="请选择职位"             style="width: 240px"           >             <el-option               v-for="position in positionList"               :key="position.value"               :label="position.label"               :value="position.value"             />           </el-select>           <el-date-picker             v-else-if="whereItem.fieldKey === 'CreateTime'"             v-model="whereItem.matchDataKey"             type="date"             style="width: 240px"             placeholder="请选择时间"           />           <el-input             v-else             v-model="whereItem.matchDataKey"             style="width: 240px"             placeholder="请输入"             clearable           />           <el-button             type="danger"             icon="Delete"             plain             size="small"             style="margin-left: 10px"             @click="deleteItem(whereItem, item)"             >删除条件</el-button           >           <!-- 当前项id:{{ whereItem.id }} -->         </div>

View Code

css如下

/* 项背景色 */ .itemBackColor {   height: 46px;   display: -webkit-box;   margin-left: 20px;   margin-right: 20px;   display: flex;   align-items: center; } .itemBackColor > *:not(:first-child) {   margin-left: 10px; }

添加条件按钮事件

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

 //添加项事件     const addItem = function (item: matchingData) {       if (item.matchingWhere.length > maxWhere.value) {         ElMessage({           message: "每层下最多添加" + maxWhere.value + "组条件",           type: "warning",         });         return;       }       item.matchingWhere.push({         id: randamId().toString(),         fieldKey: "",         matchEquationKey: "",         matchDataKey: "",       });     };      // 删除项     const deleteItem = function (item: matchingWhereData, data: matchingData) {       GetItemSpliceIndex(item.id, data);     };      //递归删除项     const GetItemSpliceIndex = (id: string, list: any) => {       //找到删除数据下标       const index = list.matchingWhere.findIndex((p: { id: string }) => {         if (p.id === id) {           return true;         }       });       if (index === -1) GetItemSpliceIndex(id, list.children);       list.matchingWhere.forEach((f: { id: string }) => {         if (f.id == id) {           //删除当前项           list.matchingWhere.splice(index, 1);           if (list.matchingWhere.length == 0) {             var parentGroup = props.data.filter((s) => s.id == list.pid);             //当前组下无任何项并且层级不等于1,删除当前组             if (parentGroup.length == 0 && list.level !== 1) {               GetGroupSpliceIndex(list.id, props.data);             }           }         }       });     };

View Code

查看效果,如下图↓

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

验证条件是否完整

编写验证方法

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

 //验证条件是否为空     const VerifyWhereEmpty = function () {       const isTrueArray = ref<boolean[]>([]);       VerifyFunction(props.data, isTrueArray.value);       const trueArray = isTrueArray.value?.filter((f) => f === true);       if (trueArray.length === 0) {         ElMessage({           message: "成功",           type: "warning",         });       } else {         ElMessage({           message: "匹配条件未填写完整",           type: "warning",         });       }     };     //递归验证     const VerifyFunction = function (       list: matchingData[],       isTrueArray: boolean[]     ) {       list.forEach((element) => {         element.matchingWhere.forEach((w) => {           if (             w.matchEquationKey.length == 0 ||             w.matchDataKey.length == 0 ||             w.fieldKey.length == 0           ) {             isTrueArray.push(true);             return;           }         });         if (element.children.length > 0) {           VerifyFunction(element.children, isTrueArray);         }       });     };

View Code

在index.vue 页面调用

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

<template>   <div>     <el-button type="success" icon="Check" @click="submitForm">       保存     </el-button>     <match :data="pageList" ref="childRef"></match>   </div> </template> <script lang="ts" setup> import { matchingData, randamId } from "@/model/match"; import { ref } from "vue"; import match from "../match/match.vue"; //样式 const emit = defineEmits(["validate"]); const pageList = ref<matchingData[]>([   {     id: "Group-1",     pid: "0",     matchGroup: "And",     level: 1,     matchingWhere: [       {         id: randamId().toString(),         fieldKey: "",         matchEquationKey: "",         matchDataKey: "",       },     ],     children: [],   }, ]); //保存 const childRef = ref(); const submitForm = function () {   if (childRef.value != null) {     childRef.value.VerifyWhereEmpty();   } }; </script>

View Code

做完这些就能达到最终效果

 

需要源码的,关注公众号,发送【权限】获取源码

以上就是本篇文章的全部内容,感谢耐心观看

后端WebApi 预览地址:http://139.155.137.144:8880/swagger/index.html

前端vue 预览地址:http://139.155.137.144:8881

关注公众号:发送【权限】,获取源码

有兴趣的朋友,请关注我微信公众号吧(*^▽^*)。

什么!你还不会写Vue组件,编写《功能级权限》匹配公式组件

关注我:一个全栈多端的宝藏博主,定时分享技术文章,不定时分享开源项目。关注我,带你认识不一样的程序世界

 

 

 

 

 

 

发表评论

评论已关闭。

相关文章