From d532b85b910d00b9bdf77ad866b4044f830b8e37 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 10:57:37 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/logic/PermLogic.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index a915ea1..1fb4058 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -124,10 +124,10 @@ class PermLogic 'keepAlive' => true, 'authList' => $authList, 'openType' => $node->open_type, + 'is_hide' => $node->is_hide == 0 ? false : true, + 'is_hide_tab' => $node->is_hide_tab == 0 ? false : true ], - 'children' => $children, - 'is_hide' => $node->is_hide, - 'is_hide_tab' => $node->is_hide_tab + 'children' => $children ]; } From abafe841f82172c3f1e8b7b8c157ffbc9b9c9b08 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 11:00:32 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/logic/PermLogic.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index 1fb4058..515bec9 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -124,8 +124,8 @@ class PermLogic 'keepAlive' => true, 'authList' => $authList, 'openType' => $node->open_type, - 'is_hide' => $node->is_hide == 0 ? false : true, - 'is_hide_tab' => $node->is_hide_tab == 0 ? false : true + 'isHide' => $node->is_hide == 0 ? false : true, + 'isHideTab' => $node->is_hide_tab == 0 ? false : true ], 'children' => $children ]; From 4eca8c46c5e07ec2d1d928779f06536b7a0a0836 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 11:34:47 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/utils/scaffold/Generate.php | 36 ++++++++++++++++---------- app/controller/IndexController.php | 22 ++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/app/common/utils/scaffold/Generate.php b/app/common/utils/scaffold/Generate.php index 7cf52ac..6735997 100644 --- a/app/common/utils/scaffold/Generate.php +++ b/app/common/utils/scaffold/Generate.php @@ -26,11 +26,11 @@ class Generate // 模板路径 $templateDir = __DIR__ . '/templates/'; - $controllerPath = __DIR__ . "/../../../{$this->options['controller']['module']}/controller/".ucfirst($this->options['controller']['name'])."Controller.php"; - $servicePath = __DIR__ . "/../../../{$this->options['service']['module']}/service/".ucfirst($this->options['service']['name'])."Service.php"; - $logicPath = __DIR__ . "/../../../{$this->options['logic']['module']}/logic/".ucfirst($this->options['logic']['name'])."Logic.php"; - $modelPath = __DIR__ . "/../../../{$this->options['model']['module']}/model/".ucfirst($this->options['model']['name']).".php"; - $validatePath = __DIR__ . "/../../../{$this->options['validate']['module']}/validate/".ucfirst($this->options['validate']['name'])."Validate.php"; + $controllerPath = __DIR__ . "/../../../{$this->options['controller']['module']}/controller/".$this->rName($this->options['controller']['name'])."Controller.php"; + $servicePath = __DIR__ . "/../../../{$this->options['service']['module']}/service/".$this->rName($this->options['service']['name'])."Service.php"; + $logicPath = __DIR__ . "/../../../{$this->options['logic']['module']}/logic/".$this->rName($this->options['logic']['name'])."Logic.php"; + $modelPath = __DIR__ . "/../../../{$this->options['model']['module']}/model/".$this->rName($this->options['model']['name']).".php"; + $validatePath = __DIR__ . "/../../../{$this->options['validate']['module']}/validate/".$this->rName($this->options['validate']['name'])."Validate.php"; // 创建目录(如果不存在) $fs->mkdir(__DIR__ . "/../../../{$this->options['controller']['module']}/controller"); @@ -86,32 +86,32 @@ class Generate case 'controller': $content = str_replace('{{controllerModule}}', $this->options['controller']['module'], $content); $content = str_replace('{{serviceModule}}', $this->options['service']['module'], $content); - $content = str_replace('{{serviceName}}', ucfirst($this->options['service']['name']), $content); - $content = str_replace('{{controllerName}}', ucfirst($this->options['controller']['name']), $content); + $content = str_replace('{{serviceName}}', $this->rName($this->options['service']['name']), $content); + $content = str_replace('{{controllerName}}', $this->rName($this->options['controller']['name']), $content); break; case 'service': $content = str_replace('{{serviceModule}}', $this->options['service']['module'], $content); $content = str_replace('{{validateModule}}', $this->options['validate']['module'], $content); - $content = str_replace('{{validateName}}', ucfirst($this->options['validate']['name']), $content); + $content = str_replace('{{validateName}}', $this->rName($this->options['validate']['name']), $content); $content = str_replace('{{modelModule}}', $this->options['model']['module'], $content); - $content = str_replace('{{modelName}}', ucfirst($this->options['model']['name']), $content); - $content = str_replace('{{serviceName}}', ucfirst($this->options['service']['name']), $content); + $content = str_replace('{{modelName}}', $this->rName($this->options['model']['name']), $content); + $content = str_replace('{{serviceName}}', $this->rName($this->options['service']['name']), $content); break; case 'logic': $content = str_replace('{{logicModule}}', $this->options['logic']['module'], $content); $content = str_replace('{{modelModule}}', $this->options['model']['module'], $content); - $content = str_replace('{{modelName}}', ucfirst($this->options['model']['name']), $content); - $content = str_replace('{{logicName}}', ucfirst($this->options['logic']['name']), $content); + $content = str_replace('{{modelName}}', $this->rName($this->options['model']['name']), $content); + $content = str_replace('{{logicName}}', $this->rName($this->options['logic']['name']), $content); break; case 'model': $content = str_replace('{{modelModule}}', $this->options['model']['module'], $content); - $content = str_replace('{{modelName}}', ucfirst($this->options['model']['name']), $content); + $content = str_replace('{{modelName}}', $this->rName($this->options['model']['name']), $content); $content = str_replace('{{table}}', $this->options['table'], $content); $content = str_replace('{{fillable}}', $this->fillableFields(), $content); break; case 'validate': $content = str_replace('{{validateModule}}', $this->options['validate']['module'], $content); - $content = str_replace('{{validateName}}', ucfirst($this->options['validate']['name']), $content); + $content = str_replace('{{validateName}}', $this->rName($this->options['validate']['name']), $content); break; } @@ -153,6 +153,14 @@ class Generate echo "删除已存在文件: {$path} \n"; } } + + /** + * 设置名称 + */ + public function rName($name = '') + { + return ucfirst(camelize($name)); + } } /** diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index 125ff1f..6ca6eae 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -71,26 +71,26 @@ class IndexController { $options = [ 'controller' => [ - 'module' => 'admin', - 'name' => 'systems' + 'module' => 'inquiry', + 'name' => 'inquiry_log' ], 'model' => [ - 'module' => 'common', - 'name' => 'systems' + 'module' => 'inquiry', + 'name' => 'inquiry_log' ], 'service' => [ - 'module' => 'admin', - 'name' => 'systems' + 'module' => 'inquiry', + 'name' => 'inquiry_log' ], 'logic' => [ - 'module' => 'common', - 'name' => 'systems' + 'module' => 'inquiry', + 'name' => 'inquiry_log' ], 'validate' => [ - 'module' => 'common', - 'name' => 'systems' + 'module' => 'inquiry', + 'name' => 'inquiry_log' ], - 'table' => 'systems' + 'table' => 'inquiry_log' ]; $result = (new Generate($options))->doGenerate(); From e5ab965e656950953a2245bc9136c1b734dcc296 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 15:13:27 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E8=AF=A2=E5=8D=95=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/model/Country.php | 49 ++ app/common/model/InquiryLog.php | 82 +++ app/common/utils/CrudUtil.php | 108 +-- app/common/validate/InquiryLogValidate.php | 29 + app/controller/IndexController.php | 12 +- app/inquiry/controller/CountryController.php | 33 + .../controller/InquiryLogController.php | 694 ++++++++++++++++++ app/inquiry/logic/CountryLogic.php | 17 + app/inquiry/logic/InquiryLogLogic.php | 17 + app/inquiry/service/CountryService.php | 31 + app/inquiry/service/InquiryLogService.php | 103 +++ config/route.php | 9 + 12 files changed, 1103 insertions(+), 81 deletions(-) create mode 100644 app/common/model/Country.php create mode 100644 app/common/model/InquiryLog.php create mode 100644 app/common/validate/InquiryLogValidate.php create mode 100644 app/inquiry/controller/CountryController.php create mode 100644 app/inquiry/controller/InquiryLogController.php create mode 100644 app/inquiry/logic/CountryLogic.php create mode 100644 app/inquiry/logic/InquiryLogLogic.php create mode 100644 app/inquiry/service/CountryService.php create mode 100644 app/inquiry/service/InquiryLogService.php diff --git a/app/common/model/Country.php b/app/common/model/Country.php new file mode 100644 index 0000000..80439a4 --- /dev/null +++ b/app/common/model/Country.php @@ -0,0 +1,49 @@ +hasOne(User::class, 'id', 'enter_user_id'); + } + + public function recipient() + { + return $this->hasOne(User::class, 'id', 'recipient'); + } + + // public function enter() + // { + // return $this->belongsTo(User::class, 'enter_user_id'); + // } + + // public function recipient() + // { + // return $this->belongsTo(User::class, 'recipient'); + // } + + public function country() + { + return $this->hasOne(Country::class, 'id', 'country'); + } +} \ No newline at end of file diff --git a/app/common/utils/CrudUtil.php b/app/common/utils/CrudUtil.php index 58e8302..22b5202 100644 --- a/app/common/utils/CrudUtil.php +++ b/app/common/utils/CrudUtil.php @@ -152,43 +152,22 @@ class CrudUtil * @return Model * @throws BusinessException */ - // public static function findByPk(string $modelClass, $id, array $with = []): Model - // { - // $m = $modelClass::with($with)->find($id); - // if (!$m) { - // throw new BusinessException("记录 ID={$id} 不存在", 404); - // } - // return $m; - // } + public static function findByPk(string $modelClass, $id, array $with = []): Model + { + $m = $modelClass::with($with)->find($id); + if (!$m) { + throw new BusinessException("记录 ID={$id} 不存在", 404); + } + return $m; + } /** * 任意条件单条查询,支持 dataLimit * - * @param string $modelClass - * @param array $where - * @param array $with - * @param array $dataLimit + * @param Builder $query * @return Model * @throws BusinessException */ - // public static function findOneBy( - // string $modelClass, - // array $where, - // array $with = [], - // array $dataLimit = [] - // ): Model { - // $config = compact('modelClass'); - // $config['model'] = $modelClass; - // $config['where'] = $where; - // $config['with'] = $with; - // $config['dataLimit'] = $dataLimit; - - // $m = self::buildQuery($config)->first(); - // if (!$m) { - // throw new BusinessException("未找到符合条件的记录", 404); - // } - // return $m; - // } public static function findOneBy(Builder $q): Model { return $q->first(); @@ -225,43 +204,32 @@ class CrudUtil * @return Model * @throws BusinessException */ - // public static function updateByPk( - // string $modelClass, - // $id, - // array $data, - // array $dataLimit = [] - // ): Model { - // /** @var Model $m */ - // $m = $modelClass::find($id); - // if (!$m) { - // throw new BusinessException("记录 ID={$id} 不存在", 404); - // } - // // dataLimit 校验 - // if (!empty($dataLimit)) { - // self::applyDataLimitOnMutate($m, $dataLimit, $data); - // } - // $m->fill($data)->save(); - // return $m; - // } + public static function updateByPk( + string $modelClass, + $id, + array $data, + array $dataLimit = [] + ): Model { + /** @var Model $m */ + $m = $modelClass::find($id); + if (!$m) { + throw new BusinessException("记录 ID={$id} 不存在", 404); + } + // dataLimit 校验 + if (!empty($dataLimit)) { + self::applyDataLimitOnMutate($m, $dataLimit, $data); + } + $m->fill($data)->save(); + return $m; + } /** * 非主键条件更新(批量),支持 dataLimit * - * @param string $modelClass - * @param array $where + * @param Builder $query * @param array $data - * @param array $dataLimit * @return int 受影响行数 */ - // public static function updateBy( - // string $modelClass, - // array $where, - // array $data, - // array $dataLimit = [] - // ): int { - // $config = ['model'=>$modelClass, 'where'=>$where, 'dataLimit'=>$dataLimit]; - // return self::buildQuery($config)->update($data); - // } public static function updateBy(Builder $q, array $data): int { return $q->update($data); @@ -274,27 +242,17 @@ class CrudUtil * @param array $ids * @return int 删除条数 */ - // public static function deleteByPk(string $modelClass, array $ids): int - // { - // return $modelClass::destroy($ids); - // } + public static function deleteByPk(string $modelClass, array $ids): int + { + return $modelClass::destroy($ids); + } /** * 非主键条件删除,支持 dataLimit * - * @param string $modelClass - * @param array $where - * @param array $dataLimit + * @param Builder $query * @return int 删除条数 */ - // public static function deleteBy( - // string $modelClass, - // array $where, - // array $dataLimit = [] - // ): int { - // $config = ['model'=>$modelClass, 'where'=>$where, 'dataLimit'=>$dataLimit]; - // return self::buildQuery($config)->delete(); - // } public static function deleteBy(Builder $q): int { return $q->delete(); diff --git a/app/common/validate/InquiryLogValidate.php b/app/common/validate/InquiryLogValidate.php new file mode 100644 index 0000000..ca266b1 --- /dev/null +++ b/app/common/validate/InquiryLogValidate.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index 6ca6eae..50a3280 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -72,25 +72,25 @@ class IndexController $options = [ 'controller' => [ 'module' => 'inquiry', - 'name' => 'inquiry_log' + 'name' => 'country' ], 'model' => [ 'module' => 'inquiry', - 'name' => 'inquiry_log' + 'name' => 'country' ], 'service' => [ 'module' => 'inquiry', - 'name' => 'inquiry_log' + 'name' => 'country' ], 'logic' => [ 'module' => 'inquiry', - 'name' => 'inquiry_log' + 'name' => 'country' ], 'validate' => [ 'module' => 'inquiry', - 'name' => 'inquiry_log' + 'name' => 'country' ], - 'table' => 'inquiry_log' + 'table' => 'country' ]; $result = (new Generate($options))->doGenerate(); diff --git a/app/inquiry/controller/CountryController.php b/app/inquiry/controller/CountryController.php new file mode 100644 index 0000000..bb709d4 --- /dev/null +++ b/app/inquiry/controller/CountryController.php @@ -0,0 +1,33 @@ +service = new CountryService(); + } + + /** + * 列表页数据格式化 + * + * @param array $data + * @return array + */ + // protected function indexFormat($data) + // { + // if (isset($data['created_at'])) + // $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + // if (isset($data['updated_at'])) + // $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + // return $data; + // } +} \ No newline at end of file diff --git a/app/inquiry/controller/InquiryLogController.php b/app/inquiry/controller/InquiryLogController.php new file mode 100644 index 0000000..9b48395 --- /dev/null +++ b/app/inquiry/controller/InquiryLogController.php @@ -0,0 +1,694 @@ +service = new InquiryLogService(); + } + + /** + * 列表页数据格式化 + * + * @param array $data + * @return array + */ + // protected function indexFormat($data) + // { + // if (isset($data['created_at'])) + // $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + // if (isset($data['updated_at'])) + // $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + // return $data; + // } + + + // 列表 + public function list(Request $request) + { + if ($request->method() == 'POST') { + $data = $request->all(); + $limit = isset($data['limit']) && $data['limit'] ? $data['limit'] : 10; + + // 状态 + $roleId = $request->user->role_id; + $where = []; + if (in_array($roleId, [RoleRulesModel::ALL_ROLE_ID, RoleRulesModel::KEFU_ROLE_ID])) { + if (isset($data["status"]) && $data["status"] != "") { + $where[] = [ + "status", "=", $data["status"] + ]; + } else { + $where[] = [ + "status", ">", -1 + ]; + } + } else { + $where[] = [ + "status", "=", 1 + ]; + } + + // 检索渠道 + if (isset($data["channel"]) && $data["channel"]) { + $where[] = [ + "log_type", "=", $data["channel"] + ]; + } + + // 检索国家 + if (isset($data["country"]) && $data["country"]) { + $where[] = [ + "log_country", "=", $data["country"] + ]; + } + + // 检索时间 + if (isset($data["ld_time"]) && $data["ld_time"]) { + $times = explode(' - ', $data["ld_time"]); + $specificDayStart = trim($times[0]); + $specificDayEnd = trim($times[1]); + $where[] = [ + "c_time", ">", strtotime($specificDayStart) + ]; + $where[] = [ + "c_time", "<=", strtotime($specificDayEnd) + ]; + } + + // 检查渠道(不取缓存中的值) + // $channel = $request->user->channel; + $uinfos = UsersModel::where('id', $request->user->uid)->first(); + $channel = $uinfos->channel; + if ($channel) { + $channel = explode(",", $channel); + $InquiryLogModelModel = InquiryLogModel::where($where)->whereIn("log_type", $channel); + } else { + $InquiryLogModelModel = InquiryLogModel::where($where); + } + + // 关键字 + if (isset($data["kwd"]) && $data["kwd"] != "") { + $InquiryLogModelModel->whereRaw("concat(`log_contact_type`,`log_contact_tel`,`log_contact_whatsapp`,`log_contacts`,`order_no`) like '%".$data['kwd']."%'"); + } + + $list = $InquiryLogModelModel + ->with([ + "eUserInfo"=>function($query) { + $query->where("id", ">", 0); + }, "rUserInfo"=>function($query) { + $query->where("id", ">", 0); + }, "countryInfo" + ]) + ->orderBy("id", "desc") + ->paginate($limit); + + $configsModel = new ConfigsModel(); + $logLevel = $configsModel->getConfig("log_level"); + $countdown = (int)($configsModel->getConfig("score_countdown")) * 60; + $inquiryChannelList = ChannelModel::all(['id', 'name']); + $inquiryChannel = []; + foreach ($inquiryChannelList as $key => $val) { + $inquiryChannel[$val->id] = $val->name; + } + + $arr = []; + foreach ($list->items() as $key => $val) { + $expiry_time = $val->r_time + $countdown; + $is_expiry = 0; + $expiry_ts = 0; + if ($expiry_time <= time()) { + $is_expiry = 1; + } else { + $diff = $expiry_time - (int)time(); + $expiry_ts = $diff * 1000; + } + $rUinfo = ""; + if ($val->rUserInfo) { + $rUinfo = $val->rUserInfo->name; + } + $eUinfo = ""; + if ($val->eUserInfo) { + $eUinfo = $val->eUserInfo->name; + } + + /** + * 显示联系方式条件: + * 1.已跟单并且当前用户是接单人 + * 2.主权限 + * 3.当前用户是录单人 + */ + if ( + ($val->status == 2 && $request->user->uid == $val->recipient) || + ($roleId == RoleRulesModel::ALL_ROLE_ID) || + ($request->user->uid == $val->enter_user_id) + ) { + $log_contact_type = $val->log_contact_type == "" ? " 无 " : $val->log_contact_type; + $log_contact_tel = $val->log_contact_tel == "" ? " 无 " : $val->log_contact_tel; + $log_contact_whatsapp = $val->log_contact_whatsapp == "" ? " 无 " : $val->log_contact_whatsapp; + } else { + $log_contact_type = "******"; + $log_contact_tel = "******"; + $log_contact_whatsapp = "******"; + } + $arr[] = [ + "id" => $val->id, + "order_no" => $val->order_no, + "enter_user_id" => $val->enter_user_id, + "recipient" => $val->recipient, + "log_quality" => $val->log_quality, + "log_quality_desc" => $logLevel[$val->log_quality], + "log_quality_color" => InquiryLogModel::LEVEL_BUTTON_COLOR[$val->log_quality], + "log_type" => $val->log_type, + "log_type_desc" => $inquiryChannel[$val->log_type], + "log_contact_type" => $log_contact_type, + "log_contact_tel" => $log_contact_tel, + "log_contact_whatsapp" => $log_contact_whatsapp, + "log_country" => $val->countryInfo->cn_addr."(".$val->countryInfo->two_letter.")", + "log_country_steering" => $val->countryInfo->steering, + "log_contacts" => $val->log_contacts, + "log_content" => $val->log_content, + "e_time" => $val->status==1?date("Y-m-d H:i:s", $expiry_time):"", + "status" => $val->status, + "status_color" => InquiryLogModel::STATUS_BUTTON_COLOR[$val->status], + "status_desc" => InquiryLogModel::STATUS[$val->status], + "is_expiry" => $is_expiry, + "expiry_ts" => $expiry_ts, + "rUinfo" => $rUinfo, + "eUinfo" => $eUinfo, + "r_time" => $val->r_time?date("Y-m-d H:i:s", $val->r_time):"", + "n_time" => date("Y-m-d H:i:s", time()), + "c_time" => date("Y-m-d H:i:s", strtotime($val->c_time)), + "u_time" => date("Y-m-d H:i:s", strtotime($val->u_time)) + ]; + } + $data = [ + 'lastPage' => $list->lastPage(), + 'currentPage' => $list->currentPage(), + 'hasMorePages' => $list->hasMorePages(), + 'list' => $arr, + 'counts' => $list->total() + ]; + return $this->successResponse($data); + } + return view('inquiry-log/list'); + } + + // 添加 + public function add(Request $request) + { + if ($request->method() == "POST") { + $enterUserId = $request->user->uid; + $data = $request->all(); + + if ($data["log_contact_type"]) { + $check1 = InquiryLogModel::where("log_contact_type", trim($data["log_contact_type"]))->first(); + if ($check1 != NULL) { + return $this->errorResponse('邮箱-联系方式已存在'); + } + } + + if ($data["log_contact_tel"]) { + $check2 = InquiryLogModel::where("log_contact_tel", trim($data["log_contact_tel"]))->first(); + if ($check2 != NULL) { + return $this->errorResponse('电话-联系方式已存在'); + } + } + + if ($data["log_contact_whatsapp"]) { + $check3 = InquiryLogModel::where("log_contact_whatsapp", trim($data["log_contact_whatsapp"]))->first(); + if ($check3 != NULL) { + return $this->errorResponse('whatsapp-联系方式已存在'); + } + } + + if (!$data["log_contact_type"] && !$data["log_contact_tel"] && !$data["log_contact_whatsapp"]) { + $check4 = InquiryLogModel::where("log_contacts", trim($data["log_contacts"]))->where("log_country", $data["country"])->first(); + if ($check4 != NULL) { + return $this->errorResponse('联系人已存在'); + } + } + + $model = new InquiryLogModel(); + $model->order_no = orderNum(); + $model->enter_user_id = $enterUserId; + $model->recipient = 0; + $model->log_type = $data["log_type"]; + $model->log_contact_type = trim($data["log_contact_type"]); + $model->log_contact_tel = trim($data["log_contact_tel"]); + $model->log_contact_whatsapp = trim($data["log_contact_whatsapp"]); + $model->log_country = $data["country"]; + $model->log_contacts = $data["log_contacts"]; + $model->log_content = $data["log_content"]; + $model->log_quality = $data["log_quality"]; + $model->status = 0; + if ($model->save()) { + return $this->successResponse([], '添加成功'); + } else { + return $this->errorResponse('添加失败,请重试'); + } + } + return view('inquiry-log/add'); + } + + // 编辑 + public function edit(Request $request) + { + if ($request->method() == "POST") { + $data = $request->all(); + $model = new InquiryLogModel(); + $info = $model->where("id", $data["id"])->first(); + + if ($data["log_contact_type"]) { + $check1 = InquiryLogModel::where("log_contact_type", trim($data["log_contact_type"]))->first(); + if ($check1 != NULL && $check1->id != $data["id"]) { + return $this->errorResponse('邮箱-联系方式已存在'); + } + } + + if ($data["log_contact_tel"]) { + $check2 = InquiryLogModel::where("log_contact_tel", trim($data["log_contact_tel"]))->first(); + if ($check2 != NULL && $check2->id != $data["id"]) { + return $this->errorResponse('电话-联系方式已存在'); + } + } + + if ($data["log_contact_whatsapp"]) { + $check3 = InquiryLogModel::where("log_contact_whatsapp", trim($data["log_contact_whatsapp"]))->first(); + if ($check3 != NULL && $check3->id != $data["id"]) { + return $this->errorResponse('whatsapp-联系方式已存在'); + } + } + + if (!$data["log_contact_type"] && !$data["log_contact_tel"] && !$data["log_contact_whatsapp"]) { + $check4 = InquiryLogModel::where("log_contacts", trim($data["log_contacts"]))->where("log_country", $data["country"])->first(); + if ($check4 != NULL && $check4->id != $data["id"]) { + return $this->errorResponse('联系人已存在'); + } + } + + $info->log_type = $data["log_type"]; + $info->log_contact_type = $data["log_contact_type"]; + $info->log_contact_tel = $data["log_contact_tel"]; + $info->log_contact_whatsapp = $data["log_contact_whatsapp"]; + $info->log_country = $data["country"]; + $info->log_contacts = $data["log_contacts"]; + $info->log_content = $data["log_content"]; + $info->log_quality = $data["log_quality"]; + if (!$info->save()) { + return $this->errorResponse('操作失败,请重试'); + } + return $this->successResponse([], '操作成功'); + } + return view('inquiry-log/edit'); + } + + // 删除 + public function del(Request $request) + { + if ($request->method() == "POST") { + $id = $request->post("id"); + $rst = InquiryLogModel::where("id", $id)->first(); + if (!$rst) { + return $this->errorResponse('询单未找到'); + } + if ($rst->enter_user_id != $request->user->uid) { + return $this->errorResponse('只能删除自己录入的询单'); + } + $res = InquiryLogModel::where("id", $id)->where("enter_user_id", $request->user->uid)->delete(); + if (!$res) { + return $this->errorResponse('操作失败,请重试'); + } + fileLog('ID:'.$request->user->uid.' - 删除:询单ID:'.$id); + return $this->successResponse([], '操作成功'); + } + return $this->errorResponse('请求方式错误'); + } + + // 单条信息 + public function info(Request $request) + { + if ($request->method() == "POST") { + $id = $request->all("id"); + $info = InquiryLogModel::where("id", $id)->first()->toArray(); + $list = CountryModel::all(["cn_addr", "two_letter", "id"]); + $arr = []; + foreach ($list as $vo) { + $arr[] = [ + "value" => $vo->id, + "name" => $vo->cn_addr."(".$vo->two_letter.")" + ]; + } + $info["guojia"] = $arr; + $info["guojia_id"] = [$info["log_country"]]; + + $configsModel = new ConfigsModel(); + // $data = $configsModel->getConfig("inquiry_channel"); + $inquiryChannelList = ChannelModel::all(['id', 'name']); + $data = []; + foreach ($inquiryChannelList as $key => $val) { + $data[$val->id] = $val->name; + } + + $arr = []; + foreach ($data as $ky => $vo) { + $arr[] = [ + "id" => $ky, + "name" => $vo + ]; + } + $info["qudao"] = $arr; + + $data1 = $configsModel->getConfig("log_level"); + $arr1 = []; + foreach ($data1 as $ky => $vo) { + $arr1[] = [ + "id" => $ky, + "name" => $vo + ]; + } + $info["dengji"] = $arr1; + if (!$info) { + return $this->errorResponse('查询失败,请重试'); + } + $info["log_content"] = strTh($info["log_content"]); + return $this->successResponse($info, 'success'); + } + return $this->errorResponse('请求方式错误'); + } + + // 立即发布 + public function release(Request $request) + { + try { + if ($request->method() == "POST") { + $id = $request->post("id"); + if (!in_array($request->user->role_id, [RoleRulesModel::ALL_ROLE_ID, RoleRulesModel::KEFU_ROLE_ID])) { + return $this->errorResponse('无操作权限'); + } + $info = InquiryLogModel::where("id", $id)->first(); + if (!$info) { + return $this->errorResponse('询单信息未找到'); + } + if ($info->status != 0) { + return $this->errorResponse('状态异常,无法发布'); + } + $info->r_time = time(); + $info->status = 1; + if (!$info->save()) { + return $this->errorResponse('发布失败,请重试'); + } + + // 发送飞书群消息通知 + $data = ["order_id"=>$id]; + RedisQueueRedis::send("release", $data); + // 发送飞书群消息通知 + + return $this->successResponse([], '发布成功'); + } + return $this->errorResponse('电话-请求方式错误'); + } catch (\Throwable $th) { + fileLog($th->getFile()."|".$th->getLine()."|".$th->getMessage()); + return $this->errorResponse($th->getMessage()); + } + } + + // 立即跟单 + public function track(Request $request) + { + // Db::beginTransaction(); + try { + if ($request->method() == "POST") { + $id = $request->post("id"); + $uid = $request->user->uid; + if (!in_array($request->user->role_id, [RoleRulesModel::ALL_ROLE_ID, RoleRulesModel::YEWU_ROLE_ID])) { + // Db::rollBack(); + return $this->errorResponse('无操作权限'); + } + $info = InquiryLogModel::where("id", $id)->first(); + if (!$info) { + return $this->errorResponse('询单信息未找到'); + } + if ($info->status != 1) { + // Db::rollBack(); + return $this->errorResponse('状态异常,无法跟单'); + } + // 更新询单 + $info->recipient = $uid; + $info->t_time = time(); + $info->status = 2; + // 记录跟单 + $model = new UserOrderModel(); + $model->uid = $request->user->uid; + $model->log_id = $id; + $model->score = (new InquiryLogModel())->score($info->log_quality, $info->r_time); + if (!$info->save() || !$model->save()) { + // Db::rollBack(); + return $this->errorResponse('操作失败,请重试'); + } + // Db::commit(); + + // // 发送飞书群消息通知 + $data1 = ["order_id"=>$id]; + RedisQueueRedis::send("track", $data1); + // // 发送飞书群消息通知 + + // // 同步询单到crm + $data2 = ["order_id"=>$id]; + RedisQueueRedis::send("inquiry-sync", $data2); + // // 同步询单到crm + + return $this->successResponse([], '跟单操作成功'); + } else { + // Db::rollBack(); + return $this->errorResponse('请求方式错误'); + } + } catch (\Throwable $th) { + // Db::rollBack(); + fileLog($th->getFile()."|".$th->getLine()."|".$th->getMessage()); + return $this->errorResponse($th->getMessage()); + } + } + + // 详情 + public function detail(Request $request) + { + if ($request->method() == "POST") { + $id = $request->all("id"); + $res = InquiryLogModel::where("id", $id)->first()->toArray(); + return $this->successResponse(["detail"=>$res["log_content"]], '操作成功'); + + } + return view('inquiry-log/detail'); + } + + // 客服分单给业务 + public function allocation(Request $request) + { + // Db::beginTransaction(); + try { + if ($request->method() == "POST") { + $data = $request->all(); + + $userInfo = UsersModel::where("id", $data["gd_user"])->first(); + if (!$userInfo) { + // Db::rollBack(); + return $this->errorResponse('用户未找到'); + } + + $model = new InquiryLogModel(); + $info = $model->where("id", $data["id"])->first(); + if (!$info) { + // Db::rollBack(); + return $this->errorResponse('询单未找到'); + } + + $uomodel = new UserOrderModel(); + $uoInfo = $uomodel->where("log_id", $data["id"])->first(); + if (!$uoInfo) { + // 记录跟单 + $HsUserOrderModel = new UserOrderModel(); + $HsUserOrderModel->uid = $data["gd_user"]; + $HsUserOrderModel->log_id = $data["id"]; + $HsUserOrderModel->score = (new InquiryLogModel())->score($info->log_quality, $info->r_time); + if (!$HsUserOrderModel->save()) { + // Db::rollBack(); + return $this->errorResponse('记录跟单操作失败,请重试'); + } + } else { + $uoInfo->uid = $data["gd_user"]; + if (!$uoInfo->save()) { + // Db::rollBack(); + return $this->errorResponse('操作失败,请重试'); + } + } + + if ($info->status != 2) { + $info->t_time = time(); + $info->status = 2; + } + $info->recipient = $data["gd_user"]; + if (!$info->save()) { + // Db::rollBack(); + return $this->errorResponse('操作失败,请重试'); + } + // Db::commit(); + + // 发送飞书群消息通知 + $data1 = ["order_id"=>$data["id"]]; + RedisQueueRedis::send("allocation", $data1); + // 发送飞书群消息通知 + + // // 同步询单到crm + $data2 = ["order_id"=>$data["id"]]; + RedisQueueRedis::send("inquiry-sync", $data2); + // // 同步询单到crm + + return $this->successResponse([], '操作成功'); + } + return view('inquiry-log/allocation'); + } catch (\Throwable $th) { + // Db::rollBack(); + fileLog($th->getFile()."|".$th->getLine()."|".$th->getMessage()); + return $this->errorResponse($th->getMessage()); + } + } + + // 导出 + public function export(Request $request) + { + if ($request->method() == "POST") { + $data = $request->all(); + + $where = []; + if (isset($data['log_lusers']) && $data['log_lusers']) { + $where[] = ['enter_user_id', '=', $data['log_lusers']]; + } + if (isset($data['log_gusers']) && $data['log_gusers']) { + $where[] = ['recipient', '=', $data['log_gusers']]; + } + if (isset($data['log_country']) && $data['log_country']) { + $where[] = ['log_country', '=', $data['log_country']]; + } + if (isset($data['log_channel']) && $data['log_channel']) { + $where[] = ['log_type', '=', $data['log_channel']]; + } + if (isset($data['log_times']) && $data['log_times']) { + $times = explode(' - ', $data["log_times"]); + $specificDayStart = trim($times[0]); + $specificDayEnd = trim($times[1]); + $where[] = [ + "c_time", ">", strtotime($specificDayStart) + ]; + $where[] = [ + "c_time", "<=", strtotime($specificDayEnd) + ]; + } + + // 查询 + $results = InquiryLogModel::with(['enterUser', 'recipientUser', 'country']) + ->where($where) + ->get() + ->map(function ($log) use($data) { + $arr = []; + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['订单号'] = $log->order_no; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['录入人'] = $log->enterUser->name ?? null; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['接单人'] = $log->recipientUser->name ?? null; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['等级'] = $log->log_quality; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['邮箱'] = $log->log_contact_type; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['电话'] = $log->log_contact_tel; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['WhatsApp'] = $log->log_contact_whatsapp; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['联系人'] = $log->log_contacts; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['国家(中文)'] = $log->country->cn_addr ?? null; + } + if (isset($data['hsl_order_no']) && $data['hsl_order_no']) { + $arr['国家(英文)'] = $log->country->en_full_name ?? null; + } + if (isset($data['hsl_r_time']) && $data['hsl_r_time']) { + $arr['发单时间'] = $log->r_time ? date('Y-m-d H:i:s', $log->r_time) : null; + } + if (isset($data['hsl_t_time']) && $data['hsl_t_time']) { + $arr['跟单时间'] = $log->t_time ? date('Y-m-d H:i:s', $log->t_time) : null; + } + return $arr; + }); + // 创建一个新的 Spreadsheet 对象 + $spreadsheet = new Spreadsheet(); + // 设置当前活动的工作表 + $sheet = $spreadsheet->getActiveSheet(); + // 设置工作表的标题 + $sheet->setCellValue('A1', '订单号'); + $sheet->setCellValue('B1', '录入人'); + $sheet->setCellValue('C1', '接单人'); + $sheet->setCellValue('D1', '等级'); + $sheet->setCellValue('E1', '邮箱'); + $sheet->setCellValue('F1', '电话'); + $sheet->setCellValue('G1', 'WhatsApp'); + $sheet->setCellValue('H1', '联系人'); + $sheet->setCellValue('I1', '国家(中文)'); + $sheet->setCellValue('J1', '国家(英文)'); + $sheet->setCellValue('K1', '发单时间'); + $sheet->setCellValue('L1', '跟单时间'); + $data = $results->toArray(); + + // 将数据填充到工作表中 + $row = 2; // 从第2行开始填充 + foreach ($data as $item) { + $sheet->setCellValue('A' . $row, $item['订单号']); + $sheet->setCellValue('B' . $row, $item['录入人']); + $sheet->setCellValue('C' . $row, $item['接单人']); + + $sheet->setCellValue('D' . $row, $item['等级']); + $sheet->setCellValue('E' . $row, $item['邮箱']); + $sheet->setCellValue('F' . $row, $item['电话']); + + $sheet->setCellValue('G' . $row, $item['WhatsApp']); + $sheet->setCellValue('H' . $row, $item['联系人']); + $sheet->setCellValue('I' . $row, $item['国家(中文)']); + + $sheet->setCellValue('J' . $row, $item['国家(英文)']); + $sheet->setCellValue('K' . $row, $item['发单时间']); + $sheet->setCellValue('L' . $row, $item['跟单时间']); + $row++; + } + + // 创建 Excel 文件的写入器 + $writer = new Xlsx($spreadsheet); + // 名称 + $fileName = $request->user->name.'_'.date('Ymd').'_'.uniqid().'.xlsx'; + // 路径 + $filePath = '/export/'.$fileName; + // 将文件保存到本地 + $writer->save(public_path().$filePath); + + return $this->successResponse(['url'=>$filePath, 'name'=>$fileName]); + } + return view('inquiry-log/export'); + } +} \ No newline at end of file diff --git a/app/inquiry/logic/CountryLogic.php b/app/inquiry/logic/CountryLogic.php new file mode 100644 index 0000000..34508b2 --- /dev/null +++ b/app/inquiry/logic/CountryLogic.php @@ -0,0 +1,17 @@ +validator; + } +} \ No newline at end of file diff --git a/app/inquiry/service/InquiryLogService.php b/app/inquiry/service/InquiryLogService.php new file mode 100644 index 0000000..04ec37a --- /dev/null +++ b/app/inquiry/service/InquiryLogService.php @@ -0,0 +1,103 @@ +validator; + } + + + protected function buildQueryConfig(Request $request, string $scene = 'index'): array + { + $p = $request->all(); + + $config = []; + $config['model'] = $this->modelClass; + switch ($scene) { + case 'default': + $config['where']['status'] = 1; + $config['order']['sort'] = 'desc'; + $config['order']['id'] = 'desc'; + break; + case 'index': + $config['order']['id'] = 'desc'; + + // 渠道 + if (isset($p['channel']) && $p['channel']) { + $config['where']['channel'] = $p['channel']; + } + + // 国家 + if (isset($p['country']) && $p['country']) { + $config['where']['country'] = $p['country']; + } + + // 时间 + if (isset($p['time']) && $p['time']) { + $time = explode(' - ', $p['time']); + $config['where']['created_at'] = [ + ['>=', strtotime($time[0])], + ['<=', strtotime($time[1])], + ]; + } + + // 状态 + if (isset($p['status']) && $p['status']) { + $config['where']['status'] = $p['status']; + } + + // 关键字 + if (isset($p['keyword']) && $p['keyword']) { + // $config['where']['order_no|email|tel|whatsapp|contacts'] = ['like', '%' . $p['keyword'] . '%']; + } + + $config['with'][] = 'enter'; + $config['with'][] = 'recipient'; + + $config['withFields']['enter'][] = 'id'; + $config['withFields']['enter'][] = 'name'; + + $config['withFields']['recipient'][] = 'id'; + $config['withFields']['recipient'][] = 'name'; + break; + case 'show': + $config['where']['id'] = $p['id']; + $config['where']['status'] = 1; + break; + case 'store': + break; + case 'update': + $config['where']['id'] = $p['id']; + break; + case 'destroy': + $config['where']['id'] = $p['id']; + break; + } + + return $config; + } +} \ No newline at end of file diff --git a/config/route.php b/config/route.php index d0e9290..01953d0 100644 --- a/config/route.php +++ b/config/route.php @@ -73,6 +73,15 @@ Route::group('/admin', function () { Route::any('/update', [app\admin\controller\CorpController::class, 'update']); Route::any('/destroy', [app\admin\controller\CorpController::class, 'destroy']); }); + + // 询单 + Route::group('/inquiry', function () { + Route::any('/list', [app\inquiry\controller\InquiryLogController::class, 'index']); + // Route::any('/show', [app\admin\controller\CorpController::class, 'show']); + // Route::any('/store', [app\admin\controller\CorpController::class, 'store']); + // Route::any('/update', [app\admin\controller\CorpController::class, 'update']); + // Route::any('/destroy', [app\admin\controller\CorpController::class, 'destroy']); + }); }); From e20ffa05c0ada732d1273308e6484c11306871bf Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 15:29:54 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/logic/PermLogic.php | 74 ++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index 275912b..af9f848 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -54,14 +54,14 @@ class PermLogic /** - * 构建目录/菜单树,节点包含权限与打开方式,拼接完整路径,并对子级菜单 component 处理 + * 构建目录/菜单树 * * @param \Illuminate\Support\Collection $resources 全部资源集合 * @param int $parentId 当前父级资源 ID * @param string $parentPath 父级完整路径(用于递归) * @return array */ - public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array + public function buildTree_bak($resources, int $parentId = 0, string $parentPath = ''): array { $tree = []; @@ -137,16 +137,7 @@ class PermLogic return $tree; } - - /** - * 构建目录/菜单树,节点包含权限与打开方式,拼接完整路径,并对子级菜单 component 处理 - * - * @param \Illuminate\Support\Collection $resources 全部资源集合 - * @param int $parentId 当前父级资源 ID - * @param string $parentPath 父级完整路径(用于递归) - * @return array - */ - public function buildTree_bak($resources, int $parentId = 0, string $parentPath = ''): array + public function buildTree_bak2($resources, int $parentId = 0, string $parentPath = ''): array { $tree = []; @@ -170,7 +161,7 @@ class PermLogic // —— 递归构建子节点 —— $children = []; - if (in_array($node->type, ['directory', 'menu'])) { + if ($node->type === 'directory') { $children = $this->buildTree($resources, $node->id, $currentPath); } @@ -218,7 +209,64 @@ class PermLogic return $tree; } + public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array + { + $tree = []; + foreach ($resources as $node) { + if ($node->parent_id !== $parentId) continue; + // 拼接完整路径 + $currentPath = $parentPath; + if ($currentPath && substr($currentPath, -1) === '/') { + $currentPath = rtrim($currentPath, '/'); + } + if (!empty($node->url)) { + if (!$currentPath) { + $currentPath = $node->url; + } else { + $url = ltrim($node->url, '/'); + $currentPath = $currentPath . '/' . $url; + } + } + + // 子节点递归 + $children = []; + if ($node->type === 'directory') { + $children = $this->buildTree($resources, $node->id, $currentPath); + } + + // 权限 + $authList = $resources + ->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id) + ->map(fn($r) => [ + 'id' => $r->id, + 'title' => $r->name, + 'auth_mark' => $r->code, + ])->values()->all(); + + // 判断是否有子级菜单(非权限) + $hasChildrenMenu = collect($resources)->where('parent_id', $node->id) + ->whereIn('type', ['directory', 'menu'])->isNotEmpty(); + + $componentValue = $hasChildrenMenu ? '/index/index' : $currentPath; + + $tree[] = [ + 'id' => $node->id, + 'name' => $node->name, + 'path' => $node->url, + 'component' => $componentValue, + 'meta' => [ + 'title' => $node->name, + 'icon' => $node->icon, + 'keepAlive' => true, + 'authList' => $authList, + 'openType' => $node->open_type, + ], + 'children' => $children, + ]; + } + return $tree; + } /** * 获取用户所有权限code From 283b21b1f8b4eb267d5b0059ae3cce331e388b68 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 19:30:27 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=8A=A9=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../traits/crud/CrudControllerTrait.php | 10 +- app/common/utils/CrudUtil.php | 131 +++++++++++++----- app/inquiry/service/InquiryLogService.php | 35 ++--- 3 files changed, 122 insertions(+), 54 deletions(-) diff --git a/app/common/traits/crud/CrudControllerTrait.php b/app/common/traits/crud/CrudControllerTrait.php index 41d9cd5..ca30ba3 100644 --- a/app/common/traits/crud/CrudControllerTrait.php +++ b/app/common/traits/crud/CrudControllerTrait.php @@ -24,7 +24,7 @@ trait CrudControllerTrait ? [$this, 'indexFormat'] : null); return $this->success($data); - } catch (\Exception $e) { + } catch (\Throwable $e) { return $this->error($e->getMessage()); } } @@ -44,7 +44,7 @@ trait CrudControllerTrait ? [$this, 'showFormat'] : null); return $this->success($data); - } catch (\Exception $e) { + } catch (\Throwable $e) { return $this->error($e->getMessage()); } } @@ -61,7 +61,7 @@ trait CrudControllerTrait $data = $this->validate($this->service->getValidator(), $request->post(), 'store'); $res = $this->service->serviceStore($request, $data); return $this->success($res, '创建成功'); - } catch (\Exception $e) { + } catch (\Throwable $e) { return $this->error($e->getMessage()); } } @@ -78,7 +78,7 @@ trait CrudControllerTrait $data = $this->validate($this->service->getValidator(), $request->post(), 'update'); $res = $this->service->serviceUpdate($request, $data); return $this->success([], '更新成功'); - } catch (\Exception $e) { + } catch (\Throwable $e) { return $this->error($e->getMessage()); } } @@ -94,7 +94,7 @@ trait CrudControllerTrait try { $count = $this->service->serviceDestroy($request); return $this->success([], "成功删除了 {$count} 条"); - } catch (\Exception $e) { + } catch (\Throwable $e) { return $this->error($e->getMessage()); } } diff --git a/app/common/utils/CrudUtil.php b/app/common/utils/CrudUtil.php index 22b5202..979181f 100644 --- a/app/common/utils/CrudUtil.php +++ b/app/common/utils/CrudUtil.php @@ -24,6 +24,7 @@ use support\exception\BusinessException; class CrudUtil { + /** * 构建查询,支持: * - 本表字段过滤 where @@ -56,48 +57,62 @@ class CrudUtil $model = new $config['model']; $q = $model->newQuery(); - // 1. eager load - if (!empty($config['with'])) { - $q->with($config['with']); - } - - // 2. 关联表字段选择 - if (!empty($config['withFields'])) { - foreach ($config['withFields'] as $rel => $fields) { - $q->with([$rel => function ($qr) use ($fields) { - $fk = $qr->getModel()->getForeignKey(); - $qr->select(array_unique(array_merge($fields, [$fk]))); - }]); + // eager-load:支持 ['rel','rel2'] 和 ['rel'=>fields[], ...] + if (! empty($config['with'])) { + foreach ($config['with'] as $rel => $fields) { + if (is_int($rel)) { + // 普通关联 + $q->with($fields); + } else { + // 带字段筛选的关联 + $q->with([$rel => function ($qr) use ($fields) { + $key = $qr->getModel()->getKeyName(); + if (! in_array($key, $fields, true)) { + $fields[] = $key; + } + $qr->select($fields); + }]); + } } } - // 3. 本表字段选择 + // 表字段 if (!empty($config['fields'])) { $q->select($config['fields']); } - // 4. where 条件(支持 dot-notation 关联过滤) + // where if (!empty($config['where'])) { foreach ($config['where'] as $col => $val) { if (strpos($col, '.') !== false) { - [$rel, $relCol] = explode('.', $col, 2); - $q->whereHas($rel, function ($qr) use ($relCol, $val) { - self::applyWhere($qr, $relCol, $val); - }); + // 多层支持 + $segments = explode('.', $col); + $leaf = array_pop($segments); + self::applyNestedWhere($q, $segments, $leaf, $val); } else { self::applyWhere($q, $col, $val); } } } - // 5. 排序 + // or where + if (!empty($config['orWhere'])) { + $q->where(function($q) use($config) { + foreach ($config['orWhere'] as $cond) { + [$col,$op,$val] = $cond; + $q->orWhere($col,$op,$val); + } + }); + } + + // 排序 if (!empty($config['order'])) { foreach ($config['order'] as $col => $dir) { $q->orderBy($col, strtolower($dir) === 'asc' ? 'asc' : 'desc'); } } - // 6. 数据权限过滤 + // 数据权限过滤 if (!empty($config['dataLimit'])) { self::applyDataLimit($q, $config['dataLimit']); } @@ -261,8 +276,29 @@ class CrudUtil //=================== Internal Methods ===================// + /** - * 应用单字段 where 过滤 + * 支持多层的 whereHas:$relations=['roles','permissions'],$leaf='name' + */ + protected static function applyNestedWhere(Builder $q, array $relations, string $leaf, $val): void + { + $rel = array_shift($relations); + $q->whereHas($rel, function (Builder $qr) use ($relations, $leaf, $val) { + if ($relations) { + // 还有更深层,继续递归 + self::applyNestedWhere($qr, $relations, $leaf, $val); + } else { + // 最后一层,使用普通 applyWhere + self::applyWhere($qr, $leaf, $val); + } + }); + } + + /** + * 单字段 where 支持: + * - 多条件数组 [ [op1,val1], [op2,val2], … ] + * - 单条件 ['op', val] + * - 直接值 * * @param Builder $q * @param string $col @@ -271,22 +307,53 @@ class CrudUtil */ protected static function applyWhere(Builder $q, string $col, $val): void { - if (is_array($val) && count($val) === 2) { - [$op, $v] = $val; - switch (strtolower($op)) { - case 'like': $q->where($col,'like',$v); break; - case 'in': $q->whereIn($col,(array)$v); break; - case 'not in': $q->whereNotIn($col,(array)$v); break; - case 'null': $q->whereNull($col); break; - case 'not null': $q->whereNotNull($col); break; - case 'between': $q->whereBetween($col,(array)$v); break; - default: $q->where($col,$op,$v); + // 多条件数组 + if (is_array($val) && isset($val[0]) && is_array($val[0])) { + foreach ($val as $pair) { + if (is_array($pair) && count($pair) === 2) { + self::applySingleWhere($q, $col, $pair[0], $pair[1]); + } } - } else { + } + // 单条件 + elseif (is_array($val) && count($val) === 2) { + self::applySingleWhere($q, $col, $val[0], $val[1]); + } + // 直接等值 + else { $q->where($col, $val); } } + /** + * 真正执行一个条件的 where + */ + protected static function applySingleWhere(Builder $q, string $col, string $op, $v): void + { + switch (strtolower($op)) { + case 'like': + $q->where($col, 'like', $v); + break; + case 'in': + $q->whereIn($col, (array)$v); + break; + case 'not in': + $q->whereNotIn($col, (array)$v); + break; + case 'null': + $q->whereNull($col); + break; + case 'not null': + $q->whereNotNull($col); + break; + case 'between': + $q->whereBetween($col, (array)$v); + break; + default: + $q->where($col, $op, $v); + } + } + /** * 应用数据权限过滤到查询(buildQuery 场景) */ diff --git a/app/inquiry/service/InquiryLogService.php b/app/inquiry/service/InquiryLogService.php index 04ec37a..bc966f4 100644 --- a/app/inquiry/service/InquiryLogService.php +++ b/app/inquiry/service/InquiryLogService.php @@ -38,12 +38,8 @@ class InquiryLogService $config = []; $config['model'] = $this->modelClass; switch ($scene) { - case 'default': - $config['where']['status'] = 1; - $config['order']['sort'] = 'desc'; - $config['order']['id'] = 'desc'; - break; case 'index': + // 排序 $config['order']['id'] = 'desc'; // 渠道 @@ -58,10 +54,14 @@ class InquiryLogService // 时间 if (isset($p['time']) && $p['time']) { - $time = explode(' - ', $p['time']); + // $time = explode(' - ', $p['time']); + // $config['where']['created_at'] = [ + // ['>=', strtotime($time[0])], + // ['<=', strtotime($time[1])], + // ]; $config['where']['created_at'] = [ - ['>=', strtotime($time[0])], - ['<=', strtotime($time[1])], + strtotime(explode(' - ', $p['time'])[0]), + strtotime(explode(' - ', $p['time'])[1]), ]; } @@ -72,17 +72,18 @@ class InquiryLogService // 关键字 if (isset($p['keyword']) && $p['keyword']) { - // $config['where']['order_no|email|tel|whatsapp|contacts'] = ['like', '%' . $p['keyword'] . '%']; + $k = '%' . $p['keyword'] . '%'; + foreach (['order_no','email','tel','whatsapp','contacts'] as $col) { + $config['orWhere'][] = [$col, 'like', $k]; + } } - $config['with'][] = 'enter'; - $config['with'][] = 'recipient'; - - $config['withFields']['enter'][] = 'id'; - $config['withFields']['enter'][] = 'name'; - - $config['withFields']['recipient'][] = 'id'; - $config['withFields']['recipient'][] = 'name'; + // 关联 + $config['with'][] = 'country'; + $config['with']['enter'][] = 'id'; + $config['with']['enter'][] = 'name'; + $config['with']['recipient'][] = 'id'; + $config['with']['recipient'][] = 'name'; break; case 'show': $config['where']['id'] = $p['id'];