model = new \app\admin\model\OrderDispatch; $this->view->assign("typeList", $this->model->getTypeList()); $this->view->assign("statusList", $this->model->getStatusList()); $this->view->assign("offlineTotalTypeList", $this->model->getOfflineTotalTypeList()); $sources = Db::name('source') ->where('status', 1) ->field(['id', 'title', 'key_word', 'pid']) ->order('pid', 'asc') ->order('sort', 'desc') ->select(); $filtered = array_filter($sources, function ($item) { return $item['pid'] == 0; }); $pid_map = array_column($filtered, null, 'id'); $res = []; foreach ($sources as $item) { if ($item['pid'] != 0 && isset($pid_map[$item['pid']])) { $res [] = [ ...$item, 'ptitle' => $pid_map[$item['pid']]['title'] ]; } } $this->view->assign("sources", $res); } /** * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 */ /** * 查看 */ public function index() { //当前是否为关联查询 $this->relationSearch = true; //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if ($this->request->isAjax()) { //如果发送的来源是Selectpage,则转发到Selectpage if ($this->request->request('keyField')) { return $this->selectpage(); } list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $list = $this->model ->with(['orderb','lastRecord']) //->auth($this->auth) ->dispatcherauth($this->auth) ->where($where) ->order($sort, $order) ->paginate($limit); foreach ($list as &$row) { $row->btn_edit = in_array($row->status, $this->model->btnActiveStatusList('btn_edit')) && $this->auth->check('orders/dispatch2/edit'); $row->btn_cancel = in_array($row->status, $this->model->btnActiveStatusList('btn_cancel')) && $this->auth->check('orders/dispatch2/del'); $row->btn_abnormal = in_array($row->status, $this->model->btnActiveStatusList('btn_abnormal')); $row->btn_finished = in_array($row->status, $this->model->btnActiveStatusList('btn_finished')) && $this->auth->check('orders/dispatch2/finish'); $row->is_disabled = in_array($row->status, $this->model->btnActiveStatusList('disabled_status')); $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')) ){ //正常情况,执行不到这里来,不用担心循环执行问题 if($row->follow != 2){ $row->follow = 2; OrderDispatch::where('id',$row->id)->update(['follow'=>2]); } } if($row->btn_record ){ if($row->follow == 2){ $row->btn_record = false; } } if($row->status == -10){ //拒绝 $row->remark = $row->reject_reason; } } $result = array("total" => $list->total(), "rows" => $list->items()); return json($result); } $abnormal = \app\admin\model\Abnormal::where('type',3)->order('sort','desc')->order('id','asc')->select(); $newList = []; foreach ($abnormal as $item){ $newList[$item->title] = $item->title; } $selectBuild = build_select('reason_title',$newList,null,['id'=>'reason_title']); $this->assignconfig('abnormal_select',$selectBuild); return $this->view->fetch(); } /** * 编辑 * * @param $ids * @return string * @throws DbException * @throws \think\Exception */ public function edit($ids = null) { $row = $this->model->get($ids); if (!$row) { $this->error(__('No Results were found')); } $order = Order::where('id',$row->id)->with(['area'])->find(); if(empty($order)){ $this->error(__('未找到关联订单')); } $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) { $this->error(__('You have no permission')); } if (false === $this->request->isPost()) { $this->view->assign('row', $row); $this->view->assign('order', $order); $this->view->assign('worker',Worker::where('status',$order->worker_id)->find()); return $this->view->fetch(); } $params = $this->request->post('row/a'); if(isset($params['action']) && $params['action'] == 'finish'){ return $this->finish($ids); } if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } if(!in_array($row->status ,$this->model->btnActiveStatusList('btn_edit'))){ $this->error(__('任务状态已变更,请刷新后再操作')); } $params = $this->preExcludeFields($params); $result = false; Db::startTrans(); try { //是否采用模型验证 if ($this->modelValidate) { $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate; $row->validateFailException()->validate($validate); } $workerChange = false; $remark = ''; if($row->worker_id != $params['worker_id']){ //更换了师傅 $worker = model('worker')->where('id',$params['worker_id'])->find(); $params ['worker_name'] = $worker->name; $params ['worker_tel'] = $worker->tel; //记录日志 $remark = '师傅由 ('.$row->worker_id.')'.$row->worker_name.' 更换为('.$params['worker_id'].')'.$worker->name; $workerChange = true; } $result = $row->allowField(true)->save($params); //$row->admin_user = $this->auth->nickname; $groups = $this->auth->getGroups($this->auth->id); $groupName = ''; if(!empty($groups)){ $groupNames = array_column($groups,'name'); $groupName = implode(',',$groupNames); } $row->admin_user = $groupName.':'.$this->auth->nickname; if($workerChange){ $hookParams = [ 'dispatch' => $row, 'remark' => $remark, ]; Hook::listen('order_dispatch_change', $hookParams); } Db::commit(); } catch (ValidateException | PDOException | Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if (false === $result) { $this->error(__('No rows were updated')); } $this->success(); } /** * 编辑 * * @param $ids * @return string * @throws DbException * @throws \think\Exception */ public function finish($ids = null) { $row = $this->model->get($ids); if (!$row) { $this->error(__('No Results were found')); } $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) { $this->error(__('You have no permission')); } $order = Order::where('id',$row->order_id)->find(); if(empty($order)){ $this->error(__('未找到关联订单')); } if (false === $this->request->isPost()) { $this->view->assign('row', $row); $this->view->assign('order', $order); $this->view->assign('action','finish'); $worker = Worker::where('id',$row->worker_id)->find(); $this->view->assign('worker', $worker); return $this->view->fetch('edit'); } $params = $this->request->post('row/a'); $orderParsms = $this->request->post('order/a'); if (empty($params) || empty($orderParsms)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); if(!in_array($row->status, $this->model->btnActiveStatusList('btn_finished'))){ $this->error('任务状态变更,请刷新后操作'); } if($order->status != Order::STATUS_DISPATCHED){ $this->error('订单状态已变更,请刷新后操作'); } $result = false; Db::startTrans(); try { //是否采用模型验证 if ($this->modelValidate) { $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate; $row->validateFailException()->validate($validate); } $params['status'] = OrderDispatch::STATUS_FINISH; $params['finish_time'] = date('Y-m-d H:i:s'); $params['follow'] = 2; $params['material_cost'] = $orderParsms['material_cost']; if($row->admin_id == 0){ $params['admin_id'] = $this->auth->id; $params['admin_user'] = $this->auth->admin_user; $orderParsms['dispatch_admin_id'] = $this->auth->id; } $result = $row->allowField(true)->save($params); //计算价格 $data = [ 'online_amount' => $orderParsms['online_amount'], //线上尾款 'online_amount_last' => $row->online_total, //线上尾款 'offline_amount' => $row->total, //线下尾款 'cost' => $orderParsms['cost'], 'cost_rate' => $orderParsms['cost_rate'], 'offline_amount_type'=> $row->offline_total_type, 'amount_images' => $params['image']??'', ]; if($row->type == 1){ //手动 $data['status'] = Order::STATUS_AUDITING; }else{ $data['status'] = Order::STATUS_CHECKING; } $data = array_merge($data,$orderParsms); $last_amount = bcadd($data['online_amount_last'],$data['offline_amount'],2); $cost = bcadd($data['cost'],$data['material_cost'],2); $data['total'] = bcadd($data['online_amount'],$last_amount,2); $data['real_amount'] = $data['total']; $data['performance'] = bcsub($data['real_amount'],$cost,2); $order->allowField(true)->save($data); //修改订单状态 $OrderLogic = new OrderLogic(); $OrderLogic -> dispachFinishAfter($row,['role'=>1,'auth'=>$this->auth,'remark'=>'后台完成任务'],true); Db::commit(); } catch (ValidateException | PDOException | Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if (false === $result) { $this->error(__('No rows were updated')); } $this->success(); } /** * 取消派单 * * @param $ids * @return void * @throws DbException * @throws DataNotFoundException * @throws ModelNotFoundException */ // public function del($ids = null) // { // if (false === $this->request->isPost()) { // $this->error(__("Invalid parameters")); // } // $ids = $ids ?: $this->request->post("ids"); // if (empty($ids)) { // $this->error(__('Parameter %s can not be empty', 'ids')); // } // $pk = $this->model->getPk(); // $adminIds = $this->getDataLimitAdminIds(); // if (is_array($adminIds)) { // $this->model->where($this->dataLimitField, 'in', $adminIds); // } // $list = $this->model->where($pk, 'in', $ids)->whereIn('status', $this->model->deleteStatusList())->select(); // // $remark = $this->request->param('remark', ''); // // $count = 0; // Db::startTrans(); // try { // foreach ($list as $item) { // //$count += $item->delete(); // $order = Order::where('id', $item->order_id)->where('status', Order::STATUS_DISPATCHED)->find(); // if (!$order) { // $this->error('订单状态已变更,请刷新后操作'); // } // //取消 // $item->save(['status' => OrderDispatch::STATUS_CANCEL, 'remark' => $remark]); // //回退订单状态 // $order->allowField(true)->save(['status' => Order::STATUS_DISPATCHING]); // // $params['order'] = $order->ref; // $params['role'] = 1; // $params['auth'] = $this->auth; // $params['remark'] = '派单被取消[ID:' . $item->id . '],订单状态回退'; // if (!empty($remark)) { // $params['remark'] .= ',操作备注:' . $remark; // } // Hook::listen('order_change', $params); // } // Db::commit(); // } catch (PDOException | Exception $e) { // Db::rollback(); // throw $e; // $this->error($e->getMessage()); // } // // $this->error(__('取消成功')); // } /** * 取消派单 * * @param $ids * @return void * @throws DbException * @throws DataNotFoundException * @throws ModelNotFoundException */ public function del($ids=null) { if (false === $this->request->isPost()) { $this->error(__("Invalid parameters")); } $ids = $this->request->post("ids/a"); $reason = $this->request->post("reason"); if (empty($ids)) { $this->error(__('Parameter %s can not be empty', 'ids')); } $pk = $this->model->getPk(); $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds)) { $this->model->where($this->dataLimitField, 'in', $adminIds); } $list = $this->model->where($pk, 'in', $ids)->whereIn('status', $this->model->deleteStatusList())->select(); if(count($list) != count($ids)){ $this->error(__("任务状态不可操作,请刷新页面后再操作")); } $remark = $reason; $count = 0; $OrderLogic = new OrderLogic(); Db::startTrans(); try { foreach ($list as $item) { //$count += $item->delete(); $order = Order::where('id', $item->order_id)->where('status', Order::STATUS_DISPATCHED)->find(); if (!$order) { $this->error('订单状态已变更,请刷新后操作'); } //取消 // $item->allowField(true)->save(['status' => OrderDispatch::STATUS_CANCEL, 'remark' => $remark]); //回退订单状态 //$order->allowField(true)->save(['status' => Order::STATUS_DISPATCHING]); /* Hook::listen('order_change', $params); $hookParams = [ 'dispatch' => $item, 'remark' => '后台取消,adminId:'.$this->auth->id ]; Hook::listen('order_dispatch_change', $hookParams);*/ $OrderLogic->cancelOrderDispatch($item,$this->auth,$remark); } Db::commit(); } catch (PDOException | Exception $e) { Db::rollback(); $this->error($e->getMessage()); } /* if ($count) { $this->success(); }*/ $this->success(__('取消成功')); } /** * 生成查询所需要的条件,排序方式 * @param mixed $searchfields 快速查询的字段 * @param boolean $relationSearch 是否关联查询 * @return array */ protected function buildparams($searchfields = null, $relationSearch = null) { $searchfields = is_null($searchfields) ? $this->searchFields : $searchfields; $relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch; $search = $this->request->get("search", ''); $filter = $this->request->get("filter", ''); $op = $this->request->get("op", '', 'trim'); $sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id'); $order = $this->request->get("order", "DESC"); $offset = max(0, $this->request->get("offset/d", 0)); $limit = max(0, $this->request->get("limit/d", 0)); $limit = $limit ?: 999999; //新增自动计算页码 $page = $limit ? intval($offset / $limit) + 1 : 1; if ($this->request->has("page")) { $page = max(0, $this->request->get("page/d", 1)); } $this->request->get([config('paginate.var_page') => $page]); $filter = (array)json_decode($filter, true); $area_id = $filter['area_id']??null; $source = $filter['source']??null; unset($filter['city_id']); unset($filter['province_id']); unset($filter['area_id']); unset($filter['source']); if(!empty($area_id)){ $filter['orderb.area_id'] = $this->getSelectAreaCode($area_id); } if(!empty($source)){ $filter['orderb.source'] = $source; } $op = (array)json_decode($op, true); $op['orderb.area_id'] = 'like%'; $op['orderb.source'] = '='; $filter = $filter ? $filter : []; $where = []; $alias = []; $bind = []; $name = ''; $aliasName = ''; if (!empty($this->model) && $relationSearch) { $name = $this->model->getTable(); $alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model)))); $aliasName = $alias[$name] . '.'; } $sortArr = explode(',', $sort); foreach ($sortArr as $index => & $item) { $item = stripos($item, ".") === false ? $aliasName . trim($item) : $item; } unset($item); $sort = implode(',', $sortArr); $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds)) { $where[] = [$aliasName . $this->dataLimitField, 'in', $adminIds]; } if ($search) { $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields); foreach ($searcharr as $k => &$v) { $v = stripos($v, ".") === false ? $aliasName . $v : $v; } unset($v); $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"]; } $index = 0; foreach ($filter as $k => $v) { if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) { continue; } $sym = $op[$k] ?? '='; if (stripos($k, ".") === false) { $k = $aliasName . $k; } $v = !is_array($v) ? trim($v) : $v; $sym = strtoupper($op[$k] ?? $sym); //null和空字符串特殊处理 if (!is_array($v)) { if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) { $sym = strtoupper($v); } if (in_array($v, ['""', "''"])) { $v = ''; $sym = '='; } } switch ($sym) { case '=': case '<>': $where[] = [$k, $sym, (string)$v]; break; case 'LIKE': case 'NOT LIKE': case 'LIKE %...%': 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 '<': case '<=': $where[] = [$k, $sym, intval($v)]; break; case 'FINDIN': case 'FINDINSET': case 'FIND_IN_SET': $v = is_array($v) ? $v : explode(',', str_replace(' ', ',', $v)); $findArr = array_values($v); foreach ($findArr as $idx => $item) { $bindName = "item_" . $index . "_" . $idx; $bind[$bindName] = $item; $where[] = "FIND_IN_SET(:{$bindName}, `" . str_replace('.', '`.`', $k) . "`)"; } break; case 'IN': case 'IN(...)': case 'NOT IN': case 'NOT IN(...)': $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)]; break; case 'BETWEEN': case 'NOT BETWEEN': $arr = array_slice(explode(',', $v), 0, 2); if (stripos($v, ',') === false || !array_filter($arr, function ($v) { return $v != '' && $v !== false && $v !== null; })) { continue 2; } //当出现一边为空时改变操作符 if ($arr[0] === '') { $sym = $sym == 'BETWEEN' ? '<=' : '>'; $arr = $arr[1]; } elseif ($arr[1] === '') { $sym = $sym == 'BETWEEN' ? '>=' : '<'; $arr = $arr[0]; } $where[] = [$k, $sym, $arr]; break; case 'RANGE': case 'NOT RANGE': $v = str_replace(' - ', ',', $v); $arr = array_slice(explode(',', $v), 0, 2); if (stripos($v, ',') === false || !array_filter($arr)) { continue 2; } //当出现一边为空时改变操作符 if ($arr[0] === '') { $sym = $sym == 'RANGE' ? '<=' : '>'; $arr = $arr[1]; } elseif ($arr[1] === '') { $sym = $sym == 'RANGE' ? '>=' : '<'; $arr = $arr[0]; } $tableArr = explode('.', $k); if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias) && !empty($this->model) && $this->relationSearch) { //修复关联模型下时间无法搜索的BUG $relation = Loader::parseName($tableArr[0], 1, false); $alias[$this->model->$relation()->getTable()] = $tableArr[0]; } $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' TIME', $arr]; break; case 'NULL': case 'IS NULL': case 'NOT NULL': case 'IS NOT NULL': $where[] = [$k, strtolower(str_replace('IS ', '', $sym))]; break; default: break; } $index++; } if (!empty($this->model)) { $this->model->alias($alias); } $model = $this->model; $where = function ($query) use ($where, $alias, $bind, &$model) { if (!empty($model)) { $model->alias($alias); $model->bind($bind); } foreach ($where as $k => $v) { if (is_array($v)) { call_user_func_array([$query, 'where'], $v); } else { $query->where($v); } } }; return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind]; } }