在上一节用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来实现吧。
增删改查的功能实现到这里就基本完成了,下面加几个功能界面,作为本节的结束吧。