From 3860885b84b2fa48ba7236da57967c3b63d0fcb1 Mon Sep 17 00:00:00 2001 From: peijunlei Date: Thu, 3 Sep 2026 16:25:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(search):=20=E6=90=9C=E7=B4=A2=E9=A1=B5?= =?UTF-8?q?=E8=B0=83=E6=95=B4tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/frontend/SearchController.php | 98 ++++++++++++++++++++-- public/themes/dist_static/static/css/search.css | 1 + public/themes/dist_static/static/js/search.js | 30 ------- public/themes/website/1/zh/demo/single_search.html | 65 +++++++------- 4 files changed, 124 insertions(+), 70 deletions(-) diff --git a/app/controller/frontend/SearchController.php b/app/controller/frontend/SearchController.php index 061657c..6a57ef6 100644 --- a/app/controller/frontend/SearchController.php +++ b/app/controller/frontend/SearchController.php @@ -12,6 +12,29 @@ use app\model\SysSetting; class SearchController extends BaseController { /** + * 按栏目标题映射搜索 Tab 类型 + */ + private function resolveSearchType(string $title): string + { + if ($title === '') { + return 'other'; + } + if (mb_strpos($title, '产品') !== false) { + return 'product'; + } + if (mb_strpos($title, '解决方案') !== false || mb_strpos($title, '方案') !== false) { + return 'solution'; + } + if (mb_strpos($title, '新闻') !== false) { + return 'news'; + } + if (mb_strpos($title, '常见问题') !== false || mb_stripos($title, 'FAQ') !== false || mb_strpos($title, '问题') !== false) { + return 'faq'; + } + return 'other'; + } + + /** * @throws \app\exception\ModelEmptyException * @throws \app\exception\ModelException * @throws \think\db\exception\DbException @@ -41,15 +64,24 @@ class SearchController extends BaseController //搜索 $param = $this->request->param(); $keywords = $param['q'] ?? ''; - $this->assign('keywords',$keywords); + $type = $param['type'] ?? 'all'; + if (!in_array($type, ['all', 'product', 'solution', 'news', 'faq'], true)) { + $type = 'all'; + } + $this->assign('keywords', $keywords); + $this->assign('sr_type', $type); // 获取可以查询的栏目 $category = new Category(); - // $categories = $category -> getAllCustomArrayData(['is_search' => 1],'id desc','id')['data']; // status: 1 正常 2 禁用 $categories = $category -> getAllCustomArrayData(['status' => 1],'id desc','id')['data']; $cateIds = array_column($categories,'id'); + $cateTypeMap = []; + foreach ($categories as $cate) { + $cateTypeMap[(int)$cate['id']] = $this->resolveSearchType((string)($cate['title'] ?? '')); + } + $cateSub = new CategorySubContent(); $cateSubWhere = [ ['seller_id','=',$this->siteId], @@ -58,16 +90,60 @@ class SearchController extends BaseController $cateSubCon = $cateSub->getAllCategorySubContent($cateSubWhere)['data']; $subIds = array_column($cateSubCon,'sub_content_id'); + // 内容 -> 首个栏目(与列表展示 category[0] 一致) + $contentCateMap = []; + foreach ($cateSubCon as $row) { + $sid = (int)$row['sub_content_id']; + if (!isset($contentCateMap[$sid])) { + $contentCateMap[$sid] = (int)$row['category_id']; + } + } + $SubContent = new SubContent(); - $content = $SubContent->with(['thumbnail'=>function($q){ - $q->field('id,name,url,type'); - },'category'])->where(['seller_id'=>$this->sellerId,'is_del'=>1]); - if(!empty($param['q'])){ - $content = $content -> whereLike('title|description|sub_title','%' . $keywords . '%'); + $baseWhere = ['seller_id' => $this->sellerId, 'is_del' => 1]; + + // 关键词命中的全量 ID(用于 Tab 全量统计) + $countQuery = (new SubContent())->where($baseWhere)->whereIn('id', $subIds ?: [0]); + if (!empty($param['q'])) { + $countQuery = $countQuery->whereLike('title|description|sub_title', '%' . $keywords . '%'); + } + $matchedIds = $countQuery->column('id'); + + $srCounts = [ + 'all' => count($matchedIds), + 'product' => 0, + 'solution' => 0, + 'news' => 0, + 'faq' => 0, + ]; + foreach ($matchedIds as $mid) { + $cid = $contentCateMap[(int)$mid] ?? 0; + $itemType = $cateTypeMap[$cid] ?? 'other'; + if (isset($srCounts[$itemType])) { + $srCounts[$itemType]++; + } } + $this->assign('sr_counts', $srCounts); + + // 按 Tab 类型筛选列表用的内容 ID + $listSubIds = $matchedIds; + if ($type !== 'all') { + $listSubIds = []; + foreach ($matchedIds as $mid) { + $cid = $contentCateMap[(int)$mid] ?? 0; + if (($cateTypeMap[$cid] ?? 'other') === $type) { + $listSubIds[] = (int)$mid; + } + } + } + + $content = (new SubContent())->with(['thumbnail'=>function($q){ + $q->field('id,name,url,type'); + },'category'])->where($baseWhere)->whereIn('id', $listSubIds ?: [0]); + $param['siteId'] = $this->siteId; $param['sellerId'] = $this->sellerId; - $data = $content->whereIn('id',$subIds) + $data = $content ->order('id','desc') ->paginate([ 'page' => $param['page'] ?? 1, @@ -79,7 +155,11 @@ class SearchController extends BaseController } $item['thumbnail'] = $item->toArray()['thumbnail']; }); - $data->appends(['q' => $keywords]); + $append = ['q' => $keywords]; + if ($type !== 'all') { + $append['type'] = $type; + } + $data->appends($append); $this->assign('list', $data->items()); $this->assign('list_page', $data->render()); return $this->fetch(config('view.view_search_page_name')); diff --git a/public/themes/dist_static/static/css/search.css b/public/themes/dist_static/static/css/search.css index 8a028cd..c8dd2e5 100644 --- a/public/themes/dist_static/static/css/search.css +++ b/public/themes/dist_static/static/css/search.css @@ -93,6 +93,7 @@ font-size: var(--font-18); font-weight: 400; line-height: var(--font-24); + text-decoration: none; cursor: pointer; transition: color var(--duration-fast) var(--easing); } diff --git a/public/themes/dist_static/static/js/search.js b/public/themes/dist_static/static/js/search.js index 1ceb3ca..674b72f 100644 --- a/public/themes/dist_static/static/js/search.js +++ b/public/themes/dist_static/static/js/search.js @@ -1,43 +1,13 @@ import "./common.js"; import "./pagination.js"; //#region js/search.js -function matchItem($item, type) { - const itemType = $item.attr("data-type") || ""; - return type === "all" || itemType === type; -} -function updateCounts($items) { - ["all", "product", "solution", "news", "faq"].forEach((type) => { - const count = $items.filter((_, el) => matchItem($(el), type)).length; - $(`[data-count="${type}"]`).text(String(count)); - }); -} -function applyFilter() { - const type = $(".sr-tabs__item.is-active").attr("data-type") || "all"; - const $items = $(".sr-item"); - let visible = 0; - $items.each(function() { - const show = matchItem($(this), type); - this.hidden = !show; - if (show) visible += 1; - }); - updateCounts($items); - const $empty = $(".sr-tabs-empty"); - if ($empty.length) $empty.prop("hidden", visible > 0 || !$items.length); -} $(function() { const q = new URLSearchParams(window.location.search).get("q")?.trim() || ""; if (q) $(".sr-search .s-search__input").val(q); - $(".sr-tabs__item").on("click", function() { - const $btn = $(this); - $btn.addClass("is-active").attr("aria-selected", "true"); - $btn.siblings(".sr-tabs__item").removeClass("is-active").attr("aria-selected", "false"); - applyFilter(); - }); $(".sr-hot__tag").on("click", function() { const keyword = $(this).attr("data-keyword") || $(this).text().trim(); $(".sr-search .s-search__input").val(keyword); $(".sr-search").trigger("submit"); }); - if ($(".sr-tabs").length) applyFilter(); }); //#endregion diff --git a/public/themes/website/1/zh/demo/single_search.html b/public/themes/website/1/zh/demo/single_search.html index 4937fd1..ed1b0af 100644 --- a/public/themes/website/1/zh/demo/single_search.html +++ b/public/themes/website/1/zh/demo/single_search.html @@ -86,22 +86,40 @@ + {php} + $sr_type_cur = $sr_type ?? 'all'; + $sr_q = $keywords ?? ''; + $sr_counts = $sr_counts ?? ['all' => 0, 'product' => 0, 'solution' => 0, 'news' => 0, 'faq' => 0]; + $sr_tabs = []; + foreach (['all', 'product', 'solution', 'news', 'faq'] as $tabType) { + $query = ['type' => $tabType]; + if ($sr_q !== '') { + $query['q'] = $sr_q; + } + $sr_tabs[$tabType] = '/search.html?' . http_build_query($query); + } + {/php}
- - - - - + + 全部 ( {$sr_counts.all} ) + + + 产品 ( {$sr_counts.product} ) + + + 解决方案 ( {$sr_counts.solution} ) + + + 新闻 ( {$sr_counts.news} ) + + + 常见问题 ( {$sr_counts.faq} ) +
@@ -115,19 +133,8 @@ $sr_cid = $vo['category_id'] ?? ($vo['category'][0]['id'] ?? 0); $sr_thumb = is_array($vo['thumbnail'] ?? null) ? ($vo['thumbnail']['url'] ?? '') : ''; $sr_url = hcUrl('detail/index', ['id' => $vo['id'], 'cid' => $sr_cid]); - $sr_cate_title = $vo['category'][0]['title'] ?? ''; - $sr_type = 'other'; - if (mb_strpos($sr_cate_title, '产品') !== false) { - $sr_type = 'product'; - } elseif (mb_strpos($sr_cate_title, '解决方案') !== false || mb_strpos($sr_cate_title, '方案') !== false) { - $sr_type = 'solution'; - } elseif (mb_strpos($sr_cate_title, '新闻') !== false) { - $sr_type = 'news'; - } elseif (mb_strpos($sr_cate_title, '常见问题') !== false || mb_strpos($sr_cate_title, 'FAQ') !== false || mb_strpos($sr_cate_title, '问题') !== false) { - $sr_type = 'faq'; - } {/php} -
+
@@ -157,10 +164,6 @@ {/volist}
- - {php} $list_empty = isHcListEmpty($list ?? null); if ($list_empty) { From d97da0317e06e31e022f43230c2dd1b615f8582d Mon Sep 17 00:00:00 2001 From: peijunlei Date: Thu, 3 Sep 2026 16:42:56 +0800 Subject: [PATCH 2/2] =?UTF-8?q?style(search.css):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E9=A1=B5=E9=9D=A2=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/themes/dist_static/static/css/search.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/themes/dist_static/static/css/search.css b/public/themes/dist_static/static/css/search.css index c8dd2e5..2ccc817 100644 --- a/public/themes/dist_static/static/css/search.css +++ b/public/themes/dist_static/static/css/search.css @@ -128,6 +128,8 @@ aspect-ratio: 300/200; overflow: hidden; border-radius: 1rem; + /* padding: 24px; */ + padding: 1.5rem; background: rgba(175, 181, 185, 0.15); } .sr-item__media img {