From 20ac0fde1518174f05d32898409261c7d1d2545a Mon Sep 17 00:00:00 2001 From: jsasg <735273025@qq.com> Date: Wed, 12 Aug 2026 10:35:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BA=A7=E5=93=81=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7=20-=20=E5=88=86=E9=A1=B5=E5=88=97=E8=A1=A8=E5=8F=8A?= =?UTF-8?q?=E5=AF=BC=E5=87=BAbug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/v1/ProductCompat.php | 89 ++++++++++++++--------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/app/admin/controller/v1/ProductCompat.php b/app/admin/controller/v1/ProductCompat.php index c929a56e..d7d310f9 100644 --- a/app/admin/controller/v1/ProductCompat.php +++ b/app/admin/controller/v1/ProductCompat.php @@ -9,6 +9,7 @@ use app\admin\model\v1\ProductCompatPartsModel; use app\admin\model\v1\ProductCompatTypesModel; use app\admin\validate\v1\ProductCompatValidate; use Generator; +use think\db\Query; class ProductCompat { @@ -20,8 +21,8 @@ class ProductCompat $params = request()->param([ 'compatible_model', 'model', - 'type_id', - 'part_id', + 'type_id/d', + 'part_id/d', 'brand_name', 'page/d' => 1, 'size/d' => 10 @@ -45,10 +46,10 @@ class ProductCompat ->language(request()->lang_id) ->where(function ($query) use($params) { if (!empty($params['type_id'])) { - $query->typeId($params['type_id']); + $query->where('type_id', '=', $params['type_id']); } if (!empty($params['part_id'])) { - $query->partId($params['part_id']); + $query->where('part_id', '=', $params['part_id']); } }) ->withSearch(['model', 'brand_name', 'compatible_model'], [ @@ -313,7 +314,7 @@ class ProductCompat 'brand_name' ]); - $list = ProductCompatModel::withoutField([ + $query = ProductCompatModel::withoutField([ 'language_id', 'deleted_at' ]) @@ -323,9 +324,6 @@ class ProductCompat }, 'parts' => function ($query) { $query->field(['id', 'name']); - }, - 'compatible_models' => function ($query) { - $query->field(['compat_id', 'compatible_model']); } ]) ->language(request()->lang_id) @@ -341,9 +339,7 @@ class ProductCompat 'model' => $params['model'] ?? null, 'brand_name' => $params['brand_name'] ?? null, 'compatible_model' => $params['compatible_model'] ?? null, - ]) - ->order(['updated_at' => 'desc']) - ->cursor(); + ]); $schema = [ 'id' => 'id', @@ -363,33 +359,58 @@ class ProductCompat 'updated_at' => '更新时间' ]; - return xlsx_writer($this->xlsxRowGenerator($list), $schema, '产品兼容性' . date('YmdHis')); + return xlsx_writer($this->xlsxRowGenerator($query), $schema, '产品兼容性' . date('YmdHis')); } - private function xlsxRowGenerator(Generator $list) + private function xlsxRowGenerator(Query $query, int $page_size = 500): Generator { - foreach ($list as $item) { - $compatible_models = []; - foreach ($item['compatible_models'] as $model) { - $compatible_models[] = $model['compatible_model']; + // 主键游标分页,避免 offset 深翻页的性能问题 + $last_id = 0; + while (true) { + $items = (clone $query) + ->where('id', '>', $last_id) + ->order(['id' => 'asc']) + ->limit($page_size) + ->select(); + if ($items->isEmpty()) { + break; } - yield [ - 'id' => $item['id'], - 'type_name' => $item['types']['type_name'], - 'brand_name' => $item['brand_name'], - 'model' => $item['model'], - 'part_name' => $item['parts']['part_name'], - 'level_name' => $item['level_name'], - 'spec_name' => $item['spec_name'], - 'series_name' => $item['series_name'], - 'capacity' => $item['capacity'], - 'frequency' => $item['frequency'], - 'compatible_models' => implode(',', $compatible_models), - 'praise_count' => $item['praise_count'], - 'sort' => $item['sort'], - 'created_at' => $item['created_at'], - 'updated_at' => $item['updated_at'] - ]; + // 仅查询当前批次的兼容型号,避免一次性拉取全量 id 及巨型 IN 子句 + $compat_map = []; + $compat_ids = $items->column('id'); + if (!empty($compat_ids)) { + $compat_models = ProductCompatModelsModel::field(['compat_id', 'compatible_model']) + ->where('compat_id', 'in', $compat_ids) + ->order(['id' => 'asc']) + ->select() + ->toArray(); + foreach ($compat_models as $compat_model) { + $compat_map[$compat_model['compat_id']][] = $compat_model['compatible_model']; + } + } + + foreach ($items as $item) { + yield [ + 'id' => $item['id'], + 'type_name' => $item['types']['name'] ?? '', + 'brand_name' => $item['brand_name'], + 'model' => $item['model'], + 'part_name' => $item['parts']['name'] ?? '', + 'level_name' => $item['level_name'], + 'spec_name' => $item['spec_name'], + 'series_name' => $item['series_name'], + 'capacity' => $item['capacity'], + 'frequency' => $item['frequency'], + 'compatible_models' => implode(',', $compat_map[$item['id']] ?? []), + 'praise_count' => $item['praise_count'], + 'sort' => $item['sort'], + 'created_at' => $item['created_at'], + 'updated_at' => $item['updated_at'] + ]; + } + + // 推进游标,按主键继续取下一页 + $last_id = $items->last()->id; } }