记ztree插件删除节点结合layer.confirm询问框问题

博客指出layer.confirm无法阻塞js执行,导致ztree插件beforeRemove回调函数未等用户确定就移除界面节点,可能造成前后台数据不一致。解决方案是不使用ztree默认删除功能,在layer.confirm中手动调用removeNode方法实现前后台数据同步删除。

问题:layer.confirm无法阻塞js执行,导致ztree插件的beforeRemove回调函数未等待用户确定删除便已经移除界面中的节点, 因此可能会出现前后台数据不一致情况,正常逻辑理应删除后台数据然后移除界面中的ztree节点元素。

解决方案:不使用ztree提供的默认删除功能(beforeRemove函数返回false即可),在layer.confirm中手动调用removeNode方法实现前台与后台的数据同步删除(舍弃ztree提供的自动删除功能)。代码如下:

//beforeRemove回调函数
function zTreeBeforeRemove(treeId, treeNode) {
      var zTree = $.fn.zTree.getZTreeObj("zTree");
      layer.confirm("确认删除节点 -> " + treeNode.name + " 吗?", {btn: ['确定', '取消']},
        function (index) {//确定
          $.ajax({
            url: url,
            data: {"id": treeNode.id},
            type: "POST",
            async: false,
            success: function (data) {
              if (!data) {
                layer.alert("该接口已经被申请!");
              } else {
                //手动移除节点
                zTree.removeNode(treeNode);
                layer.alert("删除成功!");
              }
            },
            error: function () {
              layer.alert("删除失败!");
            }
          });
        },
        function (index) {//取消
          layer.close(index);
        });
      //注意:返回false便不会触发onRemove事件
      return false;
    }

参考文献:https://blog.youkuaiyun.com/yqwayward/article/details/78312424

<!-- 端页面完整代码 --> @{ Layout = null; } <!DOCTYPE html> <html> <head> <link href="~/Scripts/layui/css/layui.css" rel="stylesheet" /> <script src="~/Scripts/layui/layui.js"></script> <script src="~/Scripts/jquery-3.4.1.js"></script> <style> body { padding: 10px 20px 20px 20px; width: 90% } .but { margin-top: -5px } </style> </head> <body> <fieldset class="layui-elem-field"> <legend> <span class="layui-breadcrumb"> <a href="">首页</a> <a href="">职位管理</a> </span> </legend> <div class="layui-field-box"> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label">职位名称</label> <div class="layui-input-block"> <input type="text" name="name" id="name" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">职位代码</label> <div class="layui-input-inline"> <input type="text" name="code" id="code" autocomplete="off" class="layui-input"> </div> </div> <button type="button" class="layui-btn layui-btn-radius but" id="searchButton" onclick="Search()"><i class="layui-icon layui-icon-search"></i>查询</button> <button type="button" class="layui-btn layui-bg-blue but" onclick="AddJob()"><i class="layui-icon layui-icon-addition"></i>添加</button> </div> </div> </fieldset> <fieldset class="layui-elem-field"> <table class="layui-hide" id="test" lay-filter="test"></table> <script type="text/html" id="toolDemo"> <div class="layui-clear-space"> <a class="layui-btn layui-btn-xs" lay-event="edit" id="Edit"><i class="layui-icon layui-icon-edit"></i>编辑</a> <a class="layui-btn layui-btn-xs layui-bg-orange" lay-event="del" id="del"><i class="layui-icon layui-icon-clear"></i>删除</a> </div> </script> </fieldset> <script> var tableIns; layui.use(['table', 'layer', 'form'], function () { var table = layui.table; var layer = layui.layer; // 创建渲染实例 tableIns = table.render({ elem: '#test', url: '/JobManagem/GetList', page: true, cols: [[ { type: 'numbers', width: '15%', title: '序列号' }, { field: 'JobName', width: '20%', title: '职位名称' }, { field: 'JobCode', width: '20%', title: '职位代码' }, { field: 'ModifyDate', width: '20%', title: '修改时间', templet: function (d) { return formatDate(d.ModifyDate); } }, { title: '操作', width: '25%', templet: '#toolDemo' } ]], }); // 编辑删除事件 table.on('tool(test)', function (obj) { var data = obj.data; if (obj.event === 'edit') { EditJob(data); } else if (obj.event === 'del') { DeleteJob(data, obj); } }); }); function formatDate(dateStr) { if (!dateStr) return ''; // 提取时间戳(兼容 "/Date(123456789)/" 格式) var timestamp = parseInt(dateStr.replace(/\/Date$(\d+)$\//, '$ 1')); var date = new Date(timestamp); return date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + // 月份从0开始,需+1 ('0' + date.getDate()).slice(-2); } // 添加职位弹窗 function AddJob() { layer.open({ type: 1, title: '添加职位', content: ` <div style="padding:20px"> <div class="layui-form-item"> <label class="layui-form-label">职位名称</label> <div class="layui-input-block"> <input type="text" id="add_name" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">职位代码</label> <div class="layui-input-block"> <input type="text" id="add_code" class="layui-input"> </div> </div> </div> `, btn: ['保存', '取消'], yes: function (index) { $.post('/JobManagem/AddJob', { JobName: $('#add_name').val(), JobCode: $('#add_code').val() }, function (res) { if (res.code == 0) { layer.close(index); Search(); // 刷新列表 } else { layer.msg('操作失败:' + res.msg); } }); } }); } // 编辑职位弹窗 function EditJob(data) { layer.open({ type: 1, title: '编辑职位', content: ` <div style="padding:20px"> <div class="layui-form-item"> <label class="layui-form-label">职位名称</label> <div class="layui-input-block"> <input type="text" id="edit_name" value="${data.JobName}" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">职位代码</label> <div class="layui-input-block"> <input type="text" id="edit_code" value="${data.JobCode}" class="layui-input"> </div> </div> </div> `, btn: ['更新', '取消'], yes: function (index) { $.post('/JobManagem/UpdateJob', { ID: data.ID, JobName: $('#edit_name').val(), JobCode: $('#edit_code').val() }, function (res) { if (res.code == 0) { layer.close(index); Search(); } else { layer.msg('更新失败:' + res.msg); } }); } }); } // 删除职位 function DeleteJob(data, obj) { layer.confirm('真的删除行 [' + data.JobName + '] 么', function (index) { $.post('/JobManagem/DeleteJob', { ID: data.ID }, function (res) { if (res.code == 0) { obj.del(); layer.close(index); } else { layer.msg('删除失败:' + res.msg); } }); }); } // 查询重载 function Search() { var nameVal = $('input[name="name"]').val().trim(); var codeVal = $('input[name="code"]').val().trim(); tableIns.reload({ where: { name: nameVal, code: codeVal }, page: { curr: 1 } // 重置分页 }); } </script> </body> </html> 这是一个vs.net mvc +layui+sqlsever数据库开发的游戏管理系统的用户管理模块,我希望你根据这段代码以及我下面提供的sql建表资料以及用户管理模块的控制器代码,研究代码风格和习惯帮我续写组织管理模块,表单要求有树形表格,给我提供完整代码表名:组织机构表(OrganizationStructure) 字段描述 字段名 数据类型 长度 是否主键 是否外键 是否必填 组织机构表主键 ID uniqueidentifier 16 1 FALSE TRUE 组织机构名称 OrgName varchar 200 0 FALSE TRUE 组织机构代码 OrgCode varchar 200 0 FALSE FALSE 级别 Leve int 4 0 FALSE FALSE 父节点 ParentId uniqueidentifier 16 0 FALSE FALSE 创建时间 CreateDate datetime 8 0 FALSE FALSE 修改时间 ModifyDate datetime 8 0 FALSE FALSE
最新发布
07-11
<!DOCTYPE html> <html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <th:block th:include="include :: header('教师管理列表')"/> <th:block th:include="include :: layout-latest-css"/> <th:block th:include="include :: ztree-css"/> </head> <body class="gray-bg"> <div class="ui-layout-west"> <div class="box box-main"> <div class="box-header"> <div class="box-title"> <i class="fa icon-grid"></i> 组织机构 </div> <div class="box-tools pull-right"> <button type="button" class="btn btn-box-tool" id="btnExpand" title="展开" style="display:none;"><i class="fa fa-chevron-up"></i></button> <button type="button" class="btn btn-box-tool" id="btnCollapse" title="折叠"><i class="fa fa-chevron-down"></i></button> <button type="button" class="btn btn-box-tool" id="btnRefresh" title="刷新部门"><i class="fa fa-refresh"></i></button> </div> </div> <div class="ui-layout-content"> <div id="tree" class="ztree"></div> </div> </div> </div> <div class="ui-layout-center"> <div class="container-div"> <div class="row"> <div class="col-sm-12 search-collapse"> <form id="formId"> <div class="select-list"> <input type="hidden" id="schoolId" name="schoolId"> <input type="hidden" id="collegeId" name="collegeId"> <ul> <li> <input id="selectConditionOneInput" type="text" name="multipleOne" style="width: 200px;" placeholder="姓名|工号(账号)"/> </li> <li> <input id="selectConditionTwoInput" type="text" name="multipleTwo" style="width: 250px;" placeholder="邮箱|手机号|身份证|昵称"/> </li> <li> <label>账号:</label> <select style="width: 60px" name="state" th:with="type=${@dict.getType('accountStatus')}"> <option value="">所有</option> <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option> </select> </li> <li> <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a> <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a> </li> </ul> </div> </form> </div> <div class="btn-group-sm" id="toolbar" role="group"> <a class="btn btn-success disabled" id="addBtn" onclick="$.operate.add($('#collegeId').val())" shiro:hasPermission="system:teacher:add"> <i class="fa fa-plus"></i> 新增 </a> <a class="btn btn-danger multiple disabled" onclick="javascript:batchUpdatePwd()" shiro:hasPermission="system:teacher:batchUpdatePwd"> <i class="fa fa-sign-out"></i> 批量重置密码 </a> <a id="importBtn" class="btn btn-info disabled" onclick="importExcel()" shiro:hasPermission="system:student:export"> <i class="fa fa-upload"></i> 导入 </a> <!-- <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="system:teacher:export">--> <!-- <i class="fa fa-download"></i> 导出--> <!-- </a>--> <a class="btn btn-warning" onclick="$.table.exportExcelByChoose()" shiro:hasPermission="system:teacher:export"> <i class="fa fa-upload"></i> 导出 </a> <a href="/teacherTemplate.xlsx">点击下载导入模版</a> </div> <div class="col-sm-12 select-table table-striped"> <table id="bootstrap-table"></table> </div> </div> </div> </div> <th:block th:include="include :: footer"/> <th:block th:include="include :: layout-latest-js"/> <th:block th:include="include :: ztree-js"/> <script th:inline="javascript"> var editFlag = [[${@permission.hasPermi('system:teacher:edit')}]]; var removeFlag = [[${@permission.hasPermi('system:teacher:remove')}]]; var genderDatas = [[${@dict.getType('sys_user_sex')}]]; var stateDatas = [[${@dict.getType('accountStatus')}]]; var prefix = ctx + "system/teacher"; $(function () { var panehHidden = false; if ($(this).width() < 769) { panehHidden = true; } $('body').layout({initClosed: panehHidden, west__size: 185}); // 回到顶部绑定 if ($.fn.toTop !== undefined) { var opt = { win: $('.ui-layout-center'), doc: $('.ui-layout-center') }; $('#scroll-up').toTop(opt); } queryTeacherList(); queryOrganizationTree(); }); function queryTeacherList() { var options = { url: prefix + "/list", createUrl: prefix + "/add/{id}", updateUrl: prefix + "/edit/{id}", removeUrl: prefix + "/remove", exportUrl: prefix + "/export", exportByChooseUrl: prefix + "/export/choose", importUrl: prefix + "/importData", modalName: "教师", columns: [ { checkbox: true }, { field: 'id', title: '唯一id', visible: false }, { field: 'name', title: '姓名' }, { field: 'account', title: '账号(职工号)' }, { field: 'gender', title: '性别', formatter: function (value, row, index) { return $.table.selectDictLabel(genderDatas, value); }, width: 20 }, { field: 'nickName', title: '昵称' }, { field: 'email', title: '邮箱' }, // { // field: 'idNum', // title: '身份证件号', // width: 100 // }, { field: 'phone', title: '手机号', // width: 100 }, { field: 'educational', title: '学历' }, { field: 'degree', title: '学位' }, // { // field: 'birthday', // title: '生日' // }, { field: 'state', title: '账号状态', formatter: function (value, row, index) { return statusTools(row); }, width: 20 }, { field: 'collegeName', title: '所在学院' }, { field: 'lastLoginTime', title: '最后一次登录时间' }, { title: '操作', align: 'center', formatter: function (value, row, index) { var actions = []; var more = []; more.push("<a id='editBtn' rowid='" + row.id + "' class='btn btn-success btn-xs " + editFlag + "' href='javascript:void(0)' onclick='power(this)'><i class='fa fa-edit'></i>权限</a> "); more.push("<a id='editBtn' rowid='" + row.id + "' class='btn btn-success btn-xs " + editFlag + "' href='javascript:void(0)' onclick='edit(this)'><i class='fa fa-edit'></i>编辑</a> "); more.push("<a id='resetPasswordBtn' rowid='" + row.id + "' class='btn btn-success btn-xs" + editFlag + "' href='javascript:void(0)' onclick='resetPassword(this)'><i class='fa fa-edit'></i>重置密码</a> "); more.push("<a id='removeBtn' rowid='" + row.id + "' class='btn btn-danger btn-xs " + editFlag + "' href='javascript:void(0)' onclick='remove(this)'><i class='fa fa-edit'></i>删除</a> "); actions.push('<a id="' + 'operation' + row.id + '" rowid="' + row.id + '" rowname="' + row.name + '" rowaccount="' + row.account + '" tabindex="0" class="btn btn-info btn-xs" role="button" data-container="body" data-placement="left" data-toggle="popover" data-html="true" data-trigger="hover" data-content="' + more.join('') + '"><i class="fa fa-chevron-circle-right"></i>更多操作</a>'); return actions.join(''); }, width: 20 }] }; $.table.init(options); } /* 账号状态显示 */ function statusTools(row) { if (row.state == 0) { // 禁用 return '<i class=\"fa fa-toggle-off text-info fa-2x\" onclick="enable(\'' + row.id + '\')"></i> '; } else { // 启用 return '<i class=\"fa fa-toggle-on text-info fa-2x\" onclick="disable(\'' + row.id + '\')"></i> '; } } /* 账号状态-停用 */ function disable(id) { $.modal.confirm("确认要禁用账号吗?", function () { $.operate.post(prefix + "/changeState", {"id": id, "state": 0}); }) } /* 账号状态-启用 */ function enable(id) { $.modal.confirm("确认要启用账号吗?", function () { $.operate.post(prefix + "/changeState", {"id": id, "state": 1}); }) } /** * 组织树 */ function queryOrganizationTree() { var url = ctx + "system/organization/collegeTreeData"; var options = { url: url, expandLevel: 3, onClick: zOnClick }; $.tree.init(options); function zOnClick(event, treeId, treeNode) { if (treeNode.level == 0) { $("#addBtn").addClass("disabled"); $("#importBtn").addClass("disabled"); } else { $("#addBtn").removeClass("disabled"); $("#importBtn").removeClass("disabled"); } var treeObj = $.fn.zTree.getZTreeObj("tree"); var levelChildren = getLastLevelChildren(treeObj, treeNode); if (levelChildren.length > 0) { var collegeId = levelChildren[0].id; switch (treeNode.level) { case 0: $("#schoolId").val(null); $("#collegeId").val(null); break; case 1: $("#schoolId").val(treeNode.id); $("#collegeId").val(collegeId); break; case 2: $("#schoolId").val(null); $("#collegeId").val(treeNode.id); break; } }else { switch (treeNode.level) { case 0, 1: $.modal.alert("此大学下面还没有学院,不能添加教师") break; } } $.table.search(); } } function getLastLevelChildren(treeObj, node) { var level4Nodes = []; function findLevel4Children(currentNode, currentLevel) { if (currentLevel == 2) { level4Nodes = level4Nodes.concat(currentNode || []); } else if (currentNode.children) { currentNode.children.forEach(function (childNode) { findLevel4Children(childNode, currentLevel + 1); }); } } findLevel4Children(node, node.level); return level4Nodes; } $('#btnExpand').click(function () { $._tree.expandAll(true); $(this).hide(); $('#btnCollapse').show(); }); $('#btnCollapse').click(function () { $._tree.expandAll(false); $(this).hide(); $('#btnExpand').show(); }); $('#btnRefresh').click(function () { queryOrganizationTree(); }); /** * 重置密码 */ function resetPassword(btn) { $.modal.confirm("确定重置密码吗?", function () { $.modal.disable(); var url = prefix + "/resetPassword/" + $(btn).attr("rowid"); var data = {"id": $(btn).attr("rowid")}; var config = { url: url, type: "get", dataType: "json", data: "", beforeSend: function () { $.modal.loading("正在处理中,请稍候..."); }, success: function (data) { if (data.code == 0) { // 成功 $.modal.closeLoading(); $.modal.alert("密码已重置为:" + $("#operation" + $(btn).attr("rowid")).attr("rowaccount") + "@tea"); $.modal.disable(); } else { // 失败 $.modal.closeLoading(); $.modal.msgError(data.msg); $.modal.disable(); } } }; $.ajax(config) }); } /** * 删除 */ function remove(btn) { $.operate.remove($(btn).attr("rowid")); // $.table.search(); } /** * 编辑 */ function edit(btn) { $.operate.edit($(btn).attr("rowid")); } function power(btn) { let teacherId = $(btn).attr("rowid") let url = prefix + "/power/" + teacherId; $.modal.open("修改教师权限", url, '800', '400'); } /** * 回车查询 */ $("#selectConditionOneInput").keydown(function (e) { if (e.keyCode == 13) { $.table.search(); } }); $("#selectConditionTwoInput").keydown(function (e) { if (e.keyCode == 13) { $.table.search(); } }); /** * 文件上传 */ function importExcel(){ top.layer.open({ type: 1, area: [400 + 'px', 230 + 'px'], fix: false, //不固定 maxmin: true, shade: 0.3, title: '导入' + table.options.modalName + '数据', content: '<form enctype="multipart/form-data" class="mt20 mb10">\n' + ' <div class="col-xs-offset-1">\n' + ' <input type="file" id="file" name="file"/>\n' + ' <input class="hidden" type="text" id="importCollegeId" name="collegeId"/>\n' + ' <font color="red" class="pull-left mt10">\n' + ' 提示:仅允许导入“xls”或“xlsx”格式文件!\n' + ' </font>\n' + ' </div>\n' + ' </form>', btn: ['<i class="fa fa-check"></i> 导入', '<i class="fa fa-remove"></i> 取消'], // 弹层外区域关闭 shadeClose: true, btn1: function(index, layero){ var file = layero.find('#file').val(); layero.find('#importCollegeId').val($("#collegeId").val()); if (file == '' || (!$.common.endWith(file, '.xls') && !$.common.endWith(file, '.xlsx'))){ $.modal.msgWarning("请选择后缀为 “xls”或“xlsx”的文件。"); return false; } var index = top.layer.load(2, {shade: false}); $.modal.disable(); var formData = new FormData(layero.find('form')[0]); $.ajax({ url: table.options.importUrl, data: formData, cache: false, contentType: false, processData: false, type: 'POST', success: function (result) { if (result.code == web_status.SUCCESS) { $.modal.close(index); $.modal.closeAll(); $.modal.alertSuccess(result.msg); $.table.refresh(); } else if (result.code == web_status.WARNING) { $.modal.close(index); $.modal.enable(); $.modal.alertWarning(result.msg) } else { $.modal.close(index); $.modal.enable(); $.modal.alertError(result.msg); } }, complete: function () { layero.find('#file').val(''); } }); } }); } // 批量更新密码 function batchUpdatePwd() { var rows = $.table.selectColumns("id"); if (rows.length === 0) { $.modal.alertWarning("请选择用户"); return; } console.log(rows) //var initPwd = [[${@config.getKey('sys.user.initPassword')}]] layer.prompt({ formType: 0, title: '请输入重置密码', placeholder: '请输入重置密码', maxlength: 16, move: false, value: null //area: ['800px', '350px'] //自定义文本域宽高 }, function(value, index, elem){ if (value.length < 2){ $.modal.msgError("请输入正确格式的密码") return } $.modal.confirm("确认重置选中的"+ rows.length +"位教师密码?", function() { $.ajax({ type: 'patch', url: ctx + "system/teacher/resetPassword", dataType: 'json', data:{ ids:rows.join(), pwd: value }, success: function (result) { if (result.code === web_status.SUCCESS) { $.modal.msgSuccess("重置成功"); } else { $.modal.msgError("重置失败"); } }, error: function () { $.modal.msgError("重置失败"); } }); }); layer.close(index); }); } </script> </body> </html> 用vue语言重写这个页面,保持原有的功能和逻辑不变
07-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值