self::getProjectName(), 'title' => 'cms内容管理', 'primary_key' => 'pid', 'ranking_rules' => 'words,sort,typo,proximity,attribute,exactness', 'max_total_hits' => 1000, 'fields' => [ [ 'name' => 'pid', 'title' => '主键', 'is_displayed' => 0, 'is_searchable' => 0, 'is_filterable' => 0, 'is_sortable' => 0, 'listorder' => 99, ], [ 'name' => 'id', 'title' => '文档ID', 'is_displayed' => 1, 'is_searchable' => 0, 'is_filterable' => 0, 'is_sortable' => 0, 'listorder' => 98, ], [ 'name' => 'catid', 'title' => '栏目ID', 'is_displayed' => 1, 'is_searchable' => 0, 'is_filterable' => 1, 'is_sortable' => 0, 'listorder' => 97, ], [ 'name' => 'modelid', 'title' => '模型id', 'is_displayed' => 0, 'is_searchable' => 0, 'is_filterable' => 1, 'is_sortable' => 0, 'listorder' => 96, ], [ 'name' => 'title', 'title' => '标题', 'is_displayed' => 1, 'is_searchable' => 1, 'is_filterable' => 0, 'is_sortable' => 0, 'listorder' => 95, ], [ 'name' => 'content', 'title' => '内容', 'is_displayed' => 1, 'is_searchable' => 1, 'is_filterable' => 0, 'is_sortable' => 0, 'listorder' => 94, ], [ 'name' => 'publish_time', 'title' => '发布时间', 'is_displayed' => 1, 'is_searchable' => 0, 'is_filterable' => 1, 'is_sortable' => 1, 'listorder' => 93, ], [ 'name' => 'url', 'title' => '网址', 'is_displayed' => 1, 'is_searchable' => 0, 'is_filterable' => 0, 'is_sortable' => 0, 'listorder' => 92, ], [ 'name' => 'thumb', 'title' => '缩略图', 'is_displayed' => 1, 'is_searchable' => 0, 'is_filterable' => 0, 'is_sortable' => 0, 'listorder' => 91, ], ], ], ]; return $data; } /** * 重置搜索索引数据库 */ public static function reset() { $models = array_values(cms_cache('Model')); $category = Db::name('cms_category')->where('type', 2)->column('modelid', 'id'); $search = self::getSearchInstance(); $totalCount = 0; if (count($models) > 0) { foreach ($models as $k => $v) { if ($v['type'] == 1) { // 独立表 Db::name($v['tablename'])->where('status', 1)->chunk(100, function ($list) use ($category, $search, &$totalCount) { $documents = []; foreach ($list as $val) { $documents[] = self::buildDocument(($category[$val['catid']] ?? 0), $val['catid'], $val['id'], $val); $totalCount++; } // 批量添加 $search->add($documents); }); } elseif ($v['type'] == 2) { // 主附表 Db::view($v['tablename'], '*') ->where('status', 1) ->view($v['tablename'] . '_data', '*', $v['tablename'] . '.id=' . $v['tablename'] . '_data' . '.did', 'LEFT') ->chunk(100, function ($list) use ($category, $search, &$totalCount) { $documents = []; foreach ($list as $val) { $documents[] = self::buildDocument(($category[$val['catid']] ?? 0), $val['catid'], $val['id'], $val, $val); $totalCount++; } // 批量添加 $search->add($documents); }); } } } return ['count' => $totalCount]; } /** * 构建文档数据 */ protected static function buildDocument($modelid, $catid, $id, $data, $dataExt = []) { $content = ''; if (isset($dataExt['content'])) { $content = strip_tags(htmlspecialchars_decode($dataExt['content'])); // 限制内容长度,避免文档过大 $content = mb_substr($content, 0, 10000, 'UTF-8'); } return [ 'pid' => self::generateDocumentId($catid, $id), 'id' => (int) $id, 'catid' => (int) $catid, 'modelid' => (int) $modelid, 'title' => $data['title'] ?? '', 'content' => $content, 'publish_time' => isset($data['publish_time']) ? (int) $data['publish_time'] : 0, 'url' => buildContentUrl($catid, $id), 'thumb' => $data['thumb'] ?? '', ]; } /** * 生成文档ID */ protected static function generateDocumentId($catid, $id) { return "{$catid}_{$id}"; } /** * 解析文档ID */ protected static function parseDocumentId($documentId) { if (strpos($documentId, '_') !== false) { list($catid, $id) = explode('_', $documentId, 2); return ['catid' => $catid, 'id' => $id]; } return null; } /** * 新增/更新索引 */ public static function update($modelid, $catid, $id, $data, $dataExt = []) { try { $document = self::buildDocument($modelid, $catid, $id, $data, $dataExt); $search = self::getSearchInstance(); return $search->add($document); } catch (\Exception $e) { return false; } } /** * 删除索引 */ public static function del($catid, $id) { try { $documentId = self::generateDocumentId($catid, $id); $search = self::getSearchInstance(); return $search->del($documentId); } catch (\Exception $e) { return false; } } /** * 获取搜索结果 */ public static function search($page = 1, $pagesize = 20, $order = '', $query = [], $pagequery = []) { $search = self::getSearchInstance(); // 构建搜索参数 $searchParams = array_merge([ 'q' => '', 'filter' => '', 'sort' => [], ], $query); // 执行搜索 return $search->search($page, $pagesize, $order, $searchParams, $pagequery); } /** * 获取搜索实例 */ protected static function getSearchInstance() { $projectName = self::getProjectName(); return MeilisearchLib::instance($projectName); } // 获取项目名 public static function getProjectName() { $config = get_addon_config('cms'); return $config['meilisearch_project_name'] ?? 'cms'; } }