|
|
|
@ -4,40 +4,132 @@ |
|
|
|
namespace app\controller\frontend; |
|
|
|
|
|
|
|
|
|
|
|
use app\exception\ModelEmptyException; |
|
|
|
use app\exception\ModelException; |
|
|
|
use app\model\Category; |
|
|
|
use app\model\CategorySubContent; |
|
|
|
use app\model\SubContent; |
|
|
|
use app\model\SysSetting; |
|
|
|
use app\service\ContentService; |
|
|
|
use app\validate\ContentValidate; |
|
|
|
use think\exception\ValidateException; |
|
|
|
use think\facade\Db; |
|
|
|
|
|
|
|
class SearchController extends BaseController |
|
|
|
{ |
|
|
|
/** 产品根栏目 */ |
|
|
|
private const PRODUCT_CATE_ID = 333; |
|
|
|
|
|
|
|
/** 新闻根栏目 */ |
|
|
|
private const NEWS_CATE_ID = 361; |
|
|
|
|
|
|
|
// 下载中心
|
|
|
|
private const DOWNLOAD_CATE_ID = 356; |
|
|
|
|
|
|
|
/** 常见问题根栏目 */ |
|
|
|
private const FAQ_CATE_ID = 357; |
|
|
|
|
|
|
|
// 视频教程
|
|
|
|
private const VIDEO_CATE_ID = 358; |
|
|
|
|
|
|
|
//产品公告
|
|
|
|
private const ANNOUNCEMENT_CATE_ID = 359; |
|
|
|
|
|
|
|
/** |
|
|
|
* 按栏目标题映射搜索 Tab 类型 |
|
|
|
* 获取栏目自身及全部子栏目 ID |
|
|
|
*/ |
|
|
|
private function resolveSearchType(string $title): string |
|
|
|
private function getCategoryTreeIds(int $rootId): array |
|
|
|
{ |
|
|
|
if ($title === '') { |
|
|
|
return 'other'; |
|
|
|
$category = new Category(); |
|
|
|
$root = $category->where([ |
|
|
|
'id' => $rootId, |
|
|
|
'seller_id' => $this->sellerId, |
|
|
|
'website_id' => $this->siteId, |
|
|
|
])->find(); |
|
|
|
if (empty($root)) { |
|
|
|
return [$rootId]; |
|
|
|
} |
|
|
|
$root = $root->toArray(); |
|
|
|
$parentPath = ($root['path'] ?? '') . $root['id'] . '-'; |
|
|
|
$childIds = $category->where([ |
|
|
|
['seller_id', '=', $this->sellerId], |
|
|
|
['website_id', '=', $this->siteId], |
|
|
|
['path', 'like', $parentPath . '%'], |
|
|
|
])->column('id'); |
|
|
|
|
|
|
|
return array_values(array_unique(array_merge( |
|
|
|
[(int)$root['id']], |
|
|
|
array_map('intval', $childIds ?: []) |
|
|
|
))); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 按栏目 ID 取关联内容 ID |
|
|
|
*/ |
|
|
|
private function getContentIdsByCategoryIds(array $cateIds): array |
|
|
|
{ |
|
|
|
if (empty($cateIds)) { |
|
|
|
return []; |
|
|
|
} |
|
|
|
$cateSub = new CategorySubContent(); |
|
|
|
$ids = $cateSub->where([ |
|
|
|
['seller_id', '=', $this->siteId], |
|
|
|
['category_id', 'in', $cateIds], |
|
|
|
])->column('sub_content_id'); |
|
|
|
|
|
|
|
return array_values(array_unique(array_map('intval', $ids ?: []))); |
|
|
|
} |
|
|
|
if (mb_strpos($title, '产品') !== false) { |
|
|
|
return 'product'; |
|
|
|
|
|
|
|
/** |
|
|
|
* 关键词命中的内容 ID |
|
|
|
*/ |
|
|
|
private function getMatchedContentIds(array $subIds, string $keywords, bool $hasKeyword): array |
|
|
|
{ |
|
|
|
$query = (new SubContent())->where([ |
|
|
|
'seller_id' => $this->sellerId, |
|
|
|
'is_del' => 1, |
|
|
|
])->whereIn('id', $subIds ?: [0]); |
|
|
|
if ($hasKeyword) { |
|
|
|
$query = $query->whereLike('title|description|sub_title', '%' . $keywords . '%'); |
|
|
|
} |
|
|
|
if (mb_strpos($title, '解决方案') !== false || mb_strpos($title, '方案') !== false) { |
|
|
|
return 'solution'; |
|
|
|
$ids = $query->column('id'); |
|
|
|
|
|
|
|
return array_map('intval', $ids ?: []); |
|
|
|
} |
|
|
|
if (mb_strpos($title, '新闻') !== false) { |
|
|
|
return 'news'; |
|
|
|
|
|
|
|
/** |
|
|
|
* 统一格式化为 Y-m-d |
|
|
|
*/ |
|
|
|
private function formatSearchDate($time): string |
|
|
|
{ |
|
|
|
if ($time === null || $time === '') { |
|
|
|
return ''; |
|
|
|
} |
|
|
|
if (mb_strpos($title, '常见问题') !== false || mb_stripos($title, 'FAQ') !== false || mb_strpos($title, '问题') !== false) { |
|
|
|
return 'faq'; |
|
|
|
if (is_numeric($time)) { |
|
|
|
return date('Y-m-d', (int)$time); |
|
|
|
} |
|
|
|
return 'other'; |
|
|
|
$ts = strtotime((string)$time); |
|
|
|
return $ts ? date('Y-m-d', $ts) : substr((string)$time, 0, 10); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 解析搜索结果类型 |
|
|
|
*/ |
|
|
|
private function resolveSearchKind(int $contentId, array $sets): array |
|
|
|
{ |
|
|
|
if (isset($sets['product'][$contentId])) { |
|
|
|
return ['product', '产品']; |
|
|
|
} |
|
|
|
if (isset($sets['news'][$contentId])) { |
|
|
|
return ['news', '新闻']; |
|
|
|
} |
|
|
|
if (isset($sets['faq'][$contentId])) { |
|
|
|
return ['faq', '常见问题']; |
|
|
|
} |
|
|
|
if (isset($sets['download'][$contentId])) { |
|
|
|
return ['download', '下载中心']; |
|
|
|
} |
|
|
|
if (isset($sets['video'][$contentId])) { |
|
|
|
return ['video', '视频']; |
|
|
|
} |
|
|
|
if (isset($sets['announce'][$contentId])) { |
|
|
|
return ['announce', '公告']; |
|
|
|
} |
|
|
|
return ['content', '内容']; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -70,99 +162,120 @@ class SearchController extends BaseController |
|
|
|
//搜索
|
|
|
|
$param = $this->request->param(); |
|
|
|
$keywords = $param['q'] ?? ''; |
|
|
|
$hasKeyword = !empty($param['q']); |
|
|
|
$type = $param['type'] ?? 'all'; |
|
|
|
if (!in_array($type, ['all', 'product', 'solution', 'news', 'faq'], true)) { |
|
|
|
if (!in_array($type, ['all', 'product', 'other', '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'];
|
|
|
|
// $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'] ?? '')); |
|
|
|
} |
|
|
|
|
|
|
|
// 全部:可搜索栏目(is_search=1)
|
|
|
|
$categoryModel = new Category(); |
|
|
|
$searchCategories = $categoryModel->getAllCustomArrayData(['is_search' => 1], 'id desc', 'id')['data']; |
|
|
|
$searchCateIds = array_column($searchCategories, 'id'); |
|
|
|
$cateSub = new CategorySubContent(); |
|
|
|
$cateSubWhere = [ |
|
|
|
['seller_id','=',$this->siteId], |
|
|
|
['category_id','in',$cateIds] |
|
|
|
]; |
|
|
|
$cateSubCon = $cateSub->getAllCategorySubContent($cateSubWhere)['data']; |
|
|
|
$subIds = array_column($cateSubCon,'sub_content_id'); |
|
|
|
$searchSubIds = array_column($cateSub->getAllCategorySubContent([ |
|
|
|
['seller_id', '=', $this->siteId], |
|
|
|
['category_id', 'in', $searchCateIds ?: [0]], |
|
|
|
])['data'], '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']; |
|
|
|
} |
|
|
|
} |
|
|
|
// 各 Tab 固定根栏目(含子栏目)
|
|
|
|
$productContentIds = $this->getContentIdsByCategoryIds($this->getCategoryTreeIds(self::PRODUCT_CATE_ID)); |
|
|
|
$newsContentIds = $this->getContentIdsByCategoryIds($this->getCategoryTreeIds(self::NEWS_CATE_ID)); |
|
|
|
$faqContentIds = $this->getContentIdsByCategoryIds($this->getCategoryTreeIds(self::FAQ_CATE_ID)); |
|
|
|
|
|
|
|
$SubContent = new SubContent(); |
|
|
|
$baseWhere = ['seller_id' => $this->sellerId, 'is_del' => 1]; |
|
|
|
// 其他 = 下载中心 + 视频 + 公告
|
|
|
|
$downloadContentIds = $this->getContentIdsByCategoryIds($this->getCategoryTreeIds(self::DOWNLOAD_CATE_ID)); |
|
|
|
$videoContentIds = $this->getContentIdsByCategoryIds($this->getCategoryTreeIds(self::VIDEO_CATE_ID)); |
|
|
|
$announceContentIds = $this->getContentIdsByCategoryIds($this->getCategoryTreeIds(self::ANNOUNCEMENT_CATE_ID)); |
|
|
|
$otherContentIds = array_values(array_unique(array_merge( |
|
|
|
$downloadContentIds, |
|
|
|
$videoContentIds, |
|
|
|
$announceContentIds |
|
|
|
))); |
|
|
|
|
|
|
|
// 关键词命中的全量 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'); |
|
|
|
$allMatchedIds = $this->getMatchedContentIds($searchSubIds, $keywords, $hasKeyword); |
|
|
|
$productMatchedIds = $this->getMatchedContentIds($productContentIds, $keywords, $hasKeyword); |
|
|
|
$newsMatchedIds = $this->getMatchedContentIds($newsContentIds, $keywords, $hasKeyword); |
|
|
|
$faqMatchedIds = $this->getMatchedContentIds($faqContentIds, $keywords, $hasKeyword); |
|
|
|
$otherMatchedIds = $this->getMatchedContentIds($otherContentIds, $keywords, $hasKeyword); |
|
|
|
|
|
|
|
$srCounts = [ |
|
|
|
'all' => count($matchedIds), |
|
|
|
'product' => 0, |
|
|
|
'solution' => 0, |
|
|
|
'news' => 0, |
|
|
|
'faq' => 0, |
|
|
|
'all' => count($allMatchedIds), |
|
|
|
'product' => count($productMatchedIds), |
|
|
|
'other' => count($otherMatchedIds), |
|
|
|
'news' => count($newsMatchedIds), |
|
|
|
'faq' => count($faqMatchedIds), |
|
|
|
]; |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
// 列表:全部不变;其余按对应栏目查
|
|
|
|
if ($type === 'product') { |
|
|
|
$listSubIds = $productMatchedIds; |
|
|
|
} elseif ($type === 'news') { |
|
|
|
$listSubIds = $newsMatchedIds; |
|
|
|
} elseif ($type === 'faq') { |
|
|
|
$listSubIds = $faqMatchedIds; |
|
|
|
} elseif ($type === 'other') { |
|
|
|
$listSubIds = $otherMatchedIds; |
|
|
|
} else { |
|
|
|
$listSubIds = $allMatchedIds; |
|
|
|
} |
|
|
|
|
|
|
|
$baseWhere = ['seller_id' => $this->sellerId, 'is_del' => 1]; |
|
|
|
$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; |
|
|
|
$productIdSet = array_flip($productContentIds); |
|
|
|
$newsIdSet = array_flip($newsContentIds); |
|
|
|
$faqIdSet = array_flip($faqContentIds); |
|
|
|
$downloadIdSet = array_flip($downloadContentIds); |
|
|
|
$videoIdSet = array_flip($videoContentIds); |
|
|
|
$announceIdSet = array_flip($announceContentIds); |
|
|
|
$kindSets = [ |
|
|
|
'product' => $productIdSet, |
|
|
|
'news' => $newsIdSet, |
|
|
|
'faq' => $faqIdSet, |
|
|
|
'download' => $downloadIdSet, |
|
|
|
'video' => $videoIdSet, |
|
|
|
'announce' => $announceIdSet, |
|
|
|
]; |
|
|
|
$tabKindMap = [ |
|
|
|
'product' => ['product', '产品'], |
|
|
|
'news' => ['news', '新闻'], |
|
|
|
'faq' => ['faq', '常见问题'], |
|
|
|
]; |
|
|
|
|
|
|
|
$data = $content |
|
|
|
->order('id','desc') |
|
|
|
->paginate([ |
|
|
|
'page' => $param['page'] ?? 1, |
|
|
|
'list_rows' => $param['limit'] ?? 10, |
|
|
|
])->each(function (&$item)use($param){ |
|
|
|
if(!empty($item['category'])) { |
|
|
|
$item['category'] = $item->toArray()['category']; |
|
|
|
$item['category_id'] = $item['category'][0]['id']; |
|
|
|
])->each(function (&$item) use ($type, $tabKindMap, $kindSets) { |
|
|
|
$row = $item->toArray(); |
|
|
|
if (!empty($row['category'])) { |
|
|
|
$item['category'] = $row['category']; |
|
|
|
$item['category_id'] = $row['category'][0]['id'] ?? 0; |
|
|
|
} |
|
|
|
$item['thumbnail'] = $row['thumbnail'] ?? null; |
|
|
|
$item['url'] = $row['url'] ?? ''; |
|
|
|
$rawContent = $row['content'] ?? ''; |
|
|
|
// 与 ContentService / 常见问题页一致:先解码再交给模板 strip_tags
|
|
|
|
$item['content'] = $rawContent !== '' ? htmlspecialchars_decode((string)$rawContent) : ''; |
|
|
|
$item['sr_date'] = $this->formatSearchDate($row['publish_time'] ?? ($row['create_time'] ?? '')); |
|
|
|
|
|
|
|
if (isset($tabKindMap[$type])) { |
|
|
|
[$kind, $name] = $tabKindMap[$type]; |
|
|
|
} else { |
|
|
|
[$kind, $name] = $this->resolveSearchKind((int)($row['id'] ?? 0), $kindSets); |
|
|
|
if ($kind === 'content' && !empty($row['category'][0]['title'])) { |
|
|
|
$name = $row['category'][0]['title']; |
|
|
|
} |
|
|
|
} |
|
|
|
$item['thumbnail'] = $item->toArray()['thumbnail']; |
|
|
|
$item['sr_kind'] = $kind; |
|
|
|
$item['sr_tab_name'] = $name; |
|
|
|
}); |
|
|
|
$append = ['q' => $keywords]; |
|
|
|
if ($type !== 'all') { |
|
|
|
|