|
|
@@ -16,17 +16,17 @@
|
|
|
<div class="graph_header" v-if="activeView === 'list'">
|
|
|
<!-- 自定义图例 -->
|
|
|
<div class="legend">
|
|
|
- <div class="legend_item" :class="{ 'selected': selectedLegend.weak }">
|
|
|
- <span class="legend_dot weak"></span>
|
|
|
- <span class="legend_text">{{ '薄弱(0%≤得分率<60%)' }}</span>
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.weak }" @click="toggleLegend('weak')">
|
|
|
+ <span class="legend_dot weak" :style="selectedLegend.weak ? {} : { backgroundColor: '#ccc' }"></span>
|
|
|
+ <span class="legend_text" :style="selectedLegend.weak ? {} : { color: '#999999' }">{{ '薄弱(0%≤得分率<60%)' }}</span>
|
|
|
</div>
|
|
|
- <div class="legend_item" :class="{ 'selected': selectedLegend.good }">
|
|
|
- <span class="legend_dot good"></span>
|
|
|
- <span class="legend_text">{{ '良好(60%≤得分率<85%)' }}</span>
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.good }" @click="toggleLegend('good')">
|
|
|
+ <span class="legend_dot good" :style="selectedLegend.good ? {} : { backgroundColor: '#ccc' }"></span>
|
|
|
+ <span class="legend_text" :style="selectedLegend.good ? {} : { color: '#999999' }">{{ '良好(60%≤得分率<85%)' }}</span>
|
|
|
</div>
|
|
|
- <div class="legend_item" :class="{ 'selected': selectedLegend.excellent }">
|
|
|
- <span class="legend_dot excellent"></span>
|
|
|
- <span class="legend_text">{{ '优秀(85%≤得分率)' }}</span>
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.excellent }" @click="toggleLegend('excellent')">
|
|
|
+ <span class="legend_dot excellent" :style="selectedLegend.excellent ? {} : { backgroundColor: '#ccc' }"></span>
|
|
|
+ <span class="legend_text" :style="selectedLegend.excellent ? {} : { color: '#999999' }">{{ '优秀(85%≤得分率)' }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 视图切换按钮 - 移到knowledge_graph容器下 -->
|
|
|
@@ -55,18 +55,17 @@
|
|
|
<div class="top_container">
|
|
|
<!-- 自定义图例 -->
|
|
|
<div class="legend">
|
|
|
- <!-- @click="toggleLegend('weak')" @click="toggleLegend('good')" @click="toggleLegend('excellent')" -->
|
|
|
- <div class="legend_item" :class="{ 'selected': selectedLegend.weak }">
|
|
|
- <span class="legend_dot weak"></span>
|
|
|
- <span class="legend_text">{{ '薄弱(0%≤得分率<60%)' }}</span>
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.weak }" @click="toggleLegend('weak')">
|
|
|
+ <span class="legend_dot weak" :style="selectedLegend.weak ? {} : { backgroundColor: '#ccc' }"></span>
|
|
|
+ <span class="legend_text" :style="selectedLegend.weak ? {} : { color: '#999999' }">{{ '薄弱(0%≤得分率<60%)' }}</span>
|
|
|
</div>
|
|
|
- <div class="legend_item" :class="{ 'selected': selectedLegend.good }">
|
|
|
- <span class="legend_dot good"></span>
|
|
|
- <span class="legend_text">{{ '良好(60%≤得分率<85%)' }}</span>
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.good }" @click="toggleLegend('good')">
|
|
|
+ <span class="legend_dot good" :style="selectedLegend.good ? {} : { backgroundColor: '#ccc' }"></span>
|
|
|
+ <span class="legend_text" :style="selectedLegend.good ? {} : { color: '#999999' }">{{ '良好(60%≤得分率<85%)' }}</span>
|
|
|
</div>
|
|
|
- <div class="legend_item" :class="{ 'selected': selectedLegend.excellent }">
|
|
|
- <span class="legend_dot excellent"></span>
|
|
|
- <span class="legend_text">{{ '优秀(85%≤得分率)' }}</span>
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.excellent }" @click="toggleLegend('excellent')">
|
|
|
+ <span class="legend_dot excellent" :style="selectedLegend.excellent ? {} : { backgroundColor: '#ccc' }"></span>
|
|
|
+ <span class="legend_text" :style="selectedLegend.excellent ? {} : { color: '#999999' }">{{ '优秀(85%≤得分率)' }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 视图切换按钮 -->
|
|
|
@@ -398,7 +397,7 @@ export default {
|
|
|
// 这是为了避免在视图切换时重复调用接口
|
|
|
if (this._isMounted && newTab !== oldTab) {
|
|
|
// 向父组件发送tab切换事件
|
|
|
- this.$emit('active-tab-change', newTab);
|
|
|
+ this.$emit('activeTabChange', newTab);
|
|
|
}
|
|
|
},
|
|
|
// 监听数据变化,重新设置默认选中项
|
|
|
@@ -576,6 +575,35 @@ export default {
|
|
|
return false;
|
|
|
},
|
|
|
|
|
|
+ // 切换图例选中状态
|
|
|
+ toggleLegend(type) {
|
|
|
+ this.selectedLegend[type] = !this.selectedLegend[type];
|
|
|
+
|
|
|
+ // 生成scoreRateTypes数组
|
|
|
+ let scoreRateTypes = [];
|
|
|
+ if (this.selectedLegend.weak) scoreRateTypes.push(1);
|
|
|
+ if (this.selectedLegend.good) scoreRateTypes.push(2);
|
|
|
+ if (this.selectedLegend.excellent) scoreRateTypes.push(3);
|
|
|
+
|
|
|
+ // 如果包含所有值,则传null,否则传数组
|
|
|
+ if (scoreRateTypes.length === 3) {
|
|
|
+ scoreRateTypes = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 向父组件发送图例变化事件,包含scoreRateTypes和当前activeTab对应的knowledgeType
|
|
|
+ let knowledgeType = 0;
|
|
|
+ if (this.activeTab === 'highFreq') {
|
|
|
+ knowledgeType = 1;
|
|
|
+ } else if (this.activeTab === 'zero') {
|
|
|
+ knowledgeType = 2;
|
|
|
+ } else {
|
|
|
+ knowledgeType = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$emit('legend-change', { scoreRateTypes, knowledgeType });
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
// 根据得分率获取对应的颜色
|
|
|
getNodeColor(scoreRate) {
|
|
|
const rate = parseFloat(scoreRate);
|
|
|
@@ -664,38 +692,46 @@ export default {
|
|
|
const generateTreeData = (data, level = 0, overrideKnowledgeId = null) => {
|
|
|
// 使用传入的overrideKnowledgeId或默认使用vm.selectedKnowledgeId
|
|
|
const currentKnowledgeId = overrideKnowledgeId !== null ? overrideKnowledgeId : vm.selectedKnowledgeId;
|
|
|
-
|
|
|
- return data.filter(item => {
|
|
|
- // 获取节点级别
|
|
|
- const nodeLevel = vm.classLevel === 0 ? getNodeLevel(item.gradeScoreRate) : getNodeLevel(item.classScoreRate);
|
|
|
- // 根据图例选中状态决定是否显示节点
|
|
|
- return vm.selectedLegend[nodeLevel];
|
|
|
- }).map(item => {
|
|
|
+
|
|
|
+ return data.map(item => {
|
|
|
// 根据节点是否为最外围节点
|
|
|
const isOutermost = !item.children || item.children.length === 0;
|
|
|
-
|
|
|
+
|
|
|
// 检查当前节点是否匹配选中的知识点ID
|
|
|
const isMatched = isOutermost && String(item.knowledgeId) === String(currentKnowledgeId);
|
|
|
-
|
|
|
+
|
|
|
// 设置节点大小:选中状态16px,未选中状态10px,非叶子节点5px
|
|
|
let symbolSize = 5;
|
|
|
if (isOutermost) {
|
|
|
symbolSize = isMatched ? 15 : 10;
|
|
|
}
|
|
|
+
|
|
|
+ // 获取节点级别,优先使用对应级别的得分率,若缺失则使用另一级别作为备选
|
|
|
+ const scoreRate = item.personalScoreRate
|
|
|
+ const nodeLevel = getNodeLevel(scoreRate);
|
|
|
|
|
|
- // 计算节点样式
|
|
|
- const itemColor = isOutermost ?
|
|
|
- vm.getNodeColor(vm.classLevel === 0 || vm.classLevel === 1 ? item.gradeScoreRate : item.classScoreRate) :
|
|
|
+ // 计算节点样式,使用与nodeLevel相同的得分率逻辑
|
|
|
+ const itemColor = isOutermost ?
|
|
|
+ vm.getNodeColor(scoreRate) :
|
|
|
'#BFC1C7';
|
|
|
+ // 仅对最外层节点应用图例过滤,非外层节点始终显示
|
|
|
+ const shouldShow = !isOutermost || vm.selectedLegend[nodeLevel];
|
|
|
+
|
|
|
+ // 设置节点透明度:显示为1,隐藏为0
|
|
|
+ const opacity = shouldShow ? 1 : 0;
|
|
|
|
|
|
const node = {
|
|
|
name: item.knowledgeName,
|
|
|
symbolSize: symbolSize,
|
|
|
- // 根据班级名称是否为年级来选择使用gradeScoreRate或classScoreRate
|
|
|
- value: vm.classLevel === 0 || vm.classLevel === 1 ? item.gradeScoreRate : item.classScoreRate,
|
|
|
+ // 使用已计算的scoreRate作为value,确保数据一致性
|
|
|
+ value: scoreRate,
|
|
|
itemStyle: {
|
|
|
color: itemColor,
|
|
|
- opacity: 1
|
|
|
+ opacity: opacity
|
|
|
+ },
|
|
|
+ // 当节点是最外层且被隐藏时,隐藏连接到该节点的线
|
|
|
+ lineStyle: {
|
|
|
+ opacity: shouldShow ? 1 : 0
|
|
|
},
|
|
|
// 添加isOutermost属性用于tooltip判断
|
|
|
isOutermost: isOutermost,
|
|
|
@@ -937,19 +973,7 @@ export default {
|
|
|
listContainer.scrollTop = listItems[targetIndex].offsetTop - 100;
|
|
|
}
|
|
|
});
|
|
|
- } else {
|
|
|
- // 打印详细调试信息
|
|
|
- console.log('点击处理调试信息:', {
|
|
|
- paramsName: params.name,
|
|
|
- params: params,
|
|
|
- knowledgeItem: knowledgeItem,
|
|
|
- targetIndex: targetIndex,
|
|
|
- activeTab: this.activeTab,
|
|
|
- targetListLength: targetList.length,
|
|
|
- targetListSample: targetList.slice(0, 3),
|
|
|
- tableDataSample: this.tableData.slice(0, 1)
|
|
|
- });
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
else if (isEmptyAreaClick || isNonOuterNodeClick) {
|
|
|
// 点击空白区域或非最外层节点,恢复所有节点透明度
|
|
|
@@ -1086,13 +1110,13 @@ export default {
|
|
|
// 根据知识点得分率获取对应的点颜色
|
|
|
getDotColor(item) {
|
|
|
// 优先使用classScoreRate,若不存在或为空则使用gradeScoreRate
|
|
|
- const scoreRate = item.classScoreRate || item.gradeScoreRate;
|
|
|
+ const scoreRate = item.personalScoreRate;
|
|
|
const rate = parseFloat(scoreRate);
|
|
|
if (rate >= 85) {
|
|
|
return '#3BA272'; // 优秀 - 绿色
|
|
|
- } else if (rate > 60) {
|
|
|
+ } else if (rate >= 60 && rate < 84) {
|
|
|
return '#FAC858'; // 良好 - 黄色
|
|
|
- } else {
|
|
|
+ } else if (rate < 59) {
|
|
|
return '#EE6666'; // 薄弱 - 红色
|
|
|
}
|
|
|
}
|
|
|
@@ -1140,10 +1164,12 @@ export default {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 5px;
|
|
|
-
|
|
|
+ cursor: pointer;
|
|
|
+ opacity: 0.7;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ font-weight: 500;
|
|
|
&.selected {
|
|
|
opacity: 1;
|
|
|
- font-weight: 500;
|
|
|
}
|
|
|
|
|
|
&:hover {
|
|
|
@@ -1380,13 +1406,12 @@ export default {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 5px;
|
|
|
- // cursor: pointer;
|
|
|
- // opacity: 0.7;
|
|
|
- // transition: all 0.3s ease;
|
|
|
-
|
|
|
+ cursor: pointer;
|
|
|
+ opacity: 0.7;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ font-weight: 500;
|
|
|
&.selected {
|
|
|
opacity: 1;
|
|
|
- font-weight: 500;
|
|
|
}
|
|
|
|
|
|
&:hover {
|