From 283b21b1f8b4eb267d5b0059ae3cce331e388b68 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 22 Jul 2025 19:30:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9F=A5=E8=AF=A2=E5=8A=A9?= =?UTF-8?q?=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'];