Przeglądaj źródła

Merge branch 'master' of e.coding.net:zdap/weixiu/weixiu_api into wait-master

liugc 1 rok temu
rodzic
commit
d2fd1ac643
30 zmienionych plików z 1590 dodań i 41 usunięć
  1. 108 0
      app/adminapi/controller/goods_time/GoodsTimeController.php
  2. 43 0
      app/adminapi/controller/works/WorkerServiceWorkController.php
  3. 106 0
      app/adminapi/lists/goods_time/GoodsTimeLists.php
  4. 25 3
      app/adminapi/lists/master_worker/MasterWorkerTeamLists.php
  5. 1 1
      app/adminapi/lists/works/ServiceWorkLists.php
  6. 168 0
      app/adminapi/lists/works/WorkerServiceWorkLists.php
  7. 127 0
      app/adminapi/logic/goods_time/GoodsTimeLogic.php
  8. 20 2
      app/adminapi/logic/master_worker/MasterWorkerLogic.php
  9. 46 6
      app/adminapi/logic/master_worker/MasterWorkerTeamLogic.php
  10. 6 0
      app/adminapi/logic/master_worker_register/MasterWorkerRegisterLogic.php
  11. 61 25
      app/adminapi/logic/works/ServiceWorkLogic.php
  12. 101 0
      app/adminapi/validate/goods_time/GoodsTimeValidate.php
  13. 2 2
      app/adminapi/validate/master_worker/MasterWorkerTeamValidate.php
  14. 2 0
      app/api/logic/GoodsReviewsLogic.php
  15. 24 0
      app/common.php
  16. 294 0
      app/common/command/AutomaticDispatch.php
  17. 55 0
      app/common/command/CancelDispatch.php
  18. 241 0
      app/common/command/UpdateWorkerScore.php
  19. 34 0
      app/common/model/goods_time/GoodsTime.php
  20. 9 2
      app/common/model/master_worker/MasterWorker.php
  21. 9 0
      app/common/model/master_worker/MasterWorkerScore.php
  22. 9 0
      app/common/model/master_worker/MasterWorkerServiceTime.php
  23. 10 0
      app/common/model/works/ServiceWork.php
  24. 17 0
      app/common/model/works/ServiceWorkReceiveLog.php
  25. 19 0
      app/workerapi/controller/WorksController.php
  26. 1 0
      app/workerapi/logic/MasterWorkerTeamLogic.php
  27. 36 0
      app/workerapi/logic/ServiceWorkReceiveLogLogic.php
  28. 1 0
      app/workerapi/logic/ServiceWorkerAllocateWorkerLogic.php
  29. 9 0
      app/workerapi/validate/ServiceWorkValidate.php
  30. 6 0
      config/console.php

+ 108 - 0
app/adminapi/controller/goods_time/GoodsTimeController.php

@@ -0,0 +1,108 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+
+namespace app\adminapi\controller\goods_time;
+
+
+use app\adminapi\controller\BaseAdminController;
+use app\adminapi\lists\goods_time\GoodsTimeLists;
+use app\adminapi\logic\goods_time\GoodsTimeLogic;
+use app\adminapi\validate\goods_time\GoodsTimeValidate;
+
+
+/**
+ * GoodsTime控制器
+ * Class GoodsTimeController
+ * @package app\adminapi\controller\goods_time
+ */
+class GoodsTimeController extends BaseAdminController
+{
+
+
+    /**
+     * @notes 获取列表
+     * @return \think\response\Json
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function lists()
+    {
+        return $this->dataLists(new GoodsTimeLists());
+    }
+
+
+    /**
+     * @notes 添加
+     * @return \think\response\Json
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function add()
+    {
+        $params = (new GoodsTimeValidate())->post()->goCheck('add');
+        $result = GoodsTimeLogic::add($params);
+        if (true === $result) {
+            return $this->success('添加成功', [], 1, 1);
+        }
+        return $this->fail(GoodsTimeLogic::getError());
+    }
+
+
+    /**
+     * @notes 编辑
+     * @return \think\response\Json
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function edit()
+    {
+        $params = (new GoodsTimeValidate())->post()->goCheck('edit');
+        $result = GoodsTimeLogic::edit($params);
+        if (true === $result) {
+            return $this->success('编辑成功', [], 1, 1);
+        }
+        return $this->fail(GoodsTimeLogic::getError());
+    }
+
+
+    /**
+     * @notes 删除
+     * @return \think\response\Json
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function delete()
+    {
+        $params = (new GoodsTimeValidate())->post()->goCheck('delete');
+        GoodsTimeLogic::delete($params);
+        return $this->success('删除成功', [], 1, 1);
+    }
+
+
+    /**
+     * @notes 获取详情
+     * @return \think\response\Json
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function detail()
+    {
+        $params = (new GoodsTimeValidate())->goCheck('detail');
+        $result = GoodsTimeLogic::detail($params);
+        return $this->data($result);
+    }
+
+
+}

+ 43 - 0
app/adminapi/controller/works/WorkerServiceWorkController.php

@@ -0,0 +1,43 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+
+namespace app\adminapi\controller\works;
+
+
+use app\adminapi\controller\BaseAdminController;
+use app\adminapi\lists\works\WorkerServiceWorkLists;
+
+
+/**
+ * ServiceWork控制器
+ * Class WorksController
+ * @package app\adminapi\controller\works
+ */
+class WorkerServiceWorkController extends BaseAdminController
+{
+
+
+    /**
+     * @notes 获取列表
+     * @return \think\response\Json
+     * @author likeadmin
+     * @date 2024/07/10 15:06
+     */
+    public function lists()
+    {
+        return $this->dataLists(new WorkerServiceWorkLists());
+    }
+
+}

+ 106 - 0
app/adminapi/lists/goods_time/GoodsTimeLists.php

@@ -0,0 +1,106 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\lists\goods_time;
+
+
+use app\adminapi\lists\BaseAdminDataLists;
+use app\common\model\goods_time\GoodsTime;
+use app\common\lists\ListsSearchInterface;
+
+
+/**
+ * GoodsTime列表
+ * Class GoodsTimeLists
+ * @package app\adminapi\listsgoods_time
+ */
+class GoodsTimeLists extends BaseAdminDataLists implements ListsSearchInterface
+{
+
+
+    /**
+     * @notes 设置搜索条件
+     * @return \string[][]
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function setSearch(): array
+    {
+        return [
+            '=' => ['service_time'],
+        ];
+    }
+    
+    public function queryWhereRaw(){
+        $where = '1=1';
+
+        if(isset($this->params['goods_category_ids']) && !empty($this->params['goods_category_ids'])){
+            $sqls = [];
+            $goods_category_ids =[];
+            foreach ($this->params['goods_category_ids'] as $val){
+                ($val = json_decode($val,true))?($goods_category_ids[] = end($val)):($goods_category_ids[] = $val);
+            }
+            foreach ($goods_category_ids as $item) {
+                $sqls[] = "FIND_IN_SET({$item}, goods_category_ids) > 0";
+            }
+            $where = implode(' OR ', $sqls);
+        }
+        return $where;
+    }
+
+    public function queryWhere(){
+        $where = [];
+        if(isset($this->params['title']) && !empty($this->params['title'])){
+            $where[] = ['title', 'like','%' .$this->params['title'] . '%'];
+        }
+        return $where;
+    }
+
+    /**
+     * @notes 获取列表
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function lists(): array
+    {
+        $list = GoodsTime::where($this->searchWhere)
+            ->where($this->queryWhere())
+            ->whereRaw($this->queryWhereRaw())
+            ->field(['id', 'title','service_time', 'goods_category_ids'])
+            ->limit($this->limitOffset, $this->limitLength)
+            ->order(['id' => 'desc'])
+            ->select()
+            ->toArray();
+        foreach($list as &$item) {
+            $item['goods_category_ids'] = explode(',', $item['goods_category_ids']);
+        }
+        return $list;
+    }
+
+    /**
+     * @notes 获取数量
+     * @return int
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function count(): int
+    {
+        return GoodsTime::where($this->searchWhere)->count();
+    }
+
+}

+ 25 - 3
app/adminapi/lists/master_worker/MasterWorkerTeamLists.php

@@ -38,11 +38,27 @@ class MasterWorkerTeamLists extends BaseAdminDataLists implements ListsSearchInt
     public function setSearch(): array
     {
         return [
-            '=' => ['team_name', 'master_worker_id','tenant_id'],
+            '=' => ['team_name', 'master_worker_id','tenant_id','accept_order_status']
 
         ];
     }
 
+    public function queryWhereRaw(){
+        $where = '1=1';
+
+        if(isset($this->params['goods_category_ids']) && !empty($this->params['goods_category_ids'])){
+            $sqls = [];
+            $goods_category_ids =[];
+            foreach ($this->params['goods_category_ids'] as $val){
+                ($val = json_decode($val,true))?($goods_category_ids[] = end($val)):($goods_category_ids[] = $val);
+            }
+            foreach ($goods_category_ids as $item) {
+                $sqls[] = "FIND_IN_SET({$item}, goods_category_ids) > 0";
+            }
+            $where = implode(' OR ', $sqls);
+        }
+        return $where;
+    }
 
     /**
      * @notes 获取列表
@@ -55,13 +71,19 @@ class MasterWorkerTeamLists extends BaseAdminDataLists implements ListsSearchInt
      */
     public function lists(): array
     {
-        return MasterWorkerTeam::with(['masterWorker'])->where($this->searchWhere)
-            ->field(['id', 'team_name', 'master_worker_id','tenant_id'])
+        $list = MasterWorkerTeam::with(['masterWorker'])
+            ->whereRaw($this->queryWhereRaw())    
+            ->where($this->searchWhere)
+            ->field(['id','tenant_id', 'team_name', 'master_worker_id','accept_order_status','goods_category_ids','min_order','am_limit','pm_limit','city','area_name'])
             ->append(['master_worker_name'])
             ->limit($this->limitOffset, $this->limitLength)
             ->order(['id' => 'desc'])
             ->select()
             ->toArray();
+        foreach($list as &$item) {
+            $item['goods_category_ids'] = $item['goods_category_ids'] ? explode(',', $item['goods_category_ids']) : [];
+        }
+        return $list;
     }
 
 

+ 1 - 1
app/adminapi/lists/works/ServiceWorkLists.php

@@ -177,7 +177,7 @@ class ServiceWorkLists extends BaseAdminDataLists implements ListsSearchInterfac
             ->where($this->searchWhere)
             ->where($this->queryWhere())
             ->where($this->queryDataWhere())
-            ->field(['id', 'work_sn', 'real_name', 'mobile', 'address', 'title', 'category_type', 'goods_category_ids', 'goods_category_id', 'base_service_fee', 'service_fee', 'work_status','work_pay_status', 'service_status', 'dispatch_time', 'receive_time', 'appointment_time', 'finished_images', 'finished_time', 'master_worker_id', 'work_amount', 'work_type', 'create_time', 'update_time','lon', 'lat','appoint_approval','refund_approval','finally_door_time','property_activity_id','order_effective_id'])
+            ->field(['id', 'work_sn', 'real_name', 'mobile', 'address', 'title', 'category_type', 'goods_category_ids', 'goods_category_id', 'base_service_fee', 'service_fee', 'work_status','work_pay_status', 'service_status', 'dispatch_time', 'receive_time', 'appointment_time', 'finished_images', 'finished_time', 'master_worker_id', 'work_amount', 'work_type', 'create_time', 'update_time','lon', 'lat','appoint_approval','refund_approval','finally_door_time','property_activity_id','order_effective_id,estimated_finish_time'])
             ->limit($this->limitOffset, $this->limitLength)
             ->order(['id' => 'desc'])
             ->select()

+ 168 - 0
app/adminapi/lists/works/WorkerServiceWorkLists.php

@@ -0,0 +1,168 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\lists\works;
+
+
+use app\adminapi\lists\BaseAdminDataLists;
+use app\common\model\master_worker\MasterWorker;
+use app\common\model\works\ServiceWork;
+use app\common\lists\ListsSearchInterface;
+use think\db\Query;
+
+
+/**
+ * 工程师服务工单列表
+ * Class WorkerServiceWorkLists
+ * @package app\adminapi\listsworks
+ */
+class WorkerServiceWorkLists extends BaseAdminDataLists implements ListsSearchInterface
+{
+
+    /**
+     * @notes 设置搜索条件
+     * @return \string[][]
+     * @author likeadmin
+     * @date 2024/07/10 15:06
+     */
+    public function setSearch(): array
+    {
+        return [
+            '=' => ['id','category_type', 'work_status', 'service_status', 'master_worker_id', 'work_type','city'],
+        ];
+    }
+
+    public function queryWhere(){
+        $where = [];
+        if (isset($this->params['master_worker_name']) && !empty($this->params['master_worker_name'])) {
+            $master_worker_ids = MasterWorker::where([['worker_number|mobile|real_name', 'like','%' .$this->params['master_worker_name'] . '%']])->column('id')??[0];
+            $where[] = ['master_worker_id','in' ,$master_worker_ids];
+        }
+        if(isset($this->params['workid']) && !empty($this->params['workid'])){
+            $where[] = ['master_worker_id', '=', $this->params['workid']];
+        }
+        return $where;
+    }
+
+    public function queryAndWhere(){
+        $where = [];
+        if (isset($this->params['work_sn']) && !empty($this->params['work_sn'])) {
+            $where[] = ['work_sn','=' ,$this->params['work_sn']];
+        }
+        if(isset($this->params['mobile']) && !empty($this->params['mobile'])){
+            $where[] = ['mobile', '=', $this->params['mobile']];
+        }
+        if(isset($this->params['real_name']) && !empty($this->params['real_name'])){
+            $where[] = ['real_name', 'like', '%'.$this->params['real_name'].'%'];
+        }
+        return $where;
+    }
+    /**
+     * @notes 获取列表
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author likeadmin
+     * @date 2024/07/10 15:06
+     */
+    public function lists(): array
+    {
+        $params = $this->params;
+        $list = MasterWorker::hasWhere('serviceWork', function($query) use ($params) {
+                $query->where('work_type','in',[0,1]);
+                if (isset($params['work_sn']) && !empty($params['work_sn'])) {
+                    $query->where(['work_sn','=',trim($params['work_sn'])]);
+                }
+                if (isset($params['mobile']) && !empty($params['mobile'])) {
+                    $query->where('mobile','=',trim($params['mobile']));
+                }
+                if (isset($params['real_name']) && !empty($params['real_name'])) {
+                    $query->where('real_name','like','%'.trim($params['real_name']).'%');
+                }
+                if (isset($params['appointment_time']) && !empty($params['appointment_time'])) {
+                    $query->where('appointment_time','between',[strtotime($params['appointment_time']), strtotime($params['appointment_time'].' 23:59:59')]);
+                } 
+                if (!empty($params['dispatch_time']) && is_array($params['dispatch_time'])) {
+                    $query->where('dispatch_time','between',[strtotime($params['dispatch_time'][0]), strtotime($params['dispatch_time'][1])]);
+                } 
+                if (empty($params['appointment_time']) && empty($params['dispatch_time'])) {
+                    $query->where('appointment_time','between',[strtotime(date('Y-m-d')), strtotime(date('Y-m-d 23:59:59'))]);
+                }
+            })->with(['serviceWork' => function($query) use($params) {
+                $query->where('work_type','in',[0,1]);
+                if (isset($params['work_sn']) && !empty($params['work_sn'])) {
+                    $query->where(['work_sn','=',trim($params['work_sn'])]);
+                }
+                if (isset($params['mobile']) && !empty($params['mobile'])) {
+                    $query->where('mobile','=',trim($params['mobile']));
+                }
+                if (isset($params['real_name']) && !empty($params['real_name'])) {
+                    $query->where('real_name','like','%'.trim($params['real_name']).'%');
+                }
+                if (isset($params['appointment_time']) && !empty($params['appointment_time'])) {
+                    $query->where('appointment_time','between',[strtotime($params['appointment_time']), strtotime($params['appointment_time'].' 23:59:59')]);
+                } 
+                if (!empty($params['dispatch_time']) && is_array($params['dispatch_time'])) {
+                    $query->where('dispatch_time','between',[strtotime($params['dispatch_time'][0]), strtotime($params['dispatch_time'][1])]);
+                } 
+                if (empty($params['appointment_time']) && empty($params['dispatch_time'])) {
+                    $query->where('appointment_time','between',[strtotime(date('Y-m-d')), strtotime(date('Y-m-d 23:59:59'))]);
+                }
+            }])
+            ->where($this->searchWhere)
+            ->where($this->queryWhere())
+            ->limit($this->limitOffset, $this->limitLength)
+            ->select()
+            ->toArray();
+        foreach($list as &$item) {
+            $item = [
+                'id' => $item['id'],
+                'worker_number' => $item['worker_number'],
+                'real_name' => $item['real_name'],
+                'category_ids' => empty($item['category_ids']) ? [] : explode(",",$item['category_ids']),
+                'serviceWork' => $item['serviceWork'],
+            ];
+        }
+        return $list;
+    }
+
+
+    /**
+     * @notes 获取数量
+     * @return int
+     * @author likeadmin
+     * @date 2024/07/10 15:06
+     */
+    public function count(): int
+    {
+        $params = $this->params;
+        return MasterWorker::hasWhere('serviceWork', function($query) use ($params) {
+            $query->where('work_type','in',[0,1]);
+            if (isset($params['work_sn']) && !empty($params['work_sn'])) {
+                $query->where('work_sn','=',trim($params['work_sn']));
+            }
+            if (isset($params['mobile']) && !empty($params['mobile'])) {
+                $query->where('mobile','=',trim($params['mobile']));
+            }
+            if (isset($params['real_name']) && !empty($params['real_name'])) {
+                $query->where('real_name','like','%'.trim($params['real_name']).'%');
+            }
+        })->with('serviceWork')
+        ->where($this->searchWhere)
+        ->where($this->queryWhere())
+        ->count();
+    }
+
+}

+ 127 - 0
app/adminapi/logic/goods_time/GoodsTimeLogic.php

@@ -0,0 +1,127 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\logic\goods_time;
+
+
+use app\common\model\goods_time\GoodsTime;
+use app\common\logic\BaseLogic;
+use think\facade\Db;
+
+
+/**
+ * GoodsTime逻辑
+ * Class GoodsTimeLogic
+ * @package app\adminapi\logic\goods_time
+ */
+class GoodsTimeLogic extends BaseLogic
+{
+
+
+    /**
+     * @notes 添加
+     * @param array $params
+     * @return bool
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public static function add(array $params): bool
+    {
+        if($params['goods_category_ids']){
+            foreach ($params['goods_category_ids'] as $val){
+                is_array($val)?($ids[] = end($val)):($ids[] = $val);
+            }
+            $params['goods_category_ids'] = implode(',',$ids);
+        }
+        Db::startTrans();
+        try {
+            GoodsTime::create([
+                'title' => $params['title'],
+                'service_time' => $params['service_time'],
+                'goods_category_ids' => $params['goods_category_ids'],
+            ]);
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            self::setError($e->getMessage());
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 编辑
+     * @param array $params
+     * @return bool
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public static function edit(array $params): bool
+    {
+        if($params['goods_category_ids']){
+            foreach ($params['goods_category_ids'] as $val){
+                is_array($val)?($ids[] = end($val)):($ids[] = $val);
+            }
+            $params['goods_category_ids'] = implode(',',$ids);
+        }
+        Db::startTrans();
+        try {
+            GoodsTime::where('id', $params['id'])->update([
+                'title' => $params['title'],
+                'service_time' => $params['service_time'],
+                'goods_category_ids' => $params['goods_category_ids'],
+            ]);
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            self::setError($e->getMessage());
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 删除
+     * @param array $params
+     * @return bool
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public static function delete(array $params): bool
+    {
+        return GoodsTime::destroy($params['id']);
+    }
+
+
+    /**
+     * @notes 获取详情
+     * @param $params
+     * @return array
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public static function detail($params): array
+    {
+        $info = GoodsTime::findOrEmpty($params['id'])->toArray();
+        if(!empty($info['goods_category_ids'])){
+            $info['goods_category_ids'] = explode(',',$info['goods_category_ids']);
+            $info['goods_category_ids'] = array_map('intval', $info['goods_category_ids']);
+        }
+        return $info;
+    }
+}

+ 20 - 2
app/adminapi/logic/master_worker/MasterWorkerLogic.php

@@ -17,8 +17,8 @@ namespace app\adminapi\logic\master_worker;
 
 use app\common\model\master_worker\MasterWorker;
 use app\common\logic\BaseLogic;
+use app\common\model\master_worker\MasterWorkerScore;
 use app\common\model\master_worker\MasterWorkerRetentionMoneyLog;
-use app\common\model\master_worker\MasterWorkerTeam;
 use think\db\Query;
 use think\facade\Config;
 use think\facade\Db;
@@ -44,7 +44,7 @@ class MasterWorkerLogic extends BaseLogic
     {
         Db::startTrans();
         try {
-            MasterWorker::create([
+            $masterWorker = MasterWorker::create([
                 'sn' => $params['sn'],
                 'avatar' => $params['avatar'],
                 'real_avatar' => $params['real_avatar'],
@@ -77,6 +77,11 @@ class MasterWorkerLogic extends BaseLogic
                 'labels' => (isset($params['labels']) && $params['labels'])?implode(',',$params['labels']):'',
                 'remark' => $params['remark']??'',
             ]);
+            
+            //添加工程师汇总评分数据
+            MasterWorkerScore::create([
+                'worker_id' => $masterWorker->id
+            ]);
 
             Db::commit();
             return true;
@@ -151,6 +156,19 @@ class MasterWorkerLogic extends BaseLogic
             ];
             //'tenant_id' => $params['tenant_id']??0,
             MasterWorker::where('id', $params['id'])->update($update);
+            
+            if (is_numeric($params['weight_score'])) {
+                $exists = MasterWorkerScore::where('worker_id', $params['id'])->value('id');
+                if ($exists) {
+                    MasterWorkerScore::where('worker_id',$params['id'])->update(['weight_score' => $params['weight_score']]);
+                } else {
+                    MasterWorkerScore::create([
+                        'worker_id' => $params['id'],
+                    'weight_score' => $params['weight_score'],
+                    ]);
+                }
+            }
+
             Db::commit();
             return true;
         } catch (\Exception $e) {

+ 46 - 6
app/adminapi/logic/master_worker/MasterWorkerTeamLogic.php

@@ -20,7 +20,6 @@ use app\common\model\master_worker\MasterWorkerTeam;
 use app\common\logic\BaseLogic;
 use think\facade\Db;
 
-
 /**
  * MasterWorkerTeam逻辑
  * Class MasterWorkerTeamLogic
@@ -41,15 +40,33 @@ class MasterWorkerTeamLogic extends BaseLogic
     {
         Db::startTrans();
         try {
-            $masterWorker = \app\common\model\master_worker\MasterWorker::where('id', $params['master_worker_id'])->find();
+            $masterWorker = MasterWorker::where('id', $params['master_worker_id'])->find();
             if($masterWorker['team_id']){
                 throw new \Exception('该师傅已加入团队');
             }
+
+            if($params['goods_category_ids']){
+                foreach ($params['goods_category_ids'] as $val){
+                    is_array($val)?($ids[] = end($val)):($ids[] = $val);
+                }
+                $params['goods_category_ids'] = implode(',',$ids);
+            }
+
             MasterWorkerTeam::where('tenant_id', $params['tenant_id'])->value('id') && throw new \Exception('该租户已有团队');
             $masterWorkerTeam = MasterWorkerTeam::create([
                 'team_name' => $params['team_name'],
                 'master_worker_id' => $params['master_worker_id'],
                 'tenant_id' => $params['tenant_id']??0,
+                'city' => $params['city'],
+                'area_name' => $params['area_name'],
+                'lon' => $params['lon'],
+                'lat' => $params['lat'],
+                'distance' => $params['distance'],
+                'am_limit' => $params['am_limit'],
+                'pm_limit' => $params['pm_limit'],
+                'min_order' => $params['min_order'],
+                'goods_category_ids' => $params['goods_category_ids'],
+                'accept_order_status' => $params['accept_order_status'],
             ]);
             MasterWorker::where('id', $params['master_worker_id'])->update(
                 [
@@ -58,6 +75,7 @@ class MasterWorkerTeamLogic extends BaseLogic
                     'tenant_id' => $params['tenant_id'],
                 ]
             );
+
             Db::commit();
             return true;
         } catch (\Exception $e) {
@@ -80,12 +98,18 @@ class MasterWorkerTeamLogic extends BaseLogic
         Db::startTrans();
         try {
             $masterWorkerTeam = MasterWorkerTeam::where('id', $params['id'])->find();
-            $masterWorker = \app\common\model\master_worker\MasterWorker::where('id', $params['master_worker_id'])->find();
+            $masterWorker = MasterWorker::where('id', $params['master_worker_id'])->find();
             if(($masterWorkerTeam['master_worker_id'] != $params['master_worker_id']) && $masterWorker['team_id']){
                 throw new \Exception('该师傅已加入团队,请先退出团队');
             }
+            if($params['goods_category_ids']){
+                foreach ($params['goods_category_ids'] as $val){
+                    is_array($val)?($ids[] = end($val)):($ids[] = $val);
+                }
+                $params['goods_category_ids'] = implode(',',$ids);
+            }
 
-            \app\common\model\master_worker\MasterWorker::where('id', $masterWorkerTeam['master_worker_id'])->update(
+            MasterWorker::where('id', $masterWorkerTeam['master_worker_id'])->update(
                 [
                     //'team_id' => $params['id'],
                     'team_role' => 0,
@@ -96,8 +120,19 @@ class MasterWorkerTeamLogic extends BaseLogic
                 'team_name' => $params['team_name'],
                 'master_worker_id' => $params['master_worker_id'],
                 'tenant_id' => $params['tenant_id']??0,
+                'city' => $params['city'],
+                'area_name' => $params['area_name'],
+                'lon' => $params['lon'],
+                'lat' => $params['lat'],
+                'distance' => $params['distance'],
+                'am_limit' => $params['am_limit'],
+                'pm_limit' => $params['pm_limit'],
+                'min_order' => $params['min_order'],
+                'goods_category_ids' => $params['goods_category_ids'],
+                'accept_order_status' => $params['accept_order_status'],
+
             ]);
-            \app\common\model\master_worker\MasterWorker::where('id', $params['master_worker_id'])->update(
+            MasterWorker::where('id', $params['master_worker_id'])->update(
                 [
                     'team_id' => $params['id'],
                     'team_role' => 1,
@@ -143,6 +178,11 @@ class MasterWorkerTeamLogic extends BaseLogic
      */
     public static function detail($params): array
     {
-        return MasterWorkerTeam::with('masterWorker')->findOrEmpty($params['id'])->toArray();
+        $info = MasterWorkerTeam::with('masterWorker')->findOrEmpty($params['id'])->toArray();
+        if(!empty($info['goods_category_ids'])){
+            $info['goods_category_ids'] = explode(',',$info['goods_category_ids']);
+            $info['goods_category_ids'] = array_map('intval', $info['goods_category_ids']);
+        }
+        return $info;
     }
 }

+ 6 - 0
app/adminapi/logic/master_worker_register/MasterWorkerRegisterLogic.php

@@ -18,6 +18,7 @@ namespace app\adminapi\logic\master_worker_register;
 use app\common\enum\notice\NoticeEnum;
 use app\common\model\master_worker\MasterWorker;
 use app\common\model\master_worker\MasterWorkerAuth;
+use app\common\model\master_worker\MasterWorkerScore;
 use app\common\model\master_worker_register\MasterWorkerRegister;
 use app\common\logic\BaseLogic;
 use app\common\service\ConfigService;
@@ -156,6 +157,10 @@ class MasterWorkerRegisterLogic extends BaseLogic
                 'tenant_id' => $params['tenant_id']??0,
                 'category_ids' => $params['category_ids']??'',
             ]);
+            //添加工程师汇总评分数据
+            MasterWorkerScore::create([
+                'worker_id' => $masterWorker->id
+            ]);
 
             $masterWorkerRegister = MasterWorkerRegister::where($where)->findOrEmpty();
             if ($masterWorkerRegister->isEmpty()) {
@@ -181,6 +186,7 @@ class MasterWorkerRegisterLogic extends BaseLogic
                     'address' => !empty($params['address'])?$params['address']:'',
                 ]);
             }
+
         }
         return $masterWorker->id;
     }

+ 61 - 25
app/adminapi/logic/works/ServiceWorkLogic.php

@@ -14,38 +14,35 @@
 
 namespace app\adminapi\logic\works;
 
-
+use think\Exception;
+use think\db\Query;
+use think\facade\Db;
+use think\facade\Log;
+use app\common\logic\BaseLogic;
 use app\api\logic\PerformanceLogic;
-use app\common\enum\worker\WorkerAccountLogEnum;
-use app\common\logic\WorkerAccountLogLogic;
-use app\common\model\coupon\CouponCategory;
-use app\common\model\coupon\UserCoupon;
 use app\common\model\dict\DictData;
-use app\common\model\master_commission\MasterWorkerCommissionConfig;
-use app\common\model\master_commission\MasterWorkerCommissionRatio;
-use app\common\model\master_worker\MasterWorker;
-use app\common\model\master_worker\MasterWorkerAccountLog;
-use app\common\model\master_worker\MasterWorkerRetentionMoneyLog;
-use app\common\model\orders\OrderEffectiveLog;
-use app\common\model\performance\PerformanceRules;
+use app\common\model\coupon\UserCoupon;
+use app\common\model\works\ServiceWork;
 use app\common\model\recharge\OrderGoods;
-use app\common\model\recharge\RechargeOrder;
 use app\common\model\spare_part\SparePart;
-use app\common\model\training\TrainingWorkerTask;
-use app\common\model\works\ServiceWork;
-use app\common\logic\BaseLogic;
-use app\common\model\works\ServiceWorkAllocateWorkerLog;
-use app\common\model\works\ServiceWorkAppointmentLog;
-use app\common\model\works\ServiceWorkCustomerLog;
 use app\common\model\works\ServiceWorkLog;
+use app\common\model\coupon\CouponCategory;
+use app\common\model\recharge\RechargeOrder;
 use app\common\model\works\ServiceWorkSpare;
-use app\workerapi\logic\ServiceWorkerAllocateWorkerLogic;
 use app\workerapi\logic\ServiceWorkLogLogic;
-use think\db\Query;
-use think\Exception;
-use think\facade\Db;
-use think\facade\Log;
-
+use app\common\model\orders\OrderEffectiveLog;
+use app\common\model\master_worker\MasterWorker;
+use app\common\model\training\TrainingWorkerTask;
+use app\common\model\performance\PerformanceRules;
+use app\common\model\works\ServiceWorkCustomerLog;
+use app\workerapi\logic\ServiceWorkReceiveLogLogic;
+use app\common\model\master_worker\MasterWorkerTeam;
+use app\common\model\works\ServiceWorkAppointmentLog;
+use app\workerapi\logic\ServiceWorkerAllocateWorkerLogic;
+use app\common\model\master_worker\MasterWorkerAccountLog;
+use app\common\model\master_worker\MasterWorkerRetentionMoneyLog;
+use app\common\model\master_commission\MasterWorkerCommissionRatio;
+use app\common\model\master_commission\MasterWorkerCommissionConfig;
 
 /**
  * ServiceWork逻辑
@@ -104,6 +101,8 @@ class ServiceWorkLogic extends BaseLogic
                 'opera_log'=>'编号['.$params['user_info']['worker_number'].']'.$params['user_info']['real_name'].'于'.date('y-m-d H:i:s',$receive_time).'领取了工单',
             ];
             ServiceWorkLogLogic::add($work_log);
+            //添加领单日志
+            ServiceWorkReceiveLogLogic::add($work_log);
             Db::commit();
         }
         catch (\Exception $e) {
@@ -361,6 +360,7 @@ class ServiceWorkLogic extends BaseLogic
             $work_log = [
                 'work_id'=>$work->id,
                 'master_worker_id'=>$work->master_worker_id,
+                'type' => 0,
                 'opera_log'=>'后台用户['.$userInfo['admin_id'].']'.$userInfo['name'].'于'.date('Y-m-d H:i:s',time()).'分配了工程师'.'编号['.$worker->worker_number.']'.$worker->real_name
             ];
             ServiceWorkerAllocateWorkerLogic::add($work_log);
@@ -861,15 +861,26 @@ class ServiceWorkLogic extends BaseLogic
             if($worker->isEmpty()){
                 throw new \Exception('工程师不存在');
             }
+            if ($work->tenant_id > 0) {
+                //团队订单取消时,派单数量减1
+                $updateData = date("H",strtotime($work->appointment_time)) < 12 ? ['am_order' => Db::raw('am_order - 1')] : ['pm_order' => Db::raw('pm_order - 1')];
+                MasterWorkerTeam::where('master_worker_id',$work->master_worker_id)->where('tenant_id',$work->tenant_id)->update($updateData);
+            }
+
+            
             MasterWorker::setWorktotal('dec',$work->master_worker_id);
             $work->master_worker_id = 0;
             $work->work_status = 0;
             $work->dispatch_time = 0;
+            $work->first_contact_time = 0;
+            $work->estimated_finish_time = 0;
+            $work->exec_time = 0;
             $work->save();
 
             $work_log = [
                 'work_id'=>$work->id,
                 'master_worker_id'=>$params['master_worker_id'],
+                'type' => 1,
                 'opera_log'=>'后台用户['.$userInfo['admin_id'].']'.$userInfo['name'].'于'.date('Y-m-d H:i:s',time()).'取消了工程师'.'编号['.$worker->worker_number.']'.$worker->real_name
             ];
             ServiceWorkerAllocateWorkerLogic::add($work_log);
@@ -930,4 +941,29 @@ class ServiceWorkLogic extends BaseLogic
             return false;
         }
     }
+
+    /**
+     *
+     * @return false|void
+     */
+    public static function contactCustomer($params)
+    {
+        try {
+            $work = ServiceWork::where(['master_worker_id'=>$params['user_id'],'work_sn'=>$params['work_sn']])->findOrEmpty();
+            if($work->isEmpty()){
+                throw new \Exception('工单不存在');
+            }
+            if (empty($work->first_contact_time)) {
+                $work->first_contact_time = time();
+                $work->save();
+            }
+            return true;
+        }
+        catch  (\Exception $e) {
+            Db::rollback();
+            self::setError($e->getMessage());
+            return false;
+        }
+    }
+
 }

+ 101 - 0
app/adminapi/validate/goods_time/GoodsTimeValidate.php

@@ -0,0 +1,101 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\validate\goods_time;
+
+
+use app\common\validate\BaseValidate;
+
+
+/**
+ * GoodsTime验证器
+ * Class GoodsTimeValidate
+ * @package app\adminapi\validate\goods_time
+ */
+class GoodsTimeValidate extends BaseValidate
+{
+
+     /**
+      * 设置校验规则
+      * @var string[]
+      */
+    protected $rule = [
+        'id' => 'require',
+        'title' => 'require',
+        'service_time' => 'require',
+        'goods_category_ids' => 'require',
+
+    ];
+
+
+    /**
+     * 参数描述
+     * @var string[]
+     */
+    protected $field = [
+        'id' => 'id',
+        'title' => '标题',
+        'service_time' => '服务时长',
+        'goods_category_ids' => '商品分类'
+    ];
+
+
+    /**
+     * @notes 添加场景
+     * @return GoodsTimeValidate
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function sceneAdd()
+    {
+        return $this->only(['title','service_time','goods_category_ids']);
+    }
+
+
+    /**
+     * @notes 编辑场景
+     * @return GoodsTimeValidate
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function sceneEdit()
+    {
+        return $this->only(['id','title','service_time','goods_category_ids']);
+    }
+
+
+    /**
+     * @notes 删除场景
+     * @return GoodsTimeValidate
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function sceneDelete()
+    {
+        return $this->only(['id']);
+    }
+
+
+    /**
+     * @notes 详情场景
+     * @return GoodsTimeValidate
+     * @author likeadmin
+     * @date 2025/02/23 11:02
+     */
+    public function sceneDetail()
+    {
+        return $this->only(['id']);
+    }
+
+}

+ 2 - 2
app/adminapi/validate/master_worker/MasterWorkerTeamValidate.php

@@ -58,7 +58,7 @@ class MasterWorkerTeamValidate extends BaseValidate
      */
     public function sceneAdd()
     {
-        return $this->only(['team_name','master_worker_id']);
+        return $this->only(['team_name','master_worker_id','city','lon','lat','distance','am_limit','pm_limit','min_order','goods_category_ids','accept_order_status']);
     }
 
 
@@ -70,7 +70,7 @@ class MasterWorkerTeamValidate extends BaseValidate
      */
     public function sceneEdit()
     {
-        return $this->only(['id','team_name','master_worker_id']);
+        return $this->only(['id','team_name','master_worker_id','city','lon','lat','distance','am_limit','pm_limit','min_order','goods_category_ids','accept_order_status']);
     }
 
 

+ 2 - 0
app/api/logic/GoodsReviewsLogic.php

@@ -37,6 +37,8 @@ class GoodsReviewsLogic extends BaseLogic
             GoodsReviews::create([
                 'goods_id'=>$goods_id,
                 'goods_category_id'=>$work['goods_category_id'],
+                'sn'=>$params['sn'],
+                'work_id'=>$order['work_id'],
                 'user_id'=>$params['user_id'],
                 'nickname'=>$params['user_info']['nickname'],
                 'avatar'=>$params['user_info']['avatar'],

+ 24 - 0
app/common.php

@@ -5,6 +5,30 @@ use app\common\model\setting\PostageRegion;
 use app\common\service\FileService;
 use think\helper\Str;
 
+
+/**
+ * 计算两点之间的距离
+ */
+function haversineDistance($lat1, $lon1, $lat2, $lon2) {
+    // 地球平均半径,单位:千米
+    $R = 6371;
+    // 将角度转换为弧度
+    $lat1 = deg2rad($lat1);
+    $lon1 = deg2rad($lon1);
+    $lat2 = deg2rad($lat2);
+    $lon2 = deg2rad($lon2);
+    // 计算纬度和经度的差值
+    $dLat = $lat2 - $lat1;
+    $dLon = $lon2 - $lon1;
+    // Haversine 公式的计算步骤
+    $a = sin($dLat / 2) * sin($dLat / 2) +
+         cos($lat1) * cos($lat2) * sin($dLon / 2) * sin($dLon / 2);
+    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
+    // 计算距离
+    $distance = $R * $c;
+    return $distance;
+}
+
 /**
  * @notes 生成密码加密密钥
  * @param string $plaintext

+ 294 - 0
app/common/command/AutomaticDispatch.php

@@ -0,0 +1,294 @@
+<?php
+namespace app\common\command;
+
+use think\facade\Db;
+use think\facade\Log;
+use think\console\Input;
+use think\console\Output;
+use think\console\Command;
+use app\common\model\works\ServiceWork;
+use app\common\model\goods_time\GoodsTime;
+use app\common\model\master_worker\MasterWorker;
+use app\common\model\master_worker\MasterWorkerTeam;
+use app\common\model\works\ServiceWorkAllocateWorkerLog;
+use app\workerapi\logic\ServiceWorkerAllocateWorkerLogic;
+use app\common\model\master_worker\MasterWorkerServiceTime;
+
+class AutomaticDispatch extends Command
+{
+    //地理时效评分占比
+    protected $distanceRate = 0.25;
+    //工程师权重评分占比
+    protected $weightRate = 0.2;
+    //工程师综合评分占比
+    protected $comprehensiveRate = 0.55;
+
+    //默认服务时长 300 分钟
+    protected $defaultServiceTime = 300; 
+
+    protected function configure()
+    {
+        $this->setName('automatic_dispatch')
+            ->setDescription('自动派单');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $this->autoDispatch();
+    }
+
+    /*
+     * 自动派单总分100分
+        1、地理效率得分(distance score)25%
+        2、工程师权重「自定义是否有证」(weight score)20%
+        3、工程师综合服务分 55%
+    */
+    protected function autoDispatch()
+    {
+        $size = 30;
+        $startTime = strtotime(date('Y-m-d 00:00:00'));
+        $endTime = strtotime(date('Y-m-d 23:59:59'));
+        while(true) {
+            
+            // 获取当前时间的前五分钟时间戳
+            $fiveMinutesAgo = time() - 120; // 300 秒 = 2 分钟
+            $list = ServiceWork::where('work_status',0)
+                        ->where(function ($query) use ($fiveMinutesAgo) {
+                            $query->where('exec_time', 0)->whereOr('exec_time', '<', $fiveMinutesAgo);
+                        })
+                        ->where('appointment_time','between', [$startTime, $endTime])
+                        ->field('id,category_type,goods_category_id,lon,lat,province,city,title,appointment_time,address,mobile')
+                        ->order('create_time','asc')
+                        ->limit($size)
+                        ->select()
+                        ->toArray();
+            if (!$list) {
+                sleep(5);
+            }
+
+            $isExec = 1;//是否派单成功
+ 
+            foreach($list as $item) {     
+                try {
+                    //优先平台工程师派单
+                    $res = $this->platformWorker($item);
+                    if ($res === false) {
+                        //门店负责人派单
+                        $res = $this->teamWorker($item);
+                        if ($res === false) {
+                            $isExec = 0;
+                        }
+                    }
+
+                } catch (\Exception $e) {
+                    print_r($e->getMessage());
+                    Log::write('自动派单异常:'.$e->getMessage());
+                    sleep(5);
+                }
+
+                if ($isExec == 0) {
+                    ServiceWork::where('id',$item['id'])->update([
+                        'exec_time' => time(),
+                    ]);
+                }
+            }
+
+        }
+    }
+
+    /**
+     * 派单给平台工程师
+     */
+    protected function platformWorker($item) {
+        $real_distance = Db::raw("ST_Distance_Sphere(
+                POINT({$item['lon']}, {$item['lat']}),
+                POINT(lon, lat)
+            ) AS real_distance");
+        // 获取符合条件的工程师
+        $worker = MasterWorker::alias('a')->leftJoin('master_worker_score b','a.id = b.worker_id')
+        ->where([
+            ['is_disable','=',0],
+            ['work_status','=',0],
+            ['accept_order_status','=',1],
+            ['city','=',$item['city']],
+            ['tenant_id','=',0]
+        ])
+        ->whereRaw('FIND_IN_SET('.$item['goods_category_id'].', a.category_ids)')
+        ->whereRaw("ST_Distance_Sphere(
+            POINT({$item['lon']}, {$item['lat']}),
+            POINT(lon, lat)
+        ) <= distance")
+        ->field(['a.id','a.tenant_id','a.distance','a.lon','a.lat','a.worker_number','a.real_name','b.comprehensive_score','b.weight_score',$real_distance])
+        ->orderRaw('(b.comprehensive_score + b.weight_score) desc')
+        ->limit(100)
+        ->select()
+        ->toArray();
+        $queue = [];
+        foreach($worker as $key => $value) {  
+            //过滤已接过此单的师傅
+            $exists = ServiceWorkAllocateWorkerLog::where('work_id', $item['id'])->where('master_worker_id',$value['id'])->count();
+            if ($exists) {
+                continue;
+            }
+            
+            
+            //计算地理效率得分
+            $realDistance = ceil($value['real_distance'] / 1000);
+            $travelTime = $realDistance * 2;//预计每公里行驶2分钟
+            
+            $distanceScore = 100 - ($travelTime * 1.5) - ($realDistance * 5);
+            $distanceScore = bcadd($distanceScore, 0, 2);
+            $tmpDistanceRate = bcmul($distanceScore, $this->distanceRate, 2);
+            $tmpRate = 0;
+            $value['travelTime'] = $travelTime;
+            $value['comprehensive_score'] = isset($value['comprehensive_score']) ? $value['comprehensive_score'] : 0;
+            $value['weight_score'] = isset($value['weight_score']) ? $value['weight_score'] : 0;
+            $tmpRate = bcmul($value['comprehensive_score'], $this->comprehensiveRate, 2) + bcmul($value['weight_score'], $this->weightRate, 2);
+            $tmpRate = bcadd($tmpRate, $tmpDistanceRate,2);
+            $tmpKey = isset($queue[$tmpRate]) ? bcadd($tmpRate, $key / 100,2) : $tmpRate;//防止键名重复
+            $queue[$tmpKey] = $value;
+           
+        }
+        //按照工程师的总分值倒序排序
+        krsort($queue);
+        foreach($queue as $worker) {
+            $serviceTime = MasterWorkerServiceTime::where('master_worker_id',$worker['id'])->where('goods_category_id',$item['goods_category_id'])->value('service_time');
+            if (empty($serviceTime)) {
+                $serviceTime = GoodsTime::whereRaw('FIND_IN_SET('.$item['goods_category_id'].', goods_category_ids)')->value('service_time');
+                $serviceTime = $serviceTime ?? $this->defaultServiceTime;//默认服务时长
+            }
+
+            //预约开始时间和结束时间
+            $appointment_time = is_numeric($item['appointment_time']) ? $item['appointment_time'] : strtotime($item['appointment_time']);
+            $estimated_finish_time = $appointment_time + $serviceTime * 60 + $worker['travelTime'] * 60;
+            //校验客户的预约时间是否在工程师的空挡期内
+            $count = ServiceWork::where([
+                ['master_worker_id','=',$worker['id']],
+                ['work_status','>=',1],
+                ['work_status','<=',5],
+            ])
+            ->where(function ($query) use ($appointment_time,$estimated_finish_time) {
+                $query->where('appointment_time', 'between',[$appointment_time, $estimated_finish_time])
+                    ->whereOr('estimated_finish_time', 'between', [$appointment_time, $estimated_finish_time]);
+            })
+            ->count();
+            if ($count == 0) {
+                $operaLog = '系统自动派单于'.date('Y-m-d H:i:s',time()).'分配了工程师'.'编号['.$worker['worker_number'].']'.$worker['real_name'];
+                $res = $this->allocateWorker($item,$worker['id'],$worker['tenant_id'],$operaLog,$estimated_finish_time);
+                if ($res === true) {
+                    return true;
+                }
+            }
+        } 
+        return false;
+    }
+
+    /**
+     * 派单给门店负责人
+     */
+    protected function teamWorker($item) {
+        $real_distance = Db::raw("ST_Distance_Sphere(
+            POINT({$item['lon']}, {$item['lat']}),
+            POINT(lon, lat)
+        ) AS real_distance");
+
+        $isAm = date("H",strtotime($item['appointment_time'])) < 12 ? 1 : 0;
+        $whereRaw = $isAm ? 'am_order < am_limit' : 'pm_order < pm_limit';
+        // 获取符合条件的工程师
+        $worker = MasterWorkerTeam::where([
+           ['accept_order_status','=',1],
+            ['city','=',$item['city']],
+        ])
+        ->whereRaw($whereRaw)
+        ->whereRaw('FIND_IN_SET('.$item['goods_category_id'].', goods_category_ids)')
+        ->whereRaw("ST_Distance_Sphere(
+            POINT({$item['lon']}, {$item['lat']}),
+            POINT(lon, lat)
+        ) <= distance")
+        ->field(['id','lon','lat','distance','tenant_id','team_name','master_worker_id','am_order','am_limit','pm_order','pm_limit','min_order','comprehensive_score', $real_distance])
+        ->order('comprehensive_score','desc')
+        ->limit(100)
+        ->select()
+        ->toArray();
+        $minQueue = [];
+        $queue = [];
+        foreach($worker as $key => $value) {  
+            //过滤已接过此单的师傅
+            $exists = ServiceWorkAllocateWorkerLog::where('work_id', $item['id'])->where('master_worker_id',$value['master_worker_id'])->count();
+            if ($exists) {
+                continue;
+            }
+            
+            if ( $value['distance'] > 0) {
+                //校验客户的地址是否在工程师的接单区域内
+                $realDistance = haversineDistance($item['lat'],$item['lon'], $value['lat'],$value['lon'],$value['distance']);
+                if ($realDistance > $value['distance']) {
+                    continue;
+                }
+            }
+            if ($value['am_order'] + $value['pm_order'] < $value['min_order']) {
+                $minQueue[] = $value;
+            } else {
+                $queue[] = $value;
+            }
+        }
+        $queue = array_merge($minQueue,$queue);
+        //优先给接单数量不足最低接单数的团队派单,其次再给服务评分高的派单
+        foreach($queue as $worker) {
+            $operaLog = '系统自动派单于'.date('Y-m-d H:i:s',time()).'分配了团队ID['.$worker['id'].']'.$worker['team_name'];
+            $res = $this->allocateWorker($item, $worker['master_worker_id'], $worker['tenant_id'], $operaLog);
+            if ($res === true) {
+                $updateData = $isAm == 1 ? ['am_order' => Db::raw('am_order + 1')] : ['pm_order' => Db::raw('pm_order + 1')];
+                MasterWorkerTeam::where('id',$worker['id'])->update($updateData);
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    /**
+     * 分配工程师
+     */
+    protected function allocateWorker($workDetail, $masterWorkerId, $tenant_id,$operaLog, $estimated_finish_time=0)
+    {
+        Db::startTrans();
+        try {
+            ServiceWork::where('id',$workDetail['id'])->update([
+                'master_worker_id'=>$masterWorkerId,
+                'tenant_id' => $tenant_id,
+                'work_status'=>1,
+                'estimated_finish_time' => $estimated_finish_time,
+                'dispatch_time'=>time(),
+                'exec_time' => time(),
+            ]);
+            MasterWorker::setWorktotal('inc',$masterWorkerId);
+            $work_log = [
+                'work_id'=>$workDetail['id'],
+                'master_worker_id'=>$masterWorkerId,
+                'type' => 0,
+                'opera_log'=> $operaLog
+            ];
+            ServiceWorkerAllocateWorkerLogic::add($work_log);
+            Db::commit();
+        } catch (\Exception $e) {
+            Db::rollback();
+            Log::write('自动派单分配工程师异常:'.$e->getMessage());
+            return false;
+        }
+        // 工程师派单通知【给工程师的通知】【公众号通知,不发短信】
+        $res = event('Notice',  [
+            'scene_id' => 113,
+            'params' => [
+                'user_id' => $masterWorkerId,
+                'order_id' => $workDetail['id'],
+                'thing9' => $workDetail['title'],
+                'time7' => $workDetail['appointment_time'],
+                'thing8' => (iconv_strlen($workDetail['address'])>15)?(mb_substr($workDetail['address'],0,15,'UTF-8').'...'):$workDetail['address'],
+                'phone_number6' => asteriskString($workDetail['mobile']),
+            ]
+        ]);
+        return true;
+    }
+
+}

+ 55 - 0
app/common/command/CancelDispatch.php

@@ -0,0 +1,55 @@
+<?php
+namespace app\common\command;
+
+use think\facade\Db;
+use think\console\Input;
+use think\console\Output;
+use think\console\Command;
+use app\common\model\works\ServiceWork;
+use app\common\model\master_worker\MasterWorkerTeam;
+
+class CancelDispatch extends Command
+{
+    protected function configure()
+    {
+        $this->setName('cancel_dispatch')
+            ->setDescription('派单5分钟未领取的工单自动取消');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $this->cancelDispatch();
+
+    }
+
+    /*
+    * 超过5分钟未领取工单的,取消分配
+    */
+    protected function cancelDispatch()
+    {
+        $list = ServiceWork::where('work_status',1)
+                ->where('dispatch_time','<',strtotime('-5 minutes'))
+                ->where('dispatch_time','>=',strtotime('-1 days'))
+                ->field('id,tenant_id,master_worker_id,appointment_time')
+                ->limit(100)
+                ->select()
+                ->toArray();
+        foreach($list as $item) {
+            ServiceWork::where('id',$item['id'])
+                        ->update([
+                            'master_worker_id' => 0,
+                            'work_status' => 0,
+                            'dispatch_time' => 0,
+                            'first_contact_time' => 0,
+                            'estimated_finish_time' => 0,
+                        ]);
+            if ($item['tenant_id'] > 0) {
+                $updateData = date("H",strtotime($item['appointment_time'])) < 12 ? ['am_order' => Db::raw('am_order - 1')] : ['pm_order' => Db::raw('pm_order - 1')];
+                MasterWorkerTeam::where('master_worker_id',$item['master_worker_id'])->where('tenant_id',$item['tenant_id'])->update($updateData);
+                
+            }
+        }
+        
+    }
+
+}

+ 241 - 0
app/common/command/UpdateWorkerScore.php

@@ -0,0 +1,241 @@
+<?php
+namespace app\common\command;
+
+use think\facade\Log;
+use think\console\Input;
+use think\console\Output;
+use think\console\Command;
+use think\console\input\Argument;
+use app\common\model\works\IssueWork;
+use app\common\model\works\ReturnWork;
+use app\common\model\works\ServiceWork;
+use app\common\model\goods_time\GoodsTime;
+use app\common\model\reviews\GoodsReviews;
+use app\common\model\master_worker\MasterWorker;
+use app\common\model\effective\OrderEffectiveLog;
+use app\common\model\works\ServiceWorkReceiveLog;
+use app\common\model\master_worker\MasterWorkerTeam;
+use app\common\model\master_worker\MasterWorkerScore;
+use app\common\model\works\ServiceWorkAllocateWorkerLog;
+use app\common\model\master_worker\MasterWorkerServiceTime;
+
+class UpdateWorkerScore extends Command
+{
+    protected $defaultServiceTime = 300; //默认服务时长 300 分钟
+    protected function configure()
+    {
+        $this->setName('update_worker_score')
+            ->setDescription('更新工程师综合评分和服务时长')
+            ->addArgument('type', Argument::OPTIONAL, '类型可选');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        // 获取传递的参数
+        $type = $input->getArgument('type');
+        
+        if ($type == 'init') {
+            $this->initMasterWorkerScore();
+        } else {
+            //更新工程师评分
+            $this->changeWorderScore();
+
+            //更新团队服务评分
+            $this->changeWorkTeamScore();
+        }
+
+    }
+
+    /**
+     * 初始化工程师汇总评分数据,只执行一次即可
+     */
+    protected function initMasterWorkerScore()
+    {
+        $masterWorker = MasterWorker::field('id')->order('id','asc')->select()->toArray();
+        foreach($masterWorker as $item) {
+            //添加工程师汇总评分数据
+            MasterWorkerScore::create([
+                'worker_id' => $item['id']
+            ]);
+        }
+    }
+
+    /*
+     * 每周统计并更新一次工程师的综合评分
+    1、用户评分 
+    2、完单率 = 完结工单/总工单
+    3、接单率 = 已领的工单/总工单
+    4、工单投诉率 = 投诉的工单(判定工程师原因) /已完成工单
+    5、客户粘性率 = 工程师第一次联系客户时间-领单时间 和定义的时间(10分钟)进行比较 
+    6、保修率 = 保修工单/已完成工单(去除保修单)
+    7、返修率 = 返修工单/已完成工单
+    8、加单率 = 加单个数/派单数
+    */
+    protected function changeWorderScore()
+    {
+        $startTime = date('Y-m-d 00:00:00', strtotime('-7 days'));
+        $endTime = date('Y-m-d 23:59:59', strtotime('-1 days'));
+        $page = 0;
+        $size = 50;
+        while(true) {
+            $page++;
+            $offset = ($page - 1) * $size;
+            $list = MasterWorker::field('id,category_ids')
+                    ->limit($offset, $size)
+                    ->select()
+                    ->toArray();
+            if (!$list) {
+                break;
+            }
+            foreach($list as $item) {
+                $workId = $item['id'];
+                $this->updateComprehensiveScore($startTime,$endTime,$workId);
+
+                //更新工程师平均服务时长
+                $this->updateServiceTime($startTime,$endTime,$item);
+            }
+        }
+    }
+
+    /**
+     * 更新工程师服务类目的平均服务时长
+     */
+    protected function updateServiceTime($startTime,$endTime,$worker) {
+        if ($worker['category_ids']) {
+            $category_ids = explode(",",$worker['category_ids']);
+            foreach($category_ids as $categoryId) {
+                $avgTime = ServiceWork::where('master_worker_id',$worker['id'])->where('service_status',3)->whereIn('work_type',[0,1])->whereBetweenTime('create_time', $startTime, $endTime)->field('AVG(finished_time - appointment_time) as avg_time')->find();
+                if (isset($avgTime['avg_time']) && $avgTime['avg_time'] > 0) {
+                    $avgTime = $avgTime['avg_time'] / 60 ;
+                } else {
+                    $avgTime = GoodsTime::whereRaw('FIND_IN_SET('.$categoryId.', goods_category_ids)')->value('service_time');
+                    $avgTime = $avgTime ?? $this->defaultServiceTime;//默认服务时长
+                }
+                $exists = MasterWorkerServiceTime::where('master_worker_id',$worker['id'])->where('goods_category_id',$categoryId)->value('id');
+                if ($exists) {
+                    MasterWorkerServiceTime::where('master_worker_id',$worker['id'])->where('goods_category_id',$categoryId)->update([
+                        'service_time' => $avgTime
+                    ]);
+                } else {
+                    MasterWorkerServiceTime::create([
+                        'master_worker_id' => $worker['id'],
+                        'goods_category_id' => $categoryId,
+                        'service_time' => $avgTime
+                    ]);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * 更新工程师综合评分
+     */
+    protected function updateComprehensiveScore($startTime,$endTime,$workId) {
+        try {
+            //查询本周平均评分值
+            $goodsReviewsAvg = GoodsReviews::alias('a')->leftJoin("service_work b","a.work_id = b.id")->whereBetweenTime('a.create_time', $startTime, $endTime)->avg('rating');
+            $commentScore = $goodsReviewsAvg > 0 ? bcdiv($goodsReviewsAvg, 5, 2) : 0;
+            
+            //总工单:统计派单日志记录
+            $allOrder = ServiceWorkAllocateWorkerLog::where('master_worker_id',$workId)->whereBetweenTime('create_time', $startTime, $endTime)->count();
+            //完结工单:统计工单表已完成的工单
+            $completeOrder = ServiceWork::where('master_worker_id',$workId)->where('service_status',3)->whereBetweenTime('create_time', $startTime, $endTime)->count();
+            
+            if ($allOrder == 0) {
+                $completionRate = 0;
+                $acceptRate = 0;
+            } else {
+                //完单率
+                $completionRate = bcdiv($completeOrder, $allOrder ,2);
+                //接单率
+                $acceptOrder = ServiceWorkReceiveLog::where('master_worker_id',$workId)->whereBetweenTime('create_time', $startTime, $endTime)->count();
+                $acceptRate = bcdiv($acceptOrder, $allOrder ,2);
+            }
+
+            if ($completeOrder == 0) {
+                $issueRate = 0;
+                $returnRate = 0;
+                $addRate = 0;
+            } else {
+                //工单投诉率
+                $issueWork = IssueWork::where('master_worker_id',$workId)->where('responsible',2)->whereBetweenTime('create_time', $startTime, $endTime)->count();
+                $issueRate = bcdiv($issueWork, $completeOrder ,2);
+                $issueRate = 1 - ($issueRate > 1 ? 1 : $issueRate);
+                //返修率
+                $returnWord = ReturnWork::where('master_worker_id',$workId)->whereBetweenTime('create_time', date('Y-m-d 00:00:00', strtotime('-30 days')), $endTime)->count();
+                $returnRate = bcdiv($returnWord, $completeOrder ,2);
+                $returnRate =  1 - ($returnRate > 1 ? 1 : $returnRate);
+                //加单率
+                $addWord = ServiceWork::where('master_worker_id',$workId)->where('work_type',2)->whereBetweenTime('create_time', $startTime, $endTime)->count();
+                $addRate = bcdiv($addWord, $completeOrder ,2);
+                $addRate = $addRate > 1 ? 1 : $addRate;
+            }
+         
+            //客户粘性率(10分钟内)
+            $avgTime = ServiceWork::where('master_worker_id',$workId)->where('work_status','>',1)->where('first_contact_time','>',0)->whereBetweenTime('create_time', $startTime, $endTime)->field('AVG(first_contact_time - receive_time) as avg_time')->find();
+            $avgTime = $avgTime['avg_time'] ? $avgTime['avg_time'] / 60 : 0;
+            $viscosityRate = $avgTime <= 10  && $avgTime > 0 ? 1 : 0;
+
+            $partOrder = ServiceWork::where('master_worker_id',$workId)->where('work_status','>',1)->where('order_effective_id',0)->whereBetweenTime('create_time', $startTime, $endTime)->count();
+            if ($partOrder == 0) {
+                $warrantyRate = 0;
+            } else {
+                //保修率
+                $effectiveOder = OrderEffectiveLog::alias('a')->leftJoin('service_work b', 'a.work_id = b.id')->where('b.id',$workId)->whereBetweenTime('a.create_time', date('Y-m-d 00:00:00', strtotime('-30 days')), $endTime)->count();
+                $warrantyRate = bcdiv($effectiveOder, $partOrder ,2);
+                $warrantyRate = 1 - ($warrantyRate > 1 ? 1 : $warrantyRate);
+            }
+            //工程师汇总评分 
+            $comprehensiveScore = $commentScore + $completionRate + $acceptRate + $issueRate + $viscosityRate + $warrantyRate + $returnRate + $addRate;
+            $comprehensiveScore = bcdiv($comprehensiveScore, 8, 2) * 100;
+            
+            MasterWorkerScore::where('worker_id',$workId)->update(['comprehensive_score' => $comprehensiveScore]);
+            
+        } catch (\Exception $e) {
+            
+            Log::write('更新工程师综合评分异常:'.$e->getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新团队服务评分
+     */
+    protected function changeWorkTeamScore() {
+        $page = 0;
+        $size = 50;
+        while(true) {
+            $page++;
+            $offset = ($page - 1) * $size;
+            $list = MasterWorkerTeam::alias('a')->leftJoin('master_worker b','a.master_worker_id=b.id')->field('a.id,b.tenant_id')
+                    ->limit($offset, $size)
+                    ->select()
+                    ->toArray();
+            if (!$list) {
+                break;
+            }
+            try {
+                foreach($list as $item) {
+                    $comprehensiveScore = 3.5;
+                    if ($item['tenant_id'] > 0) {
+                        $avg = MasterWorker::alias('a')->leftJoin('master_worker_score b','a.id=b.worker_id')
+                        ->where('a.tenant_id',$item['tenant_id'])
+                        ->field('AVG(b.comprehensive_score) as avg')
+                        ->find();
+                        if (isset($avg['avg']) && $avg['avg'] > 0) {
+                            $comprehensiveScore = bcdiv($avg['avg'], 20 , 1);
+                            $comprehensiveScore = $comprehensiveScore < 3.5 ? 3.5 : $comprehensiveScore;
+                            $comprehensiveScore = $comprehensiveScore > 5 ? 5 : $comprehensiveScore;
+                        } 
+                    }
+                    
+                    MasterWorkerTeam::where('id',$item['id'])->update(['comprehensive_score' => $comprehensiveScore]);
+                }
+            } catch (\Exception $e) {
+                Log::write('更新团队综合评分异常:'.$e->getMessage());
+                return false;
+            }
+        }
+    }
+}

+ 34 - 0
app/common/model/goods_time/GoodsTime.php

@@ -0,0 +1,34 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+namespace app\common\model\goods_time;
+
+
+use app\common\model\BaseModel;
+
+
+
+/**
+ * GoodsTime模型
+ * Class GoodsTime
+ * @package app\common\model\goods_time
+ */
+class GoodsTime extends BaseModel
+{
+    
+    protected $name = 'goods_time';
+    
+
+    
+}

+ 9 - 2
app/common/model/master_worker/MasterWorker.php

@@ -6,11 +6,12 @@
 
 namespace app\common\model\master_worker;
 
+use think\facade\Cache;
 use app\common\model\BaseModel;
 use app\common\model\dict\DictData;
-use app\common\model\MasterWorkerRegister;
 use app\common\service\FileService;
-use think\facade\Cache;
+use app\common\model\works\ServiceWork;
+use app\common\model\MasterWorkerRegister;
 
 /**
  * 工程师表
@@ -111,4 +112,10 @@ class MasterWorker extends BaseModel
     {
         return $value?array_map(function($item){ return (int)$item; },explode(',',$value)):[];
     }
+    
+    //工单记录
+    public function serviceWork()
+    {
+        return $this->hasMany(ServiceWork::class,'master_worker_id','id')->field('id,master_worker_id,title,address,appointment_time,dispatch_time,estimated_finish_time,finished_time,goods_category_id,mobile,real_name,city,work_sn,work_status','in',[0,1])->order('appointment_time','asc');
+    }
 }

+ 9 - 0
app/common/model/master_worker/MasterWorkerScore.php

@@ -0,0 +1,9 @@
+<?php
+namespace app\common\model\master_worker;
+use app\common\model\BaseModel;
+
+
+class MasterWorkerScore extends BaseModel
+{
+    protected $name = 'master_worker_score';
+}

+ 9 - 0
app/common/model/master_worker/MasterWorkerServiceTime.php

@@ -0,0 +1,9 @@
+<?php
+namespace app\common\model\master_worker;
+use app\common\model\BaseModel;
+
+
+class MasterWorkerServiceTime extends BaseModel
+{
+    protected $name = 'master_worker_service_time';
+}

+ 10 - 0
app/common/model/works/ServiceWork.php

@@ -207,6 +207,16 @@ class ServiceWork extends BaseModel
         return !empty($data['finished_time'])?date('Y-m-d H:i:s',$data['finished_time']):'';
     }
 
+    public function getEstimatedFinishTimeAttr($value,$data)
+    {
+        return !empty($data['estimated_finish_time'])?date('Y-m-d H:i:s',$data['estimated_finish_time']):'';
+    }
+
+    public function getFirstContactTimeAttr($value,$data)
+    {
+        return !empty($data['first_contact_time'])?date('Y-m-d H:i:s',$data['first_contact_time']):'';
+    }
+
     public function getWorkImagesAttr($value)
     {
         return !empty($value)?json_decode($value,true):'';

+ 17 - 0
app/common/model/works/ServiceWorkReceiveLog.php

@@ -0,0 +1,17 @@
+<?php
+namespace app\common\model\works;
+
+
+use app\common\model\BaseModel;
+
+
+/**
+ * ServiceWorkReceiveLog模型
+ * Class ServiceWorkReceiveLog
+ * @package app\common\model\works
+ */
+class ServiceWorkReceiveLog extends BaseModel
+{
+    protected $name = 'service_work_receive_log';
+
+}

+ 19 - 0
app/workerapi/controller/WorksController.php

@@ -331,5 +331,24 @@ class WorksController extends BaseApiController
         return $this->success('操作成功,已确定新的预约时间', [], 1, 1);
     }
 
+    
+    /**
+     * 第一次电话联系客户
+     * @return \think\response\Json
+     */
+    public function contactCustomer()
+    {
+        $params = (new ServiceWorkValidate())->post()->goCheck('contact', [
+            'user_id' => $this->userId,
+            'user_info' => $this->userInfo
+        ]);
+        $result = ServiceWorkLogic::contactCustomer($params);
+        if (false === $result) {
+            return $this->fail(ServiceWorkLogic::getError());
+        }
+        
+        return $this->success('成功', [], 1, 1);
+    }
+
 
 }

+ 1 - 0
app/workerapi/logic/MasterWorkerTeamLogic.php

@@ -147,6 +147,7 @@ class MasterWorkerTeamLogic extends  BaseLogic
             $work_log = [
                 'work_id'=>$work->id,
                 'master_worker_id'=>$work->master_worker_id,
+                'type' => 0,
                 'opera_log'=>'团队负责人['.$userInfo['user_id'].']'.$userInfo['real_name'].'于'.date('Y-m-d H:i:s',time()).'分配了工程师成员'.'编号['.$worker->worker_number.']'.$worker->real_name
             ];
             ServiceWorkerAllocateWorkerLogic::add($work_log);

+ 36 - 0
app/workerapi/logic/ServiceWorkReceiveLogLogic.php

@@ -0,0 +1,36 @@
+<?php
+namespace app\workerapi\logic;
+use app\common\logic\BaseLogic;
+use app\common\model\works\ServiceWorkReceiveLog;
+use think\Exception;
+
+
+/**
+ * ServiceWorkReceiveLog逻辑
+ * Class ServiceWorkLogLogic
+ * @package app\workerapi\logic\works
+ */
+class ServiceWorkReceiveLogLogic extends BaseLogic
+{
+    /**
+     * @notes 添加
+     * @param array $params
+     * @return bool
+     * @throws Exception
+     * @author whitef
+     * @date 2024/07/10 15:06
+     */
+    public static function add(array $params): bool
+    {
+        if(empty($params['work_id']) || empty($params['master_worker_id']) || empty($params['opera_log'])) {
+            throw new Exception('参数错误');
+        }
+        ServiceWorkReceiveLog::create([
+            'work_id' => $params['work_id'],
+            'master_worker_id' => $params['master_worker_id'],
+            'opera_log'=>$params['opera_log']
+        ]);
+
+        return true;
+    }
+}

+ 1 - 0
app/workerapi/logic/ServiceWorkerAllocateWorkerLogic.php

@@ -25,6 +25,7 @@ class ServiceWorkerAllocateWorkerLogic extends BaseLogic
         ServiceWorkAllocateWorkerLog::create([
             'work_id' => $params['work_id'],
             'master_worker_id' => $params['master_worker_id'],
+            'type' => $params['type'],
             'opera_log'=>$params['opera_log']
         ]);
 

+ 9 - 0
app/workerapi/validate/ServiceWorkValidate.php

@@ -129,4 +129,13 @@ class ServiceWorkValidate extends BaseValidate
     {
         return $this->only(['work_sn','appointment_time']);
     }
+
+    /**
+     * 电话联系客户
+     * @return ServiceWorkValidate
+     */
+    public function sceneContact()
+    {
+        return $this->only(['work_sn']);
+    }
 }

+ 6 - 0
config/console.php

@@ -13,5 +13,11 @@ return [
         'query_add_agreement' => 'app\common\command\AddAgreementPdf',
         //工程师每日开启接单的通知
         'open_obtain_order' => 'app\common\command\OpenObtainOrder',
+        //工程师自动派单
+        'automatic_dispatch' => 'app\common\command\AutomaticDispatch',
+        //自动取消超时未领的工单
+        'cancel_dispatch' => 'app\common\command\CancelDispatch',
+        //工程师每周更新一次综合评分和服务时长
+        'update_worker_score' => 'app\common\command\UpdateWorkerScore',
     ],
 ];