1 菜单管理页面设计
1.1 业务设计
菜单管理又称为资源管理,是系统资源对外的表现形式。本模块主要是实现对菜单进行添加、修改、查询、删除等操作。
CREATE TABLE `sys_menus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL COMMENT '资源名称',
`url` varchar(200) DEFAULT NULL COMMENT '资源URL',
`type` int(11) DEFAULT NULL COMMENT '类型 1:菜单 2:按钮',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
`parentId` int(11) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
`permission` varchar(500) DEFAULT NULL COMMENT '授权(如:sys:user:create)',
`createdTime` datetime DEFAULT NULL COMMENT '创建时间',
`modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
`createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
`modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='资源管理';
菜单表与角色表是多对多的关系,在表设计时,多对多关系通常由中间表(关系表)进行维护
基于角色菜单表的设计,其角色和菜单对应的关系数据要存储到关系表中,其具体存储形式
菜单与角色的关系表脚本设计如下:
CREATE TABLE `sys_role_menus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL COMMENT '角色ID',
`menu_id` int(11) DEFAULT NULL COMMENT 'ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色与菜单对应关系';
1.2 原型设计
当在主页左侧菜单栏,点击菜单管理时,在主页内容呈现区,呈现菜单列表页面
当在菜单列表页面点击添加按钮时,异步加载菜单编辑页面,并在列表内容呈现区,呈现菜单编辑页面,如图-4所示。
在菜单编辑页面选择上级菜单时,异步加载菜单信息,并以树结构的形式呈现上级菜单
1.3 API设计
菜单管理业务后台API分层架构及调用关系如图
2 菜单管理页面展示
2.1 首页菜单事件处理
▪ 业务描述与设计实现
首先准备菜单列表页面(/templates/pages/sys/menu_list.html),然后在starter.html页面中点击菜单管理时异步加载菜单列表页面。
▪ 关键代码设计与实现
找到项目中的starter.html页面,页面加载完成以后,注册菜单管理项的点击事件,当点击菜单管理时,执行事件处理函数。关键代码如下:
$(function(){
…
doLoadUI("load-menu-id","menu/menu_list")
})
说明:对于doLoadUI函数,假如在starter.html中已经定义,则无需再次定义.
function doLoadUI(id,url){
$("#"+id).click(function(){
$("#mainContentId").load(url);
});
}
其中,load函数为jquery中的ajax异步请求函数。
2.2 菜单列表页面
▪ 业务描述与设计实现
本页面呈现菜单信息时要以树结构形式进行呈现。此树结构会借助jquery中的treeGrid插件进行实现,所以在菜单列表页面需要引入treeGrid相关JS。但是,具体的treeGrid怎么用可自行在网上进行查询(已比较成熟)。
▪ 关键代码设计与实现:
关键JS引入(menu_list.html),代码如下:
<script type="text/javascript" src="bower_components/treegrid/jquery.treegrid.extension.js"></script>
<script type="text/javascript" src="bowe
r_components/treegrid/jquery.treegrid.min.js"></script>
<script type="text/javascript" src="bower_components/treegrid/tree.table.js"></script>
3 菜单管理页面代码实现
3.1 菜单列表数据实现
3.1.1 数据加载时序
页面数据展示
菜单列表页面加载完成,启动菜单数据异步加载操作,本次菜单列表页面要呈现菜单以及上级菜单信息,其数据查询时,数据的封装及传递过程
页面菜单数据删除展示
基于用户在列表页面上选择的的菜单记录ID,执行删除操作,本次删除业务实现中,首先要基于id判断当前菜单是否有子菜单,假如有子菜单则不允许删除,没有则先删除菜单角色关系数据,然后再删除菜单自身信息。
上级菜单页面展示
在菜单编辑页面上,点击上级菜单时,其数据加载时序分析
菜单数据添加实现
用户在菜单编辑页面输入数据,然后异步提交到服务端,其简易数据传递基本架构
用户在菜单添加页面中填写好菜单数据,然后点击保存按钮,将用户填写的数据添加到数据库。
菜单数据更新展示
当点击编辑页面更新按钮时
3.1.2 代码实现
第一步:创建SysMenuDao层接口
package com.cy.pj.sys.dao;
import com.cy.pj.common.pojo.Node;
import com.cy.pj.sys.pojo.SysMenu;
import com.cy.pj.sys.pojo.SysUserMenu;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
@Mapper
public interface SysMenuDao {
List<SysUserMenu> findMenusByIds(List<Integer> menuIds);
//基于菜单ID获取授权表示
List<String> findPermissions(List<Integer> menuIds);
int updateObject(SysMenu entity);
@Insert(" insert into sys_menus " +
"(name,url,type,sort,note,parentId,permission,createdTime,modifiedTime,createdUser,modifiedUser) " +
"values " +
"(#{name},#{url},#{type},#{sort},#{note},#{parentId},#{permission},now(),now(),#{createdUser},#{modifiedUser})")
int insertObject(SysMenu entity);
@Select("select id,name,parentId from sys_menus")
List<Node> findZtreeMenuNodes();
@Select("select count(*) from sys_menus where parentId=#{id}")
int getChildCount(Integer id);
@Delete("delete from sys_menus where id=#{id}")
int deleteObject(Integer id);
//查询所有菜单信息
List<Map<String,Object>> findObjects();
}
第二步:创建SysMenuMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.pj.sys.dao.SysMenuDao">
<resultMap type="com.cy.pj.sys.pojo.SysUserMenu" id="sysUserMenu">
<!-- 一级菜单映射 -->
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="url" column="url"/>
<!-- 二级菜单映射 -->
<collection property="childs" ofType="com.cy.pj.sys.pojo.SysUserMenu">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
<result property="url" column="curl"/>
</collection>
</resultMap>
<select id="findMenusByIds"
resultMap="sysUserMenu">
select p.id,p.name,p.url,c.id cid,c.name cname,c.url curl
from sys_menus p join sys_menus c
on c.parentId=p.id
<where>
<foreach collection="menuIds"
open="("
close=")"
separator="or"
item="menuId">
c.id=#{menuId}
</foreach>
and p.parentId is null
</where>
</select>
<select id="findPermissions"
resultType="string">
select permission <!-- sys:user:update -->
from sys_menus
where id in
<foreach collection="menuIds"
open="("
close=")"
separator=","
item="item">
#{item}
</foreach>
</select>
<!--查询所有菜单以及菜单对应的上级菜单,当没有上级菜单时,当前菜单的上级菜单显示为null-->
<select id="findObjects" resultType="map">
/*方法1(左外关联查询)*/
/*select c.*,p.name parentName
from sys_menus c left join sys_menus p
on c.parentId=p.id*/
/*方法2(嵌套查询)*/
select c.*,(select p.name
from sys_menus p
where c.parentId=p.id) parentName
from sys_menus c
</select>
<update id="updateObject"
parameterType="com.cy.pj.sys.pojo.SysMenu">
update sys_menus
set
name=#{name},
type=#{type},
sort=#{sort},
url=#{url},
parentId=#{parentId},
permission=#{permission},
modifiedUser=#{modifiedUser},
modifiedTime=now()
where id=#{id}
</update>
</mapper>
第三步:创建SysMenuService接口
在菜单查询中,业务层对象主要是借助数据层对象完成菜单数据的查询。后续还可以基于AOP对数据进行缓存,记录访问日志等。
package com.cy.pj.sys.servive;
import com.cy.pj.common.pojo.Node;
import com.cy.pj.sys.pojo.SysMenu;
import com.cy.pj.sys.pojo.SysUserMenu;
import java.util.List;
import java.util.Map;
public interface SysMenuService {
List<SysUserMenu> findUserMenusByUserId(Integer id);
int updateObject(SysMenu entity);
int saveObject(SysMenu entity);
List<Node> findZtreeMenuNodes();
int deleteObject(Integer id);
List<Map<String,Object>> findObjects();
}
第四步:创建SysMenuServiceImpl实现类
package com.cy.pj.sys.servive.impl;
import com.cy.pj.common.exception.ServiceException;
import com.cy.pj.common.pojo.Node;
import com.cy.pj.sys.dao.SysUserRoleDao;
import com.cy.pj.sys.pojo.SysMenu;
import com.cy.pj.sys.dao.SysMenuDao;
import com.cy.pj.sys.dao.SysRoleMenuDao;
import com.cy.pj.sys.pojo.SysUserMenu;
import com.cy.pj.sys.servive.SysMenuService;
import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class SysMenuServiceImpl implements SysMenuService {
@Autowired
private SysMenuDao sysMenuDao;
@Autowired
private SysRoleMenuDao sysRoleMenuDao;
@Autowired
private SysUserRoleDao sysUserRoleDao;
@Override
public List<SysUserMenu> findUserMenusByUserId(Integer id) {
//1.对用户id进行判断
//2.基于用户id查找用户对应的角色id
List<Integer> roleIds=
sysUserRoleDao.findRoleIdsByUserId(id);
//3.基于角色id获取角色对应的菜单信息,并进行封装.
List<Integer> menuIds=
sysRoleMenuDao.findMenuIdsByRoleIds(roleIds);
//4.基于菜单id获取用户对应的菜单信息并返回
return sysMenuDao.findMenusByIds(menuIds);
}
@Override
public int updateObject(SysMenu entity) {
//1.合法验证
if(entity==null)
throw new ServiceException("保存对象不能为空");
if(StringUtils.isEmpty(entity.getName()))
throw new ServiceException("菜单名不能为空");
//2.更新数据
int rows=sysMenuDao.updateObject(entity);
if(rows==0)
throw new ServiceException("记录可能已经不存在");
//3.返回数据
return rows;
}
@Override
public int saveObject(SysMenu entity) {
//1.合法验证
if(entity==null)
throw new IllegalArgumentException("保存对象不能为空");
if(StringUtils.isEmpty(entity.getName()))
throw new IllegalArgumentException("菜单名不能为空");
//2.保存数据
int rows=sysMenuDao.insertObject(entity);
//3.返回数据
return rows;
}
@Override
public List<Node> findZtreeMenuNodes() {
return sysMenuDao.findZtreeMenuNodes();
}
@Override
public int deleteObject(Integer id) {
//1,参数校验
if(id==null||id<1)
throw new IllegalArgumentException("id值无效");
//2,判定菜单是否有子菜单,有则不允许删除
int childCount=sysMenuDao.getChildCount(id);
if(childCount>0)
throw new ServiceException("请先删除子菜单");
//3,删除关系数据
sysRoleMenuDao.deleteObjectsByMenuId(id);
int rows=sysMenuDao.deleteObject(id);
//4,删除自身信息
if(rows==0)
throw new ServiceException("记录可能已经不存在");
return rows;
}
@Override
public List<Map<String, Object>> findObjects() {
return sysMenuDao.findObjects();
}
}
第五步:创建SysMenuController控制层
控制层对象主要负责请求和响应数据的处理,例如,本模块通过业务层对象执行业务逻辑,再通过VO对象封装响应结果(主要对业务层数据添加状态信息),最后将响应结果转换为JSON格式的字符串响应到客户端。
package com.cy.pj.sys.controller;
import com.cy.pj.common.pojo.JsonResult;
import com.cy.pj.sys.pojo.SysMenu;
import com.cy.pj.sys.servive.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SysMenuController {
@Autowired
private SysMenuService sysMenuService;
@RequestMapping("/menu/doUpdateObject")
public JsonResult doUpdateObject(SysMenu entity){
sysMenuService.updateObject(entity);
return new JsonResult("update ok");
}
@RequestMapping("/menu/doSaveObject")
public JsonResult doSaveObject(SysMenu entity){
sysMenuService.saveObject(entity);
return new JsonResult("save ok");
}
@RequestMapping("/menu/doFindZtreeMenuNodes")
public JsonResult doFindZtreeMenuNodes(){
return new JsonResult(
sysMenuService.findZtreeMenuNodes());
}
@RequestMapping("/menu/doDeleteObject")
public JsonResult doDeleteObject(Integer id){
sysMenuService.deleteObject(id);
return new JsonResult("delete ok");
}
@GetMapping("menu/doFindObjects")
public JsonResult doFindObjects(){
return new JsonResult(sysMenuService.findObjects());
}
}
第六步:创建SysRoleMenuDao接口
package com.cy.pj.sys.dao;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface SysRoleMenuDao {
List<Integer> findMenuIdsByRoleIds(
@Param("roleIds")List<Integer> roleIds);
int insertObjects(
@Param("roleId")Integer roleId,
@Param("menuIds")Integer[] menuIds);
@Delete("delete from sys_role_menus where role_id=#{roleId}")
int deleteObjectsByRoleId(Integer roleId);
//基于菜单id执行关系
@Delete("delete from sys_role_menus where menu_id=#{menuId}")
int deleteObjectsByMenuId(Integer menuId);
}
第七步:创建SysRoleMenuMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.pj.sys.dao.SysRoleMenuDao">
<select id="findMenuIdsByRoleIds"
resultType="int">
select menu_id
from sys_role_menus
where role_id in
<foreach collection="roleIds"
open="("
close=")"
separator=","
item="item">
#{item}
</foreach>
</select>
<select id="findMenuIdsByRoleId"
resultType="int">
select menu_id
from sys_role_menus
where role_id=#{id}
</select>
<insert id="insertObjects">
insert into sys_role_menus
(role_id,menu_id)
values
<foreach collection="menuIds"
separator=","
item="menuId">
(#{roleId},#{menuId})
</foreach>
</insert>
</mapper>
第八步:创建Node 类
定义值对象封装查询到的上级菜单id,name,parentId信息。
package com.cy.pj.common.pojo;
import lombok.Data;
import java.io.Serializable;
@Data
public class Node implements Serializable {
private static final long serialVersionUID = -7022202313802285223L;
private Integer id;
private String name;
private Integer parentId;
}
第九步:创建SysMenu 类
定义持久化对象,封装客户端请求数据,并将数据传递到数据层进行持久化。
package com.cy.pj.sys.pojo;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class SysMenu implements Serializable {
private static final long serialVersionUID = -1086340530112865421L;
private Integer id;
/**菜单名称*/
private String name;
/**菜单url: log/doFindPageObjects*/
private String url;
/**菜单类型(两种:按钮,普通菜单)*/
private Integer type=1;
/**排序(序号)*/
private Integer sort;
/**备注*/
private String note;
/**上级菜单id*/
private Integer parentId;
/**菜单对应的权限标识(sys:log:delete)*/
private String permission;
/**创建用户*/
private String createdUser;
/**修改用户*/
private String modifiedUser;
private Date createdTime;
private Date modifiedTime;
}
3.2 客户端页面呈现
menu_list.html
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">
菜单管理</h3>
<div class="box-tools">
<div class="input-group input-group-sm" style="width: 100px;">
<div class="input-group-btn">
<button type="button"
class="btn btn-success btn-delete">
删除</button>
<button type="button" class="btn btn-default btn-add">添加</button>
<button type="button" class="btn btn-default btn-update">修改</button>
</div>
</div>
</div>
</div>
<!-- /.box-header -->
<div class="box-body table-responsive no-padding">
<table id="menuTable" class="table table-hover">
<thead>
<tr>
<th data-field="selectItem" data-checkbox="true"></th>
</tr>
</thead>
</table>
</div>
</div>
<!-- /.box -->
</div>
</div>
<script type="text/javascript" src="bower_components/treegrid/jquery.treegrid.extension.js"></script>
<script type="text/javascript" src="bower_components/treegrid/jquery.treegrid.min.js"></script>
<script type="text/javascript" src="bower_components/treegrid/tree.table.js"></script>
<script type="text/javascript">
/**
* 初始化表格的列
*/
var columns = [
{
field : 'selectItem',
radio : true
},
{
title : '菜单ID',
field : 'id',
align : 'center',
valign : 'middle',
width : '80px'
},
{
title : '菜单名称',
field : 'name',
align : 'center',
valign : 'middle',
width : '130px'
},
{
title : '上级菜单',
field : 'parentName',
align : 'center',
valign : 'middle',
sortable : true,
width : '100px'
},
{
title : '类型',
field : 'type',
align : 'center',
valign : 'middle',
width : '70px',
formatter : function(item, index) {
if (item.type == 1) {
return '<span class="label label-success">菜单</span>';
}
if (item.type == 2) {
return '<span class="label label-warning">按钮</span>';
}
}
},
{
title : '排序号',
field : 'sort',
align : 'center',
valign : 'middle',
sortable : true,
width : '70px'
},
{
title : '菜单URL',
field : 'url',
align : 'center',
valign : 'middle',
width : '160px'
},
{
title : '授权标识',//要显示的标题名称
field : 'permission',//json串中的key
align : 'center',//水平居中
valign : 'middle',//垂直居中
sortable : false //是否排序
} ];//格式来自官方demos -->treeGrid(jquery扩展的一个网格树插件)
$(function(){
doGetObjects();
$(".input-group-btn")
.on("click",".btn-delete",doDeleteObject)
.on("click",".btn-add,.btn-update",doLoadEditUI);
})
function doLoadEditUI(){
var title;
//基于点击对象的class属性值,修改标题
if($(this).hasClass("btn-add")){
title="添加菜单";
}else{
title="修改菜单";
var item=doGetCheckedItem();
if(!item){
alert("请先选择");
return;
}
$("#mainContentId")
.data("rowData",item);
}
//异步加载编辑页面
var url="menu/menu_edit";
$("#mainContentId").load(url,function(){
$(".box-title").html(title);
})
}
function doGetCheckedItem(){
return $("tbody input[type='radio']:checked")
.parents("tr").data("rowData");
}
function doGetCheckedId(){
//方法1:
//var radio=$("tbody input[type='radio']:checked"); //if(radio)return radio.val(); //方法2:
//1.获取选中的记录
var selections=$("#menuTable")
//bootstrapTreeTable是treeGrid插件内部定义的jquery扩展函数
//getSelections为扩展函数内部要调用的一个方法
.bootstrapTreeTable("getSelections");
//2.对记录进行判定
if(selections.length==1)
return selections[0].id;
}
function doDeleteObject(){
//1.获取选中记录的id值
var id=doGetCheckedId();
console.log("id="+id);
if(!id){
alert("请先选中");
return;
}
//2.给出提示是否确认删除
if(!confirm("确认删除吗"))return;
//3.发送异步请求执行删除操作
//3.1定义请求参数
var params={"id":id};
//3.2定义请求url
var url="menu/doDeleteObject";
//3.3发送异步请求
$.post(url,params,function(result){
if(result.state==1){
alert(result.message);
$("tbody input[type='radio']:checked")
.parents("tr").remove();
}else{
alert(result.message);
}
})
}
function doGetObjects(){
//移除mainContentId位置的数据
$("#mainContentId").removeData();
var treeTable=new TreeTable(
"menuTable",//tableId
"menu/doFindObjects",//url
columns);//表中列的配置
//treeTable.setExpandColumn(2);
//做表格初始化
treeTable.init(); //发起ajax请求(借助ajax函数)
}
菜单列表页面(/templates/pages/sys/menu_edit.html)
<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">添加菜单</h3>
</div>
<!-- /.box-header -->
<!-- form start --> <form class="form-horizontal">
<div class="box-body">
<div class="form-group">
<label for="nameId" class="col-sm-2 control-label">类型</label>
<div class="col-sm-10 typeRadio">
<label class="radio-inline">
<input type="radio" name="typeId" value="1" checked> 菜单 </label>
<label class="radio-inline">
<input type="radio" name="typeId" value="2"> 按钮 </label>
</div>
</div>
<div class="form-group">
<label for="nameId" class="col-sm-2 control-label">菜单名称</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="nameId" placeholder="名称">
</div>
</div>
<div class="form-group">
<label for="parentId" class="col-sm-2 control-label">上级菜单</label>
<div class="col-sm-10">
<input type="text" class="form-control load-sys-menu" readonly="readonly" id="parentId" placeholder="上级菜单">
</div>
</div>
<div class="form-group">
<label for="urlId" class="col-sm-2 control-label">菜单URL</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="urlId" placeholder="url">
</div>
</div>
<div class="form-group">
<label for="permissionId" class="col-sm-2 control-label">授权标识:</label>
<div class="col-sm-10">
<input type="text" id="permissionId"
placeholder="多个用逗号分隔,如:user:list,user:create"
class="form-control">
</div>
</div>
<div class="form-group">
<label for="sortId" class="col-sm-2 control-label">排序号:</label>
<div class="col-sm-10">
<input type="text" id="sortId" placeholder="排序号"
class="form-control">
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="button" class="btn btn-default btn-cancel">Cancel</button>
<button type="button" class="btn btn-info pull-right btn-save">Save</button>
</div>
<!-- /.box-footer -->
</form>
<!-- zTree 对应的div -->
<div class="layui-layer layui-layer-page layui-layer-molv layer-anim" id="menuLayer" type="page" times="2" showtime="0" contype="object"
style="z-index:59891016; width: 300px; height: 450px; top: 100px; left: 500px; display:none">
<div class="layui-layer-title" style="cursor: move;">选择菜单</div>
<div class="layui-layer-content" style="height: 358px;">
<div style="padding: 10px;" class="layui-layer-wrap">
<ul id="menuTree" class="ztree"></ul> <!-- 动态加载树 -->
</div>
</div>
<span class="layui-layer-setwin"> <a class="layui-layer-ico layui-layer-close layui-layer-close1 btn-cancel" ></a></span>
<div class="layui-layer-btn layui-layer-btn-">
<a class="layui-layer-btn0 btn-confirm">确定</a>
<a class="layui-layer-btn1 btn-cancel">取消</a>
</div>
</div>
</div>
<script type="text/javascript" src="bower_components/ztree/jquery.ztree.all.min.js"></script>
<script type="text/javascript" src="bower_components/layer/layer.js">
</script>
<script type="text/javascript">
var zTree; //zTree是第三方扩展的一个Jquery插件
//初始化zTree时会用到
var setting = {
data : {
simpleData : {
enable : true,//表示使用简单数据模式
idKey : "id", //节点数据中保存唯一标识的属性名称
pIdKey : "parentId", //节点数据中保存其父节点唯一标识的属性名称
rootPId : null //根节点id
}//json 格式javascript对象
}
}//json 格式的javascript对象
$(function(){
$(".form-horizontal")//事件不能注册到$("#mainContentId")对象上
.on("click",".load-sys-menu",doLoadZtreeNodes);
$("#menuLayer")
.on("click",".btn-confirm",doSetSelectNode)
.on("click",".btn-cancel",doHideTree);
$(".box-footer")
.on("click",".btn-cancel",doCancel)
.on("click",".btn-save",doSaveOrUpdate)
var data=$("#mainContentId").data("rowData");
if(data)doInitEditFormData(data);
})
function doInitEditFormData(data){
/* $("input[type='radio']").each(function(){
if($(this).val()==data.type){ $(this).prop("checked",true); } }) */ $(".typeRadio input[value='"+data.type+"']").prop("checked",true);
$("#nameId").val(data.name);
$("#sortId").val(data.sort);
$("#urlId").val(data.url);
$("#permissionId").val(data.permission);
$("#parentId").val(data.parentName);
$("#parentId").data("parentId",data.parentId);
}
//获取表单数据
function doGetEditFormData(){
var params={
type:$("form input[name='typeId']:checked").val(),
name:$("#nameId").val(),
url:$("#urlId").val(),
sort:$("#sortId").val(),
permission:$("#permissionId").val(),
parentId:$("#parentId").data("parentId")
}
return params;
}
function doSaveOrUpdate(){
//1.获取表单数据
var params=doGetEditFormData();
var rowData=
$("#mainContentId").data("rowData");
//2.异步提交表单数据(post)
var insertUrl="menu/doSaveObject";
var updateUrl="menu/doUpdateObject";
var url=rowData?updateUrl:insertUrl;
if(rowData)params.id=rowData.id;
$.post(url,params,function(result){
if(result.state==1){
alert(result.message);
doCancel();
}else{
alert(result.message);
}
});
}
//编辑页面cancel事件处理
function doCancel(){
//1.定义url
var url="menu/menu_list";
//2.异步加载列表页面
$("#mainContentId").load(url);
}
//zTree取消按钮事件处理函数
function doHideTree(){
$("#menuLayer").css("display","none");
}
//zTree确定按钮事件处理函数
function doSetSelectNode(){
//1.获取选中的节点对象
var nodes=zTree.getSelectedNodes();
if(nodes.length==1){
var selectedNode=nodes[0];
console.log("selectNode",selectedNode);
var rowData=$("#mainContentId").data("rowData");
if(rowData){//修改时做如下处理
//判定当前选中的上级菜单节点是否为当前要修改节点的子节点.
var flag=isChild(rowData.id,selectedNode);
if(flag){
alert("不能选择当前节点以及对应子节点");
return;
}
}
//2.将对象中内容,填充到表单
$("#parentId").data("parentId",selectedNode.id);
$("#parentId").val(selectedNode.name);
}
//3.隐藏树对象
doHideTree();
}
//判定当前选中节点是否是当前节点的子节点
function isChild(currentNodeId,selectNode){
if(selectNode.id==currentNodeId)return true;
var node=selectNode.getParentNode();
if(!node)return false;
return isChild(currentNodeId,node);
}
function doLoadZtreeNodes(){
var url="menu/doFindZtreeMenuNodes";
//异步加载数据,并初始化数据
$.getJSON(url,function(result){
if(result.state==1){
//使用init函数需要先引入ztree对应的js文件
zTree=$.fn.zTree.init(
$("#menuTree"),
setting,
result.data);//id,name,parentId
//doRemoveNodeFromZtree();//修改时,可考虑此方案
//显示zTree对应的div
$("#menuLayer").css("display","block");
}else{
alert(result.message);
}
})
}
function doRemoveNodeFromZtree(){
//判定是否是修改,假如是修改,从zTree中移除当前菜单以及对应子菜单
var rowData=$("#mainContentId").data("rowData");
if(rowData){//rowData有值,表示是修改.
console.log("zTree",zTree);
//1.获取当前的菜单对象
var node=zTree.getNodeByParam("id",rowData.id,null);
console.log("node",node);
//2.移除当前菜单.
zTree.removeNode(node);
}
}
</script>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。