Merge remote-tracking branch 'origin/develop' into feature/hant
# Conflicts: # application/admin/controller/orders/Dispatch2.php
This commit is contained in:
commit
808c8801d3
|
|
@ -30,6 +30,7 @@ class OrderDispatchLog
|
|||
'status' => $dispatch->status,
|
||||
'status_text' => $statusList[$dispatch->status],
|
||||
'remark' => $remark,
|
||||
'images' => $dispatch->record_images??'',
|
||||
'admin_user' => $dispatch->admin_user??'系统',
|
||||
];
|
||||
\app\admin\model\OrderDispatchLog::create($data);
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ class Ajax extends Backend
|
|||
$where['level'] = 3;
|
||||
}
|
||||
}
|
||||
$provincelist = Db::name('areas')->where($where)->field('id as value,name')->select();
|
||||
$provincelist = Db::name('areas')->where($where)->field('code as value,name')->select();
|
||||
$this->success('', '', $provincelist);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class AutoDispatchLogic
|
|||
$worker = (new Worker())->where('id', $worker_id)->find();
|
||||
$insert ['worker_name'] = $worker['name'];
|
||||
$insert ['worker_tel'] = $worker['tel'];
|
||||
$insert['follow'] = 1;
|
||||
$orderDispatch = new OrderDispatch();
|
||||
$res = $orderDispatch->allowField(true)->save($insert);
|
||||
$order->status = \app\admin\model\Order::STATUS_DISPATCHED;
|
||||
|
|
|
|||
|
|
@ -808,7 +808,30 @@ class Order extends Backend
|
|||
}
|
||||
$this->request->get([config('paginate.var_page') => $page]);
|
||||
$filter = (array)json_decode($filter, true);
|
||||
|
||||
|
||||
|
||||
$province_id = $filter['province_id']??null;
|
||||
$city_id = $filter['city_id']??null;
|
||||
$area_id = $filter['city_id']??null;
|
||||
unset($filter['city_id']);
|
||||
unset($filter['province_id']);
|
||||
unset($filter['area_id']);
|
||||
|
||||
if(!empty($area_id)){
|
||||
$filter['area_id'] = $area_id;
|
||||
}else{
|
||||
if(!empty($city_id)){
|
||||
$filter['area_id'] = $city_id;
|
||||
}else{
|
||||
if(!empty($province_id)){
|
||||
$filter['area_id'] = $province_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$op = (array)json_decode($op, true);
|
||||
$op['area_id'] = 'LIKE%';
|
||||
$filter = $filter ? $filter : [];
|
||||
$where = [];
|
||||
$alias = [];
|
||||
|
|
@ -873,6 +896,15 @@ class Order extends Backend
|
|||
case 'NOT LIKE %...%':
|
||||
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
|
||||
break;
|
||||
// ✅ 新增:右匹配(like%)
|
||||
case 'LIKE%':
|
||||
$where[] = [$k, 'LIKE', "{$v}%"];
|
||||
break;
|
||||
|
||||
// ✅ 新增:左匹配(%like)
|
||||
case '%LIKE':
|
||||
$where[] = [$k, 'LIKE', "%{$v}"];
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class Auditorder extends Backend
|
|||
$list = $this->model
|
||||
->scope('tab',Order::TAB_AUDIT)
|
||||
->alias('order')
|
||||
->with(['auditadmin'])
|
||||
->with(['auditadmin','workerman'])
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->paginate($limit);
|
||||
|
|
|
|||
|
|
@ -69,16 +69,12 @@ class Dispatch2 extends Backend
|
|||
return $this->selectpage();
|
||||
}
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
|
||||
// $filter = (array)json_decode(input()['filter'] ?? '', true);
|
||||
// $type = $filter['dispatch_type'] ?? false;
|
||||
// dd($where,$filter);
|
||||
|
||||
$list = $this->model
|
||||
->with(['orderb','lastRecord'])
|
||||
->auth($this->auth)
|
||||
->where($where);
|
||||
|
||||
$list = $list->order($sort, $order)
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->paginate($limit);
|
||||
|
||||
foreach ($list as &$row) {
|
||||
|
|
@ -90,17 +86,24 @@ class Dispatch2 extends Backend
|
|||
$row->btn_record = in_array($row->status, $this->model->btnActiveStatusList('btn_record')) && $this->auth->check('orders/dispatchrecord/add');
|
||||
|
||||
if(!in_array($row->status, $this->model->btnActiveStatusList('btn_record')) ){
|
||||
//正常情况,执行不到这里来,不用担心循环执行问题
|
||||
$row->follow = 2;
|
||||
OrderDispatch::where('id',$row->id)->update(['follow'=>2]);
|
||||
}
|
||||
if($row->btn_record){
|
||||
|
||||
if($row->follow == 0 ){
|
||||
if($row->btn_record != 2){
|
||||
$row->btn_record = true;
|
||||
}else{
|
||||
$row->btn_record = false;
|
||||
}
|
||||
|
||||
/*if($row->follow == 0 ){
|
||||
$row->btn_record = true;
|
||||
}else{
|
||||
$row->btn_record = false;
|
||||
}*/
|
||||
|
||||
// if($row->type == 2)
|
||||
// {
|
||||
// $row->btn_record = false;
|
||||
|
|
@ -130,6 +133,7 @@ class Dispatch2 extends Backend
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
$result = array("total" => $list->total(), "rows" => $list->items());
|
||||
|
||||
return json($result);
|
||||
|
|
@ -494,6 +498,7 @@ class Dispatch2 extends Backend
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 生成查询所需要的条件,排序方式
|
||||
* @param mixed $searchfields 快速查询的字段
|
||||
|
|
@ -519,7 +524,28 @@ class Dispatch2 extends Backend
|
|||
}
|
||||
$this->request->get([config('paginate.var_page') => $page]);
|
||||
$filter = (array)json_decode($filter, true);
|
||||
|
||||
$province_id = $filter['province_id']??null;
|
||||
$city_id = $filter['city_id']??null;
|
||||
$area_id = $filter['city_id']??null;
|
||||
unset($filter['city_id']);
|
||||
unset($filter['province_id']);
|
||||
unset($filter['area_id']);
|
||||
|
||||
if(!empty($area_id)){
|
||||
$filter['orderb.area_id'] = $area_id;
|
||||
}else{
|
||||
if(!empty($city_id)){
|
||||
$filter['orderb.area_id'] = $city_id;
|
||||
}else{
|
||||
if(!empty($province_id)){
|
||||
$filter['orderb.area_id'] = $province_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$op = (array)json_decode($op, true);
|
||||
$op['orderb.area_id'] = 'like%';
|
||||
$filter = $filter ? $filter : [];
|
||||
$where = [];
|
||||
$alias = [];
|
||||
|
|
@ -550,9 +576,6 @@ class Dispatch2 extends Backend
|
|||
$where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
|
||||
}
|
||||
$index = 0;
|
||||
if (!isset($filter['type'])){
|
||||
$filter['type'] = 1;
|
||||
}
|
||||
foreach ($filter as $k => $v) {
|
||||
if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) {
|
||||
continue;
|
||||
|
|
@ -585,6 +608,16 @@ class Dispatch2 extends Backend
|
|||
case 'NOT LIKE %...%':
|
||||
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
|
||||
break;
|
||||
|
||||
// ✅ 新增:右匹配(like%)
|
||||
case 'LIKE%':
|
||||
$where[] = [$k, 'LIKE', "{$v}%"];
|
||||
break;
|
||||
|
||||
// ✅ 新增:左匹配(%like)
|
||||
case '%LIKE':
|
||||
$where[] = [$k, 'LIKE', "%{$v}"];
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
|
|
|
|||
|
|
@ -126,10 +126,10 @@ class Dispatchrecord extends Backend
|
|||
|
||||
$params['need_notice'] = 0;
|
||||
$params['status'] = 1;
|
||||
if(!empty($params['rate'])){ //修改任务的状态
|
||||
/* if(!empty($params['rate'])){ //修改任务的状态
|
||||
if($dispatch->status != $params['rate']){
|
||||
$dispatch->status = $params['rate'];
|
||||
$dispatch->save();
|
||||
$dispatch->save();*/
|
||||
|
||||
$groups = $this->auth->getGroups($this->auth->id);
|
||||
$groupName = '';
|
||||
|
|
@ -139,17 +139,18 @@ class Dispatchrecord extends Backend
|
|||
}
|
||||
|
||||
$dispatch->admin_user = $groupName.':'. $this->auth->nickname;
|
||||
$dispatch->record_images = $params['images'];
|
||||
$hookParams = [
|
||||
'dispatch' => $dispatch,
|
||||
'remark' => '人工跟进,备注内容:'.$params['remark'],
|
||||
'remark' => '跟进订单,跟进内容:'.$params['remark'],
|
||||
];
|
||||
Hook::listen('order_dispatch_change', $hookParams);
|
||||
|
||||
if($params['rate'] == 10){
|
||||
/* if($params['rate'] == 10){
|
||||
$dispatch->got_time = date('Y-m-d H:i:s', time());
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
/* }
|
||||
}*/
|
||||
$dispatch->follow = 1;
|
||||
}
|
||||
$dispatch->record_count ++;
|
||||
|
|
|
|||
|
|
@ -167,6 +167,28 @@ class Revisitorder extends Backend
|
|||
$op['revisit_id'] = '=';
|
||||
}
|
||||
|
||||
|
||||
$province_id = $filter['province_id']??null;
|
||||
$city_id = $filter['city_id']??null;
|
||||
$area_id = $filter['city_id']??null;
|
||||
unset($filter['city_id']);
|
||||
unset($filter['province_id']);
|
||||
unset($filter['area_id']);
|
||||
|
||||
if(!empty($area_id)){
|
||||
$filter['area_id'] = $area_id;
|
||||
}else{
|
||||
if(!empty($city_id)){
|
||||
$filter['area_id'] = $city_id;
|
||||
}else{
|
||||
if(!empty($province_id)){
|
||||
$filter['area_id'] = $province_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
$op['area_id'] = 'LIKE%';
|
||||
|
||||
|
||||
/* if($returnvalue>0){
|
||||
$op['aftersale_id'] = '>';
|
||||
$op['status'] = '70';
|
||||
|
|
@ -237,6 +259,15 @@ class Revisitorder extends Backend
|
|||
case 'NOT LIKE %...%':
|
||||
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
|
||||
break;
|
||||
// ✅ 新增:右匹配(like%)
|
||||
case 'LIKE%':
|
||||
$where[] = [$k, 'LIKE', "{$v}%"];
|
||||
break;
|
||||
|
||||
// ✅ 新增:左匹配(%like)
|
||||
case '%LIKE':
|
||||
$where[] = [$k, 'LIKE', "%{$v}"];
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
|
|
|
|||
|
|
@ -137,6 +137,8 @@ class Dispatcher extends Backend
|
|||
// 使用 IFNULL 确保结果为 null 时返回 0
|
||||
"IFNULL(COUNT(CASE WHEN status = 60 THEN 1 END), 0) AS finish_num", //完成数
|
||||
"IFNULL(COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END), 0) AS count_num", //总订单数 (排除取消 和草稿)
|
||||
"IFNULL(COUNT(CASE WHEN is_overtime = 1 THEN 1 END), 0) AS overtime_num", //超时数
|
||||
|
||||
"IFNULL(SUM(CASE WHEN status = 60 THEN total END), 0) AS total", //成效额
|
||||
"IFNULL(SUM(CASE WHEN status = 60 THEN performance END), 0) AS performance", //业绩
|
||||
"IFNULL(SUM(CASE WHEN status = 60 THEN (cost + material_cost) END), 0) AS cost_total", //总成本
|
||||
|
|
@ -196,6 +198,8 @@ class Dispatcher extends Backend
|
|||
$datum->performance_avg = $this->_calc($datum->performance,$datum->finish_num,2);
|
||||
//客单价 = 总成效额 / 完单数
|
||||
$datum->total_avg = $this->_calc($datum->total,$datum->finish_num,2);
|
||||
//超时率
|
||||
$datum->overtime_rate = $this->_calc($datum->overtime_num,$datum->count_num,4,true);
|
||||
|
||||
if(!empty($datum->dispatch_admin_id)){
|
||||
$datum->admin_user = Admin::where('id',$datum->dispatch_admin_id)->value('nickname')??'系统';
|
||||
|
|
|
|||
|
|
@ -301,8 +301,7 @@ class Worker extends Backend
|
|||
$datum->arrive_rate = $this->_calc($datum->arrive_count,$datum->get_count,4,true);
|
||||
//好评率
|
||||
$datum->good_rate = $this->_calc($datum->good_count,$datum->finish_num,4,true);
|
||||
|
||||
//及时联系率
|
||||
//及时联系率=(已预约上门数/已接单数)。
|
||||
$datum->get_time_rate = $this->_calc($datum->get_js_count,$datum->get_count,4,true);
|
||||
|
||||
|
||||
|
|
@ -354,7 +353,31 @@ class Worker extends Backend
|
|||
$this->request->get([config('paginate.var_page') => $page]);
|
||||
$filter = (array)json_decode($filter, true);
|
||||
unset($filter['daterange']);
|
||||
|
||||
|
||||
|
||||
$province_id = $filter['province_id']??null;
|
||||
$city_id = $filter['city_id']??null;
|
||||
$area_id = $filter['city_id']??null;
|
||||
unset($filter['city_id']);
|
||||
unset($filter['province_id']);
|
||||
unset($filter['area_id']);
|
||||
|
||||
if(!empty($area_id)){
|
||||
$filter['fa_worker.area_id'] = $area_id;
|
||||
}else{
|
||||
if(!empty($city_id)){
|
||||
$filter['fa_worker.area_id'] = $city_id;
|
||||
}else{
|
||||
if(!empty($province_id)){
|
||||
$filter['fa_worker.area_id'] = $province_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$op = (array)json_decode($op, true);
|
||||
$op['fa_worker.area_id'] = 'LIKE%';
|
||||
|
||||
$filter = $filter ? $filter : [];
|
||||
$where = [];
|
||||
$alias = [];
|
||||
|
|
@ -417,6 +440,15 @@ class Worker extends Backend
|
|||
case 'NOT LIKE %...%':
|
||||
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
|
||||
break;
|
||||
// ✅ 新增:右匹配(like%)
|
||||
case 'LIKE%':
|
||||
$where[] = [$k, 'LIKE', "{$v}%"];
|
||||
break;
|
||||
|
||||
// ✅ 新增:左匹配(%like)
|
||||
case '%LIKE':
|
||||
$where[] = [$k, 'LIKE', "%{$v}"];
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class Worker extends Backend
|
|||
|
||||
$area = Area::getByCode($params['area_id']);
|
||||
if($area){
|
||||
$location = getLocation($area->merge_name);
|
||||
$location = getLocation($area->merge_name.' '.$params['address']);
|
||||
if(!empty($location)){
|
||||
$params['lng'] = $location['lng'];
|
||||
$params['lat'] = $location['lat'];
|
||||
|
|
|
|||
|
|
@ -262,4 +262,9 @@ class Order extends Model
|
|||
return $query;
|
||||
}
|
||||
|
||||
|
||||
public function workerman(){
|
||||
return $this->belongsTo(Worker::class,'worker_id',);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
14
application/admin/view/common/area_select.html
Normal file
14
application/admin/view/common/area_select.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script id="categorytpl" type="text/html">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select style="width: 80px;" class="province form-control" name="province_id" data-url="ajax/area"></select>
|
||||
<select style="width: 80px;" class="city form-control" name="city_id" data-url="ajax/area" data-query-name="province"></select>
|
||||
<select style="width: 90px;" class="area form-control" name="area_id" data-url="ajax/area" data-query-name="city"></select>
|
||||
<input type="hidden" class="operate" data-name="province_id" value="like%" />
|
||||
<input type="hidden" class="operate" data-name="city_id" value="like%" />
|
||||
<input type="hidden" class="operate" data-name="area_id" value="like%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
|
@ -125,3 +125,20 @@
|
|||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<script id="categorytpl" type="text/html">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select style="width: 25%;" class="province form-control" name="province_id" data-url="ajax/area"></select>
|
||||
<select style="width: 30%;" class="city form-control" name="city_id" data-url="ajax/area" data-query-name="province"></select>
|
||||
<select style="width:auto" class="area form-control" name="area_id" data-url="ajax/area" data-query-name="city"></select>
|
||||
<input type="hidden" class="operate" data-name="province_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="city_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="area_id" value="LIKE%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,40 @@
|
|||
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('师傅收款码')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input readonly id="c-worker_images" class="form-control" size="50" value="{$worker.images}" type="text">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<!-- <span><button type="button" id="faupload-worker_images" class="btn btn-danger faupload" data-input-id="c-worker_images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-worker_images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
<span><button type="button" id="fachoose-worker_images" class="btn btn-primary fachoose" data-input-id="c-worker_images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>-->
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-worker_images"></span>
|
||||
</div>
|
||||
<ul class="row list-inline faupload-preview" id="p-worker_images"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('转账凭证')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input id="c-trans_images" class="form-control" size="50" value="{$row.trans_images}" name="row[trans_images]" type="text">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="faupload-trans_images" class="btn btn-danger faupload" data-input-id="c-trans_images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-trans_images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
<span><button type="button" id="fachoose-trans_images" class="btn btn-primary fachoose" data-input-id="c-trans_images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-trans_images"></span>
|
||||
</div>
|
||||
<ul class="row list-inline faupload-preview" id="p-trans_images"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('审核状态')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
|
|
@ -187,6 +221,7 @@
|
|||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Audit_remark')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
|
|
|
|||
|
|
@ -54,3 +54,22 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script id="categorytpl" type="text/html">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select style="width: 25%;" class="province form-control" name="province_id" data-url="ajax/area"></select>
|
||||
<select style="width: 30%;" class="city form-control" name="city_id" data-url="ajax/area" data-query-name="province"></select>
|
||||
<select style="width:auto" class="area form-control" name="area_id" data-url="ajax/area" data-query-name="city"></select>
|
||||
<input type="hidden" class="operate" data-name="province_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="city_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="area_id" value="LIKE%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<div id="image-preview-overlay" style="display:none;position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.6);z-index:9999;justify-content:center;align-items:center;">
|
||||
<img id="image-preview-img" src="" style="max-width:90%;max-height:90%;box-shadow:0 0 20px #000;border-radius:6px;" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.progress-images img:hover {
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const logs = {$logs}; // 后端传入的数据,格式保持和你的一致
|
||||
|
||||
|
|
@ -129,9 +141,10 @@
|
|||
return `
|
||||
<div class="timeline-progress-item">
|
||||
<span class="progress-time">${progress.create_time}</span>
|
||||
<span class="progress-user">${progress.status_text}</span>
|
||||
<span class="progress-user">${progress.status_text}</span>
|
||||
<span class="progress-user">${innerUserDisplay}</span>
|
||||
<span class="progress-remark">${progress.remark || '无内容'}</span>
|
||||
${renderProgressImages(progress.images)}
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
|
@ -152,4 +165,45 @@
|
|||
}
|
||||
|
||||
renderTimeline(logs);
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const overlay = document.getElementById('image-preview-overlay');
|
||||
const previewImg = document.getElementById('image-preview-img');
|
||||
|
||||
// 事件委托:图片点击弹窗
|
||||
document.body.addEventListener('click', function (e) {
|
||||
if (e.target.tagName === 'IMG' && e.target.dataset.preview === 'true') {
|
||||
previewImg.src = e.target.src;
|
||||
overlay.style.display = 'flex';
|
||||
}
|
||||
});
|
||||
|
||||
// 点击遮罩关闭
|
||||
overlay.addEventListener('click', function () {
|
||||
overlay.style.display = 'none';
|
||||
previewImg.src = '';
|
||||
});
|
||||
});
|
||||
|
||||
function renderProgressImages(imageStr) {
|
||||
if (!imageStr || typeof imageStr !== 'string') return '';
|
||||
|
||||
const imageList = imageStr.split(',')
|
||||
.map(url => url.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (!imageList.length) return '';
|
||||
|
||||
return `
|
||||
<div class="progress-images" style="margin-top: 6px;">
|
||||
${imageList.map(img => `
|
||||
<img src="${img}" data-preview="true"
|
||||
style="width:40px;height:40px;border-radius:4px;border:1px solid #ccc;margin-right:5px;"
|
||||
onerror="this.style.display='none'" />
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<label class="control-label col-xs-12 col-sm-2">{:__('跟进依据')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input id="c-images" class="form-control" size="50" name="row[images]" type="text">
|
||||
<input data-rule="required" id="c-images" class="form-control" size="50" name="row[images]" type="text">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="faupload-images" class="btn btn-danger faupload" data-input-id="c-images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
<span><button type="button" id="fachoose-images" class="btn btn-primary fachoose" data-input-id="c-images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
{if condition='$dispatch.type eq 1'}
|
||||
|
||||
|
||||
<!--
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('任务进度')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
|
|
@ -54,12 +55,13 @@
|
|||
<label><input type="radio" {if condition="$dispatch.status eq 30"}checked{/if} name="row[rate]" value="30"> 服务中</label>
|
||||
</div>
|
||||
|
||||
<!-- const STATUS_GOTIT = 10; //已接-->
|
||||
<!-- const STATUS_PLANIT = 20; //已预约-->
|
||||
<!-- const STATUS_OVERTIME = 25; //超时(过了预约时间)-->
|
||||
<!-- const STATUS_CLOCK = 30; //已打卡-->
|
||||
<!– const STATUS_GOTIT = 10; //已接–>
|
||||
<!– const STATUS_PLANIT = 20; //已预约–>
|
||||
<!– const STATUS_OVERTIME = 25; //超时(过了预约时间)–>
|
||||
<!– const STATUS_CLOCK = 30; //已打卡–>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
|
|
@ -70,6 +72,9 @@
|
|||
<label><input type="radio" name="row[notice_time]" value="2"> 2天后</label>
|
||||
<label><input type="radio" name="row[notice_time]" value="3"> 3天后</label>
|
||||
<label><input type="radio" name="row[notice_time]" value="4"> 4天后</label>
|
||||
<label><input type="radio" name="row[notice_time]" value="5"> 5天后</label>
|
||||
<label><input type="radio" name="row[notice_time]" value="6"> 6天后</label>
|
||||
<label><input type="radio" name="row[notice_time]" value="7"> 7天后</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -44,3 +44,19 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script id="categorytpl" type="text/html">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select style="width: 25%;" class="province form-control" name="province_id" data-url="ajax/area"></select>
|
||||
<select style="width: 30%;" class="city form-control" name="city_id" data-url="ajax/area" data-query-name="province"></select>
|
||||
<select style="width:auto" class="area form-control" name="area_id" data-url="ajax/area" data-query-name="city"></select>
|
||||
<input type="hidden" class="operate" data-name="province_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="city_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="area_id" value="LIKE%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -340,3 +340,20 @@
|
|||
</div>
|
||||
</div>
|
||||
</script>-->
|
||||
|
||||
|
||||
<script id="categorytpl" type="text/html">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select style="width: 25%;" class="province form-control" name="province_id" data-url="ajax/area"></select>
|
||||
<select style="width: 30%;" class="city form-control" name="city_id" data-url="ajax/area" data-query-name="province"></select>
|
||||
<select style="width:auto" class="area form-control" name="area_id" data-url="ajax/area" data-query-name="city"></select>
|
||||
<input type="hidden" class="operate" data-name="province_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="city_id" value="LIKE%" />
|
||||
<input type="hidden" class="operate" data-name="area_id" value="LIKE%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@
|
|||
<input id="area_id" style="display: none" class="form-control" name="row[area_id]" hidden type="text" value="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('详细地址')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input id="c-address" data-rule="required" class="form-control" name="row[address]" type="text" value="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">师傅归属:</label>
|
||||
<div class='col-xs-12 col-sm-8'>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@
|
|||
value="{$row.area_id}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('详细地址')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input id="c-address" data-rule="required" class="form-control" name="row[address]" type="text" value="{$row.address}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">师傅归属:</label>
|
||||
<div class='col-xs-12 col-sm-8'>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use think\Hook;
|
|||
class CheckOrderDispatchGotCommand extends Command
|
||||
{
|
||||
protected $title = '【自动派单未接单检测,五分钟未接单,重派派单】/【自动派接单五分钟未预约,重新派单】/【自动派单上门时间已到,未完成上门】,每分钟执行一次';
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('check:dispatch-toget')
|
||||
|
|
@ -27,6 +28,8 @@ class CheckOrderDispatchGotCommand extends Command
|
|||
$this->_toget();
|
||||
$this->_toplan();
|
||||
$this->_toarrive();
|
||||
$this->_tofinished();
|
||||
|
||||
$output->info('OVER');
|
||||
}
|
||||
|
||||
|
|
@ -127,4 +130,23 @@ class CheckOrderDispatchGotCommand extends Command
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private function _tofinished(): void
|
||||
{
|
||||
|
||||
//https://f1jo9ghdket.feishu.cn/wiki/PCK8wtWnSihQrukCRq1c3nCynyd
|
||||
//5.自动订单派单完之后不需要进入待跟进状态,当师傅确认上门之后10分钟之内没有更新进度(首次更新进度),则需要进入待跟进状态,需要人为跟进。
|
||||
|
||||
$Model = new OrderDispatch();
|
||||
$now = date('Y-m-d H:i:s', time() -600); //创建三十分名以
|
||||
$count = $Model->where('status', OrderDispatch::STATUS_CLOCK)
|
||||
->where('type', 2)
|
||||
->where('follow', 1)
|
||||
->whereNull('estimated_finish_time')
|
||||
->where('arrive_time', '<=', $now)
|
||||
->update(['follow'=>0]);
|
||||
|
||||
echo '已上门未更新:'. $count. PHP_EOL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -278,6 +278,26 @@ class Backend extends Controller
|
|||
}
|
||||
$this->request->get([config('paginate.var_page') => $page]);
|
||||
$filter = (array)json_decode($filter, true);
|
||||
|
||||
$province_id = $filter['province_id']??null;
|
||||
$city_id = $filter['city_id']??null;
|
||||
$area_id = $filter['city_id']??null;
|
||||
unset($filter['city_id']);
|
||||
unset($filter['province_id']);
|
||||
unset($filter['area_id']);
|
||||
|
||||
if(!empty($area_id)){
|
||||
$filter['area_id'] = $area_id;
|
||||
}else{
|
||||
if(!empty($city_id)){
|
||||
$filter['area_id'] = $city_id;
|
||||
}else{
|
||||
if(!empty($province_id)){
|
||||
$filter['area_id'] = $province_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$op = (array)json_decode($op, true);
|
||||
$filter = $filter ? $filter : [];
|
||||
$where = [];
|
||||
|
|
@ -341,6 +361,15 @@ class Backend extends Controller
|
|||
case 'NOT LIKE %...%':
|
||||
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
|
||||
break;
|
||||
// ✅ 新增:右匹配(like%)
|
||||
case 'LIKE%':
|
||||
$where[] = [$k, 'LIKE', "{$v}%"];
|
||||
break;
|
||||
|
||||
// ✅ 新增:左匹配(%like)
|
||||
case '%LIKE':
|
||||
$where[] = [$k, 'LIKE', "%{$v}"];
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
|
|
|
|||
|
|
@ -210,6 +210,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
addclass: 'datetimerange',
|
||||
autocomplete: false
|
||||
},
|
||||
|
||||
{field: 'area', title: __('地区'), searchList: function (column) {
|
||||
return Template('categorytpl', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
}, visible: false
|
||||
},
|
||||
|
||||
{
|
||||
field: 'operate',
|
||||
title: __('Operate'),
|
||||
|
|
@ -225,6 +233,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
title: __('Edit'),
|
||||
extend: 'data-toggle="tooltip" data-container="body"',
|
||||
classname: 'btn btn-xs btn-info btn-editone',
|
||||
dropdown: "更多",
|
||||
visible: function (row) {
|
||||
if (row.status != 60 && row.status != 70) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|||
{field: 'cost', title: __('Cost'), operate:false},
|
||||
{field: 'material_cost', title: __('材料成本'), operate:false},
|
||||
{field: 'performance', title: __('Performance'), operate:false},
|
||||
|
||||
{field: 'workerman.images', title: __('师傅收款码'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images},
|
||||
{field: 'trans_images', title: __('转账凭证'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images},
|
||||
|
||||
// {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_admin_id', title: __('Audit_admin_id')},
|
||||
|
|
|
|||
|
|
@ -94,8 +94,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form','layer'], function ($,
|
|||
},
|
||||
|
||||
|
||||
{field: 'got_time', title: __('接单时间'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
|
||||
|
||||
{field: 'plan_time', title: __('Plan_time'), operate:false, addclass:'datetimerange', autocomplete:false,
|
||||
{field: 'plan_time', title: __('Plan_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false,
|
||||
formatter:function(value,row,index){
|
||||
if(row.status == 25){
|
||||
return' <span style="color:red;font-weight: bold">'+value+'</span>';
|
||||
|
|
@ -123,11 +124,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form','layer'], function ($,
|
|||
|
||||
//{field: 'order.source_shop', title: __('Order.source_shop'), operate: '='},
|
||||
// {field: 'order.source', title: __('Order.source')},
|
||||
{field: 'orderb.customer', title: __('Order.customer'), operate: false},
|
||||
{field: 'orderb.customer', title: __('Order.customer'), operate: 'like'},
|
||||
{field: 'orderb.tel', title: __('Order.tel'), operate: 'like'},
|
||||
{field: 'orderb.address', title: __('Order.address'), operate: false, table: table, class: 'autocontent', formatter: Table.api.formatter.content},
|
||||
|
||||
{field: 'orderb.item_title', title: __('Order.item_title'), operate: false},
|
||||
{field: 'orderb.item_title', title: __('Order.item_title'), operate: 'like'},
|
||||
{field: 'orderb.detail', title: __('Order.detail'), operate: false, table: table, class: 'autocontent', formatter: Table.api.formatter.content},
|
||||
|
||||
{field: 'order.images', title: __('Order.images'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images},
|
||||
|
|
@ -153,6 +154,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form','layer'], function ($,
|
|||
//{field: 'update_time', title: __('Update_time'), operate:false, addclass:'datetimerange', autocomplete:false},
|
||||
{field: 'finish_time', title: __('Finish_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
|
||||
|
||||
{field: 'area', title: __('地区'), searchList: function (column) {
|
||||
return Template('categorytpl', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
}, visible: false
|
||||
},
|
||||
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate,
|
||||
|
||||
align:'left',
|
||||
|
|
|
|||
|
|
@ -122,6 +122,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|||
|
||||
//{field: 'review.admin_id', title: __('Review.admin_id')},
|
||||
|
||||
{field: 'area', title: __('地区'), searchList: function (column) {
|
||||
return Template('categorytpl', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
}, visible: false
|
||||
},
|
||||
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate,
|
||||
formatter: Table.api.formatter.operate,
|
||||
buttons:[
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
|||
{field: 'total_avg', title: __('客单价(¥)'), operate: false},
|
||||
|
||||
{field: 'avg_time_diff', title: __('派单时效(小时)'), operate: false},
|
||||
{field: 'overtime_num', title: __('派单超时数'), operate: false},
|
||||
{field: 'overtime_rate', title: __('派单超时率(%)'), operate: false},
|
||||
|
||||
//{field: 'admin_user', title: __('派单员'),operate: "LIKE",visible:false},
|
||||
//{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false},
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
|||
{field: 'cash_value', title: __('变现值'), operate: false},
|
||||
{field: 'refuse_rate', title: __('拒单率(%)'), operate: false},
|
||||
{field: 'arrive_rate', title: __('上门率(%)'), operate: false},
|
||||
{field: 'get_time_rate', title: __('接单及时率(%)'), operate: false},
|
||||
{field: 'get_time_rate', title: __('及时联系率(%)'), operate: false},
|
||||
|
||||
{field: 'good_rate', title: __('好评率(%)'), operate: false},
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
|||
}
|
||||
},
|
||||
*/
|
||||
{field: 'area2.merge_name', title: __('地区'),operate: 'LIKE',visible:false},
|
||||
{field: 'area2.merge_name', title: __('地区'),operate: false},
|
||||
|
||||
{field: 'daterange', title: __('时间筛选'), addclass:'datetimerange',
|
||||
autocomplete:false,
|
||||
|
|
@ -74,6 +74,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
|||
defaultValue: Config.default_daterange
|
||||
},
|
||||
|
||||
{field: 'area', title: __('地区'), searchList: function (column) {
|
||||
return Template('categorytpl', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
}, visible: false
|
||||
},
|
||||
|
||||
{field: 'operate', title: __('Operate'), table: table2, events: Table.api.events.operate, formatter: Table.api.formatter.operate,
|
||||
buttons: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'],
|
|||
//{field: 'lng', title: __('Lng'), operate:'BETWEEN'},
|
||||
//{field: 'lat', title: __('Lat'), operate:'BETWEEN'},
|
||||
{field: 'area.short_merge_name', title: __('Area.short_merge_name'), searchable: false},
|
||||
{field: 'address', title: __('地址'), searchable: false},
|
||||
{field: 'rate', title: '分成'},
|
||||
{field: 'rate_remark', title: '分成备注'},
|
||||
{field: 'remark', title: '备注'},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user