RBAC模型
一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。【今天写其中的一种】
1.权限【Authority】
页面示例:
权限数据库字段设计如下【可根据需要自行添加】:
CREATE TABLE `authority` (
`auth_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '权限id',
`auth_name` varchar(20) NOT NULL COMMENT '权限名称',
`auth_pid` int(10) unsigned NOT NULL COMMENT '权限父级名称',
`auth_c` varchar(255) NOT NULL COMMENT '控制器名',
`auth_a` varchar(255) NOT NULL COMMENT '方法名',
`auth_path` varchar(255) NOT NULL COMMENT '全路径',
`is_show` tinyint(1) NOT NULL COMMENT '是否显示',
`auth_ico` varchar(50) NOT NULL,
`auth_sort` smallint(3) NOT NULL DEFAULT '999' COMMENT '排序',
`add_time` int(11) DEFAULT NULL,
`update_time` int(11) DEFAULT NULL,
PRIMARY KEY (`auth_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=228 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='权限表';
PHP代码部分如下:
1.封装一个公共的无限极:
public function getTree($array, $pid=0, $level=0)
{
//声明静态数组,避免递归调用时,多次声明导致数组覆盖
static $list = [];
foreach ($array as $key => $value){
//第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点
if ($value['mg_pid'] == $pid){
//父节点为根节点的节点,级别为0,也就是第一级
$value['level'] = $level;
//把数组放到list中
$list[] = $value;
//把这个节点从数组中移除,减少后续递归消耗
unset($array[$key]);
$this->getTree($array, $value['mg_id'], $level+1);
}
}
return $list;
}
2. 取出所有权限表中所有数据重组
//重组数组加上等级
public function authorityListApi()
{
$common=new Common; //实例化common 控制器
$list = \db('authority')->order('auth_path desc')->select();
$pageList = $common->getTree($list); //递归调用
return json_encode(array('code'=>0, 'data' => $pageList));
}
//渲染视图
public function showList()
{
return $this->fetch('index');
}
前端代码部分
1.这里用的是layui前端框架
①html部分
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-header"></div>
<div class="layui-card-body">
<script type="text/html" id="test-table-toolbar-toolbarDemo">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="add"><i class="layui-icon"></i>增加权限</button>
</div>
</script>
<table class="layui-hide" id="test-table-page" lay-filter="test-table-page"></table>
<script type="text/html" id="authGz">
{{ d.auth_c }}/{{ d.auth_a }}
</script>
<script type="text/html" id="authId">
{{ d.auth_path }}
</script>
<script type="text/html" id="icon">
<i class="layui-icon {{ d.auth_ico }}"> {{ d.auth_ico }}</i>
</script>
<script type="text/html" id="test-table-switchTpl">
<input type="checkbox" name="type" lay-skin="switch" lay-text="显示|隐藏" lay-filter="test-table-sexDemo" value="{{ d.auth_id }}" {{ d.is_show == 1 ? 'checked' : '' }}>
</script>
<script type="text/html" id="table-useradmin-admin">
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit" dataid="{{ d.id }}"></i>编辑</a>
</script>
</div>
</div>
</div>
</div>
</div>
②script部分
table.render({
elem: '#test-table-page'
,url: '/authorityListApi'
,toolbar: '#test-table-toolbar-toolbarDemo'
,cols: [[
{field:'auth_id', title:'ID', width:80, sort: true}
,{field:'cate_name', title:'权限名称(用于展示左侧栏)'}
,{field:'', title:'权限路径',templet:'#authGz'}
,{field:'', title:'权限编号',templet:'#authId'}
,{field:'', title:'图标',templet:'#icon'}
,{field:'is_show', title:'是否显示',templet:'#test-table-switchTpl'}
,{title: '操作', width: 80, fixed: 'right', toolbar: '#table-useradmin-admin'}
]],
done:function (res,curr,count) {
var data =res.data;
$("th").css({'color':'black'});
for (var i in data) {
$("tr[data-index='" + i+ "']").attr('cate-id',data[i].auth_id);
$("tr[data-index='" + i+ "']").attr('pid',data[i].auth_pid);
$("tr[data-index='" + i+ "']").attr('data-name',data[i].auth_name);
$("tr[data-index='" + i+ "']").attr('level',data[i].level);
if (data[i].auth_pid==0){
$("tr[data-index='" + i+ "']").find("td[data-field='cate_name']").children().html('<i class="layui-icon x-show"></i>' + data[i].auth_name);
}
}
$("tbody tr[pid!='0']").hide();
}
});
角色【Role】
页面示例
角色数据库字段设计如下【可根据需要自行添加】:
CREATE TABLE `role` (
`role_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '角色id',
`role_name` varchar(50) NOT NULL COMMENT '角色名称',
`role_auth_ids` text NOT NULL COMMENT '角色具有权限的id组合,1,2,3',
`role_auth_ac` text COMMENT '权限的控制器和方法的组合,格式:控制器-方法',
`role_auth_name` text,
`role_des` varchar(500) NOT NULL COMMENT '描述',
`role_status` tinyint(1) DEFAULT '0' COMMENT '0:有效,1:禁用,2:删除',
`add_time` int(11) DEFAULT NULL,
`update_time` int(11) DEFAULT NULL,
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色表';
PHP代码部分如下:
//渲染视图
public function showList()
{
return $this->fetch('index');
}
//渲染数据
public function showListApi()
{
$roleList = db('sw_role')->field("*,FROM_UNIXTIME(add_time,'%Y-%m-%d %H:%i') as add_time")->select();
return json_encode(array('code'=>0, 'data' => $roleList));
}
//添加提交
public function addRoleApi()
{
$data = request()->param();
$roleIds = implode(',', $data['role_auth_ids']);
$authList = db('sw_authority')->where("auth_id IN ({$roleIds})")->select(); //所有选中的数据
$authName = array_column($authList,'auth_name');
$roleName = db('sw_role')->where("role_name = '{$data['role_name']}'")->find(); //查询角色名称
$ownRoleIds = db('sw_role')->where("role_auth_ids = '{$roleIds}'")->find(); //查询角色已经存在的权限ID
if ($roleName){
ajax_return(array('status'=>'error','msg'=>'角色名称已经存在!'));
}
if ($ownRoleIds){
ajax_return(array('status'=>'error','msg'=>'当前权限与“'. $ownRoleIds['role_name'] .'”完全相同'));
}
$temp = [];
foreach ($authList as $value) {
//判断选中的pid不等于0的
if ($value['auth_pid'] != 0) {
$temp[] = $value['auth_c']. '-' . $value['auth_a']; //拼接控制器+方法名
}
}
$roleAuthAc = implode(',', $temp);
$roleData = [
'role_name' => $data['role_name'],
'role_auth_ids' => $roleIds,
'role_auth_name' => implode(',', $authName),
'role_des' => $data['role_des'],
'role_auth_ac' => $roleAuthAc,
'role_status' => 0,
'add_time' => time()
];
if(db('sw_role')->insert($roleData)) {
return json_encode(array('status'=>'success','msg'=>'添加成功!', 'url' => 'roleShowList'));
} else {
return json_encode(array('status'=>'error','msg'=>'添加失败!'));
}
}
//封装一个方法用于无限极角色回显【修改时用】
public function procHtml($menus)
{
$newArr = [];
if(is_array($menus)) {
$i = 0;
foreach ($menus as $k => $t) {
if ($t['auth_pid'] == 0) {
if (!empty($t['checked'])){
$newArr[$i]['checked'] = 'true';
}
$newArr[$i]['name'] = $t['auth_name'];
$newArr[$i]['value'] = $t['auth_id'];
if (!empty(!empty($t['trees']))){
if (!empty($t['checked'])){
$newArr[$i]['checked'] = 'true';
}
$newArr[$i]['name'] = $t['auth_name'];
$newArr[$i]['value'] = $t['auth_id'];
$newArr[$i]['list'] =$this->procHtml($t['trees']);
}
} else {
if (!empty($t['trees'])){
if (!empty($t['checked'])){
$newArr[$i]['checked'] = 'true';
}
$newArr[$i]['name'] = $t['auth_name'];
$newArr[$i]['value'] = $t['auth_id'];
$newArr[$i]['list'] =$this->procHtml($t['trees']);
}else{
if (!empty($t['checked'])){
$newArr[$i]['checked'] = 'true';
}
$newArr[$i]['name'] = $t['auth_name'];
$newArr[$i]['value'] = $t['auth_id'];
}
}
$i++;
}
}
return $newArr;
}
//修改
public function updateSelectApi()
{
$data = request()->param();
//所有权限
$allList = db('sw_authority')->order('auth_sort DESC')->select();
//当前ID拥有权限
$ownAuthority = \db('sw_role')->where("role_id = {$data['roleId']}")->find();
$ownAuthorityList = db('sw_authority')->where("auth_id IN ({$ownAuthority['role_auth_ids']})")->order('auth_sort DESC')->select();
$newList = [];
foreach ($allList as $key => $value){
$newList[] = $value;
foreach ($ownAuthorityList as $k => $v){
if ($value['auth_id'] == $v['auth_id']){
$newList[$key]['checked'] = 'true';
}
}
}
$menus = $this->getTree($newList,0,1);
$list = $this->procHtml($menus);
$newList =[
'code' => 0,
'msg' =>'获取成功',
'data' => [
'trees' => $list
]
];
return json_encode(array('code'=>0,'data'=>$newList,'ownAuthority'=>$ownAuthority));
}
html部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>权限树扩展分享</title>
{include file="../public/resource/newWebcss.html" /}
{include file="../public/resource/newWebjs.html" /}
</head>
<body>
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form">
<div class="layui-row">
<div class="layui-col-md11 layui-col-md-offset1">
<div class="layui-form">
<div class="layui-form-item">
<div class="layui-form-label">快捷操作</div>
<div class="layui-form-block">
<button type="button" class="layui-btn layui-btn-primary" onclick="checkAll('#LAY-auth-tree-index')">全选</button>
<button type="button" class="layui-btn layui-btn-primary" onclick="uncheckAll('#LAY-auth-tree-index')">全不选</button>
<button type="button" class="layui-btn layui-btn-primary" onclick="showAll('#LAY-auth-tree-index')">全部展开</button>
<button type="button" class="layui-btn layui-btn-primary" onclick="closeAll('#LAY-auth-tree-index')">全部隐藏</button>
</div>
</div>
</div>
</div>
<div class="layui-col-md6 layui-col-md-offset1">
<!-- 此扩展能递归渲染一个权限树,点击深层次节点,父级节点中没有被选中的节点会被自动选中,单独点击父节点,子节点会全部 选中/去选中 -->
<form class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">角色名称<span style="color: red">*</span></label>
<div class="layui-input-block">
<input class="layui-input" type="text" required="" lay-verify="required" name="role_name" placeholder="请输入角色名称" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">选择权限<span style="color: red">*</span></label>
<div class="layui-input-block">
<div id="LAY-auth-tree-index"></div>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">权限描述<span style="color: red">*</span></label>
<div class="layui-input-block">
<textarea placeholder="请输入内容" required="" lay-verify="required" id="role_des" name="role_des" class="layui-textarea"></textarea>
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<input type="hidden" id="roleId" value="{$roleId}">
<button class="layui-btn" type="button" lay-submit lay-filter="LAY-auth-tree-submit">提交</button>
<button class="layui-btn layui-btn-primary" type="reset">重置</button>
</div>
</div>
</div>
</form>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
<script type="text/javascript">
layui.config({
base: '__STATIC__/newWeb/layuiadmin/extends/layui_exts/',
}).extend({
authtree: 'authtree',
});
layui.use(['jquery', 'authtree', 'form', 'layer'], function(){
var $ = layui.jquery;
var authtree = layui.authtree;
var form = layui.form;
var layer = layui.layer;
// 初始化
$.ajax({
url: '/roleUpdateSelectApi',
data:{
'roleId' : $('#roleId').val()
},
dataType: 'json',
success: function(data){
var trees = data.data.data.trees;
console.log(data.ownAuthority.role_name)
var role_name = data.ownAuthority.role_name;
var role_des = data.ownAuthority.role_des;
$('input[name=role_name]').val(role_name)
$('textarea[name=role_des]').val(role_des)
// 渲染时传入渲染目标ID,树形结构数据(具体结构看样例,checked表示默认选中),以及input表单的名字
authtree.render('#LAY-auth-tree-index', trees, {
inputname: 'authids[]'
,layfilter: 'lay-check-auth'
// ,autoclose: false
// ,autochecked: false
// ,openchecked: true
// ,openall: true
,autowidth: true
});
// PS:使用 form.on() 会引起了事件冒泡延迟的BUG,需要 setTimeout(),并且无法监听全选/全不选
// PS:如果开启双击展开配置,form.on()会记录两次点击事件,authtree.on()不会
form.on('checkbox(lay-check-auth)', function(data){
// 注意这里:需要等待事件冒泡完成,不然获取叶子节点不准确。
setTimeout(function(){
console.log('监听 form 触发事件数据', data);
// 获取选中的叶子节点
var leaf = authtree.getLeaf('#LAY-auth-tree-index');
console.log('leaf', leaf);
// 获取最新选中
var lastChecked = authtree.getLastChecked('#LAY-auth-tree-index');
console.log('lastChecked', lastChecked);
// 获取最新取消
var lastNotChecked = authtree.getLastNotChecked('#LAY-auth-tree-index');
console.log('lastNotChecked', lastNotChecked);
}, 100);
});
// 使用 authtree.on() 不会有冒泡延迟
authtree.on('change(lay-check-auth)', function(data) {
console.log('监听 authtree 触发事件数据', data);
// 获取所有节点
var all = authtree.getAll('#LAY-auth-tree-index');
console.log('all', all);
// 获取所有已选中节点
var checked = authtree.getChecked('#LAY-auth-tree-index');
console.log('checked', checked);
// 获取所有未选中节点
var notchecked = authtree.getNotChecked('#LAY-auth-tree-index');
console.log('notchecked', notchecked);
// 获取选中的叶子节点
var leaf = authtree.getLeaf('#LAY-auth-tree-index');
console.log('leaf', leaf);
// 获取最新选中
var lastChecked = authtree.getLastChecked('#LAY-auth-tree-index');
console.log('lastChecked', lastChecked);
// 获取最新取消
var lastNotChecked = authtree.getLastNotChecked('#LAY-auth-tree-index');
console.log('lastNotChecked', lastNotChecked);
});
authtree.on('deptChange(lay-check-auth)', function(data) {
console.log('监听到显示层数改变',data);
});
}
});
form.on('submit(LAY-auth-tree-submit)', function(obj){
var role_name = $('input[name=role_name]').val();
var role_des = $('#role_des').val();
var role_id = $('#roleId').val();
console.log(role_name);
console.log(role_des);
var authids = authtree.getChecked('#LAY-auth-tree-index'); //已经选中节点
var notchecked = authtree.getNotChecked('#LAY-auth-tree-index'); //未选中节点
console.log('Choosed authids is', authids);
console.log(notchecked);
if (role_name == "" || role_name == null) {layer.msg('角色名称不能为空',function () {});return;}
if (role_name.length <=3) {layer.msg('权限字数不少于4个字');return;}
if (role_des == "" || role_des == null) {layer.msg('权限描述不能为空');return;}
if (authids.length < 1) {layer.msg('至少有一个权限',function () {});return;}
obj.field.authids = authids;
$.ajax({
url: '/UpdateRole',
dataType: 'json',
data: {
role_name : role_name,
role_auth_ids : authids,
id : role_id,
role_des : role_des
},
success: function(res){
if (res.status == 'success'){
layer.msg(res.msg, {icon: 6});
setTimeout(function () {
var index = parent.layer.getFrameIndex(window.name);
parent.location.href=res.url; //刷新父级页面
parent.layer.close(index); //关闭当前页面
},600)
}else {
layer.msg(res.msg,function () {});
}
}
});
return false;
});
});
</script>
<script type="text/javascript">
// 获取最大深度样例
function getMaxDept(dst){
layui.use(['jquery', 'layer', 'authtree'], function(){
var layer = layui.layer;
var authtree = layui.authtree;
layer.alert('树'+dst+'的最大深度为:'+authtree.getMaxDept(dst));
});
}
// 全选样例
function checkAll(dst){
layui.use(['jquery', 'layer', 'authtree'], function(){
var layer = layui.layer;
var authtree = layui.authtree;
authtree.checkAll(dst);
});
}
// 全不选样例
function uncheckAll(dst){
layui.use(['jquery', 'layer', 'authtree'], function(){
var layer = layui.layer;
var authtree = layui.authtree;
authtree.uncheckAll(dst);
});
}
// 显示全部
function showAll(dst){
layui.use(['jquery', 'layer', 'authtree'], function(){
var layer = layui.layer;
var authtree = layui.authtree;
authtree.showAll(dst);
});
}
// 隐藏全部
function closeAll(dst){
layui.use(['jquery', 'layer', 'authtree'], function(){
var layer = layui.layer;
var authtree = layui.authtree;
authtree.closeAll(dst);
});
}
// 获取节点状态
function getNodeStatus(dst){
layui.use(['jquery', 'layer', 'authtree', 'laytpl'], function(){
var layer = layui.layer;
var authtree = layui.authtree;
var laytpl = layui.laytpl;
// 获取所有节点
var all = authtree.getAll('#LAY-auth-tree-index');
// 获取所有已选中节点
var checked = authtree.getChecked('#LAY-auth-tree-index');
// 获取所有未选中节点
var notchecked = authtree.getNotChecked('#LAY-auth-tree-index');
// 获取选中的叶子节点
var leaf = authtree.getLeaf('#LAY-auth-tree-index');
// 获取最新选中
var lastChecked = authtree.getLastChecked('#LAY-auth-tree-index');
// 获取最新取消
var lastNotChecked = authtree.getLastNotChecked('#LAY-auth-tree-index');
var data = [
{func: 'getAll', desc: '获取所有节点', data: all},
{func: 'getChecked', desc: '获取所有已选中节点', data: checked},
{func: 'getNotChecked', desc: '获取所有未选中节点', data: notchecked},
{func: 'getLeaf', desc: '获取选中的叶子节点', data: leaf},
{func: 'getLastChecked', desc: '获取最新选中', data: lastChecked},
{func: 'getLastNotChecked', desc: '获取最新取消', data: lastNotChecked},
];
var string = laytpl($('#LAY-auth-tree-nodes').html()).render({
data: data,
});
layer.open({
title: '节点状态'
,content: string
,area: '800px'
,tipsMore: true
});
$('body').unbind('click').on('click', '.LAY-auth-tree-show-detail', function(){
layer.open({
type: 1,
title: $(this).data('title')+'-节点详情',
content: '['+$(this).data('content')+']',
tipsMore: true
});
});
});
}
// 显示到某层
function showDept(dst) {
layui.use(['layer', 'authtree', 'jquery'], function(){
var jquery = layui.jquery;
var layer = layui.layer;
var authtree = layui.authtree;
layer.prompt({title: '显示到某层'}, function(value, index, elem) {
authtree.showDept(dst, value);
layer.close(index);
});
});
}
// 关闭某层以后的所有层
function closeDept(dst) {
layui.use(['layer', 'authtree', 'jquery'], function(){
var jquery = layui.jquery;
var layer = layui.layer;
var authtree = layui.authtree;
layer.prompt({title: '关闭某层以后的所有层'}, function(value, index, elem) {
authtree.closeDept(dst, value);
layer.close(index);
});
});
}
// 转换列表
function listConvert(url) {
layui.use(['layer', 'authtree', 'jquery', 'form', 'code'], function(){
var jquery = layui.jquery;
var layer = layui.layer;
var authtree = layui.authtree;
var form = layui.form;
layer.open({
title: '列表转树演示'
,content: '<fieldset class="layui-elem-field layui-field-title"><legend>列表数据转权限树</legend></fieldset><form class="layui-form"> <div class="layui-form-item"> <label class="layui-form-label">多选权限</label> <div class="layui-input-block"> <div id="LAY-auth-tree-convert-index"></div> </div> </div> <div class="layui-form-item"> <div class="layui-input-block"> <button class="layui-btn" type="submit" lay-submit lay-filter="LAY-auth-tree-submit">提交</button> <button class="layui-btn layui-btn-primary" type="reset">重置</button> </div> </div></form><pre class="layui-code" id="LAY-auth-tree-convert-code"></pre>'
,area: ['800px', '400px']
,tipsMore: true
,success: function() {
$.ajax({
url: url,
dataType: 'json',
success: function(res){
$('#LAY-auth-tree-convert-code').text(JSON.stringify(res, null, 2));
layui.code({
title: '返回的列表数据'
});
// 支持自定义递归字段、数组权限判断等
// 深坑注意:如果API返回的数据是字符串,那么 startPid 的数据类型也需要是字符串
var trees = authtree.listConvert(res.data.list, {
primaryKey: 'alias'
,startPid: '0'
,parentKey: 'palias'
,nameKey: 'name'
,valueKey: 'alias'
,checkedKey: res.data.checkedAlias
});
// 如果页面中多个树共存,需要注意 layfilter 需要不一样
authtree.render('#LAY-auth-tree-convert-index', trees, {
inputname: 'authids[]',
layfilter: 'lay-check-convert-auth',
// openall: true,
autowidth: true,
});
}
});
},
});
});
}
</script>
<!-- 状态模板 -->
<script type="text/html" id="LAY-auth-tree-nodes">
<style type="text/css">
.layui-layer-page .layui-layer-content{
padding: 20px;
line-height: 22px;
}
</style>
<table class="layui-table">
<thead>
<th>方法名</th>
<th>描述</th>
<th>节点</th>
</thead>
<tbody>
{{# layui.each(d.data, function(index, item) { }}
<tr>
<td>{{item.func}}</td>
<td>{{item.desc}}</td>
<td><a class="LAY-auth-tree-show-detail" href="javascript:;" data-title="{{item.desc}}" data-content="{{item.data.join(']<br>[')}}">查看详情</a>({{item.data.length}})</td>
</tr>
{{# });}}
</tbody>
</table>
</script>
</html>
用户
页面示例
用户数据库字段设计如下【可根据需要自行添加】:
CREATE TABLE sw_manager
(
mg_id
int(11) NOT NULL AUTO_INCREMENT,
mg_name
varchar(32) NOT NULL,
mg_pwd
varchar(32) NOT NULL,
mg_time
int(11) NOT NULL,
mg_role_id
int(11) NOT NULL DEFAULT ‘2’ COMMENT ‘角色id’,
mg_status
tinyint(1) NOT NULL DEFAULT ‘0’ COMMENT ‘0:正常,1:禁用’,
mg_remark
varchar(20) DEFAULT NULL COMMENT ‘角色备注’,
mg_update_time
int(11) NOT NULL DEFAULT ‘0’ COMMENT ‘更新时间’,
mg_pid
int(11) NOT NULL DEFAULT ‘0’,
mg_phone
varchar(20) DEFAULT NULL COMMENT ‘登录手机号’,
deviceToken
varchar(255) DEFAULT NULL COMMENT ‘手机唯一标识’,
type
tinyint(1) DEFAULT ‘1’ COMMENT ’ 1 正常 2关闭’,
status
tinyint(1) DEFAULT ‘2’ COMMENT ‘1 客服 2 坐席’,
mg_image
varchar(255) DEFAULT NULL COMMENT ‘头像’,
online_status
varchar(20) DEFAULT NULL COMMENT ‘状态’,
sign
varchar(255) DEFAULT NULL COMMENT ‘签名’,
sex
tinyint(1) DEFAULT ‘1’ COMMENT ‘1男 2女’,
email
varchar(100) DEFAULT NULL COMMENT ‘邮箱’,
online_time
int(11) DEFAULT NULL COMMENT ‘登陆时间’,
offline_time
int(255) DEFAULT NULL COMMENT ‘离线时间’,
PRIMARY KEY (mg_id
) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3410 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT=‘用户表’