Merge remote-tracking branch 'origin/develop' into feature/hant

This commit is contained in:
hant 2025-04-23 19:39:57 +08:00
commit 6078af68d8
9 changed files with 418 additions and 150 deletions

View File

@ -2,10 +2,12 @@
namespace app\admin\controller\statistics; namespace app\admin\controller\statistics;
use app\admin\model\Admin;
use app\admin\model\Order; use app\admin\model\Order;
use app\common\controller\Backend; use app\common\controller\Backend;
use think\exception\DbException; use think\exception\DbException;
use think\response\Json; use think\response\Json;
use function Symfony\Component\Clock\now;
/** /**
* 订单列管理 * 订单列管理
@ -46,32 +48,76 @@ class Dispatcher extends Backend
*/ */
public function index() public function index()
{ {
//$this->chart();
$today = now()->format('Y-m-d');
$this->chart(); $today_end = now()->format('Y-m-d');
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags', 'trim']); $this->request->filter(['strip_tags', 'trim']);
if (false === $this->request->isAjax()) { if (false === $this->request->isAjax()) {
$this->assign('daterange',$today.' - '.$today_end);
return $this->view->fetch(); return $this->view->fetch();
} }
//如果发送的来源是 Selectpage则转发到 Selectpage
if ($this->request->request('keyField')) { $filter = $this->request->param('filter');
return $this->selectpage(); $filter = json_decode($filter,true);
if(!empty($filter['daterange'])){
$arr = explode(' - ',$filter['daterange']);
if(trim($arr[0])){
$filter['start_time'] = trim($arr[0]);
}
if(trim($arr[1])){
$filter['end_time'] = trim($arr[1]);
}
} }
[$where, $sort, $order, $offset, $limit] = $this->buildparams();
$list = $this->model $list = $this->chart($filter,false);
->where($where)
->order($sort, $order) $result = array("total" => $list->total(), "rows" => $list->items());
->paginate($limit);
$result = ['total' => $list->total(), 'rows' => $list->items()];
return json($result); return json($result);
} }
//图表统计
public function chart(){
$filter = $this->request->param('filter/a',[]); public function chartData()
{
$filter = $this->request->post();
if(!empty($filter['daterange'])){
$arr = explode(' - ',$filter['daterange']);
if(trim($arr[0])){
$filter['start_time'] = trim($arr[0]);
}
if(trim($arr[1])){
$filter['end_time'] = trim($arr[1]).' 23:59:59';
}
}
$data = $this->chart($filter,true);
$newData = [
['派单员','总业绩(¥)','转化率(%)','利润率(%)','变现值']
];
foreach ($data as $datum){
$newData[] = [
$datum['admin_user'],
$datum['performance'],
$datum['trans_rate'],
$datum['performance_rate'],
$datum['cash_value'],
];
}
return $newData;
}
//图表统计
public function chart($filter,$getAll=false){
$orderValid = implode(',',$this->model->tabStatus(Order::TAB_VALID)); $orderValid = implode(',',$this->model->tabStatus(Order::TAB_VALID));
@ -106,9 +152,8 @@ class Dispatcher extends Backend
}else{ //按录单时间 }else{ //按录单时间
$time_field = 'create_time'; $time_field = 'create_time';
} }
$builder->whereBetween($time_field,$filter['start_time'],$filter['end_time']); $builder->whereBetween($time_field,[$filter['start_time'],$filter['end_time']]);
} }
//城市 //城市
if(!empty($filter['area_id'])){ if(!empty($filter['area_id'])){
$builder->where('area_id',$filter['area_id']); $builder->where('area_id',$filter['area_id']);
@ -117,26 +162,46 @@ class Dispatcher extends Backend
if(!empty($filter['item_id'])){ if(!empty($filter['item_id'])){
$builder->where('item_id',$filter['item_id']); $builder->where('item_id',$filter['item_id']);
} }
$data = $builder->group('dispatch_admin_id')->select();
if($getAll){
$data = $builder->group('dispatch_admin_id')->select();
}else{
$data = $builder->group('dispatch_admin_id')->paginate();
}
$newData = []; $newData = [];
foreach ($data as $datum){ if(!empty($data)){
//利润率 = 总业绩/总成效额 foreach ($data as &$datum){
$datum->performance_rate = $this->_calc($datum->performance,$datum->total); //利润率 = 总业绩/总成效额
//转化率 = 完单数 / 总订单数 $datum->performance_rate = $this->_calc($datum->performance,$datum->total,4,true);
$datum->trans_rate = $this->_calc($datum->finish_num,$datum->count_num); //转化率 = 完单数 / 总订单数
//变现值 = 总业绩 / 总订单数 $datum->trans_rate = $this->_calc($datum->finish_num,$datum->count_num,4,true);
$datum->cash_value = $this->_calc($datum->performance,$datum->count_num,2); //变现值 = 总业绩 / 总订单数
//客单利润 = 总利润 / 完单数 $datum->cash_value = $this->_calc($datum->performance,$datum->count_num,2);
$datum->performance_avg = $this->_calc($datum->performance,$datum->finish_num,2); //客单利润 = 总利润 / 完单数
//客单价 = 总成效额 / 完单数 $datum->performance_avg = $this->_calc($datum->performance,$datum->finish_num,2);
$datum->total_avg = $this->_calc($datum->total,$datum->finish_num,2); //客单价 = 总成效额 / 完单数
$datum->total_avg = $this->_calc($datum->total,$datum->finish_num,2);
$newData[] = $datum->toArray(); if(!empty($datum->dispatch_admin_id)){
$datum->admin_user = Admin::where($datum->dispatch_admin_id)->value('nickname')??'系统';
}else{
$datum->admin_user = '系统';
}
$datum->avg_time_diff = $this->_calc($datum->avg_time_diff,3600,2);
$datum->id = $datum->dispatch_admin_id;
$newData[] = $datum->toArray();
}
} }
dump($newData);exit; if($getAll){
return $newData;
}else{
return $data;
}
//dump($newData);exit;
} }
@ -146,8 +211,14 @@ class Dispatcher extends Backend
* @param $scale * @param $scale
* @return int|string * @return int|string
*/ */
private function _calc($a,$b,$scale=4){ private function _calc($a,$b,$scale=4,$is_percent=false){
return $b > 0 ? bcdiv($a,$b,$scale) : 0; $val = $b > 0 ? bcdiv($a,$b,$scale) : 0;
if($is_percent){
return bcmul($val,100,2);
}
return $val;
} }
} }

View File

@ -1,46 +1,66 @@
<div class="panel panel-default panel-intro"> <div class="panel panel-default panel-intro">
<div class="panel-heading"> <div class="panel-heading">
{:build_heading(null,FALSE)} <!--<div class="panel-lead"><em>多表格Multitable</em>用于展示在一个页面展示多个表格数据,并且每次切换时刷新</div>-->
<ul class="nav nav-tabs" data-field="status"> <ul class="nav nav-tabs">
<li class="{:$Think.get.status === null ? 'active' : ''}"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> <li class="active"><a data-val="first" href="#first" data-toggle="tab">统计图表</a></li>
{foreach name="statusList" item="vo"} <li><a href="#second" data-val="second" data-toggle="tab">统计列表</a></li>
<li class="{:$Think.get.status === (string)$key ? 'active' : ''}"><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
{/foreach}
</ul> </ul>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div id="myTabContent" class="tab-content"> <div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one"> <div class="tab-pane fade active in" id="first">
<div class="widget-body no-padding"> <section class="connectedSortable">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> <div class="nav-tabs-custom charts-custom">
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('statistics/dispatcher/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a> <!-- Tabs within a box -->
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('statistics/dispatcher/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a> <ul class="nav nav-tabs pull-right">
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('statistics/dispatcher/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a> <li class="active"><a href="#bar-chart" data-toggle="tab">柱状图</a></li>
<!-- <li><a href="#pie-chart" data-toggle="tab">饼图</a></li>-->
<li class="pull-left header"><i class="fa fa-inbox"></i> 派单员数据</li>
</ul>
<div>
<div class="form-inline" id="chart-filter" style="margin-top:20px;margin-bottom: 30px;">
<!-- 单选:维度 -->
<div class="form-group">
<label class="radio-inline">
<input type="radio" name="filter[time_by]" value="1" checked> 派单时间
</label>
<label class="radio-inline">
<input type="radio" name="filter[time_by]" value="2"> 录单时间
</label>
</div>
<!-- 时间范围 -->
<div class="form-group" style="margin-left: 15px;">
<input type="text" class="form-control datetimerange" data-locale='{"format":"YYYY-MM-DD"}' placeholder="指定日期" name="filter[daterange]" id="daterange" value="{$daterange}" autocomplete="off" style="width: 170px;">
</div>
<!-- 查询按钮 -->
<button class="btn btn-default" id="filter-btn" style="margin-left: 15px;">查询</button>
</div>
<div class="dropdown btn-group {:$auth->check('statistics/dispatcher/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
{foreach name="statusList" item="vo"}
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:" data-params="status={$key}">{:__('Set status to ' . $key)}</a></li>
{/foreach}
</ul>
</div> </div>
<div class="tab-content no-padding">
<!-- Morris chart - Sales -->
<!--
<div class="chart tab-pane" id="pie-chart" style="width: 100%; height: 500px;"></div>
-->
<div class="chart tab-pane active" id="bar-chart" style="width: 100%; height: 500px;"></div>
</div>
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('statistics/dispatcher/edit')}"
data-operate-del="{:$auth->check('statistics/dispatcher/del')}"
width="100%">
</table>
</div>
</div>
</section>
</div>
<div class="tab-pane fade" id="second">
<table id="table2" class="table table-striped table-bordered table-hover" width="100%">
</table>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -21,6 +21,10 @@ class OrderDispatch extends Model
public function getArriveImagesAttr($val) public function getArriveImagesAttr($val)
{ {
if (empty($val)) {
return [];
}
$images = explode(',', $val); $images = explode(',', $val);
foreach ($images as $k => $v) { foreach ($images as $k => $v) {
$images[$k] = cdnurl($v, true); $images[$k] = cdnurl($v, true);
@ -31,6 +35,10 @@ class OrderDispatch extends Model
public function getImagesAttr($val) public function getImagesAttr($val)
{ {
if (empty($val)) {
return [];
}
$images = explode(',', $val); $images = explode(',', $val);
foreach ($images as $k => $v) { foreach ($images as $k => $v) {
$images[$k] = cdnurl($v, true); $images[$k] = cdnurl($v, true);
@ -41,6 +49,10 @@ class OrderDispatch extends Model
public function getImageAttr($val) public function getImageAttr($val)
{ {
if (empty($val)) {
return '';
}
return cdnurl($val, true); return cdnurl($val, true);
} }
} }

View File

@ -218,7 +218,7 @@ return [
'host' => Env::get('redis.redis_host'), // Redis 服务器地址 'host' => Env::get('redis.redis_host'), // Redis 服务器地址
'port' => Env::get('redis.redis_port'), // Redis 端口 'port' => Env::get('redis.redis_port'), // Redis 端口
'password' => Env::get('redis.redis_password'), // Redis 密码,如果有的话 'password' => Env::get('redis.redis_password'), // Redis 密码,如果有的话
'select' => Env::get('redis.redis_db'), 'select' => 5,
], ],
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Cookie设置 // | Cookie设置

View File

@ -3,9 +3,7 @@
namespace app\services; namespace app\services;
use app\common\library\Token; use app\common\library\Token;
use EasyWeChat\Factory; use EasyWeChat\MiniApp\Application;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\MiniProgram\Application;
class WorkerService extends BaseService class WorkerService extends BaseService
{ {
@ -47,8 +45,9 @@ class WorkerService extends BaseService
{ {
$app = $this->getMiniProgramApp(); $app = $this->getMiniProgramApp();
try { try {
$info = $app->auth->session($code); $utils = $app->getUtils();
} catch (InvalidConfigException $e) { $info = $utils->codeToSession($code);
} catch (\Exception $e) {
$this->apiError('登录失败', $e); $this->apiError('登录失败', $e);
} }
@ -82,18 +81,31 @@ class WorkerService extends BaseService
'app_id' => config('mini_program.app_id'), 'app_id' => config('mini_program.app_id'),
'secret' => config('mini_program.secret'), 'secret' => config('mini_program.secret'),
]; ];
return Factory::miniProgram($config); return new Application($config);
} }
/** /**
* 解密微信手机号 * 通过 code 获取用户手机号
* @param string $code
* @return array
*/
private function code2PhoneNumberInfo(string $code): array
{
$app = $this->getMiniProgramApp();
$phoneInfo = $app->getClient()->postJson('wxa/business/getuserphonenumber', ['code' => $code]);
return $phoneInfo->toArray();
}
/**
* 获取用户手机号
* @param string $code * @param string $code
* @return mixed * @return mixed
*/ */
public function getPhoneNumber(string $code) public function getPhoneNumber(string $code)
{ {
//getPhoneNumber 方法通过魔术方法 __call 获取 //通过 code 获取手机号信息
$phoneInfo = $this->getMiniProgramApp()->getPhoneNumber($code); $phoneInfo = $this->code2PhoneNumberInfo($code);
if (empty($phoneInfo)) { if (empty($phoneInfo)) {
$this->apiError('获取手机号失败', 0, $phoneInfo); $this->apiError('获取手机号失败', 0, $phoneInfo);
@ -137,4 +149,40 @@ class WorkerService extends BaseService
return true; return true;
} }
/**
* 更新师傅位置
* @param int $workerId
* @param float $latitude
* @param float $longitude
* @return true
*/
public function updateWorkerLocation(int $workerId, float $latitude, float $longitude)
{
$worker = $this->getWorkerModel()->find($workerId);
if (empty($worker)) {
$this->apiError('更新位置失败,用户不存在');
}
$worker->lat = $latitude;
$worker->lng = $longitude;
$worker->location_update_time = datetime(time());
$worker->update_time = datetime(time());
$worker->save();
return true;
}
} }

View File

@ -77,4 +77,21 @@ class Worker extends WorkerApi
{ {
$this->success('操作成功', $this->user); $this->success('操作成功', $this->user);
} }
/**
* 更新师傅位置
* @return void
*/
public function updateWorkerLocation()
{
$params = $this->request->request();
$validate = $this->validate($params, \app\worker\validate\Worker::class . '.updateWorkerLocation');
if ($validate !== true) {
$this->error($validate);
}
$this->getWorkerService()->updateWorkerLocation($this->user['id'], $params['latitude'], $params['longitude']);
$this->success('操作成功');
}
} }

View File

@ -9,6 +9,8 @@ class Worker extends Validate
protected $rule = [ protected $rule = [
'code' => 'require|max:128', 'code' => 'require|max:128',
'vendor_token' => 'require|max:128', 'vendor_token' => 'require|max:128',
'latitude' => 'require|number',
'longitude' => 'require|number',
]; ];
protected $message = [ protected $message = [
@ -18,5 +20,6 @@ class Worker extends Validate
protected $scene = [ protected $scene = [
'login' => ['code'], 'login' => ['code'],
'bindPhoneNumber' => ['code', 'vendor_token'], 'bindPhoneNumber' => ['code', 'vendor_token'],
'updateWorkerLocation' => ['latitude', 'longitude'],
]; ];
} }

View File

@ -84,7 +84,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'id', title: __('Id')}, {field: 'id', title: __('Id')},
//{field: 'dispatch_id', title: __('Dispatch_id')}, //{field: 'dispatch_id', title: __('Dispatch_id')},
//{field: 'worker_id', title: __('Worker_id')}, //{field: 'worker_id', title: __('Worker_id')},
{field: 'remark', title: __('跟进内容'), operate: 'LIKE', table: table2, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'remark', title: __('跟进内容'), operate: false, table: table1, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'images', title: __('跟进依据'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images}, {field: 'images', title: __('跟进依据'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images},
/* {field: 'need_notice', title: __(''), searchList: {"0":__(''),"1":__('')}, formatter: Table.api.formatter.normal}, /* {field: 'need_notice', title: __(''), searchList: {"0":__(''),"1":__('')}, formatter: Table.api.formatter.normal},
{field: 'notice_time', title: __('提醒时间'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},*/ {field: 'notice_time', title: __('提醒时间'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},*/
@ -121,7 +121,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
//{field: 'worker_id', title: __('Worker_id')}, //{field: 'worker_id', title: __('Worker_id')},
// {field: 'status', title: __('Status')}, // {field: 'status', title: __('Status')},
{field: 'status_text', title: __('Status_text'), operate: 'LIKE'}, {field: 'status_text', title: __('Status_text'), operate: 'LIKE'},
{field: 'remark', title: __('Remark'), operate: 'LIKE', table: table1, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'remark', title: __('Remark'), operate: false, table: table2, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, {field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
// {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} // {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
] ]

View File

@ -1,88 +1,185 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-theme', 'template','addtabs','moment'], function ($, undefined, Backend, Table, Form,Echarts,undefined,Template,Datatable,Moment) {
var Controller = { var Controller = {
index: function () { index: function () {
// 初始化表格参数配置 //绑定事件
Table.api.init({ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
extend: { var $targetPanel = $($(this).attr("href"));
index_url: 'statistics/dispatcher/index' + location.search, var tabVal = $(this).data('val');
add_url: 'statistics/dispatcher/add',
edit_url: 'statistics/dispatcher/edit', if (tabVal === 'second') {
del_url: 'statistics/dispatcher/del', // 当切换到“统计列表”时,自动刷新表格
multi_url: 'statistics/dispatcher/multi', //$targetPanel.find(".btn-refresh").trigger("click");
import_url: 'statistics/dispatcher/import', // 初始化表格参数配置
table: 'order', Table.api.init();
// 表格2
var table2 = $("#table2");
table2.bootstrapTable({
url: 'statistics/dispatcher/index' + location.search,
toolbar: '#toolbar1',
sortName: 'id',
search: false,
commonSearch:true,
visible: false,
showToggle: false,
showColumns: false,
showExport: true,
searchFormVisible:true,
columns: [
[
//{field: 'id', title: __('Id')},
{field: 'id', title: __('ID'),visible:false,operate: false},
{field: 'admin_user', title: __('派单员'),operate: "LIKE"},
{field: 'count_num', title: __('总订单数'),operate: false},
{field: 'finish_num', title: __('完单数'),operate: false},
{field: 'total', title: __('成效额(¥)'), operate: false},
{field: 'performance', title: __('总业绩(¥)'), operate: false},
{field: 'cost_total', title: __('总成本(¥)'), operate: false},
{field: 'refund_total', title: __('退款金额(¥)'), operate: false},
{field: 'refund_count', title: __('退款单数'), operate: false},
{field: 'performance_rate', title: __('利润率(%)'), operate: false},
{field: 'trans_rate', title: __('转化率(%)'), operate: false},
{field: 'cash_value', title: __('变现值'), operate: false},
{field: 'performance_avg', title: __('客单利润(¥)'), operate: false},
{field: 'total_avg', title: __('客单价(¥)'), operate: false},
{field: 'avg_time_diff', title: __('派单时效(小时)'), operate: false},
//{field: 'admin_user', title: __('派单员'),operate: "LIKE",visible:false},
//{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false},
//{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false},
{field: 'time_by', title: __('时间维度'), visible:false,searchList: {"1":__('录单时间'),"2":__('派单时间')},defaultValue:1, formatter: Table.api.formatter.normal},
{field: 'daterange', title: __('时间筛选'), addclass:'datetimerange',
autocomplete:false,
operate: "RANGE",
datetimeFormat: "YYYY-MM-DD",
//defaultValue:today()+' - '+today(),
data:'autocomplete="off" data-local={"format":"YYYY-MM-DD"}',
visible:false},
// {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格2绑定事件
Table.api.bindevent(table2);
} }
}); });
var table = $("#table");
// 初始化表格
table.bootstrapTable({ // 触发 tab 后发起 ajax 获取图表数据
url: $.fn.bootstrapTable.defaults.extend.index_url, $('ul.nav-tabs li.active a[data-toggle="tab"]').on("shown.bs.tab", function () {
pk: 'id', getChartData();
sortName: 'id',
fixedColumns: true,
fixedRightNumber: 1,
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'order_no', title: __('Order_no'), operate: 'LIKE'},
{field: 'customer', title: __('Customer'), operate: 'LIKE'},
{field: 'tel', title: __('Tel'), operate: 'LIKE'},
{field: 'status', title: __('Status'), searchList: {"0":__('Status 0'),"10":__('Status 10'),"20":__('Status 20'),"30":__('Status 30'),"40":__('Status 40'),"50":__('Status 50'),"60":__('Status 60'),"-10":__('Status -10')}, formatter: Table.api.formatter.status},
{field: 'area_id', title: __('Area_id'), operate: 'LIKE'},
{field: 'address', title: __('Address'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'lng', title: __('Lng'), operate:'BETWEEN'},
{field: 'lat', title: __('Lat'), operate:'BETWEEN'},
{field: 'work_tel_id', title: __('Work_tel_id')},
{field: 'source_shop', title: __('Source_shop'), operate: 'LIKE'},
{field: 'source', title: __('Source')},
{field: 'source_uid', title: __('Source_uid'), operate: 'LIKE'},
{field: 'item_id', title: __('Item_id')},
{field: 'item_title', title: __('Item_title'), operate: 'LIKE'},
{field: 'detail', title: __('Detail'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'remark', title: __('Remark'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'images', title: __('Images'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images},
{field: 'plan_time', title: __('Plan_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'admin_id', title: __('Admin_id')},
{field: 'coupon_id', title: __('Coupon_id')},
{field: 'total', title: __('Total'), operate:'BETWEEN'},
{field: 'online_amount', title: __('Online_amount'), operate:'BETWEEN'},
{field: 'offline_amount', title: __('Offline_amount'), operate:'BETWEEN'},
{field: 'online_amount_last', title: __('Online_amount_last'), operate:'BETWEEN'},
{field: 'offline_amount_type', title: __('Offline_amount_type'), searchList: {"1":__('Offline_amount_type 1'),"2":__('Offline_amount_type 2')}, formatter: Table.api.formatter.normal},
{field: 'discount_amount', title: __('Discount_amount'), operate:'BETWEEN'},
{field: 'refund_amount', title: __('Refund_amount'), operate:'BETWEEN'},
{field: 'worker_refund_amount', title: __('Worker_refund_amount'), operate:'BETWEEN'},
{field: 'real_amount', title: __('Real_amount'), operate:'BETWEEN'},
{field: 'cost', title: __('Cost'), operate:'BETWEEN'},
{field: 'material_cost', title: __('Material_cost'), operate:'BETWEEN'},
{field: 'performance', title: __('Performance'), operate:'BETWEEN'},
{field: 'cancel_reason_id', title: __('Cancel_reason_id')},
{field: 'cancel_detail', title: __('Cancel_detail'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'audit_remark', title: __('Audit_remark'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'audit_admin_id', title: __('Audit_admin_id')},
{field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'delete_time', title: __('Delete_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'dispatch_type', title: __('Dispatch_type')},
{field: 'receive_type', title: __('Receive_type')},
{field: 'revisit_id', title: __('Revisit_id')},
{field: 'dispatch_admin_id', title: __('Dispatch_admin_id')},
{field: 'dispatch_admin_user', title: __('Dispatch_admin_user'), operate: 'LIKE'},
{field: 'dispatch_time', title: __('Dispatch_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'aftersale_id', title: __('Aftersale_id')},
{field: 'amount_images', title: __('Amount_images'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
}); });
// 为表格绑定事件
Table.api.bindevent(table); function getChartData(){
// 获取单选框选中的值
var timeBy = $('input[name="filter[time_by]"]:checked').val();
// 获取日期范围值
var daterange = $('#daterange').val();
// 构建查询参数
var params = {
'time_by': timeBy,
'daterange': daterange
};
$.ajax({
url: "statistics/dispatcher/chartData", //
type: "POST",
dataType: "json",
data:params,
success: function (response) {
// 数据结构
// response = {
// source: [
// ['产品销售', '2015', '2016', '2017'],
// ['风扇', 43.3, 85.8, 93.7],
// ...
// ]
// }
var barChart = Echarts.init(document.getElementById('bar-chart'), 'walden');
var option = {
legend: {},
tooltip: {},
dataset: {
source: response
},
xAxis: { type: 'category' },
yAxis: {},
series: [
{ type: 'bar' },
{ type: 'bar' },
{ type: 'bar' },
{ type: 'bar' }
]
};
barChart.setOption(option);
},
error: function () {
console.error("图表数据加载失败");
}
});
}
var form = $("#chart-filter");
var ranges = {};
ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];
ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];
ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')];
ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')];
ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')];
ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')];
ranges[__('今年')] = [Moment().startOf('year'), Moment().endOf('year')];
var options = {
timePicker: false,
autoUpdateInput: false,
timePickerSeconds: true,
timePicker24Hour: true,
autoApply: true,
locale: {
format: 'YYYY-MM-DD',
customRangeLabel: __("Custom Range"),
applyLabel: __("Apply"),
cancelLabel: __("Clear"),
},
ranges: ranges,
};
var callback = function (start, end) {
$(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format));
};
require(['bootstrap-daterangepicker'], function () {
$(".datetimerange", form).each(function () {
$(this).on('apply.daterangepicker', function (ev, picker) {
callback.call(picker, picker.startDate, picker.endDate);
var label = picker.chosenLabel;
$(picker.element).data('label', label).trigger("change");
});
$(this).on('cancel.daterangepicker', function (ev, picker) {
$(this).val('');
});
$(this).daterangepicker($.extend({}, options), callback);
});
});
// 手动触发一次激活 tab 的 shown.bs.tab
getChartData();
// 绑定查询按钮的点击事件
$('#filter-btn').on('click', function() {
getChartData();
});
}, },
add: function () { add: function () {
Controller.api.bindevent(); Controller.api.bindevent();
}, },