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

# Conflicts:
#	application/admin/controller/orders/Dispatch2.php
This commit is contained in:
hant 2025-06-16 20:59:45 +08:00
commit 808c8801d3
31 changed files with 455 additions and 33 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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 '<':

View File

@ -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);

View File

@ -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 '<':

View File

@ -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 ++;

View File

@ -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 '<':

View File

@ -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')??'系统';

View File

@ -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 '<':

View File

@ -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'];

View File

@ -262,4 +262,9 @@ class Order extends Model
return $query;
}
public function workerman(){
return $this->belongsTo(Worker::class,'worker_id',);
}
}

View 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>

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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; //已打卡-->
&lt;!&ndash; const STATUS_GOTIT = 10; //已接&ndash;&gt;
&lt;!&ndash; const STATUS_PLANIT = 20; //已预约&ndash;&gt;
&lt;!&ndash; const STATUS_OVERTIME = 25; //超时(过了预约时间)&ndash;&gt;
&lt;!&ndash; const STATUS_CLOCK = 30; //已打卡&ndash;&gt;
</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>

View File

@ -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>

View File

@ -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>

View File

@ -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'>

View File

@ -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'>

View File

@ -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;
}
}

View File

@ -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 '<':

View File

@ -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;

View File

@ -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')},

View File

@ -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',

View File

@ -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:[

View File

@ -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},

View File

@ -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: [
{

View File

@ -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: '备注'},