()
| 67 | } |
| 68 | |
| 69 | loadSearchIndex() { |
| 70 | debugLog('🔍 Loading search index...'); |
| 71 | |
| 72 | const query = ` |
| 73 | SELECT |
| 74 | i.*, |
| 75 | GROUP_CONCAT(DISTINCT al.label) as tags, |
| 76 | GROUP_CONCAT(DISTINCT al.category) as categories, |
| 77 | GROUP_CONCAT(DISTINCT al.weight) as weights, |
| 78 | GROUP_CONCAT(DISTINCT lc.description) as tag_descriptions |
| 79 | FROM issues i |
| 80 | LEFT JOIN article_labels al ON i.number = al.issue_number |
| 81 | LEFT JOIN label_categories lc ON al.label = lc.label |
| 82 | GROUP BY i.number |
| 83 | `; |
| 84 | |
| 85 | this.db.all(query, [], (err, rows) => { |
| 86 | if (err) { |
| 87 | console.error('❌ Error loading search index:', err); |
| 88 | this.dbInitFailed = true; |
| 89 | return; |
| 90 | } |
| 91 | |
| 92 | debugLog(`📊 Loaded ${rows.length} articles for search index`); |
| 93 | |
| 94 | // 处理数据 |
| 95 | const processedRows = rows.map(row => { |
| 96 | const tags = row.tags ? row.tags.split(',') : []; |
| 97 | const categories = row.categories ? row.categories.split(',') : []; |
| 98 | const weights = row.weights ? row.weights.split(',').map(Number) : []; |
| 99 | const descriptions = row.tag_descriptions ? row.tag_descriptions.split(',') : []; |
| 100 | |
| 101 | // 解析 JSON 格式的标签 |
| 102 | let labels = []; |
| 103 | try { |
| 104 | labels = row.labels ? JSON.parse(row.labels) : []; |
| 105 | } catch (e) { |
| 106 | debugLog(`⚠️ Failed to parse labels for issue #${row.number}`); |
| 107 | } |
| 108 | |
| 109 | return { |
| 110 | ...row, |
| 111 | tags, |
| 112 | categories, |
| 113 | weights, |
| 114 | descriptions, |
| 115 | labels, |
| 116 | // 合并所有可搜索的文本 |
| 117 | searchContent: [ |
| 118 | row.title, |
| 119 | row.body, |
| 120 | ...tags, |
| 121 | ...categories, |
| 122 | ...descriptions, |
| 123 | ...labels |
| 124 | ].filter(Boolean).join(' ') |
| 125 | }; |
| 126 | }); |
no test coverage detected