【JSON2WEB】 12基于Amis-admin的动态导航菜单树

【JSON2WEB】01 WEB管理信息系统架构设计

【JSON2WEB】02 JSON2WEB初步UI设计

【JSON2WEB】03 go的模板包html/template的使用

【JSON2WEB】04 amis低代码前端框架介绍

【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成

【JSON2WEB】06 JSON2WEB前端框架搭建

【JSON2WEB】07 Amis可视化设计器CRUD增删改查

【JSON2WEB】08 Amis的事件和校验

【JSON2WEB】09 Amis-editor的代码移植到json2web

【JSON2WEB】10 基于 Amis 做个登录页面login.html

【JSON2WEB】11 基于 Amis 角色功能权限设置页面


管理信息系统一般注册用户较多,功能页面也很多,不同用户有不同的功能页面的操作权限,根据用户角色功能权限,生成动态的页面导航功能树是我采用的常规操作。

1 动态菜单的设计

关于数据库的表设计参阅 【REST2SQL】13 用户角色功能权限设计。

1.1 创建几个相关视图

  • 角色-页面权限视图
create or replace view role_menu_v as
select m.p_id as m_id,m.s_name ,s.pf_role,r.p_id as r_id,decode(length(s.pf_role),4,1,0) as b_yn,m.f_modfrom s_menu m
cross join s_role r --先做一个角色与功能的笛卡尔交叉,再连接角色功能表
left join s_role_menu s on s.pf_menu = m.p_id and s.pf_role = r.p_id
order by r.p_id,m.p_id
;

在这里插入图片描述

  • 用户-角色视图
create or replace view user_role_v as
select r.p_id as r_id,r.s_name ,s.pf_user,u.p_id as u_id,decode(length(s.pf_role),4,1,0) as b_ynfrom s_role r
cross join s_user u --先做一个用户与角色的笛卡尔交叉,再连接用户角色表
left join s_user_role s on s.pf_user = u.p_id and s.pf_role = r.p_id
order by u.p_id,r.p_id
;

在这里插入图片描述

  • 用户-角色-页面视图
create or replace view user_role_menu_v as
select distinctm.p_id || m.s_name || nvl(m.s_note,'') as s_name,m.s_WINp,m.s_PARM,m.p_id as pf_menu,m.s_note,--u.pf_role,u.pf_user,m.f_mod
from s_user_role u -- 用户 - 角色 = 功能视图
left join s_role_menu r on r.pf_role = u.pf_role
left join s_menu m on m.p_id = r.pf_menu
order by u.pf_user, m.p_id
;

在这里插入图片描述

  • 用户-页面视图
create or replace view user_page_v as
select s_name as label,pf_menu as url,s_winp as schemaApi,pf_user as userid,decode(substr(pf_menu,2,3),'000',1,2) as layer
from USER_ROLE_MENU_V -- 用户功能页面
where f_mod = 'BS'
;

在这里插入图片描述
这个视图就是最后动态菜单树要呈现的内容,label,url,schemaapi是amin-admin矿建的要求,userid为用户Id,layer为导航菜单的层级,我一般只用2级。

2 后端实现

前端登录时发送过来用户ID,根据用户id获得页面权限列表和token。后端我还是用REST2SQL来实现。

2.1 创建获取用户页面的函数

代码如下:

/ 获取用户页面
func getUserPages(userId string) map[string]interface{} {selectSQL := "select label,url,schemaApi,layer from user_page_v where userid = '" + userId + "'"//执行 sql并返回 json 结果logger.Alog(true, fmt.Sprint("getUserPage:", selectSQL))result := Icrud.SelectData(selectSQL)// json串反序列化var dataset []map[string]interface{}err := json.Unmarshal([]byte(result), &dataset)if err != nil {fmt.Println("Error:", err)return nil}rows := make(map[string]interface{})rows["rows"] = datasetreturn rows
}

输入参数用户ID,返回一个map。

2.2 doToken()函数的修改

用户验证成功后,获取用户页面功能列表。

// 根据请求参数执行不同的TOKEN操作 ///
func doTOKEN(w http.ResponseWriter, req map[string]interface{}) {// 返回数据rw := returnMap()rowsMap := make(map[string]interface{})tokenMap := make(map[string]interface{})// token操作, generate or validateresToken := strings.ToLower(req["ResName"].(string))switch resToken {case "generate-token":// w.Write([]byte("generate-token"))var uid_pwd map[string]string = make(map[string]string)uid_pwd["Userid"] = req["Userid"].(string)uid_pwd["Passwd"] = req["Passwd"].(string)// 用户名及密码验证ret1 := uidPwdIsValid(uid_pwd)if ret1 == 1 {//fmt.Println(ret1)tokenMap = token.GenerateTokenHandler(w, uid_pwd)rw["msg"] = "恭喜您登录成功!"// 获取功能页面列表rowsMap = getUserPages(uid_pwd["Userid"])//fmt.Println(rowsMap)} else {tokenMap["token"] = "无效用户Id:" + uid_pwd["Userid"] + "或密码" + uid_pwd["Passwd"]rw["status"] = 401rw["msg"] = "用户ID或密码无效!"}// http://127.0.0.1:5217/TOKEN/generate-token?userid=9998&passwd=8999// curl "http://127.0.0.1:5217/TOKEN/generate-token?userid=9998&passwd=8999"case "validate-token"://w.Write([]byte("validate-token"))var tokenString string = req["Authorization"].(string)fmt.Println(tokenString)tokenMap = token.ValidateTokenHandler(w, tokenString)// curl http://localhost:5217/token/validate-token -H "Authorization:token"}// 返回数据if tokenMap == nil {rw["status"] = 401rw["msg"] = "无效token"}dataMap := make(map[string]interface{})dataMap["rows"] = rowsMap["rows"]dataMap["token"] = tokenMap["token"]rw["data"] = dataMap// 输出到 http.ResponseWriterhttpResWriter(w, rw)
}

就是返回token和用户页面列表,Json内容如下:


{"data": {"rows": [{"LABEL": "Z000系统管理","LAYER": 1,"SCHEMAAPI": null,"URL": "Z000"},{"LABEL": "Z010页面管理","LAYER": 2,"SCHEMAAPI": "page.json","URL": "Z010"},{"LABEL": "Z020角色管理","LAYER": 2,"SCHEMAAPI": "role.json","URL": "Z020"},{"LABEL": "Z030角色功能权限设置","LAYER": 2,"SCHEMAAPI": "role_menu.json","URL": "Z030"},{"LABEL": "Z040用户管理","LAYER": 2,"SCHEMAAPI": "user.json","URL": "Z040"},{"LABEL": "Z050用户角色设置","LAYER": 2,"SCHEMAAPI": "user_role.json","URL": "Z050"}],"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiI1NDQ0IiwicGFzc3dkIjoiNDQ0NSIsImV4cCI6MTcxMjE1MjE4NiwiaXNzIjoiNTIxN-iCoeWKoemZoiJ9.H13dcOP6I4LV-KbCKsr8kYmtO3_jwf3QJ3uvk7Goy2k"},"msg": "恭喜您登录成功!","status": 0
}

用户页面是要按层级排序的。

3 前端实现

登录成功后,保存用户页面列表,主页获取导航site.json时加入,用户功能页面。

3.1 site.json页面

{"status": 0,"msg": "","data": {"pages": [{"label": "Home","url": "/","redirect": "welcome"},{"label": "导航树","children": [{"label": "Welcome to Json2Web","url": "welcome","schemaApi": "get:/pages/hello.json"}          ]},{"label": "示例","children": [{"label": "REST2SQL","link": "https://blog.csdn.net/html5builder/article/details/135544119"},{"label": "JSON2WEB","link": "https://blog.csdn.net/html5builder/article/details/135698948"},{"label": "AMIS文档","link": "https://aisuda.bce.baidu.com/amis/zh-CN/docs/index"}]}]}
}

动态页面菜单就加在【导航树】的节点下面。

3.2 login.html登录页面

只需要成功后,保存下来用户功能页面即可。api代码如下:

api: {url: 'http://127.0.0.1:5217/token/generate-token?userid=$userId&passwd=$passWd',method: 'get',adaptor: function (payload) {console.log(payload);if (payload.status === 0) {localStorage.setItem('token', payload.data.token);let rows = JSON.stringify(payload.data.rows)// console.log('rows',rows);localStorage.setItem('rows', rows);// localStorage.clear(); location.href = '/login.html';return payload;}}},

关键代码就两行:

	let rows = JSON.stringify(payload.data.rows)// console.log('rows',rows);localStorage.setItem('rows', rows);

先把json对象转为json字符串,在保存到loacaStorage中。

3.2 index.html主页

原来页面导航的api如下:

api:'/pages/site.json'

增加接收适配器代码如下:

api: {url: '/pages/site.json',adaptor: function (payload) {console.log('Payload', payload);// 页面权限字符串let rows = localStorage.getItem("rows");// 字符串转jsonlet pageJson = JSON.parse(rows);console.log('pageJson:', pageJson);// 要插入菜单的节点let pages = payload.data.pages[1];console.log('pages:', pages);// 创建动态菜单pageJson.map(function (page) {let layers = page.LAYER;let labels = page.LABEL;let schemaApis = 'get:/pages/' + page.SCHEMAAPI;let urls = page.URL;let l1 = pages.children.length;if (layers == 1) {// 插入一级菜单               pages.children[l1] = {label:labels,"children":[]};} else {    // 插入二级菜单let l2 =  pages.children[l1 - 1].children.length;       pages.children[l1 - 1].children[l2] = {label:labels,url:urls,schemaApi:schemaApis};  };});// 返回return payload;}}

注:先取出保存的用户页面列表Json字符串并转为json对象方便操作,再定位要插入导航节点,三采用map循环创建动态菜单(根据层级构建,一级只有label,和children[];二级还有url和schemaapi)。

4 实操演练

4.1 登录

在这里插入图片描述
输入用户名和密码点【提交】即可。

4.2 欢迎页面

登录成功切换到主页的欢迎页面:

在这里插入图片描述

4.3 动态导航菜单加载成功

动态导航菜单加载成功,测试各页面操作正常。
在这里插入图片描述


本文完。

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

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

相关文章

Flume 拦截器概念及自定义拦截器的运用

文章目录 Flume 拦截器拦截器的作用拦截器运用1.创建项目2.实现拦截器接口3.编写事件处理逻辑4.拦截器构建5.打包与上传6.编写配置文件7.测试运行 Flume 拦截器 在 Flume 中,拦截器(Interceptors)是一种可以在事件传输过程中拦截、处理和修改…

FreeRtos入门-4 事件组与同步点

事件组 事件组 同步点 创建 xEventGroupCalc xEventGroupCreate();//1&#xff0c;创建事件组 xEventGroupSyc xEventGroupCreate() 设置 xEventGroupSetBits(xEventGroupCalc,(1<<0));//设置事件组bit0 位 xEventGroupSync(xEventGroupSyc,BUSYING,ALL,portMAX…

VB 通过COM接口解析PSD文件

最近有PS测评的需求&#xff0c;故而想到了解析psd文件&#xff0c;目的就是为了获取文档信息和图层信息&#xff1b;获取PS的图像信息有很多方式&#xff0c;有过程性的&#xff0c;比如监听PS的各种操作事件&#xff1b;有结果性的&#xff0c;比如本文写的解析PSD文件。 0.…

使用pip安装geopandas(24.4更新)

geopandas是我们用Python进行地理分析常用的库&#xff0c;在数据处理、分析、制图等场景中有着极为广泛的应用&#xff0c;但是在安装过程中会出现各种问题。​geopandas的安装方式有很多&#xff0c;今天我们选取较为简单的pip来进行geopandas的安装。 ​首先&#xff0c;我…

内部类(InnerClass)

概述 什么是内部类 将一个类A定义在另一个类B里面&#xff0c;里面的那个类A就称为内部类&#xff08;InnerClass&#xff09;&#xff0c;类B则称为外部类&#xff08;OuterClass&#xff09;。 为什么要声明内部类呢 具体来说&#xff0c;当一个事物A的内部&#xff0c;还有…

Java web第一次作业

1.学会用记事本编写jsp文件&#xff0c;并放进tomcat的相关目录下&#xff0c;运行。 源代码&#xff1a; <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head> <title>我的第一个JSP页面</ti…

JavaSE——运算符

1. 概念 运算符是一种用于执行特定操作的符号或关键字。在编程中&#xff0c;运算符用于对变量、常量和表达式进行操作&#xff0c;以产生一个结果。 作为一门计算机语言&#xff0c; Java 也提供了一套丰富的运算符来操纵变量。 Java 中运算符可分为以下&#xff1a;算术运算…

电商系列之促销

> 插&#xff1a;AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

算法沉淀——动态规划篇(子数组系列问题(下))

算法沉淀——动态规划篇&#xff08;子数组系列问题&#xff08;下&#xff09;&#xff09; 前言一、等差数列划分二、最长湍流子数组三、单词拆分四、环绕字符串中唯一的子字符串 前言 几乎所有的动态规划问题大致可分为以下5个步骤&#xff0c;后续所有问题分析都将基于此 …

CSS之第一个CSS样式和CSS选择符

前端这些博客&#xff0c;我觉得都是固定的语法&#xff0c;故而不会以过多的文字进行描述&#xff0c;本系列博文均以实例和代码介绍的方式进行&#xff0c;主要按照代码进行。不会以过多的文字描述。 第一个CSS样式 <!DOCTYPE html> <html lang"en">…

【JavaEE初阶系列】——文件操作 IO 之 文件系统操作

目录 &#x1f4dd;认识文件 &#x1f6a9;树型结构组织 和 目录 &#x1f388;绝对路径和相对路径 &#x1f6a9;文件类型 &#x1f4dd;文件系统操作 &#x1f388;File 概述 &#x1f388;File类的使用 1. 绝对路径 vs 相对路径 2. 路径分隔符 3. 静态成员变量 4…

【C语言】翻译环境与运行环境

一、前言 在我们学习C语言的时候&#xff0c;第一个接触的程序就是&#xff1a;在屏幕上打印” hello word! “&#xff0c;可当时的我们却未去深入的理解与感悟&#xff0c;一个程序代码是如何运行的&#xff1b;而这一期的博客&#xff0c;则是带着我们&#xff0c;通过C代码…

mac电脑安装redis教程

1、下载地址 Download | RedisRedisYou can download the last Redis source files here. For additional options, see the Redis downloads section below.Stable (7.2)Redis 7.2 …https://redis.io/download/#redis-downloads 2、安装 2.1 解压下载后的压缩文件 2.2 进入…

Vulnhub:WESTWILD: 1.1

目录 信息收集 arp nmap nikto whatweb WEB web信息收集 dirmap enm4ulinux sumbclient get flag1 ssh登录 提权 横向移动 get root 信息收集 arp ┌──(root㉿ru)-[~/kali/vulnhub] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 0…

LeetCode-236. 二叉树的最近公共祖先【树 深度优先搜索 二叉树】

LeetCode-236. 二叉树的最近公共祖先【树 深度优先搜索 二叉树】 题目描述&#xff1a;解题思路一&#xff1a;递归判断解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖…

linux操作系统的进程状态

这个博客只是为了自己复习用的&#xff01;&#xff01;&#xff01; 冯诺依曼体系结构 计算机是由一个一个硬件组成的 输入设备&#xff1a;键盘&#xff0c;鼠标&#xff0c;扫描仪&#xff0c;写板等等 中央处理器&#xff08;CPU&#xff09;:含有运算器和控制器等 输出单…

【算法练习】27:冒泡排序学习笔记

一、冒泡排序的算法思想 原理&#xff1a;以升序为例&#xff0c;冒泡排序通过从左往右连续比较相邻元素&#xff0c;当发现左边比右边大就交换元素。从左往右依次比较完称为“一轮”&#xff0c;每轮结束之后就会固定一个元素。 时间复杂度&#xff1a;2层循环&#xff0c;所以…

不讲概念,讲实操,mysql 分表模糊查询、分页查询 及 merge 表的使用

1.Mysql merge合并表的要求 1.合并的分表必须是 MyISAM 引擎&#xff0c;MyISAN引擎是不支持事务的。2.Merge表只保证合表后数据唯一性&#xff0c;合表前的数据可能会存在重复。3.表的结构必须一致&#xff0c;包括索引、字段类型、引擎和字符集。4.删除 tb_member1 分表正确…

Python实现BOA蝴蝶优化算法优化卷积神经网络分类模型(CNN分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝴蝶优化算法(butterfly optimization algorithm, BOA)是Arora 等人于2019年提出的一种元启发式智能算…