在上一节用dataTable实现数据列表时,已经加了表头工具栏和表内工具栏,栏内的按钮功能都是用来完成数据的增删改查了,这又分成两类功能,一类是删除或设置,这类功能简单,只需要选定记录,然后提交到后端服务进行特定字段的修改即可,另一类是查明细、增加、修改记录,这三类功能,都需要生成一个新的数据编辑界面完成记录全内容的展示,然后输入相应的字段值,提交到后端服务进行相应的数据更新操作,同时,在录入和提交时,还需要对录入字段值进行合规检查。

       编辑功能的前端录入界面是采用layUI-form来实现的,由数据列表界面进入编辑录入界面的方式可以有多种,标准做法是在列表中选定记录后直接跳转到编辑页面,但我还是喜欢用layUI-layer弹出层功能来展示编辑界面,这样列表和编辑界面同时存在,控制上可以做出多种变化,比如编辑界面选择full模式,从外观看就可跳转实现是完全一样的。

       增删改查编辑功能的实现包括三部分,即列表页面下的JS控制实现、编辑页面的实现和后端编辑服务程序的实现,下面一个个列出来。

       第一个 member_list.html.j2,列表页面下的JavaScript实现,实际就是在上一节数据列表的基础上,加入各个按钮的处理实现,其代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>会员管理</title>
    <link rel="stylesheet" href="/static/layui/css/layui.css"  media="all">
</head>
<body>

<table id="table_list" lay-filter="table_list" style="margin-top:-15px;"></table>

<script type="text/html" id="toolBar">
    <div class="layui-btn-container">
        <div class="layui-inline">
            <label class="layui-btn-sm">会员名称:</label>
            <div class="layui-input-inline">
                <input type="text" id="searchtext" placeholder="请输入名称" autocomplete="off" class="layui-input layui-btn-sm">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline" style="padding-left:10px;padding-top:8px">
                <button id="btn_search" type="button" class="layui-btn layui-btn-normal layui-btn-sm" lay-event="search">
                    <i class="layui-icon layui-icon-search"></i>查询
                </button>
                <button id="btn_add" type="button" class="layui-btn layui-btn-sm" lay-event="add">
                    <i class="layui-icon layui-icon-add-1"></i>增加会员
                </button>
                <button id="btn_mban" type="button" class="layui-btn layui-btn-sm" lay-event="mban">
                    <i class="layui-icon layui-icon-lock"></i>批量封禁
                </button>
           </div>
        </div>
    </div>
</script>

<script type="text/html" id="linetoolBar">
    {% raw %}
    {{# if (d.status == 0 ) { }}
        <a lay-event="ban" title="封禁"><i class="layui-icon layui-icon-lock" style="color:red;"></i></a>
    {{# } if (d.status == 9) { }}
        <a lay-event="unban" title="解禁"><i class="layui-icon layui-icon-ok-circle" style="color:green;"></i></a>
    {{# } }}
    <a lay-event="edit" title="编辑" ><i class="layui-icon layui-icon-edit"></i></a>
    <a lay-envent="rsetpwd" title="重置密码"><i class="layui-icon layui-icon-password"></i></a>
    <a lay-event="del" title="删除"><i class="layui-icon layui-icon-delete" style="color:red;"></i></a>
    {% endraw %}

</script>
<script src="/static/layui/layui.js"></script>
<script>
layui.use(['jquery','layer','table'], function(){
	var layer=layui.layer
        ,$=layui.jquery
        ,table=layui.table;
    var cur_row;  	//初始化表格当前行
    var url_list = '{{url_for("sysadm.member_list")}}';
    var url_edit = '{{url_for("sysadm.member_edit")}}';

    table.render({
            elem: '#table_list'
            ,height: 'full'
            ,url: url_list
            ,toolbar: '#toolBar'
            ,method: 'POST'
            ,page: true //开启分页
            ,limits: [16, 20, 30, 40, 50]           
            ,limit : 16
            ,even : true
            ,size : 'sm'
            ,cols: [[ 
            { type: 'checkbox', fixed: 'left' }
            ,{field: 'id', title: 'ID', width:30, sort: true, fixed: 'left'}
            ,{field: 'username', title: '会员名', width:90, sort: true, fixed: 'left'}
            ,{field: 'nickname', title: '昵称', width:90, sort: true}
            ,{field: 'email', title: '邮箱', width:170, sort: true}
            ,{field: 'sex_name', title: '性别', width:60, sort: true}
            ,{field: 'telephone', title: '电话', width:100, sort: true}
            ,{field: 'role_note', title: '会员角色', width: 100}
            ,{field: 'status_name', title: '状态', width: 30}
            ,{field: 'agent', title: '推荐人', width: 70}
            ,{field: 'regtime', title: '注册时间', width:160} 
            ,{fixed: 'right', width:120, align:'center', toolbar: '#linetoolBar'}
            ]]
    });

    //表头工具栏事件
    table.on('toolbar(table_list)', function (obj) {
        let cpage = obj.config.page.curr;
        console.log(JSON.stringify(obj.config.page))

        switch (obj.event) {
            case 'search':
                table_refresh(1);
                break;
            case 'add':
                cur_row=null;
		        table_edit('add','新增',-1,cpage);
                break;
            case 'mban':
                table_mban(cpage);
                break;
        };
    });

    //table行内工具栏事件
    table.on('tool(table_list)', function (obj) {    //obj是指这张表中的数据
        cur_row = obj.data;
        rid = cur_row.id;
        let cpage = obj.config.page.curr;
        //obj.event:获取触发事件的元素的 event 值,用于区分不同的操作
        switch(obj.event) {
            case 'edit':
                table_edit('upd',"编辑",rid,cpage);
                break;
            case 'del':
                layer.confirm('确认删除会员吗?id:' + rid, {icon: 3, title:'提示'}, function(index){
                    $.post(url_edit + '?opr=del',{id:rid},function(rs){
                        if(rs.success){
                            //调用查询方法刷新数据
                            table_refresh(cpage);
                            layer.msg(rs.msg,function(){});
                        }else{
                            layer.msg(rs.msg,function(){});
                        }
                    },'json');
                    layer.close(index);
                });                
                break;
            case 'ban':
                layer.confirm('确认封禁会员吗?id:' + rid, {icon: 3, title:'提示'}, function(index){
                    $.post(url_edit + '?opr=ban',{id:rid},function(rs){
                        if(rs.success){
                            //调用查询方法刷新数据
                            table_refresh(cpage);
                            layer.msg(rs.msg,function(){});
                        }else{
                            layer.msg(rs.msg,function(){});
                        }
                    },'json');
                    layer.close(index);
                });                
                break;
            case 'unban':
                layer.confirm('确认解禁会员吗?id:' + rid, {icon: 3, title:'提示'}, function(index){
                    $.post(url_edit + '?opr=unban',{id:rid},function(rs){
                        if(rs.success){
                            //调用查询方法刷新数据
                            table_refresh(cpage);
                            layer.msg(rs.msg,function(){});
                        }else{
                            layer.msg(rs.msg,function(){});
                        }
                    },'json');
                    layer.close(index);
                });                
                break;
             case 'resetpwd':
                layer.confirm('确认重置口令吗?id:' + rid, {icon: 3, title:'提示'}, function(index){
                    $.post(url_edit + '?opr=resetpwd',{id:rid},function(rs){
                        if(rs.success){
                            layer.msg(rs.msg,function(){});
                        }else{
                            layer.msg(rs.msg,function(){});
                        }
                    },'json');
                    layer.close(index);
                });                
                break;

        }
    });

    function table_refresh(cpage) {
        table.reload('table_list', {
            where: {                           
                'searchtext':$('#searchtext').val()
            },  
            page: { curr: cpage },
        },true);
    }

    function table_mban(cpage) {
        var checkData = table.checkStatus('table_list').data; //得到选中的数据
        if (checkData.length === 0) {
            layer.msg('请选择数据');
            return false;
        }

        var idArr = [];
        for (var i = 0; i < checkData.length; i++) {
            idArr.push(checkData[i].id);
        }
        layer.confirm('确认批量封禁会员吗?', {icon: 3, title:'提示'}, function(index){
            $.post(url_edit + '?opr=mban',
                {id:idArr.join(',')},function(rs){
                if(rs.success){
                    //调用查询方法刷新数据
                    table_refresh(cpage);
                    layer.msg(rs.msg);
                }else{
                    layer.msg(rs.msg);
                }
            },'json');
            layer.close(index);
        });                
    }

    function table_edit(opr,title,rid,cpage){
        if (opr =='add') url = url_edit;
        else url = url_edit + '?id=' + rid;
        
        layer.open({
            type: 2, 
            title:title,
            area: ['660px', '460px'],
            skin: 'layui-layer-rim',    //样式类名
            content:  url, //编辑页面
            btn:['保存','关闭'],
            yes: function(index, layero){
                table_save(layero,url,opr,cpage);
            },
            btn3: function(index, layero){
                layer.closeAll();
            },
        });
    }

    function table_save(layero,url,opr,cpage) {
        var iframeWin = window[layero.find('iframe')[0]['name']];
        var vform = iframeWin.layui.form;
        //console.log('vform:' + JSON.stringify(vform));
        vform.submit('edit-form',function(data){
            console.log('data:' + JSON.stringify(data));
            $.post(url_edit + '?opr=' + opr,
                data.field,function(rs){
                if(rs.success){
                    layer.closeAll();
                    layer.msg(rs.msg,function(){});
                    table_refresh(cpage);
                }else{
                    layer.msg(rs.msg,function(){});
                }
            },'json');
        });

/*
        var iframeWin = window[layero.find('iframe')[0]['name']];
        var formData = iframeWin.layui.form.val("edit-form");
        //console.log('formData:' + JSON.stringify(formData));

        $.post(url_edit + '?opr=' + opr,formData,function(rs){
            if(rs.success){
                layer.closeAll();
                layer.msg(rs.msg,function(){});
                table_refresh(cpage);
            }else{
                layer.msg(rs.msg,function(){});
            }
        },'json');
*/
    }

});

</script>
</body>
</html>

       这个HTML+JS列表页面,除了数据列表的渲染外,还加入了表头工具栏和行内工具栏的处理程序,表头工具栏主要包括查询、增加和批量删除,行内工具栏包括编辑、删除和重置口令、封禁/解封两个状态设置功能,展示界面如下图:

        JavaScript部分,在table.render()主函数下的两个table.on是编辑功能的总入口,table.on(toolbar(table_list))用以完成表头工具栏的功能实现,table.on(tool(table_list))实现行内工具栏的功能。

        function(obj)的入口参数obj内包含当前选中的记录信息以及table的各种参数信息,可以用console.log()打印出来进行分析,分页控制参数page和limit也在里面有。对前端界面来说,最重要的参数是当前记录的id值,以及当前页数。ID值是编辑功能的记录索引,在编辑程序的每一部分都会用到,当前页数,则用于前端更新完成后的页面刷新,如果这个参数取不到,那每次刷新都会重置到列表第一页,可以说,十分不友好。

       删除以及状态设置功能都不需要录入数据,直接确认后提交到后台服务端即可,编辑功能则统一由table_edit()函数实现,本功能里包括新增和更改功能,实际还有查询明细功能,都是用layer.open打开编辑页面进行记录数据录入。编辑页面程序member_edit.html.j2内容如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>会员编辑</title>
<link rel="stylesheet" href="/static/layui/css/layui.css"  media="all">
</head>
<style>
.layui-form-select dl{
	max-height:150px;
}
</style>
<body>
<div style="padding:10px;">
    <form class="layui-form" lay-filter="edit-form" action="">
        <input type="hidden" id="id" name="id"/>
        <div class="layui-form-item">
            <div class="layui-inline" style="width:47%">
                <label class="layui-form-label required">用户名</label>
                <div class="layui-input-block">
                    <input class="layui-input" id="username" name="username" value="" placeholder="6-15位字母或数字" autocomplete="off"
                        lay-verType="tips" lay-verify="required|username" required/>
                </div>
            </div>
            <div class="layui-inline" style="width:47%">
                <label class="layui-form-label">昵称</label>
                <div class="layui-input-block">
                    <input class="layui-input" id="nickname" name="nickname" value="" placeholder="" autocomplete="off"
                        lay-verType="tips" lay-verify="required" required/>
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-inline" style="width:47%">
                <label class="layui-form-label required">邮箱</label>
                <div class="layui-input-block">
                    <input class="layui-input" id="email" name="email" value="" placeholder="例如:123@123.com" type="email"
                        lay-verType="tips" lay-verify="required|email" required/>
                </div>
            </div>
            <div class="layui-inline" style="width:47%">
                <label class="layui-form-label">电话</label>
                <div class="layui-input-block">
                    <input class="layui-input" id="telephone" name="telephone" value="" placeholder="例如:13999999999" type="tel"
                        lay-verType="tips" lay-verify="required|phone" required/>
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">性别</label>
            <div class="layui-input-block">
                <input type="radio" name="sex" value="1" title="男" checked>
                <input type="radio" name="sex" value="2" title="女"> 
                <input type="radio" name="sex" value="0" title="无" >
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-inline" style="width:47%">
                <label class="layui-form-label">类别</label>
                <div class="layui-input-block">
                    <select name="role_cd">
                        <option value="">---请选择---</option>
                    </select>
                </div>
            </div>
            <div class="layui-inline" style="width:47%">
                <label class="layui-form-label">状态</label>
                <div class="layui-input-block">
                    <select name="status">
                        <option value="">---请选择---</option>
                    </select>
                </div>
            </div>

        </div>
    </form>
</div>
<script src="/static/layui/layui.js"></script>
<script>
layui.use(['layer','form','jquery'],function(){
	var $=layui.jquery,
    layer=layui.layer,
	form=layui.form;

		form.verify({
			username: function(value, elem){
				if (!new RegExp("^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$").test(value)) {
					return '用户名不能有特殊字符';
				}
				if (/(^_)|(__)|(_+$)/.test(value)) {
					return '用户名首尾不能出现下划线';
				}
				if (/^\d+$/.test(value)) {
					return '用户名不能全为数字';
				}
			},
		});

    initDimension();
    initFormData();

    //由UID从服务器数据库中取出数据作为原始数据
    function initFormData(){
        rscode = null;
        {% if rsdata %}
            rscode = {{ rsdata.success }};
            var rsmsg = '{{ rsdata.msg | safe }}';
            var rsdata = {{ rsdata.data | tojson}};
            if (rscode != null) {
                console.log('rsdata:' + JSON.stringify(rsdata));
                //form.val('edit-form',$.extend({}, rsdata||{}));//将父页面传递的行数据赋值到表单中
                form.val('edit-form',rsdata);
            }
        {% endif %}
    }

    //由后台取出选项条目数据对选项进行动态刷新
    function initDimension() {
        {% if rsdim %}
            var status_dim = {{ rsdim.status_dim | safe }};
            var role_dim = {{ rsdim.role_dim | safe }};

            if (status_dim != null) set_select_option(status_dim,'status');
            if (role_dim != null) set_select_option(role_dim,'role_cd');
            form.render('select'); 
            //set_select_disable('parent_id');
        {% endif %}
    }

    //设置select中的选项条目
    function set_select_option(select_dim,sname) {

        var $select = $('[name="'+ sname + '"]');
  
        $select.empty();
        for (var i = 0; i<select_dim.length; i++ ) {
            option_item = select_dim[i];
            $select.append($('<option>').text(option_item[0] + '_' + option_item[1]).attr('value', option_item[0]));
        }
    }

    //设置select中的树型选项条目
    function set_select_tree(select_dim,sname) {

        var $select = $('[name="'+ sname + '"]');
  
        $select.empty();

        $select.append($('<option>').text('根结点_0').attr('value', 0));
        for (var i = 0; i<select_dim.length; i++ ) {
            option_item = select_dim[i];
            let level = option_item[3];
            let lstr ='├' + '─'.repeat(level)

            $select.append($('<option>').text(lstr + option_item[1] + '_' + option_item[0]).attr('value', option_item[0]));
        }
    }

    function set_select_disable(sname) {
        var $select = $('[name="'+ sname + '"]');
        $select.attr('disabled','disabled');
    }

});

</script>
</body>
</html>

       编辑页面程序的HTML页面部分,主要是一个layui-form表单的配置,在表单定义项里必须定义layui-filter作为表单的唯一标识字,在提交后的处理中都用此标识作为索引。表单输入项的具体配置规则不再多说,这里主要强调一下校验规则。

       实际上表单的校验包括了两种,一种是HTML5自带的校验,比如通过type的设置也可以对数字、密码和电话号码进行检验,必输项可以通过设置required属性进行校验。第二种校验是layui提供的校验功能,通过设置layui-verify和layui-verType来实现校验和校验信息展示。不过这些校验功能都必须由表内submit提交时才有效,采用layer.open()的btn提交时都是无效的。

        如何既用弹出页打开编辑界面并用btn提交,同时又让校验规则生效,在开发手记第二节中已经讲过了,不过用form.submit() 提交只能激活layui自带的校验功能,html5的校验仍然无效,当然,layUI的校验已经对html5的校验形成了全覆盖,所以有这一个生效也够了。

PS:在member_list.html.j2最后有一段注释掉的js程序,是不用form.submit()提交的原始程序,这种模式下校验是无效的,好在,新改的程序,不需要后台服务端做任何修改。       

        var iframeWin = window[layero.find('iframe')[0]['name']];
        var formData = iframeWin.layui.form.val("edit-form");
        //console.log('formData:' + JSON.stringify(formData));
        $.post(url_edit + '?opr=' + opr,formData,function(rs){
            if(rs.success){
                layer.closeAll();
                layer.msg(rs.msg,function(){});
                table_refresh(cpage);
            }else{
                layer.msg(rs.msg,function(){});
            }
        },'json');

        编辑页面程序的JS部分主要是完成页面的初始化工作,包括三部分,一、form.verify()用于设置输入自定义校验规则,二、initDimension()完成对选择项的初始化,三、initFormData完成对输入域初值的初始化工作。

      关于校验,layui本身提供了required必输项校验和六种格式校验(包括phone手机号、email邮箱、url网址、number数字、date日期、identity身份证),这些校验项定义在lay-verify属性里。要注意的是,required和格式校验是并存关系,也就是说如果不设必填约束,那么输入为空时是不进行格式校验的。

       当然,如果是复杂的校验,就需要进行规则自定义了,form.verify()函数中可以自定义各种校验函数,通过正则表达式可以完成所有想要的校验。layui的校验功能足够完备,基本上可以取消后端的普遍校验了,这也解决了俺的一个大问题,就是弹出层模式下,不单前端检验无效,后端基于form类的校验也失效了,现在看,真也不需要恢复了。当然,涉及到数据的验证还是要在后端服务里实现,但那已经属于处理流程的一部分了。

       校验设置上,还有一个lay-verType设置是显示信息方式,不设置这个属性缺省是msg模式,不过我更喜欢tips模式。但似乎这个项是要求每一个输入域都设置,不知道有没有在form项上的统一设置功能。

        第二个,选择项的选项初始化,是编辑界面实现的第二个功能,以前见别人写过的程序,对于选择项,是后台程序里定义一个,前端表单里定义一个,甚至后台数据库里还有一个,只要有改变,就得三个地方改。我是十分不喜欢这种编程风格的,数据就应该只有一个出处,一处修改其它地方自动更新。这块的实现就是由后端生成选项数据,然后传到前端来动态刷新选项。

        选择项的初始化,包括普通select的初始化外,还包括自定义的layui-Tree树型组件的初始化。这块有一个坑,就是按html页面约定只修改option项是无效的,layui的选择域实际上是根据select/option又生成了一个显示层,这个渲染是在页面装入时就做的。所以,初始完option后,必须要用form.render('select')刷新一下才能更新layui新生成的元素。

        第三个是输入域初值的初始化,新增功能是没有初值的,所以这块用不到,编辑和显示明细时都需要对输入域的value值进行初始化。记录的初值提取也有两种模式来实现,一是用列表主页面的数据带过来,也就是table.on里的obj.data的数据作为源,二是到服务端用id重新在数据库里读取记录数据。我觉得第二种更合适一些,毕竟列表界面的数据和实际数据库数据可能出现不一致的情况。并且对于flask,似乎也不支持直接页面跳转,横竖都要到后端走一遭,不如顺带读取一下数据,反正按主键id读取记录也不怎么耗资源。

       将数据初始化到表单里用的是form.val()来实现的。这块也有一个坑,就是特定元素,实际上也有一个同样的函数,比如$('#email‘).val()也可以实现value值的初始化,但千万不要这么用,这个函数是jquery提供的,虽然在layui中javascript原生函数、jquery函数和layUI-API可以混用,但在某些地方还真有些区别,比如这个初始化赋值,无论是整体表单赋值还是单个输入域赋值,都要用form.val()来做。

       特别指出一下,别的类型的输入项用elem.val()也没啥问题,就是radio单选项的初值设定,用元素操作设置checked属性是不生效的,必须用form.val()才行。 

       前端的实现基本完成了,下面就是后端服务的实现,这块无论是增删改查,我都集成一个函数入口中完成。这种模式可能在权限管理上有些问题,不过集中控制分支实现一直是我喜欢的编程模式,这样可以在总入口程序中统一处理一些校验功能。后端服务程序如下:

@bp.route('/member_edit/',methods=['GET','POST'])
@login_required
def member_edit():
    if request.method == 'GET':
        udim = {
            'status_dim': json.dumps(Member_Status().get_list()),
            'role_dim' : json.dumps(Member_Role().get_list())
        }
        uid= request.values.get('id')
        if uid == None:
            return render_template('admin/member_edit.html.j2',rsdim=udim)
        else:
            irow= db.session.query(Members).filter_by(uid=uid).first()
            udata = dict(id=irow.uid,username=irow.username,email=irow.email,avatar=irow.avatar,
                        nickname=irow.nickname,sex=irow.sex,telephone=irow.telephone,agent=irow.agent,
                        regtime=irow.regtime.strftime('%Y-%m-%d %H:%M:%S'),
                        status=irow.status,role_cd=irow.role_cd)
            rsdata = {
                "success": 1,
                "msg": "取会员数据成功",
                "data":udata
            }
            return render_template('admin/member_edit.html.j2',rsdata=rsdata,rsdim=udim)
    else :
        opr = request.values.get('opr')
        logging.debug('oprmode: ' + opr)
        uid = request.values.get('id')
        try : 
            if opr == 'add' :
                rs_data = member_add()
            elif opr == 'upd' :
                rs_data = member_update(uid)
            elif opr == 'del' :
                rs_data = member_delete(uid)
            elif opr == 'ban' :
                rs_data = member_ban(uid)
            elif opr == 'unban' :
                rs_data = member_unban(uid)
            elif opr == 'mban' :
                rs_data = member_mban(uid)
            else :
                rs_data = member_reset_passwd(uid)
        except SQLAlchemyError as e:
            db.session.rollback()
            rs_data = {
                'success':0,
                'msg':'更新会员记录失败:' + str(e.orig),
                'status':200
            }
        return json.dumps(rs_data)

#新增操作员    
def member_add():
    logging.debug('Add Member ....')
    username = request.values.get('username')
    nickname = request.values.get('nickname')
    email = request.values.get('email')
    telephone = request.values.get('telephone')
    avatar = request.values.get('avatar')
    role_cd = request.values.get('role_cd')
    sex = request.values.get('sex')
    status = request.values.get('status')
    rawpass = config.PASSWORD_INITIAL
    useradd = Members(username=username,password=rawpass,email=email,status=status,sex=sex,
                      role_cd=role_cd,nickname=nickname,telephone=telephone,avatar=avatar)
    useradd.password=rawpass
    db.session.add(useradd)
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'增加会员成功',
        'status':200
    }
    return rs_data

#修改操作员
def member_update(uid):
    logging.debug('Update Member %s....' % uid)

    irow= db.session.query(Members).filter_by(uid=uid).first()
    irow.username = request.values.get('username')
    irow.nickname = request.values.get('nickname')
    irow.email = request.values.get('email')
    irow.telephone = request.values.get('telephone')
    irow.avatar = request.values.get('avatar')
    irow.sex = request.values.get('sex')
    irow.role_cd = request.values.get('role_cd')
    irow.status = request.values.get('status')
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'修改会员信息成功' + uid,
        'status':200
    }
    return rs_data

#删除会员
def member_delete(uid):
    logging.debug('Member del ' + uid)
    irow= db.session.query(Members).filter_by(uid=uid).first()
    db.session.delete(irow)
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'删除会员成功' + uid,
        'status':200
    }
    return rs_data

#批量删除会员==保留
def member_mdelete(ridstr):
    logging.debug('Member muli delete ' + ridstr)
    ridlist = list(map(int,ridstr.split(',')))
    logging.debug('Ban %s...' % str(ridlist))
    rows = db.session.query(Members).filter(Members.uid.in_(ridlist)).all()
    for irow in rows:
        db.session.delete(irow)
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'删除会员成功' + ridstr,
        'status':200
    }
    return rs_data

def member_reset_passwd(uid):
    logging.debug('Member reset password ' + uid)
    irow= db.session.query(Members).filter_by(uid=uid).first()
    irow.password = config.PASSWORD_INITIAL
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'重置会员密码成功' + uid,
        'status':200
    }
    return rs_data

#封禁会员
def member_ban(rid):
    logging.debug('Member ban ' + rid)
    db.session.query(Members).filter_by(uid=rid).update({Members.status:9})
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'封禁会员成功' + rid,
        'status':200
    }
    return rs_data

#封禁会员
def member_unban(rid):
    logging.debug('Member ban ' + rid)
    db.session.query(Members).filter_by(uid=rid).update({Members.status:0})
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'解禁会员成功' + rid,
        'status':200
    }
    return rs_data

#批量封禁会员
def member_mban(ridstr):
    logging.debug('Member muli ban ' + ridstr)
    ridlist = list(map(int,ridstr.split(',')))
    logging.debug('Ban %s...' % str(ridlist))
    rows = db.session.query(Members).filter(Members.uid.in_(ridlist)).all()
    for irow in rows:
        irow.status = 9
    db.session.commit()
    rs_data = {
        'success':1,
        'msg':'批量封禁会员成功' + ridstr,
        'status':200
    }
    return rs_data

       后端服务入口的路由命名为"member_edit",分为GET和POST两部分,GET部分对应layer.open()打开页面部分的页面和数据准备,包括代码维信息的准备以及编辑记录数据的准备,作为返回数据的两部分随页面渲染功能下传。

       POST部分对应列表页面js处理中的各类post()请求,根据post请求的opr来区分功能进入各自的数据处理函数,包括增加、更改、删除这些基础功能,也包括各种业务处理。这部分程序简单,就不再深入展开阐述了。

       应该说,写到这块,有一个最深切的对python的期盼,就是希望python能够实现switch功能,这许多的功能分支,用if-elif-else简直太LOW了。查了一下,python 3.10版本之后已经提供了类switch分支的语法,叫match,不过,既然这个功能提供不久,为了稳定性,还是先用if-else来实现吧。

       增删改查的功能实现到这里就基本完成了,下面加几个功能界面,作为本节的结束吧。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部