1、显示/隐藏导出功能
require-table.js
showExport: true
2、导出时忽略列
exportOptions: {ignoreColumn: [0, 'operate', 'photos']}
3、设置弹窗高度
Fast.config.openArea = ['100%', '95%']
4、添加行内按钮(自定义列)
//自定义按钮
{field: 'id', title: "MD编辑", formatter: function (val, row, index){
var str = 'MD编辑';
return '<a title="MD编辑" href="/et?id='+ row.id +'" class="btn btn-xs btn-primary btn-dialog">'+str+'</a>'
}, operate: false},
5、添加行内按钮组别(操作列)
{
field: 'buttons',
width: "120px",
title: __('按钮组'),
table: table,
events: Table.api.events.operate,
buttons: [
{
name: 'detail',
text: '下级',
title: '下级',
classname: 'btn btn-xs btn-primary btn-dialog',
icon: 'fa fa-list',
url: 'user/level_graph',
callback: function (data) {
Layer.alert("接收到回传数据:" + JSON.stringify(data), {title: "回传数据"});
},
visible: function (row) {
//返回true时按钮显示,返回false隐藏
return true;
},
]
},
6、页面使用vue
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<div id="app" style="margin-top: 10px; padding: 10px">
</div>
<script>
new Vue({
el: '#app',
data: function (){
return {
}
},
created: function (){
this.getList()
},
methods:{
getList(){
axios.post('/user/list', {
}).then( (response) => {
}).catch(function (error) {
console.log(error);
});
},
}
})
</script>
7、页面按钮绑定点击事件,使用ajax
diy: function () {
$('.btn-save').bind('click', function (){
Fast.api.ajax({
url:'test',
data:{
'a': $('#a').val(),
},
},function (res){
if (res.code == 1){
window.location.reload()
}
});
})
Controller.api.bindevent();
},
8、审核通过、审核驳回下拉按钮组
javascript代码
{
field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate,
formatter: Table.api.formatter.operate,
buttons: [
{
name: 'detail', text: '审核通过', icon: '', classname: 'btn btn-xs btn-success btn-pass',dropdown: '操作',
},
{
name: 'detail', text: '审核不通过', icon: '', classname: 'btn btn-xs btn-success btn-reject',dropdown: '操作',
},
{
name: 'addtabs',
text: __('订单明细'),
title: __('订单明细'),
classname: 'btn btn-xs btn-warning btn-addtabs',
url: 'order/index?id={ids}'
}
]
}
// 为表格绑定事件
Table.api.bindevent(table);
table.on('post-body.bs.table', function(e, setting, json, xhr) {
$('.btn-pass', this).on('click', function(e) {
var row = table.bootstrapTable('getData')[$(this).data('row-index')]
Layer.confirm('您确定通过此申请吗?', {icon: 3, title: '提示'}, function(index) {
Fast.api.ajax({
url: 'a/setStatus',
data: {
id: row.id,
status: 1
}
}, function(data, ret) {
table.bootstrapTable('refresh')
})
Layer.close(index)
})
})
$('.btn-reject', this).on('click', function(e) {
var row = table.bootstrapTable('getData')[$(this).data('row-index')]
var content = '<div class="form" style="padding: 5px;" xmlns="http://www.w3.org/1999/html"><div class="form-group"><label class="label-control col-xs-12 col-sm-12"></label><textarea class="form-control" id="reject-reason" rows="5" cols="30" placeholder="请填写拒绝理由"></textarea></div></div>';
var index = Layer.open({
type: 1,
title: '拒绝通过',
// area: ['350px', '230px'],
content: content,
btn: ['确定', '取消'],
btn1: function() { //用户点击确定
Fast.api.ajax({
url: 'a/setStatus',
data: {
id: row.id,
reject_reason: $("#reject-reason").val(),
status: 2
}
}, function(ret, data) {
Layer.close(index)
table.bootstrapTable('refresh')
return false //阻止默认事件
}, function(ret, data) {
Toastr.error(data.msg)
return false
})
}
})
})
})
php代码
public function setStatus()
{
$data = $this->request->param();
$res = \app\admin\model\BuildPartner::where('id', $data['id'])->find();
!$res && $this->error('不存在');
if ($data['status'] == 2 && (!isset($data['reject_reason']) || empty($data['reject_reason']))) {
$this->error('请填写拒绝理由');
}
$updateData = ['status' => $data['status'], 'handle_time' => time()];
if (!empty($data['reject_reason'])) {
$updateData = array_merge($updateData, ['reject_reason' => $data['reject_reason']]);
}
Db::startTrans();
try {
\app\admin\model\XXX::where('id', $data['id'])->update($updateData);
//如果同意则
if ($data['status'] == 1){
}
Db::commit();
} catch (Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success('操作成功');
}
9、列表页面渲染多个
使用场景:订单列表页面js文件会包含发货、退款等各种操作,比较复杂。如果想单独分离出来未支付订单、已发货订单、售后订单,可以公用index方法,操作如下:
//默认查看所有订单
index: function() {
Controller.bootIndex('order/index')
},
//查看未支付订单
unpay: function() {
Controller.bootIndex('order/unpay')
},
//查看已发货订单
hasSend: function() {
Controller.bootIndex('order/hasSend')
},
//查看售后订单
after_sale: function() {
Controller.bootIndex('order/after_sale')
},
//commonList即之前的index方法,以上都能公用下面的方法
commonList: function (url) {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: url + location.search,
add_url: 'order/add',
edit_url: 'order/edit',
del_url: 'order/del',
multi_url: 'order/multi',
table: 'order',
//...一大堆逻辑
},
10、使用定时任务
10.1、安装官方定时任务插件
10.2、运行crontab -e -u root,添加
* * * * * /usr/bin/php /www/yoursite/public/index.php /addons/crontab/autotask/index > /dev/null 2>&1 &
10.3、后台管理-常规管理-定时任务-添加计划任务
*/1 每一分钟执行一次
11、忘记密码,数据库重置密码为123456
password 541acf0cc702c085e411601e611ff2e4
halt umPKsI
12、列表页面工具栏新增时间筛选,ajax请求
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/moment.js/2.22.1/moment-with-locales.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
<div id="toolbar" class="toolbar">
<input id="c-start" style="display: inline-block;width: 150px" class="form-control" data-date-format="YYYY-MM-DD HH:mm:ss" type="text" value="{$start}">
<input id="c-end" style="display: inline-block;width: 150px" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" type="text" value="{$end}">
<a href="javascript:void(0);" onclick="exportSalesInfo()" class="btn btn-primary">导出汇总单</a>
<a href="javascript:;" class="btn btn-success deliveryCgpOrderAll">一键发货</a>
</div>
<script>
$('#c-start').datetimepicker({
locale: moment.locale('zh-CN')
});
$('#c-end').datetimepicker({
locale: moment.locale('zh-CN')
});
function exportSalesInfo(){
var start = $('#c-start').val();
var end = $('#c-end').val();
window.location.href = '/admin.php/order/exportSalesInfo?start=' + start + '&end=' + end;
}
function deliveryCgpOrderAll(){
$.post('/admin.php/order/deliveryCgpOrderAll',{},function(res){});
}
</script>
13、配置跨域
13.1 接口新增初始化方法
public function _initialize()
{
//方便本地调试(解决跨域问题)
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: token, Origin, X-Requested-With, Content-Type, Accept, Authorization");
header('Access-Control-Allow-Methods: POST,GET,PUT,DELETE');
parent::_initialize();
}
13.2 注释掉跨域检测
application/common/controller/Api.php
// check_cors_request();
14、放置静态常量
application/common/Constant.php 新建文件
namespace app\common;
/**
* 常量
*/
class Constant {
public static $userLevel = [
0 => "普通用户",
1 => "会员",
];
}
其他文件使用
use app\common\Constant;
$arr = Constant::$userLevel;
15、同一账号不能同时登录
fastadmin自带的是同一账号可以多处登录,即可以一个账号可以同时在线
可以在App\Common\Library\Auth中修改为一个账号只能同时在线一个
direct 方法中 增加 Token::clear($user->id);(大概320行)
$this->_user = $user;
Token::clear($user->id);
$this->_token = Random::uuid();
Token::set($this->_token, $user->id, $this->keeptime);
16、页面元素(输入框、按钮)绑定弹窗等相关事件
input button
$(document).on("click", ".btn-forgot", function () {
var id = "resetpwdtpl";
var content = Template(id, {});
Layer.open({
type: 1,
title: __('Reset password'),
area: ["450px", "355px"],
content: content,
success: function (layero) {
Form.api.bindevent($("#resetpwd-form", layero), function (data) {
Layer.closeAll();
}
);
}
});
});
//输入框
$(document).on("change", "input[name=type]", function () {
var type = $(this).val();
$("div.form-group[data-type]").addClass("hide");
$("div.form-group[data-type='" + type + "']").removeClass("hide");
$('#resetpwd-form').validator("setField", {
captcha: "required;length(4);integer[+];remote(" + $(this).data("check-url") + ", event=resetpwd, " + type + ":#" + type + ")",
});
$(".btn-captcha").data("url", $(this).data("send-url")).data("type", type);
});
17、状态字段(toggle)
新增
{:build_radios('row[enable]', [0 => '否', 1 => '是'], 1)}
编辑
{:build_radios('row[enable]', [0 => '否', 1 => '是'], $row['enable'])}
列表(主键为id)
{field: 'enable', title: __('Enable'), formatter: Table.api.formatter.toggle},
列表(主键非id)
{field: 'enable', title: __('Enable'), formatter: function(val, row, index){
if (val == 0){
return '<a href="javascript:;" data-toggle="tooltip" title="" class="btn-change " data-index="0" data-id="'+ row.task_id +'" data-params="enable=1" data-original-title="点击切换"><i class="fa fa-toggle-on text-success text-success fa-flip-horizontal text-gray fa-2x"></i></a>';
}else{
return '<a href="javascript:;" data-toggle="tooltip" title="" class="btn-change " data-index="1" data-id="'+ row.task_id +'" data-params="enable=0" data-original-title="点击切换"><i class="fa fa-toggle-on text-success text-success fa-2x"></i></a>';
}
}},
18、status lable normal searchList flag
Table.api.formatter.status
Table.api.formatter.normal
{field: 'item', title: __('Item'), searchList: {"1":"头部","2":"上衣"},formatter: Table.api.formatter.status},
19、全局字段
application/common/controller/Backend.php
此处注意,如果是常量类,则可以使用反射,获取所有静态属性
$config = [
'part' => Constant::$part //注入常量
//使用反射,获取所有静态属性
'OrderConstant' => (new \ReflectionClass(OrderConstant::class))->getStaticProperties(),
];
使用 window.Config.part
{field: 'item', title: __('Item'), searchList: window.Config.part, formatter: Table.api.formatter.status},
20、二维数组FieldList
数据源为json数组
<div class="form-group" id="consume-input">
<label class="control-label col-xs-12 col-sm-2">{:__('Consume')}:</label>
<div class="col-xs-12 col-sm-8">
<dl class="fieldlist" data-name="row[consume]" data-template="testtpl">
<dd>
<ins>道具</ins>
<ins>数量</ins>
</dd>
<dd>
<a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> 追加</a>
</dd>
<textarea name="row[consume]" class="form-control hide" cols="30" rows="5">{$row.consume|htmlentities}</textarea>
</dl>
<!--定义模板-->
<script type="text/html" id="testtpl">
<dd class="form-inline">
<input type="text" name="row[<%=name%>][<%=index%>][ItemId]" class="form-control selectpage" data-primary-key="item_id" data-source="ngc_items/synthetic_items_list" data-field="item_name" value="<%=row['ItemId']%>" size="10">
<input type="text" name="row[<%=name%>][<%=index%>][ConsumeNum]" class="form-control" value="<%=row['ConsumeNum']%>" size="30">
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</dd>
</script>
</div>
</div>
js
edit: function () {
$(document).on("fa.event.appendfieldlist", ".btn-append", function(){
Form.events.selectpage($("#consume-input"));
});
Controller.api.bindevent();
},
21、列表页增加tab标签页切换筛选过滤功能
index.html
<div class="panel-heading">
{:build_heading(null, false)}
<ul class="nav nav-tabs">
<li class="active"><a href="#all" data-toggle="tab">所有记录</a></li>
{foreach $typeList as $index=>$vo}
<li class="{$vo.active?'active':''}"><a href="#{$index}" data-toggle="tab" data-record_type="{$index}">{$vo}</a></li>
{/foreach}
</ul>
</div>
js
$('.panel-heading a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var that = $(this)
var options = table.bootstrapTable('getOptions');
options.pageNumber = 1;
options.queryParams = function (params){
var filter = {}
filter['record_type'] = that.data('record_type')
params.filter = JSON.stringify(filter)
return params
}
table.bootstrapTable('refresh', {})
return false;
})