fastadmin 后台管理框架使用技巧(持续更新中)
FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架,具体介绍,请查看文档,文档地址为:https://doc.fastadmin.net/docs/index.html
这里只整理一下在使用过程中用到的小技巧,以便用到的时候查看,其实,在fastadmin的论坛中,有一篇介绍后台表格的文章,说的也不错,如有问题,请先点击:一张图解析FastAdmin中的表格列表的功能
如果还没解决,那就继续往下看了
1、修改默认排序字段
在fastadmin后台中,如果数据表里存在weigh字段,则index页面显示的时候,包括排序按钮是显示三个按钮,如果没有,则显示修改和删除两个按钮
如果不想要使用默认字段weigh来排序的话,只需要改一个地方就好了,就是在table初始化的时候,把默认的排序字段改成你想要其他的字段就行了
如图所示:,其实,我们可以在require.js中大约65行出看到,table在初始化的时候,默认是dragsortfield:weigh,只要改掉这个值就行了
2、自定义菜单
在fastadmin中,默认是自带三个操作按钮,分别是拖拽、编辑和删除,如果想要自定义菜单按钮的话,也挺简单,在“一张图解析fastadmin表格列表的功能”文章中有提过,一般是有三种形式:弹出窗口、ajax和新选项卡,就是在classname中增加不同的样式,弹窗:
"
btn-dialog
",ajax:"
btn-magic btn-ajax
",新选项卡:"
btn-addtabs
",通过不同的样式绑定了不同的事件,下面一个示例是弹窗的,而且只是数据展示,还没有数据处理
1 {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, 2 buttons:[ 3 { 4 name: 'cow_list', 5 hidden:false, 6 title: '可用牛牛', 7 classname: 'btn btn-xs btn-success btn-dialog', 8 icon: 'fa fa-github-alt', 9 url: 'farm/log/index',
10 extend:'data-area=\'["60%","70%"]\'',
11 },
12 ], formatter: Table.api.formatter.operate}
效果如图所示:,
如果是要操作数据的话,比如自带的edit和add,需要再增加
1 cow_list: function () {
2 Controller.api.bindevent();
3 },
因为是index,要特殊一些,因为index方法包含了get和ajax两步操作,get渲染出主页模板,然后再用ajax请求数据,所以还得修改js中index对应的URL地址,比如直接获取参数,或者直接自定义查询条件,两者区别在于后者直接修改了在弹窗出现的index页面中通用搜索显示时候的相应字段的默认值,比如user_id默认为空,自定义之后,直接user_id为指定值了。
3、渲染数据
我们知道,fastadmin底层自带了很多渲染数据的格式,比如
> `Table.api.formatter.icon` 快速将字段渲染成一个按钮,仅支持Fontawesome按钮 > `Table.api.formatter.image` 快速将字段渲染成图片展示的形式 > `Table.api.formatter.images` 快速将字段渲染成多图片展示的形式,字段数据请以`,`进行分隔 > `Table.api.formatter.status` 快速将字段渲染成状态,默认`normal/hidden/deleted/locked`这四个状态 > `Table.api.formatter.url` 快速将字段渲染成URL框 > `Table.api.formatter.search` 快速将字段渲染成可搜索的链接,点击后将执行搜索 > `Table.api.formatter.addtabs` 快速将字段渲染成可添加到选项卡的链接,点击后将把链接添加到选项卡 > `Table.api.formatter.flag` 快速将字段渲染成标志,仅支持`index/hot/recommend/new`这四种标志 > `Table.api.formatter.label` 快速将字段渲染Label标签 > `Table.api.formatter.datetime` 快速时间戳数据渲染成日期时间数据 > `Table.api.formatter.operate` 操作栏固定按钮 > `Table.api.formatter.buttons` 快速生成多个按钮 > `Table.api.formatter.toggle` 快速生成切换按钮
我们可以自定义渲染数据,比如订单查询的时候,一个订单可能会对应多条商品数据,这在index页面显示的时候,就不好显示了,所以可以把每个订单对应的商品数据,都放在一个字段里,示例如下图所示,此处goods字段是控制器中with的一对多的goods模型
1 {field: 'goods',title:'商品',formatter:function (value,data,key) { 2 var content = ''; 3 value.forEach((value,key)=>{ 4 content += value.title+'-'; 5 content += value.attr_name+'*'; 6 content += value.num+','; 7 }); 8 return content; 9 }}, 10 // {field: 'address_address', title: __('Address_address')},
4、js中使用控制器中的数据
如果想在js中调用控制器中的方法,就不能使用$this->view->assign()了,得使用$this->assignconfig("total", $total),然后在js中调用
Config.total,或可参考文章:js中如何使用控制器中的数据
5、自定义配置
在fast中,自带这很多类型的配置信息,类型比较丰富,有字符、文本、数组、单图、多图等,在做一下配置项的时候非常方便,比如一些比例设置、开关设置等
如果想自定义配置的话,也很简单,首先在application/common/model/config.php中获取配置类型的方法,可以追加自己想要的类型,比如:
1 'radio' => __('Radio'),
2 'array' => __('Array'),
3 'custom' => __('Custom'),
4 'rank' =>'名次规则',
5 ]; 6 return $typeList; 7 }
然后在application/admin/view/general/config/index.html文件中,增加自定义配置的格式就行了,比如我这个是借用一下数组的格式
1 {case rank} 2 <dl class="fieldlist" data-name="row[{$item.name}]">
3 <dd>
4 <ins>名次</ins>
5 <ins>分红比例</ins>
6 </dd>
7 <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
8 <textarea name="row[{$item.name}]" class="form-control hide" cols="30" rows="5">{$item.value}</textarea>
9 </dl>
10 {/case}
最后展示一下效果
6、自定义按钮
这里的自定义按钮并不是表格中的自定义菜单,而是工具栏按钮,如图所示:
html代码,切记a标签的title属性一定要有,否则在弹出框中没有顶部的标题:
1 <a href="javascript:;" class="btn btn-default" style="font-size:14px;color:dodgerblue;">
2 <i class="fa fa-dollar"></i>
3 <span class="extend">
4 账户余额:<span id="price">0</span>
5 </span>
6 </a>
7 <a class="btn btn-info btn-dialog btn-withdraw" href="shop/log/withdraw" data-name="withdraw" title="申请提现">
8 <i class="fa fa-leaf"></i>申请提现 9 </a>
10 </div>
在js中增加事件:这段代码很重要,自定义什么方法就给什么方法绑定event事件
1 withdraw: function () { 2 Controller.api.bindevent(); 3 },
4 api: { 5 bindevent: function () { 6 Form.api.bindevent($("form[role=form]")); 7 } 8 }
最终效果图如下:
下面又是一个详细的补充,因为在这个位置,自定义按钮,使用btn-dialog,像一些title,data-title=“弹窗标题”,href=“跳转地址” ,data-area='["40%","35%"]'都好说,data-params也不好使,只能在href后绑定参数,但是不能像btn-edit一样传递选中行的参数ids,
所以如果想传递选中行的参数,得手动在js中绑定参数,就是下面这种,或者在每一行的operate里添加自定义按钮,在那里参数ids是fast底层绑定的,
最终效果图:
index.html中的相关代码:
1 <a href="javascript:;" class="btn btn-success btn-disabled disabled" id="btn-recharge-credit"><i class="fa fa-plus"></i> 充值销账</a>
2 <a href="javascript:;" class="btn btn-success btn-disabled disabled" id="btn-change-credit"><i class="fa fa-cny"></i> 调整额度</a>
3 <a href="javascript:;" class="btn btn-success btn-multi btn-disabled disabled" data-params="state=1"><i class="fa fa-eye"></i>解冻</a>
4 <a href="javascript:;" class="btn btn-success btn-multi btn-disabled disabled" data-params="state=0"><i class="fa fa-eye-slash"></i>冻结</a>
充值销账和调整额度是自己加的,解冻冻结是系统自带的multi方法
相关js代码部分:
1 // 为表格绑定事件
2 Table.api.bindevent(table); 3
4 // 点击充值销账按钮
5 $(document).on("click", "#btn-recharge-credit", function () { 6 let ids = Table.api.selectedids(table); 7 console.log(ids);//注意ids 为数组
8 // var url = 'jq/finance/credit_account/edit?ids='+ids;//弹出窗口
9 // Fast.api.open(url, '充值销账',{
10 // callback:function (value) {
11 // console.log(value);
12 // }
13 // });
14 //还是按照ids个数多个弹框吧
15 for (let index in ids) { 16 var url = 'jq/finance/credit_account/edit?ids='+ids[index];//弹出窗口
17 Fast.api.open(url, '充值销账',{area:['40%', '35%']}); 18 } 19 }); 20 // 点击调整额度按钮
21 $(document).on("click", "#btn-change-credit", function () { 22 let ids = Table.api.selectedids(table); 23 console.log(ids);//注意ids 为数组
24 // var url = 'jq/finance/credit_account/recharge?ids='+ids;//弹出窗口
25 // Fast.api.open(url, '调整额度',{
26 // callback:function (value) {
27 // console.log(value);
28 // }
29 // });
30 for (let index in ids) { 31 var url = 'jq/finance/credit_account/recharge?ids='+ids[index];//弹出窗口
32 Fast.api.open(url, '调整额度',{ 33 area:['35%', '30%'] 34 }); 35 } 36 });
标题,还可以自定义css样式:Fast.api.open(url, '<span style="color: red">充值销账</span>',{area:['40%', '35%']});
下面这段代码很重要,如果不加的话,页面提交就是原始提交,不走ajax了,而且很多远程selectpage都失效了
1 add: function () { 2 Controller.api.bindevent(); 3 }, 4 //充值销账,直接借助edit方法
5 edit: function () { 6 Controller.api.bindevent(); 7 }, 8 //调整额度,这段很重要
9 recharge:function() { 10 Controller.api.bindevent(); 11 }, 12 api: { 13 bindevent: function () { 14 Form.api.bindevent($("form[role=form]")); 15 } 16 }
7、二级分类
在有的时候,需要有多级类别,比如添加商品的时候,需要先选择父类,再选择子类,其实,这个有点像三级联动,但是自己写起来比较麻烦,在fast中有已经写好了,详情请见插件中的开发实例中,这里只是整理一部分。
效果如图所示:父类是“心理”,然后下面有“心理测试”,“心理暗示”,两个子类,这样就能实现效果了
,
此处是源码部分:
1 <div class="form-group"> 2 <label class="control-label col-xs-12 col-sm-2">{:__('Category_id')}:</label> 3 <div class="col-xs-12 col-sm-8"> 4 <div class="form-inline" data-toggle="cxselect" data-selects="first,second"> 5 <select data-rule="required" style="width: 50%" class="first form-control" name="row[category_pid]" data-url="ajax/category?type=science&pid=0"></select>
<select data-rule="required" style="width: 50%" class="second form-control" name="row[category_id]" data-url="ajax/category" data-query-name="pid"></select> 6 </div> 7 </div> 8 </div>
这里重点是调用了ajax.php下的category方法,并传递两个参数,注意传递pid=0之后,需要更改下category方法,这里就不说明了 。
补充:在fast自动生成的selectpage时,默认是传id的,如果要自定义参数的话,可直接在url后追加,值得注意的是,像一些“>”、“<”等符号必须转义才能用,不然会被当成普通字符串处理,
以下是实现自定义条件为 custom[type][] = <,custom[type][] = 3, 即type < 3,其中,<位小于号<的十进制,也可以采用转义字符<,就像字符&用&表示一样
1 <div class="form-group col-lg-6 col-md-6">
2 <label class="control-label col-xs-12 col-sm-4">{:__('Out_bill_unit')}:</label>
3 <div class="col-xs-12 col-sm-8">
4 <input id="c-out_bill_unit" data-rule="required" data-source="jq/product/Agent_company/selectpage?custom[type][]=<&custom[type][]=3" class="form-control selectpage" name="row[out_bill_unit]" type="text" value="">
5 </div>
6 </div>
8、详情内自定义审核按钮
一般在查看详情的时候,有修改操作,自动生成的就是这个样子,默认就是确定及重置操作,其中确定是提交到form表单指定的action地址上,已经满足了日常修改的需求
但有时候,只有一个提交是不够的,特别是用到审核的时候,既有审核通过,也有审核拒绝,都是提交,那改怎么办呢,其实就是动态的修改form表单action指定的地址,
实现后效果如下:
这是代码:
1 <div class="form-group layer-footer">
2 <label class="control-label col-xs-12 col-sm-2"></label>
3 <div class="col-xs-12 col-sm-8">
4 {if condition="$row['admin_status'] eq 0"} 5 <button onclick="on_sub(true);" class="btn btn-success">取消咨询</button>
6 {/if} 7 {if condition="$row['admin_refund_status'] eq 0"} 8 <button onclick="on_sub(false);" class="btn btn-warning">同意退款</button>
9 {/if} 10 <!-- <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>-->
11 <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
12 </div>
13 <input type="hidden" id="is_true" name="is_true" value="0">
14 <script>
15 var on_sub = function (on) { 16 var url = on ? 'Consult/cancel' : 'Consult/refund'; 17 url = url + '?ids={:input("ids")}'; 18 $('#edit-form').attr('action',url); 19 } 20 </script>
21 </div>
自动生成的edit页面,提交的时候默认是edit
9、手动增加软删除
在最开始设计表用命令生成增删改查的时候,如果一开始没有设计delete_time字段,就不能实现软删除,所以在后来想要再添加的时候,稍微有点麻烦,其实完全可以重新生成一个测试表,仿照新生成的model改一下就行了,强烈建议一开始就把软删除加上,不然如果已经写了接口再添加的话,你会骂娘的,关于软删除,更多可以查看手册:软删除
1 use traits\model\SoftDelete; 2
3 class Product extends Model 4 { 5 use SoftDelete; 6 // 自动写入时间戳字段
7 protected $autoWriteTimestamp = 'int'; 8
9 // 定义时间戳字段名
10 protected $createTime = 'createtime'; 11 protected $updateTime = 'updatetime'; 12 protected $deleteTime = 'delete_time';//默认就是deleteTime,所以此处直接可以省略可以不写
需要注意的是:tp5底层实现软删除的delete_time字段默认值是null,而不是0,所以这个地方一定要注意!
10、手动更改toggle
一般toggle开关针对的是status字段,而且默认值是0或1,但是系统用户与后台管理员的status是字符串normal与hidden,所以要是也想实现toggle开关,可以添加yes:'normal',no:'hidden',还是直接上代码吧
1 { 2 field: 'status', title: __("Status"), 3 searchList: {'hidden': __('Hidden'), 'normal': __('Normal')}, 4 formatter: function (value, row, index) { 5 if(row.id == Config.admin.id){ 6 return ''; 7 } 8 return Table.api.formatter.toggle.call(this, value, row, index); 9 }, 10 yes: 'normal', 11 no: 'hidden'
12 },
然后,处理事件 我直接手写的
1 /** 2 * 批量更新 3 * @internal 4 */
5 public function multi($ids = "") 6 { 7 // 管理员禁止批量操作 8 //暂不考虑ids 是多个的情况下
9 if ($ids > 1) { 10 $status = $this->model->where('id',$ids)->value('status'); 11 $new_status = $status == 'normal' ? 'hidden' : 'normal' ; 12 $this->model->save([ 13 'status'=>$new_status,
14 ],['id'=>$ids]); 15 $this->success('操作成功'); 16 } else { 17 $this->error('超级管理员不能隐藏'); 18 } 19 }
如果有其他更好的方法,欢迎留言交流!
11、设置某字段正序或倒序按钮
{field: 'id', title: __('Id'),operate:false,sortable: true},
这个太简单了,实在是不想多说了,其实就是字段在sql中的asc和desc,所以对于先查询出来,再二次加工的那种就不生效了
12、二级分类
在很多地方都用到二级分类,包括商品的一级分类是什么,二级分类是什么,选择范围只能是该一级分类下的二级分类,不多说了,还是直接上代码吧
这段代码在fastadmin的开发实例中有,可以参考那个,不过修改只提供了一种,这里还有更简单的方式
1 <select class="first form-control" style="width: 50%" data-rule="required"
2 name="row[jq_category_id]" data-url="jq/ajax/category" >
3 <option selected="selected" value="{$row.jq_category_id|htmlentities}">{$row.jq_category_name|htmlentities}</option>
4 </select>
5 <select class="second form-control" style="width:50%" data-rule="required"
6 name="row[jq_category_child_id]" data-url="jq/ajax/category"
7 data-query-name="pid" value="{$row.jq_category_child_id|htmlentities}">
8 <option selected="selected" value="{$row.jq_category_child_id|htmlentities}">{$row.jq_category_child_name|htmlentities}</option>
9 </select>
10
11 <select class="first form-control" style="width: 50%" data-rule="required"
12 name="row[jq_insurance_company_id]" data-url="jq/ajax/company?type=1" data-value="{$row.jq_insurance_company_id|htmlentities}">
13 </select>
14 <select class="second form-control" style="width: 50%" data-rule="required"
15 name="row[jq_insurance_child_company_id]" data-value="{$row.jq_insurance_child_company_id|htmlentities}"
16 data-url="jq/ajax/company?type=3" data-query-name="pid">
17 </select>
13、控制table中字段的长度
在列表展示中,如果像一些字段比如简介或备注之类的东西,内容太长,全部显示有点不友好,这里是限制长度,给个width(百分比或ps都行),字符过长显示...,鼠标放上去,显示全部
1 {field: 'des', title: __('Des'), operate:false,cellStyle:function (value,row,index,field) { 2 return { 3 css: { 4 "min-width": "150px", 5 "white-space": "nowrap", 6 "text-overflow": "ellipsis", 7 "overflow": "hidden", 8 "max-width":"300px"
9 } 10 }; 11 },formatter:function (value,row,index,field) { 12 var span=document.createElement('span'); 13 span.setAttribute('title',value); 14 span.innerHTML = value; 15 return span.outerHTML; 16 }},
通过cssStyle自定义样式,然后再自定义formatter即可,效果如下所示
14、data_rule 验证规则
常用的data_rule就是required了,表示该字段不能为空,常用的还有 mobile,tel,email,url,range(0~),length(1~5)等,多个验证用空格连接,或使用竖杠|。
更多规则直接参考nice-validator,因为fastadmin就是用的这个插件,或者直接参考文档表单验证部分,里面更全
1 <div class="form-group">
2 <label class="control-label col-xs-12 col-sm-2">{:__('Claim_mobile')}:</label>
3 <div class="col-xs-12 col-sm-8">
4 <input id="c-claim_mobile" data-rule="required mobile|tel" class="form-control" name="row[data][claim_mobile]" type="text" value="">
5 </div>
6 </div>
15、关于table的搜索问题
关闭表格中左侧的切换视图、显示列 和导出数据等按钮:
1 <table 2 id="table" 3 class="table table-striped table-bordered table-hover table-nowrap" 4 data-show-export="false" 5 data-show-toggle="false" 6 data-show-columns="false" 7 width="100%"> 8 </table>,也可以在js文件中控制
showToggle: false,//隐藏切换按钮
showColumns: false,//隐藏显示列按钮
showExport: false,//隐藏导出数据按钮
search:false,//隐藏快速搜索
searchFormVisible: true,//默认打开通用搜索
showSearch: false,//隐藏通用搜索按钮
16、关于使用地图位置(经纬度)选择插件的注意点
在使用经纬度插件的时候,data-toggle="addresspicker" 最好是不要放在button标签或者a标签里面,因为如果在button和a标签外面有form表单的话,会触发整个表单的提交工作,
添加还好点,因为添加的时候其他字段有验证会阻止当前表单的提交工作,但是edit编辑的时候就不能阻止了,当想修改经纬度的时候,刚一点击就触发了保存操作,就修改不了了,
所以最好的是,放一个div标签,给个btn的class就行了
1 <div class="btn btn-success" data-toggle="addresspicker" data-lat-id="c-lat" data-lng-id="c-lon">选取经纬度</div>