Fastadmin踩坑日记-2.魔改表格
经过日夜的查找,终于可以慢慢的上手这个了,踩了几个坑,记录一下

坑1-前台无法显示emoji字符
最早的几个emoji是2个字节,在utf8默认的双字节编码中是可以正常显示的,比如那个红色感叹号❕,到后来emoji逐步成为了4个字符,原本的utf8_gerneral_ci字符集就没法显示了,必须手动设置
显示emoji需要几个条件
-
数据库字符集为
utf8mb4
,mysql里面是utf8mb4_gerneral_ci
-
字段字符集为
ut8mb4
,mysql里面是utf8mb4_gerneral_ci
-
后台连接数据库设置的时候也要选择
ut8mb4
,也就是在db.php
类似这个文件里例如

之前一直没有成功,原来是条件3没有满足,导致前台一直看到的是?
而不是emoji如????
(左边是一个emoji,但显示不出来,原来typecho也是要改的。。。),改了3之后终于成功了

坑2-Bootstrap-table显示图像或自定义渲染显示
这个就比如说,数据库里有一个gender字段存储用户的性别,0是男,1是女
渲染到BT表格(Bootstrap-table,下同)上的时候想要直接显示男或女,
或者你想自定义这个表格内容的css,就需要用到BT的formatter渲染器
首先需要完成踩坑日记1的curd生成表格的操作,然后到前台页面的对应js中
位置为public/assets/js/[backend|frontend]这个根据你的这个bt表格在前台后台决定/<插件名>/<表>.js
找到对应的字段如

加入一个formatter即可,如果是本页的可以放在页面下面的api当中,然后字段就可以对应的渲染了,然后注意,坑来了

本页的控制器是Controller,而非Table,所以要访问这个渲染器,一定是Controller.api.formatter.xxxxx
,不是Table.api.formatter.xxxx
比较常用的formatter有
Table.api.formatter.icon //渲染成图标按钮
Table.api.formatter.image //渲染成单张图片
Table.api.formatter.images //渲染成多张图片
Table.api.formatter.content //内容自动截取
Table.api.formatter.status //渲染成状态
Table.api.formatter.normal //渲染成label
Table.api.formatter.toggle //渲染成开关
Table.api.formatter.url //渲染成文本框链接
Table.api.formatter.search //渲染成搜索链接
Table.api.formatter.addtabs //渲染成打开新选项卡链接
Table.api.formatter.dialog //渲染成弹窗链接
Table.api.formatter.flag //渲染成标志
Table.api.formatter.label //渲染成标志
Table.api.formatter.datetime //渲染成日期时间
Table.api.formatter.operate //渲染成操作栏按钮
Table.api.formatter.buttons //渲染成按钮组
最终效果如下

坑3-点击按钮无法设置为弹窗
还是在位置为public/assets/js/[backend|frontend]这个根据你的这个bt表格在前台后台决定/<插件名>/<表>.js
这里的classname写成btn-dialog即可设置为弹窗,url即为弹窗对应的控制器

在控制器里面对应输出相应的页面即可,可以参照下图,下图输出的是渲染后的view/index.html

坑4-弹窗内的更新事件完成后不会自己关闭
我这是非主流方法,因为什么callback方法都试过了,没反应,无法让弹窗数据与父级窗口交互,自己摸索出一套办法
要点1. 表单必须是ajax
Ajax表单提交才会触发右上角的小窗口提示更新成功或失败,如果是form里的submit则会全局页面刷新显示成功

要点2.学会使用parent来控制父级窗口
在弹窗内,parent表示的就是父级窗口,这样就可以访问进行相关的操作
在弹窗内可以执行下面的js代码实现数据交互
parent.Toastr.success(data) //父级成功弹窗
parent.Toastr.error(data) //父级失败弹窗
parent.Layer.closeAll() //父级关闭所有弹窗,也就是弹窗可以关闭自己

//弹窗内执行的js文件
<script>
function submit() {
var url = 'mypchelper/orders/update'
var formData = $('#myForm').serialize()
//序列化为 a=1&b=2这样的序列
Fast.api.ajax({
url: url,
type: 'POST',
data: formData,
success: function(data) {
parent.Toastr.success(data.msg)
switch (data.data.errcode) {
case 0:
parent.Toastr.success('消息已经推送至用户手机')
break
case 40003:
parent.Toastr.error('推送错误:touser字段openid为空或者不正确')
parent.Toastr.error('错误信息:' + data.data.errmsg)
break
case 40037:
parent.Toastr.error('推送错误:订阅模板id为空不正确')
parent.Toastr.error('错误信息:' + data.data.errmsg)
break
case 43101:
parent.Toastr.error(
'推送错误:用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系'
)
parent.Toastr.error('错误信息:' + data.data.errmsg)
break
case 47003:
parent.Toastr.error(
'推送错误:模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错'
)
parent.Toastr.error('错误信息:' + data.data.errmsg)
break
case 41030:
parent.Toastr.error(
'推送错误:page路径不正确,需要保证在现网版本小程序中存在,与app.json保持一致'
)
parent.Toastr.error('错误信息:' + data.data.errmsg)
break
}
parent.Layer.closeAll()
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
Toastr.error('网络错误,请稍后重试!')
console.log('提交请求的错误信息:' + errorThrown + XMLHttpRequest)
}
})
}
</script>
要点3. Controller内isAjax()函数
对应处理ajax的数据请求
if ($this->request->isAjax()) { //form提交ajax请求
$result = false;
$params = $this->request->post("r/a"); //前端页面内form的input name为r[对应字段名]
if ($params) {
$id = $params['id']; //获取数据赋值
}
//然后sql方法处理即可
............sql process.............
if ($result !== false) {
$res = $this->temMsg($openid, $problem, $orderreply); //我这里封装了一个微信推送的函数
$this->success('更新成功', null, $res); //把res数据传给前端
//$this -> redirect('mypchelper/Orders/index', 5, '页面跳转中...'); //这个别试,会在弹窗内跳转
} else {
$this->error(__('No rows were updated'));
}
}
还有就是其他人的主流办法,分享自定义按钮btn-dialog在关闭弹窗后刷新父窗体 刷新 关闭 按钮 callback 自定义
坑5 Fastadmin Bootstrap-table表格访问多表数据(联合查询多表)(thinkphp关联模型)
有时候我们会遇到这种情况
数据库一张表要和别的表联动输出数据,这个时候就需要在取数据的时候下功夫
官方给了个例子,在controller/example/relationmodel.php
内,可以看着改,不过我们自己还是来写一遍
我们举个例子
举个例子
数据库
现在有orders
以及users
表
orders
表内有id_users
字段和users
表内的id
字段是一个玩意儿
也就是orders.id_users
字段是一个外键
输出的时候我们要吧orders和users的信息一起输出,这个在sql里面非常容易实现,但现在是要用fastadmin的php方法实现,所以我们先看控制器
控制器初始化
在controller/demo/orders.php内主动构造index方法,而非继承使用backend本身封装的方法
一定要有$this->relationSearch = true;
表明是多表联合查询,然后载入需要的附属表$this->searchFields = "users"; //需要的表
这里容易搞混,因为users是表而Users是数据层Model,我们需要使用with()函数来预载入附属表users对应的model,即
$total = $this->model //载入本controller对应的model这里也就是orders的model
->with("Users") //预载入对应附属表的model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->with("Users")
->where($where)
->order(['processstatus' => 'ASC', $sort => $order])
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
然后到对应的model中,追加belongTo()函数,对应参数为belongsTo(表名,原表的id,外接表id,我也不知到,连接类型[左连接、右连接啥的]),那我们这里就是如下
public function users()
{
return $this->belongsTo('Users', 'id_users', 'id', [], 'LEFT')->setEagerlyType(0);
//对应表
}
然后还需要在前端js设置一下输出,位置为public/assets/js/[backend|frontend]这个根据你的这个bt表格在前台后台决定/<插件名>/<表>.js
这里field要设置成附表.字段
如我这里的几个字段,后面的表头title如果想要原生输出,位置在application/[admin看是不是后台文件]/lang/<插件名/表.php>
里面,修改即可
下面是加入了需要输出的附表字段后的部分字段
//orders.js中的bootstrap-table渲染字段
{ field: 'users.name', title: __('机主姓名') }, //对应model中的字段
{ field: 'users.mobile', title: __('机主手机') },
{
field: 'users.QQ',
title: __('机主QQ'),
formatter: Controller.api.formatter.tolink
},
{ field: 'users.address', title: __('宿舍地址') },
{ field: 'pcmodel', title: __('Pcmodel') },
{ field: 'problem', title: __('Problem') },
之后前端就可以正常显示联合查询后的数据了
附上完整的controller/index
//在controller/demo/orders.php内
/**
* 查看
*/
public function index()
{
$this->relationSearch = true;
$this->searchFields = "users"; //需要的表
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->with("Users") //预载入对应的model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->with("Users")
->where($where)
->order(['process' => 'ASC', $sort => $order])
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
坑6-换了用户就无法访问自定义的模块
记得在controller头部设置
protected $noNeedRight = ['*']; //无需权限即可访问
当然官方也给了说明
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = []; //里面放对应的模块如'add','edit'之类
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = [];
/**
* 权限Auth
* @var Auth
*/
protected $auth = null;
类似案例