|
|
@@ -879,15 +879,14 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
padding: 20px;
|
|
|
}}
|
|
|
|
|
|
- /* 候选词库固定区域 */
|
|
|
+ /* 候选词库固定区域 - 移到顶部横跨全宽 */
|
|
|
.candidate-library {{
|
|
|
- position: sticky;
|
|
|
- top: 0;
|
|
|
- z-index: 100;
|
|
|
background: white;
|
|
|
- border-bottom: 2px solid #e5e7eb;
|
|
|
- padding: 15px;
|
|
|
- margin-bottom: 10px;
|
|
|
+ max-width: 1400px;
|
|
|
+ margin: 0 auto 20px;
|
|
|
+ padding: 15px 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
|
}}
|
|
|
|
|
|
.candidate-header {{
|
|
|
@@ -927,11 +926,13 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
max-height: 0;
|
|
|
overflow: hidden;
|
|
|
transition: max-height 0.3s ease;
|
|
|
+ opacity: 0;
|
|
|
}}
|
|
|
|
|
|
.candidate-content.expanded {{
|
|
|
max-height: 400px;
|
|
|
overflow-y: auto;
|
|
|
+ opacity: 1;
|
|
|
}}
|
|
|
|
|
|
.candidate-section {{
|
|
|
@@ -2820,11 +2821,10 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
}}
|
|
|
|
|
|
.high-similarity-item {{
|
|
|
- padding: 10px 12px;
|
|
|
- margin: 8px 0;
|
|
|
+ padding: 12px 15px;
|
|
|
+ border-bottom: 1px solid #e5e7eb;
|
|
|
background: white;
|
|
|
border-left: 3px solid #22c55e;
|
|
|
- border-radius: 4px;
|
|
|
transition: all 0.2s ease;
|
|
|
}}
|
|
|
|
|
|
@@ -2833,6 +2833,7 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
}}
|
|
|
|
|
|
.high-feature-name {{
|
|
|
+ font-size: 14px;
|
|
|
font-weight: 600;
|
|
|
color: #166534;
|
|
|
margin-bottom: 4px;
|
|
|
@@ -2840,12 +2841,13 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
|
|
|
.high-feature-score {{
|
|
|
display: inline-block;
|
|
|
- font-size: 13px;
|
|
|
+ font-size: 12px;
|
|
|
font-weight: 600;
|
|
|
color: #16a34a;
|
|
|
background: #dcfce7;
|
|
|
padding: 2px 8px;
|
|
|
border-radius: 4px;
|
|
|
+ margin-right: 6px;
|
|
|
}}
|
|
|
|
|
|
.high-feature-meta {{
|
|
|
@@ -3115,10 +3117,16 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
+ <!-- 候选词库区域 -->
|
|
|
+ <div id="candidateLibraryContainer"></div>
|
|
|
+
|
|
|
<!-- 主容器 - 级联布局 -->
|
|
|
<div class="main-container">
|
|
|
<!-- 左侧栏:原始特征列表 -->
|
|
|
- <div class="left-sidebar" id="leftSidebar"></div>
|
|
|
+ <div class="left-sidebar" id="leftSidebar">
|
|
|
+ <div class="sidebar-header">选题点</div>
|
|
|
+ <div class="sidebar-content" id="leftContent"></div>
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 中间栏:base_word列表 -->
|
|
|
<div class="middle-sidebar" id="middleSidebar">
|
|
|
@@ -3134,6 +3142,7 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
|
|
|
<!-- 详情区域:搜索结果 -->
|
|
|
<div class="detail-area" id="detailArea">
|
|
|
+ <div class="sidebar-header">搜索结果</div>
|
|
|
<div class="detail-placeholder">👈 请从左侧选择特征查看详情</div>
|
|
|
<div class="detail-content" id="detailContent"></div>
|
|
|
</div>
|
|
|
@@ -3419,19 +3428,15 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
let selectedSearchWordIdx = null;
|
|
|
|
|
|
function renderLeftSidebar() {{
|
|
|
- const sidebar = document.getElementById('leftSidebar');
|
|
|
+ const leftContent = document.getElementById('leftContent');
|
|
|
let html = '';
|
|
|
|
|
|
- // 添加候选词库
|
|
|
- const allCandidates = extractAllCandidates();
|
|
|
- html += renderCandidateLibrary(allCandidates);
|
|
|
-
|
|
|
- // 1. 高相似度特征区域(≥0.8)
|
|
|
+ // 1. 高相似度选题点区域(≥0.8)
|
|
|
if (highSimilarityFeatures && highSimilarityFeatures.length > 0) {{
|
|
|
html += `
|
|
|
<div class="high-similarity-section">
|
|
|
<div class="high-similarity-header">
|
|
|
- <div class="high-similarity-title">📋 当前帖子-已匹配(≥0.8)</div>
|
|
|
+ <div class="high-similarity-title">📋 选题点-已匹配(≥0.8)</div>
|
|
|
<div class="high-similarity-count">${{highSimilarityFeatures.length}}个</div>
|
|
|
</div>
|
|
|
<div class="high-similarity-list">
|
|
|
@@ -3444,9 +3449,11 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
|
|
|
html += `
|
|
|
<div class="high-similarity-item">
|
|
|
- <div class="high-feature-name">✓ ${{name}}</div>
|
|
|
- <div class="high-feature-score">${{similarity.toFixed(2)}}</div>
|
|
|
- <div class="high-feature-meta">${{dimension}}</div>
|
|
|
+ <div class="high-feature-name">👤 ${{name}}</div>
|
|
|
+ <div class="cascade-item-meta">
|
|
|
+ <span class="high-feature-score">相似度: ${{similarity.toFixed(2)}}</span>
|
|
|
+ <span class="high-feature-meta">${{dimension}}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
`;
|
|
|
}});
|
|
|
@@ -3457,13 +3464,13 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
`;
|
|
|
}}
|
|
|
|
|
|
- // 2. 部分匹配特征区域(0.5-0.8)
|
|
|
+ // 2. 部分匹配选题点区域(0.5-0.8)
|
|
|
const partialMatchCount = data.length;
|
|
|
if (partialMatchCount > 0) {{
|
|
|
html += `
|
|
|
<div class="partial-similarity-section">
|
|
|
<div class="partial-similarity-header">
|
|
|
- <div class="partial-similarity-title">📋 当前帖子-部分匹配(0.5-0.8)</div>
|
|
|
+ <div class="partial-similarity-title">📋 选题点-部分匹配(0.5-0.8)</div>
|
|
|
<div class="partial-similarity-count">${{partialMatchCount}}个</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -3500,12 +3507,12 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
}});
|
|
|
}}
|
|
|
|
|
|
- // 3. 低相似度特征区域(<0.5)
|
|
|
+ // 3. 低相似度选题点区域(<0.5)
|
|
|
if (lowSimilarityFeatures && lowSimilarityFeatures.length > 0) {{
|
|
|
html += `
|
|
|
<div class="low-similarity-section">
|
|
|
<div class="low-similarity-header">
|
|
|
- <div class="low-similarity-title">📋 当前帖子-未匹配(<0.5)</div>
|
|
|
+ <div class="low-similarity-title">📋 选题点-未匹配(<0.5)</div>
|
|
|
<div class="low-similarity-count">${{lowSimilarityFeatures.length}}个</div>
|
|
|
</div>
|
|
|
<div class="low-similarity-list">
|
|
|
@@ -3531,7 +3538,7 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
`;
|
|
|
}}
|
|
|
|
|
|
- sidebar.innerHTML = html;
|
|
|
+ leftContent.innerHTML = html;
|
|
|
}}
|
|
|
|
|
|
// ========== 级联交互函数 ==========
|
|
|
@@ -3632,6 +3639,12 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
const sourceWord = sw.source_word || '';
|
|
|
const score = sw.score || 0;
|
|
|
|
|
|
+ // 获取综合评分信息
|
|
|
+ const comprehensiveScore = sw.comprehensive_score || 0;
|
|
|
+ const scoreDetail = sw.comprehensive_score_detail || {{}};
|
|
|
+ const totalN = scoreDetail.N || 0;
|
|
|
+ const matchM = scoreDetail.M || 0;
|
|
|
+
|
|
|
const evaluation = sw['evaluation_with_filter'];
|
|
|
let evalBadges = '';
|
|
|
if (evaluation) {{
|
|
|
@@ -3661,6 +3674,14 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
<div style="font-size:11px;color:#6b7280;margin-top:4px;">
|
|
|
组合词: ${{sourceWord}} → [${{score.toFixed(2)}}]
|
|
|
</div>
|
|
|
+ <div style="font-size:12px;margin-top:6px;display:flex;align-items:center;gap:8px;">
|
|
|
+ <span style="color:#7c3aed;font-weight:600;">
|
|
|
+ 综合评分: ${{comprehensiveScore.toFixed(3)}}
|
|
|
+ </span>
|
|
|
+ <span style="color:#059669;font-weight:600;">
|
|
|
+ M/N: ${{matchM}}/${{totalN}}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
${{evalBadges ? `<div style="margin-top:4px;">${{evalBadges}}</div>` : ''}}
|
|
|
${{reasoning ? `
|
|
|
<div class="search-word-reasoning">
|
|
|
@@ -3698,6 +3719,20 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
}}
|
|
|
}}
|
|
|
|
|
|
+ // 折叠/展开帖子评估详情
|
|
|
+ function toggleEvalDetail(evalDetailId) {{
|
|
|
+ const detailEl = document.getElementById(evalDetailId);
|
|
|
+ const toggleBtn = event.currentTarget;
|
|
|
+
|
|
|
+ if (detailEl.style.display === 'none') {{
|
|
|
+ detailEl.style.display = 'block';
|
|
|
+ toggleBtn.innerHTML = '详情 ▲';
|
|
|
+ }} else {{
|
|
|
+ detailEl.style.display = 'none';
|
|
|
+ toggleBtn.innerHTML = '详情 ▼';
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+
|
|
|
// 选择search word - 显示detail area
|
|
|
function selectSearchWord(featureIdx, baseWordIdx, swIdx) {{
|
|
|
selectedSearchWordIdx = swIdx;
|
|
|
@@ -3745,48 +3780,127 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
notes.forEach((note, noteIdx) => {{
|
|
|
const noteCard = note.note_card || {{}};
|
|
|
const title = noteCard.display_title || '无标题';
|
|
|
- const cover = (noteCard.image_list && noteCard.image_list[0]) || noteCard.cover?.url_default || '';
|
|
|
+ const imageList = noteCard.image_list || [];
|
|
|
+ const cover = imageList[0] || noteCard.cover?.url_default || '';
|
|
|
const noteId = note.id || note.note_id || '';
|
|
|
const type = noteCard.type || 'normal';
|
|
|
- const typeIcon = type === 'video' ? '🎬' : '📷';
|
|
|
-
|
|
|
- // 获取评估信息
|
|
|
- const noteEval = sw.evaluation_with_filter?.notes_with_scores?.find(n => n.note_id === noteId || n.id === noteId);
|
|
|
- const evalScore = noteEval?.evaluation_score || 0;
|
|
|
- const matchLevel = noteEval?.match_level || '未评估';
|
|
|
-
|
|
|
+ const typeIcon = type === 'video' ? '🎬' : '🖼️';
|
|
|
+ const user = noteCard.user || {{}};
|
|
|
+ const userName = user.nickname || '未知用户';
|
|
|
+ const userAvatar = user.avatar || '';
|
|
|
+
|
|
|
+ // 从notes_evaluation获取评估信息(通过note_index匹配)
|
|
|
+ const notesEvaluation = sw.evaluation_with_filter?.notes_evaluation || [];
|
|
|
+ const noteEval = notesEvaluation[noteIdx] || {{}};
|
|
|
+
|
|
|
+ const queryRelevance = noteEval['Query相关性'] || '未评估';
|
|
|
+ const comprehensiveScore = noteEval['综合得分'] || 0;
|
|
|
+ const matchType = noteEval['匹配类型'] || '未评估';
|
|
|
+ const explanation = noteEval['说明'] || noteEval['评分说明'] || '';
|
|
|
+ const firstLayerEval = noteEval['第一层评估'] || {{}};
|
|
|
+
|
|
|
+ // 根据匹配类型确定样式
|
|
|
let matchClass = '';
|
|
|
let matchColor = '';
|
|
|
- if (matchLevel.includes('完全匹配')) {{
|
|
|
+ let matchIcon = '';
|
|
|
+ if (matchType.includes('完全匹配')) {{
|
|
|
matchClass = 'match-complete';
|
|
|
matchColor = '#22c55e';
|
|
|
- }} else if (matchLevel.includes('相似匹配')) {{
|
|
|
+ matchIcon = '🟢';
|
|
|
+ }} else if (matchType.includes('相似匹配')) {{
|
|
|
matchClass = 'match-similar';
|
|
|
matchColor = '#f59e0b';
|
|
|
- }} else if (matchLevel.includes('弱相似')) {{
|
|
|
+ matchIcon = '🟡';
|
|
|
+ }} else if (matchType.includes('弱相似')) {{
|
|
|
matchClass = 'match-weak';
|
|
|
matchColor = '#f97316';
|
|
|
- }} else if (matchLevel.includes('无匹配')) {{
|
|
|
+ matchIcon = '🟠';
|
|
|
+ }} else if (matchType.includes('无匹配')) {{
|
|
|
matchClass = 'match-none';
|
|
|
matchColor = '#dc2626';
|
|
|
- }} else {{
|
|
|
+ matchIcon = '🔴';
|
|
|
+ }} else if (matchType.includes('过滤')) {{
|
|
|
matchClass = 'match-filtered';
|
|
|
matchColor = '#6b7280';
|
|
|
+ matchIcon = '⚫';
|
|
|
+ }} else {{
|
|
|
+ matchClass = 'match-unknown';
|
|
|
+ matchColor = '#9ca3af';
|
|
|
+ matchIcon = '⚪';
|
|
|
}}
|
|
|
|
|
|
+ const evalDetailId = `eval-detail-${{featureIdx}}-${{baseWordIdx}}-${{swIdx}}-${{noteIdx}}`;
|
|
|
+
|
|
|
+ // 检查是否有解构数据
|
|
|
+ const hasDeconstruction = deconstructionData[noteId] != null;
|
|
|
+
|
|
|
html += `
|
|
|
- <div class="note-card ${{matchClass}}" style="border:1px solid #e5e7eb;border-radius:8px;overflow:hidden;background:white;cursor:pointer;transition:all 0.2s;border-left:4px solid ${{matchColor}};"
|
|
|
- onclick="openDeconstructionModal('${{noteId}}')">
|
|
|
- ${{cover ? `<img src="${{cover}}" style="width:100%;height:180px;object-fit:cover;">` : `<div style="width:100%;height:180px;background:#f3f4f6;display:flex;align-items:center;justify-content:center;color:#9ca3af;">${{typeIcon}}</div>`}}
|
|
|
+ <div class="note-card ${{matchClass}}" style="border:2px solid #fbbf24;border-radius:12px;overflow:hidden;background:white;transition:all 0.2s;">
|
|
|
+ <!-- 图片轮播区域 -->
|
|
|
+ <div style="position:relative;width:100%;height:200px;background:#f3f4f6;">
|
|
|
+ ${{cover ? `<img src="${{cover}}" style="width:100%;height:100%;object-fit:cover;">` : `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:#9ca3af;">${{typeIcon}}</div>`}}
|
|
|
+ <div style="position:absolute;top:10px;right:10px;background:rgba(0,0,0,0.6);color:white;padding:4px 10px;border-radius:20px;font-size:12px;font-weight:600;">
|
|
|
+ 1/${{imageList.length || 1}}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 内容区域 -->
|
|
|
<div style="padding:12px;">
|
|
|
- <div style="font-size:14px;font-weight:600;margin-bottom:8px;line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;">
|
|
|
+ <!-- 标题 -->
|
|
|
+ <div style="font-size:14px;font-weight:600;margin-bottom:8px;line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:#1f2937;">
|
|
|
${{title}}
|
|
|
</div>
|
|
|
- <div style="font-size:11px;color:#6b7280;display:flex;justify-content:space-between;align-items:center;">
|
|
|
- <span>${{typeIcon}} ${{type}}</span>
|
|
|
- <span style="color:${{matchColor}};font-weight:600;">${{evalScore.toFixed(2)}}</span>
|
|
|
+
|
|
|
+ <!-- 类型标签 -->
|
|
|
+ <div style="margin-bottom:8px;">
|
|
|
+ <span style="display:inline-block;padding:2px 8px;background:#ecfdf5;color:#059669;font-size:11px;border-radius:4px;">
|
|
|
+ ${{typeIcon}} 图文
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 作者信息 -->
|
|
|
+ <div style="display:flex;align-items:center;margin-bottom:10px;">
|
|
|
+ ${{userAvatar ? `<img src="${{userAvatar}}" style="width:20px;height:20px;border-radius:50%;margin-right:6px;">` : '<div style="width:20px;height:20px;border-radius:50%;background:#e5e7eb;margin-right:6px;"></div>'}}
|
|
|
+ <span style="font-size:11px;color:#6b7280;">${{userName}}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 评分徽章 -->
|
|
|
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:8px;background:#f9fafb;border-radius:6px;margin-bottom:8px;">
|
|
|
+ <span style="font-size:12px;color:${{matchColor}};font-weight:600;">
|
|
|
+ ${{matchIcon}} ${{matchType}} (${{comprehensiveScore.toFixed(1)}}分)
|
|
|
+ </span>
|
|
|
+ <button onclick="event.stopPropagation(); toggleEvalDetail('${{evalDetailId}}')"
|
|
|
+ style="font-size:11px;color:#667eea;background:none;border:none;cursor:pointer;padding:2px 6px;">
|
|
|
+ 详情 ▼
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 评估详情(可展开) -->
|
|
|
+ <div id="${{evalDetailId}}" style="display:none;font-size:11px;color:#6b7280;padding:8px;background:#fef3c7;border-radius:6px;margin-top:8px;max-height:150px;overflow-y:auto;">
|
|
|
+ <div style="margin-bottom:6px;">
|
|
|
+ <strong style="color:#92400e;">Query相关性:</strong> ${{queryRelevance}}
|
|
|
+ </div>
|
|
|
+ ${{explanation ? `
|
|
|
+ <div style="margin-bottom:6px;">
|
|
|
+ <strong style="color:#92400e;">说明:</strong> ${{explanation}}
|
|
|
+ </div>
|
|
|
+ ` : ''}}
|
|
|
+ ${{firstLayerEval['说明'] ? `
|
|
|
+ <div>
|
|
|
+ <strong style="color:#92400e;">第一层评估:</strong> ${{firstLayerEval['说明']}}
|
|
|
+ </div>
|
|
|
+ ` : ''}}
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 解构按钮(仅当有解构数据时显示) -->
|
|
|
+ ${{hasDeconstruction ? `
|
|
|
+ <button class="deconstruction-toggle-btn"
|
|
|
+ onclick="event.stopPropagation(); openDeconstructionModal('${{noteId}}', '${{title.replace(/'/g, "\\'")}}')"
|
|
|
+ style="width:100%;padding:10px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;border:none;border-top:1px solid #e5e7eb;cursor:pointer;font-size:13px;font-weight:600;transition:all 0.3s;display:flex;align-items:center;justify-content:center;gap:6px;">
|
|
|
+ 🎯 查看解构
|
|
|
+ </button>
|
|
|
+ ` : ''}}
|
|
|
</div>
|
|
|
`;
|
|
|
}});
|
|
|
@@ -4042,7 +4156,10 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
|
|
|
// 打开解构模态窗口
|
|
|
function openDeconstructionModal(noteId, noteTitle) {{
|
|
|
- console.log('🔧 [调试] openDeconstructionModal被调用, noteId:', noteId);
|
|
|
+ console.log('🔧 [调试] ========== openDeconstructionModal 开始 ==========');
|
|
|
+ console.log('🔧 [调试] noteId:', noteId);
|
|
|
+ console.log('🔧 [调试] noteTitle:', noteTitle);
|
|
|
+ console.log('🔧 [调试] noteId类型:', typeof noteId);
|
|
|
|
|
|
const modal = document.getElementById('deconstructionModal');
|
|
|
const modalContent = document.getElementById('modalContent');
|
|
|
@@ -4056,21 +4173,45 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
// 设置标题
|
|
|
modalNoteTitle.textContent = noteTitle || '解构分析';
|
|
|
|
|
|
- // 检查是否有数据
|
|
|
+ // 详细检查数据
|
|
|
+ console.log('📊 [调试] similarityData对象类型:', typeof similarityData);
|
|
|
+ console.log('📊 [调试] similarityData的keys数量:', Object.keys(similarityData).length);
|
|
|
+ console.log('📊 [调试] 前5个可用的noteId:', Object.keys(similarityData).slice(0, 5));
|
|
|
+
|
|
|
const hasSimilarityData = !!similarityData[noteId];
|
|
|
- console.log('📊 [调试] 相似度数据存在:', hasSimilarityData);
|
|
|
+ console.log('📊 [调试] similarityData[noteId]存在:', hasSimilarityData);
|
|
|
+
|
|
|
+ if (hasSimilarityData) {{
|
|
|
+ const data = similarityData[noteId];
|
|
|
+ console.log('📊 [调试] similarityData[noteId]内容:', data);
|
|
|
+ console.log('📊 [调试] deconstructed_features字段存在:', 'deconstructed_features' in data);
|
|
|
+ if ('deconstructed_features' in data) {{
|
|
|
+ console.log('📊 [调试] deconstructed_features长度:', data.deconstructed_features ? data.deconstructed_features.length : 'null/undefined');
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+
|
|
|
+ // 同时检查deconstructionData
|
|
|
+ const hasDeconstructionData = !!deconstructionData[noteId];
|
|
|
+ console.log('📊 [调试] deconstructionData[noteId]存在:', hasDeconstructionData);
|
|
|
+ if (hasDeconstructionData) {{
|
|
|
+ console.log('📊 [调试] deconstructionData[noteId]:', deconstructionData[noteId]);
|
|
|
+ }}
|
|
|
|
|
|
if (!hasSimilarityData) {{
|
|
|
console.warn('⚠️ [警告] 未找到相似度数据, noteId:', noteId);
|
|
|
- console.log('📋 [调试] 可用的noteId列表:', Object.keys(similarityData));
|
|
|
- modalContent.innerHTML = '<div style="padding: 30px; text-align: center; color: #6b7280;">暂无解构数据</div>';
|
|
|
+ console.log('📋 [调试] 完整的可用noteId列表:', Object.keys(similarityData));
|
|
|
+ modalContent.innerHTML = '<div style="padding: 30px; text-align: center; color: #6b7280;">暂无解构数据<br><small>noteId: ' + noteId + '</small></div>';
|
|
|
}} else {{
|
|
|
try {{
|
|
|
- modalContent.innerHTML = renderDeconstructionContent(noteId);
|
|
|
+ console.log('🎨 [调试] 开始渲染解构内容...');
|
|
|
+ const content = renderDeconstructionContent(noteId);
|
|
|
+ console.log('🎨 [调试] 渲染返回的HTML长度:', content.length);
|
|
|
+ modalContent.innerHTML = content;
|
|
|
console.log('✅ [调试] 解构内容渲染成功');
|
|
|
}} catch (error) {{
|
|
|
console.error('❌ [错误] 渲染解构内容失败:', error);
|
|
|
- modalContent.innerHTML = `<div style="padding: 30px; text-align: center; color: red;">渲染错误: ${{error.message}}</div>`;
|
|
|
+ console.error('❌ [错误] 错误堆栈:', error.stack);
|
|
|
+ modalContent.innerHTML = `<div style="padding: 30px; text-align: center; color: red;">渲染错误: ${{error.message}}<br><pre style="text-align:left;font-size:10px;">${{error.stack}}</pre></div>`;
|
|
|
}}
|
|
|
}}
|
|
|
|
|
|
@@ -4078,6 +4219,7 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
modal.classList.add('active');
|
|
|
document.body.style.overflow = 'hidden'; // 禁止背景滚动
|
|
|
console.log('✅ [调试] 模态窗口已显示');
|
|
|
+ console.log('🔧 [调试] ========== openDeconstructionModal 结束 ==========');
|
|
|
}}
|
|
|
|
|
|
// 关闭模态窗口
|
|
|
@@ -4265,27 +4407,46 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
|
|
|
// 渲染解构内容
|
|
|
function renderDeconstructionContent(noteId) {{
|
|
|
+ console.log('🎨 [renderDeconstructionContent] ========== 开始 ==========');
|
|
|
+ console.log('🎨 [renderDeconstructionContent] noteId:', noteId);
|
|
|
+ console.log('🎨 [renderDeconstructionContent] noteId类型:', typeof noteId);
|
|
|
+
|
|
|
const similarityInfo = similarityData[noteId];
|
|
|
+ console.log('🎨 [renderDeconstructionContent] similarityInfo:', similarityInfo);
|
|
|
+ console.log('🎨 [renderDeconstructionContent] similarityInfo是否为null/undefined:', similarityInfo == null);
|
|
|
+
|
|
|
if (!similarityInfo) {{
|
|
|
+ console.warn('⚠️ [renderDeconstructionContent] similarityInfo不存在');
|
|
|
return `<div style="padding: 30px; text-align: center; color: #6b7280;">
|
|
|
<div style="font-size: 48px; margin-bottom: 10px;">📭</div>
|
|
|
<div style="font-size: 16px; margin-bottom: 8px;">暂无解构数据</div>
|
|
|
<div style="font-size: 14px; opacity: 0.7;">该帖子未进行特征解构分析</div>
|
|
|
+ <div style="font-size: 12px; opacity: 0.5; margin-top: 8px;">noteId: ${{noteId}}</div>
|
|
|
</div>`;
|
|
|
}}
|
|
|
|
|
|
const originalFeature = similarityInfo.original_feature || '未知特征';
|
|
|
+ console.log('🎨 [renderDeconstructionContent] originalFeature:', originalFeature);
|
|
|
+
|
|
|
const features = similarityInfo.deconstructed_features || [];
|
|
|
+ console.log('🎨 [renderDeconstructionContent] features:', features);
|
|
|
+ console.log('🎨 [renderDeconstructionContent] features类型:', typeof features);
|
|
|
+ console.log('🎨 [renderDeconstructionContent] features.length:', features.length);
|
|
|
+ console.log('🎨 [renderDeconstructionContent] features是数组:', Array.isArray(features));
|
|
|
|
|
|
if (features.length === 0) {{
|
|
|
+ console.warn('⚠️ [renderDeconstructionContent] features长度为0');
|
|
|
return `<div style="padding: 30px; text-align: center; color: #6b7280;">
|
|
|
<div style="font-size: 48px; margin-bottom: 10px;">🔍</div>
|
|
|
<div style="font-size: 16px; margin-bottom: 8px;">未提取到解构特征</div>
|
|
|
<div style="font-size: 14px; opacity: 0.7;">原始特征:"${{originalFeature}}"</div>
|
|
|
<div style="font-size: 13px; opacity: 0.6; margin-top: 10px;">该帖子虽然评分较高,但AI未能从中提取到有效的解构特征</div>
|
|
|
+ <div style="font-size: 12px; opacity: 0.5; margin-top: 8px;">noteId: ${{noteId}}</div>
|
|
|
</div>`;
|
|
|
}}
|
|
|
|
|
|
+ console.log('✅ [renderDeconstructionContent] 有效特征数量:', features.length);
|
|
|
+
|
|
|
// 按维度分组
|
|
|
const dimensionGroups = {{}};
|
|
|
features.forEach(feat => {{
|
|
|
@@ -4620,7 +4781,25 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
console.log('📊 [数据] 评估特征数:', data.length);
|
|
|
console.log('📊 [数据] 解构结果数:', Object.keys(deconstructionData).length);
|
|
|
console.log('📊 [数据] 相似度分析数:', Object.keys(similarityData).length);
|
|
|
- console.log('📋 [数据] 相似度分析可用noteId:', Object.keys(similarityData));
|
|
|
+ console.log('📋 [数据] 解构数据前5个noteId:', Object.keys(deconstructionData).slice(0, 5));
|
|
|
+ console.log('📋 [数据] 相似度分析前5个noteId:', Object.keys(similarityData).slice(0, 5));
|
|
|
+
|
|
|
+ // 测试特定noteId
|
|
|
+ const testNoteId = '6662ada60000000015012f7d';
|
|
|
+ console.log('🧪 [测试] 检查特定noteId:', testNoteId);
|
|
|
+ console.log('🧪 [测试] 在deconstructionData中:', testNoteId in deconstructionData);
|
|
|
+ console.log('🧪 [测试] 在similarityData中:', testNoteId in similarityData);
|
|
|
+ if (testNoteId in similarityData) {{
|
|
|
+ const testData = similarityData[testNoteId];
|
|
|
+ console.log('🧪 [测试] similarityData内容:', testData);
|
|
|
+ console.log('🧪 [测试] deconstructed_features存在:', 'deconstructed_features' in testData);
|
|
|
+ if ('deconstructed_features' in testData) {{
|
|
|
+ console.log('🧪 [测试] deconstructed_features长度:', testData.deconstructed_features ? testData.deconstructed_features.length : 'null/undefined');
|
|
|
+ if (testData.deconstructed_features && testData.deconstructed_features.length > 0) {{
|
|
|
+ console.log('🧪 [测试] 第一个特征:', testData.deconstructed_features[0]);
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+ }}
|
|
|
console.log('='.repeat(60));
|
|
|
|
|
|
// 初始化
|
|
|
@@ -4628,6 +4807,11 @@ def generate_html(data: List[Dict[str, Any]], stats: Dict[str, Any],
|
|
|
console.log('✅ [系统] DOM加载完成,开始初始化...');
|
|
|
|
|
|
try {{
|
|
|
+ // 渲染候选词库(移到顶部独立区域)
|
|
|
+ const allCandidates = extractAllCandidates();
|
|
|
+ document.getElementById('candidateLibraryContainer').innerHTML = renderCandidateLibrary(allCandidates);
|
|
|
+ console.log('✅ [系统] 候选词库渲染完成');
|
|
|
+
|
|
|
renderLeftSidebar();
|
|
|
console.log('✅ [系统] 左侧导航(级联模式)渲染完成');
|
|
|
|