|
@@ -353,6 +353,37 @@ function QueryNode({ id, data, sourcePosition, targetPosition }) {
|
|
|
<strong>Parent:</strong> {data.parent}
|
|
<strong>Parent:</strong> {data.parent}
|
|
|
</div>
|
|
</div>
|
|
|
)}
|
|
)}
|
|
|
|
|
+ {data.nodeType === 'domain_combination' && Array.isArray(data.source_word_details) && data.source_word_details.length > 0 && (
|
|
|
|
|
+ <div style={{
|
|
|
|
|
+ marginTop: '6px',
|
|
|
|
|
+ paddingTop: '6px',
|
|
|
|
|
+ borderTop: '1px solid #f3f4f6',
|
|
|
|
|
+ fontSize: '10px',
|
|
|
|
|
+ color: '#6b7280',
|
|
|
|
|
+ lineHeight: '1.5',
|
|
|
|
|
+ }}>
|
|
|
|
|
+ <strong style={{ color: '#4b5563' }}>来源词得分:</strong>
|
|
|
|
|
+ <div style={{ marginTop: '4px', display: 'flex', flexDirection: 'column', gap: '4px' }}>
|
|
|
|
|
+ {data.source_word_details.map((detail, idx) => {
|
|
|
|
|
+ const words = (detail.words || []).map((w) => {
|
|
|
|
|
+ const numericScore = typeof w.score === 'number' ? w.score : parseFloat(w.score || '0');
|
|
|
|
|
+ const formattedScore = Number.isFinite(numericScore) ? numericScore.toFixed(2) : '0.00';
|
|
|
|
|
+ return w.text + ' (' + formattedScore + ')';
|
|
|
|
|
+ }).join(' + ');
|
|
|
|
|
+ const segmentLabel = detail.segment_type ? '[' + detail.segment_type + '] ' : '';
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div key={idx} style={{ display: 'flex', flexWrap: 'wrap', gap: '4px', alignItems: 'center' }}>
|
|
|
|
|
+ {segmentLabel && <span style={{ color: '#4b5563' }}>{segmentLabel}</span>}
|
|
|
|
|
+ <span style={{ color: '#2563eb' }}>{words}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ })}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div style={{ marginTop: '4px', fontWeight: '500', color: data.is_above_sources ? '#16a34a' : '#dc2626' }}>
|
|
|
|
|
+ {data.is_above_sources ? '✅ 组合得分高于所有来源词' : '⚠️ 组合得分未超过全部来源词'}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
{data.selectedWord && (
|
|
{data.selectedWord && (
|
|
|
<div style={{
|
|
<div style={{
|
|
|
marginTop: '6px',
|
|
marginTop: '6px',
|
|
@@ -794,6 +825,26 @@ function TreeNode({ node, level, children, isCollapsed, onToggle, isSelected, on
|
|
|
const strategy = getPrimaryStrategy(node.data); // 使用智能提取函数
|
|
const strategy = getPrimaryStrategy(node.data); // 使用智能提取函数
|
|
|
const strategyColor = getStrategyColor(strategy);
|
|
const strategyColor = getStrategyColor(strategy);
|
|
|
const nodeActualType = node.data.nodeType || node.type; // 获取实际节点类型
|
|
const nodeActualType = node.data.nodeType || node.type; // 获取实际节点类型
|
|
|
|
|
+ const isDomainCombination = nodeActualType === 'domain_combination';
|
|
|
|
|
+
|
|
|
|
|
+ let sourceSummary = '';
|
|
|
|
|
+ if (isDomainCombination && Array.isArray(node.data.source_word_details) && node.data.source_word_details.length > 0) {
|
|
|
|
|
+ const summaryParts = [];
|
|
|
|
|
+ node.data.source_word_details.forEach((detail) => {
|
|
|
|
|
+ const words = Array.isArray(detail.words) ? detail.words : [];
|
|
|
|
|
+ const wordTexts = [];
|
|
|
|
|
+ words.forEach((w) => {
|
|
|
|
|
+ const numericScore = typeof w.score === 'number' ? w.score : parseFloat(w.score || '0');
|
|
|
|
|
+ const formattedScore = Number.isFinite(numericScore) ? numericScore.toFixed(2) : '0.00';
|
|
|
|
|
+ wordTexts.push(w.text + ' (' + formattedScore + ')');
|
|
|
|
|
+ });
|
|
|
|
|
+ if (wordTexts.length > 0) {
|
|
|
|
|
+ const segmentLabel = detail.segment_type ? '[' + detail.segment_type + '] ' : '';
|
|
|
|
|
+ summaryParts.push(segmentLabel + wordTexts.join(' + '));
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ sourceSummary = summaryParts.join(' | ');
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 计算字体颜色:根据分数提升幅度判断
|
|
// 计算字体颜色:根据分数提升幅度判断
|
|
|
let fontColor = '#374151'; // 默认颜色
|
|
let fontColor = '#374151'; // 默认颜色
|
|
@@ -950,6 +1001,38 @@ function TreeNode({ node, level, children, isCollapsed, onToggle, isSelected, on
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+ {/* 域组合的来源词得分(树状视图,右对齐) */}
|
|
|
|
|
+ {isDomainCombination && sourceSummary && (
|
|
|
|
|
+ <div style={{
|
|
|
|
|
+ fontSize: '10px',
|
|
|
|
|
+ color: '#2563eb',
|
|
|
|
|
+ lineHeight: '1.4',
|
|
|
|
|
+ display: 'flex',
|
|
|
|
|
+ flexDirection: 'column',
|
|
|
|
|
+ alignItems: 'flex-end',
|
|
|
|
|
+ gap: '2px',
|
|
|
|
|
+ textAlign: 'right',
|
|
|
|
|
+ }}>
|
|
|
|
|
+ {node.data.source_word_details.map((detail, idx) => {
|
|
|
|
|
+ const summary = (() => {
|
|
|
|
|
+ const words = Array.isArray(detail.words) ? detail.words : [];
|
|
|
|
|
+ const parts = words.map((w) => {
|
|
|
|
|
+ const numericScore = typeof w.score === 'number' ? w.score : parseFloat(w.score || '0');
|
|
|
|
|
+ const formattedScore = Number.isFinite(numericScore) ? numericScore.toFixed(2) : '0.00';
|
|
|
|
|
+ return w.text + ' (' + formattedScore + ')';
|
|
|
|
|
+ });
|
|
|
|
|
+ const prefix = detail.segment_type ? '[' + detail.segment_type + '] ' : '';
|
|
|
|
|
+ return prefix + parts.join(' + ');
|
|
|
|
|
+ })();
|
|
|
|
|
+ return (
|
|
|
|
|
+ <span key={idx} title={summary}>
|
|
|
|
|
+ {summary}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ );
|
|
|
|
|
+ })}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+
|
|
|
{/* 分数下划线 - 步骤和轮次节点不显示 */}
|
|
{/* 分数下划线 - 步骤和轮次节点不显示 */}
|
|
|
{nodeActualType !== 'step' && nodeActualType !== 'round' && (
|
|
{nodeActualType !== 'step' && nodeActualType !== 'round' && (
|
|
|
<div style={{
|
|
<div style={{
|
|
@@ -1158,6 +1241,10 @@ function transformData(data) {
|
|
|
domains: node.domains || [], // 域索引数组(domain_combination节点特有)
|
|
domains: node.domains || [], // 域索引数组(domain_combination节点特有)
|
|
|
domains_str: node.domains_str || '', // 域标识字符串(如"D0,D1")
|
|
domains_str: node.domains_str || '', // 域标识字符串(如"D0,D1")
|
|
|
from_segments: node.from_segments || [], // 来源segments(domain_combination节点特有)
|
|
from_segments: node.from_segments || [], // 来源segments(domain_combination节点特有)
|
|
|
|
|
+ source_word_details: node.source_word_details || [], // 组合来源词及其得分
|
|
|
|
|
+ source_scores: node.source_scores || [], // 扁平来源得分
|
|
|
|
|
+ is_above_sources: node.is_above_sources || false, // 组合是否高于来源得分
|
|
|
|
|
+ max_source_score: node.max_source_score !== undefined ? node.max_source_score : null, // 来源最高分
|
|
|
},
|
|
},
|
|
|
position: { x: 0, y: 0 },
|
|
position: { x: 0, y: 0 },
|
|
|
});
|
|
});
|