架构图
表结构设计
同样还是和之前的表结构类似:
CREATE TABLE `member` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`nickname` varchar(100) NOT NULL DEFAULT '' COMMENT '会员名',
`mobile` varchar(11) NOT NULL DEFAULT '' COMMENT '会员手机号码',
`sex` tinyint(1) NOT NULL DEFAULT '0' COMMENT '性别 1:男 2:女',
`avatar` varchar(200) NOT NULL DEFAULT '' COMMENT '会员头像',
`salt` varchar(32) NOT NULL DEFAULT '' COMMENT '随机salt',
`reg_ip` varchar(100) NOT NULL DEFAULT '' COMMENT '注册ip',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1:有效 0:无效',
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后一次更新时间',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '插入时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员表';
然后我们可以对上述表中的某些字段具体文字化,使用property方法:
"""
虚拟字段status_desc和sex_desc,在前端展示时可以将字符转换成文字
"""
@property
def status_desc(self):
return app.config['STATUS_MAPPING'][ str( self.status ) ]
@property
def sex_desc(self):
sex_mapping = {
"0":"未知",
"1":"男",
"2":"女"
}
return sex_mapping[str(self.sex)]
代码书写
关于本篇web中的member.py文件中,后端需要确定的是四个接口,分别为:
# -*- coding: utf-8 -*-
from flask import Blueprint,render_template
route_member = Blueprint( 'member_page',__name__ )
@route_member.route( "/index" )
def index():
return render_template( "member/index.html" )
@route_member.route( "/info" )
def info():
return render_template( "member/info.html" )
@route_member.route( "/set" )
def set():
return render_template( "member/set.html" )
@route_member.route( "/comment" )
def comment():
return render_template( "member/comment.html" )
然后我们首先来写index展示页面,这个接口的功能很明显,和当时用户管理模块中的index一样,是需要将会员的信息展示出来,跟之前一样,我们先将该文件的蓝图在www中注册,然后在导入文件下面加入定义,就能开始写接口代码,代码为:
@route_member.route( "/index" )
def index():
resp_data = {}
req = request.values
page = int(req["p"]) if ("p" in req and req["p"]) else 1
query = Member.query # 拿到Member这个对象
if 'status' in req and int( req['status'] ) > -1 : # 对选项框有进行操作,-1位默认值
query = query.filter( Member.status == int( req['status'] ) )
page_params = {
"total": query.count(), # 查询总数量
"page_size": app.config["PAGE_SIZE"], # 当前每页分页大小
"page": page, # 第几页
"display": app.config["PAGE_DISPLAY"], # 展示页数
'url': request.full_path.replace("&p={}".format(page),"")
}
pages = iPagination(page_params) # 统一分页封装类
offset = (page - 1) * app.config["PAGE_SIZE"] # 偏移量
list = query.order_by(Member.id.desc() ).offset(offset).limit() # 结果集
resp_data["list"] = list # 循环数据
resp_data["pages"] = pages # 分页数据
resp_data['status_mapping'] = app.config['STATUS_MAPPING'] # 搜索框状态
resp_data['current'] = 'index'
return ops_render( "member/index.html",resp_data )
这里需要注意到的是分页功能,因为分页这个函数是我们在Helper中自定义的,所以该有和参数和account一样不能少,写完了后端后,我们就根据后端传过来的json修改前端模板,首先是HTML的一些地方:
<tbody>
{% if list %}
{% for item in list %}
<tr>
<td><img alt="image" class="img-circle" src="{{ item.avatar }}" style="width: 40px;height: 40px;"></td>
<td>{{ item.nickname }}</td>
<td>{{ item.sex_desc }}</td>
<td>{{ item.status_desc }}</td>
<td>
<a href="{{ buildUrl('/member/info') }}?id={{ item.id }}">
<i class="fa fa-eye fa-lg"></i>
</a>
{% if item.status == 1 %}
<a class="m-l" href="{{ buildUrl('/member/set') }}?id={{ item.id }}">
<i class="fa fa-edit fa-lg"></i>
</a>
<a class="m-l remove" href="javascript:void(0);" data="{{ item.id }}">
<i class="fa fa-trash fa-lg"></i>
</a>
{% else %}
<a class="m-l recover" href="javascript:void(0);" data="{{ item.id }}">
<i class="fa fa-rotate-left fa-lg"></i>
</a>
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
<tr><td colspan="5">暂无数据</td></tr>
{% endif %}
</tbody>
另外还需要修改选项框中的数据更改项,以保证选择任何一个选项都能实时更新数据:
<select name="status" class="form-control inline">
<option value="-1">请选择状态</option>
{% for tmp_key in status_mapping %}
<option value="{{ tmp_key }}" {% if tmp_key == search_con['status'] %} selected {% endif %}>{{ status_mapping[ tmp_key ] }}</option>
{% endfor %}
</select>
另外关于Member的JavaScript文件,因为基本上功能和account的index.js重复,我们可以直接复制过来改一下绑定的标签就能直接用了,最后启动便能看到演示效果:
其它功能基本就是类似于第二篇中后台账号管理的接口功能,因为晚上网速有点卡,另外又是跨年了,所以就先到这里,之后回来补。